diff -Nru duktape-2.0.0/AUTHORS.rst duktape-2.1.1/AUTHORS.rst --- duktape-2.0.0/AUTHORS.rst 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/AUTHORS.rst 2017-07-28 22:05:08.000000000 +0000 @@ -41,6 +41,8 @@ * 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 Other contributions =================== diff -Nru duktape-2.0.0/config/architectures/architecture_mips32.h.in duktape-2.1.1/config/architectures/architecture_mips32.h.in --- duktape-2.0.0/config/architectures/architecture_mips32.h.in 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/architectures/architecture_mips32.h.in 2017-07-28 22:05:08.000000000 +0000 @@ -1,10 +1,6 @@ #define DUK_USE_ARCH_STRING "mips32" /* MIPS byte order varies so rely on autodetection. */ -/* Based on 'make checkalign' there are no alignment requirements on - * Linux MIPS except for doubles, which need align by 4. Alignment - * requirements vary based on target though. - */ #if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 4 +#define DUK_USE_ALIGN_BY 8 #endif #define DUK_USE_PACKED_TVAL diff -Nru duktape-2.0.0/config/architectures/architecture_mips64.h.in duktape-2.1.1/config/architectures/architecture_mips64.h.in --- duktape-2.0.0/config/architectures/architecture_mips64.h.in 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/architectures/architecture_mips64.h.in 2017-07-28 22:05:08.000000000 +0000 @@ -1,8 +1,5 @@ #define DUK_USE_ARCH_STRING "mips64" /* MIPS byte order varies so rely on autodetection. */ -/* Good default is a bit arbitrary because alignment requirements - * depend on target. See https://github.com/svaarala/duktape/issues/102. - */ #if !defined(DUK_USE_ALIGN_BY) #define DUK_USE_ALIGN_BY 8 #endif diff -Nru duktape-2.0.0/config/compilers/compiler_clang.h.in duktape-2.1.1/config/compilers/compiler_clang.h.in --- duktape-2.0.0/config/compilers/compiler_clang.h.in 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/compilers/compiler_clang.h.in 2017-07-28 22:05:08.000000000 +0000 @@ -29,6 +29,9 @@ #define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) #endif +/* DUK_HOT */ +/* DUK_COLD */ + #if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) #snippet "msvc_visibility.h.in" #else diff -Nru duktape-2.0.0/config/compilers/compiler_gcc.h.in duktape-2.1.1/config/compilers/compiler_gcc.h.in --- duktape-2.0.0/config/compilers/compiler_gcc.h.in 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/compilers/compiler_gcc.h.in 2017-07-28 22:05:08.000000000 +0000 @@ -33,6 +33,12 @@ #define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) #endif +#if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && \ + defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40300) +#define DUK_HOT __attribute__((hot)) +#define DUK_COLD __attribute__((cold)) +#endif + #if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) #snippet "msvc_visibility.h.in" #elif defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40000) diff -Nru duktape-2.0.0/config/config-options/DUK_USE_DATE_TZO_WINDOWS_NO_DST.yaml duktape-2.1.1/config/config-options/DUK_USE_DATE_TZO_WINDOWS_NO_DST.yaml --- duktape-2.0.0/config/config-options/DUK_USE_DATE_TZO_WINDOWS_NO_DST.yaml 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_DATE_TZO_WINDOWS_NO_DST.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,10 @@ +define: DUK_USE_DATE_TZO_WINDOWS_NO_DST +introduced: 2.0.1 +default: false +tags: + - date + - portability +description: > + Use Win32 API calls to get local time offset at a certain time. + Does not take into account daylight savings time. When enabled, + appropriate date/time headers must be included. diff -Nru duktape-2.0.0/config/config-options/DUK_USE_FINALIZER_TORTURE.yaml duktape-2.1.1/config/config-options/DUK_USE_FINALIZER_TORTURE.yaml --- duktape-2.0.0/config/config-options/DUK_USE_FINALIZER_TORTURE.yaml 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_FINALIZER_TORTURE.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,11 @@ +define: DUK_USE_FINALIZER_TORTURE +introduced: 2.1.0 +default: false +tags: + - gc + - memory + - development + - torture +description: > + Development time option: simulate a fake finalizer call every time when + finalizers might be executed (even if the actual finalize_list is empty). diff -Nru duktape-2.0.0/config/config-options/DUK_USE_GC_TORTURE.yaml duktape-2.1.1/config/config-options/DUK_USE_GC_TORTURE.yaml --- duktape-2.0.0/config/config-options/DUK_USE_GC_TORTURE.yaml 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_GC_TORTURE.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -7,8 +7,8 @@ - development - torture description: > - Development time option: force full mark-and-sweep on every allocation to - stress test memory management. + Development time option: force full mark-and-sweep on every allocation and + in other chosen places to stress test memory management. Using a low value (e.g. 3) for DUK_USE_MARK_AND_SWEEP_RECLIMIT is also recommended. diff -Nru duktape-2.0.0/config/config-options/DUK_USE_GLOBAL_BINDING.yaml duktape-2.1.1/config/config-options/DUK_USE_GLOBAL_BINDING.yaml --- duktape-2.0.0/config/config-options/DUK_USE_GLOBAL_BINDING.yaml 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_GLOBAL_BINDING.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,10 @@ +define: DUK_USE_GLOBAL_BINDING +introduced: 2.1.0 +default: false +tags: + - ecmascript + - experimental +description: > + Provide a 'global' binding (https://github.com/tc39/proposal-global). + Disabled by default because it's still a proposal and there may be + reasons it won't be widely implemented: https://github.com/tc39/proposal-global/issues/20. diff -Nru duktape-2.0.0/config/config-options/DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT.yaml duktape-2.1.1/config/config-options/DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT.yaml --- duktape-2.0.0/config/config-options/DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT.yaml 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,14 @@ +define: DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT +introduced: 2.1.0 +default: 2 +tags: + - performance + - lowmemory +description: > + Abandon array part if its density is below L. The limit L is expressed as + a .3 fixed point point, e.g. 2 means 2/8 = 25%. + + The default limit is quite low: one array entry with packed duk_tval is 8 + bytes whereas one normal entry is 4+1+8 = 13 bytes without a hash entry, + and 17-21 bytes with a hash entry (load factor 0.5-1.0). So the array part + shouldn't be abandoned very easily from a footprint point of view. diff -Nru duktape-2.0.0/config/config-options/DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT.yaml duktape-2.1.1/config/config-options/DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT.yaml --- duktape-2.0.0/config/config-options/DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT.yaml 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,13 @@ +define: DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT +introduced: 2.1.0 +default: 9 +tags: + - performance + - lowmemory +description: > + Skip abandon check in object array part resize if new_size < L * old_size. + The limit L is expressed as a .3 fixed point value, e.g. 9 means 9/8 = + 112.5% of current size. + + This is rather technical and you should only change the parameter if you've + looked at the internals. diff -Nru duktape-2.0.0/config/config-options/DUK_USE_HOBJECT_ARRAY_MINGROW_ADD.yaml duktape-2.1.1/config/config-options/DUK_USE_HOBJECT_ARRAY_MINGROW_ADD.yaml --- duktape-2.0.0/config/config-options/DUK_USE_HOBJECT_ARRAY_MINGROW_ADD.yaml 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_HOBJECT_ARRAY_MINGROW_ADD.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,8 @@ +define: DUK_USE_HOBJECT_ARRAY_MINGROW_ADD +introduced: 2.1.0 +default: 16 +tags: + - performance +description: > + Technical internal parameter, see sources for details. Only adjust if + you've looked at the internals. diff -Nru duktape-2.0.0/config/config-options/DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR.yaml duktape-2.1.1/config/config-options/DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR.yaml --- duktape-2.0.0/config/config-options/DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR.yaml 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,8 @@ +define: DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR +introduced: 2.1.0 +default: 8 +tags: + - performance +description: > + Technical internal parameter, see sources for details. Only adjust if + you've looked at the internals. diff -Nru duktape-2.0.0/config/config-options/DUK_USE_HOBJECT_ENTRY_MINGROW_ADD.yaml duktape-2.1.1/config/config-options/DUK_USE_HOBJECT_ENTRY_MINGROW_ADD.yaml --- duktape-2.0.0/config/config-options/DUK_USE_HOBJECT_ENTRY_MINGROW_ADD.yaml 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_HOBJECT_ENTRY_MINGROW_ADD.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,8 @@ +define: DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR +introduced: 2.1.0 +default: 8 +tags: + - performance +description: > + Technical internal parameter, see sources for details. Only adjust if + you've looked at the internals. diff -Nru duktape-2.0.0/config/config-options/DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR.yaml duktape-2.1.1/config/config-options/DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR.yaml --- duktape-2.0.0/config/config-options/DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR.yaml 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,8 @@ +define: DUK_USE_HOBJECT_ENTRY_MINGROW_ADD +introduced: 2.1.0 +default: 16 +tags: + - performance +description: > + Technical internal parameter, see sources for details. Only adjust if + you've looked at the internals. diff -Nru duktape-2.0.0/config/config-options/DUK_USE_HOBJECT_HASH_PART.yaml duktape-2.1.1/config/config-options/DUK_USE_HOBJECT_HASH_PART.yaml --- duktape-2.0.0/config/config-options/DUK_USE_HOBJECT_HASH_PART.yaml 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_HOBJECT_HASH_PART.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -9,5 +9,3 @@ enabled unless the target is very low on memory. If DUK_USE_OBJSIZES16 is defined, this option must not be defined. - -# FIXME: expose property limit for hash table as a DUK_USE_xxx flag? diff -Nru duktape-2.0.0/config/config-options/DUK_USE_HOBJECT_HASH_PROP_LIMIT.yaml duktape-2.1.1/config/config-options/DUK_USE_HOBJECT_HASH_PROP_LIMIT.yaml --- duktape-2.0.0/config/config-options/DUK_USE_HOBJECT_HASH_PROP_LIMIT.yaml 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_HOBJECT_HASH_PROP_LIMIT.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,20 @@ +define: DUK_USE_HOBJECT_HASH_PROP_LIMIT +introduced: 2.1.0 +default: 8 +tags: + - performance + - lowmemory +description: > + Minimum number of properties needed for a hash part to be included in the + object property table. This limit is checked whenever an object is resized. + + A hash part improves property lookup performance even for small objects, + starting from roughly 4 properties. However, this ignores the cost of + setting up and managing the hash part, which is offset only if property + lookups made through the hash part can offset the setup cost. A hash part + is worth it for heavily accessed small objects or large objects (even those + accessed quite infrequently). The limit doesn't take into account property + access frequency, so it is necessarily a compromise. + + A lower value improves performance (a value as low a 4-8 can be useful) + while a higher value conserves memory. diff -Nru duktape-2.0.0/config/config-options/DUK_USE_HTML_COMMENTS.yaml duktape-2.1.1/config/config-options/DUK_USE_HTML_COMMENTS.yaml --- duktape-2.0.0/config/config-options/DUK_USE_HTML_COMMENTS.yaml 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_HTML_COMMENTS.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,7 @@ +define: DUK_USE_HTML_COMMENTS +introduced: 2.1.0 +default: true +tags: + - ecmascript2015 +description: > + Enable ES2015 Annex B.1.3 HTML comment syntax. diff -Nru duktape-2.0.0/config/config-options/DUK_USE_INJECT_HEAP_ALLOC_ERROR.yaml duktape-2.1.1/config/config-options/DUK_USE_INJECT_HEAP_ALLOC_ERROR.yaml --- duktape-2.0.0/config/config-options/DUK_USE_INJECT_HEAP_ALLOC_ERROR.yaml 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_INJECT_HEAP_ALLOC_ERROR.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,7 @@ +define: DUK_USE_INJECT_HEAP_ALLOC_ERROR +introduced: 2.1.0 +default: false +tags: + - development +description: > + Force heap allocation to fail, value indicates the desired error position. diff -Nru duktape-2.0.0/config/config-options/DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE.yaml duktape-2.1.1/config/config-options/DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE.yaml --- duktape-2.0.0/config/config-options/DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE.yaml 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -1,5 +1,6 @@ define: DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE introduced: 1.3.0 +removed: 2.1.0 related: - DUK_USE_GC_TORTURE - DUK_USE_REFZERO_FINALIZER_TORTURE diff -Nru duktape-2.0.0/config/config-options/DUK_USE_MS_STRINGTABLE_RESIZE.yaml duktape-2.1.1/config/config-options/DUK_USE_MS_STRINGTABLE_RESIZE.yaml --- duktape-2.0.0/config/config-options/DUK_USE_MS_STRINGTABLE_RESIZE.yaml 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_MS_STRINGTABLE_RESIZE.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -1,5 +1,6 @@ define: DUK_USE_MS_STRINGTABLE_RESIZE introduced: 1.0.0 +removed: 2.1.0 default: true tags: - gc diff -Nru duktape-2.0.0/config/config-options/DUK_USE_REFCOUNT16.yaml duktape-2.1.1/config/config-options/DUK_USE_REFCOUNT16.yaml --- duktape-2.0.0/config/config-options/DUK_USE_REFCOUNT16.yaml 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_REFCOUNT16.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -4,5 +4,6 @@ tags: - lowmemory - experimental + - gc description: > Use a 16-bit reference count field (for low memory environments). diff -Nru duktape-2.0.0/config/config-options/DUK_USE_REFCOUNT32.yaml duktape-2.1.1/config/config-options/DUK_USE_REFCOUNT32.yaml --- duktape-2.0.0/config/config-options/DUK_USE_REFCOUNT32.yaml 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_REFCOUNT32.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,12 @@ +define: DUK_USE_REFCOUNT32 +introduced: 2.1.0 +default: true +tags: + - gc +description: > + Use a 32-bit reference count field. + + While on some 64-bit systems it's theoretically possible to wrap a 32-bit + counter field, assuming a 16-byte duk_tval the Duktape heap would have to + be larger than 64GB for that to happen. Because of this the default is to + use a 32-bit refcount field. diff -Nru duktape-2.0.0/config/config-options/DUK_USE_REFZERO_FINALIZER_TORTURE.yaml duktape-2.1.1/config/config-options/DUK_USE_REFZERO_FINALIZER_TORTURE.yaml --- duktape-2.0.0/config/config-options/DUK_USE_REFZERO_FINALIZER_TORTURE.yaml 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_REFZERO_FINALIZER_TORTURE.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -1,5 +1,6 @@ define: DUK_USE_REFZERO_FINALIZER_TORTURE introduced: 1.3.0 +removed: 2.1.0 related: - DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE default: false diff -Nru duktape-2.0.0/config/config-options/DUK_USE_SHEBANG_COMMENTS.yaml duktape-2.1.1/config/config-options/DUK_USE_SHEBANG_COMMENTS.yaml --- duktape-2.0.0/config/config-options/DUK_USE_SHEBANG_COMMENTS.yaml 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_SHEBANG_COMMENTS.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,8 @@ +define: DUK_USE_SHEBANG_COMMENTS +introduced: 2.1.0 +default: true +tags: + - ecmascript2015 +description: > + Support parsing of a "shebang" comment ('#!...') on the first line of + source text. diff -Nru duktape-2.0.0/config/config-options/DUK_USE_STRTAB_CHAIN_SIZE.yaml duktape-2.1.1/config/config-options/DUK_USE_STRTAB_CHAIN_SIZE.yaml --- duktape-2.0.0/config/config-options/DUK_USE_STRTAB_CHAIN_SIZE.yaml 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_STRTAB_CHAIN_SIZE.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -1,5 +1,6 @@ define: DUK_USE_STRTAB_CHAIN_SIZE introduced: 1.1.0 +removed: 2.1.0 requires: - DUK_USE_STRTAB_CHAIN default: false diff -Nru duktape-2.0.0/config/config-options/DUK_USE_STRTAB_CHAIN.yaml duktape-2.1.1/config/config-options/DUK_USE_STRTAB_CHAIN.yaml --- duktape-2.0.0/config/config-options/DUK_USE_STRTAB_CHAIN.yaml 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_STRTAB_CHAIN.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -1,5 +1,6 @@ define: DUK_USE_STRTAB_CHAIN introduced: 1.1.0 +removed: 2.1.0 related: - DUK_USE_STRTAB_CHAIN_SIZE default: false diff -Nru duktape-2.0.0/config/config-options/DUK_USE_STRTAB_GROW_LIMIT.yaml duktape-2.1.1/config/config-options/DUK_USE_STRTAB_GROW_LIMIT.yaml --- duktape-2.0.0/config/config-options/DUK_USE_STRTAB_GROW_LIMIT.yaml 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_STRTAB_GROW_LIMIT.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,10 @@ +define: DUK_USE_STRTAB_GROW_LIMIT +introduced: 2.1.0 +default: 17 # 17/16 = 1.0625 +tags: + - performance + - lowmemory +description: > + Grow top level strtable allocation when load factor reaches this value. + Expressed as a .4 fixed point; the load factor is computed as + floor((count / size) * 16.0), e.g. 32 means a load factor of 2.0. diff -Nru duktape-2.0.0/config/config-options/DUK_USE_STRTAB_MAXSIZE.yaml duktape-2.1.1/config/config-options/DUK_USE_STRTAB_MAXSIZE.yaml --- duktape-2.0.0/config/config-options/DUK_USE_STRTAB_MAXSIZE.yaml 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_STRTAB_MAXSIZE.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,13 @@ +define: DUK_USE_STRTAB_MAXSIZE +introduced: 2.1.0 +default: 268435456 +tags: + - performance + - lowmemory +description: > + Maximum size for Duktape heap string table, must be 2^N, and small enough + so that if the value is multiplied by sizeof(duk_hstring *) it won't overflow + duk_size_t. + + To avoid resizing the strtable at all, set DUK_USE_STRTAB_MINSIZE and + DUK_USE_STRTAB_MAXSIZE to the same value. diff -Nru duktape-2.0.0/config/config-options/DUK_USE_STRTAB_MINSIZE.yaml duktape-2.1.1/config/config-options/DUK_USE_STRTAB_MINSIZE.yaml --- duktape-2.0.0/config/config-options/DUK_USE_STRTAB_MINSIZE.yaml 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_STRTAB_MINSIZE.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,9 @@ +define: DUK_USE_STRTAB_MINSIZE +introduced: 2.1.0 +default: 1024 +tags: + - performance + - lowmemory +description: > + Minimum size for Duktape heap string table, must be 2^N, and should never + be lower than 64. diff -Nru duktape-2.0.0/config/config-options/DUK_USE_STRTAB_PROBE.yaml duktape-2.1.1/config/config-options/DUK_USE_STRTAB_PROBE.yaml --- duktape-2.0.0/config/config-options/DUK_USE_STRTAB_PROBE.yaml 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_STRTAB_PROBE.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -1,5 +1,6 @@ define: DUK_USE_STRTAB_PROBE introduced: 1.1.0 +removed: 2.1.0 default: true tags: - lowmemory diff -Nru duktape-2.0.0/config/config-options/DUK_USE_STRTAB_PTRCOMP.yaml duktape-2.1.1/config/config-options/DUK_USE_STRTAB_PTRCOMP.yaml --- duktape-2.0.0/config/config-options/DUK_USE_STRTAB_PTRCOMP.yaml 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_STRTAB_PTRCOMP.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,14 @@ +define: DUK_USE_STRTAB_PTRCOMP +introduced: 2.1.0 +default: false +requires: + - DUK_USE_HEAPPTR16 +tags: + - performance + - lowmemory +description: > + Pointer compress the top level heap->strtable[] string table. On 32-bit + targets this saves 2 bytes per entry, e.g. for 256 entries 0.5kB. However, + the additional pointer compression code increases footprint by 200-300 + bytes. The option also reduces performance a little bit, so this should + be enabled when RAM is much more constrained than ROM. diff -Nru duktape-2.0.0/config/config-options/DUK_USE_STRTAB_RESIZE_CHECK_MASK.yaml duktape-2.1.1/config/config-options/DUK_USE_STRTAB_RESIZE_CHECK_MASK.yaml --- duktape-2.0.0/config/config-options/DUK_USE_STRTAB_RESIZE_CHECK_MASK.yaml 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_STRTAB_RESIZE_CHECK_MASK.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,16 @@ +define: DUK_USE_STRTAB_RESIZE_CHECK_MASK +introduced: 2.1.0 +default: 255 +tags: + - performance + - lowmemory +description: > + Somewhat technical: bit mask (must be 2^N-1) used against heap->st_count to + determine the interval between string table resize checks. A resize check + is made when heap->st_count & DUK_USE_STRTAB_RESIZE_CHECK_MASK is zero. + + A large value makes string table grow/shrink checks less frequent. Usually + this has very little practical impact on memory performance. There are + corner cases, such as dereferencing a large number of strings simultaneously, + where this parameter affects how many new strings need to be inserted before + the string table shrinks to a more appropriate size. diff -Nru duktape-2.0.0/config/config-options/DUK_USE_STRTAB_SHRINK_LIMIT.yaml duktape-2.1.1/config/config-options/DUK_USE_STRTAB_SHRINK_LIMIT.yaml --- duktape-2.0.0/config/config-options/DUK_USE_STRTAB_SHRINK_LIMIT.yaml 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_STRTAB_SHRINK_LIMIT.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,10 @@ +define: DUK_USE_STRTAB_SHRINK_LIMIT +introduced: 2.1.0 +default: 6 # 6/16 = 0.375 +tags: + - performance + - lowmemory +description: > + Shrink top level strtable allocation when load factor reaches this value. + Expressed as a .4 fixed point; the load factor is computed as + floor((count / size) * 16.0), e.g. 8 means a load factor of 0.5. diff -Nru duktape-2.0.0/config/config-options/DUK_USE_STRTAB_TORTURE.yaml duktape-2.1.1/config/config-options/DUK_USE_STRTAB_TORTURE.yaml --- duktape-2.0.0/config/config-options/DUK_USE_STRTAB_TORTURE.yaml 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/config-options/DUK_USE_STRTAB_TORTURE.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,9 @@ +define: DUK_USE_STRTAB_TORTURE +introduced: 2.1.0 +default: false +tags: + - torture +description: > + Resize string table (grow, shrink back) for every intern. Ensures string + table chaining is correct, and resize side effects are exercised on every + resize. diff -Nru duktape-2.0.0/config/examples/debugger_support.yaml duktape-2.1.1/config/examples/debugger_support.yaml --- duktape-2.0.0/config/examples/debugger_support.yaml 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/examples/debugger_support.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -3,7 +3,6 @@ DUK_USE_DEBUGGER_SUPPORT: true # Basic set of Notifys. -DUK_USE_DEBUGGER_FWD_LOGGING: true DUK_USE_DEBUGGER_THROW_NOTIFY: true # Automatically pause on an uncaught error about to be thrown. diff -Nru duktape-2.0.0/config/examples/low_memory.yaml duktape-2.1.1/config/examples/low_memory.yaml --- duktape-2.0.0/config/examples/low_memory.yaml 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/examples/low_memory.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -41,14 +41,27 @@ #DUK_USE_REGEXP_SUPPORT: false DUK_USE_DEBUG_BUFSIZE: 2048 DUK_USE_LIGHTFUNC_BUILTINS: true -DUK_USE_STRTAB_CHAIN: true -DUK_USE_STRTAB_PROBE: false -DUK_USE_STRTAB_CHAIN_SIZE: 128 + +# Using the same minsize and maxsize drops code footprint by around 400 bytes +# (string table resize code is omitted). Enabling DUK_USE_STRTAB_PTRCOMP +# saves some RAM (two bytes per strtab entry) at the cost of 200-300 bytes of +# code footprint. +DUK_USE_STRTAB_MINSIZE: 128 +DUK_USE_STRTAB_MAXSIZE: 128 +DUK_USE_STRTAB_SHRINK_LIMIT: 0 # doesn't matter if minsize==masize +DUK_USE_STRTAB_GROW_LIMIT: 65536 # -""- +DUK_USE_STRTAB_RESIZE_CHECK_MASK: 255 # -""- +#DUK_USE_STRTAB_PTRCOMP: true # sometimes useful with pointer compression DUK_USE_HSTRING_ARRIDX: false +# Only add a hash table for quite large objects to conserve memory. Even +# lower memory targets usually drop hash part support entirely. +DUK_USE_HOBJECT_HASH_PROP_LIMIT: 64 + # Consider using pointer compression, see doc/low-memory.rst. #DUK_USE_REFCOUNT16: true +#DUK_USE_REFCOUNT32: false #DUK_USE_STRHASH16: true #DUK_USE_STRLEN16: true #DUK_USE_BUFLEN16: true @@ -98,6 +111,8 @@ DUK_USE_ES7_EXP_OPERATOR: false # pulls in pow() DUK_USE_ENCODING_BUILTINS: false DUK_USE_ES6_UNICODE_ESCAPE: false +DUK_USE_HTML_COMMENTS: false +DUK_USE_SHEBANG_COMMENTS: false DUK_USE_REFLECT_BUILTIN: false DUK_USE_ES6: false DUK_USE_SYMBOL_BUILTIN: false diff -Nru duktape-2.0.0/config/header-snippets/compiler_fillins.h.in duktape-2.1.1/config/header-snippets/compiler_fillins.h.in --- duktape-2.0.0/config/header-snippets/compiler_fillins.h.in 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/header-snippets/compiler_fillins.h.in 2017-07-28 22:05:08.000000000 +0000 @@ -38,7 +38,8 @@ /* Macro for suppressing warnings for potentially unreferenced variables. * The variables can be actually unreferenced or unreferenced in some * specific cases only; for instance, if a variable is only debug printed, - * it is unreferenced when debug printing is disabled. + * it is unreferenced when debug printing is disabled. May cause warnings + * for volatile arguments. */ #define DUK_UNREF(x) do { (void) (x); } while (0) #endif @@ -80,6 +81,13 @@ #define DUK_ALWAYS_INLINE /*nop*/ #endif +#if !defined(DUK_HOT) +#define DUK_HOT /*nop*/ +#endif +#if !defined(DUK_COLD) +#define DUK_COLD /*nop*/ +#endif + #if !defined(DUK_EXTERNAL_DECL) #define DUK_EXTERNAL_DECL extern #endif diff -Nru duktape-2.0.0/config/header-snippets/date_provider.h.in duktape-2.1.1/config/header-snippets/date_provider.h.in --- duktape-2.0.0/config/header-snippets/date_provider.h.in 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/header-snippets/date_provider.h.in 2017-07-28 22:05:08.000000000 +0000 @@ -22,10 +22,12 @@ #if defined(DUK_USE_DATE_GET_LOCAL_TZOFFSET) /* External provider already defined. */ -#elif defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME) +#elif defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S) || defined(DUK_USE_DATE_TZO_GMTIME) #define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_gmtime((d)) #elif defined(DUK_USE_DATE_TZO_WINDOWS) #define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows((d)) +#elif defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST) +#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows_no_dst((d)) #else #error no provider for DUK_USE_DATE_GET_LOCAL_TZOFFSET() #endif diff -Nru duktape-2.0.0/config/header-snippets/platform_fillins.h.in duktape-2.1.1/config/header-snippets/platform_fillins.h.in --- duktape-2.0.0/config/header-snippets/platform_fillins.h.in 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/header-snippets/platform_fillins.h.in 2017-07-28 22:05:08.000000000 +0000 @@ -113,7 +113,8 @@ #define DUK_DOUBLE_INFINITY (__builtin_inf()) #elif defined(INFINITY) #define DUK_DOUBLE_INFINITY ((double) INFINITY) -#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) +#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) && \ + !defined(DUK_F_OLD_SOLARIS) && !defined(DUK_F_AIX) #define DUK_DOUBLE_INFINITY (1.0 / 0.0) #else /* In VBCC (1.0 / 0.0) results in a warning and 0.0 instead of infinity. @@ -129,7 +130,8 @@ #undef DUK_USE_COMPUTED_NAN #if defined(NAN) #define DUK_DOUBLE_NAN NAN -#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) +#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) && \ + !defined(DUK_F_OLD_SOLARIS) && !defined(DUK_F_AIX) #define DUK_DOUBLE_NAN (0.0 / 0.0) #else /* In VBCC (0.0 / 0.0) results in a warning and 0.0 instead of NaN. @@ -178,6 +180,9 @@ * To be safe, use replacements. */ #define DUK_F_USE_REPL_ALL +#elif defined(DUK_F_AIX) +/* Older versions may be missing isnan(), etc. */ +#define DUK_F_USE_REPL_ALL #endif #if defined(DUK_F_USE_REPL_ALL) @@ -266,9 +271,10 @@ /* The functions below exist only in C99/C++11 or later and need a workaround * for platforms that don't include them. MSVC isn't detected as C99, but * these functions also exist in MSVC 2013 and later so include a clause for - * that too. + * that too. Android doesn't have log2; disable all of these for Android. */ -#if defined(DUK_F_C99) || defined(DUK_F_CPP11) || (defined(_MSC_VER) && (_MSC_VER >= 1800)) +#if (defined(DUK_F_C99) || defined(DUK_F_CPP11) || (defined(_MSC_VER) && (_MSC_VER >= 1800))) && \ + !defined(DUK_F_ANDROID) && !defined(DUK_F_MINT) #if !defined(DUK_CBRT) #define DUK_CBRT cbrt #endif @@ -281,7 +287,7 @@ #if !defined(DUK_TRUNC) #define DUK_TRUNC trunc #endif -#endif /* DUK_F_C99 */ +#endif /* DUK_F_C99 etc */ /* NetBSD 6.0 x86 (at least) has a few problems with pow() semantics, * see test-bug-netbsd-math-pow.js. MinGW has similar (but different) diff -Nru duktape-2.0.0/config/header-snippets/types1.h.in duktape-2.1.1/config/header-snippets/types1.h.in --- duktape-2.0.0/config/header-snippets/types1.h.in 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/header-snippets/types1.h.in 2017-07-28 22:05:08.000000000 +0000 @@ -47,10 +47,14 @@ #if defined(DUK_F_X86) || defined(DUK_F_X32) || \ defined(DUK_F_M68K) || defined(DUK_F_PPC32) || \ defined(DUK_F_BCC) || \ - (defined(__WORDSIZE) && (__WORDSIZE == 32)) + (defined(__WORDSIZE) && (__WORDSIZE == 32)) || \ + ((defined(DUK_F_OLD_SOLARIS) || defined(DUK_F_AIX) || \ + defined(DUK_F_HPUX)) && defined(_ILP32)) #define DUK_F_32BIT_PTRS #elif defined(DUK_F_X64) || \ - (defined(__WORDSIZE) && (__WORDSIZE == 64)) + (defined(__WORDSIZE) && (__WORDSIZE == 64)) || \ + ((defined(DUK_F_OLD_SOLARIS) || defined(DUK_F_AIX) || \ + defined(DUK_F_HPUX)) && defined(_LP64)) #define DUK_F_64BIT_PTRS #else /* not sure, not needed with C99 anyway */ diff -Nru duktape-2.0.0/config/header-snippets/types.h.in duktape-2.1.1/config/header-snippets/types.h.in --- duktape-2.0.0/config/header-snippets/types.h.in 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/header-snippets/types.h.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,541 +0,0 @@ -/* - * Wrapper typedefs and constants for integer types, also sanity check types. - * - * C99 typedefs are quite good but not always available, and we want to avoid - * forcibly redefining the C99 typedefs. So, there are Duktape wrappers for - * all C99 typedefs and Duktape code should only use these typedefs. Type - * detection when C99 is not supported is best effort and may end up detecting - * some types incorrectly. - * - * Pointer sizes are a portability problem: pointers to different types may - * have a different size and function pointers are very difficult to manage - * portably. - * - * http://en.wikipedia.org/wiki/C_data_types#Fixed-width_integer_types - * - * Note: there's an interesting corner case when trying to define minimum - * signed integer value constants which leads to the current workaround of - * defining e.g. -0x80000000 as (-0x7fffffffL - 1L). See doc/code-issues.txt - * for a longer discussion. - * - * Note: avoid typecasts and computations in macro integer constants as they - * can then no longer be used in macro relational expressions (such as - * #if DUK_SIZE_MAX < 0xffffffffUL). There is internal code which relies on - * being able to compare DUK_SIZE_MAX against a limit. - */ - -/* XXX: add feature options to force basic types from outside? */ - -#if !defined(INT_MAX) -#error INT_MAX not defined -#endif - -/* Check that architecture is two's complement, standard C allows e.g. - * INT_MIN to be -2**31+1 (instead of -2**31). - */ -#if defined(INT_MAX) && defined(INT_MIN) -#if INT_MAX != -(INT_MIN + 1) -#error platform does not seem complement of two -#endif -#else -#error cannot check complement of two -#endif - -/* Pointer size determination based on architecture. - * XXX: unsure about BCC correctness. - */ -#if defined(DUK_F_X86) || defined(DUK_F_X32) || \ - defined(DUK_F_BCC) || \ - (defined(__WORDSIZE) && (__WORDSIZE == 32)) -#define DUK_F_32BIT_PTRS -#elif defined(DUK_F_X64) || \ - (defined(__WORDSIZE) && (__WORDSIZE == 64)) -#define DUK_F_64BIT_PTRS -#else -/* not sure, not needed with C99 anyway */ -#endif - -/* Intermediate define for 'have inttypes.h' */ -#undef DUK_F_HAVE_INTTYPES -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ - !(defined(DUK_F_AMIGAOS) && defined(DUK_F_VBCC)) -/* vbcc + AmigaOS has C99 but no inttypes.h */ -#define DUK_F_HAVE_INTTYPES -#elif defined(__cplusplus) && (__cplusplus >= 201103L) -/* C++11 apparently ratified stdint.h */ -#define DUK_F_HAVE_INTTYPES -#endif - -/* Basic integer typedefs and limits, preferably from inttypes.h, otherwise - * through automatic detection. - */ -#if defined(DUK_F_HAVE_INTTYPES) -/* C99 or compatible */ - -#define DUK_F_HAVE_64BIT -#include - -typedef uint8_t duk_uint8_t; -typedef int8_t duk_int8_t; -typedef uint16_t duk_uint16_t; -typedef int16_t duk_int16_t; -typedef uint32_t duk_uint32_t; -typedef int32_t duk_int32_t; -typedef uint64_t duk_uint64_t; -typedef int64_t duk_int64_t; -typedef uint_least8_t duk_uint_least8_t; -typedef int_least8_t duk_int_least8_t; -typedef uint_least16_t duk_uint_least16_t; -typedef int_least16_t duk_int_least16_t; -typedef uint_least32_t duk_uint_least32_t; -typedef int_least32_t duk_int_least32_t; -typedef uint_least64_t duk_uint_least64_t; -typedef int_least64_t duk_int_least64_t; -typedef uint_fast8_t duk_uint_fast8_t; -typedef int_fast8_t duk_int_fast8_t; -typedef uint_fast16_t duk_uint_fast16_t; -typedef int_fast16_t duk_int_fast16_t; -typedef uint_fast32_t duk_uint_fast32_t; -typedef int_fast32_t duk_int_fast32_t; -typedef uint_fast64_t duk_uint_fast64_t; -typedef int_fast64_t duk_int_fast64_t; -typedef uintptr_t duk_uintptr_t; -typedef intptr_t duk_intptr_t; -typedef uintmax_t duk_uintmax_t; -typedef intmax_t duk_intmax_t; - -#define DUK_UINT8_MIN 0 -#define DUK_UINT8_MAX UINT8_MAX -#define DUK_INT8_MIN INT8_MIN -#define DUK_INT8_MAX INT8_MAX -#define DUK_UINT_LEAST8_MIN 0 -#define DUK_UINT_LEAST8_MAX UINT_LEAST8_MAX -#define DUK_INT_LEAST8_MIN INT_LEAST8_MIN -#define DUK_INT_LEAST8_MAX INT_LEAST8_MAX -#define DUK_UINT_FAST8_MIN 0 -#define DUK_UINT_FAST8_MAX UINT_FAST8_MAX -#define DUK_INT_FAST8_MIN INT_FAST8_MIN -#define DUK_INT_FAST8_MAX INT_FAST8_MAX -#define DUK_UINT16_MIN 0 -#define DUK_UINT16_MAX UINT16_MAX -#define DUK_INT16_MIN INT16_MIN -#define DUK_INT16_MAX INT16_MAX -#define DUK_UINT_LEAST16_MIN 0 -#define DUK_UINT_LEAST16_MAX UINT_LEAST16_MAX -#define DUK_INT_LEAST16_MIN INT_LEAST16_MIN -#define DUK_INT_LEAST16_MAX INT_LEAST16_MAX -#define DUK_UINT_FAST16_MIN 0 -#define DUK_UINT_FAST16_MAX UINT_FAST16_MAX -#define DUK_INT_FAST16_MIN INT_FAST16_MIN -#define DUK_INT_FAST16_MAX INT_FAST16_MAX -#define DUK_UINT32_MIN 0 -#define DUK_UINT32_MAX UINT32_MAX -#define DUK_INT32_MIN INT32_MIN -#define DUK_INT32_MAX INT32_MAX -#define DUK_UINT_LEAST32_MIN 0 -#define DUK_UINT_LEAST32_MAX UINT_LEAST32_MAX -#define DUK_INT_LEAST32_MIN INT_LEAST32_MIN -#define DUK_INT_LEAST32_MAX INT_LEAST32_MAX -#define DUK_UINT_FAST32_MIN 0 -#define DUK_UINT_FAST32_MAX UINT_FAST32_MAX -#define DUK_INT_FAST32_MIN INT_FAST32_MIN -#define DUK_INT_FAST32_MAX INT_FAST32_MAX -#define DUK_UINT64_MIN 0 -#define DUK_UINT64_MAX UINT64_MAX -#define DUK_INT64_MIN INT64_MIN -#define DUK_INT64_MAX INT64_MAX -#define DUK_UINT_LEAST64_MIN 0 -#define DUK_UINT_LEAST64_MAX UINT_LEAST64_MAX -#define DUK_INT_LEAST64_MIN INT_LEAST64_MIN -#define DUK_INT_LEAST64_MAX INT_LEAST64_MAX -#define DUK_UINT_FAST64_MIN 0 -#define DUK_UINT_FAST64_MAX UINT_FAST64_MAX -#define DUK_INT_FAST64_MIN INT_FAST64_MIN -#define DUK_INT_FAST64_MAX INT_FAST64_MAX - -#define DUK_UINTPTR_MIN 0 -#define DUK_UINTPTR_MAX UINTPTR_MAX -#define DUK_INTPTR_MIN INTPTR_MIN -#define DUK_INTPTR_MAX INTPTR_MAX - -#define DUK_UINTMAX_MIN 0 -#define DUK_UINTMAX_MAX UINTMAX_MAX -#define DUK_INTMAX_MIN INTMAX_MIN -#define DUK_INTMAX_MAX INTMAX_MAX - -#define DUK_SIZE_MIN 0 -#define DUK_SIZE_MAX SIZE_MAX - -#else /* C99 types */ - -/* When C99 types are not available, we use heuristic detection to get - * the basic 8, 16, 32, and (possibly) 64 bit types. The fast/least - * types are then assumed to be exactly the same for now: these could - * be improved per platform but C99 types are very often now available. - * 64-bit types are not available on all platforms; this is OK at least - * on 32-bit platforms. - * - * This detection code is necessarily a bit hacky and can provide typedefs - * and defines that won't work correctly on some exotic platform. - */ - -#if (defined(CHAR_BIT) && (CHAR_BIT == 8)) || \ - (defined(UCHAR_MAX) && (UCHAR_MAX == 255)) -typedef unsigned char duk_uint8_t; -typedef signed char duk_int8_t; -#else -#error cannot detect 8-bit type -#endif - -#if defined(USHRT_MAX) && (USHRT_MAX == 65535UL) -typedef unsigned short duk_uint16_t; -typedef signed short duk_int16_t; -#elif defined(UINT_MAX) && (UINT_MAX == 65535UL) -/* On some platforms int is 16-bit but long is 32-bit (e.g. PureC) */ -typedef unsigned int duk_uint16_t; -typedef signed int duk_int16_t; -#else -#error cannot detect 16-bit type -#endif - -#if defined(UINT_MAX) && (UINT_MAX == 4294967295UL) -typedef unsigned int duk_uint32_t; -typedef signed int duk_int32_t; -#elif defined(ULONG_MAX) && (ULONG_MAX == 4294967295UL) -/* On some platforms int is 16-bit but long is 32-bit (e.g. PureC) */ -typedef unsigned long duk_uint32_t; -typedef signed long duk_int32_t; -#else -#error cannot detect 32-bit type -#endif - -/* 64-bit type detection is a bit tricky. - * - * ULLONG_MAX is a standard define. __LONG_LONG_MAX__ and __ULONG_LONG_MAX__ - * are used by at least GCC (even if system headers don't provide ULLONG_MAX). - * Some GCC variants may provide __LONG_LONG_MAX__ but not __ULONG_LONG_MAX__. - * - * ULL / LL constants are rejected / warned about by some compilers, even if - * the compiler has a 64-bit type and the compiler/system headers provide an - * unsupported constant (ULL/LL)! Try to avoid using ULL / LL constants. - * As a side effect we can only check that e.g. ULONG_MAX is larger than 32 - * bits but can't be sure it is exactly 64 bits. Self tests will catch such - * cases. - */ -#undef DUK_F_HAVE_64BIT -#if !defined(DUK_F_HAVE_64BIT) && defined(ULONG_MAX) -#if (ULONG_MAX > 4294967295UL) -#define DUK_F_HAVE_64BIT -typedef unsigned long duk_uint64_t; -typedef signed long duk_int64_t; -#endif -#endif -#if !defined(DUK_F_HAVE_64BIT) && defined(ULLONG_MAX) -#if (ULLONG_MAX > 4294967295UL) -#define DUK_F_HAVE_64BIT -typedef unsigned long long duk_uint64_t; -typedef signed long long duk_int64_t; -#endif -#endif -#if !defined(DUK_F_HAVE_64BIT) && defined(__ULONG_LONG_MAX__) -#if (__ULONG_LONG_MAX__ > 4294967295UL) -#define DUK_F_HAVE_64BIT -typedef unsigned long long duk_uint64_t; -typedef signed long long duk_int64_t; -#endif -#endif -#if !defined(DUK_F_HAVE_64BIT) && defined(__LONG_LONG_MAX__) -#if (__LONG_LONG_MAX__ > 2147483647L) -#define DUK_F_HAVE_64BIT -typedef unsigned long long duk_uint64_t; -typedef signed long long duk_int64_t; -#endif -#endif -#if !defined(DUK_F_HAVE_64BIT) && \ - (defined(DUK_F_MINGW) || defined(DUK_F_MSVC)) -/* Both MinGW and MSVC have a 64-bit type. */ -#define DUK_F_HAVE_64BIT -typedef unsigned long duk_uint64_t; -typedef signed long duk_int64_t; -#endif -#if !defined(DUK_F_HAVE_64BIT) -/* cannot detect 64-bit type, not always needed so don't error */ -#endif - -typedef duk_uint8_t duk_uint_least8_t; -typedef duk_int8_t duk_int_least8_t; -typedef duk_uint16_t duk_uint_least16_t; -typedef duk_int16_t duk_int_least16_t; -typedef duk_uint32_t duk_uint_least32_t; -typedef duk_int32_t duk_int_least32_t; -typedef duk_uint8_t duk_uint_fast8_t; -typedef duk_int8_t duk_int_fast8_t; -typedef duk_uint16_t duk_uint_fast16_t; -typedef duk_int16_t duk_int_fast16_t; -typedef duk_uint32_t duk_uint_fast32_t; -typedef duk_int32_t duk_int_fast32_t; -#if defined(DUK_F_HAVE_64BIT) -typedef duk_uint64_t duk_uint_least64_t; -typedef duk_int64_t duk_int_least64_t; -typedef duk_uint64_t duk_uint_fast64_t; -typedef duk_int64_t duk_int_fast64_t; -#endif -#if defined(DUK_F_HAVE_64BIT) -typedef duk_uint64_t duk_uintmax_t; -typedef duk_int64_t duk_intmax_t; -#else -typedef duk_uint32_t duk_uintmax_t; -typedef duk_int32_t duk_intmax_t; -#endif - -/* Note: the funny looking computations for signed minimum 16-bit, 32-bit, and - * 64-bit values are intentional as the obvious forms (e.g. -0x80000000L) are - * -not- portable. See code-issues.txt for a detailed discussion. - */ -#define DUK_UINT8_MIN 0UL -#define DUK_UINT8_MAX 0xffUL -#define DUK_INT8_MIN (-0x80L) -#define DUK_INT8_MAX 0x7fL -#define DUK_UINT_LEAST8_MIN 0UL -#define DUK_UINT_LEAST8_MAX 0xffUL -#define DUK_INT_LEAST8_MIN (-0x80L) -#define DUK_INT_LEAST8_MAX 0x7fL -#define DUK_UINT_FAST8_MIN 0UL -#define DUK_UINT_FAST8_MAX 0xffUL -#define DUK_INT_FAST8_MIN (-0x80L) -#define DUK_INT_FAST8_MAX 0x7fL -#define DUK_UINT16_MIN 0UL -#define DUK_UINT16_MAX 0xffffUL -#define DUK_INT16_MIN (-0x7fffL - 1L) -#define DUK_INT16_MAX 0x7fffL -#define DUK_UINT_LEAST16_MIN 0UL -#define DUK_UINT_LEAST16_MAX 0xffffUL -#define DUK_INT_LEAST16_MIN (-0x7fffL - 1L) -#define DUK_INT_LEAST16_MAX 0x7fffL -#define DUK_UINT_FAST16_MIN 0UL -#define DUK_UINT_FAST16_MAX 0xffffUL -#define DUK_INT_FAST16_MIN (-0x7fffL - 1L) -#define DUK_INT_FAST16_MAX 0x7fffL -#define DUK_UINT32_MIN 0UL -#define DUK_UINT32_MAX 0xffffffffUL -#define DUK_INT32_MIN (-0x7fffffffL - 1L) -#define DUK_INT32_MAX 0x7fffffffL -#define DUK_UINT_LEAST32_MIN 0UL -#define DUK_UINT_LEAST32_MAX 0xffffffffUL -#define DUK_INT_LEAST32_MIN (-0x7fffffffL - 1L) -#define DUK_INT_LEAST32_MAX 0x7fffffffL -#define DUK_UINT_FAST32_MIN 0UL -#define DUK_UINT_FAST32_MAX 0xffffffffUL -#define DUK_INT_FAST32_MIN (-0x7fffffffL - 1L) -#define DUK_INT_FAST32_MAX 0x7fffffffL - -/* 64-bit constants. Since LL / ULL constants are not always available, - * use computed values. These values can't be used in preprocessor - * comparisons; flag them as such. - */ -#if defined(DUK_F_HAVE_64BIT) -#define DUK_UINT64_MIN ((duk_uint64_t) 0) -#define DUK_UINT64_MAX ((duk_uint64_t) -1) -#define DUK_INT64_MIN ((duk_int64_t) (~(DUK_UINT64_MAX >> 1))) -#define DUK_INT64_MAX ((duk_int64_t) (DUK_UINT64_MAX >> 1)) -#define DUK_UINT_LEAST64_MIN DUK_UINT64_MIN -#define DUK_UINT_LEAST64_MAX DUK_UINT64_MAX -#define DUK_INT_LEAST64_MIN DUK_INT64_MIN -#define DUK_INT_LEAST64_MAX DUK_INT64_MAX -#define DUK_UINT_FAST64_MIN DUK_UINT64_MIN -#define DUK_UINT_FAST64_MAX DUK_UINT64_MAX -#define DUK_INT_FAST64_MIN DUK_INT64_MIN -#define DUK_INT_FAST64_MAX DUK_INT64_MAX -#define DUK_UINT64_MIN_COMPUTED -#define DUK_UINT64_MAX_COMPUTED -#define DUK_INT64_MIN_COMPUTED -#define DUK_INT64_MAX_COMPUTED -#define DUK_UINT_LEAST64_MIN_COMPUTED -#define DUK_UINT_LEAST64_MAX_COMPUTED -#define DUK_INT_LEAST64_MIN_COMPUTED -#define DUK_INT_LEAST64_MAX_COMPUTED -#define DUK_UINT_FAST64_MIN_COMPUTED -#define DUK_UINT_FAST64_MAX_COMPUTED -#define DUK_INT_FAST64_MIN_COMPUTED -#define DUK_INT_FAST64_MAX_COMPUTED -#endif - -#if defined(DUK_F_HAVE_64BIT) -#define DUK_UINTMAX_MIN DUK_UINT64_MIN -#define DUK_UINTMAX_MAX DUK_UINT64_MAX -#define DUK_INTMAX_MIN DUK_INT64_MIN -#define DUK_INTMAX_MAX DUK_INT64_MAX -#define DUK_UINTMAX_MIN_COMPUTED -#define DUK_UINTMAX_MAX_COMPUTED -#define DUK_INTMAX_MIN_COMPUTED -#define DUK_INTMAX_MAX_COMPUTED -#else -#define DUK_UINTMAX_MIN 0UL -#define DUK_UINTMAX_MAX 0xffffffffUL -#define DUK_INTMAX_MIN (-0x7fffffffL - 1L) -#define DUK_INTMAX_MAX 0x7fffffffL -#endif - -/* This detection is not very reliable. */ -#if defined(DUK_F_32BIT_PTRS) -typedef duk_int32_t duk_intptr_t; -typedef duk_uint32_t duk_uintptr_t; -#define DUK_UINTPTR_MIN DUK_UINT32_MIN -#define DUK_UINTPTR_MAX DUK_UINT32_MAX -#define DUK_INTPTR_MIN DUK_INT32_MIN -#define DUK_INTPTR_MAX DUK_INT32_MAX -#elif defined(DUK_F_64BIT_PTRS) && defined(DUK_F_HAVE_64BIT) -typedef duk_int64_t duk_intptr_t; -typedef duk_uint64_t duk_uintptr_t; -#define DUK_UINTPTR_MIN DUK_UINT64_MIN -#define DUK_UINTPTR_MAX DUK_UINT64_MAX -#define DUK_INTPTR_MIN DUK_INT64_MIN -#define DUK_INTPTR_MAX DUK_INT64_MAX -#define DUK_UINTPTR_MIN_COMPUTED -#define DUK_UINTPTR_MAX_COMPUTED -#define DUK_INTPTR_MIN_COMPUTED -#define DUK_INTPTR_MAX_COMPUTED -#else -#error cannot determine intptr type -#endif - -/* SIZE_MAX may be missing so use an approximate value for it. */ -#undef DUK_SIZE_MAX_COMPUTED -#if !defined(SIZE_MAX) -#define DUK_SIZE_MAX_COMPUTED -#define SIZE_MAX ((size_t) (-1)) -#endif -#define DUK_SIZE_MIN 0 -#define DUK_SIZE_MAX SIZE_MAX - -#endif /* C99 types */ - -/* A few types are assumed to always exist. */ -typedef size_t duk_size_t; -typedef ptrdiff_t duk_ptrdiff_t; - -/* The best type for an "all around int" in Duktape internals is "at least - * 32 bit signed integer" which is most convenient. Same for unsigned type. - * Prefer 'int' when large enough, as it is almost always a convenient type. - */ -#if defined(UINT_MAX) && (UINT_MAX >= 0xffffffffUL) -typedef int duk_int_t; -typedef unsigned int duk_uint_t; -#define DUK_INT_MIN INT_MIN -#define DUK_INT_MAX INT_MAX -#define DUK_UINT_MIN 0 -#define DUK_UINT_MAX UINT_MAX -#else -typedef duk_int_fast32_t duk_int_t; -typedef duk_uint_fast32_t duk_uint_t; -#define DUK_INT_MIN DUK_INT_FAST32_MIN -#define DUK_INT_MAX DUK_INT_FAST32_MAX -#define DUK_UINT_MIN DUK_UINT_FAST32_MIN -#define DUK_UINT_MAX DUK_UINT_FAST32_MAX -#endif - -/* Same as 'duk_int_t' but guaranteed to be a 'fast' variant if this - * distinction matters for the CPU. These types are used mainly in the - * executor where it might really matter. - */ -typedef duk_int_fast32_t duk_int_fast_t; -typedef duk_uint_fast32_t duk_uint_fast_t; -#define DUK_INT_FAST_MIN DUK_INT_FAST32_MIN -#define DUK_INT_FAST_MAX DUK_INT_FAST32_MAX -#define DUK_UINT_FAST_MIN DUK_UINT_FAST32_MIN -#define DUK_UINT_FAST_MAX DUK_UINT_FAST32_MAX - -/* Small integers (16 bits or more) can fall back to the 'int' type, but - * have a typedef so they are marked "small" explicitly. - */ -typedef int duk_small_int_t; -typedef unsigned int duk_small_uint_t; -#define DUK_SMALL_INT_MIN INT_MIN -#define DUK_SMALL_INT_MAX INT_MAX -#define DUK_SMALL_UINT_MIN 0 -#define DUK_SMALL_UINT_MAX UINT_MAX - -/* Fast variants of small integers, again for really fast paths like the - * executor. - */ -typedef duk_int_fast16_t duk_small_int_fast_t; -typedef duk_uint_fast16_t duk_small_uint_fast_t; -#define DUK_SMALL_INT_FAST_MIN DUK_INT_FAST16_MIN -#define DUK_SMALL_INT_FAST_MAX DUK_INT_FAST16_MAX -#define DUK_SMALL_UINT_FAST_MIN DUK_UINT_FAST16_MIN -#define DUK_SMALL_UINT_FAST_MAX DUK_UINT_FAST16_MAX - -/* Boolean values are represented with the platform 'int'. */ -typedef duk_small_int_t duk_bool_t; -#define DUK_BOOL_MIN DUK_SMALL_INT_MIN -#define DUK_BOOL_MAX DUK_SMALL_INT_MAX - -/* Index values must have at least 32-bit signed range. */ -typedef duk_int_t duk_idx_t; -#define DUK_IDX_MIN DUK_INT_MIN -#define DUK_IDX_MAX DUK_INT_MAX - -/* Unsigned index variant. */ -typedef duk_uint_t duk_uidx_t; -#define DUK_UIDX_MIN DUK_UINT_MIN -#define DUK_UIDX_MAX DUK_UINT_MAX - -/* Array index values, could be exact 32 bits. - * Currently no need for signed duk_arridx_t. - */ -typedef duk_uint_t duk_uarridx_t; -#define DUK_UARRIDX_MIN DUK_UINT_MIN -#define DUK_UARRIDX_MAX DUK_UINT_MAX - -/* Duktape/C function return value, platform int is enough for now to - * represent 0, 1, or negative error code. Must be compatible with - * assigning truth values (e.g. duk_ret_t rc = (foo == bar);). - */ -typedef duk_small_int_t duk_ret_t; -#define DUK_RET_MIN DUK_SMALL_INT_MIN -#define DUK_RET_MAX DUK_SMALL_INT_MAX - -/* Error codes are represented with platform int. High bits are used - * for flags and such, so 32 bits are needed. - */ -typedef duk_int_t duk_errcode_t; -#define DUK_ERRCODE_MIN DUK_INT_MIN -#define DUK_ERRCODE_MAX DUK_INT_MAX - -/* Codepoint type. Must be 32 bits or more because it is used also for - * internal codepoints. The type is signed because negative codepoints - * are used as internal markers (e.g. to mark EOF or missing argument). - * (X)UTF-8/CESU-8 encode/decode take and return an unsigned variant to - * ensure duk_uint32_t casts back and forth nicely. Almost everything - * else uses the signed one. - */ -typedef duk_int_t duk_codepoint_t; -typedef duk_uint_t duk_ucodepoint_t; -#define DUK_CODEPOINT_MIN DUK_INT_MIN -#define DUK_CODEPOINT_MAX DUK_INT_MAX -#define DUK_UCODEPOINT_MIN DUK_UINT_MIN -#define DUK_UCODEPOINT_MAX DUK_UINT_MAX - -/* IEEE float/double typedef. */ -typedef float duk_float_t; -typedef double duk_double_t; - -/* We're generally assuming that we're working on a platform with a 32-bit - * address space. If DUK_SIZE_MAX is a typecast value (which is necessary - * if SIZE_MAX is missing), the check must be avoided because the - * preprocessor can't do a comparison. - */ -#if !defined(DUK_SIZE_MAX) -#error DUK_SIZE_MAX is undefined, probably missing SIZE_MAX -#elif !defined(DUK_SIZE_MAX_COMPUTED) -#if DUK_SIZE_MAX < 0xffffffffUL -/* On some systems SIZE_MAX can be smaller than max unsigned 32-bit value - * which seems incorrect if size_t is (at least) an unsigned 32-bit type. - * However, it doesn't seem useful to error out compilation if this is the - * case. - */ -#endif -#endif - -/* Type for public API calls. */ -typedef struct duk_hthread duk_context; diff -Nru duktape-2.0.0/config/helper-snippets/DUK_F_AIX.h.in duktape-2.1.1/config/helper-snippets/DUK_F_AIX.h.in --- duktape-2.0.0/config/helper-snippets/DUK_F_AIX.h.in 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/helper-snippets/DUK_F_AIX.h.in 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,5 @@ +/* AIX */ +#if defined(_AIX) +/* defined(__xlc__) || defined(__IBMC__): works but too wide */ +#define DUK_F_AIX +#endif diff -Nru duktape-2.0.0/config/helper-snippets/DUK_F_ANDROID.h.in duktape-2.1.1/config/helper-snippets/DUK_F_ANDROID.h.in --- duktape-2.0.0/config/helper-snippets/DUK_F_ANDROID.h.in 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/helper-snippets/DUK_F_ANDROID.h.in 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,3 @@ +#if defined(ANDROID) || defined(__ANDROID__) +#define DUK_F_ANDROID +#endif diff -Nru duktape-2.0.0/config/helper-snippets/DUK_F_DURANGO.h.in duktape-2.1.1/config/helper-snippets/DUK_F_DURANGO.h.in --- duktape-2.0.0/config/helper-snippets/DUK_F_DURANGO.h.in 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/helper-snippets/DUK_F_DURANGO.h.in 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,4 @@ +/* Durango (Xbox One) */ +#if defined(_DURANGO) || defined(_XBOX_ONE) +#define DUK_F_DURANGO +#endif diff -Nru duktape-2.0.0/config/helper-snippets/DUK_F_HPUX.h.in duktape-2.1.1/config/helper-snippets/DUK_F_HPUX.h.in --- duktape-2.0.0/config/helper-snippets/DUK_F_HPUX.h.in 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/helper-snippets/DUK_F_HPUX.h.in 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,7 @@ +/* HPUX */ +#if defined(__hpux) +#define DUK_F_HPUX +#if defined(__ia64) +#define DUK_F_HPUX_ITANIUM +#endif +#endif diff -Nru duktape-2.0.0/config/helper-snippets/DUK_F_SUN.h.in duktape-2.1.1/config/helper-snippets/DUK_F_SUN.h.in --- duktape-2.0.0/config/helper-snippets/DUK_F_SUN.h.in 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/helper-snippets/DUK_F_SUN.h.in 2017-07-28 22:05:08.000000000 +0000 @@ -1,4 +1,12 @@ /* illumos / Solaris */ #if defined(__sun) && defined(__SVR4) #define DUK_F_SUN +#if defined(__SUNPRO_C) && (__SUNPRO_C < 0x550) +#define DUK_F_OLD_SOLARIS +/* Defines _ILP32 / _LP64 required by DUK_F_X86/DUK_F_X64. Platforms + * are processed before architectures, so this happens before the + * DUK_F_X86/DUK_F_X64 detection is emitted. + */ +#include +#endif #endif diff -Nru duktape-2.0.0/config/helper-snippets/DUK_F_X86.h.in duktape-2.1.1/config/helper-snippets/DUK_F_X86.h.in --- duktape-2.0.0/config/helper-snippets/DUK_F_X86.h.in 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/helper-snippets/DUK_F_X86.h.in 2017-07-28 22:05:08.000000000 +0000 @@ -1,6 +1,9 @@ /* Intel x86 (32-bit), x64 (64-bit) or x32 (64-bit but 32-bit pointers), * define only one of DUK_F_X86, DUK_F_X64, DUK_F_X32. * https://sites.google.com/site/x32abi/ + * + * With DUK_F_OLD_SOLARIS the header must be included + * before this. */ #if defined(__amd64__) || defined(__amd64) || \ defined(__x86_64__) || defined(__x86_64) || \ diff -Nru duktape-2.0.0/config/platforms/platform_aix.h.in duktape-2.1.1/config/platforms/platform_aix.h.in --- duktape-2.0.0/config/platforms/platform_aix.h.in 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/platforms/platform_aix.h.in 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,12 @@ +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include + +#define DUK_USE_OS_STRING "aix" diff -Nru duktape-2.0.0/config/platforms/platform_durango.h.in duktape-2.1.1/config/platforms/platform_durango.h.in --- duktape-2.0.0/config/platforms/platform_durango.h.in 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/platforms/platform_durango.h.in 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,32 @@ +/* Durango = XboxOne + * Configuration is nearly identical to Windows, except for + * DUK_USE_DATE_TZO_WINDOWS. + */ + +/* Initial fix: disable secure CRT related warnings when compiling Duktape + * itself (must be defined before including Windows headers). Don't define + * for user code including duktape.h. + */ +#if defined(DUK_COMPILING_DUKTAPE) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +/* MSVC does not have sys/param.h */ +#define DUK_USE_DATE_NOW_WINDOWS +#define DUK_USE_DATE_TZO_WINDOWS_NO_DST +/* Note: PRS and FMT are intentionally left undefined for now. This means + * there is no platform specific date parsing/formatting but there is still + * the ISO 8601 standard format. + */ +#if defined(DUK_COMPILING_DUKTAPE) +/* Only include when compiling Duktape to avoid polluting application build + * with a lot of unnecessary defines. + */ +#include +#endif + +#define DUK_USE_OS_STRING "durango" + +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif diff -Nru duktape-2.0.0/config/platforms/platform_hpux.h.in duktape-2.1.1/config/platforms/platform_hpux.h.in --- duktape-2.0.0/config/platforms/platform_hpux.h.in 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/config/platforms/platform_hpux.h.in 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,13 @@ +#define DUK_F_NO_STDINT_H +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include + +#define DUK_USE_OS_STRING "hpux" diff -Nru duktape-2.0.0/config/platforms/platform_solaris.h.in duktape-2.1.1/config/platforms/platform_solaris.h.in --- duktape-2.0.0/config/platforms/platform_solaris.h.in 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/platforms/platform_solaris.h.in 2017-07-28 22:05:08.000000000 +0000 @@ -4,7 +4,16 @@ #define DUK_USE_DATE_FMT_STRFTIME #include +#if defined(DUK_F_OLD_SOLARIS) +/* Old Solaris with no endian.h, stdint.h */ +#define DUK_F_NO_STDINT_H +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#else /* DUK_F_OLD_SOLARIS */ #include +#endif /* DUK_F_OLD_SOLARIS */ + #include #include #include diff -Nru duktape-2.0.0/config/platforms/platform_tinspire.h.in duktape-2.1.1/config/platforms/platform_tinspire.h.in --- duktape-2.0.0/config/platforms/platform_tinspire.h.in 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/platforms/platform_tinspire.h.in 2017-07-28 22:05:08.000000000 +0000 @@ -1,3 +1,7 @@ +#if defined(DUK_COMPILING_DUKTAPE) && !defined(_XOPEN_SOURCE) +#define _XOPEN_SOURCE /* e.g. strptime */ +#endif + #define DUK_USE_DATE_NOW_GETTIMEOFDAY #define DUK_USE_DATE_TZO_GMTIME_R #define DUK_USE_DATE_PRS_STRPTIME diff -Nru duktape-2.0.0/config/platforms.yaml duktape-2.1.1/config/platforms.yaml --- duktape-2.0.0/config/platforms.yaml 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/config/platforms.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -28,6 +28,10 @@ check: DUK_F_AMIGAOS include: platform_amigaos.h.in - + name: Durango (XboxOne) + check: DUK_F_DURANGO + include: platform_durango.h.in + - name: Windows check: DUK_F_WINDOWS include: platform_windows.h.in @@ -56,6 +60,14 @@ check: DUK_F_SUN include: platform_solaris.h.in - + name: AIX + check: DUK_F_AIX + include: platform_aix.h.in + - + name: HPUX + check: DUK_F_HPUX + include: platform_hpux.h.in + - name: Generic POSIX check: DUK_F_POSIX include: platform_posix.h.in diff -Nru duktape-2.0.0/debian/changelog duktape-2.1.1/debian/changelog --- duktape-2.0.0/debian/changelog 2017-01-24 18:12:39.000000000 +0000 +++ duktape-2.1.1/debian/changelog 2017-08-13 18:03:07.000000000 +0000 @@ -1,3 +1,11 @@ +duktape (2.1.1-1) unstable; urgency=medium + + * New upstream release + * debian/control: set standard to 4.0.1 (no changes) + * debian/rules: replace DH_BUILD_OPTIONS by DH_BUILD_MAINT_OPTIONS + + -- Thorsten Alteholz Sun, 13 Aug 2017 20:03:07 +0200 + duktape (2.0.0-1) unstable; urgency=medium * New upstream release diff -Nru duktape-2.0.0/debian/control duktape-2.1.1/debian/control --- duktape-2.0.0/debian/control 2016-12-12 17:43:02.000000000 +0000 +++ duktape-2.1.1/debian/control 2017-08-13 18:03:07.000000000 +0000 @@ -4,7 +4,7 @@ Maintainer: Debian IoT Maintainers Uploaders: Thorsten Alteholz Build-Depends: debhelper (>=9) -Standards-Version: 3.9.8 +Standards-Version: 4.0.1 Homepage: http://duktape.org Vcs-Browser: https://anonscm.debian.org/cgit/debian-iot/duktape.git Vcs-Git: https://anonscm.debian.org/git/debian-iot/duktape.git diff -Nru duktape-2.0.0/debian/rules duktape-2.1.1/debian/rules --- duktape-2.0.0/debian/rules 2016-10-14 20:30:59.000000000 +0000 +++ duktape-2.1.1/debian/rules 2017-08-13 18:03:07.000000000 +0000 @@ -3,7 +3,7 @@ # does not seem to work here, so no debug stuff -export DEB_BUILD_OPTIONS=noddebs +export DEB_BUILD_MAINT_OPTIONS=noddebs %: dh $@ diff -Nru duktape-2.0.0/debugger/duk_debug_meta.json duktape-2.1.1/debugger/duk_debug_meta.json --- duktape-2.0.0/debugger/duk_debug_meta.json 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/debugger/duk_debug_meta.json 2017-07-28 22:05:08.000000000 +0000 @@ -1147,10 +1147,6 @@ }, { "mask": 4096, - "name": "undef_value" - }, - { - "mask": 8192, "name": "func_decl" } ], @@ -1181,10 +1177,6 @@ }, { "mask": 4096, - "name": "undef_value" - }, - { - "mask": 8192, "name": "func_decl" } ], @@ -1215,10 +1207,6 @@ }, { "mask": 4096, - "name": "undef_value" - }, - { - "mask": 8192, "name": "func_decl" } ], @@ -1249,10 +1237,6 @@ }, { "mask": 4096, - "name": "undef_value" - }, - { - "mask": 8192, "name": "func_decl" } ], diff -Nru duktape-2.0.0/debugger/duk_opcodes.yaml duktape-2.1.1/debugger/duk_opcodes.yaml --- duktape-2.0.0/debugger/duk_opcodes.yaml 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/debugger/duk_opcodes.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -705,8 +705,6 @@ - mask: 0x800 name: accessor - mask: 0x1000 - name: undef_value - - mask: 0x2000 name: func_decl - name: DECLVAR_CR args: @@ -723,8 +721,6 @@ - mask: 0x800 name: accessor - mask: 0x1000 - name: undef_value - - mask: 0x2000 name: func_decl - name: DECLVAR_RC args: @@ -741,8 +737,6 @@ - mask: 0x800 name: accessor - mask: 0x1000 - name: undef_value - - mask: 0x2000 name: func_decl - name: DECLVAR_CC args: @@ -759,8 +753,6 @@ - mask: 0x800 name: accessor - mask: 0x1000 - name: undef_value - - mask: 0x2000 name: func_decl - name: REGEXP_RR args: diff -Nru duktape-2.0.0/debugger/Makefile duktape-2.1.1/debugger/Makefile --- duktape-2.0.0/debugger/Makefile 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/debugger/Makefile 2017-07-28 22:05:08.000000000 +0000 @@ -54,7 +54,7 @@ npm install duk_debug_meta.json: - python ../tools/merge_debug_meta.py --output $@ \ + python2 ../tools/merge_debug_meta.py --output $@ \ --class-names duk_classnames.yaml \ --opcodes duk_opcodes.yaml \ --debug-commands duk_debugcommands.yaml \ diff -Nru duktape-2.0.0/duk_dist_meta.json duktape-2.1.1/duk_dist_meta.json --- duktape-2.0.0/duk_dist_meta.json 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/duk_dist_meta.json 2017-07-28 22:05:08.000000000 +0000 @@ -1,9 +1,9 @@ { "comment": "Metadata for Duktape distributable", - "duk_version_string": "2.0.0", + "duk_version_string": "2.1.1", "type": "duk_dist_meta", - "duk_version": 20000, - "git_branch": "master", - "git_commit": "4180966c47d6d87106008dd4338de8d507c8072b", - "git_describe": "v2.0.0" + "duk_version": 20101, + "git_branch": "v2.1-maintenance", + "git_commit": "9c8fba6392d1913cb5359be7b8f386fa3cdd8b4d", + "git_describe": "v2.1.1" } \ No newline at end of file diff -Nru duktape-2.0.0/examples/alloc-hybrid/duk_alloc_hybrid.c duktape-2.1.1/examples/alloc-hybrid/duk_alloc_hybrid.c --- duktape-2.0.0/examples/alloc-hybrid/duk_alloc_hybrid.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/examples/alloc-hybrid/duk_alloc_hybrid.c 2017-07-28 22:05:08.000000000 +0000 @@ -12,6 +12,7 @@ #include #include #include +#include "duk_alloc_hybrid.h" /* Define to enable some debug printfs. */ /* #define DUK_ALLOC_HYBRID_DEBUG */ diff -Nru duktape-2.0.0/examples/alloc-logging/duk_alloc_logging.c duktape-2.1.1/examples/alloc-logging/duk_alloc_logging.c --- duktape-2.0.0/examples/alloc-logging/duk_alloc_logging.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/examples/alloc-logging/duk_alloc_logging.c 2017-07-28 22:05:08.000000000 +0000 @@ -19,6 +19,7 @@ #include #include #include +#include "duk_alloc_logging.h" #define ALLOC_LOG_FILE "/tmp/duk-alloc-log.txt" diff -Nru duktape-2.0.0/examples/alloc-torture/duk_alloc_torture.c duktape-2.1.1/examples/alloc-torture/duk_alloc_torture.c --- duktape-2.0.0/examples/alloc-torture/duk_alloc_torture.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/examples/alloc-torture/duk_alloc_torture.c 2017-07-28 22:05:08.000000000 +0000 @@ -16,6 +16,7 @@ #include #include #include +#include "duk_alloc_torture.h" #define RED_ZONE_SIZE 16 #define RED_ZONE_BYTE 0x5a diff -Nru duktape-2.0.0/examples/cmdline/duk_cmdline_ajduk.c duktape-2.1.1/examples/cmdline/duk_cmdline_ajduk.c --- duktape-2.0.0/examples/cmdline/duk_cmdline_ajduk.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/examples/cmdline/duk_cmdline_ajduk.c 2017-07-28 22:05:08.000000000 +0000 @@ -87,7 +87,7 @@ { 16, 300, AJS_POOL_BORROW, 0 }, { 20, 300, AJS_POOL_BORROW, 0 }, { 24, 300, AJS_POOL_BORROW, 0 }, - { 28, 150, AJS_POOL_BORROW, 0 }, + { 28, 250, AJS_POOL_BORROW, 0 }, { 32, 150, AJS_POOL_BORROW, 0 }, { 40, 150, AJS_POOL_BORROW, 0 }, { 48, 50, AJS_POOL_BORROW, 0 }, @@ -95,14 +95,17 @@ { 56, 50, AJS_POOL_BORROW, 0 }, { 60, 50, AJS_POOL_BORROW, 0 }, { 64, 50, AJS_POOL_BORROW, 0 }, + { 96, 50, AJS_POOL_BORROW, 0 }, { 128, 80, AJS_POOL_BORROW, 0 }, + { 200, 1, AJS_POOL_BORROW, 0 }, /* duk_heap, with heap ptr compression, ROM strings+objects */ { 256, 16, AJS_POOL_BORROW, 0 }, + { 288, 1, AJS_POOL_BORROW, 0 }, { 320, 1, AJS_POOL_BORROW, 0 }, - { 392, 1, AJS_POOL_BORROW, 0 }, /* duk_hthread, with heap ptr compression, ROM strings+objects */ + { 396, 1, AJS_POOL_BORROW, 0 }, /* duk_hthread, with heap ptr compression, ROM strings+objects */ + { 400, 1, AJS_POOL_BORROW, 0 }, /* duk_hthread, with heap ptr compression, RAM strings+objects */ + { 536, 1, AJS_POOL_BORROW, 0 }, /* duk_heap, with heap ptr compression, RAM strings+objects */ { 512, 16, AJS_POOL_BORROW, 0 }, - { 964, 1, AJS_POOL_BORROW, 0 }, /* duk_heap, with heap ptr compression, ROM strings+objects */ { 1024, 6, AJS_POOL_BORROW, 0 }, - { 1344, 1, AJS_POOL_BORROW, 0 }, /* duk_heap, with heap ptr compression, RAM strings+objects */ { 2048, 5, AJS_POOL_BORROW, 0 }, { 4096, 3, 0, 0 }, { 8192, 3, 0, 0 }, diff -Nru duktape-2.0.0/examples/cmdline/duk_cmdline.c duktape-2.1.1/examples/cmdline/duk_cmdline.c --- duktape-2.0.0/examples/cmdline/duk_cmdline.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/examples/cmdline/duk_cmdline.c 2017-07-28 22:05:08.000000000 +0000 @@ -239,12 +239,13 @@ if (src_data != NULL && src_len >= 2 && src_data[0] == (char) 0xff) { /* Bytecode. */ - duk_push_lstring(ctx, src_data, src_len); - duk_to_buffer(ctx, -1, NULL); + void *buf; + buf = duk_push_fixed_buffer(ctx, src_len); + memcpy(buf, (const void *) src_data, src_len); duk_load_function(ctx); } else { /* Source code. */ - comp_flags = 0; + comp_flags = DUK_COMPILE_SHEBANG; duk_compile_lstring_filename(ctx, comp_flags, src_data, src_len); } @@ -289,7 +290,7 @@ #if 0 /* Manual test for bytecode dump/load cycle: dump and load before - * execution. Enable manually, then run "make qecmatest" for a + * execution. Enable manually, then run "make ecmatest" for a * reasonably good coverage of different functions and programs. */ duk_dump_function(ctx); @@ -1122,7 +1123,7 @@ if (!ctx) { fprintf(stderr, "Failed to create Duktape heap\n"); fflush(stderr); - exit(-1); + exit(1); } #if defined(DUK_CMDLINE_AJSHEAP) diff -Nru duktape-2.0.0/examples/debug-trans-socket/duk_trans_socket_unix.c duktape-2.1.1/examples/debug-trans-socket/duk_trans_socket_unix.c --- duktape-2.0.0/examples/debug-trans-socket/duk_trans_socket_unix.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/examples/debug-trans-socket/duk_trans_socket_unix.c 2017-07-28 22:05:08.000000000 +0000 @@ -19,6 +19,7 @@ #endif /* !USE_SELECT */ #include #include "duktape.h" +#include "duk_trans_socket.h" #if !defined(DUK_DEBUG_PORT) #define DUK_DEBUG_PORT 9091 diff -Nru duktape-2.0.0/examples/debug-trans-socket/duk_trans_socket_windows.c duktape-2.1.1/examples/debug-trans-socket/duk_trans_socket_windows.c --- duktape-2.0.0/examples/debug-trans-socket/duk_trans_socket_windows.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/examples/debug-trans-socket/duk_trans_socket_windows.c 2017-07-28 22:05:08.000000000 +0000 @@ -51,6 +51,7 @@ #include #include #include "duktape.h" +#include "duk_trans_socket.h" #if defined(_MSC_VER) #pragma comment (lib, "Ws2_32.lib") diff -Nru duktape-2.0.0/extras/module-duktape/duk_module_duktape.c duktape-2.1.1/extras/module-duktape/duk_module_duktape.c --- duktape-2.0.0/extras/module-duktape/duk_module_duktape.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/extras/module-duktape/duk_module_duktape.c 2017-07-28 22:05:08.000000000 +0000 @@ -5,6 +5,14 @@ #include "duktape.h" #include "duk_module_duktape.h" +/* (v)snprintf() is missing before MSVC 2015. Note that _(v)snprintf() does + * NOT NUL terminate on truncation, but that's OK here. + * http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 + */ +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define snprintf _snprintf +#endif + #if 0 /* Enable manually */ #define DUK__ASSERT(x) do { \ if (!(x)) { \ @@ -346,7 +354,7 @@ * (Note capitalization: .filename matches Node.js while .fileName is * used elsewhere in Duktape.) */ - duk_push_string(ctx, "})"); + duk_push_string(ctx, "\n})"); /* Newline allows module last line to contain a // comment. */ duk_concat(ctx, 3); if (!duk_get_prop_string(ctx, DUK__IDX_MODULE, "filename")) { /* module.filename for .fileName, default to resolved ID if diff -Nru duktape-2.0.0/extras/module-duktape/Makefile duktape-2.1.1/extras/module-duktape/Makefile --- duktape-2.0.0/extras/module-duktape/Makefile 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/extras/module-duktape/Makefile 2017-07-28 22:05:08.000000000 +0000 @@ -11,3 +11,4 @@ ./test 'assert(typeof Duktape.modSearch === "undefined");' ./test 'Duktape.modSearch = function myModSearch(id) { return "exports.foo = 123;" }; assert(require("dummy").foo === 123);' ./test 'Duktape.modSearch = function myModSearch(id) { return "exports.foo = 234;" }; delete Duktape; assert(typeof Duktape === "undefined"); assert(require("dummy").foo === 234);' + ./test 'Duktape.modSearch = function myModSearch(id) { return "exports.foo = 234; // comment" }; delete Duktape; assert(typeof Duktape === "undefined"); assert(require("dummy").foo === 234);' diff -Nru duktape-2.0.0/extras/module-node/duk_module_node.c duktape-2.1.1/extras/module-node/duk_module_node.c --- duktape-2.0.0/extras/module-node/duk_module_node.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/extras/module-node/duk_module_node.c 2017-07-28 22:05:08.000000000 +0000 @@ -204,6 +204,8 @@ #else static duk_int_t duk__eval_module_source(duk_context *ctx) { #endif + const char *src; + /* * Stack: [ ... module source ] */ @@ -217,9 +219,11 @@ * e.g. Node.js. */ duk_push_string(ctx, "(function(exports,require,module,__filename,__dirname){"); - duk_dup(ctx, -2); /* source */ - duk_push_string(ctx, "})"); - duk_concat(ctx, 3); + src = duk_require_string(ctx, -2); + duk_push_string(ctx, (src[0] == '#' && src[1] == '!') ? "//" : ""); /* Shebang support. */ + duk_dup(ctx, -3); /* source */ + duk_push_string(ctx, "\n})"); /* Newline allows module last line to contain a // comment. */ + duk_concat(ctx, 4); /* [ ... module source func_src ] */ diff -Nru duktape-2.0.0/extras/module-node/Makefile duktape-2.1.1/extras/module-node/Makefile --- duktape-2.0.0/extras/module-node/Makefile 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/extras/module-node/Makefile 2017-07-28 22:05:08.000000000 +0000 @@ -15,3 +15,5 @@ ./test 'var ape = require("ape"); assert(ape.module.loaded === true && ape.wasLoaded === false, "module.loaded");' ./test 'var ape = require("ape"); assert(ape.__filename === "ape.js", "__filename");' ./test 'var badger = require("badger"); assert(badger.foo === 123 && badger.bar === 234, "exports.foo assignment");' + ./test 'var comment = require("comment"); assert(comment.foo === 123 && comment.bar === 234, "last line with // comment");' + ./test 'var shebang = require("shebang"); assert(shebang.foo === 123 && shebang.bar === 234, "shebang");' diff -Nru duktape-2.0.0/extras/module-node/test.c duktape-2.1.1/extras/module-node/test.c --- duktape-2.0.0/extras/module-node/test.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/extras/module-node/test.c 2017-07-28 22:05:08.000000000 +0000 @@ -36,6 +36,10 @@ duk_push_string(ctx, "module.exports = { module: module, __filename: __filename, wasLoaded: module.loaded };"); } else if (strcmp(module_id, "badger.js") == 0) { duk_push_string(ctx, "exports.foo = 123; exports.bar = 234;"); + } else if (strcmp(module_id, "comment.js") == 0) { + duk_push_string(ctx, "exports.foo = 123; exports.bar = 234; // comment"); + } else if (strcmp(module_id, "shebang.js") == 0) { + duk_push_string(ctx, "#!ignored\nexports.foo = 123; exports.bar = 234;"); } else { duk_error(ctx, DUK_ERR_TYPE_ERROR, "cannot find module: %s", module_id); } diff -Nru duktape-2.0.0/license.spdx duktape-2.1.1/license.spdx --- duktape-2.0.0/license.spdx 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/license.spdx 2017-07-28 22:05:08.000000000 +0000 @@ -1,14461 +1,14941 @@ - - <_3:fileName>./config/config-options/DUK_USE_HSTRING_EXTDATA.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1160"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d0c303420f5cb41478a761415a6c3b1255f96869 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ff69aff0a588f5c66dc08c3ab096ae91a9406da5 - + ./config/helper-snippets/DUK_F_ARM.h.in + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + 8918e2ba44f48cbad31eb4b914c22df3a630da7a + + + + + + ./config/feature-options/DUK_OPT_DDDPRINT.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Duktape is an embeddable Javascript engine, with a focus on portability and compact footprint + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Duktape Ecmascript interpreter + + + + + + + + + + + + + + + + + + + + + + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + duktape-2.1.1.tar.xz + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Duktape + + Duktape is copyrighted by its authors and licensed under the MIT license. MurmurHash2 is used internally, it is also under the MIT license. Duktape module loader is based on the CommonJS module loading specification (without sharing any code), CommonJS is under the MIT license. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + http://duktape.org/ + + + + + + + + + + + + Organization: duktape.org + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + http://duktape.org/duktape-2.1.1.tar.xz + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Official duktape.org release built from GitHub repo https://github.com/svaarala/duktape. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2.1.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Organization: duktape.org + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./config/platforms/platform_tinspire.h.in + + + + + ./config/config-options/DUK_USE_FINALIZER_TORTURE.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + 484c4cbf935e7b38a0d43b491576ada56ddc59a1 + + + + + + + + ./config/config-options/DUK_USE_CPP_EXCEPTIONS.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + ./config/config-options/DUK_USE_HSTRING_CLEN.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./examples/alloc-torture/duk_alloc_torture.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + ./config/config-options/DUK_USE_32BIT_PTRS.yaml + + + + bb94ce16f0e382c5f77d3f25b34f98dbb3774c0f + + + + + c5be3577e198e24f10ffe61fa21bff4a69246168 + + + + + + + ./src-separate/duk_util_bitencoder.c + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-separate/duk_api_buffer.c + + + + + + + + + + + + ./config/config-options/DUK_USE_DATE_TZO_GMTIME_R.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./src-input/duk_bi_string.c + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + a0e70baeeeb45ca74a0eb7312d6502530b8482ea + + + + + + 4caccabb685f620b904723e2c97aa2eae5096728 + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + ./config/header-snippets/platform_cppextras.h.in + + + + 75b8e7c8e2f306c3c0aa83b79846f757acd83cf7 + + + + ./extras/module-node/duk_module_node.h + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SPDX license for Duktape 2.1.1 + + + + + + + + + + + + + + + + + + + + + + + + SPDX-1.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - <_3:fileName>./config/config-options/DUK_USE_OS_STRING.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1000"/> + + ./config/config-options/DUK_USE_STRTAB_CHAIN.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./src-separate/duk_bi_thrower.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS372"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./README.rst + + + + - - <_3:fileName>./config/config-options/DUK_USE_BYTEORDER.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1084"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-input/duk_bi_function.c + - - <_3:fileName>./config/config-options/DUK_USE_STRTAB_CHAIN.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS948"/> + + ./src-input/duk_util_tinyrandom.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./src-separate/duk_builtins.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS204"/> + ./src-separate/duk_api_bytecode.c + - - <_3:fileName>./config/config-options/DUK_USE_EXEC_FUN_LOCAL.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1050"/> + + ./config/feature-options/DUK_OPT_SIGSETJMP.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c7dc5159da983151a1718707eb5009570318b546 + + + f34df48d9f648285023482412ed825ffc5f00e98 - - <_3:fileName>./src-separate/duk_util_misc.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS246"/> + + + + e8d6d451ab95a57de6515434b4889a3d5bcb2066 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9b254d86bac8eb249de6789e8521c0441220e383 + + 290a5e0940738c497792a9261b83ae349d8bfb19 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>324b051b9bd40e29cc8dd721f8c03a4ca933905b + + + 5d2bf5b2953a619bd1cd156ab6ce47140336eba2 - - <_3:fileName>./debugger/duk_debugcommands.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./src-separate/duk_util_hashbytes.c + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS56"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>149584de234020f72f4b5c5fa23357d351de1ab7 - - - - <_3:fileName>./examples/codepage-conv/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./examples/dummy-date-provider/dummy_date_provider.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS88"/> + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f406f7db9beb9a66addefafd9a03d29365f2660c + + 9657c366438093bdd2a8db606da8ce982663ada9 + - - <_3:fileName>./src-separate/duk_util_hashbytes.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS436"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a9b7b714143adc2d874e328413e3d5399fda8abd + + + cc29429c71aa37475617e351d3cdcac87d55d76d - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>604f325ae4c368ca973bd122e7a98071fe9d1027 + + c51bf4414e4197ea88f91a4497689972d9b71917 + - - <_3:fileName>./config/helper-snippets/DUK_F_OPENBSD.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./config/config-options/DUK_USE_HOBJECT_HASH_PROP_LIMIT.yaml + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1380"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./src-input/duk_bi_number.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./examples/guide/fib.js - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1744"/> + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7db2a928052b97e6bad7cb9da91cb86247233cba + + + ./src-input/duk_hbufobj_misc.c + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + 8015d14ffbc7a4a4b93d654f093aa48ec17fce4e - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1322326a94dfa7af345af7ac0c7b60d787320e7d + + ede5151f7e6fff690fe7edb0b0a5e73d49969c62 + - - <_3:fileName>./examples/eval/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + ./src-separate/duk_replacements.h + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS130"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>fb2406b05571014ed4365f8662890707cddd5665 - + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_FLEX_C99.yaml + + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c83d0559f42fc713df412f8e21549e2a7e74074a + + + bbc5a800cc28683a58279cca5b21269a7266ba71 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bb0d7a6b563c118a0c1e6f0f2b6b8a50f09e280c - + + + + + + ./config/config-options/DUK_USE_ESBC_LIMITS.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/platforms/platform_flashplayer.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/feature-options/DUK_OPT_NO_OBJECT_ES6_PROTO_PROPERTY.yaml + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS784"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9ff0ba5156be808917ab3ab9ac602107afa7814e - + + + + + + ./config/helper-snippets/DUK_F_SUN.h.in + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c67a9e99a6d31a57e400e21b9cf282ade5506a0d - + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./examples/eventloop/socket.c + + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./src-input/UnicodeData-8bit.txt + - - <_3:fileName>./src-input/duk_util_bitencoder.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1698"/> + + ./config/header-snippets/object_layout.h.in + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>68b8873adab6f2c0ddd8ba08d64639aa0b8599a7 + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./examples/alloc-logging/duk_alloc_logging.h + + + + + 064fc117cb63c3278067c9480d7276cb9b354fc5 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>5271e503e4775b2be09c3e9bb04468da26b66fab + + + 0c06c4f4b278877410bf7e9af775913318b48738 - - <_3:fileName>./src-input/duk_bi_date.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1574"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./examples/alloc-hybrid/duk_alloc_hybrid.h - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>fa12651d5b9bea4efd87fd7448051f0903647c4c - + + + + + + + ./config/feature-options/DUK_OPT_EXAMPLE.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./src-separate/duk_bi_math.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS296"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./config/config-options/DUK_USE_FAST_REFCOUNT_DEFAULT.yaml + + - - <_3:fileName>./src-input/duk_unicode_tables.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-input/duk_error_macros.c - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1606"/> + + + - - <_3:creator>Organization: duktape.org - - - <_3:created rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">2017-01-02T03:09:50Z - <_3:licenseListVersion>1.20 + + 78289788e94f30189cc26b68f6780136639fd5b2 + + + + + + + + + + ./src-input/duk_bi_boolean.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>63ded311f7b05332e068906d8667c466ab671873 + + ea55a5be61f2eea1dc02ee6481fc836adef4404a + + + + + ./config/examples/low_memory_strip.yaml + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0bf9287bdff77a59737ae2dc00ed983faab89c1c + + c51bf4414e4197ea88f91a4497689972d9b71917 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c3b5e005ebb6854c0fc17ad6c8ad915f725fa091 + + + 0b73d63799058538ad46235ddc07b04e4caa0919 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>5788bd9269db59578632eb6283ecc0d54d5d9b2f + + 550d1c67a391fa6ad171bf39e278d6edb2e1655a + - - <_3:fileName>./config/config-options/DUK_USE_PACKED_TVAL.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1066"/> + + + 2d47b9120905bbcb050a48ec2c0546204759329a + - - <_3:fileName>./extras/console/duk_console.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1418"/> + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/feature-options/DUK_OPT_SELF_TESTS.yaml - - <_3:fileName>./examples/alloc-hybrid/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_STRHASH_SKIP_SHIFT.yaml + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS84"/> + - - <_3:fileName>./config/config-options/DUK_USE_EXTSTR_INTERN_CHECK.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./config/config-options/DUK_USE_DEBUGGER_INSPECT.yaml + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1278"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4392fa63e6e9174ec09ef2e3a4e4e3bd03e94126 + + + a4a2f621d0087563e1886bdd846f6cd8806e3825 - - <_3:fileName>./config/config-options/DUK_USE_REGEXP_SUPPORT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS890"/> + ./src-input/duk_hbufobj.h + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2b89124b62a51daeab2e8d84395dd83337c28ec2 + + + 2c44d7d488bb32ca481cd48c49eae5fe254a859a - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>e6b61a8c5af43d0b2a9b74d34d147c10acc8d372 + + + 18cffde6810c634fafad39bef2e89805d879c684 - - <_3:fileName>./config/config-options/DUK_USE_STRHASH_SKIP_SHIFT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS964"/> + + + ./config/feature-options/DUK_OPT_NO_OBJECT_ES6_SETPROTOTYPEOF.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/config-options/DUK_USE_INTEGER_BE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1116"/> + + + ./config/feature-options/DUK_OPT_HEAPPTR_ENC16.yaml - - <_3:fileName>./config/config-options/DUK_USE_SOURCE_NONBMP.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS916"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./duk_dist_meta.json - - - <_3:summary>Duktape Ecmascript interpreter - <_3:sourceInfo>Official duktape.org release built from GitHub repo https://github.com/svaarala/duktape. - <_3:packageFileName>duktape-2.0.0.tar.xz - <_3:name>Duktape - <_3:description>Duktape is an embeddable Javascript engine, with a focus on portability and compact footprint - <_3:licenseInfoFromFiles rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:originator>Organization: duktape.org - <_3:packageVerificationCode rdf:nodeID="IPWfDqBS5"/> - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:hasFile rdf:nodeID="IPWfDqBS489"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1159"/> - <_3:hasFile rdf:nodeID="IPWfDqBS447"/> - <_3:hasFile rdf:nodeID="IPWfDqBS917"/> - <_3:hasFile rdf:nodeID="IPWfDqBS431"/> - <_3:hasFile rdf:nodeID="IPWfDqBS635"/> - <_3:hasFile rdf:nodeID="IPWfDqBS173"/> - <_3:hasFile rdf:nodeID="IPWfDqBS371"/> - <_3:hasFile rdf:nodeID="IPWfDqBS863"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1083"/> - <_3:hasFile rdf:nodeID="IPWfDqBS947"/> - <_3:hasFile rdf:nodeID="IPWfDqBS203"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1049"/> - <_3:hasFile rdf:nodeID="IPWfDqBS843"/> - <_3:hasFile rdf:nodeID="IPWfDqBS245"/> - <_3:hasFile rdf:nodeID="IPWfDqBS479"/> - <_3:hasFile rdf:nodeID="IPWfDqBS637"/> - <_3:hasFile rdf:nodeID="IPWfDqBS875"/> - <_3:hasFile rdf:nodeID="IPWfDqBS963"/> - <_3:hasFile rdf:nodeID="IPWfDqBS275"/> - <_3:hasFile rdf:nodeID="IPWfDqBS339"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1235"/> - <_3:hasFile rdf:nodeID="IPWfDqBS55"/> - <_3:hasFile rdf:nodeID="IPWfDqBS349"/> - <_3:hasFile rdf:nodeID="IPWfDqBS87"/> - <_3:hasFile rdf:nodeID="IPWfDqBS731"/> - <_3:hasFile rdf:nodeID="IPWfDqBS461"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1395"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1587"/> - <_3:hasFile rdf:nodeID="IPWfDqBS451"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1659"/> - <_3:hasFile rdf:nodeID="IPWfDqBS715"/> - <_3:hasFile rdf:nodeID="IPWfDqBS435"/> - <_3:hasFile rdf:nodeID="IPWfDqBS305"/> - <_3:hasFile rdf:nodeID="IPWfDqBS167"/> - <_3:hasFile rdf:nodeID="IPWfDqBS291"/> - <_3:hasFile rdf:nodeID="IPWfDqBS829"/> - <_3:hasFile rdf:nodeID="IPWfDqBS25"/> - <_3:hasFile rdf:nodeID="IPWfDqBS853"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1551"/> - <_3:hasFile rdf:nodeID="IPWfDqBS871"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1379"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1009"/> - <_3:hasFile rdf:nodeID="IPWfDqBS285"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1743"/> - <_3:hasFile rdf:nodeID="IPWfDqBS327"/> - <_3:hasFile rdf:nodeID="IPWfDqBS129"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1219"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1285"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1657"/> - <_3:hasFile rdf:nodeID="IPWfDqBS537"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1337"/> - <_3:hasFile rdf:nodeID="IPWfDqBS603"/> - <_3:hasFile rdf:nodeID="IPWfDqBS783"/> - <_3:hasFile rdf:nodeID="IPWfDqBS27"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1453"/> - <_3:hasFile rdf:nodeID="IPWfDqBS375"/> - <_3:hasFile rdf:nodeID="IPWfDqBS575"/> - <_3:hasFile rdf:nodeID="IPWfDqBS443"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1327"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1633"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1429"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1697"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1359"/> - <_3:hasFile rdf:nodeID="IPWfDqBS725"/> - <_3:hasFile rdf:nodeID="IPWfDqBS437"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1573"/> - <_3:hasFile rdf:nodeID="IPWfDqBS295"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1639"/> - <_3:hasFile rdf:nodeID="IPWfDqBS773"/> - <_3:hasFile rdf:nodeID="IPWfDqBS931"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1605"/> - <_3:hasFile rdf:nodeID="IPWfDqBS569"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1535"/> - <_3:hasFile rdf:nodeID="IPWfDqBS847"/> - <_3:hasFile rdf:nodeID="IPWfDqBS11"/> - <_3:hasFile rdf:nodeID="IPWfDqBS107"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1595"/> - <_3:hasFile rdf:nodeID="IPWfDqBS249"/> - <_3:hasFile rdf:nodeID="IPWfDqBS487"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1557"/> - <_3:hasFile rdf:nodeID="IPWfDqBS943"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1723"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1757"/> - <_3:hasFile rdf:nodeID="IPWfDqBS699"/> - <_3:hasFile rdf:nodeID="IPWfDqBS115"/> - <_3:hasFile rdf:nodeID="IPWfDqBS83"/> - <_3:hasFile rdf:nodeID="IPWfDqBS765"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1527"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1277"/> - <_3:hasFile rdf:nodeID="IPWfDqBS183"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1613"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1443"/> - <_3:hasFile rdf:nodeID="IPWfDqBS889"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1623"/> - <_3:hasFile rdf:nodeID="IPWfDqBS155"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1051"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1679"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1115"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1737"/> - <_3:hasFile rdf:nodeID="IPWfDqBS539"/> - <_3:hasFile rdf:nodeID="IPWfDqBS807"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1439"/> - <_3:hasFile rdf:nodeID="IPWfDqBS545"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1399"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1751"/> - <_3:hasFile rdf:nodeID="IPWfDqBS299"/> - <_3:hasFile rdf:nodeID="IPWfDqBS753"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1039"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1635"/> - <_3:hasFile rdf:nodeID="IPWfDqBS755"/> - <_3:hasFile rdf:nodeID="IPWfDqBS187"/> - <_3:hasFile rdf:nodeID="IPWfDqBS933"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1251"/> - <_3:hasFile rdf:nodeID="IPWfDqBS879"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1139"/> - <_3:hasFile rdf:nodeID="IPWfDqBS311"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1675"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1229"/> - <_3:hasFile rdf:nodeID="IPWfDqBS709"/> - <_3:hasFile rdf:nodeID="IPWfDqBS343"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1513"/> - <_3:hasFile rdf:nodeID="IPWfDqBS423"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1311"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1507"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1555"/> - <_3:hasFile rdf:nodeID="IPWfDqBS823"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1779"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1031"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1441"/> - <_3:hasFile rdf:nodeID="IPWfDqBS199"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1559"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1183"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1701"/> - <_3:hasFile rdf:nodeID="IPWfDqBS841"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1401"/> - <_3:hasFile rdf:nodeID="IPWfDqBS453"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1425"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1291"/> - <_3:hasFile rdf:nodeID="IPWfDqBS67"/> - <_3:hasFile rdf:nodeID="IPWfDqBS179"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1433"/> - <_3:hasFile rdf:nodeID="IPWfDqBS125"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1663"/> - <_3:hasFile rdf:nodeID="IPWfDqBS849"/> - <_3:hasFile rdf:nodeID="IPWfDqBS737"/> - <_3:hasFile rdf:nodeID="IPWfDqBS795"/> - <_3:hasFile rdf:nodeID="IPWfDqBS799"/> - <_3:hasFile rdf:nodeID="IPWfDqBS627"/> - <_3:hasFile rdf:nodeID="IPWfDqBS611"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1791"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1469"/> - <_3:hasFile rdf:nodeID="IPWfDqBS969"/> - <_3:hasFile rdf:nodeID="IPWfDqBS433"/> - <_3:hasFile rdf:nodeID="IPWfDqBS711"/> - <_3:hasFile rdf:nodeID="IPWfDqBS365"/> - <_3:hasFile rdf:nodeID="IPWfDqBS391"/> - <_3:hasFile rdf:nodeID="IPWfDqBS981"/> - <_3:hasFile rdf:nodeID="IPWfDqBS581"/> - <_3:hasFile rdf:nodeID="IPWfDqBS721"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1135"/> - <_3:hasFile rdf:nodeID="IPWfDqBS185"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1411"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1733"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1295"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1649"/> - <_3:hasFile rdf:nodeID="IPWfDqBS287"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1153"/> - <_3:hasFile rdf:nodeID="IPWfDqBS477"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1173"/> - <_3:hasFile rdf:nodeID="IPWfDqBS379"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1577"/> - <_3:hasFile rdf:nodeID="IPWfDqBS397"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1347"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1025"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1787"/> - <_3:hasFile rdf:nodeID="IPWfDqBS649"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1601"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1355"/> - <_3:hasFile rdf:nodeID="IPWfDqBS217"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1617"/> - <_3:hasFile rdf:nodeID="IPWfDqBS747"/> - <_3:hasFile rdf:nodeID="IPWfDqBS207"/> - <_3:hasFile rdf:nodeID="IPWfDqBS191"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1789"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1093"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1161"/> - <_3:hasFile rdf:nodeID="IPWfDqBS651"/> - <_3:hasFile rdf:nodeID="IPWfDqBS205"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1413"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1455"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1467"/> - <_3:hasFile rdf:nodeID="IPWfDqBS495"/> - <_3:hasFile rdf:nodeID="IPWfDqBS373"/> - <_3:hasFile rdf:nodeID="IPWfDqBS877"/> - <_3:hasFile rdf:nodeID="IPWfDqBS717"/> - <_3:hasFile rdf:nodeID="IPWfDqBS913"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1759"/> - <_3:hasFile rdf:nodeID="IPWfDqBS341"/> - <_3:hasFile rdf:nodeID="IPWfDqBS253"/> - <_3:hasFile rdf:nodeID="IPWfDqBS897"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1741"/> - <_3:hasFile rdf:nodeID="IPWfDqBS591"/> - <_3:hasFile rdf:nodeID="IPWfDqBS607"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1471"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1215"/> - <_3:hasFile rdf:nodeID="IPWfDqBS209"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1583"/> - <_3:hasFile rdf:nodeID="IPWfDqBS159"/> - <_3:hasFile rdf:nodeID="IPWfDqBS283"/> - <_3:hasFile rdf:nodeID="IPWfDqBS675"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1703"/> - <_3:hasFile rdf:nodeID="IPWfDqBS21"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1275"/> - <_3:hasFile rdf:nodeID="IPWfDqBS723"/> - <_3:hasFile rdf:nodeID="IPWfDqBS403"/> - <_3:hasFile rdf:nodeID="IPWfDqBS501"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1415"/> - <_3:hasFile rdf:nodeID="IPWfDqBS89"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1627"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1175"/> - <_3:hasFile rdf:nodeID="IPWfDqBS181"/> - <_3:hasFile rdf:nodeID="IPWfDqBS389"/> - <_3:hasFile rdf:nodeID="IPWfDqBS587"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1713"/> - <_3:hasFile rdf:nodeID="IPWfDqBS279"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1271"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1157"/> - <_3:hasFile rdf:nodeID="IPWfDqBS377"/> - <_3:hasFile rdf:nodeID="IPWfDqBS629"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1801"/> - <_3:hasFile rdf:nodeID="IPWfDqBS771"/> - <_3:hasFile rdf:nodeID="IPWfDqBS13"/> - <_3:hasFile rdf:nodeID="IPWfDqBS227"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1111"/> - <_3:hasFile rdf:nodeID="IPWfDqBS859"/> - <_3:hasFile rdf:nodeID="IPWfDqBS301"/> - <_3:hasFile rdf:nodeID="IPWfDqBS331"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1643"/> - <_3:hasFile rdf:nodeID="IPWfDqBS617"/> - <_3:hasFile rdf:nodeID="IPWfDqBS525"/> - <_3:hasFile rdf:nodeID="IPWfDqBS79"/> - <_3:hasFile rdf:nodeID="IPWfDqBS885"/> - <_3:hasFile rdf:nodeID="IPWfDqBS493"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1141"/> - <_3:hasFile rdf:nodeID="IPWfDqBS949"/> - <_3:hasFile rdf:nodeID="IPWfDqBS615"/> - <_3:hasFile rdf:nodeID="IPWfDqBS315"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1343"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1653"/> - <_3:hasFile rdf:nodeID="IPWfDqBS149"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1243"/> - <_3:hasFile rdf:nodeID="IPWfDqBS741"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1445"/> - <_3:hasFile rdf:nodeID="IPWfDqBS507"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1731"/> - <_3:hasFile rdf:nodeID="IPWfDqBS973"/> - <_3:hasFile rdf:nodeID="IPWfDqBS621"/> - <_3:hasFile rdf:nodeID="IPWfDqBS671"/> - <_3:hasFile rdf:nodeID="IPWfDqBS257"/> - <_3:hasFile rdf:nodeID="IPWfDqBS851"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1533"/> - <_3:hasFile rdf:nodeID="IPWfDqBS813"/> - <_3:hasFile rdf:nodeID="IPWfDqBS51"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1799"/> - <_3:hasFile rdf:nodeID="IPWfDqBS547"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1545"/> - <_3:hasFile rdf:nodeID="IPWfDqBS197"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1103"/> - <_3:hasFile rdf:nodeID="IPWfDqBS911"/> - <_3:hasFile rdf:nodeID="IPWfDqBS639"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1711"/> - <_3:hasFile rdf:nodeID="IPWfDqBS427"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1185"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1273"/> - <_3:hasFile rdf:nodeID="IPWfDqBS739"/> - <_3:hasFile rdf:nodeID="IPWfDqBS467"/> - <_3:hasFile rdf:nodeID="IPWfDqBS233"/> - <_3:hasFile rdf:nodeID="IPWfDqBS213"/> - <_3:hasFile rdf:nodeID="IPWfDqBS23"/> - <_3:hasFile rdf:nodeID="IPWfDqBS485"/> - <_3:hasFile rdf:nodeID="IPWfDqBS109"/> - <_3:hasFile rdf:nodeID="IPWfDqBS535"/> - <_3:hasFile rdf:nodeID="IPWfDqBS439"/> - <_3:hasFile rdf:nodeID="IPWfDqBS597"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1137"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1267"/> - <_3:hasFile rdf:nodeID="IPWfDqBS667"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1419"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1519"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1575"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1213"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1549"/> - <_3:hasFile rdf:nodeID="IPWfDqBS465"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1531"/> - <_3:hasFile rdf:nodeID="IPWfDqBS237"/> - <_3:hasFile rdf:nodeID="IPWfDqBS499"/> - <_3:hasFile rdf:nodeID="IPWfDqBS733"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1407"/> - <_3:hasFile rdf:nodeID="IPWfDqBS999"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1077"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1231"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1715"/> - <_3:hasFile rdf:nodeID="IPWfDqBS497"/> - <_3:hasFile rdf:nodeID="IPWfDqBS355"/> - <_3:hasFile rdf:nodeID="IPWfDqBS659"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1485"/> - <_3:hasFile rdf:nodeID="IPWfDqBS805"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1101"/> - <_3:hasFile rdf:nodeID="IPWfDqBS951"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1125"/> - <_3:hasFile rdf:nodeID="IPWfDqBS665"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1717"/> - <_3:hasFile rdf:nodeID="IPWfDqBS787"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1193"/> - <_3:hasFile rdf:nodeID="IPWfDqBS573"/> - <_3:hasFile rdf:nodeID="IPWfDqBS891"/> - <_3:hasFile rdf:nodeID="IPWfDqBS53"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1699"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1579"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1133"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1785"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1745"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1725"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1541"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1693"/> - <_3:hasFile rdf:nodeID="IPWfDqBS393"/> - <_3:hasFile rdf:nodeID="IPWfDqBS821"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1315"/> - <_3:hasFile rdf:nodeID="IPWfDqBS171"/> - <_3:hasFile rdf:nodeID="IPWfDqBS647"/> - <_3:hasFile rdf:nodeID="IPWfDqBS449"/> - <_3:hasFile rdf:nodeID="IPWfDqBS633"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1749"/> - <_3:hasFile rdf:nodeID="IPWfDqBS91"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1511"/> - <_3:hasFile rdf:nodeID="IPWfDqBS779"/> - <_3:hasFile rdf:nodeID="IPWfDqBS263"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1565"/> - <_3:hasFile rdf:nodeID="IPWfDqBS653"/> - <_3:hasFile rdf:nodeID="IPWfDqBS767"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1265"/> - <_3:hasFile rdf:nodeID="IPWfDqBS751"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1147"/> - <_3:hasFile rdf:nodeID="IPWfDqBS555"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1015"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1797"/> - <_3:hasFile rdf:nodeID="IPWfDqBS557"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1603"/> - <_3:hasFile rdf:nodeID="IPWfDqBS455"/> - <_3:hasFile rdf:nodeID="IPWfDqBS825"/> - <_3:hasFile rdf:nodeID="IPWfDqBS259"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1487"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1353"/> - <_3:hasFile rdf:nodeID="IPWfDqBS785"/> - <_3:hasFile rdf:nodeID="IPWfDqBS567"/> - <_3:hasFile rdf:nodeID="IPWfDqBS685"/> - <_3:hasFile rdf:nodeID="IPWfDqBS127"/> - <_3:hasFile rdf:nodeID="IPWfDqBS317"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1089"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1073"/> - <_3:hasFile rdf:nodeID="IPWfDqBS77"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1687"/> - <_3:hasFile rdf:nodeID="IPWfDqBS111"/> - <_3:hasFile rdf:nodeID="IPWfDqBS195"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1781"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1081"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1171"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1523"/> - <_3:hasFile rdf:nodeID="IPWfDqBS777"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1747"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1499"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1003"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1247"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1063"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1011"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1491"/> - <_3:hasFile rdf:nodeID="IPWfDqBS561"/> - <_3:hasFile rdf:nodeID="IPWfDqBS165"/> - <_3:hasFile rdf:nodeID="IPWfDqBS559"/> - <_3:hasFile rdf:nodeID="IPWfDqBS623"/> - <_3:hasFile rdf:nodeID="IPWfDqBS267"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1195"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1501"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1035"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1151"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1481"/> - <_3:hasFile rdf:nodeID="IPWfDqBS855"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1099"/> - <_3:hasFile rdf:nodeID="IPWfDqBS927"/> - <_3:hasFile rdf:nodeID="IPWfDqBS41"/> - <_3:hasFile rdf:nodeID="IPWfDqBS35"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1333"/> - <_3:hasFile rdf:nodeID="IPWfDqBS923"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1241"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1591"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1783"/> - <_3:hasFile rdf:nodeID="IPWfDqBS845"/> - <_3:hasFile rdf:nodeID="IPWfDqBS483"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1735"/> - <_3:hasFile rdf:nodeID="IPWfDqBS775"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1457"/> - <_3:hasFile rdf:nodeID="IPWfDqBS417"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1155"/> - <_3:hasFile rdf:nodeID="IPWfDqBS729"/> - <_3:hasFile rdf:nodeID="IPWfDqBS325"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1763"/> - <_3:hasFile rdf:nodeID="IPWfDqBS529"/> - <_3:hasFile rdf:nodeID="IPWfDqBS523"/> - <_3:hasFile rdf:nodeID="IPWfDqBS419"/> - <_3:hasFile rdf:nodeID="IPWfDqBS511"/> - <_3:hasFile rdf:nodeID="IPWfDqBS471"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1463"/> - <_3:hasFile rdf:nodeID="IPWfDqBS905"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1309"/> - <_3:hasFile rdf:nodeID="IPWfDqBS469"/> - <_3:hasFile rdf:nodeID="IPWfDqBS719"/> - <_3:hasFile rdf:nodeID="IPWfDqBS899"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1283"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1685"/> - <_3:hasFile rdf:nodeID="IPWfDqBS857"/> - <_3:hasFile rdf:nodeID="IPWfDqBS837"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1281"/> - <_3:hasFile rdf:nodeID="IPWfDqBS307"/> - <_3:hasFile rdf:nodeID="IPWfDqBS941"/> - <_3:hasFile rdf:nodeID="IPWfDqBS47"/> - <_3:hasFile rdf:nodeID="IPWfDqBS549"/> - <_3:hasFile rdf:nodeID="IPWfDqBS93"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1561"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1495"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1305"/> - <_3:hasFile rdf:nodeID="IPWfDqBS971"/> - <_3:hasFile rdf:nodeID="IPWfDqBS965"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1149"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1165"/> - <_3:hasFile rdf:nodeID="IPWfDqBS761"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1647"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1201"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1131"/> - <_3:hasFile rdf:nodeID="IPWfDqBS759"/> - <_3:hasFile rdf:nodeID="IPWfDqBS935"/> - <_3:hasFile rdf:nodeID="IPWfDqBS445"/> - <_3:hasFile rdf:nodeID="IPWfDqBS599"/> - <_3:hasFile rdf:nodeID="IPWfDqBS231"/> - <_3:hasFile rdf:nodeID="IPWfDqBS657"/> - <_3:hasFile rdf:nodeID="IPWfDqBS743"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1363"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1259"/> - <_3:hasFile rdf:nodeID="IPWfDqBS411"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1681"/> - <_3:hasFile rdf:nodeID="IPWfDqBS335"/> - <_3:hasFile rdf:nodeID="IPWfDqBS219"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1307"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1543"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1793"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1095"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1317"/> - <_3:hasFile rdf:nodeID="IPWfDqBS641"/> - <_3:hasFile rdf:nodeID="IPWfDqBS333"/> - <_3:hasFile rdf:nodeID="IPWfDqBS883"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1509"/> - <_3:hasFile rdf:nodeID="IPWfDqBS707"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1503"/> - <_3:hasFile rdf:nodeID="IPWfDqBS251"/> - <_3:hasFile rdf:nodeID="IPWfDqBS681"/> - <_3:hasFile rdf:nodeID="IPWfDqBS101"/> - <_3:hasFile rdf:nodeID="IPWfDqBS577"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1017"/> - <_3:hasFile rdf:nodeID="IPWfDqBS201"/> - <_3:hasFile rdf:nodeID="IPWfDqBS473"/> - <_3:hasFile rdf:nodeID="IPWfDqBS997"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1237"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1301"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1075"/> - <_3:hasFile rdf:nodeID="IPWfDqBS839"/> - <_3:hasFile rdf:nodeID="IPWfDqBS413"/> - <_3:hasFile rdf:nodeID="IPWfDqBS661"/> - <_3:hasFile rdf:nodeID="IPWfDqBS867"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1345"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1225"/> - <_3:hasFile rdf:nodeID="IPWfDqBS441"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1199"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1521"/> - <_3:hasFile rdf:nodeID="IPWfDqBS145"/> - <_3:hasFile rdf:nodeID="IPWfDqBS235"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1767"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1479"/> - <_3:hasFile rdf:nodeID="IPWfDqBS955"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1109"/> - <_3:hasFile rdf:nodeID="IPWfDqBS175"/> - <_3:hasFile rdf:nodeID="IPWfDqBS319"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1645"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1191"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1417"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1207"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1641"/> - <_3:hasFile rdf:nodeID="IPWfDqBS553"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1059"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1381"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1371"/> - <_3:hasFile rdf:nodeID="IPWfDqBS887"/> - <_3:hasFile rdf:nodeID="IPWfDqBS689"/> - <_3:hasFile rdf:nodeID="IPWfDqBS995"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1493"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1321"/> - <_3:hasFile rdf:nodeID="IPWfDqBS247"/> - <_3:hasFile rdf:nodeID="IPWfDqBS73"/> - <_3:hasFile rdf:nodeID="IPWfDqBS583"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1341"/> - <_3:hasFile rdf:nodeID="IPWfDqBS503"/> - <_3:hasFile rdf:nodeID="IPWfDqBS85"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1313"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1119"/> - <_3:hasFile rdf:nodeID="IPWfDqBS563"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1385"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1209"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1319"/> - <_3:hasFile rdf:nodeID="IPWfDqBS229"/> - <_3:hasFile rdf:nodeID="IPWfDqBS121"/> - <_3:hasFile rdf:nodeID="IPWfDqBS593"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1423"/> - <_3:hasFile rdf:nodeID="IPWfDqBS975"/> - <_3:hasFile rdf:nodeID="IPWfDqBS271"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1203"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1707"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1021"/> - <_3:hasFile rdf:nodeID="IPWfDqBS19"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1335"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1483"/> - <_3:hasFile rdf:nodeID="IPWfDqBS989"/> - <_3:hasFile rdf:nodeID="IPWfDqBS463"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1611"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1637"/> - <_3:hasFile rdf:nodeID="IPWfDqBS81"/> - <_3:hasFile rdf:nodeID="IPWfDqBS239"/> - <_3:hasFile rdf:nodeID="IPWfDqBS683"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1451"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1421"/> - <_3:hasFile rdf:nodeID="IPWfDqBS281"/> - <_3:hasFile rdf:nodeID="IPWfDqBS481"/> - <_3:hasFile rdf:nodeID="IPWfDqBS399"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1609"/> - <_3:hasFile rdf:nodeID="IPWfDqBS223"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1261"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1121"/> - <_3:hasFile rdf:nodeID="IPWfDqBS421"/> - <_3:hasFile rdf:nodeID="IPWfDqBS351"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1669"/> - <_3:hasFile rdf:nodeID="IPWfDqBS631"/> - <_3:hasFile rdf:nodeID="IPWfDqBS509"/> - <_3:hasFile rdf:nodeID="IPWfDqBS99"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1013"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1143"/> - <_3:hasFile rdf:nodeID="IPWfDqBS57"/> - <_3:hasFile rdf:nodeID="IPWfDqBS151"/> - <_3:hasFile rdf:nodeID="IPWfDqBS921"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1437"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1257"/> - <_3:hasFile rdf:nodeID="IPWfDqBS385"/> - <_3:hasFile rdf:nodeID="IPWfDqBS983"/> - <_3:hasFile rdf:nodeID="IPWfDqBS45"/> - <_3:hasFile rdf:nodeID="IPWfDqBS625"/> - <_3:hasFile rdf:nodeID="IPWfDqBS309"/> - <_3:hasFile rdf:nodeID="IPWfDqBS75"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1671"/> - <_3:hasFile rdf:nodeID="IPWfDqBS269"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1661"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1041"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1085"/> - <_3:hasFile rdf:nodeID="IPWfDqBS69"/> - <_3:hasFile rdf:nodeID="IPWfDqBS321"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1631"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1665"/> - <_3:hasFile rdf:nodeID="IPWfDqBS225"/> - <_3:hasFile rdf:nodeID="IPWfDqBS869"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1615"/> - <_3:hasFile rdf:nodeID="IPWfDqBS521"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1027"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1187"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1391"/> - <_3:hasFile rdf:nodeID="IPWfDqBS123"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1123"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1773"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1331"/> - <_3:hasFile rdf:nodeID="IPWfDqBS881"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1069"/> - <_3:hasFile rdf:nodeID="IPWfDqBS37"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1177"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1597"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1339"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1807"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1351"/> - <_3:hasFile rdf:nodeID="IPWfDqBS133"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1253"/> - <_3:hasFile rdf:nodeID="IPWfDqBS735"/> - <_3:hasFile rdf:nodeID="IPWfDqBS137"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1567"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1303"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1349"/> - <_3:hasFile rdf:nodeID="IPWfDqBS97"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1435"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1537"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1197"/> - <_3:hasFile rdf:nodeID="IPWfDqBS381"/> - <_3:hasFile rdf:nodeID="IPWfDqBS243"/> - <_3:hasFile rdf:nodeID="IPWfDqBS595"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1673"/> - <_3:hasFile rdf:nodeID="IPWfDqBS833"/> - <_3:hasFile rdf:nodeID="IPWfDqBS405"/> - <_3:hasFile rdf:nodeID="IPWfDqBS289"/> - <_3:hasFile rdf:nodeID="IPWfDqBS261"/> - <_3:hasFile rdf:nodeID="IPWfDqBS141"/> - <_3:hasFile rdf:nodeID="IPWfDqBS727"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1619"/> - <_3:hasFile rdf:nodeID="IPWfDqBS915"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1249"/> - <_3:hasFile rdf:nodeID="IPWfDqBS815"/> - <_3:hasFile rdf:nodeID="IPWfDqBS361"/> - <_3:hasFile rdf:nodeID="IPWfDqBS791"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1765"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1655"/> - <_3:hasFile rdf:nodeID="IPWfDqBS565"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1357"/> - <_3:hasFile rdf:nodeID="IPWfDqBS61"/> - <_3:hasFile rdf:nodeID="IPWfDqBS265"/> - <_3:hasFile rdf:nodeID="IPWfDqBS831"/> - <_3:hasFile rdf:nodeID="IPWfDqBS457"/> - <_3:hasFile rdf:nodeID="IPWfDqBS579"/> - <_3:hasFile rdf:nodeID="IPWfDqBS827"/> - <_3:hasFile rdf:nodeID="IPWfDqBS163"/> - <_3:hasFile rdf:nodeID="IPWfDqBS153"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1739"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1297"/> - <_3:hasFile rdf:nodeID="IPWfDqBS65"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1431"/> - <_3:hasFile rdf:nodeID="IPWfDqBS347"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1145"/> - <_3:hasFile rdf:nodeID="IPWfDqBS105"/> - <_3:hasFile rdf:nodeID="IPWfDqBS337"/> - <_3:hasFile rdf:nodeID="IPWfDqBS803"/> - <_3:hasFile rdf:nodeID="IPWfDqBS769"/> - <_3:hasFile rdf:nodeID="IPWfDqBS95"/> - <_3:hasFile rdf:nodeID="IPWfDqBS781"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1461"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1087"/> - <_3:hasFile rdf:nodeID="IPWfDqBS693"/> - <_3:hasFile rdf:nodeID="IPWfDqBS961"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1777"/> - <_3:hasFile rdf:nodeID="IPWfDqBS39"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1205"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1179"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1389"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1061"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1329"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1403"/> - <_3:hasFile rdf:nodeID="IPWfDqBS957"/> - <_3:hasFile rdf:nodeID="IPWfDqBS757"/> - <_3:hasFile rdf:nodeID="IPWfDqBS143"/> - <_3:hasFile rdf:nodeID="IPWfDqBS977"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1683"/> - <_3:hasFile rdf:nodeID="IPWfDqBS797"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1053"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1529"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1505"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1181"/> - <_3:hasFile rdf:nodeID="IPWfDqBS703"/> - <_3:hasFile rdf:nodeID="IPWfDqBS937"/> - <_3:hasFile rdf:nodeID="IPWfDqBS701"/> - <_3:hasFile rdf:nodeID="IPWfDqBS571"/> - <_3:hasFile rdf:nodeID="IPWfDqBS409"/> - <_3:hasFile rdf:nodeID="IPWfDqBS763"/> - <_3:hasFile rdf:nodeID="IPWfDqBS353"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1775"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1585"/> - <_3:hasFile rdf:nodeID="IPWfDqBS789"/> - <_3:hasFile rdf:nodeID="IPWfDqBS131"/> - <_3:hasFile rdf:nodeID="IPWfDqBS323"/> - <_3:hasFile rdf:nodeID="IPWfDqBS895"/> - <_3:hasFile rdf:nodeID="IPWfDqBS519"/> - <_3:hasFile rdf:nodeID="IPWfDqBS985"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1475"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1571"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1079"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1043"/> - <_3:hasFile rdf:nodeID="IPWfDqBS255"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1221"/> - <_3:hasFile rdf:nodeID="IPWfDqBS793"/> - <_3:hasFile rdf:nodeID="IPWfDqBS533"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1805"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1383"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1067"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1269"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1553"/> - <_3:hasFile rdf:nodeID="IPWfDqBS979"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1761"/> - <_3:hasFile rdf:nodeID="IPWfDqBS29"/> - <_3:hasFile rdf:nodeID="IPWfDqBS273"/> - <_3:hasFile rdf:nodeID="IPWfDqBS541"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1497"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1489"/> - <_3:hasFile rdf:nodeID="IPWfDqBS7"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1719"/> - <_3:hasFile rdf:nodeID="IPWfDqBS407"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1651"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1007"/> - <_3:hasFile rdf:nodeID="IPWfDqBS161"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1107"/> - <_3:hasFile rdf:nodeID="IPWfDqBS459"/> - <_3:hasFile rdf:nodeID="IPWfDqBS601"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1547"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1599"/> - <_3:hasFile rdf:nodeID="IPWfDqBS357"/> - <_3:hasFile rdf:nodeID="IPWfDqBS865"/> - <_3:hasFile rdf:nodeID="IPWfDqBS367"/> - <_3:hasFile rdf:nodeID="IPWfDqBS953"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1023"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1163"/> - <_3:hasFile rdf:nodeID="IPWfDqBS945"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1689"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1091"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1037"/> - <_3:hasFile rdf:nodeID="IPWfDqBS835"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1033"/> - <_3:hasFile rdf:nodeID="IPWfDqBS49"/> - <_3:hasFile rdf:nodeID="IPWfDqBS303"/> - <_3:hasFile rdf:nodeID="IPWfDqBS297"/> - <_3:hasFile rdf:nodeID="IPWfDqBS691"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1097"/> - <_3:hasFile rdf:nodeID="IPWfDqBS359"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1323"/> - <_3:hasFile rdf:nodeID="IPWfDqBS531"/> - <_3:hasFile rdf:nodeID="IPWfDqBS679"/> - <_3:hasFile rdf:nodeID="IPWfDqBS801"/> - <_3:hasFile rdf:nodeID="IPWfDqBS169"/> - <_3:hasFile rdf:nodeID="IPWfDqBS939"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1299"/> - <_3:hasFile rdf:nodeID="IPWfDqBS811"/> - <_3:hasFile rdf:nodeID="IPWfDqBS17"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1047"/> - <_3:hasFile rdf:nodeID="IPWfDqBS383"/> - <_3:hasFile rdf:nodeID="IPWfDqBS809"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1525"/> - <_3:hasFile rdf:nodeID="IPWfDqBS475"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1005"/> - <_3:hasFile rdf:nodeID="IPWfDqBS861"/> - <_3:hasFile rdf:nodeID="IPWfDqBS215"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1803"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1753"/> - <_3:hasFile rdf:nodeID="IPWfDqBS991"/> - <_3:hasFile rdf:nodeID="IPWfDqBS677"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1695"/> - <_3:hasFile rdf:nodeID="IPWfDqBS609"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1465"/> - <_3:hasFile rdf:nodeID="IPWfDqBS63"/> - <_3:hasFile rdf:nodeID="IPWfDqBS959"/> - <_3:hasFile rdf:nodeID="IPWfDqBS147"/> - <_3:hasFile rdf:nodeID="IPWfDqBS655"/> - <_3:hasFile rdf:nodeID="IPWfDqBS193"/> - <_3:hasFile rdf:nodeID="IPWfDqBS429"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1211"/> - <_3:hasFile rdf:nodeID="IPWfDqBS71"/> - <_3:hasFile rdf:nodeID="IPWfDqBS415"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1361"/> - <_3:hasFile rdf:nodeID="IPWfDqBS585"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1477"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1771"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1369"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1117"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1263"/> - <_3:hasFile rdf:nodeID="IPWfDqBS33"/> - <_3:hasFile rdf:nodeID="IPWfDqBS551"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1279"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1721"/> - <_3:hasFile rdf:nodeID="IPWfDqBS967"/> - <_3:hasFile rdf:nodeID="IPWfDqBS139"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1127"/> - <_3:hasFile rdf:nodeID="IPWfDqBS817"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1375"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1795"/> - <_3:hasFile rdf:nodeID="IPWfDqBS401"/> - <_3:hasFile rdf:nodeID="IPWfDqBS395"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1289"/> - <_3:hasFile rdf:nodeID="IPWfDqBS329"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1377"/> - <_3:hasFile rdf:nodeID="IPWfDqBS925"/> - <_3:hasFile rdf:nodeID="IPWfDqBS873"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1607"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1625"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1727"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1045"/> - <_3:hasFile rdf:nodeID="IPWfDqBS663"/> - <_3:hasFile rdf:nodeID="IPWfDqBS59"/> - <_3:hasFile rdf:nodeID="IPWfDqBS819"/> - <_3:hasFile rdf:nodeID="IPWfDqBS189"/> - <_3:hasFile rdf:nodeID="IPWfDqBS345"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1325"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1001"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1227"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1515"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1621"/> - <_3:hasFile rdf:nodeID="IPWfDqBS903"/> - <_3:hasFile rdf:nodeID="IPWfDqBS695"/> - <_3:hasFile rdf:nodeID="IPWfDqBS605"/> - <_3:hasFile rdf:nodeID="IPWfDqBS705"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1167"/> - <_3:hasFile rdf:nodeID="IPWfDqBS893"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1709"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1019"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1189"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1755"/> - <_3:hasFile rdf:nodeID="IPWfDqBS425"/> - <_3:hasFile rdf:nodeID="IPWfDqBS713"/> - <_3:hasFile rdf:nodeID="IPWfDqBS919"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1539"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1409"/> - <_3:hasFile rdf:nodeID="IPWfDqBS515"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1705"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1569"/> - <_3:hasFile rdf:nodeID="IPWfDqBS313"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1593"/> - <_3:hasFile rdf:nodeID="IPWfDqBS157"/> - <_3:hasFile rdf:nodeID="IPWfDqBS517"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1105"/> - <_3:hasFile rdf:nodeID="IPWfDqBS687"/> - <_3:hasFile rdf:nodeID="IPWfDqBS135"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1517"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1217"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1427"/> - <_3:hasFile rdf:nodeID="IPWfDqBS491"/> - <_3:hasFile rdf:nodeID="IPWfDqBS669"/> - <_3:hasFile rdf:nodeID="IPWfDqBS745"/> - <_3:hasFile rdf:nodeID="IPWfDqBS643"/> - <_3:hasFile rdf:nodeID="IPWfDqBS697"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1447"/> - <_3:hasFile rdf:nodeID="IPWfDqBS31"/> - <_3:hasFile rdf:nodeID="IPWfDqBS543"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1255"/> - <_3:hasFile rdf:nodeID="IPWfDqBS613"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1245"/> - <_3:hasFile rdf:nodeID="IPWfDqBS293"/> - <_3:hasFile rdf:nodeID="IPWfDqBS909"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1769"/> - <_3:hasFile rdf:nodeID="IPWfDqBS43"/> - <_3:hasFile rdf:nodeID="IPWfDqBS241"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1393"/> - <_3:hasFile rdf:nodeID="IPWfDqBS117"/> - <_3:hasFile rdf:nodeID="IPWfDqBS369"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1677"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1449"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1065"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1029"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1667"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1239"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1629"/> - <_3:hasFile rdf:nodeID="IPWfDqBS15"/> - <_3:hasFile rdf:nodeID="IPWfDqBS619"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1293"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1563"/> - <_3:hasFile rdf:nodeID="IPWfDqBS527"/> - <_3:hasFile rdf:nodeID="IPWfDqBS177"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1405"/> - <_3:hasFile rdf:nodeID="IPWfDqBS993"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1367"/> - <_3:hasFile rdf:nodeID="IPWfDqBS363"/> - <_3:hasFile rdf:nodeID="IPWfDqBS749"/> - <_3:hasFile rdf:nodeID="IPWfDqBS119"/> - <_3:hasFile rdf:nodeID="IPWfDqBS211"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1387"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1729"/> - <_3:hasFile rdf:nodeID="IPWfDqBS901"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1113"/> - <_3:hasFile rdf:nodeID="IPWfDqBS103"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1365"/> - <_3:hasFile rdf:nodeID="IPWfDqBS505"/> - <_3:hasFile rdf:nodeID="IPWfDqBS907"/> - <_3:hasFile rdf:nodeID="IPWfDqBS673"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1459"/> - <_3:hasFile rdf:nodeID="IPWfDqBS645"/> - <_3:hasFile rdf:nodeID="IPWfDqBS387"/> - <_3:hasFile rdf:nodeID="IPWfDqBS513"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1691"/> - <_3:hasFile rdf:nodeID="IPWfDqBS9"/> - <_3:hasFile rdf:nodeID="IPWfDqBS113"/> - <_3:hasFile rdf:nodeID="IPWfDqBS929"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1589"/> - <_3:hasFile rdf:nodeID="IPWfDqBS589"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1129"/> - <_3:hasFile rdf:nodeID="IPWfDqBS987"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1055"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1581"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1057"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1169"/> - <_3:hasFile rdf:nodeID="IPWfDqBS277"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1071"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1287"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1397"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1373"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1223"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1233"/> - <_3:hasFile rdf:nodeID="IPWfDqBS221"/> - <_3:hasFile rdf:nodeID="IPWfDqBS1473"/> - <_3:downloadLocation rdf:datatype="http://www.w3.org/2001/XMLSchema#anyURI">http://duktape.org/duktape-2.0.0.tar.xz - <_3:licenseComments>Duktape is copyrighted by its authors and licensed under the MIT license. MurmurHash2 is used internally, it is also under the MIT license. Duktape module loader is based on the CommonJS module loading specification (without sharing any code), CommonJS is under the MIT license. - <_3:licenseDeclared rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:homePage rdf:datatype="http://www.w3.org/2001/XMLSchema#anyURI">http://duktape.org/ - <_3:supplier>Organization: duktape.org - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:versionInfo>2.0.0 - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a5989c0742f4b6c6cb847275f6b4e4d1c78c6b0b - - - - <_3:fileName>./config/header-snippets/reject_fast_math.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS754"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f80f5ef421c8fea695b8028754704c22c3dad74d - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b5a79c153fd45b08931582302e7c63e071612148 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>01c0fcd4dc6762d4be2946af802e6acaadec993c - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>5833f862ccb539e1fb963d912e9430fa4bdeb467 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ddcdbc041baddc866b2864c8e68255fdf0dccde0 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>031ae3235611c0e0b2d8a1684053fc6b980e3f7b - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>3cdf24c947702ea84c7e7829f9c62333c701d21c - - - - <_3:fileName>./src-input/duk_regexp_compiler.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1676"/> - - - <_3:fileName>./config/config-options/DUK_USE_AUGMENT_ERROR_THROW.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1230"/> - - - <_3:fileName>./src-separate/duk_api_string.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS424"/> - - - <_3:fileName>./extras/module-duktape/Makefile - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1442"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bb4315b6b2a1e903a696ebcc550dd278e208f6ee - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ee95cfadbff61990ae6b33f8b7f3fcd61f563533 - - - - <_3:fileName>./config/config-options/DUK_USE_SECTION_B.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1184"/> - - - <_3:packageVerificationCodeExcludedFile>./license.spdx - <_3:packageVerificationCodeValue>83919bd0fb690bafef3fb9d69d377e09af9747c7 - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7b79fce07f8f8b9e6f07cad3555d71e42334a853 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c897c1c61bf2ddf0542809c83ab37276bf71f815 - - - - <_3:fileName>./config/header-snippets/64bitops.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS750"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>88bff259291d0c0045db28b79482aeec154b4a87 - - - - <_3:fileName>./config/config-options/DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS850"/> - - - <_3:fileName>./config/platforms/platform_openbsd.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS800"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>dfbbd8bc95a46f832c67ebf680b0c9b0888f6245 - - - - <_3:fileName>./src-input/duk_api_memory.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1646"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>eba10f01290917065c4b29830f029f9edb9de618 - - - - <_3:fileName>./config/config-options/DUK_USE_DOUBLE_LINKED_HEAP.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1134"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bdb9243b436ef5c70967bddd16d0cc9e74971b1c - - - - <_3:fileName>./src-input/builtins.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1650"/> - - - <_3:fileName>./src-separate/duk_hbufobj.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS288"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>219265e6b4f3c1a25e36ab84a760ddae7797fce5 - - - - <_3:fileName>./config/config-options/DUK_USE_MATH_FMAX.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1154"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bd938d928e81e72389fd32c90c0f4524594aaf19 - - - - <_3:fileName>./config/config-options/DUK_USE_DOUBLE_LE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1174"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>54558ada92f58a356ab20fae3096b57882930f60 - - - - <_3:fileName>./src-input/duk_hobject_props.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1546"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>97ea8e8de93864cfcce483b0066bdcdb2c8af2ce - - - - <_3:fileName>./src-input/duk_bi_protos.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1602"/> - - - <_3:fileName>./src-separate/duk_hobject_enum.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS218"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a40d0374715746d167e89f0c61963f962a90165e - - - - <_3:fileName>./config/header-snippets/types_legacy.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS748"/> - - - <_3:fileName>./src-separate/duk_util_bufwriter.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS208"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>24b96d44acc76a490813e43a070e3d09f07782ce - - - - <_3:fileName>./config/config-options/DUK_USE_ARCH_STRING.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1074"/> - - - <_3:fileName>./src-input/duk_hobject_pc2line.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1576"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d6d966a9b8a8a8f44b9066a00da9f9ceb0aec2d5 - - - - <_3:fileName>./config/config-options/DUK_USE_ERRCREATE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS914"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>64839613434cb4c8d82ae07ea17933b448cf73f8 - - - - <_3:fileName>./config/feature-options/DUK_OPT_BUFFEROBJECT_SUPPORT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS634"/> - - - <_3:fileName>./config/feature-options/DUK_OPT_NO_SECTION_B.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS608"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a13012d5efdd48b39f2100d2d060e7f5d03dae3a - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>39377ca5ad8255d31ae2862d872151e035f2df6e - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d45f24269cb41394de0c5c7a647e20db063f2b1c - - - - <_3:fileName>./examples/hello/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS160"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>6348fc1ff60cc7ae12474faa6fe6598ba8b0b6d7 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>76deaceac1803dc35ad32593a3961f2ac3b3acd9 - - - - <_3:fileName>./config/config-options/DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS972"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ebe6476a85dd433c66abffbeca6c6105285824bf - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>03b4c77af1f40e8c1e4b853c1be252e126044582 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d664591350383e69ece0d236f7b894f7d4480825 - - - - <_3:fileName>./src-input/duk_hbufobj_misc.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1504"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>07b3a6879ea93374f9f2cd13bb236d6ecd269ea3 - - - - <_3:fileName>./config/config-options/DUK_USE_INTERRUPT_DEBUG_FIXUP.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1200"/> - - - <_3:fileName>./config/config-options/DUK_USE_NONSTD_ARRAY_MAP_TRAILER.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1272"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ab83cd50472dcb13efa4a74a718740256ef3b1f3 - - - - <_3:fileName>./config/config-options/DUK_USE_MATH_ROUND.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS996"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8c5296a4a041af04aae3ff2678d7c1ce82b1edcc - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d70b4083ccd3b5dac32ad07e58d3132dc3390b79 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>58143c765e94cde57b4328d6de6a716bb14e598f - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4a9ef686f4680d9a05c42f82067b4cebe4fa695f - - - - <_3:fileName>./src-input/duk_json.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1654"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c5312406e1bef117c7264595e4ecb0b841f0f389 - - - - <_3:fileName>./config/config-options/DUK_USE_TRACEBACK_DEPTH.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1298"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>555555d7335078daa9a6d103651e7218abd2611e - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7fa8741e58cd98f607f5094f3fb190662d03b48a - - - - <_3:fileName>./src-input/duk_hobject_finalizer.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1534"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a3ebed7f54ca2678c040a4788af01e5ca665b1a7 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f789d1a5eb5d77bba4cced563970d4dcd2c44d68 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ea55a5be61f2eea1dc02ee6481fc836adef4404a - - - - <_3:fileName>./config/config-options/DUK_USE_DATAPTR16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1186"/> - - - <_3:fileName>./config/helper-snippets/DUK_F_ULL_CONSTS.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1362"/> - - - <_3:fileName>./Makefile.sandbox - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS24"/> - - - <_3:fileName>./config/feature-options/DUK_OPT_NO_REFERENCE_COUNTING.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS486"/> - - - <_3:fileName>./tools/dukutil.py - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1798"/> - - - <_3:fileName>./config/config-options/DUK_USE_PACK_GCC_ATTR.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1138"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>09bb0d45824e56bb64ee9e6e59f219130ffd4ecc - - - - <_3:fileName>./extras/console/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1420"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>cf3215413afe523b54b0e887b237cf788d925eab - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f79136aef9fb5e548d63b9520af7f4600207faa7 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1c245898a94c4ab12cda618dfe42ac8c48682c77 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1b4d42fe7d94810261aaa6b3f0a96d633e682e0e - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>6f41c758fc3f97aebfd2f62d2a09ae0548587c4b - - - - <_3:fileName>./config/config-options/DUK_USE_STRICT_UTF8_SOURCE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1232"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>3a0f7d3f3186b920867e4b3ac5767364005865e1 - - - - <_3:fileName>./extras/alloc-pool/duk_alloc_pool.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1486"/> - - - <_3:fileName>./config/other-defines/platform_functions.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS806"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b5ba28fbd30b118a931af50553988e092d5a97e1 - - - - <_3:fileName>./config/helper-snippets/DUK_F_UCLIBC.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1338"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9f7f3a805998f9625d68896a24f15a24d14896d7 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>5590b62977c295ffea8de128b75eb95e3667e413 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8e1a45476cf90a37c853d201c5bc07aec22b52b8 - - - - <_3:fileName>./src-input/duk_api_buffer.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1718"/> - - - <_3:fileName>./config/platforms/platform_generic.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS788"/> - - - <_3:fileName>./config/feature-options/DUK_OPT_EXEC_TIMEOUT_CHECK.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS604"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>525e80da2b6d3640fd42af0f662d7b68865d6529 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>763b6705afa7b6c6d028da04bb669e0e9fc11eb3 - - - - <_3:fileName>./tools/extract_chars.py - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1786"/> - - - <_3:fileName>./src-input/duk_debug_fixedbuffer.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1746"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ea413ed7d47cf27c6f3ffe25956b1370b653c200 - - - - <_3:fileName>./examples/debug-trans-socket/duk_trans_socket.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS172"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8cff533c618fccd4b0b57cd2548cc089155dd823 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>523e4f8a77802ab002b00257f92d44f4a91e3a95 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>22577ac0780d7a5db504ccddda510b881fb234ac - - - - <_3:fileName>./src-separate/duk_bi_boolean.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS376"/> - - - <_3:fileName>./config/config-options/DUK_USE_ESBC_MAX_LINENUMBER.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS860"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bfc7f6c09c5804217368c10e920d27172d88959f - - - - <_3:fileName>./config/helper-snippets/DUK_F_PPC.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1328"/> - - - <_3:fileName>./config/feature-options/DUK_OPT_NO_JC.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS556"/> - - - <_3:fileName>./src-separate/duk_api_object.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS356"/> - - - <_3:fileName>./config/architectures/architecture_arm64.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS826"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>3f899f6333159173bdb8165e48350567c34d14dc - - - - <_3:fileName>./config/helper-snippets/DUK_F_QNX.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1354"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a5a476d653ecaa3b94218ad646065fb949e8d62d - - - - <_3:fileName>./config/config-options/DUK_USE_ERRTHROW.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1316"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>47443510d688691ed0eaa5a3885012265ba6f05c - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f02e11dc0003c18558fc9fb59cbd39363eda6518 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ff69aff0a588f5c66dc08c3ab096ae91a9406da5 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ab40ea7b5e44bb61b688d9a8eebce7ec40cef1d1 - - - - <_3:fileName>./src-input/duk_bi_array.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1688"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1043c0b85f86de642ecdac58e1002ae714f05b8c - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b26846101ed45e884911c4314279ee62dce2fe36 - - - - <_3:fileName>./examples/alloc-logging/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS196"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>3a2d38d8c3e0191f6634862247f4f7631be8e9a8 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>67221a936e2ce8fb69d90c32f412adef5867dc90 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8d1131dd16033521735614833194563fdbd5608c - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c7dc5159da983151a1718707eb5009570318b546 - - - - <_3:fileName>./src-input/duk_util.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1524"/> - - - <_3:fileName>./config/config-options/DUK_USE_BYTECODE_DUMP_SUPPORT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1012"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>feca5644b37aca10a7bd2fee0551f255169b99ca - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>acfd32ba813477baadf8d5e3a14a922289f13463 - - - - <_3:fileName>./src-input/duk_numconv.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1502"/> - - - <_3:fileName>./config/config-options/DUK_USE_IDCHAR_FASTPATH.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1178"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bb94ce16f0e382c5f77d3f25b34f98dbb3774c0f - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b6247f203a3a957776207ea56985300096ac13ee - - - - <_3:fileName>./tools/scan_used_stridx_bidx.py - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1784"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b4c0ca5ddc8e53a64857da5d6602d25e87ce82fb - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>5f89917c0262574a299a19edd39ed1d4802162f3 - - - - <_3:fileName>./config/platforms/platform_tos.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS776"/> - - - <_3:fileName>./config/config-options/DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1164"/> - - - <_3:fileName>./config/header-snippets/types2.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS730"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>5d5e2dac5c9d27d2d0cfcca8dc83937d8429eb96 - - - - <_3:fileName>./config/feature-options/DUK_OPT_FASTINT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS530"/> - - - <_3:fileName>./config/feature-options/DUK_OPT_UNDERSCORE_SETJMP.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS524"/> - - - <_3:fileName>./config/feature-options/DUK_OPT_NO_COMMONJS_MODULES.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS512"/> - - - <_3:fileName>./config/tags.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS472"/> - - - <_3:fileName>./extras/module-node/duk_module_node.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1464"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>5590b62977c295ffea8de128b75eb95e3667e413 - - - - <_3:fileName>./config/config-options/DUK_USE_DPRINT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1310"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>78289788e94f30189cc26b68f6780136639fd5b2 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9d97cd24eba146d098b88505afb3e9d9c71fb05a - - - - <_3:fileName>./config/examples/compliance.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS720"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>82314b509ee3b15b393fefe747c8e0169ab39aaa - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>484fb41d516abcbe8c97af5aa80b76c67dbfb0cb - - - - <_3:fileName>./config/architectures/architecture_superh.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS838"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>6389e13711ca106d4b29f9c948970cbdd73871de - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>db4b6e4c8be849b5c0b0a84df9f1f0154d0c7708 - - - - <_3:fileName>./src-input/SpecialCasing-8bit.txt - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1710"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ec4eb4acda5042e218ce3f3d68d34e2c83a0f9f9 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>31149151d8a28798b96e542d77ca605c6669430c - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bcfed1d744e13b2d3fe0256385fd8053005f78fd - - - - <_3:fileName>./extras/logging/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1450"/> - - - <_3:fileName>./config/config-options/DUK_USE_REFCOUNT16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS936"/> - - - <_3:fileName>./src-separate/duk_alloc_default.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS446"/> - - - <_3:fileName>./config/header-snippets/platform_fillins.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS744"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>07b50af99a03e22031d88d803f1026fe1e78313e - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9f8f21626bc2389e86b7228f926cb293b072d3c8 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4310cf609e97ce1d4cfaafa8c5060580b946fe95 - - - - <_3:fileName>./config/config-options/DUK_USE_ZERO_BUFFER_DATA.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1318"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>af6b0cd61c02efa575b9106682606297d26f013b - - - - <_3:fileName>./src-input/duk_js_compiler.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1628"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>6e5ab10b5431e945a8aa3625190e89a56ee6f424 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>820715160155bc4e82c401e1650efc80972071b8 - - - - <_3:fileName>./src-separate/duk_unicode_support.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS202"/> - - - <_3:fileName>./config/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS474"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4b2165beaa1a153360cbf9cb6a667c19964e1d6c - - - - <_3:fileName>./extras/duk-v1-compat/duk_v1_compat.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1412"/> - - - <_3:fileName>./src-input/duk_api_debug.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1512"/> - - - <_3:fileName>./config/config-options/DUK_USE_PANIC_HANDLER.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS840"/> - - - <_3:fileName>./config/feature-options/DUK_OPT_TARGET_INFO.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS516"/> - - - <_3:fileName>./config/helper-snippets/DUK_F_BCC.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1350"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>08bb3e8bcdb54506629bafa0458490fe214cd138 - - - - <_3:fileName>./examples/guide/process.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS146"/> - - - <_3:fileName>./src-separate/duk_hthread_misc.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS236"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>93573df8348a41adb790f59e39bf99d9a7bf3a3d - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>895bd58e08b961fdb938f83648059c42b7e38255 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>01faca6e5c2f2d1bb900568ce77b723a6c123b4b - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c66e7d39f7dce513264d511f05dcc60934a5d7d5 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d8b699b9aa839228e9713c3edd6af63b67406c66 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9e401b9c2bfc0c884067440ca4654fc34efac9ad - - - - <_3:fileName>./config/config-options/DUK_USE_ROM_GLOBAL_INHERIT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1060"/> - - - <_3:fileName>./src-input/duk_hobject.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1686"/> - - - <_3:fileName>./src-separate/duk_bi_encoding.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS248"/> - - - <_3:fileName>./config/helper-snippets/DUK_F_C99.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1386"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>fdea20e9cbcd771f4dc1495f079f64a2a91a501f - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>09ee87b3ae8afe8b7c2295127835b05b00603b25 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0c8c6a420632c5787d7af455c9bf89586549d970 - - - - <_3:fileName>./config/feature-options/DUK_OPT_EXAMPLE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS594"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>043c5603e35121d4eb613e7b9d87c1dc7e353ecb - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>550d1c67a391fa6ad171bf39e278d6edb2e1655a - - - - <_3:fileName>./tools/dump_bytecode.py - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1792"/> - - - <_3:fileName>./config/config-options/DUK_USE_DEBUGGER_SUPPORT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1202"/> - - - <_3:fileName>./tools/extract_caseconv.py - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1794"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>75d1b90f973098d6549bee80963392803e6ea25c - - - - <_3:fileName>./config/config-options/DUK_USE_ARRAY_PROP_FASTPATH.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS868"/> - - - <_3:fileName>./config/config-options/DUK_USE_VOLUNTARY_GC.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS956"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>62c3607437a8e017102ba2805a9d02b6ef237c8a - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>34ade3ad11cbaee09d7495fc67a012971f134b02 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>54558ada92f58a356ab20fae3096b57882930f60 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a80d9739d96708035b6a7d05f66337af84aa602f - - - - <_3:fileName>./src-separate/duk_bi_proxy.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS422"/> - - - <_3:fileName>./src-separate/duk_hthread.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS352"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a44f7292247d00bd4f2a0f234cf96bc51573081f - - - - <_3:fileName>./config/feature-options/DUK_OPT_DDPRINT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS632"/> - - - <_3:fileName>./config/feature-options/DUK_OPT_REFCOUNT16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS510"/> - - - <_3:fileName>./examples/eventloop/main.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS100"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4044e8c57705c4e466130586954c05d972818406 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4baffeb2aa785bdc1065eb9ddb8c64c8a028655d - - - - <_3:fileName>./extras/module-duktape/duk_module_duktape.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1438"/> - - - <_3:fileName>./src-separate/duk_hobject.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS386"/> - - - <_3:fileName>./examples/coffee/hello.coffee - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS76"/> - - - <_3:fileName>./src-input/duk_bi_boolean.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1672"/> - - - <_3:fileName>./src-separate/duk_forwdecl.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS270"/> - - - <_3:fileName>./config/config-options/DUK_USE_UNALIGNED_ACCESSES_POSSIBLE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1042"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>61043b4a6f3cf86375ea6e34ebf83b550a1935b2 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f0ded24e507b30368469fc37873f43866f7263bb - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>71d5cf27c55126c830521a986f4c0dced1f5f1e0 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2f76ddc687fbab7a6fbce2bf60e828c1b5f8384d - - - - <_3:fileName>./config/config-options/DUK_USE_COMMONJS_MODULES.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1300"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>5c2f7a75a864e293b930281437969ca35dfdb0ca - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b9ff938b290ad7d766e1d004d82609d0b8d34751 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7acd860e0b93fc4bed4960be0c9421cd544d9180 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7110f0a065541b2d2eb169badb3f6eaa5505032b - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>e0d4ca493223bebff11d87460121b0825f5d9242 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ca6fd53cd0140ef19ce816bbc50d8b6de9e55f1e - - - - <_3:fileName>./src-input/duk_hthread_builtins.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1598"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d273b0e72994792e9c30e2a77a2495040e896e53 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2e1c07e87002953c494e3e3424aa3a4c986960d0 - - - - <_3:fileName>./config/helper-snippets/DUK_F_ARM.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1352"/> - - - <_3:fileName>./config/config-options/DUK_USE_MATH_FMIN.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1254"/> - - - <_3:fileName>./config/header-snippets/alignment_fillin.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS736"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>dbb3d4542e0cc93dfff65b901f08c48440061edd - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>cdf7e844cd74b4d0277a3c54ef4f98e5029443b2 - - - - <_3:fileName>./examples/jxpretty/jxpretty.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS98"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7d9965b277af3b0a4be8000b833c29506638a60d - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>09239b0d8665e3fdb06e7d6e5c8be2cb20ae4de5 - - - - <_3:fileName>./src-separate/duk_hbuffer_ops.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS382"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>19f689b750db15a7cca576a630a249db15bcd32e - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>85e5af77abcef4bd9793000ef80ba8549b6d14ee - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2da826dfc0ccd82b32412fc19c18746cffabd3de - - - - <_3:fileName>./examples/guide/uppercase.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS142"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f13d6c338e5f33e8302ddb872c9130d8c3fdd3b5 - - - - <_3:fileName>./extras/logging/test.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1454"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>65116139ca353060adb8109691eef6f2c36cbeea - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>caa1f90113a2f6c2134aadd6d68fbd62d00bba3c - - - - <_3:fileName>./config/helper-snippets/DUK_F_POSIX.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1358"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>654056dc71de1907e361d2b599340fe38b220560 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7fd58215ed03b7f38f823c4909f50d8659f22aec - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>fda701fd3552814b654b4a2a42b197eaa370100e - - - - <_3:fileName>./LICENSE.txt - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS8"/> - - - <_3:fileName>./config/architectures/architecture_mips64.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS828"/> - - - <_3:fileName>./examples/cmdline/duk_cmdline.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS164"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>684fe1ca1b6a79846dbe3abe73d96283f56a4b83 - - - - <_3:fileName>./config/feature-options/DUK_OPT_DEBUGGER_DUMPHEAP.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS546"/> - - - <_3:fileName>./debugger/static/style.css - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS66"/> - - - <_3:fileName>./config/config-options/DUK_USE_FILE_IO.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1146"/> - - - <_3:fileName>./config/platforms/platform_genericunix.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS770"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>5ffa5691c16dbc417e047d80f538d9593850bfd7 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9b85fa1c1e28fabb7d32976be0f380d48f65cd90 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>174f7b632c99f1499a6cafdaab6d6d2e0556b02e - - - - <_3:fileName>./config/helper-snippets/DUK_F_ORBIS.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1390"/> - - - <_3:fileName>./config/helper-snippets/DUK_F_LINUX.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1330"/> - - - <_3:fileName>./extras/duk-v1-compat/test_eval2.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1404"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>09285654f142f03129319e150339445f41721cee - - - - <_3:fileName>./config/config-options/DUK_USE_PANIC_SEGFAULT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1054"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f503347d93483d5af29a4d68e514401f4bffc19c - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>996b3e7433e52ccda2f968f8eb6afd50c6f47eb0 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2ce8a3541834f4fe53f39191265370670300812a - - - - <_3:fileName>./config/examples/performance_sensitive.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS704"/> - - - <_3:fileName>./config/feature-options/DUK_OPT_DEEP_C_STACK.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS572"/> - - - <_3:fileName>./config/header-snippets/cpp_exception_sanity.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS764"/> - - - <_3:fileName>./src-separate/duk_json.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS354"/> - - - <_3:fileName>./tools/genconfig.py - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1776"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b6d0d99431d64f47e5a8086a8ca2d7b5af5f1568 - - - - <_3:fileName>./config/config-options/DUK_USE_DATE_TZO_GMTIME_R.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1044"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>fc75c97f35c16a8e964153c835ac36cda516fa04 - - - - <_3:fileName>./config/feature-options/DUK_OPT_STRLEN16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS534"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>6e79daebf74b5d1cb4ccbb1fa19f373d6a79a0fe - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>043b24a2cd514c40b4ce75bcd0204f2db8d5fd4f - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>6feece755ec26b4ba0b97340afc727839cbb10b6 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>72677c24d3803320172b5330a7678fedafa062c0 - - - - <_3:fileName>./src-input/duk_js_bytecode.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1554"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a8c0b54002a3a7d8c69d385e7fbcf4b70d1efc70 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a0a83407e2df1feec48016a43cb7727789c05b5d - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>58abb86f759d552a92afdb9154b3f6ec3df9c50a - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1c727e21ecd4e45f27b8cd9b673939889b55f10f - - - - <_3:fileName>./polyfills/duktape-buffer.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS458"/> - - - <_3:fileName>./src-separate/duk_js_executor.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS408"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>cf5cb3be898bfd3410e218750667856fb954cb98 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>44d586c078e67c7b60ce82c4e2704a18f92e3928 - - - - <_3:fileName>./config/config-options/DUK_USE_FUNC_FILENAME_PROPERTY.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1218"/> - - - <_3:fileName>./examples/cmdline/duk_cmdline_ajduk.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS162"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>be0e7eb2cebe3402a9c67065a051b343c2f38d46 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>59c2a146022c8f01d10d3663460b1917d7879392 - - - - <_3:fileName>./config/config-options/DUK_USE_STRHASH_DENSE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1006"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>df60e2cb707de62dfa29f7bf5d78c56505057aa3 - - - - <_3:fileName>./src-separate/duk_hobject_class.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS304"/> - - - <_3:fileName>./config/compilers/compiler_tinyc.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS692"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d4e7b072fdde2cb12a4b0b2b7971c9354d16d88e - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d01da2742622d5f681c612196b3bfab050c1aaf1 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>dbb3d4542e0cc93dfff65b901f08c48440061edd - - - - <_3:fileName>./config/compilers/compiler_clang.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS680"/> - - - <_3:fileName>./src-input/duk_forwdecl.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1564"/> - - - <_3:fileName>./config/architectures/architecture_x86.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS810"/> - - - <_3:fileName>./config/architectures.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS476"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ff804968ca8e7dd6e415126c35569127cb4a0725 - - - - <_3:fileName>./src-input/duk_debug_macros.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1754"/> - - - <_3:fileName>./config/config-options/DUK_USE_JSON_DECSTRING_FASTPATH.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS992"/> - - - <_3:fileName>./config/feature-options/DUK_OPT_DATAPTR16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS678"/> - - - <_3:fileName>./extras/module-node/duk_module_node.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1466"/> - - - <_3:fileName>./debugger/duk_opcodes.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS64"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1eb68650f26279fc1b8968055dce544385d6a954 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1b2d3fff9cdee972a43e472c1af229fe74ab3416 - - - - <_3:fileName>./examples/guide/primecheck.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS148"/> - - - <_3:fileName>./src-separate/duk_bi_global.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS226"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>18cffde6810c634fafad39bef2e89805d879c684 - - - - <_3:fileName>./examples/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS72"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>67912274a1cf6be140faff95ef0afcc5b6f1ad29 - - - - <_3:fileName>./config/config-options/DUK_USE_RDTSC.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1118"/> - - - <_3:fileName>./config/helper-snippets/DUK_F_CLANG.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1374"/> - - - <_3:fileName>./duk_dist_meta.json - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS34"/> - - - <_3:fileName>./config/feature-options/DUK_OPT_NO_VOLUNTARY_GC.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS552"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>23b9f2042c47a5d5fa473e3cad1647801091b868 - - - - <_3:fileName>./config/config-options/DUK_USE_ES6_REGEXP_BRACES.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1128"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0c06c4f4b278877410bf7e9af775913318b48738 - - - - <_3:fileName>./config/helper-snippets/DUK_F_NETBSD.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1376"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>422a4cc945db929af74e7ea09145b5be5aeedf5b - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1e1fd454558f0884153f735c187a3beedc7a44f0 - - - - <_3:fileName>./config/helper-snippets/DUK_F_CPP.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1378"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9cf89b0c8a1188f8bdca7a68c69c54fe73cd45ed - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>83a4f859444591fb0661eecf3be4aa937918c166 - - - - <_3:fileName>./config/feature-options/DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS664"/> - - - <_3:fileName>./config/config-options/DUK_USE_LEXER_SLIDING_WINDOW.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS844"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>6a1500fea27ea278c4f0c64d908e16cc60df684b - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>cb46ea9dcb2e07f36d9817a428922568891d02ce - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>e7b508c2336d82d12bf9a6dfa863a60f1ccb2f3f - - - - <_3:fileName>./config/config-options/DUK_USE_DEBUGGER_THROW_NOTIFY.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1016"/> - - - <_3:fileName>./config/examples/enable_debug_print1.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS714"/> - - - <_3:fileName>./config/config-options/DUK_USE_DEBUG_WRITE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS920"/> - - - <_3:fileName>./extras/duk-v1-compat/test_compile2.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1410"/> - - - <_3:fileName>./src-input/duk_api_inspect.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1570"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bd50c5d463e5e0af70c431bb415f823d634408cf - - - - <_3:fileName>./src-input/duk_heap_misc.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1594"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>53b7e23f085353f37438cb1b7e8757d66b753599 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a0633e6b3a780281a34f293b5476aacb6047974f - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>37bf12aa9253008f5b763d9f5d2d2ad26335ec7c - - - - <_3:fileName>./config/header-snippets/types_c99.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS746"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d8813198f0510fedcae2a8b6a8b1b4d0b7331484 - - - - <_3:fileName>./extras/logging/duk_logging.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1448"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c8714b619f0c719857cce2ffebff43a54fded469 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4f3fbede562fe5f3f2ffe49a0523779dc620c81a - - - - <_3:fileName>./config/feature-options/DUK_OPT_SETJMP.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS544"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9b4ed86ac44da12b78e9eb87d0d9aaa7149b0518 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d5c2fa62ed03af9de803157b465588e3ceb3787b - - - - <_3:fileName>./config/config-options/DUK_USE_VERBOSE_EXECUTOR_ERRORS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS910"/> - - - <_3:fileName>./examples/eventloop/basic-test.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS118"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f742435dd3ddc1ae6f2587856fd4b7aebeff1118 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0ee226edb0ea3c35fc0ff28499241a6dde397b38 - - - - <_3:fileName>./config/header-snippets/compiler_fillins.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS760"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bda50b818153f21b2be45976a6ac18f33b6c263d - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>877e40426fdcc613d4314889a30b93d526d420e3 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c2deb792abf0153293226495ae6bcdcd9c729fac - - - - <_3:fileName>./src-separate/duk_js_bytecode.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS260"/> - - - <_3:fileName>./examples/eventloop/poll.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS120"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>97f183cd870ccdfcd5335c6c8a2cf4ce6bd79345 - - - - <_3:fileName>./config/config-options/DUK_USE_ES6_OBJECT_PROTO_PROPERTY.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS902"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1cb1bb722401069e5bfadd20525727567109e0e0 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c5c07548a9924f5ec10ab0f39fa52424804f6be5 - - - - <_3:fileName>./config/feature-options/DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS674"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0fcd418bc6efe63f95bf4cdc1538dfd5f0ce6478 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b44e173d521416f444c72dad7ee63b7e8fc9b29f - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4e5a54de08355669dc98b5d4ad379384b33da4e5 - - - - <_3:fileName>./examples/eventloop/ecma_eventloop.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS114"/> - - - <_3:fileName>./config/config-options/DUK_USE_REGEXP_COMPILER_RECLIMIT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS930"/> - - - <_3:fileName>./config/config-options/DUK_USE_SYMBOL_BUILTIN.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1130"/> - - - <_3:fileName>./config/config-options/DUK_USE_COMPILER_RECLIMIT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1056"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>aa852ff18f4abd7522d0ee91a5887e9dd6431b54 - - - - <_3:fileName>./config/config-options/DUK_USE_JSON_QUOTESTRING_FASTPATH.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1072"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d5319628c9f9e16d2036ce7ebcda90483b5e369b - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a6421e1ac83fe5caba70acb338464e6a811ce160 - - - - <_3:fileName>./config/config-options/DUK_USE_JSON_SUPPORT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1234"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>174f7b632c99f1499a6cafdaab6d6d2e0556b02e - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>00b024d1353868edf2fe4c7d35d57218f14be057 - - - - <_3:fileName>./config/feature-options/DUK_OPT_DEBUG_BUFSIZE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS490"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>45391c3ac7f5de5a4480c83cce1c6a4946598174 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d9fb89aabcdd4ad250f9f0c16b28c48cc21c09fb - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b75a923c01d2a8997257370fefe859b43ae8ff8e - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>194e0bf80a1ddcc4d2d68ea6d2539656f3044f78 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>58f8147365c2618f8a718b5f3bfb6070b2429a96 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>3f55abd9ce2635fe2e20795f0356ccd72e2c3b99 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d51f7bfc58d650a8d0a67cb0b84eae4faec0c75b - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>6d6a0ed935fc74ff5163e40366294a0f759501f2 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0811e545a133c3a62672e239624a0c1f11478b8d - - - - <_3:fileName>./src-separate/duk_js_call.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS276"/> - - - <_3:describesPackage rdf:nodeID="IPWfDqBS4"/> - <_3:dataLicense rdf:resource="http://spdx.org/licenses/CC0-1.0"/> - <_3:creationInfo rdf:nodeID="IPWfDqBS3"/> - SPDX license for Duktape 2.0.0 - - <_3:specVersion>SPDX-1.2 - <_3:referencesFile rdf:nodeID="IPWfDqBS489"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1159"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS447"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS917"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS431"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS635"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS173"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS371"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS863"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1083"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS947"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS203"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1049"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS843"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS245"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS479"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS637"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS875"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS963"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS275"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS339"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1235"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS55"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS349"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS87"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS731"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS461"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1395"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1587"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS451"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1659"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS715"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS435"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS305"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS167"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS291"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS829"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS25"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS853"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1551"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS871"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1379"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1009"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS285"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1743"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS327"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS129"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1219"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1285"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1657"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS537"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1337"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS603"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS783"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS27"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1453"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS375"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS575"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS443"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1327"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1633"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1429"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1697"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1359"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS725"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS437"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1573"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS295"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1639"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS773"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS931"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1605"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS569"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1535"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS847"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS11"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS107"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1595"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS249"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS487"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1557"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS943"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1723"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1757"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS699"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS115"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS83"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS765"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1527"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1277"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS183"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1613"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1443"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS889"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1623"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS155"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1051"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1679"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1115"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1737"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS539"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS807"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1439"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS545"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1399"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1751"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS299"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS753"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1039"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1635"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS755"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS187"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS933"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1251"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS879"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1139"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS311"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1675"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1229"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS709"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS343"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1513"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS423"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1311"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1507"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1555"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS823"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1779"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1031"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1441"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS199"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1559"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1183"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1701"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS841"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1401"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS453"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1425"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1291"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS67"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS179"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1433"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS125"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1663"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS849"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS737"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS795"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS799"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS627"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS611"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1791"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1469"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS969"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS433"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS711"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS365"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS391"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS981"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS581"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS721"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1135"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS185"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1411"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1733"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1295"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1649"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS287"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1153"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS477"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1173"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS379"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1577"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS397"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1347"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1025"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1787"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS649"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1601"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1355"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS217"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1617"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS747"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS207"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS191"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1789"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1093"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1161"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS651"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS205"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1413"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1455"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1467"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS495"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS373"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS877"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS717"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS913"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1759"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS341"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS253"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS897"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1741"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS591"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS607"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1471"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1215"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS209"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1583"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS159"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS283"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS675"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1703"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS21"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1275"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS723"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS403"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS501"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1415"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS89"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1627"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1175"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS181"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS389"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS587"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1713"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS279"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1271"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1157"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS377"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS629"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1801"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS771"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS13"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS227"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1111"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS859"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS301"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS331"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1643"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS617"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS525"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS79"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS885"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS493"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1141"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS949"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS615"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS315"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1343"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1653"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS149"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1243"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS741"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1445"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS507"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1731"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS973"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS621"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS671"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS257"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS851"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1533"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS813"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS51"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1799"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS547"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1545"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS197"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1103"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS911"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS639"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1711"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS427"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1185"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1273"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS739"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS467"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS233"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS213"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS23"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS485"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS109"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS535"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS439"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS597"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1137"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1267"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS667"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1419"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1519"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1575"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1213"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1549"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS465"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1531"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS237"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS499"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS733"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1407"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS999"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1077"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1231"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1715"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS497"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS355"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS659"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1485"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS805"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1101"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS951"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1125"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS665"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1717"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS787"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1193"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS573"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS891"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS53"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1699"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1579"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1133"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1785"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1745"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1725"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1541"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1693"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS393"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS821"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1315"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS171"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS647"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS449"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS633"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1749"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS91"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1511"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS779"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS263"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1565"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS653"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS767"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1265"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS751"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1147"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS555"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1015"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1797"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS557"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1603"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS455"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS825"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS259"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1487"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1353"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS785"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS567"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS685"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS127"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS317"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1089"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1073"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS77"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1687"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS111"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS195"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1781"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1081"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1171"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1523"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS777"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1747"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1499"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1003"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1247"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1063"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1011"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1491"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS561"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS165"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS559"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS623"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS267"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1195"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1501"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1035"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1151"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1481"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS855"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1099"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS927"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS41"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS35"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1333"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS923"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1241"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1591"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1783"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS845"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS483"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1735"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS775"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1457"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS417"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1155"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS729"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS325"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1763"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS529"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS523"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS419"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS511"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS471"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1463"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS905"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1309"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS469"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS719"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS899"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1283"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1685"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS857"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS837"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1281"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS307"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS941"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS47"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS549"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS93"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1561"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1495"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1305"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS971"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS965"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1149"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1165"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS761"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1647"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1201"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1131"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS759"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS935"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS445"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS599"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS231"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS657"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS743"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1363"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1259"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS411"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1681"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS335"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS219"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1307"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1543"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1793"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1095"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1317"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS641"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS333"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS883"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1509"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS707"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1503"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS251"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS681"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS101"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS577"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1017"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS201"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS473"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS997"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1237"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1301"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1075"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS839"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS413"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS661"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS867"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1345"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1225"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS441"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1199"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1521"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS145"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS235"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1767"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1479"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS955"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1109"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS175"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS319"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1645"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1191"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1417"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1207"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1641"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS553"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1059"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1381"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1371"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS887"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS689"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS995"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1493"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1321"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS247"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS73"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS583"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1341"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS503"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS85"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1313"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1119"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS563"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1385"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1209"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1319"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS229"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS121"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS593"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1423"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS975"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS271"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1203"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1707"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1021"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS19"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1335"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1483"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS989"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS463"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1611"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1637"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS81"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS239"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS683"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1451"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1421"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS281"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS481"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS399"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1609"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS223"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1261"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1121"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS421"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS351"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1669"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS631"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS509"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS99"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1013"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1143"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS57"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS151"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS921"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1437"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1257"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS385"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS983"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS45"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS625"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS309"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS75"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1671"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS269"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1661"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1041"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1085"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS69"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS321"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1631"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1665"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS225"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS869"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1615"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS521"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1027"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1187"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1391"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS123"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1123"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1773"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1331"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS881"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1069"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS37"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1177"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1597"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1339"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1807"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1351"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS133"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1253"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS735"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS137"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1567"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1303"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1349"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS97"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1435"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1537"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1197"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS381"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS243"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS595"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1673"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS833"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS405"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS289"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS261"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS141"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS727"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1619"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS915"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1249"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS815"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS361"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS791"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1765"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1655"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS565"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1357"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS61"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS265"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS831"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS457"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS579"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS827"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS163"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS153"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1739"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1297"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS65"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1431"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS347"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1145"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS105"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS337"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS803"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS769"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS95"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS781"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1461"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1087"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS693"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS961"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1777"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS39"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1205"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1179"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1389"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1061"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1329"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1403"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS957"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS757"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS143"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS977"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1683"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS797"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1053"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1529"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1505"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1181"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS703"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS937"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS701"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS571"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS409"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS763"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS353"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1775"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1585"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS789"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS131"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS323"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS895"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS519"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS985"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1475"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1571"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1079"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1043"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS255"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1221"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS793"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS533"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1805"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1383"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1067"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1269"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1553"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS979"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1761"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS29"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS273"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS541"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1497"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1489"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS7"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1719"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS407"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1651"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1007"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS161"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1107"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS459"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS601"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1547"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1599"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS357"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS865"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS367"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS953"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1023"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1163"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS945"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1689"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1091"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1037"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS835"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1033"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS49"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS303"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS297"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS691"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1097"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS359"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1323"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS531"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS679"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS801"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS169"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS939"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1299"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS811"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS17"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1047"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS383"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS809"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1525"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS475"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1005"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS861"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS215"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1803"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1753"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS991"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS677"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1695"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS609"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1465"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS63"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS959"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS147"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS655"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS193"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS429"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1211"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS71"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS415"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1361"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS585"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1477"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1771"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1369"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1117"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1263"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS33"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS551"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1279"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1721"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS967"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS139"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1127"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS817"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1375"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1795"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS401"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS395"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1289"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS329"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1377"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS925"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS873"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1607"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1625"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1727"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1045"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS663"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS59"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS819"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS189"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS345"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1325"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1001"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1227"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1515"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1621"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS903"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS695"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS605"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS705"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1167"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS893"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1709"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1019"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1189"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1755"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS425"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS713"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS919"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1539"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1409"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS515"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1705"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1569"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS313"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1593"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS157"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS517"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1105"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS687"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS135"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1517"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1217"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1427"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS491"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS669"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS745"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS643"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS697"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1447"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS31"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS543"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1255"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS613"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1245"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS293"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS909"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1769"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS43"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS241"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1393"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS117"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS369"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1677"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1449"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1065"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1029"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1667"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1239"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1629"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS15"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS619"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1293"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1563"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS527"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS177"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1405"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS993"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1367"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS363"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS749"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS119"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS211"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1387"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1729"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS901"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1113"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS103"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1365"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS505"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS907"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS673"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1459"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS645"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS387"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS513"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1691"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS9"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS113"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS929"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1589"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS589"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1129"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS987"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1055"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1581"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1057"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1169"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS277"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1071"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1287"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1397"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1373"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1223"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1233"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS221"/> - <_3:referencesFile rdf:nodeID="IPWfDqBS1473"/> + + + cc407be303fcd2bbd3005ec6110ef6b55095a0b9 + - - <_3:fileName>./src-separate/duk_api_memory.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS350"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-separate/duk_api_inspect.c + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7232f08a0e94ff9a904cfeb1ac6d727f289f0076 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a71b8ab18f8f14e980269c6a2a306e32a4e4e885 - + + + + + + ./config/header-snippets/cpp_exception_sanity.h.in + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./src-input/duk_api_bytecode.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + + ./tools/genbuiltins.py - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1660"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>5d978296025cf899d0c3fabb6cd40507c97a9d8d + + a5bfd4c7cba5293f11c4a28838f3d8cca7312cfc + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>6b2c192574f557fed386580cf37d682a80e0140c + + + d4e7b072fdde2cb12a4b0b2b7971c9354d16d88e - - <_3:fileName>./src-input/duk_lexer.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1552"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>398a2f235ced56eeee14280fce550b2ebd99306c + + + 5239530ef8fe6b431bb600add955bb2b43095afa - - <_3:fileName>./extras/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + + ./examples/codepage-conv/duk_codepage_conv.h + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1398"/> - - <_3:fileName>./src-input/duk_hbuffer.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + 067a800a9f5db1ec8328d8748483a53f5f13dd95 + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1658"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_ES6_REGEXP_BRACES.yaml + + - - <_3:fileName>./config/feature-options/DUK_OPT_DPRINT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./config/feature-options/DUK_OPT_NO_STRICT_DECL.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS538"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2dd1462f73421a442300f0f0d7054fa68d07d3ea + + 01138dd2786346a159c06e43f094d07f002df881 + - - <_3:fileName>./src-separate/duk_debug_fixedbuffer.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS444"/> + ./config/header-snippets/alignment_fillin.h.in + - - <_3:fileName>./src-input/duk_debug_vsnprintf.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./config/feature-options/DUK_OPT_DEBUGGER_FWD_LOGGING.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1634"/> + + + + - - <_3:fileName>./extras/minimal-printf/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1430"/> + + + + ./config/feature-options/DUK_OPT_NO_AUGMENT_ERRORS.yaml - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ede5151f7e6fff690fe7edb0b0a5e73d49969c62 - + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./examples/dummy-date-provider/README.rst + + + + + - - <_3:fileName>./config/header-snippets/byteorder_derived.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + ./debugger/duk_classnames.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS726"/> - - <_3:fileName>./src-input/duk_heap_markandsweep.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1640"/> + + + ./config/config-options/DUK_USE_JSON_EATWHITE_FASTPATH.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9dd1ed891714d3c8542185cb6cf059826a5a115a + + + 936cc6469c4d90c03414d7fff1162337774e7cd8 - - <_3:fileName>./config/config-options/DUK_USE_EXEC_TIMEOUT_CHECK.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + ./src-separate/duk_bi_string.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS932"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>be4dc9ca69b47904b70cac8355b94555444466d1 - + + + + + + ./src-separate/duk_source_meta.json + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>149584de234020f72f4b5c5fa23357d351de1ab7 + + + e8ae9fdde226f75d6f6bad2d9e2746f59e451d01 - - <_3:fileName>./README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS12"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>846a4b80b0d42a5130141a8eb4ab7f1c8f33e27f + + + a8c0b54002a3a7d8c69d385e7fbcf4b70d1efc70 - - <_3:fileName>./src-separate/duk_unicode.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + ./src-separate/duk_debug_macros.c - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS250"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d869c0f8797a659124b3ba31c75f494b15bea5e6 - + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/feature-options/DUK_OPT_NO_ES6_PROXY.yaml + + + - - <_3:fileName>./src-input/duk_hbuffer_alloc.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-separate/duk_unicode_support.c + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1558"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>22ea5eab18fdfa9b14d755b2eaadfb05e4b43d16 + + + 09bb0d45824e56bb64ee9e6e59f219130ffd4ecc - - <_3:fileName>./examples/debug-trans-dvalue/test.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS184"/> + + ./src-separate/duk_hthread_builtins.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./extras/module-duktape/test.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1444"/> + ./examples/jxpretty/jxpretty.c - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>239f16cf83e73eeeb0c54000a3d739b873fd6483 - - - - <_3:fileName>./src-input/duk_internal.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./config/platforms/platform_windows.h.in + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1624"/> + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8483a2211d6323480efa605ee646959695b742c6 - + + + ./config/config-options/DUK_USE_DUKTAPE_BUILTIN.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>5271e503e4775b2be09c3e9bb04468da26b66fab + + + 680b93d235b19070a67f6ded7e4644277bee4c68 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7edf7600e1a6f09d1e4a0e2f9be418b59fff7c52 - + + + + + ./config/config-options/DUK_USE_EXEC_TIMEOUT_CHECK.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./src-input/duk_heap_hashstring.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1680"/> + ./extras/duk-v1-compat/test_compile2.js + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>3a81b3aa623cc81a9a80f40db3dd6c32b3f26c6c - + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./config/config-options/DUK_USE_IDCHAR_FASTPATH.yaml + + - - <_3:fileName>./extras/duk-v1-compat/duk_v1_compat.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1400"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./config/config-options/DUK_USE_HOBJECT_LAYOUT_2.yaml - - <_3:fileName>./src-input/duk_bi_pointer.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./config/config-options/DUK_USE_EXEC_FUN_LOCAL.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1752"/> + + - - <_3:fileName>./extras/print-alert/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + + ./config/helper-snippets/DUK_F_QNX.h.in + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1468"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>cd55d15de8e1e2629edb637d2704a61974542a0b + + 4242d16a8a93277a92cb303c19dc0035b64fb9f2 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>68e5fbde6514a3c3d381035077213e7ada956bd0 - + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/compilers.yaml + - - <_3:fileName>./config/config-options/DUK_USE_BASE64_FASTPATH.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/feature-options/DUK_OPT_DATAPTR16.yaml + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1062"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f3d5a9f7971ae436b0fd90b516eb55ebc8f239c4 + + + b823009fcdc91c45193ea61215fe0136c15a6e5a - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c07b0673b25fd4fec942bb781279563ef7856837 + + + af7c872ee35b876363952b07b518cdff3795bd40 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f5241cb38baccbfff3b042da15e039ec8c6cec7f - + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/helper-snippets/DUK_F_ANDROID.h.in + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bd0ae6d792a55411d1d601e9bc3dc8f7b41f8135 - + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./examples/guide/processlines.c + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>3fcc61b062acde600b790fbf0a3028510f4fb005 + + d9fb89aabcdd4ad250f9f0c16b28c48cc21c09fb + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./config/config-options/DUK_USE_DDPRINT.yaml + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7c23b7d22d0576fa31863396a1f99fe65ae492be + + cd3f7e2dc9077f1f03aeb592a804a2a9e58db2bf + - - <_3:fileName>./config/feature-options/DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./config/platforms/platform_emscripten.h.in + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS506"/> - - <_3:fileName>./config/config-options/DUK_USE_SETJMP.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./config/config-options/DUK_USE_HOBJECT_HASH_PART.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1252"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>497ee6ace70fe75d9fc25ce0bd1c3ba4f3518c87 + + + 8483a2211d6323480efa605ee646959695b742c6 - - <_3:fileName>./config/config-options/DUK_USE_SIGSETJMP.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./config/config-options/DUK_USE_DEBUG.yaml + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1140"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c2223c5141efb9a995688c6e9b57fca2a06175d5 - + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-separate/duk_heap_memory.c + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a0cf25ef6d0b2816f79c1e1c42e08fbe8ce91d8b - + + + + + + ./debugger/static/webui.js + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>07d8da49875b4048d2821ebe4aea3e9721abb825 - + + ./config/config-options/DUK_USE_ARRAY_PROP_FASTPATH.yaml + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ac3e136b155d9b77eeaa3c8255f35d13efd3ecfa + + c3e7c28498f09d3f9bdfc2006952df17a51184e5 + - - <_3:fileName>./config/architectures/architecture_powerpc64.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS824"/> + + + ./config/config-options/DUK_USE_STRICT_UTF8_SOURCE.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./tools/combine_src.py - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1780"/> + + + + 45ef2fedf1972cda257b186df63dfc223dbd0f54 - - <_3:fileName>./config/config-options/DUK_USE_ESBC_LIMITS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_PARANOID_DATE_COMPUTATION.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1032"/> + + - - <_3:fileName>./src-input/duk_regexp.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./config/config-options/DUK_USE_DATE_PRS_GETDATE.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1560"/> - - <_3:fileName>./extras/duk-v1-compat/test_eval1.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1402"/> + + e6d75a7c9cc7f6109387ceda77f4b56f4e78b8f1 + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>81f62b481dc3495eb4d69dae289591f988ef8d2f + + + 4e59c7b6e46e0ec47a84175bba68d6b47a5b1cc7 - - <_3:fileName>./config/config-options/DUK_USE_EXEC_INDIRECT_BOUND_CHECK.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1292"/> + + + 5833f862ccb539e1fb963d912e9430fa4bdeb467 + - - <_3:fileName>./debugger/static/webui.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS68"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/feature-options/DUK_OPT_NO_FUNC_STMT.yaml - - <_3:fileName>./examples/debug-trans-dvalue/Makefile - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS180"/> + + ./config/feature-options/DUK_OPT_TARGET_INFO.yaml - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9f8f21626bc2389e86b7228f926cb293b072d3c8 + + f441f79468112b6d4002e64fc6043c96c9bfdbf1 + - - <_3:fileName>./extras/minimal-printf/duk_minimal_printf.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-separate/duk_debug_vsnprintf.c - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1434"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>6994cdb0af2435f070a870ce854b81072cff02a4 + + + 72677c24d3803320172b5330a7678fedafa062c0 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d2ac6ac9e93fac629050fc83d39363863d879ba8 - - - - <_3:fileName>./config/config-options/DUK_USE_HSTRING_CLEN.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS998"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./extras/logging/duk_logging.h + - - <_3:fileName>./config/feature-options/DUK_OPT_NO_BYTECODE_DUMP_SUPPORT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS612"/> + + + + + ./LICENSE.txt + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./src-separate/duk_api_stack.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS434"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_STRING_BUILTIN.yaml - - <_3:fileName>./config/examples/rom_builtins.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/helper-snippets/DUK_F_EMSCRIPTEN.h.in + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS712"/> - - <_3:fileName>./src-separate/duk_source_meta.json - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS366"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a4daa6a7716a668a341617db1cd994bb0eeb320c - + ./config/header-snippets/compiler_fillins.h.in + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>01d9ee35878785c070a7b0b7304def0dc377c7af + + 53b98a94c0c26af0b4217b23f231c25d3de26be5 + - - <_3:fileName>./config/examples/security_sensitive.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS722"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_FUNC_FILENAME_PROPERTY.yaml + + - - <_3:fileName>./src-input/duk_tval.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1734"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>525e80da2b6d3640fd42af0f662d7b68865d6529 + + 700d0db5f26ccdde22fb43000ff183fab145b46d + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c5be3577e198e24f10ffe61fa21bff4a69246168 - + + + + ./config/config-options/DUK_USE_ERRCREATE.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>35f7195d949252ea6bc9c25360941a4141886346 - + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-input/duk_api_codec.c - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>936825b1abdf981153f894234ffb564a49c34a29 - + + ./src-input/duk_error.h + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/config-options/DUK_USE_DEBUGGER_FWD_LOGGING.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./src-separate/duk_hobject_class.c + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1136"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b55b06c60625f9553ff2b3240e9d4943af0c6266 + + 15ccd87ae7025ee6bc841eb2adb9077a1a83d73a + - - <_3:fileName>./config/feature-options/DUK_OPT_HEAPPTR_DEC16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-separate/duk_bi_encoding.c - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS650"/> + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>511ed2315fcdf89b37ae5a44ecb9bb63f978889f - + + + ./src-input/duk_util_bitencoder.c + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>be0e7eb2cebe3402a9c67065a051b343c2f38d46 - + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./src-separate/duk_regexp_compiler.c + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bd26962a105f83f1e4df97454ac7fdc01ed2454a + + 2c4d73775edda84d8664b58be73f92f22cd6db49 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>47c073f157be83b4ecfe64918ff878ac6cd2099f - + + + + + + ./config/config-options/DUK_USE_AUGMENT_ERROR_CREATE.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4a57adfbe86798552776f7919725a3176ffcfa98 - + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-separate/duk_api_debug.c + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9f082261795edaca184c141605e84fc8a96ac81d - + + + + ./config/feature-options/DUK_OPT_NO_BUFFEROBJECT_SUPPORT.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ed4b2d40f4406368eb62ba8a5ea81eb3a2635986 + + + 84a925fc469424497f4d37a8b11f1d110baa8e41 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>846a4b80b0d42a5130141a8eb4ab7f1c8f33e27f + + + 8c5ee5b508a23ac5089a7e6c76593b6678965869 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8a93bd26354028c246c213b885e132ae595f3b57 + + + 1c08e3a9035859a7e76dd8397faa69e32227c3c4 - - <_3:fileName>./config/feature-options/DUK_OPT_NO_VERBOSE_ERRORS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS622"/> - - - <_3:fileName>./src-separate/duk_regexp_executor.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./config/header-snippets/byteorder_fillin.h.in + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS206"/> - - <_3:fileName>./extras/logging/duk_logging.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1456"/> + ./src-input/duk_bi_date_windows.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>3ec2f416b467cf1202923ad1c93a0786e477540d + + 87f66c3811cafee84fcbde7e52119e40d25afb39 + - - <_3:fileName>./src-separate/duk_debug.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + ./config/config-options/DUK_USE_EXEC_PREFER_SIZE.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS374"/> + - - <_3:fileName>./config/examples/low_memory_strip.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./extras/console/test.c + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS718"/> + + - - <_3:fileName>./src-separate/duk_heap_refcount.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./config/other-defines/platform_functions.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS342"/> + + + - - <_3:fileName>./config/feature-options/DUK_OPT_NO_NONSTD_FUNC_STMT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS574"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>af0d5f62efa1018ee7e93f40da35d752c02b4187 + + + c3b1b9c324cddb3526474584f4f35682220de7de - - <_3:fileName>./config/feature-options/DUK_OPT_NO_AUGMENT_ERRORS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS592"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./config/config-options/DUK_USE_BYTEORDER_FORCED.yaml - - <_3:fileName>./config/config-options/DUK_USE_HOBJECT_LAYOUT_2.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1262"/> + + + d0a31fca003e3028fe0d029906f65053634837c5 + - - <_3:fileName>./src-separate/duk_bi_reflect.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS330"/> + ./src-separate/duk_heap_misc.c + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>99d36e3da909a12bd064806397804efa6f6e17c3 + + + 36f51bfa3c9d50eedf7183315f08196d27e4f154 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>e4f8a99fc1f5e2898f35b2e94fbd0d1ba4928490 - + + + + + ./examples/hello/hello.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./src-separate/duk_heap_stringtable.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./config/config-options/DUK_USE_TAILCALL.yaml + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS284"/> - - <_3:fileName>./config/feature-options/DUK_OPT_NO_OBJECT_ES6_PROTO_PROPERTY.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + ./config/config-options/DUK_USE_SELF_TESTS.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS676"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>85c6870d769648da9305714b760e893e450effe0 + + 62385dce58219430c29e6970576a1d04ea0fe7b7 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>fc6a3bcece2e0525d4603e176a9e896688c6de0e + + 8c0026f6b343073c6b39c54a74ef8b9aeab2a8fc + - - <_3:fileName>./config/examples/enable_debug_print0.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS724"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ea9a99fc1cba271a4598a222c97191aa67f42a25 - + + + ./src-separate/duk_bi_duktape.c + - - <_3:fileName>./src-input/duk_bi_date_windows.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1714"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/other-defines/other_defines.yaml - - <_3:fileName>./src-separate/duk_builtins.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS280"/> + ./config/header-snippets/date_provider.h.in + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./config/config-options/DUK_USE_STRICT_DECL.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-separate/duk_hobject.h - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1158"/> + + - - <_3:fileName>./config/platforms/platform_genericbsd.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_ES6_REGEXP_SYNTAX.yaml + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS772"/> + - - <_3:fileName>./Makefile.hello - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./src-input/duk_js_bytecode.h - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS14"/> + - - <_3:fileName>./src-separate/duk_bi_function.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./config/header-snippets/inline_workaround.h.in + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS228"/> - - <_3:fileName>./config/config-options/DUK_USE_DPRINT_RDTSC.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1112"/> + + + + ./config/header-snippets/types2.h.in + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>089c395fca3cedceec09fd38d32d0c77dc8658f4 - - - - <_3:fileName>./examples/coffee/globals.coffee - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS80"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./config/config-options/DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE.yaml - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>748abde5cf2f68709270fe20fd152fd48a329fc7 - + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_EXTSTR_FREE.yaml + + + - - <_3:fileName>./config/config-options/DUK_USE_POW_WORKAROUNDS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS886"/> + + + ./config/feature-options/DUK_OPT_DEBUG.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/feature-options/DUK_OPT_TRACEBACK_DEPTH.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS494"/> + ./config/config-options/DUK_USE_MATH_FMIN.yaml + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0a0b92d48449a1bc52e8be419a60ef27a9d5a41f + + + 279fd7202e72b7796a1147428885fd6d54c2fc7e - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1cd731519543ce78141971d455e806db68d719f1 + + da9bea876b6dae7cf354be26b5580ad0f1600841 + - - <_3:fileName>./config/config-options/DUK_USE_ESBC_MAX_BYTES.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1244"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_ES6_PROXY.yaml + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bc37be576519d2713e5f18496e6ad167978d0785 + + 13620d842239fea3141ed1dda9629636fe429cd9 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>17f922490479e0e7875258fe338a1a75c88f64f3 + + + 1dd90f5fc7f34d0f138dbb7b11d53392f002db0c - - <_3:fileName>./config/feature-options/DUK_OPT_NO_JSONC.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS672"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-separate/duk_util_bitdecoder.c + - - <_3:fileName>./src-separate/duk_lexer.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS258"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>da9bea876b6dae7cf354be26b5580ad0f1600841 + + a75d516be529be065841333b9ea3d8fb6ce6d2bf + + + + + + + ./config/feature-options/DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./debugger/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS52"/> + + + + ./Makefile.coffee - - <_3:fileName>./src-separate/duk_api_inspect.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS274"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./config/config-options/DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE.yaml - - <_3:fileName>./src-separate/duk_bi_error.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS198"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_ATAN2_WORKAROUNDS.yaml + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>094eb07738bc769a2f096e01d7de5deb7ed1bf7f + + 04645d3ee7dc5fd11e81ec78e72bbd311fb076b5 + - - <_3:fileName>./src-separate/duk_js_ops.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + ./config/config-options/DUK_USE_STRTAB_TORTURE.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS428"/> - - <_3:fileName>./src-separate/duk_hstring_misc.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS234"/> + ./config/feature-options/DUK_OPT_EXTSTR_FREE.yaml + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a7be013650a56fbe6cb7650afa35cd0582db74ff - - - - <_3:fileName>./config/examples/debugger_support.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS706"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-separate/duk_util_misc.c + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a08e43879af86c86670dbbaa10af31e4ad8e5951 - + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-separate/duk_builtins.c + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4674717b6b5b3acecf143752b2051b1f3a4dfbec + + + 3c7e23532004e30b22be7e5487ac97802b26bc11 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d273268b97a6906abc4a1603691f0d888bdfb491 + + 55f3bb1a5e2221a4a2381c1b293609dcc4ed687b + - - <_3:fileName>./polyfills/console-minimal.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS468"/> + ./src-input/duk_hthread.h + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7ed28894fd636d138d031ca9c80efa4e80b51cf1 + + + 10c24a17c2f5f82d8c1a8fab8673c0c9075c1817 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>eb77c3d3595b786cd1d56e64f54d852ccc35a6bc + + ff69aff0a588f5c66dc08c3ab096ae91a9406da5 + - - <_3:fileName>./config/feature-options/DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS660"/> + + + + 4b2165beaa1a153360cbf9cb6a667c19964e1d6c - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>87d70928f4ac893f5d41f19d3179bcb712f3d04e + + 9888edb8332bc63ba259b10d7f18c760db974a23 + - - <_3:fileName>./config/config-options/DUK_USE_REFLECT_BUILTIN.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./config/feature-options/DUK_OPT_NO_MS_STRINGTABLE_RESIZE.yaml + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1126"/> - - <_3:fileName>./config/config-options/DUK_USE_FUNCTION_BUILTIN.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./src-separate/duk_bi_buffer.c + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1236"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/config-options/DUK_USE_PARANOID_MATH.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./src-input/duk_selftest.c + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1194"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4db06fd9d96853165d9c5bb92d722ee87649081a - + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./src-input/duk_error_throw.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1494"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>94e5c27bdac6dcd7633a78966c4746d9c0585248 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>257477affc6974925dfdd8f182596fd923773ca9 - + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./extras/duk-v1-compat/test_compile1.js + - - <_3:fileName>./src-input/duk_bi_proxy.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./debugger/duk_opcodes.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1726"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ad42b45836057eab327c0be7a10e2511e6d992ea + + + 108d6717c567c0135c91a083e3acb170a1ba86fd - - <_3:fileName>./src-input/duk_harray.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + ./config/feature-options/DUK_OPT_NO_SOURCE_NONBMP.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1544"/> + + + - - <_3:fileName>./config/architectures/architecture_emscripten.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS822"/> + + ./config/config-options/DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./src-input/duk_js_executor.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./config/architectures/architecture_arm32.h.in + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1712"/> + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>af59bb7e48744b4c75aeb512d458f1244184202d - + + + ./src-separate/duk_hobject_misc.c + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./config/platforms/platform_posix.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./src-noline/duk_config.h - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS780"/> - - <_3:fileName>./src-separate/duk_hbuffer_alloc.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-separate/duk_exception.h - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS264"/> + + + - - <_3:fileName>./src-input/UnicodeData.txt - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1566"/> + + ./config/helper-snippets/DUK_F_ORBIS.h.in + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>140631b8d425914215232ba351987dbc0884c3b8 + + a62e44c8b763e455366b0caae3aff14abfc4569a + - - <_3:fileName>./config/examples/disable_bufferobjects.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS702"/> - - - <_3:fileName>./config/config-options/DUK_USE_FULL_TVAL.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-separate/duk_hcompfunc.h + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1274"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>6bc73cdb2ca01065f1e4cf4485f898ea54697b70 - - - - <_3:fileName>./config/feature-options/DUK_OPT_NO_STRICT_DECL.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS558"/> + + + + ./config/helper-snippets/DUK_F_NETBSD.h.in + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./src-input/duk_js_arith.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./config/compilers/compiler_tinyc.h.in - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1604"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d1b470355a5fee93adb31032e455446005ca2d10 + + + 27bf3ddb7d43d5b9c27cae0c966cff12d29c23c9 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c897c1c61bf2ddf0542809c83ab37276bf71f815 + + + 1f0880faaf1dc514e15b81b68213ff9b519d4e9b - - <_3:fileName>./config/feature-options/DUK_OPT_FORCE_BYTEORDER.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS568"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./mandel.js + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>af7c872ee35b876363952b07b518cdff3795bd40 - + + + ./config/config-options/DUK_USE_DATE_NOW_TIME.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>03513d7b6fc13d8cf6781cc682800ce6f8468d53 + + + 8402d0b335764c245437b9e147cff99dd4f4cc34 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>61356640e5038915763a697966cff8b8bade612d - + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/feature-options/DUK_OPT_BUFLEN16.yaml + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>615baeec8dd79a073bd53eab2b8f81516c8a03dd - + + + ./config/config-options/DUK_USE_STRHASH16.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8e79a19c02102b9abeb8ce79394c090fe9bb336a + + + 66ec9c11690fa8339b13e81564a7898cce9b9a14 - - <_3:fileName>./examples/coffee/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS78"/> + ./config/config-options/DUK_USE_REFERENCE_COUNTING.yaml - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7ce0aa7674120ee1db9a8c49d4cb6b75d7bbd605 - + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/platforms.yaml + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1f42c900d10898702dd7959f06ae1fdc7b3df3a6 - + + ./config/feature-options/DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER.yaml + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./examples/eventloop/fileio.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS112"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-separate/duk_js_ops.c - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>e8d6d451ab95a57de6515434b4889a3d5bcb2066 - + + + + + ./src-separate/duk_bi_array.c + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d1aa83335e2cecb5ce01d40c0c5eea72cb171972 - + + + ./extras/module-duktape/test.c + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>98f108d8a5c41d1f577601983a383c9c38643521 - + + + + ./src-separate/duk_api_string.c + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./licenses/splitmix64.txt + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./src-input/duk_alloc_default.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./src-separate/duk_hobject_enum.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1748"/> + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a016e3fdb90c643b12f8ab9000b499e9248bf03d + + + 206ffd13c06208e85baba2b257fe3ddebb56a6c2 - - <_3:fileName>./config/feature-options/DUK_OPT_SEGFAULT_ON_PANIC.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS560"/> + + + ./config/config-options/DUK_USE_PREFER_SIZE.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./src-separate/duk_hobject_alloc.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS268"/> + + ./config/feature-options/DUK_OPT_DEBUGGER_FWD_PRINTALERT.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>08f9536a60dfdb1b04b673b36b8d6eb067ba86b8 + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-separate/duk_hthread_misc.c + + + + + + 484fb41d516abcbe8c97af5aa80b76c67dbfb0cb + - - <_3:fileName>./config/config-options/DUK_USE_MATH_BUILTIN.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-input/duk_dblunion.h - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS856"/> + + + + + 61356640e5038915763a697966cff8b8bade612d + + - - <_3:fileName>./Makefile.jxpretty - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./src-separate/duk_heap_stringcache.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS36"/> + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>49dcd350a10ed1fd7ffc5bf021f1b0dfc5a37446 + + 7386be4993a77794052574ccfc48e97f4e8915b5 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>42ddc03124956c14602a7e3a66d37386be0293d1 + + 9d97cd24eba146d098b88505afb3e9d9c71fb05a + - - <_3:fileName>./extras/module-node/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1458"/> + + ./config/helper-snippets/DUK_F_VBCC.h.in - - <_3:fileName>./src-noline/duk_config.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/feature-options/DUK_OPT_NO_VERBOSE_ERRORS.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS40"/> + + + - - <_3:fileName>./config/config-options/DUK_USE_FUNCPTR_DEC16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1156"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-input/duk_api_call.c - - <_3:fileName>./src-separate/duk_hthread_stacks.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./examples/alloc-logging/README.rst - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS326"/> - - <_3:fileName>./src-separate/duk_heaphdr.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./extras/print-alert/duk_print_alert.h + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS420"/> + - - <_3:fileName>./config/config-options/DUK_USE_DATE_FORMAT_STRING.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + ./config/feature-options/DUK_OPT_ASSERTIONS.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS906"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./polyfills/performance-now.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS470"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f0a2c3d666e7225d386d1ac280742d46c82cf5ad + + + fc4b4ae52fa46951b304fa94b12cbe94064fe366 - - <_3:fileName>./src-separate/duk_js_arith.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS308"/> + + ./config/examples/enable_debug_print0.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./debugger/duk_debugerrors.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./examples/debug-trans-dvalue/test.c + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS48"/> - - <_3:fileName>./config/feature-options/DUK_OPT_NO_BUFFEROBJECT_SUPPORT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS550"/> + + ./extras/console/Makefile + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./config/config-options/DUK_USE_SHUFFLE_TORTURE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + ./src-input/duk_heap_markandsweep.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1290"/> + - - <_3:fileName>./src-input/duk_hobject_alloc.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1562"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-separate/duk_bi_date.c - - <_3:fileName>./src-input/duk_numconv.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./debugger/static/style.css + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1720"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./extras/alloc-pool/ptrcomp.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1484"/> + + ./src-separate/duk_json.h + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/header-snippets/types1.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/feature-options/DUK_OPT_DECLARE.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS762"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>28520ba887f6790e82c5edf9f8ef12db692922b7 - + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bd26962a105f83f1e4df97454ac7fdc01ed2454a + + + 2dd1462f73421a442300f0f0d7054fa68d07d3ea - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b9e1e8cb6f43dd1f3f63538b9819a5bd7cd7fa91 - + + + + ./config/compilers/compiler_vbcc.h.in + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./config/helper-snippets/DUK_F_EMSCRIPTEN.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1364"/> + + + + ./src-input/duk_hbuffer_alloc.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>53977e24e3f60006deb0d7dc6760e1373487e77c - + + ./config/feature-options/DUK_OPT_LIGHTFUNC_BUILTINS.yaml + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d549e43cd3afaaccb29854d4868050fd4c4c79f0 - + + + + ./src-input/duk_hthread_builtins.c + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>881f1b114c9fbba139044ddcbbc5398243185d10 + + + f396c6aec456b183ef77e33da1dfffc89c417056 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7f1552015bd1bc4d9e7562c9ed80c7cb29f59b55 + + + 3f45451d2c809cbd73eacf5699c181b86d324909 - - <_3:fileName>./config/config-options/DUK_USE_JSON_BUILTIN.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS884"/> + ./src-separate/duk_harray.h + + - - <_3:fileName>./config/compilers/compiler_gcc.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS682"/> + + ./config/feature-options/DUK_OPT_SHUFFLE_TORTURE.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./examples/eventloop/c_eventloop.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + ./config/feature-options/DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS102"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./config/feature-options/DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./src-input/duk_hthread_alloc.c + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS578"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>887a666e371f4aa5b2f5617f1a8bd10a270b4521 - + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./config/examples/low_memory.yaml + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>39fd549c28f19dc9f0c93cce1fca50ef64f7ca83 - + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-input/duk_tval.h - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bee1c12df927c44ecb4e0f1613114131d14554bf - + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./polyfills/object-assign.js + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>185ee3d054a6f46d54a3473cbbf30521b418fe89 + + b5ba28fbd30b118a931af50553988e092d5a97e1 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b81a68b8d643e5f35c4c53e0b85de7a7d1538d64 - + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./src-separate/duk_api_compile.c + + - - <_3:fileName>./config/config-options/DUK_USE_DEBUG.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./config/config-options/DUK_USE_INTEGER_ME.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1226"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c6ecd2e0444e5984e1c568fc2103a28e61df67d5 - + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + ./config/config-options/DUK_USE_SETJMP.yaml - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>dfc0b1246ddd75506dc4b3794f906baf7f5c687e - + + + + ./src-separate/duk_util_bufwriter.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./extras/alloc-pool/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./src-separate/duk_bi_regexp.c + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1480"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ad42b45836057eab327c0be7a10e2511e6d992ea + + b63bb52ba6f8661feafc2f6bf42110725b590abf + - - <_3:fileName>./src-separate/duk_selftest.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS320"/> + + + + ./config/platforms/platform_aix.h.in + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/feature-options/DUK_OPT_SELF_TESTS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_MARK_AND_SWEEP.yaml + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS630"/> - - <_3:fileName>./config/config-options/DUK_USE_EXTSTR_FREE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1208"/> + + + ./config/feature-options/DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY.yaml + - - <_3:fileName>./config/feature-options/DUK_OPT_FUNCPTR_ENC16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS554"/> + + f483297f5b54759ea086884a18fcfb8e8d878eda + + - - <_3:fileName>./config/helper-snippets/DUK_F_CYGWIN.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1382"/> + + + + ./config/feature-options/DUK_OPT_JSON_STRINGIFY_FASTPATH.yaml + - - <_3:fileName>./config/config-options/DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/header-snippets/platform_sharedincludes.h.in + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS888"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>e680bc42fb4cacf2f82a40f05e14a280a6981614 + + + b54e14e55a177d46c78404e11f232ff4e0f82116 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c4f7aeabb2dd685b624b85a77fe677086c69d5ef - - - - <_3:fileName>./config/helper-snippets/DUK_F_NO_STDINT_H.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + ./config/platforms/platform_linux.h.in + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1342"/> - - <_3:fileName>./config/config-options/DUK_USE_ALIGN_BY.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./src-input/duk_bi_regexp.c + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1148"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/config-options/DUK_USE_PC2LINE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./src-input/duk_heap_refcount.c - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1314"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>26e5fb2f31b011884e8d178f0e6d7b3b8cfdb864 + + + d1c61fb3ede8251d3f5406f68c49e3f461c8746b - - <_3:fileName>./config/feature-options/DUK_OPT_DATAPTR_DEC16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS564"/> - - - <_3:fileName>./src-separate/duk_bi_date_unix.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + ./extras/module-node/README.rst + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS230"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bcfed1d744e13b2d3fe0256385fd8053005f78fd + + + d5e579babcae88dd628cc4ae5bfbab3f0cc14c67 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>97f183cd870ccdfcd5335c6c8a2cf4ce6bd79345 - + + + + + ./examples/eventloop/c_eventloop.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./src-input/duk_bi_regexp.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1708"/> + ./config/helper-snippets/DUK_F_TOS.h.in + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - - <_3:fileName>./config/helper-snippets/DUK_F_MIPS.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-input/duk_replacements.h - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1336"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>321c61274d91796567e7b0bd4da4a67b108a5bbc - + + + ./config/helper-snippets/DUK_F_X86.h.in + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ccbe1785277c59b6193f562d04b8e41d3dc7f531 + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-input/duk_bi_reflect.c + + + + + + + 6340182b4d5fab0dc7ef741980286cb054abec6c - - <_3:fileName>./src-input/duk_util_tinyrandom.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1610"/> + ./src-input/duk_api_object.c + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./src-separate/duk_bi_symbol.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-input/duk_heap_stringcache.c + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS224"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d3b91ed21c7cc0063e1a29a204457da50b1b3ef5 - + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>cef3eff34957436e126465462367875569963db7 - + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/architectures/architecture_sparc32.h.in + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>319f96d5222100cd17b2efc6b8740cf48abec30d - + + + + + + ./config/compilers/compiler_generic.h.in + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>5f89917c0262574a299a19edd39ed1d4802162f3 + + + 1a5eb6fdf1de5055e21fadf39a069384d3f04ae3 - - <_3:fileName>./debugger/duk_debug_meta.json - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS58"/> + + + ./config/config-options/DUK_USE_DOUBLE_LE.yaml - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d49c1cdb51b3a4fdd823c13831617a1f0a93edd1 + + + 7b79fce07f8f8b9e6f07cad3555d71e42334a853 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>108d6717c567c0135c91a083e3acb170a1ba86fd + + + 3d3e1ac9abf52775453307faf0a168fee177e645 - - <_3:fileName>./config/feature-options/DUK_OPT_STRTAB_CHAIN.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_DATE_BUILTIN.yaml + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS626"/> - - <_3:fileName>./config/config-options/DUK_USE_EXAMPLE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1086"/> + + + ./config/feature-options/DUK_OPT_DEBUGGER_DUMPHEAP.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./debugger/static/index.html - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + ./config/config-options/DUK_USE_STRLEN16.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS70"/> + + - - <_3:fileName>./src-input/duk_lexer.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + ./config/feature-options/DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1632"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>114aaaa03ae5f0749eb3227aa7f066e001746975 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1f5097ffee410e3ddcce14e8735be35e1c312b19 - + + + + + ./src-separate/duk_error_throw.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2460c026301db3c6988e8c0f0c01092a888d4da3 - + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./config/feature-options/DUK_OPT_DEBUGGER_TRANSPORT_TORTURE.yaml - - <_3:fileName>./config/config-options/DUK_USE_EXEC_REGCONST_OPTIMIZE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS870"/> + + + ./config/header-snippets/architecture_fillins.h.in - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bc70d7db67fa486267b644b48840784d66111cef - + + ./config/config-options/DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT.yaml + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/feature-options/DUK_OPT_DEBUGGER_FWD_PRINTALERT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS600"/> + + + + ./src-separate/duk_heaphdr.h + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/config-options/DUK_USE_FINALIZER_SUPPORT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1028"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./config/architectures/architecture_mips64.h.in + - - <_3:fileName>./config/config-options/DUK_USE_ES7_EXP_OPERATOR.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1188"/> + + + + + ./config/config-options/DUK_USE_REPL_FPCLASSIFY.yaml - - <_3:fileName>./config/helper-snippets/DUK_F_X86.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1332"/> + ./src-input/duk_heap_alloc.c + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b070e59599f3d279034a2f8991a63475b15d6162 + + 39ba23af6c40e9e63b4a5668b667c5e8874293d2 + - - <_3:fileName>./config/config-options/DUK_USE_DDDPRINT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + ./src-input/duk_api_string.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS882"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>95f0e467f3a04245b061f3ca47cf4c5a33e61bd6 + + 1b49f5b5cdd7d32262568f53ec2073077d19d6ea + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>66ec9c11690fa8339b13e81564a7898cce9b9a14 + + bfeee02b6ac0e9fe286334a6658255656402a5e4 + - - <_3:fileName>./examples/cpp-exceptions/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS134"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./src-separate/duk_regexp.h - - <_3:fileName>./src-input/duk_bi_string.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1568"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>83d0fa93dad6434dadd19996cc41d11259404662 + + + df0be76d86f9c7a8f3ff117966dc1457b5c944fe - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>af0d5f62efa1018ee7e93f40da35d752c02b4187 - + + + ./src-input/duk_bi_symbol.c + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a1f3d0f8f136ecba1278aac0bb7981c68cbdb12d - + + ./src-input/duk_unicode_tables.c + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>92b4247db4a86ec02abf980160bd0a0675e8de82 + + + a06c61bed150ef8a0cc494579e1d0cf035acf13e - - <_3:fileName>./config/feature-options/DUK_OPT_DECLARE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS504"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./Makefile.cmdline - - <_3:fileName>./src-input/duk_api_heap.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1620"/> + ./examples/eventloop/basic-test.js + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>5239530ef8fe6b431bb600add955bb2b43095afa + + d549e43cd3afaaccb29854d4868050fd4c4c79f0 + - - <_3:fileName>./src-input/duk_hnatfunc.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./examples/eventloop/ecma_eventloop.js - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1636"/> + + - - <_3:fileName>./config/other-defines/other_defines.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS804"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4310cf609e97ce1d4cfaafa8c5060580b946fe95 - + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./examples/sandbox/README.rst + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>3ee8cbebe37e0827b04d002290095a23cc82e5f6 - + + + + + ./licenses/murmurhash2.txt + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>149fd21526c90d52b22e77b297f76e6da3e656ff - + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./config/config-options/DUK_USE_REGEXP_EXECUTOR_RECLIMIT.yaml + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b55b06c60625f9553ff2b3240e9d4943af0c6266 - + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./examples/README.rst + + + + + - - <_3:fileName>./config/config-options/DUK_USE_REPL_ISFINITE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./src-separate/duk_refcount.h + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS864"/> + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>765ef83e5ebb3143fcba12f8686a25d6e6f09d8b + + + 0cc625a8d72def6d789f26930691c72953954361 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a7be013650a56fbe6cb7650afa35cd0582db74ff - + + + + + + ./config/examples/debugger_support.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2616aabef11957037b1427f23da12b968c05d9c1 + + a1c387a2b044fc5b9f9180f63d1717831c9af780 + - - <_3:fileName>./tools/scan_strings.py - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./src-separate/duk_bi_reflect.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1808"/> + + - - <_3:fileName>./extras/minimal-printf/Makefile - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./src-input/duk_bi_number.c + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1432"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9263c86b830a60e34c1c7c26aa7e18908fe563da - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b4c0ca5ddc8e53a64857da5d6602d25e87ce82fb - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b768ecd4053b99f2e44223fe0893c64ecd98d15b - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0838780a21e177fe67c3638a241c660c346d288a - + + + ./config/config-options/DUK_USE_DEBUGGER_PAUSE_UNCAUGHT.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ddb7731f06008f9f7fe10546c7bc64ee6568c052 + + + 7db2a928052b97e6bad7cb9da91cb86247233cba - - <_3:fileName>./config/config-options/DUK_USE_JSON_DECNUMBER_FASTPATH.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS974"/> + + + ./config/feature-options/DUK_OPT_STRHASH16.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/platforms/platform_solaris.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./extras/print-alert/README.rst + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS782"/> + - - <_3:fileName>./config/compilers/compiler_emscripten.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/feature-options/DUK_OPT_NO_JSONX.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS694"/> + - - <_3:fileName>./config/config-options/DUK_USE_ROM_OBJECTS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./src-input/duk_bi_protos.h + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS962"/> + - - <_3:fileName>./extras/duk-v1-compat/Makefile - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1408"/> + + + + ./config/config-options/DUK_USE_REPL_ISNAN.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/config-options/DUK_USE_STRLEN16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1206"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./examples/debug-trans-dvalue/duk_trans_dvalue.c - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9382fc0a5c7ba0d4929ffcb6db48fe0bca974a8b + + cf3215413afe523b54b0e887b237cf788d925eab + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>fc6a3bcece2e0525d4603e176a9e896688c6de0e + + 76d282992e2f312cde96ed6de39863883d0c36e9 + - - <_3:fileName>./examples/alloc-torture/duk_alloc_torture.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS154"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_DEBUGGER_TRANSPORT_TORTURE.yaml + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7750412047b5bbd94475d0217d5dca5c4ac3c6ee + + + a71b8ab18f8f14e980269c6a2a306e32a4e4e885 - - <_3:fileName>./src-input/duk_bi_error.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1492"/> + ./config/config-options/DUK_USE_PACK_DUMMY_MEMBER.yaml + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8fb178a8b3c0efede2a2773c11d97918fecb3528 - - - - <_3:fileName>./src-input/duk_dblunion.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1586"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-separate/duk_bi_boolean.c - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2223a8b8b21e21ef47c78aa41fa9627bee40b06a - + + + + + + ./polyfills/object-prototype-definesetter.js + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0ec6da5d51a0fbe7ad3725af169a2808665ee75f - + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_REFZERO_FINALIZER_TORTURE.yaml + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>63fbd4cac6fe8395feffdb3a009441a136036a3a - + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-input/duk_debugger.c + + + + - - <_3:fileName>./src-input/duk_hthread_alloc.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1666"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./config/config-options/DUK_USE_FLEX_ONESIZE.yaml - - <_3:fileName>./config/helper-snippets/DUK_F_FREEBSD.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./config/config-options/DUK_USE_GCC_PRAGMAS.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1394"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>6eb72cbeb7f08079d07c1ac5da3230c01c40920b + + + a821ac7ec988ca2327b7f45e93116b73b741f465 - - <_3:fileName>./config/config-options/DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1222"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./examples/eval/README.rst - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b859c85ce9b2e332c0a171e061faa8c0326e0451 - + + + ./src-separate/duk_heap_alloc.c + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ac909735adaae34684dec95a1697f1923cf11266 + + 2ff1dc97f0d2288ef8b0a55d4d8af383e8725426 + - - <_3:fileName>./config/feature-options/DUK_OPT_NO_JSONX.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS596"/> + ./src-input/duk_bi_math.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./extras/alloc-pool/duk_alloc_pool.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + ./config/config-options/DUK_USE_DATE_PRS_STRPTIME.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1490"/> + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d6d966a9b8a8a8f44b9066a00da9f9ceb0aec2d5 + + a37e32cff86f1cb12351d0effc9f1bff1e70bc13 + - - <_3:fileName>./src-input/duk_hthread.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./src-input/duk_debug_vsnprintf.c - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1652"/> + + + + + + 3c2639d3263e22a693c6d6c4357f186149dec34d - - <_3:fileName>./src-input/duk_selftest.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + 555555d7335078daa9a6d103651e7218abd2611e + + + ./examples/jxpretty/README.rst + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1616"/> + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>84a925fc469424497f4d37a8b11f1d110baa8e41 + + + 5788bd9269db59578632eb6283ecc0d54d5d9b2f - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>234952538660f1f936bad7165e349ce48c575bd2 + + 1477f6a86de2034d299d2ea7d51bd803b259c012 + - - <_3:fileName>./config/config-options/DUK_USE_TRACEBACKS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1108"/> + + + + 14808d03825d86bd0afc3e02fef2d2e09f8f460e - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a37e32cff86f1cb12351d0effc9f1bff1e70bc13 + + eb77c3d3595b786cd1d56e64f54d852ccc35a6bc + - - <_3:fileName>./src-separate/duk_hbuffer.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./config/architectures/architecture_powerpc32.h.in + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS358"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./src-input/duk_bi_object.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1736"/> + ./src-input/duk_numconv.h - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f1020eedf224158992a70be40cfb1267e806399f - + + + ./examples/eventloop/client-socket-test.js + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0e4fd82c8f6a18bfef5fede40307ed460b7212c7 + + 15ad80be0261075ecc86742df352f3bac2fd3217 + - - <_3:fileName>./src-separate/duk_heap_misc.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS298"/> + ./config/helper-snippets/DUK_F_CLANG.h.in + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d70b4083ccd3b5dac32ad07e58d3132dc3390b79 + + + d8813198f0510fedcae2a8b6a8b1b4d0b7331484 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>32167fdeb965e3b707c3bbca072e269f57ebe93d - + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./config/helper-snippets/DUK_F_PPC.h.in + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>113e9dce2fc881206ea51ac5723a3f2044be9b9f + + a95a05ffc93c119e6feee16cb01d0ccd1a6df091 + - - <_3:fileName>./config/helper-snippets/DUK_F_TOS.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1324"/> + + ./config/config-options/DUK_USE_DATAPTR16.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/feature-options/DUK_OPT_FUNCPTR_DEC16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS532"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/compilers/compiler_msvc.h.in - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2cf1bf8b74928280d733ff125306324cde1dafdf + + + 47c073f157be83b4ecfe64918ff878ac6cd2099f - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>03b4c77af1f40e8c1e4b853c1be252e126044582 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f503347d93483d5af29a4d68e514401f4bffc19c - - - - <_3:fileName>./config/architectures/architecture_arm32.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./config/config-options/DUK_USE_AVOID_PLATFORM_FUNCPTRS.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS812"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>de302c659385353558fd792b4ddf8c5e70797e82 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>22ea5eab18fdfa9b14d755b2eaadfb05e4b43d16 - + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/config-options/DUK_USE_NONSTD_FUNC_CALLER_PROPERTY.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS862"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_EXPLICIT_NULL_INIT.yaml + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f742435dd3ddc1ae6f2587856fd4b7aebeff1118 + + + 8a93bd26354028c246c213b885e132ae595f3b57 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f6c9fca4e362ec09c551e923d51d7093c1a264d5 - - - - <_3:fileName>./config/helper-snippets/DUK_F_GCC.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1360"/> + ./tools/extract_chars.py + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./config/config-options/DUK_USE_COROUTINE_SUPPORT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./src-separate/duk_dblunion.h - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS960"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f977bedf2631aca7493ce2d1cc2dd253e93cc566 + + fb2406b05571014ed4365f8662890707cddd5665 + - - <_3:fileName>./config/config-options/DUK_USE_FATAL_HANDLER.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1212"/> - - - <_3:fileName>./extras/alloc-pool/ptrcomp_fixup.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1478"/> + ./src-separate/duk_henv.h + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./config/helper-snippets/DUK_F_MSVC.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./config/feature-options/DUK_OPT_NO_JX.yaml + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1370"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2d47b9120905bbcb050a48ec2c0546204759329a + + b6247f203a3a957776207ea56985300096ac13ee + - - <_3:fileName>./config/feature-options/DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS582"/> + + ./config/config-options/DUK_USE_FUNCTION_BUILTIN.yaml + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9babdc4300dc79498f1d2bce3935f70c7666827e + + + a0c593d9d203fd0d2b3b204ae39992d8a332c86d - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c2223c5141efb9a995688c6e9b57fca2a06175d5 - - - - <_3:fileName>./config/helper-snippets/DUK_F_TINSPIRE.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1356"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>3cf3df6af3b4bb276bfa9305f4193efddcaaa37b + + b431766e1cfdd5a19bd0f1d4b4dac04cff439ad1 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>49a0495ca06511f8f85caa5a9441d77b5b74f87b + + + 8e1a45476cf90a37c853d201c5bc07aec22b52b8 - - <_3:fileName>./src-separate/duk_heap_memory.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS402"/> + ./config/config-options/DUK_USE_PARANOID_MATH.yaml + + + - - <_3:fileName>./config/config-options/DUK_USE_ES6_PROXY.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./src-separate/duk_error_misc.c - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS898"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>33c7608ed956874d642dd81d3b2f7584e6878a72 + + 7881506e8ff2479944166f80633183dce0b92628 + - - <_3:fileName>./config/config-options/DUK_USE_MS_STRINGTABLE_RESIZE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS852"/> + + + ./config/config-options/DUK_USE_ESBC_MAX_LINENUMBER.yaml - - <_3:fileName>./debugger/package.json - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS60"/> + + + + ./src-separate/duk_hobject_pc2line.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a536fe74c5574b2abcaf15e0f12ca3a705878bb2 - - - - <_3:fileName>./src-separate/duk_js_var.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/architectures/architecture_x86.h.in + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS346"/> - - <_3:fileName>./src-input/SpecialCasing.txt - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-separate/duk_selftest.c + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1550"/> - - <_3:fileName>./src-separate/duk_replacements.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS440"/> + ./config/feature-options/DUK_OPT_NO_SECTION_B.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/examples/enable_fastint.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS696"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./licenses/lua.txt + + - - <_3:fileName>./config/feature-options/DUK_OPT_NO_BROWSER_LIKE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./config/feature-options/DUK_OPT_EXTERNAL_STRINGS.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS606"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>648ba478fe390a171f7464f0ffee3e003d9de3ab - + + ./src-separate/duk_error.h + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>58193cfef36035e44c517256a84bc5e4da3dc6a7 - + + + ./config/config-options/DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9a31edd2028d39d24aa9bfdbd2b70ce2a64b8493 + + + f0f13d25ed1255364447accef4d023dd8ed0bc3f - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0125ebcabe62cef4923e75527d3128e8c48cdf1f + + + 5f89917c0262574a299a19edd39ed1d4802162f3 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2faa38660857db0600b15f0870fb2adde485fb8d + + 2f76ddc687fbab7a6fbce2bf60e828c1b5f8384d + - - <_3:fileName>./src-input/duk_util_bufwriter.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + ./config/config-options/DUK_USE_NONSTD_FUNC_STMT.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1500"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>68fc322fe33c22d75a188881f8e618cb392e2d8a + + + ac909735adaae34684dec95a1697f1923cf11266 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d5e579babcae88dd628cc4ae5bfbab3f0cc14c67 + + + 86f6054fb0acb6434994c8ecdbc4ee64abaff285 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>79d42208c44a8ecef264682f6c72eb8bb4ad122a + + + e5f9464a44b4a8cdda06fbd8503a3cd37f04164f + + + + + + ./examples/coffee/hello.coffee + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b179e01832915e76316312d8603fdd6c72f3ddd4 + + + cc54527457f651a7560d0ab5953c4423ac045253 - - <_3:fileName>./config/compilers/compiler_bcc.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + ./config/config-options/DUK_USE_TRACEBACK_DEPTH.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS688"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>10c24a17c2f5f82d8c1a8fab8673c0c9075c1817 - + + ./config/helper-snippets/DUK_F_POSIX.h.in + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./src-input/duk_bi_global.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1518"/> + + + ./src-separate/duk_heap_stringtable.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>cd946b6dc4b385ebf968551d58d122457ca2d81c - + + + ./config/config-options/DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - - <_3:fileName>./extras/minimal-printf/duk_minimal_printf.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1428"/> + ./config/config-options/DUK_USE_PC2LINE.yaml + + - - <_3:fileName>./config/config-options/DUK_USE_MARK_AND_SWEEP.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./tools/resolve_combined_lineno.py + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1018"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/feature-options/DUK_OPT_EXTERNAL_STRINGS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS644"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./config/config-options/DUK_USE_GLOBAL_BUILTIN.yaml - - <_3:fileName>./Makefile.eventloop - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./config/examples/security_sensitive.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS32"/> + + - - <_3:fileName>./examples/eventloop/client-socket-test.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./config/config-options/DUK_USE_STRTAB_MINSIZE.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS122"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./examples/alloc-hybrid/duk_alloc_hybrid.c + + + + 1a39c4e48802cd130b20048df8515ffd308f79cc + - - <_3:fileName>./polyfills/object-prototype-definesetter.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS464"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_ROM_OBJECTS.yaml + + + + - - <_3:fileName>./config/config-options/DUK_USE_HOBJECT_LAYOUT_1.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1078"/> + + + + ./src-separate/duk_error_longjmp.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>49d0b785377b9d56cb70bbed74cd34c0d1c64b32 + + + 62ff89202a17f7e7386a37bfd56d3337bf6ab899 - - <_3:fileName>./src-noline/duktape.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS44"/> + ./config/config-options/DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./src-separate/duk_config.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + ./examples/eval/eval.c + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS370"/> + - - <_3:fileName>./src-input/duk_hbuffer_ops.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1678"/> + + ./config/config-options/DUK_USE_64BIT_OPS.yaml + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>5844aa496feafa656524f4e02e300afa34936dcf - + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/feature-options/DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT.yaml + - - <_3:fileName>./mandel.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS16"/> + ./Makefile.hello - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ff9118d49ebfa3557c4248f16fe3364ad976ed44 - + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-input/duk_bi_encoding.c + + + - - <_3:fileName>./config/config-options/DUK_USE_PACK_DUMMY_MEMBER.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./polyfills/duktape-error-setter-writable.js - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1304"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/config-options/DUK_USE_USER_INITJS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./src-separate/duk_regexp_executor.c + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1294"/> + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>5c2f7a75a864e293b930281437969ca35dfdb0ca + + + a5b9b0e4e9cf985ce67bf6c342b193b363ae2357 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>325633587f490f79810f78f19ef7ca4b263b4847 + + + ca8852f7c984751bb182b4099151a9f0017e5381 + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./config/config-options/DUK_USE_VARIADIC_MACROS.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-input/duk_api_internal.h + + + + + + + 92794d5e42227b6cf73824c394bfa98ba0a6af09 + - - <_3:fileName>./src-separate/duk_api_call.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + ./config/feature-options/DUK_OPT_DLL_BUILD.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS256"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bb94ce16f0e382c5f77d3f25b34f98dbb3774c0f + + + 07b50af99a03e22031d88d803f1026fe1e78313e - - <_3:fileName>./src-separate/duk_hbufobj_misc.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS212"/> + + ./examples/guide/uppercase.c + - - <_3:fileName>./src-input/duk_bi_thread.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./config/config-options/DUK_USE_HSTRING_ARRIDX.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1730"/> + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>6389e13711ca106d4b29f9c948970cbdd73871de + + + a0c593d9d203fd0d2b3b204ae39992d8a332c86d - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4718593942e66999888eb0a56572eaed93c4f5a3 + + + 71b56d45f8ed6055b15d8ad4454080284efe6320 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>e0b4c75970bc07f17812e9d2711aa21d5e73c83b - + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./config/config-options/DUK_USE_JSON_DEC_RECLIMIT.yaml + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>3a18848270679c3676691342934872f9510c6dbe - + + + + ./debugger/static/index.html + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f9072f5c361c86887b57ce662b3cd7211b4ce346 - + + + ./config/config-options/DUK_USE_DATE_GET_NOW.yaml + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2c44d7d488bb32ca481cd48c49eae5fe254a859a + + + 4674717b6b5b3acecf143752b2051b1f3a4dfbec - - <_3:fileName>./config/feature-options/DUK_OPT_DEBUGGER_FWD_LOGGING.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-input/duk_jmpbuf.h - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS646"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4db06fd9d96853165d9c5bb92d722ee87649081a - + + + + ./src-noline/duk_source_meta.json + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./extras/module-duktape/duk_module_duktape.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1446"/> + + + ./Makefile.eventloop + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./Makefile.sharedlibrary - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS10"/> + + ./config/platforms/platform_tos.h.in + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9bad9281c81e26cc8fd9e4cebf22791a3c58953a - + + + + ./src-input/duk_alloc_default.c + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9bb6ca1fa3ad4c593b000b2de5aca013b95adda0 + + + ./config/config-options/DUK_USE_COMPUTED_NAN.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + 8b51c94bc412af77277e9f919c0aca4ec5ae8179 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1b9505297d7bf88af1a1a2f37d1a47833ceb06ae + + 302141ef70a561b63c1e5e9247bf4f00621d78c1 + - - <_3:fileName>./config/config-options/DUK_USE_ARRAY_FASTPATH.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./src-separate/duk_hobject_alloc.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1058"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>76deaceac1803dc35ad32593a3961f2ac3b3acd9 - + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_DPRINT.yaml + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>821d0801ed06574f5503b9d5b76eebc2f3347328 - + + + ./extras/minimal-printf/duk_minimal_printf.h + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>3237996b63a91f77d8e28a1fd95cee3581653843 + + + 1b43b9e5d5a10e32acaf50fff25138f1077bc7fe - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>021e861014ab9e9ab906643ef6685c62f87eb6ab + + + 31149151d8a28798b96e542d77ca605c6669430c - - <_3:fileName>./src-separate/duk_heap_stringcache.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + ./config/platforms/platform_amigaos.h.in + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS448"/> - - <_3:fileName>./config/config-options/DUK_USE_DEBUGGER_INSPECT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS918"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./src-input/duk_bi_proxy.c + - - <_3:fileName>./src-separate/duk_bi_object.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + ./src-input/duk_api_compile.c + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS432"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9f2cc67e2ea3207f535fd4cf52fac95d425d0d2e - + - - <_3:fileName>./config/feature-options/DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./extras/minimal-printf/README.rst + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS488"/> + + + + - - <_3:fileName>./config/feature-options/DUK_OPT_DEBUGGER_TRANSPORT_TORTURE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/feature-options/DUK_OPT_NO_FILE_IO.yaml + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS638"/> + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9678a4365925b40c96c3626c39b790c0574533dd + + + 9b4ed86ac44da12b78e9eb87d0d9aaa7149b0518 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>5b2e82eceb788df59bd57e7708c116e46a860072 + + + caa1f90113a2f6c2134aadd6d68fbd62d00bba3c - - <_3:fileName>./config/config-options/DUK_USE_NONSTD_GETTER_KEY_ARGUMENT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS876"/> + + + + a0a83407e2df1feec48016a43cb7727789c05b5d - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f441f79468112b6d4002e64fc6043c96c9bfdbf1 + + + 539fc3e53e1a392c4d54968f8e4e90bc49a736d9 - - <_3:fileName>./src-separate/duk_hnatfunc.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./src-separate/duk_bi_global.c + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS340"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>fd9e637eeb76970ee8979e633ad14fb8373f7a07 + + 6130c5fb5721757ae3c9bb80c889ef31f77c29ba + - - <_3:fileName>./src-input/duk_error.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + ./extras/alloc-pool/duk_alloc_pool.c + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1514"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>dbea11328269ff4e954fcac30c38d1310d028677 + + 6275e937886be08832b263510e5b910f4fdfb59e + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>512de805b6311b702ad2b1c143e24747a896c5fa + + 1e740c56b2803fd26479030874881333a64b9b74 + - - <_3:fileName>./config/helper-snippets/DUK_F_UNIX.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/header-snippets/packed_tval_fillin.h.in + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1396"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>dcf77d110c1826159576dfc92cc2996cf4bd0439 + + + d030fd37b72538190aa765588d54fb32f788a7a0 - - <_3:fileName>./src-input/duk_util_bitdecoder.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1588"/> - - - <_3:fileName>./src-separate/duk_debug_macros.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS452"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./examples/eventloop/main.c - - <_3:fileName>./config/examples/shallow_c_stack.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS716"/> + ./extras/duk-v1-compat/README.rst + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a0660bd79f4d47b95a6db98ccce46a6e95ab6a80 + + 4c0065913a47c815b673b6da75d0d4d3e49ae5f9 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>324239d893eafa800800faa764908d6ea232d78c - - - - <_3:fileName>./examples/debug-trans-socket/duk_trans_socket_windows.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./config/compilers/compiler_bcc.h.in - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS168"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>cb53b7840e10a86a1ac15e0ee6319b36a24ba924 - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>68b8873adab6f2c0ddd8ba08d64639aa0b8599a7 + + 3aadf800b97c060152c00498b94553985e31c982 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>55c5af54de6869b35ba055476780a924bb5b746d - + + + ./config/config-options/DUK_USE_REGEXP_CANON_WORKAROUND.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./AUTHORS.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS26"/> + + + + ./config/platforms/platform_apple.h.in + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./src-input/duk_heap_refcount.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./config/config-options/DUK_USE_HSTRING_EXTDATA.yaml + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1638"/> - - <_3:fileName>./config/config-options/DUK_USE_FASTINT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./examples/cmdline/duk_cmdline_ajduk.c + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS872"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>324b051b9bd40e29cc8dd721f8c03a4ca933905b + + 548110e8be09c682e67929b3f270a6a480b30294 + - - <_3:fileName>./config/config-options/DUK_USE_JSON_STRINGIFY_FASTPATH.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1010"/> + ./src-separate/duk_hbuffer_alloc.c - - <_3:fileName>./config/feature-options/DUK_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS636"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./tools/merge_debug_meta.py + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>5590b62977c295ffea8de128b75eb95e3667e413 + + + 7216d147f8036390c8b6b2e32daa9cf30c5432fb - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9f2cc67e2ea3207f535fd4cf52fac95d425d0d2e + + 82314b509ee3b15b393fefe747c8e0169ab39aaa + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>72e17a756cd47580b6125c5aa10a89ce2bb9b7a9 - + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-input/duk_util_bitdecoder.c + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>cc29429c71aa37475617e351d3cdcac87d55d76d + + + d0c303420f5cb41478a761415a6c3b1255f96869 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>cd946b6dc4b385ebf968551d58d122457ca2d81c + + 92ce3decf72b10b0023116ac727a752e8749aa90 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>31b9be336f23663ecfb92b7e49a9a94fea50ea61 + + bccf22fe631bc5d0ddedc31339518d7f5578e7d8 + - - <_3:fileName>./config/platforms.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS478"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./config/config-options/DUK_USE_NONSTD_JSON_ESC_U2028_U2029.yaml + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>cc407be303fcd2bbd3005ec6110ef6b55095a0b9 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>6130c5fb5721757ae3c9bb80c889ef31f77c29ba - + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_DATE_PARSE_STRING.yaml + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>6620f1f2d0714ae0c83d6585590c2e5883cf4a0a - + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./config/config-options/DUK_USE_DOUBLE_LINKED_HEAP.yaml + + - - <_3:fileName>./config/platforms/platform_apple.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./src-input/duk_hobject_props.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS774"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2e03e3fa86f25b27b4ef6487fc55112eb3397170 - + + + + ./config/config-options/DUK_USE_JSON_QUOTESTRING_FASTPATH.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>07b3a6879ea93374f9f2cd13bb236d6ecd269ea3 - + + + + + ./config/feature-options/DUK_OPT_NO_JSONC.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>62ff89202a17f7e7386a37bfd56d3337bf6ab899 - + + + + + ./config/helper-snippets/DUK_F_CYGWIN.h.in + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/config-options/DUK_USE_DATE_FMT_STRFTIME.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS944"/> + + ./src-separate/duk_api_codec.c - - <_3:fileName>./config/examples/disable_es6.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS700"/> + + + + ./extras/console/duk_console.h + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/header-snippets/platform_sharedincludes.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS766"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-separate/duk_bi_object.c + + + + - - <_3:fileName>./src-separate/duk_hobject_pc2line.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/architectures/architecture_arm64.h.in - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS282"/> + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>51c2f0a0ae55d972e55fa99306938971df0be3a2 - + + ./config/config-options/DUK_USE_ARCH_STRING.yaml + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./examples/jxpretty/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./config/config-options/DUK_USE_FASTINT.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS96"/> + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>df0be76d86f9c7a8f3ff117966dc1457b5c944fe + + + 01faca6e5c2f2d1bb900568ce77b723a6c123b4b - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>734d4f4a2f28b6b3df4db12a5bc6b2b84816370b + + 0674047084209a5024e62499bd0593c894167295 + - - <_3:fileName>./extras/module-duktape/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1440"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>fb913b14a8e2827fc9c4c1f7d9eb1278bd102d1a - + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_DATE_GET_LOCAL_TZOFFSET.yaml - - <_3:fileName>./src-input/duk_replacements.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./src-input/duk_bi_error.c + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1742"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>99928d954c5b34b61e98d61534282905989ca671 + + c589f36a3e792383a5dc4196dcc6cd21462e5230 + - - <_3:fileName>./config/config-options/DUK_USE_GLOBAL_BUILTIN.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS880"/> + + e680bc42fb4cacf2f82a40f05e14a280a6981614 + + - - <_3:fileName>./config/feature-options/DUK_OPT_NO_PACKED_TVAL.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + ./src-input/duk_hbuffer_ops.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS566"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>cc84b5894800d434ab9ce8ab3a1aef077f709506 - - - <_3:fileName>./config/config-options/DUK_USE_DEBUG_BUFSIZE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-input/duk_api_debug.c - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1308"/> + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f2d9a140bfb00688a277148c7f5eb16275f607f3 + + + 9f2cc67e2ea3207f535fd4cf52fac95d425d0d2e - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>23cf8b40dbb8e07a2e4ad7333aa4db6756ca8242 + + + a6421e1ac83fe5caba70acb338464e6a811ce160 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bd1beb68239b1a4224f5224aa6b17b1ca8c8bff3 + + a0a83407e2df1feec48016a43cb7727789c05b5d + - - <_3:fileName>./src-input/duk_hobject_misc.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-separate/duk_bi_math.c + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1508"/> + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ebec67f0e7e3c393f01dd50f9c661fca6b779328 + + 881f1b114c9fbba139044ddcbbc5398243185d10 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>e6d75a7c9cc7f6109387ceda77f4b56f4e78b8f1 - - - - <_3:fileName>./config/config-options/DUK_USE_NONSTD_SETTER_KEY_ARGUMENT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS842"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9b6e480763339e9e249e47755c80c198b0fac72a - + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./Makefile.jxpretty - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1b4d42fe7d94810261aaa6b3f0a96d633e682e0e + + + b9cb2916325600c430473986730e566ab6718815 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>90362a2493de41a41ed705c3f286356db9020008 + + 936825b1abdf981153f894234ffb564a49c34a29 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ea9a99fc1cba271a4598a222c97191aa67f42a25 + + + 64566ae0bdc1c3e1017604b6b45d515c30d976eb - - <_3:fileName>./examples/dummy-date-provider/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + ./config/feature-options/DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS126"/> + - - <_3:fileName>./config/header-snippets/msvc_visibility.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS738"/> + ./examples/hello/README.rst + + + - - <_3:fileName>./config/platforms/platform_linux.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS796"/> + + + + a8e303629c820f11766517de993860897a35b022 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c237e384900f6c517265b6b1f7ded0e5d9faaf69 + + 6e5ab10b5431e945a8aa3625190e89a56ee6f424 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a534e0108c394ab49c72dc9dec62029f2bf91406 + + 043b24a2cd514c40b4ce75bcd0204f2db8d5fd4f + - - <_3:fileName>./config/config-options/DUK_USE_DPRINT_COLORS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS970"/> + ./config/feature-options/DUK_OPT_NO_BYTECODE_DUMP_SUPPORT.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./config/config-options/DUK_USE_DOUBLE_ME.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1220"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a15c8491351869c1529bf5748f554039cf1018eb - + + + + + ./examples/debug-trans-socket/duk_trans_socket_windows.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./src-separate/duk_api_compile.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-separate/duk_hnatfunc.h - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS392"/> + + + - - <_3:fileName>./examples/sandbox/sandbox.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_FULL_TVAL.yaml + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS186"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2c44d7d488bb32ca481cd48c49eae5fe254a859a + + + 9888edb8332bc63ba259b10d7f18c760db974a23 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1e740c56b2803fd26479030874881333a64b9b74 + + a5989c0742f4b6c6cb847275f6b4e4d1c78c6b0b + - - <_3:fileName>./src-input/duk_heap_stringtable.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + ./src-input/strings.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1578"/> + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0b5596da17555ad475a5de16b88d18c183ab6d21 + + 0c8c6a420632c5787d7af455c9bf89586549d970 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>28dc111c6a0c6bc4b041108eaf74b08167d0a4fa - + + + + + + ./config/config-options/DUK_USE_REPL_ISFINITE.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>43b9b72a847085560f84a476f823744e637b3f70 + + + 42ddc03124956c14602a7e3a66d37386be0293d1 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1a64e0946145a92e1620fb5cfee75a3a9d2956d2 - + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-separate/duk_jmpbuf.h + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7f5238fdc9fc1e0e362ebe9660135b4a868c2661 + + c4012e98e850e8ec72b7b445c46771cb18789bfe + - - <_3:fileName>./examples/alloc-logging/log2gnuplot.py - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS192"/> + + + + 0cc625a8d72def6d789f26930691c72953954361 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9e81b2414e53620f2a8dd5c15de8896c343ca7b8 + + + 76deaceac1803dc35ad32593a3961f2ac3b3acd9 - - <_3:fileName>./config/architectures/architecture_m68k.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS814"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9aedb54b5598cfb1fabc7e96e28237a1ab710cc0 - + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/feature-options/DUK_OPT_BUFFEROBJECT_SUPPORT.yaml + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f1c6b0f6e8a9bd67a11a58f0569f3e06afa69e33 + + a40d0374715746d167e89f0c61963f962a90165e + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0ec6da5d51a0fbe7ad3725af169a2808665ee75f - + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./extras/print-alert/test.c + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>73a7e14185a2bcfa868083ddd7be4806b111fbfd - + + + + ./config/config-options/DUK_USE_DEBUGGER_SUPPORT.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ba8d5c0458e36b58d580a0d1f4d8b1e94f7d9d09 + + 235c35fc0a44ba78b50a392af5d936c62b46775a + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c42980acd5d218990e40cffd30b9e84aa0f36b25 - + + + + + + ./examples/eventloop/fileio.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./extras/alloc-pool/test.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./src-input/duk_util_hashbytes.c + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1488"/> + + - - <_3:fileName>./src-separate/duk_numconv.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-separate/duk_bi_proxy.c + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS210"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c633f8619ed0e75a43d42d966d7834e526827dda - + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_AUGMENT_ERROR_THROW.yaml + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>536cb431ce24b3032601b548479b6fb6f8764e51 + + 9b254d86bac8eb249de6789e8521c0441220e383 + - - <_3:fileName>./src-separate/duk_hcompfunc.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-separate/duk_js_bytecode.h - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS404"/> + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>048c915047f148e35ceabc8bf4eafda0530e6e28 + + f830b9571e52a1943907b7ab83b31d19841a2e31 + - - <_3:fileName>./config/feature-options/DUK_OPT_BUFLEN16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS502"/> + ./src-input/duk_js.h + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./extras/duk-v1-compat/test_compile1.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1416"/> + + + + 1043c0b85f86de642ecdac58e1002ae714f05b8c - - <_3:fileName>./src-separate/duk_lexer.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS336"/> + + 9893700d76a15b9d9401eca1eb0a40a34933c0b4 + + - - <_3:fileName>./examples/debug-trans-dvalue/duk_trans_dvalue.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_DOUBLE_ME.yaml + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS182"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>700d0db5f26ccdde22fb43000ff183fab145b46d + + + dae7949fdb2499782142beb9dfc26fc361b4d1f0 - - <_3:fileName>./config/feature-options/DUK_OPT_SIGSETJMP.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS588"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>09d5941728d8b74cd13c9faacaade4fba1ddb8f3 + + 47443510d688691ed0eaa5a3885012265ba6f05c + - - <_3:fileName>./src-separate/duk_error_macros.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + ./config/config-options/DUK_USE_ERRTHROW.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS378"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/config-options/DUK_USE_JX.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./config/config-options/DUK_USE_FATAL_HANDLER.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1192"/> + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>60725c57ad6151972c19a7610899387b488ec288 + + 867cac057ecaeed5a01fde135115bd295a78ffd8 + - - <_3:fileName>./src-separate/duk_hthread_builtins.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS302"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a4d21026ffbbff2e612dcc6b272a670d191c2ff7 - + ./config/header-snippets/byteorder_derived.h.in + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./src-separate/duk_js_compiler.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + ./config/helper-snippets/DUK_F_MSVC.h.in + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS332"/> + + - - <_3:fileName>./config/feature-options/DUK_OPT_NO_OCTAL_SUPPORT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_ESBC_MAX_BYTES.yaml + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS618"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>da20e9f1611f46a870cad37c93aeaf0c1cdde7aa - + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./extras/module-node/duk_module_node.c + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ddb7731f06008f9f7fe10546c7bc64ee6568c052 - + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./config/config-options/DUK_USE_DOUBLE_BE.yaml - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d4456e3a8ac7f027af7db2b4557b0be535a26fb3 - + + + + + ./tools/yaml2json.py + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>77e76c341a29fae1658f6417b59afc44af5519ca + + 9b254d86bac8eb249de6789e8521c0441220e383 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ca8852f7c984751bb182b4099151a9f0017e5381 - + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./config/other-defines/c_types.yaml + - - <_3:fileName>./config/feature-options/DUK_OPT_ASSERTIONS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS616"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-separate/duk_hbuffer.h + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7d0d6e5c35e543326fc4f335ea92b5dd1c630d3e + + 31b9be336f23663ecfb92b7e49a9a94fea50ea61 + - - <_3:fileName>./src-separate/duk_replacements.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS316"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_FUNC_NAME_PROPERTY.yaml - - <_3:fileName>./examples/guide/prime.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS150"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/compilers/compiler_gcc.h.in + + + - - <_3:fileName>./config/feature-options/DUK_OPT_DPRINT_RDTSC.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS508"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f5036786154c7b87d513d25e87d3cfa1ea0b9d64 + + c6481ef081e76cf3c06586bc6ec54b8b084df161 + - - <_3:fileName>./config/config-options/DUK_USE_ENCODING_BUILTINS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./config/feature-options/DUK_OPT_TRACEBACK_DEPTH.yaml + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1258"/> - - <_3:fileName>./config/platforms/platform_cygwin.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + 22577ac0780d7a5db504ccddda510b881fb234ac + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS798"/> + ./examples/cmdline/duk_cmdline.c + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>51c2f0a0ae55d972e55fa99306938971df0be3a2 + + 2952675782b5d4e5f0c46246e495525824d18a57 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a08e43879af86c86670dbbaa10af31e4ad8e5951 + + + 9b85fa1c1e28fabb7d32976be0f380d48f65cd90 - - <_3:fileName>./config/config-options/DUK_USE_NONSTD_JSON_ESC_U2028_U2029.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS912"/> + + ./config/config-options/DUK_USE_DEEP_C_STACK.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1477f6a86de2034d299d2ea7d51bd803b259c012 + + + 6f41c758fc3f97aebfd2f62d2a09ae0548587c4b - - <_3:fileName>./config/header-snippets/platform_cppextras.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + ./src-separate/duk_util.h + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS740"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>e5a5f0db067ec56c6d2f7356f412222a8884dc92 - - - - <_3:fileName>./src-separate/duk_jmpbuf.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS214"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./debugger/README.rst + - - <_3:fileName>./src-input/duk_bi_duktape.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1702"/> + + + ./extras/duk-v1-compat/test_eval2.js - - <_3:fileName>./config/config-options/DUK_USE_BUILTIN_INITJS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1002"/> + + ./config/feature-options/DUK_OPT_EXEC_TIMEOUT_CHECK.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/config-options/DUK_USE_TARGET_INFO.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./config/feature-options/DUK_OPT_FORCE_BYTEORDER.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS904"/> + + + + - - <_3:fileName>./config/config-options/DUK_USE_COMPUTED_NAN.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1190"/> + ./src-separate/duk_api_time.c + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c421588cff2ced0f938f3aa073f0ce48a553c935 + + de302c659385353558fd792b4ddf8c5e70797e82 + - - <_3:fileName>./polyfills/duktape-isfastint.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS466"/> + + ./config/config-options/DUK_USE_ROM_PTRCOMP_FIRST.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./src-input/duk_hcompfunc.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + ./config/config-options/DUK_USE_GC_TORTURE.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1706"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./src-separate/duk_js.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + ./config/feature-options/DUK_OPT_DPRINT_COLORS.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS238"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8e1a45476cf90a37c853d201c5bc07aec22b52b8 - + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./config/feature-options/DUK_OPT_NO_FILE_IO.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS498"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./examples/eventloop/c_eventloop.js + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>484c4cbf935e7b38a0d43b491576ada56ddc59a1 - + + + + + ./src-input/duk_js_call.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7fd58215ed03b7f38f823c4909f50d8659f22aec - + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-separate/duk_api_call.c + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>6eb3ac68f1ef4456c94c518c3a7afaeae48d1a69 + + 4d562b6ab95fd3b5c536db49ca78ce3000be0c0e + - - <_3:fileName>./config/feature-options/DUK_OPT_DATAPTR_ENC16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS666"/> + ./config/feature-options/DUK_OPT_NO_TRACEBACKS.yaml - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>cb46ea9dcb2e07f36d9817a428922568891d02ce - + + + ./polyfills/console-minimal.js + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>748abde5cf2f68709270fe20fd152fd48a329fc7 + + + 043c5603e35121d4eb613e7b9d87c1dc7e353ecb - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2685bcf2640692a14198527c0d5dc3262b2ed061 + + 0a53751e62b48704017c6839c5264927f0130880 + - - <_3:fileName>./config/config-options/DUK_USE_JSON_ENC_RECLIMIT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS892"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-separate/duk_bi_error.c + - - <_3:fileName>./debugger/Makefile - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS54"/> + ./config/config-options/DUK_USE_STRTAB_RESIZE_CHECK_MASK.yaml + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bc37be576519d2713e5f18496e6ad167978d0785 + + + f5241cb38baccbfff3b042da15e039ec8c6cec7f + + + + ./config/feature-options/DUK_OPT_EXTSTR_INTERN_CHECK.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8fa3e2ce8d44a9946c535cdbb411e66ab865e8b0 + + + b859c85ce9b2e332c0a171e061faa8c0326e0451 - - <_3:fileName>./src-input/duk_unicode.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-separate/duk_debug_fixedbuffer.c - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1542"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9f3e1e77e31ce573126abe1e7adba02261e34ee9 - + + + ./config/platforms/platform_durango.h.in + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - - <_3:fileName>./src-input/duk_heap_stringcache.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1750"/> + + ./config/feature-options/DUK_OPT_PANIC_HANDLER.yaml + - - <_3:fileName>./examples/codepage-conv/test.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + ./extras/logging/test.c - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS92"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>070787b18e465b40c2589e365ba6cbb299933d83 - + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-separate/duk_bi_thread.c - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>6d6a0ed935fc74ff5163e40366294a0f759501f2 + + + e7390a8f9b29a5ee991f33d6a7dc5b291b2f5141 - - <_3:fileName>./config/header-snippets/inline_workaround.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS768"/> + ./config/platforms/platform_openbsd.h.in - - <_3:fileName>./config/config-options/DUK_USE_COMPILER_STRING.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + + ./config/helper-snippets/DUK_F_FREEBSD.h.in + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1266"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>cc59276261320c29a5168ede62c55b921b11cd37 - + + ./config/feature-options/DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8c5ee5b508a23ac5089a7e6c76593b6678965869 - + + + ./config/feature-options/DUK_OPT_NO_PACKED_TVAL.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>92ce3decf72b10b0023116ac727a752e8749aa90 + + + f920e5f39cc338c759351cb01591a48f49daf3e6 - - <_3:fileName>./polyfills/duktape-error-setter-writable.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS456"/> + + ./src-input/duk_bi_json.c - - <_3:fileName>./examples/dummy-date-provider/dummy_date_provider.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS128"/> + ./src-input/duk_bi_duktape.c + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f3ed5c785b60b0f39a74cc3f5b73b0c6e24287c3 + + e7390a8f9b29a5ee991f33d6a7dc5b291b2f5141 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a5bfd4c7cba5293f11c4a28838f3d8cca7312cfc + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./config/feature-options/DUK_OPT_SETJMP.yaml + + + 9e401b9c2bfc0c884067440ca4654fc34efac9ad + - - <_3:fileName>./config/platforms/platform_amigaos.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./config/config-options/DUK_USE_ROM_GLOBAL_INHERIT.yaml + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS786"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0811e545a133c3a62672e239624a0c1f11478b8d - + + + + + ./src-input/duk_regexp_executor.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f1020eedf224158992a70be40cfb1267e806399f + + + 6feece755ec26b4ba0b97340afc727839cbb10b6 - - <_3:fileName>./tools/duk_meta_to_strarray.py - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1782"/> + + + + ./config/helper-snippets/DUK_F_DURANGO.h.in + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/config-options/DUK_USE_ROM_GLOBAL_CLONE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + ./config/platforms/platform_genericunix.h.in - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1082"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./config/platforms/platform_emscripten.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_PACKED_TVAL.yaml + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS778"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1c81542f71633b983d5fad3ca22ee54fa33c6589 + + 4cd3c4b69a92040017526ff84efb1e468bc436fc + - - <_3:fileName>./config/config-options/DUK_USE_FLEX_C99.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/platforms/platform_genericbsd.h.in + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1004"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bdd92a8da86a7c626d98f86a7f41ffac27635806 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>aa1f72e7a2b4891ec1f445eb031dfba69bdc85de - + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./examples/debug-trans-socket/duk_trans_socket_unix.c + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b80c8be283c2ad3501e422d39508a7cfa765d632 + + + 85cc3ad49e0ebc536ca7efc917b4369bb8ab2586 - - <_3:fileName>./examples/cmdline/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS166"/> + + ./src-separate/duk_alloc_default.c + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/config-options/DUK_USE_FLEX_ZEROSIZE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1196"/> + + + + ./config/helper-snippets/DUK_F_AIX.h.in - - <_3:fileName>./extras/alloc-pool/Makefile - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1482"/> + + 1a39c4e48802cd130b20048df8515ffd308f79cc + + - - <_3:fileName>./config/config-options/DUK_USE_REGEXP_EXECUTOR_RECLIMIT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./tools/create_spdx_license.py - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1100"/> + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/config-options/DUK_USE_STRTAB_PROBE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS928"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_STRHASH_DENSE.yaml - - <_3:fileName>./src-noline/duktape.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/architectures/architecture_x32.h.in + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS42"/> - - <_3:fileName>./config/config-options/DUK_USE_HOBJECT_LAYOUT_3.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1242"/> + + + + 820715160155bc4e82c401e1650efc80972071b8 - - <_3:fileName>./config/config-options/DUK_USE_JSON_DEC_RECLIMIT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS846"/> + + ./debugger/duk_debug_proxy.js - - <_3:fileName>./config/architectures/architecture_sparc64.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS832"/> + + + + 1cb67a46fec2d198b68c1faeaff801c5e0b8d56f - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f5b5b79a655e7fbfd11fe94b5e1d97ed45f15267 + + 633bb3732a4d6593bd0102b927430d7f6bedc2eb + - - <_3:fileName>./examples/eventloop/c_eventloop.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS108"/> + + 88ab1d060886393d94b6fb7c6054a0189117340b + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9382fc0a5c7ba0d4929ffcb6db48fe0bca974a8b + + 1eb68650f26279fc1b8968055dce544385d6a954 + - - <_3:fileName>./config/config-options/DUK_USE_MARK_AND_SWEEP_RECLIMIT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS900"/> + + + b431766e1cfdd5a19bd0f1d4b4dac04cff439ad1 + - - <_3:fileName>./config/config-options/DUK_USE_DATAPTR_ENC16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./src-input/duk_bi_date.c - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1284"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bdeb29fd0b17ff588e3b27c9ad421c8862130648 + + + 5e1c4e7836552ed2db8cd18f7505962d344d6670 - - <_3:fileName>./config/config-options/DUK_USE_DATE_PRS_GETDATE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS858"/> + + + ./config/helper-snippets/DUK_F_TINYC.h.in + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + bee1c12df927c44ecb4e0f1613114131d14554bf + + - - <_3:fileName>./config/config-options/DUK_USE_USER_DECLARE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./extras/module-duktape/duk_module_duktape.h - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1282"/> + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8fd242cf73e663d4b76d5b2a2ec5f78250a1fc65 + + 45391c3ac7f5de5a4480c83cce1c6a4946598174 + - - <_3:fileName>./config/config-options/DUK_USE_PARANOID_DATE_COMPUTATION.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS942"/> + ./debugger/Makefile + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./examples/guide/processlines.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + 7f1552015bd1bc4d9e7562c9ed80c7cb29f59b55 + + + + 80db4d3079a7e20ee0da07a089bd16fbfb611265 + + + + + + 1cec45c2d1998fa704e215a832b96856886d8aec + + + + + + + ./config/helper-snippets/DUK_F_GCC.h.in - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS140"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>dae7949fdb2499782142beb9dfc26fc361b4d1f0 + + + 1eb50379d9666232283722a2b9e18ebbd8a4d036 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>5d593ae6316ed7a3ea6e7ed0a47267745d79d12d + + + c2223c5141efb9a995688c6e9b57fca2a06175d5 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9bcbdd7d6fed9271f4bff23a23c6cad5e43c569d + + 1b49f5b5cdd7d32262568f53ec2073077d19d6ea + - - <_3:fileName>./config/config-options/DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1098"/> + + + 0952e4605da61d7296cb65c709dca67b5646d68e + - - <_3:fileName>./config/config-options/DUK_USE_ALIGN_8.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS966"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./config/config-options/DUK_USE_NUMBER_BUILTIN.yaml + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b982e61cd9151f6beef9c09428c845aff6572835 + + b3db58b9744de8c3afcc2fbadd38cedfc6a3d0d5 + - - <_3:fileName>./src-input/duktape.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./config/config-options/DUK_USE_HEAPPTR16.yaml + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1648"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/config-options/DUK_USE_NO_DOUBLE_ALIASING_SELFTEST.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1132"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/feature-options/DUK_OPT_NO_REGEXP_SUPPORT.yaml + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ed5f57f06ed4c688667789d238c7dcbf53741a7f + + + ./src-separate/duk_lexer.h + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./examples/guide/primecheck.c + + + 1322326a94dfa7af345af7ac0c7b60d787320e7d + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0f9c171bc34b70d3e2a6ccdefbf9983ef40731b3 + + + 525e80da2b6d3640fd42af0f662d7b68865d6529 - - <_3:fileName>./config/config-options/DUK_USE_HEAPPTR16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1114"/> + ./config/config-options/DUK_USE_DATE_FORMAT_STRING.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1a076d357ad863948af41a4548ddc96a5b6efb23 + + + 973b149b368bdb1c7dd070fb15edd2669f2897a7 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>dc4e9b1ce4f040f46b6bb1c3ee14d60bdc4ceda0 - - - - <_3:fileName>./config/config-options/DUK_USE_ASSERTIONS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1246"/> + ./config/feature-options/DUK_OPT_DPRINT_RDTSC.yaml + + + - - <_3:fileName>./config/feature-options/DUK_OPT_HEAPPTR16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./examples/alloc-torture/README.rst + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS590"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c622c5706ac71df3f1f61d78f440025710e9eb88 + + + cfc3b322f9816eaf5ac73401afe5cc2cff96c1fe - - <_3:fileName>./config/config-options/DUK_USE_DEBUGGER_DUMPHEAP.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-separate/duk_util_tinyrandom.c + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1260"/> - - <_3:fileName>./config/compilers.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS480"/> + + ./examples/codepage-conv/README.rst + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./src-input/strings.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1682"/> + + + + ./config/config-options/DUK_USE_INTEGER_BE.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8b51c94bc412af77277e9f919c0aca4ec5ae8179 + + + 070787b18e465b40c2589e365ba6cbb299933d83 - - <_3:fileName>./src-separate/duk_api_heap.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./examples/guide/README.rst + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS324"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ac15c07051c5f1cb05eeb27d5ea67a369ec7fb3e - + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./extras/minimal-printf/duk_minimal_printf.c + + - - <_3:fileName>./src-separate/duk_bi_buffer.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS334"/> + + + + ./config/config-options/DUK_USE_OBJECT_BUILTIN.yaml - - <_3:fileName>./config/examples/timing_sensitive.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + ./config/config-options/DUK_USE_DDDPRINT.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS708"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8a0985b15edda0391b5dda6b84a20fdc89376cc2 + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_DATE_NOW_WINDOWS.yaml + + + + + + + + 9f2cc67e2ea3207f535fd4cf52fac95d425d0d2e - - <_3:fileName>./src-input/duk_bi_json.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1596"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/feature-options/DUK_OPT_NO_ZERO_BUFFER_DATA.yaml - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c640b61e3177c48c1e4aa319155dc33502161be1 - + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_DEBUGGER_THROW_NOTIFY.yaml - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b823009fcdc91c45193ea61215fe0136c15a6e5a + + 6e79daebf74b5d1cb4ccbb1fa19f373d6a79a0fe + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1b365f83282745659aa239b8d5993fb8e7df1fca + + + acfd32ba813477baadf8d5e3a14a922289f13463 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>936cc6469c4d90c03414d7fff1162337774e7cd8 + + 02157444f6e2db250d79a2012e1fc12fa1133361 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>37c4b279336fdd9737f76e90603b89282f3c42d1 + + 9bb6ca1fa3ad4c593b000b2de5aca013b95adda0 + - - <_3:fileName>./config/config-options/DUK_USE_STRTAB_CHAIN_SIZE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1238"/> + ./config/config-options/DUK_USE_SHUFFLE_TORTURE.yaml + + - - <_3:fileName>./config/config-options/DUK_USE_INTEGER_LE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./src-input/duk_regexp.h + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1302"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b648ee8ed5f3f43b10480bbcb068a436d379bc09 + + c42980acd5d218990e40cffd30b9e84aa0f36b25 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>26c211f6a2f663d1fa48d938f5484f4060d8ff3d - + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + ./config/helper-snippets/DUK_F_SUPERH.h.in - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>98643d0524d3d5079a56e6eafc14b050cdb55eda - + + + + + + ./config/feature-options/DUK_OPT_STRLEN16.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./src-separate/duk_api_buffer.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/architectures/architecture_emscripten.h.in - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS414"/> + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>379b72c9dc094ae724828facc127d6e3c9eb6bda + + + 67912274a1cf6be140faff95ef0afcc5b6f1ad29 - - <_3:fileName>./config/config-options/DUK_USE_DUKTAPE_BUILTIN.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS878"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./polyfills/duktape-error-setter-nonwritable.js - - <_3:fileName>./config/config-options/DUK_USE_VARIADIC_MACROS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1216"/> + + eae356dfdf5fefa117c90c67113de4f7d3fdeff7 + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>caada55e058253f6ff08ba15730be8c0e8b0f082 + + + 65cd324991dc4a73f33d9b03c3b1617a0a7f69fe - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>39be8f5a1b6bf1a3fed5e3e9228c5c5ed3a2e63d + + + cd3f7e2dc9077f1f03aeb592a804a2a9e58db2bf - - <_3:fileName>./config/config-options/DUK_USE_ATAN2_WORKAROUNDS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_EXEC_INDIRECT_BOUND_CHECK.yaml + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1110"/> - - <_3:fileName>./examples/debug-trans-dvalue/duk_trans_dvalue.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS176"/> + + a1b56bf89cc0b16cb33855a51a39ab655823fc9f + + - - <_3:fileName>./config/helper-snippets/DUK_F_CPP11.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1372"/> + + 3aadf800b97c060152c00498b94553985e31c982 + + - - <_3:fileName>./config/compilers/compiler_generic.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS690"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./licenses/commonjs.txt + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7f3e3c61f6a55853d54cd8753196c70155e22b35 + + e6b61a8c5af43d0b2a9b74d34d147c10acc8d372 + - - <_3:fileName>./examples/coffee/mandel.coffee - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS74"/> + ./config/helper-snippets/DUK_F_LINUX.h.in + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./config/feature-options/DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS584"/> + + + ./src-separate/duk_api_heap.c - - <_3:fileName>./config/config-options/DUK_USE_EXEC_PREFER_SIZE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1120"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-separate/duk_error_macros.c + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ca9e1a8f73c5dcbe2e8c45d25ce9865cd93866e6 - + + + + + ./config/config-options/DUK_USE_HOBJECT_ENTRY_MINGROW_ADD.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>fdaa275ec6abaafa7c812d61161c7edd78617926 + + + a3ebed7f54ca2678c040a4788af01e5ca665b1a7 - - <_3:fileName>./config/config-options/DUK_USE_DATE_PRS_STRPTIME.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./config/config-options/DUK_USE_HOBJECT_ARRAY_MINGROW_ADD.yaml + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1204"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>141b3f8ffdd7a510709d7bade109e970fc65b61c - + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./examples/debug-trans-dvalue/Makefile - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>e023af5c2fb4b1efab74a230c552f1eb1b37fc10 + + + 8d1131dd16033521735614833194563fdbd5608c - - <_3:fileName>./config/config-options/DUK_USE_AVOID_PLATFORM_FUNCPTRS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1022"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./config/feature-options/DUK_OPT_FUNCPTR_DEC16.yaml - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>34af4d8a5e26158d762ca27598c6278fcd572b4f - + + ./config/architectures/architecture_m68k.h.in + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2e03e3fa86f25b27b4ef6487fc55112eb3397170 + + + b55b06c60625f9553ff2b3240e9d4943af0c6266 - - <_3:fileName>./config/feature-options/DUK_OPT_DPRINT_COLORS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS482"/> + + + f8cdbc76655bf7892e3a1c1112035a14804b00b9 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9dec1b34df7a0d6773a1367000d7c27dd0894454 + + dc4e9b1ce4f040f46b6bb1c3ee14d60bdc4ceda0 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>36f51bfa3c9d50eedf7183315f08196d27e4f154 + + + 0811e545a133c3a62672e239624a0c1f11478b8d - - <_3:fileName>./examples/alloc-hybrid/duk_alloc_hybrid.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS82"/> + + ./src-input/SpecialCasing-8bit.txt + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f982055fcb3a2931e97d3ca184b471a4f4d3267b + + 09dcf5ba8d4145a177400296eee4aa13c579a65b + - - <_3:fileName>./src-input/duk_debug.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1670"/> - - - <_3:fileName>./config/config-options/DUK_USE_ROM_STRINGS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS984"/> + + ./config/platforms/platform_cygwin.h.in + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>523e4f8a77802ab002b00257f92d44f4a91e3a95 + + 9ff0ba5156be808917ab3ab9ac602107afa7814e + - - <_3:fileName>./config/config-options/DUK_USE_EXPLICIT_NULL_INIT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + ./config/feature-options/DUK_OPT_DEEP_C_STACK.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1014"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2ca9d977a128d217889ac2eb7ecb53f39847bd36 + + + 7067e460242aeaf79d594a5aa741344b2fa70c51 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>54e4cf1a4824acb67b8b0e8c0544f311821d84c4 - + + ./extras/README.rst + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./debugger/duk_debug.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./src-separate/duk_hthread.h + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS46"/> + + + - - <_3:fileName>./src-separate/duk_unicode_tables.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + ./config/config-options/DUK_USE_INJECT_HEAP_ALLOC_ERROR.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS310"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f0f13d25ed1255364447accef4d023dd8ed0bc3f + + 0838780a21e177fe67c3638a241c660c346d288a + - - <_3:fileName>./src-separate/duk_error_augment.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + + + ./config/feature-options/DUK_OPT_HAVE_CUSTOM_H.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS322"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>15ccd87ae7025ee6bc841eb2adb9077a1a83d73a - + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./examples/debug-trans-socket/README.rst + + + - - <_3:fileName>./config/feature-options/DUK_OPT_USER_INITJS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS522"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./config/config-options/DUK_USE_HTML_COMMENTS.yaml - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8c5296a4a041af04aae3ff2678d7c1ce82b1edcc + + + 3b8236810650f4e28bd84984b3c7e55029f241b0 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>46186f8bd845acc9cca22d6d74b4aa0fa97a8ea5 + + + a08e43879af86c86670dbbaa10af31e4ad8e5951 - - <_3:fileName>./src-noline/duk_source_meta.json - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS38"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>db4b6e4c8be849b5c0b0a84df9f1f0154d0c7708 + + + 29b4d0211a0878fb5fc07209bdc763e00bb6cd32 - - <_3:fileName>./licenses/commonjs.txt - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1762"/> + ./config/platforms/platform_generic.h.in - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>290a5e0940738c497792a9261b83ae349d8bfb19 - + + ./config/config-options/DUK_USE_POW_WORKAROUNDS.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4c30862a14c17d3e9f8621bdc001f4f1621dcd3e + + + 1b43b9e5d5a10e32acaf50fff25138f1077bc7fe - - <_3:fileName>./extras/minimal-printf/test.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1436"/> + + + + c3057ade4eeaeefbf2c59026cd6729b6a2882d3a - - <_3:fileName>./config/config-options/DUK_USE_PREFER_SIZE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1198"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2ff1dc97f0d2288ef8b0a55d4d8af383e8725426 - + ./src-separate/duk_numconv.c + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./src-separate/duk_api_time.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./config/architectures/architecture_sparc64.h.in + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS244"/> + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1a5eb6fdf1de5055e21fadf39a069384d3f04ae3 + + + 08f9536a60dfdb1b04b673b36b8d6eb067ba86b8 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>11a7a5b6b1557adeca8a9def51cb44282f24c853 + + + b9e1e8cb6f43dd1f3f63538b9819a5bd7cd7fa91 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1b789c31109dc1dbca88058996e8e8213cee9140 + + + 65e4fcd926433e482dfd99cf0a7a68c9cb993268 - - <_3:fileName>./src-separate/duk_bi_regexp.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_ALIGN_8.yaml + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS406"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c3b1b9c324cddb3526474584f4f35682220de7de - + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_HEX_FASTPATH.yaml + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>24f7bfa5a1caaf8b8f82d94641cc753712890e41 + + + fc75c97f35c16a8e964153c835ac36cda516fa04 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4e59c7b6e46e0ec47a84175bba68d6b47a5b1cc7 + + 3f55abd9ce2635fe2e20795f0356ccd72e2c3b99 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f828e5a5a88f63e033c8bb91587fd65f1a6463aa + + + 37c4b279336fdd9737f76e90603b89282f3c42d1 - - <_3:fileName>./config/architectures/architecture_sparc32.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS816"/> + + + ./config/config-options/DUK_USE_USER_DECLARE.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./src/duk_source_meta.json - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_VERBOSE_ERRORS.yaml + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1766"/> + - - <_3:fileName>./src-input/duk_api_object.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1656"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_PANIC_SEGFAULT.yaml - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>160be49b60f1ff1e125f0524859e86644ca5bf43 - + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-input/duk_bi_thread.c + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0b5596da17555ad475a5de16b88d18c183ab6d21 + + 65e7d20d354a69549d56b06560396e75f4c370e0 + - - <_3:fileName>./src-input/duk_tval.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1664"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9b316a4606c3b7c5938aa709b53a6972e9240711 + + bdb9243b436ef5c70967bddd16d0cc9e74971b1c + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a1b56bf89cc0b16cb33855a51a39ab655823fc9f + + + 4cd3c4b69a92040017526ff84efb1e468bc436fc - - <_3:fileName>./config/helper-snippets/DUK_F_BSD.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1392"/> + + ./src-input/duk_debug.h - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>867cac057ecaeed5a01fde135115bd295a78ffd8 - + + ./config/feature-options/DUK_OPT_HEAPPTR_DEC16.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - - <_3:fileName>./extras/module-node/test.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + ./config/config-options/DUK_USE_MATH_BUILTIN.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1462"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c9c65b1bc315afaaf70a219969ff3c95425ef628 - + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./config/config-options/DUK_USE_DEBUGGER_DUMPHEAP.yaml - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ba8248d12aa1af3bb74fade616001c0666a9129e + + a1f3d0f8f136ecba1278aac0bb7981c68cbdb12d + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>3e46bf32b8ec805112529a9eaeaed47618aff258 - + + + + ./src-input/duk_hobject.h + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/config-options/DUK_USE_HEX_FASTPATH.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1180"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_VALSTACK_UNSAFE.yaml - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a739735783e9ca0c43981fb9c8c5e3be06e94c1f - + + + + ./config/config-options/DUK_USE_NONSTD_SETTER_KEY_ARGUMENT.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>40b60f1a18a6352e7ebe2f681728ce297df2d710 - + + + ./src-separate/duk_js_call.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>50a0b4160ee66b3999dd614402a807a10f1fc853 - + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./config/feature-options/DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY.yaml + + + - - <_3:fileName>./config/config-options/DUK_USE_INTEGER_ME.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./src-input/duk_js_compiler.c - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS978"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>965499f07831f2cb69ad089d16ae8f9facffcaf0 + + 39be8f5a1b6bf1a3fed5e3e9228c5c5ed3a2e63d + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a821ac7ec988ca2327b7f45e93116b73b741f465 + + + 6d6a0ed935fc74ff5163e40366294a0f759501f2 - - <_3:fileName>./config/helper-snippets/DUK_F_SUPERH.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + + ./examples/cmdline/README.rst + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1334"/> + + ./src-input/duk_debug_fixedbuffer.c - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4d02f921b99409a38de077aca279f9513645cf88 + + + 4d343182d8c6106649c2c5bb6c839d22fb779012 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>064fc117cb63c3278067c9480d7276cb9b354fc5 + + + 918a17775b0ee1d2d294d12aec71fba07e2dedf9 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>38ceb89e840618ba30fa19731672f73f2c9ce7e8 + + 3842b780f5835861bb69008b2d6bc14c3e8b0969 + - - <_3:fileName>./config/config-options/DUK_USE_VERBOSE_ERRORS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1150"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./extras/alloc-pool/ptrcomp_fixup.h + + + - - <_3:fileName>./config/platforms/platform_tinspire.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS790"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_OCTAL_SUPPORT.yaml + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f9ea98185af04c0785a8ba19569c0715647709d2 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>80fa455402d3c9d0003aac90591ce218e3333cec - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b9cb2916325600c430473986730e566ab6718815 - - - - <_3:fileName>./config/config-options/DUK_USE_ES6.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1076"/> + + + ./config/header-snippets/reject_fast_math.h.in + - - <_3:fileName>./config/config-options/DUK_USE_PANIC_EXIT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS986"/> + + ./config/config-options/DUK_USE_NONSTD_ARRAY_MAP_TRAILER.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/config-options/DUK_USE_ES6_REGEXP_SYNTAX.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1080"/> + + ./src-separate/duk_js_arith.c + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c46260b8734e0db2e7c5a4a628c9fab0bc7b669a + + + 1c727e21ecd4e45f27b8cd9b673939889b55f10f - - <_3:fileName>./config/platforms/platform_orbis.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./examples/eventloop/server-socket-test.js + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS794"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/config-options/DUK_USE_UNION_INITIALIZERS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1270"/> + + + + 525e80da2b6d3640fd42af0f662d7b68865d6529 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0a53751e62b48704017c6839c5264927f0130880 + + 50a0b4160ee66b3999dd614402a807a10f1fc853 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>20b57462bc9bce779df71b35021e9ab7daa6fa95 + + + a44431c47ba58b63d41ad4cb3c6ccc549a892d48 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b1a1b5ac98f59ad44b382ce0767b3511d0a59292 + + + da39a3ee5e6b4b0d3255bfef95601890afd80709 - - <_3:fileName>./Makefile.eval - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS30"/> - - - <_3:fileName>./config/feature-options/DUK_OPT_NO_REGEXP_SUPPORT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS542"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8f9b5746882e630100ff2e6c7ee58ddc5d39c37a + + + 87801faec7afe7e24b542bacd2baf09afc3b386a - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ec867321b2655290d76d6640aca4bb638332ece4 - + + + + + + ./extras/alloc-pool/README.rst + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>23bb2a117ca989acb17aa740425dd46a020ccb6a + + + 276b3344cb3ec7e583a4aaac7d227fa072a5cfa9 - - <_3:fileName>./config/config-options/DUK_USE_DEEP_C_STACK.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_FINALIZER_SUPPORT.yaml + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1008"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a0e70baeeeb45ca74a0eb7312d6502530b8482ea + + + ac8a0949abd1320a5171b80fb15121726c5c88de - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>64839613434cb4c8d82ae07ea17933b448cf73f8 + + + b3aa4396aa5da8b8e81301fb7f27cdd8063d1e78 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>dafd4cd29ec8e228ab44be3c92e8ad7b8969fcde + + + 09285654f142f03129319e150339445f41721cee - - <_3:fileName>./config/feature-options/DUK_OPT_NO_OBJECT_ES6_SETPROTOTYPEOF.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS602"/> - - - <_3:fileName>./config/config-options/DUK_USE_OBJECT_BUILTIN.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1068"/> + + 2d02cef84737ac54c081dc18581e9e84f5bc7502 + + - - <_3:fileName>./config/config-options/DUK_USE_PACKED_TVAL_POSSIBLE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS866"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./debugger/duk_debugcommands.yaml + - - <_3:fileName>./src-separate/duk_hthread_alloc.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS368"/> + ./config/config-options/DUK_USE_DATE_TZO_GMTIME.yaml + + + - - <_3:fileName>./config/config-options/DUK_USE_ES6_UNICODE_ESCAPE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS954"/> + + ./extras/alloc-pool/test.c + - - <_3:fileName>./config/config-options/DUK_USE_SELF_TESTS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./src-input/duk_regexp_compiler.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1024"/> + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c9ba7a80e622c1b182f1683728f8154e876ecf0e + + 1c81542f71633b983d5fad3ca22ee54fa33c6589 + - - <_3:fileName>./config/config-options/DUK_USE_NONSTD_FUNC_STMT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1034"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b3ca8c4271d84ae7c27a7a8f739969a3581ba6b2 - + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_MARK_AND_SWEEP_RECLIMIT.yaml - - <_3:fileName>./src-separate/duk_api_bytecode.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS360"/> + + ./src-separate/duk_heap.h + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/config-options/DUK_USE_DDPRINT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS976"/> + + ./tools/dukutil.py + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/platforms/platform_qnx.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS802"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_EXEC_REGCONST_OPTIMIZE.yaml + - - <_3:fileName>./examples/debug-trans-socket/duk_trans_socket_unix.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + 51bdf2ab016c4f10193aedf5bd4fb8721156b75f + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-separate/duk_hbufobj_misc.c - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS170"/> + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>35269945cbb0f6d7168b069c19eadbd27afd6df3 + + d273268b97a6906abc4a1603691f0d888bdfb491 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f8cdbc76655bf7892e3a1c1112035a14804b00b9 + + f2805a6ce52407091fb7b145d0a81fcd5c84e513 + - - <_3:fileName>./Makefile.cmdline - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS18"/> - - - <_3:fileName>./src-separate/duk_heap_hashstring.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS384"/> + + ./src-input/duk_heaphdr.h + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ebe2924771df79f3fc41663c50e17688c95c5d08 + + + b768ecd4053b99f2e44223fe0893c64ecd98d15b - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>87f66c3811cafee84fcbde7e52119e40d25afb39 - + + + ./src-separate/duk_api_object.c + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>29b1960bc40607c2cf496465068611b2ffc4de87 + + 7f3e3c61f6a55853d54cd8753196c70155e22b35 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f483297f5b54759ea086884a18fcfb8e8d878eda + + + 1ea9739c4e914cc8100d7363c9f233f10babe734 - - <_3:fileName>./src-input/duk_heaphdr.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/compilers/compiler_emscripten.h.in + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1724"/> + + - - <_3:fileName>./examples/alloc-logging/duk_alloc_logging.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./config/feature-options/DUK_OPT_NO_MARK_AND_SWEEP.yaml + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS194"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + 49bb057bdaef78d25b9b1735faa05ad518f4ee6b + - - <_3:fileName>./src-separate/duk_tval.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS430"/> + + ./tools/scan_used_stridx_bidx.py + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/config-options/DUK_USE_OBJSIZES16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_JSON_ENC_RECLIMIT.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1296"/> - - <_3:fileName>./config/feature-options/DUK_OPT_HEAPPTR_ENC16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + 02157444f6e2db250d79a2012e1fc12fa1133361 + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS586"/> + ./config/config-options/DUK_USE_HOBJECT_LAYOUT_3.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c9b507a62367956d2c2f431c7cb07e7a1a7987ab + + + 1e1fd454558f0884153f735c187a3beedc7a44f0 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4caccabb685f620b904723e2c97aa2eae5096728 + + eba10f01290917065c4b29830f029f9edb9de618 + - - <_3:fileName>./config/config-options/DUK_USE_GET_RANDOM_DOUBLE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./config/helper-snippets/DUK_F_C99.h.in + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1264"/> - - <_3:fileName>./src-input/duk_debugger.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1722"/> + ./extras/module-node/test.c + + + - - <_3:fileName>./config/config-options/DUK_USE_REGEXP_CANON_WORKAROUND.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS968"/> + + + + 048c915047f148e35ceabc8bf4eafda0530e6e28 - - <_3:fileName>./tools/merge_debug_meta.py - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + 790f770697ad6a547e46cd410272710b3fc921aa + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_STRTAB_SHRINK_LIMIT.yaml + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1796"/> + + - - <_3:fileName>./src-separate/duk_util_bitencoder.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./src-separate/duk_selftest.h + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS396"/> + + + + 114aaaa03ae5f0749eb3227aa7f066e001746975 + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8348ebca89bdf8d42ea995bbb249f326257c823b + + + 973b149b368bdb1c7dd070fb15edd2669f2897a7 - - <_3:fileName>./examples/codepage-conv/duk_codepage_conv.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-input/duk_strings.h + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS94"/> + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>6b98824e13a3d9536542b8da51d012a3d66ceec1 - + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/platforms/platform_orbis.h.in - - <_3:fileName>./config/config-options/DUK_USE_HEAPPTR_ENC16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1306"/> + ./config/config-options/DUK_USE_ENCODING_BUILTINS.yaml + + + - - <_3:fileName>./config/config-options/DUK_USE_DEBUGGER_TRANSPORT_TORTURE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1312"/> + ./src/duk_source_meta.json - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>75b8e7c8e2f306c3c0aa83b79846f757acd83cf7 + + + 5d53f0e4d2c41c70c9891e530c16dac7354889ac - - <_3:fileName>./config/config-options/DUK_USE_PARANOID_ERRORS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS874"/> + + + + 09ee87b3ae8afe8b7c2295127835b05b00603b25 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>996b3e7433e52ccda2f968f8eb6afd50c6f47eb0 + + db1f3e76b30212cb07e32d85c585160bb3681407 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>85cc3ad49e0ebc536ca7efc917b4369bb8ab2586 + + + e5a5f0db067ec56c6d2f7356f412222a8884dc92 - - <_3:fileName>./examples/alloc-logging/duk_alloc_logging.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS190"/> + ./config/header-snippets/msvc_visibility.h.in + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./config/helper-snippets/DUK_F_AMIGAOS.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1326"/> + ./src-input/duk_unicode_support.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./src-input/duk_bi_symbol.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1516"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_DPRINT_COLORS.yaml - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>cba2de26d84acf9af3cc3950ce739864dd6e6307 + + b44e173d521416f444c72dad7ee63b7e8fc9b29f + - - <_3:fileName>./config/config-options/DUK_USE_DEBUGGER_PAUSE_UNCAUGHT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1168"/> + + + + ./src-separate/duk_hbuffer_ops.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/config-options/DUK_USE_DATE_GET_NOW.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1020"/> + + ./extras/print-alert/duk_print_alert.c + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>e36b278271ad5c367fde67e1dc637e7e5f1e1ca4 - + + + + + + + ./config/config-options/DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./licenses/xoroshiro128plus.txt - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_STRTAB_MAXSIZE.yaml + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1756"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4d343182d8c6106649c2c5bb6c839d22fb779012 - + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_PANIC_ABORT.yaml + + + - - <_3:fileName>./src-input/duk_api_time.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1536"/> + + ./tools/configure.py + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0cc625a8d72def6d789f26930691c72953954361 + + + 8483a2211d6323480efa605ee646959695b742c6 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9c2e1b603604fbd23d687377694fe8b66ff2af48 + + 149584de234020f72f4b5c5fa23357d351de1ab7 + - - <_3:fileName>./src-separate/duk_util_tinyrandom.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + f88d68880f451267e7e2eca4b6c4191e8c3fe011 + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS314"/> + + ./config/config-options/DUK_USE_SIGSETJMP.yaml + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ec4eb4acda5042e218ce3f3d68d34e2c83a0f9f9 - + + ./extras/module-duktape/README.rst + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>14808d03825d86bd0afc3e02fef2d2e09f8f460e + + 77e76c341a29fae1658f6417b59afc44af5519ca + - - <_3:fileName>./config/feature-options/DUK_OPT_NO_PC2LINE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS518"/> + + + 3cf73c037e331b0eaf9bfa6846ecd316ec9cf354 + - - <_3:fileName>./src-separate/duk_util.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS232"/> + + ./src-input/duk_hobject_enum.c + - - <_3:fileName>./src-input/UnicodeData-8bit.txt - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1696"/> + + + ./config/config-options/DUK_USE_GLOBAL_BINDING.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>6a7baa773a719cbc5770f77b5b2faf46579f7095 + + + d9de9120af7009133f55d1f9844f1e64d74a13d4 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>90362a2493de41a41ed705c3f286356db9020008 + + + 33c7608ed956874d642dd81d3b2f7584e6878a72 - - <_3:fileName>./src-separate/duk_api_internal.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS294"/> - - - <_3:fileName>./src-separate/duk_hobject_finalizer.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS242"/> + + ./src-separate/duk_js_compiler.h + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>07a167411a356aebfbe987353846a9c711998f20 + + + 3c6d9c22cfc8850cb8a4ebb5169a9f8eb570132d - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0674047084209a5024e62499bd0593c894167295 + + + 02e3abb683294bb7adbe8fb4698186645a06da8d - - <_3:fileName>./config/config-options/DUK_USE_INTERRUPT_COUNTER.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./src-input/duk_js_arith.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1240"/> + - - <_3:fileName>./src-input/duk_bi_buffer.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + 43c04714a43d22d81a4b4b698daaf00bb865b9b2 + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1630"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-input/duk_hbuffer.h - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ceaa461d035b4428a0165cd432eea13f664e05d0 + + 9f7f3a805998f9625d68896a24f15a24d14896d7 + - - <_3:fileName>./config/feature-options/DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS620"/> + + ./config/config-options/DUK_USE_FLEX_ZEROSIZE.yaml + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>aa8fc5e5443a5aa1c2c3a49c929bc2678652255e + + + ada872547e2bed31a1c7db446728495b7f52079a - - <_3:fileName>./config/config-options/DUK_USE_REPL_ISINF.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS940"/> + + + ./src-separate/duk_error_augment.c + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/feature-options/DUK_OPT_EXTSTR_FREE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS528"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-input/duk_hobject_misc.c + + + + + + + + a304f1306843bc83c1180bf9411393a0d757ba67 - - <_3:fileName>./config/config-options/DUK_USE_FAST_REFCOUNT_DEFAULT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS994"/> + + ./src-input/duk_tval.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/helper-snippets/DUK_F_WINDOWS.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./src-noline/duktape.h + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1368"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>cfc3b322f9816eaf5ac73401afe5cc2cff96c1fe + + + 6340182b4d5fab0dc7ef741980286cb054abec6c - - <_3:fileName>./config/helper-snippets/DUK_F_SUN.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1384"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./config/examples/disable_es6.yaml + + - - <_3:fileName>./config/helper-snippets/DUK_F_APPLE.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + ./tools/duk_meta_to_strarray.py + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1366"/> - - <_3:fileName>./config/config-options/DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1092"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f5a7345704be5f9b2a775b7153447ad7c27f047e + + + c67a9e99a6d31a57e400e21b9cf282ade5506a0d - - <_3:fileName>./extras/module-node/Makefile - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1460"/> + + ./src-separate/duk_unicode_tables.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>6948cdc8e0862da8d114d21ff174af187aa63219 + + 9babdc4300dc79498f1d2bce3935f70c7666827e + - - <_3:fileName>./config/feature-options/DUK_OPT_STRICT_UTF8_SOURCE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS514"/> + ./tools/genconfig.py + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>fc4228517dd74be6e897e70a093d2ea1e61a353a + + + 059005bfb13d446c8f3395f0662c6e35a8fb9548 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8c23d8568a42ac3a5aeefb138396a29d69186569 + + + b694667912aa266b15478aec08fb4ffd43f287e0 - - <_3:fileName>./config/feature-options/DUK_OPT_DLL_BUILD.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS658"/> + + 098248571205603dcd74f158406faac5c1e9e4db + + - - <_3:fileName>./config/config-options/DUK_USE_BUFLEN16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + ./src-input/duk_api_inspect.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS988"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>54da1fbed3ce3f7150639cafa7c66164891bd6da + + + 51bdf2ab016c4f10193aedf5bd4fb8721156b75f - - <_3:fileName>./extras/duk-v1-compat/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1406"/> + + ./src-separate/duk_hthread_stacks.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>fb2406b05571014ed4365f8662890707cddd5665 + + + 73df7932ee7d6a5e492c5d2ff80fb34fee34bf8a - - <_3:fileName>./config/config-options/DUK_USE_NATIVE_CALL_RECLIMIT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + ./extras/alloc-pool/duk_alloc_pool.h + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1224"/> - - <_3:fileName>./extras/print-alert/test.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./tools/prepare_unicode_data.py + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1474"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f830b9571e52a1943907b7ab83b31d19841a2e31 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d53085a45e5f62dc5b3dca1f9f1e1bdb305fd5bc - + + + + ./config/helper-snippets/DUK_F_BCC.h.in + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f8e4195b4b2ada6059072839c62fb73d2354019c + + + be4dc9ca69b47904b70cac8355b94555444466d1 - - <_3:fileName>./examples/debug-trans-socket/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/platforms/platform_solaris.h.in - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS174"/> + + + + - - <_3:fileName>./src-separate/duk_strings.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS412"/> + + ./src-input/duk_hobject_class.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/config-options/DUK_USE_DEBUGGER_FWD_PRINTALERT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_HEAPPTR_ENC16.yaml + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1040"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2e1c07e87002953c494e3e3424aa3a4c986960d0 + + + 0e590fee39698aec4b1dbfbbcfe311f2d96ee795 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>dfbbd8bc95a46f832c67ebf680b0c9b0888f6245 + + 4f937b155a7bd79f7c97c8a7aac206521ddd0188 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>01138dd2786346a159c06e43f094d07f002df881 + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./config/helper-snippets/DUK_F_BSD.h.in + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./config/config-options/DUK_USE_COMPUTED_INFINITY.yaml + + + + + f3d5a9f7971ae436b0fd90b516eb55ebc8f239c4 - - <_3:fileName>./config/header-snippets/packed_tval_fillin.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + 1b9505297d7bf88af1a1a2f37d1a47833ceb06ae + + + ./examples/guide/process.js + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS732"/> + - - <_3:fileName>./polyfills/object-assign.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_GET_RANDOM_DOUBLE.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS462"/> + + + - - <_3:fileName>./config/config-options/DUK_USE_STRING_BUILTIN.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1026"/> + + + ./tools/combine_src.py - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>257e1fb388d7c2df6f633d629c2d9f665ce1bf60 - + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + ./src-separate/duk_config.h - - <_3:fileName>./src-separate/duk_bi_protos.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS306"/> + ./src-input/duk_hthread_misc.c + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a5b9b0e4e9cf985ce67bf6c342b193b363ae2357 + + ./config/header-snippets/platform_fillins.h.in + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + + + 74a734b4fbba511d2fbf80d360ff6bd5302ebad7 + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_NONSTD_GETTER_KEY_ARGUMENT.yaml + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4a1c5e238c44e75ac93bfb1edcdcde2f26954b5b + + + + + ./config/feature-options/DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + 537ba4f022e66f5d4e010a8e371fa92544b665dc - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>e7390a8f9b29a5ee991f33d6a7dc5b291b2f5141 + + + 2d1d9cf996f6ad45bd65d4f9f135e3f3381de575 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a62e44c8b763e455366b0caae3aff14abfc4569a + + + ac3e136b155d9b77eeaa3c8255f35d13efd3ecfa - - <_3:fileName>./src-separate/duk_util_bitdecoder.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + ./src-input/duk_forwdecl.h + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS292"/> + + + + + + + a649e32bea73f77a7decfc83d465dd2ef9a47794 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>5b7481802027177b572aed1f9522cdff9578bae7 + + + e49e602097809b43d2716c5010bc521a00fe831a - - <_3:fileName>./config/architectures/architecture_generic.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS830"/> + + + + ./src-input/duk_bi_pointer.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/config-options/DUK_USE_BOOLEAN_BUILTIN.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS854"/> + + ./config/feature-options/DUK_OPT_NO_VOLUNTARY_GC.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>421be368f817cc0374cab55f6c62a1ab6e30c02b + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_ARRAY_BUILTIN.yaml + + + + + + + c3b5e005ebb6854c0fc17ad6c8ad915f725fa091 - - <_3:fileName>./src-separate/duk_internal.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS328"/> + ./src-input/duk_hnatfunc.h + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/config-options/DUK_USE_ARRAY_BUILTIN.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1286"/> + + + + 180ddee3e437f0caee5fe06aa9cb427455318d2a - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f68b056e907f117d869d5ee9c8016427e8f7d088 + + e8ae9fdde226f75d6f6bad2d9e2746f59e451d01 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>e5cc9b34109a953f0535a7d709b20be822f29827 + + ./examples/eventloop/README.rst + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + 1a64e0946145a92e1620fb5cfee75a3a9d2956d2 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>75c61dd080cd643b7449f673105b7b7e4bdda0f5 + + + 4db06fd9d96853165d9c5bb92d722ee87649081a - - <_3:fileName>./Makefile.dukdebug - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./examples/cpp-exceptions/cpp_exceptions.cpp - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS28"/> + + + + + + + fdaa275ec6abaafa7c812d61161c7edd78617926 - - <_3:fileName>./config/feature-options/DUK_OPT_NO_SOURCE_NONBMP.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS576"/> + + + ./config/header-snippets/types_legacy.h.in + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4044e8c57705c4e466130586954c05d972818406 + + 23cf8b40dbb8e07a2e4ad7333aa4db6756ca8242 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f2e0d93394d0f353e42af9dbdfbb043b1c462ae4 + + + + + ./src-separate/duk_hstring.h + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + fb2406b05571014ed4365f8662890707cddd5665 - - <_3:fileName>./src-separate/duktape.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + + ./src-separate/duk_replacements.c - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS438"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4db4ca2d7ce3f076fd195372d53e8bc5714d2597 + + + dc2dfcb611a83e35facfc52ec3b1ff307eb271c2 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>272265025f87ee803a2f4ee2f9711083ac1f5da7 - + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./config/architectures/architecture_mips32.h.in - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0952e4605da61d7296cb65c709dca67b5646d68e + + e0d4ca493223bebff11d87460121b0825f5d9242 + - - <_3:fileName>./config/feature-options/DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + ./examples/alloc-logging/log2gnuplot.py + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS570"/> - - <_3:fileName>./config/config-options/DUK_USE_DATE_PARSE_STRING.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_NONSTD_FUNC_CALLER_PROPERTY.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS848"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>059005bfb13d446c8f3395f0662c6e35a8fb9548 - + + ./Makefile.eval + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9da72a89b2c26a4073408299b29a74d8e8e0effd - + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-input/duk_js_executor.c - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9893700d76a15b9d9401eca1eb0a40a34933c0b4 - + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + ./config/helper-snippets/DUK_F_OPENBSD.h.in - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>eccb7f16db67b963a86050dcc3d4f56ff97d9414 + + + 0f9c171bc34b70d3e2a6ccdefbf9983ef40731b3 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bd3d0e5ba2b68864d8bde1f91e6310c04d56224e + + + 2ce8a3541834f4fe53f39191265370670300812a - - <_3:fileName>./examples/eventloop/curses-timers.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + ./config/feature-options/DUK_OPT_DEBUG_BUFSIZE.yaml + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS116"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bdb9103f1104e1295f3aac026dfc46919b0ee63b + + + 7054031543b78b05ce4dbb8beb15e4bfda8ae282 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>654592b896f142417be178b910cf35beb0c8dcf3 + + + 0baab0a0e3693ec40811e6bed6f34e23f9fceea3 + + + + ./config/config-options/DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - - <_3:fileName>./extras/console/Makefile - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1422"/> + + ./src-separate/duk_api_memory.c - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a44431c47ba58b63d41ad4cb3c6ccc549a892d48 + + + 539fc3e53e1a392c4d54968f8e4e90bc49a736d9 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a304f1306843bc83c1180bf9411393a0d757ba67 + + + a8cd1862fa60306cb9570def08974137866c09fb - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4d562b6ab95fd3b5c536db49ca78ce3000be0c0e + + 9678a4365925b40c96c3626c39b790c0574533dd + - - <_3:fileName>./examples/alloc-torture/duk_alloc_torture.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + 0e2c0f34a387336aed77a3dd3f67ebe3f527ccb5 + + + + + ./config/config-options/DUK_USE_BASE64_FASTPATH.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS156"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>6a7baa773a719cbc5770f77b5b2faf46579f7095 + + 024cd43cdffd9101905babfce42500e78fb46dba + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>099a3237525b972082568a8aefcbb4264b3d47ba + + + 29b1960bc40607c2cf496465068611b2ffc4de87 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c8c8034feefe02c4c453c33b95be3056e4ced520 + + + 633bb3732a4d6593bd0102b927430d7f6bedc2eb - - <_3:fileName>./config/config-options/DUK_USE_DATE_NOW_TIME.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1052"/> + + + + ab62f0df98070e3087a0fb8b2824e81f5e246fd8 - - <_3:fileName>./src-input/duk_api_stack.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + 8fa3e2ce8d44a9946c535cdbb411e66ab865e8b0 + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1738"/> + ./config/feature-options/DUK_OPT_NO_JC.yaml + - - <_3:fileName>./config/feature-options/DUK_OPT_NO_MARK_AND_SWEEP.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS540"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_JSON_BUILTIN.yaml + - - <_3:fileName>./config/other-defines/c_types.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-input/duk_hstring_misc.c + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS808"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>094eb07738bc769a2f096e01d7de5deb7ed1bf7f - + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/feature-options/DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT.yaml + - - <_3:fileName>./src-separate/duk_bi_json.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./src-input/duk_heap.h + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS300"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/header-snippets/types.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS758"/> + + ./config/config-options/DUK_USE_PANIC_HANDLER.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>fa85ee3394206d18c611b837e700257ba8336250 - + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./src-input/duk_unicode.h - - <_3:fileName>./config/header-snippets/date_provider.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./config/config-options/DUK_USE_COMPILER_STRING.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS756"/> + + + - - <_3:fileName>./examples/sandbox/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS188"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/feature-options/DUK_OPT_STRTAB_CHAIN_SIZE.yaml - - <_3:fileName>./config/config-options/DUK_USE_PANIC_ABORT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_FUNCPTR_ENC16.yaml + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS934"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b3f724fbb8bb68408ab3050e12f8e99e98994847 + + 2da49f0d383feb4e2862bde546acde9bbc010057 + - - <_3:fileName>./src-separate/duk_exception.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS312"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-input/duk_bi_object.c - - <_3:fileName>./config/examples/enable_debug_print2.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS710"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./examples/debug-trans-dvalue/duk_trans_dvalue.h - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>3237996b63a91f77d8e28a1fd95cee3581653843 - + + + + + + ./config/config-options/DUK_USE_REFLECT_BUILTIN.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>17e392f86eeef77b2a608f66b14a4c9354bd5f83 + + + 5ffa5691c16dbc417e047d80f538d9593850bfd7 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>edb22a7fd3e25c2db7f4fd6766ce0703768f9c45 + + + edb22a7fd3e25c2db7f4fd6766ce0703768f9c45 - - <_3:fileName>./src-input/duk_heap.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1556"/> + + + ./src-separate/duk_js_var.c - - <_3:fileName>./tools/create_spdx_license.py - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + ./config/config-options/DUK_USE_DEBUG_LEVEL.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1802"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./src-separate/duk_error_throw.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./src-separate/duk_tval.h + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS200"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4f34bac3654432817f59e5853e7ae149af14d225 - - - - <_3:fileName>./polyfills/duktape-error-setter-nonwritable.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS454"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>cd55d15de8e1e2629edb637d2704a61974542a0b - - - - <_3:fileName>./extras/console/duk_console.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1426"/> + + + ./config/architectures/architecture_superh.h.in + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8eb48fb0706391e81cd9edbeb52c9bfd7848e951 + + + c83d0559f42fc713df412f8e21549e2a7e74074a - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c3e7c28498f09d3f9bdfc2006952df17a51184e5 + + + 140631b8d425914215232ba351987dbc0884c3b8 - - <_3:fileName>./config/feature-options/DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS628"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./config/feature-options/DUK_OPT_SEGFAULT_ON_PANIC.yaml + - - <_3:fileName>./extras/print-alert/Makefile - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src/duk_config.h - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1470"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>215f6fec820889330048f7f2c1b5a220eb963657 - + + ./examples/sandbox/sandbox.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - - <_3:fileName>./config/config-options/DUK_USE_DATE_GET_LOCAL_TZOFFSET.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./src-separate/duk_bi_pointer.c - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS982"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./licenses/murmurhash2.txt - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1758"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER.yaml + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b694667912aa266b15478aec08fb4ffd43f287e0 + + a3696b013eb47462214bc91568c2ab006c985558 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8b33e4aa64c09d33721bda1113dd7b6d418fe444 + + 7edf7600e1a6f09d1e4a0e2f9be418b59fff7c52 + - - <_3:fileName>./src-separate/duk_heap_markandsweep.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS344"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-input/duk_hcompfunc.h - - <_3:fileName>./src-separate/duk_regexp_compiler.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS380"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/feature-options/DUK_OPT_NO_PC2LINE.yaml - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>38ac8f6fca8cc656ae35e420ac89d0d05814ddf1 - + + ./src-noline/duktape.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + + + + + ./src-input/duk_harray.h + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./src-separate/duk_debugger.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + + + ./config/header-snippets/types_c99.h.in + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS398"/> - - <_3:fileName>./config/helper-snippets/DUK_F_M68K.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + 918a17775b0ee1d2d294d12aec71fba07e2dedf9 + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1348"/> + ./config/feature-options/DUK_OPT_NO_COMMONJS_MODULES.yaml + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>be0c1ed61c84fd83b156eb80bfc11c44b3d18d9c + + dd07e72d680a378b1ecd916611c888013051d1bd + - - <_3:fileName>./tools/configure.py - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./polyfills/global.js + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1788"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>548110e8be09c682e67929b3f270a6a480b30294 + + + f3ed5c785b60b0f39a74cc3f5b73b0c6e24287c3 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4b7b9d8d4cb87befce317fdc38e96f40e13cdd05 + + + 2ca9d977a128d217889ac2eb7ecb53f39847bd36 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0e120595fb9cf6b883f3a408c157403eae5d7468 + + 83d0fa93dad6434dadd19996cc41d11259404662 + - - <_3:fileName>./src-input/duk_error_augment.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/examples/compliance.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1618"/> + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4a1d9dd409a812bc2ffe481a94bd18ff0edeaec9 + + + 9aedb54b5598cfb1fabc7e96e28237a1ab710cc0 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>65e4fcd926433e482dfd99cf0a7a68c9cb993268 + + 6275e937886be08832b263510e5b910f4fdfb59e + - - <_3:fileName>./config/config-options/DUK_USE_REFERENCE_COUNTING.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1094"/> + + + a1336b3e2f152ce109dbae911c57312101dfd5bf + - - <_3:fileName>./config/config-options/DUK_USE_PACK_CLANG_ATTR.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1142"/> + + + bb4315b6b2a1e903a696ebcc550dd278e208f6ee + - - <_3:fileName>./extras/duk-v1-compat/test.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1414"/> + + ./extras/console/README.rst + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d0a31fca003e3028fe0d029906f65053634837c5 + + + 884bb62571381479dd69caad82eb6523b45aec70 - - <_3:fileName>./config/feature-options/DUK_OPT_DDDPRINT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS496"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_MATH_FMAX.yaml - - <_3:fileName>./src-input/duk_strings.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1716"/> + + + + a63af7be25d2ec188d4b49ff94f62f4dd7937349 - - <_3:fileName>./licenses/lua.txt - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1760"/> + + + ec867321b2655290d76d6640aca4bb638332ece4 + - - <_3:fileName>./src-separate/duk_hobject_props.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS254"/> + + + 4c30862a14c17d3e9f8621bdc001f4f1621dcd3e + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>78a78b9ca07b9288621ccc098650870f566eaa92 + + + 0dc11f5c2a5a84347a724e86ddd6ca78746c5a07 - - <_3:fileName>./extras/print-alert/duk_print_alert.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + 1ea9739c4e914cc8100d7363c9f233f10babe734 + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_MATH_ROUND.yaml + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1472"/> + + + + c07b0673b25fd4fec942bb781279563ef7856837 + + - - <_3:fileName>./src-input/duk_hstring.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1584"/> + + + + ./config/architectures.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./Makefile.codepage - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + 19cfacc0e9bd5c8a846c7d18a423130a9660f622 + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./config/feature-options/DUK_OPT_NO_BROWSER_LIKE.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS22"/> + - - <_3:fileName>./config/config-options/DUK_USE_FUNCPTR16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1276"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./examples/eventloop/poll.c + + + + + 512de805b6311b702ad2b1c143e24747a896c5fa + - - <_3:fileName>./examples/codepage-conv/duk_codepage_conv.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + + + ./src-input/duk_heap_finalize.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS90"/> - - <_3:fileName>./config/config-options/DUK_USE_ES6_OBJECT_SETPROTOTYPEOF.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1176"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./config/helper-snippets/DUK_F_CPP11.h.in - - <_3:fileName>./src-input/duk_hobject_enum.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./config/config-options/DUK_USE_MS_STRINGTABLE_RESIZE.yaml + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1510"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>58f8147365c2618f8a718b5f3bfb6070b2429a96 + + + 20b57462bc9bce779df71b35021e9ab7daa6fa95 - - <_3:fileName>./tools/genbuiltins.py - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1800"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>45ef2fedf1972cda257b186df63dfc223dbd0f54 + + + ed4b2d40f4406368eb62ba8a5ea81eb3a2635986 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>832543d9949cf7ca5791e704e39e7837d93cd4c9 + + 49a0495ca06511f8f85caa5a9441d77b5b74f87b + - - <_3:fileName>./config/config-options/DUK_USE_JSON_EATWHITE_FASTPATH.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1172"/> + + bd26962a105f83f1e4df97454ac7fdc01ed2454a + + - - <_3:fileName>./src/duk_config.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1768"/> + + + ./config/config-options/DUK_USE_JC.yaml + - - <_3:fileName>./tools/resolve_combined_lineno.py - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1790"/> + + + + 87b1de3429de499a85dad75b2d0297461a87c523 - - <_3:fileName>./src-input/duk_error_misc.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1644"/> + + + + 8f9b5746882e630100ff2e6c7ee58ddc5d39c37a - - <_3:fileName>./config/feature-options/DUK_OPT_SHUFFLE_TORTURE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + ./config/config-options/DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS526"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>239f16cf83e73eeeb0c54000a3d739b873fd6483 + + + 4242d16a8a93277a92cb303c19dc0035b64fb9f2 - - <_3:fileName>./config/config-options/DUK_USE_REPL_SIGNBIT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./src-input/duk_hobject_alloc.c - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS950"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4c9dbfd33b5e0e7c8d04d78ac0e3fa18b19c8caf + + + 9d97cd24eba146d098b88505afb3e9d9c71fb05a - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1cb67a46fec2d198b68c1faeaff801c5e0b8d56f + + + bdd92a8da86a7c626d98f86a7f41ffac27635806 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d030fd37b72538190aa765588d54fb32f788a7a0 - + + + + + + + ./src/duktape.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9c2e1b603604fbd23d687377694fe8b66ff2af48 + + aa39823cbb0e62aeba077a6e9510d0906a195bf2 + - - <_3:fileName>./config/header-snippets/byteorder_fillin.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./config/config-options/DUK_USE_BRANCH_HINTS.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS742"/> - - <_3:fileName>./src-separate/duk_api_debug.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + ./config/config-options/DUK_USE_STRTAB_CHAIN_SIZE.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS220"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./src-input/duk_js_ops.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + ./src-separate/duk_bi_json.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1732"/> + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>666f157dda4c3d1dea5ffbc7be7c5abb343481e4 + + f13d6c338e5f33e8302ddb872c9130d8c3fdd3b5 + - - <_3:fileName>./config/feature-options/DUK_OPT_PANIC_HANDLER.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS652"/> + + + + b918661de386fc9df8cabc20607ceba9eeb4ee34 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0e4fd82c8f6a18bfef5fede40307ed460b7212c7 + + ff804968ca8e7dd6e415126c35569127cb4a0725 + - - <_3:fileName>./config/feature-options/DUK_OPT_NO_ZERO_BUFFER_DATA.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS548"/> + + ./config/helper-snippets/DUK_F_CPP.h.in - - <_3:fileName>./config/config-options/DUK_USE_DATE_TZO_GMTIME.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1104"/> + + + + 511ed2315fcdf89b37ae5a44ecb9bb63f978889f - - <_3:fileName>./config/config-options/DUK_USE_BUFFEROBJECT_SUPPORT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./AUTHORS.rst + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS946"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ba01693a576afdd00bbddf3bb3b558d89a132137 + + + 094eb07738bc769a2f096e01d7de5deb7ed1bf7f - - <_3:fileName>./config/feature-options/DUK_OPT_NO_MS_STRINGTABLE_RESIZE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS640"/> + + fa12651d5b9bea4efd87fd7448051f0903647c4c + + - - <_3:fileName>./examples/eventloop/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS110"/> + + + ./config/feature-options/DUK_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/feature-options/DUK_OPT_LIGHTFUNC_BUILTINS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS536"/> + + d4456e3a8ac7f027af7db2b4557b0be535a26fb3 + + - - <_3:fileName>./config/feature-options/DUK_OPT_STRTAB_CHAIN_SIZE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS598"/> + + + cdf7e844cd74b4d0277a3c54ef4f98e5029443b2 + - - <_3:fileName>./config/config-options/DUK_USE_FUNCPTR_ENC16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + 90a82bf9ef21b2d0517a3bc4fa47a39a24d833da + + + + + ./config/examples/performance_sensitive.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1268"/> - - <_3:fileName>./config/feature-options/DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + + ./config/config-options/DUK_USE_INTERRUPT_DEBUG_FIXUP.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS668"/> - - <_3:fileName>./src-input/duk_bi_function.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + ./src-input/duk_api_heap.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1520"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9657c366438093bdd2a8db606da8ce982663ada9 + + + 257e1fb388d7c2df6f633d629c2d9f665ce1bf60 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>62385dce58219430c29e6970576a1d04ea0fe7b7 + + + e6236308ecd830a057e1f31cb3468cf36c6b25d7 - - <_3:fileName>./config/config-options/DUK_USE_JC.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1214"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4239a907720cf3620bd0b03eb43981e7182e305a + + + c5312406e1bef117c7264595e4ecb0b841f0f389 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>43c04714a43d22d81a4b4b698daaf00bb865b9b2 + + 65116139ca353060adb8109691eef6f2c36cbeea + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>62c3607437a8e017102ba2805a9d02b6ef237c8a + + 7fa8741e58cd98f607f5094f3fb190662d03b48a + - - <_3:fileName>./config/feature-options/DUK_OPT_INTERRUPT_COUNTER.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS500"/> + + + + b1a1b5ac98f59ad44b382ce0767b3511d0a59292 - - <_3:fileName>./config/header-snippets/object_layout.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS734"/> + + + fc4228517dd74be6e897e70a093d2ea1e61a353a + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>537ba4f022e66f5d4e010a8e371fa92544b665dc + + + bd1beb68239b1a4224f5224aa6b17b1ca8c8bff3 - - <_3:fileName>./config/config-options/DUK_USE_HOBJECT_HASH_PART.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./config/config-options/DUK_USE_BYTECODE_DUMP_SUPPORT.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS958"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/config-options/DUK_USE_FUNC_NAME_PROPERTY.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1102"/> + ./src-separate/duk_debugger.c - - <_3:fileName>./config/config-options/DUK_USE_VALSTACK_UNSAFE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS952"/> + + + + dcf77d110c1826159576dfc92cc2996cf4bd0439 - - <_3:fileName>./src-input/duk_hthread_stacks.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1622"/> + ./src-separate/duk_hbufobj.h + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>37b1eed3bc692611b9607a3dd3fa262b7b0c3160 + + 7216d147f8036390c8b6b2e32daa9cf30c5432fb + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>73df7932ee7d6a5e492c5d2ff80fb34fee34bf8a + + + 9f082261795edaca184c141605e84fc8a96ac81d - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2386d0f8016a13bce8cfad15d3ac2e515af18d9d - + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./config/header-snippets/64bitops.h.in + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2b89124b62a51daeab2e8d84395dd83337c28ec2 - + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./config/helper-snippets/DUK_F_ULL_CONSTS.h.in + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>422a4cc945db929af74e7ea09145b5be5aeedf5b - + + + ./src-input/duk_hthread_stacks.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0c192f3df7ed956fb60437fc98b7c933d3673255 + + be0c1ed61c84fd83b156eb80bfc11c44b3d18d9c + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>33e70456ec777298bd211e85275d27e71c95c878 + + + + ./src-separate/duk_heap_refcount.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + d273b0e72994792e9c30e2a77a2495040e896e53 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2df5c51b4a62d1aa3d9573c9005c71d839cbee19 + + f1c6b0f6e8a9bd67a11a58f0569f3e06afa69e33 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a0a83407e2df1feec48016a43cb7727789c05b5d + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./config/config-options/DUK_USE_HOBJECT_LAYOUT_1.yaml + + + + e4f8a99fc1f5e2898f35b2e94fbd0d1ba4928490 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2a55284f755fd8367399510daa3570a93203d6ff + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./debugger/duk_debugerrors.yaml + + + + + + fd51ec0049e1ce34f0afc9c01a8206cd6072cdf7 + - - <_3:fileName>./src-input/duk_error_longjmp.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1580"/> + + + ./config/feature-options/DUK_OPT_NO_OCTAL_SUPPORT.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1f3860956ae1463e3c886d9d0efaf69ca56805de + + + 3e46bf32b8ec805112529a9eaeaed47618aff258 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>92b4247db4a86ec02abf980160bd0a0675e8de82 + + 73a7e14185a2bcfa868083ddd7be4806b111fbfd + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>66bd2a379a8bfbc380d816c2395a94b011a5d2ee + + + 1b2f94db2f25c172b821edcc546ee6b90cc98b97 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>23cf8b40dbb8e07a2e4ad7333aa4db6756ca8242 + + + 1fcf367a04cc09f979e97f25fffe9d6b9959b5c5 - - <_3:fileName>./src-input/duk_heap_alloc.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + ./config/config-options/DUK_USE_INTEGER_LE.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1694"/> + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>6e2af71ada62c408d30381e5330c4369aff3bae4 - + + ./extras/module-node/Makefile + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>206ffd13c06208e85baba2b257fe3ddebb56a6c2 + + ./licenses/xoroshiro128plus.txt + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + 2cf1bf8b74928280d733ff125306324cde1dafdf + - - <_3:fileName>./config/feature-options/DUK_OPT_OBJSIZES16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS648"/> + ./config/config-options/DUK_USE_NATIVE_CALL_RECLIMIT.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/feature-options/DUK_OPT_STRHASH16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS654"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./examples/alloc-torture/duk_alloc_torture.h + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a3696b013eb47462214bc91568c2ab006c985558 + + + 6a1500fea27ea278c4f0c64d908e16cc60df684b - - <_3:fileName>./src-input/duk_js_compiler.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/helper-snippets/DUK_F_UCLIBC.h.in - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1532"/> + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>10bb35bc195325b56271971f1b12640a7bde4d2d - + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_DEBUGGER_FWD_LOGGING.yaml + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>27bd858100fa17bbb03f741eae0fd3aad9a1f310 + + bdb9103f1104e1295f3aac026dfc46919b0ee63b + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4091a3a23fe8d47432e6c6fe73d27590e31ce214 - + + + + + ./extras/duk-v1-compat/test.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>268d0dab85b69247ce036eaa197728702d290845 + + 2b9167f66a35d1e5ea97fc23ec4ecae4782f0e7d + - - <_3:fileName>./src-input/duk_debugger.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1700"/> + ./config/config-options/DUK_USE_HEAPPTR_DEC16.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>618cdd1d0eb4b358610fe893bae4b62abc233e32 + + + 6348fc1ff60cc7ae12474faa6fe6598ba8b0b6d7 - - <_3:fileName>./config/compilers/compiler_vbcc.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./debugger/duk_debug.js + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS686"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0b73d63799058538ad46235ddc07b04e4caa0919 - + + + ./config/config-options/DUK_USE_DATAPTR_ENC16.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./src-separate/duk_util_hashprime.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./config/feature-options/DUK_OPT_FUNCPTR_ENC16.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS318"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f396c6aec456b183ef77e33da1dfffc89c417056 + + + 97f183cd870ccdfcd5335c6c8a2cf4ce6bd79345 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>37b1eed3bc692611b9607a3dd3fa262b7b0c3160 + + a5a476d653ecaa3b94218ad646065fb949e8d62d + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7a4fc9dbd0f9085a75d0482bc8748b203ec9c2fd + + + a95a05ffc93c119e6feee16cb01d0ccd1a6df091 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>16baa211354a6f11b421d22e13c852c9c7748a31 - + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./config/tags.yaml + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./extras/logging/Makefile + + - - <_3:fileName>./src-input/duk_bi_encoding.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1540"/> + + + + ./src-separate/duk_bi_date_windows.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d791ee30f44f9b4960a7f03ab5dc9e4b6e8e2536 + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./src-input/duk_internal.h + + + + + a44f7292247d00bd4f2a0f234cf96bc51573081f - - <_3:fileName>./src-input/duk_util_hashprime.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + ./config/config-options/DUK_USE_OBJSIZES16.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1614"/> + - - <_3:fileName>./config/config-options/DUK_USE_32BIT_PTRS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./config/config-options/DUK_USE_ROM_GLOBAL_CLONE.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1248"/> + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/config-options/DUK_USE_DEBUG_LEVEL.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1064"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-separate/duk_bi_protos.h - - <_3:fileName>./config/feature-options/DUK_OPT_EXTSTR_INTERN_CHECK.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS562"/> + + ./polyfills/duktape-buffer.js + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>36f51bfa3c9d50eedf7183315f08196d27e4f154 + + + f0a2c3d666e7225d386d1ac280742d46c82cf5ad - - <_3:fileName>./config/feature-options/DUK_OPT_DEBUGGER_SUPPORT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-separate/duk_hthread_alloc.c + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS624"/> - - <_3:fileName>./config/config-options/DUK_USE_64BIT_OPS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1152"/> + + ./config/config-options/DUK_USE_ALIGN_4.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f02e11dc0003c18558fc9fb59cbd39363eda6518 + + aa4f1346d57cf6c968430c53adda361a2526197b + - - <_3:fileName>./config/config-options/DUK_USE_OCTAL_SUPPORT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS924"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>fec8c0387ddc9798b79b51f6f6f0a8303e8c8a54 + + 58c701ade28ee5a475dede84a6e771893e3fc40f + - - <_3:fileName>./src-input/duk_heap_memory.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1704"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/helper-snippets/DUK_F_AMIGAOS.h.in + - - <_3:fileName>./config/feature-options/DUK_OPT_HAVE_CUSTOM_H.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS484"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9e401b9c2bfc0c884067440ca4654fc34efac9ad + + + 72e17a756cd47580b6125c5aa10a89ce2bb9b7a9 - - <_3:fileName>./src-separate/duk_debugger.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS418"/> + + a63af7be25d2ec188d4b49ff94f62f4dd7937349 + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b81a68b8d643e5f35c4c53e0b85de7a7d1538d64 + + + f2e0d93394d0f353e42af9dbdfbb043b1c462ae4 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4f937b155a7bd79f7c97c8a7aac206521ddd0188 + + + df60e2cb707de62dfa29f7bf5d78c56505057aa3 - - <_3:fileName>./licenses/splitmix64.txt - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1764"/> + ./src-separate/duk_heap_finalize.c - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>88ab1d060886393d94b6fb7c6054a0189117340b + + + d3b91ed21c7cc0063e1a29a204457da50b1b3ef5 - - <_3:fileName>./config/config-options/DUK_USE_REFZERO_FINALIZER_TORTURE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1088"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/compilers/compiler_clang.h.in + - - <_3:fileName>./tools/extract_unique_options.py - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + 7ca24bea45b703a038057539d69673e78482553c + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/feature-options/DUK_OPT_HEAPPTR16.yaml + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1774"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7c5e71af49539cc5c8b7f6e2fd161a735dbf8bcb + + + a4d21026ffbbff2e612dcc6b272a670d191c2ff7 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>58c701ade28ee5a475dede84a6e771893e3fc40f + + a4daa6a7716a668a341617db1cd994bb0eeb320c + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>21ecc0bf6c79ab5f8a10fffe109cb22422c2fa80 + + + ff69aff0a588f5c66dc08c3ab096ae91a9406da5 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ada872547e2bed31a1c7db446728495b7f52079a + + + a13012d5efdd48b39f2100d2d060e7f5d03dae3a - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>18a9c1521f2a53697cf6ccf61aa850e7e0b8b362 + + 9e81b2414e53620f2a8dd5c15de8896c343ca7b8 + - - <_3:fileName>./config/config-options/DUK_USE_LIGHTFUNC_BUILTINS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./config/config-options/DUK_USE_PACK_MSVC_PRAGMA.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1166"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>3c2639d3263e22a693c6d6c4357f186149dec34d + + + ab40ea7b5e44bb61b688d9a8eebce7ec40cef1d1 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>19debd472907a63a41a9af9347cd1a2c6c41ff7a + + + b070e59599f3d279034a2f8991a63475b15d6162 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>02e3abb683294bb7adbe8fb4698186645a06da8d - + + + ./config/feature-options/DUK_OPT_INTERRUPT_COUNTER.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>23575db7cd88e42c0c3fc1630f44bf608fcec76d + + + ./config/config-options/DUK_USE_SOURCE_NONBMP.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + cc54527457f651a7560d0ab5953c4423ac045253 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>65e7d20d354a69549d56b06560396e75f4c370e0 + + 4718593942e66999888eb0a56572eaed93c4f5a3 + - - <_3:fileName>./config/feature-options/DUK_OPT_DEBUG.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + ./extras/print-alert/Makefile + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS642"/> + + ./config/config-options/DUK_USE_JSON_STRINGIFY_FASTPATH.yaml + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b5a79c153fd45b08931582302e7c63e071612148 + + 2c44d7d488bb32ca481cd48c49eae5fe254a859a + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>224f71b8e1183ec2feec467bf79e065184a61b56 + + 24b96d44acc76a490813e43a070e3d09f07782ce + - - <_3:fileName>./src-separate/duk_api_codec.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + 7c23b7d22d0576fa31863396a1f99fe65ae492be + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./tools/json2yaml.py - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS390"/> + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>141b3f8ffdd7a510709d7bade109e970fc65b61c + + 7d97be886ccadc59e0f53aa1aebc3fd05a16a384 + - - <_3:fileName>./src-separate/duk_harray.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS252"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./src-input/duk_heap_stringtable.c + + - - <_3:fileName>./config/feature-options/DUK_OPT_GC_TORTURE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS492"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_FUNCPTR_DEC16.yaml - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7ea5ab3fc207fd794cc26141a2f130ae55af1db1 - + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./examples/coffee/globals.coffee + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>e7390a8f9b29a5ee991f33d6a7dc5b291b2f5141 + + ./src-separate/duk_js_compiler.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + + f17e8fc258e9d616bf681e4d1775684b9faa8cbf - - <_3:fileName>./config/config-options/DUK_USE_DATE_TZO_GMTIME_S.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1162"/> + + ./src-separate/duk_numconv.h + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/feature-options/DUK_OPT_NO_ES6_PROXY.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./config/feature-options/DUK_OPT_DATAPTR_ENC16.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS662"/> - - <_3:fileName>./config/helper-snippets/DUK_F_TINYC.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_BUFFEROBJECT_SUPPORT.yaml + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1346"/> - - <_3:fileName>./src-separate/duk_bi_number.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS442"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_ES6_UNICODE_ESCAPE.yaml + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>5b9a67e5f2de5fe5aa46ab3958dd629a7dc3f614 + + + 877e40426fdcc613d4314889a30b93d526d420e3 - - <_3:fileName>./config/helper-snippets/DUK_F_MINGW.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + ./extras/logging/duk_logging.c + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1344"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>aa4f1346d57cf6c968430c53adda361a2526197b + + + 9f7e8ddbdc36ed74fdaa2aa612014ebe390be1d7 - - <_3:fileName>./config/helper-snippets/DUK_F_MINT.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1320"/> + + + + d9de9120af7009133f55d1f9844f1e64d74a13d4 - - <_3:fileName>./src-input/duk_js_var.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1642"/> + + + + 9426aa8e40c2dbc41243b2ebf3d82339b4241cb2 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8402d0b335764c245437b9e147cff99dd4f4cc34 + + 523e4f8a77802ab002b00257f92d44f4a91e3a95 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>da39a3ee5e6b4b0d3255bfef95601890afd80709 + + 185ee3d054a6f46d54a3473cbbf30521b418fe89 + - - <_3:fileName>./config/helper-snippets/DUK_F_SPARC.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1322"/> + + + + 67221a936e2ce8fb69d90c32f412adef5867dc90 - - <_3:fileName>./src-separate/duk_heap_alloc.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS394"/> + + 1b2d3fff9cdee972a43e472c1af229fe74ab3416 + + - - <_3:fileName>./src-separate/duk_bi_pointer.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + + ./src-input/duktape.h.in + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS450"/> - - <_3:fileName>./examples/alloc-hybrid/duk_alloc_hybrid.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS86"/> + + ./src-separate/duk_js_executor.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/config-options/DUK_USE_COMPUTED_INFINITY.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1210"/> + + fa85ee3394206d18c611b837e700257ba8336250 + + - - <_3:fileName>./config/config-options/DUK_USE_REPL_ISNAN.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./config/config-options/DUK_USE_COMPILER_RECLIMIT.yaml + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1036"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./extras/console/test.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + 88bff259291d0c0045db28b79482aeec154b4a87 + + + + + + + ./src-separate/duk_debug.h + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1424"/> - - <_3:fileName>./src-separate/duk_bi_string.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-input/duk_hstring.h + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS272"/> + + + + + + b55b06c60625f9553ff2b3240e9d4943af0c6266 - - <_3:fileName>./Makefile.coffee - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS20"/> + + + ./examples/cpp-exceptions/README.rst + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/config-options/DUK_USE_DATE_NOW_GETTIMEOFDAY.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-separate/duk_bi_function.c - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS990"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>54e4cf1a4824acb67b8b0e8c0544f311821d84c4 + + + 765ef83e5ebb3143fcba12f8686a25d6e6f09d8b - - <_3:fileName>./src-input/duk_replacements.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1612"/> + + + + c237e384900f6c517265b6b1f7ded0e5d9faaf69 - - <_3:fileName>./src-separate/duk_js_compiler.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./tools/scan_strings.py + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS240"/> - - <_3:fileName>./config/compilers/compiler_msvc.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS684"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/platforms/platform_posix.h.in + + + - - <_3:fileName>./extras/logging/Makefile - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./src-input/duk_util.h + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1452"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f0a507897ed04be93d20edd14439310c5373e48a - + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_ZERO_BUFFER_DATA.yaml + + + - - <_3:fileName>./src-input/duk_bi_date_unix.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1522"/> + ./examples/eventloop/curses-timers.js + + - - <_3:fileName>./src-separate/duk_bi_duktape.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS400"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./config/config-options/DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS.yaml + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8831625bce38f3db331e3d4b6656640659237de5 + + 8eb48fb0706391e81cd9edbeb52c9bfd7848e951 + - - <_3:fileName>./config/config-options/DUK_USE_PACK_MSVC_PRAGMA.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1122"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-separate/duk_internal.h - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f441f79468112b6d4002e64fc6043c96c9bfdbf1 + + 021e861014ab9e9ab906643ef6685c62f87eb6ab + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>64566ae0bdc1c3e1017604b6b45d515c30d976eb + + + c5c07548a9924f5ec10ab0f39fa52424804f6be5 - - <_3:fileName>./config/config-options/DUK_USE_AUGMENT_ERROR_CREATE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1144"/> + + ./config/config-options/DUK_USE_SHEBANG_COMMENTS.yaml + - - <_3:fileName>./examples/alloc-torture/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS152"/> + ./config/config-options/DUK_USE_ES7_EXP_OPERATOR.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>38f2e3331c3288003417442dbb6ddabb3c42b352 + + + 47b8e367d396cb47bc96a77576863c68cb940bbe - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1f5097ffee410e3ddcce14e8735be35e1c312b19 + + + 85c6870d769648da9305714b760e893e450effe0 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>55aa8c67f1fa418f8d625a32a9d6268e9d94429c - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4f3fbede562fe5f3f2ffe49a0523779dc620c81a - + + + + + + ./config/config-options/DUK_USE_SECTION_B.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./src-input/duk_api_public.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./src-input/duk_api_memory.c + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1684"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8015d14ffbc7a4a4b93d654f093aa48ec17fce4e - + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./examples/debug-trans-socket/duk_trans_socket.h + - - <_3:fileName>./src-input/duk_regexp_executor.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./src-input/duk_api_buffer.c + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1498"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>01d9ee35878785c070a7b0b7304def0dc377c7af + + + e0b4c75970bc07f17812e9d2711aa21d5e73c83b - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>3a3d4617a9f48298cc4461920d8acc8dec0dd536 + + + f2d9a140bfb00688a277148c7f5eb16275f607f3 + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-input/duk_numconv.c + + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>3a2d38d8c3e0191f6634862247f4f7631be8e9a8 + + + + + + + ./config/feature-options/DUK_OPT_FUNCPTR16.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_BUILTIN_INITJS.yaml + + + + b179e01832915e76316312d8603fdd6c72f3ddd4 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b918661de386fc9df8cabc20607ceba9eeb4ee34 + + 6b98824e13a3d9536542b8da51d012a3d66ceec1 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f7a55a3fd14359cb9e72c2a5c9417560410a6044 + + + 8b33e4aa64c09d33721bda1113dd7b6d418fe444 - - <_3:fileName>./config/config-options/DUK_USE_UNDERSCORE_SETJMP.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./src-input/duk_api_bytecode.c - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1124"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./config/config-options/DUK_USE_DOUBLE_BE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1070"/> + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/header-snippets/types1.h.in - - <_3:fileName>./config/helper-snippets/DUK_F_FLASHPLAYER.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/feature-options/DUK_OPT_STRICT_UTF8_SOURCE.yaml + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1340"/> - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>29b4d0211a0878fb5fc07209bdc763e00bb6cd32 - - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b0ac5a30d9424a3ce1591e9ecc33ca4eff9d3b11 - - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>98a4d4c44dfc8273105e496706ce6d7dc6e3c9ed + + + 79d42208c44a8ecef264682f6c72eb8bb4ad122a - - <_3:fileName>./examples/guide/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./config/architectures/architecture_powerpc64.h.in + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS138"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>fb4f806e7282dd3cb2df04e228672d8b0b1b8eb4 - + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/feature-options/DUK_OPT_UNDERSCORE_SETJMP.yaml + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>33e70456ec777298bd211e85275d27e71c95c878 + + 09239b0d8665e3fdb06e7d6e5c8be2cb20ae4de5 + - - <_3:fileName>./src-input/duk_util_misc.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/platforms/platform_hpux.h.in + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1538"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7d9965b277af3b0a4be8000b833c29506638a60d - + + ./Makefile.dukdebug + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./src-input/duk_error_macros.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./extras/module-duktape/Makefile + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1674"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>321c61274d91796567e7b0bd4da4a67b108a5bbc + + + bb0d7a6b563c118a0c1e6f0f2b6b8a50f09e280c - - <_3:fileName>./config/architectures/architecture_x32.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS834"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-input/duk_henv.h - - <_3:fileName>./src-separate/duk_hstring.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./src-input/duk_json.h + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS290"/> + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>54da1fbed3ce3f7150639cafa7c66164891bd6da + + 0e4fd82c8f6a18bfef5fede40307ed460b7212c7 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2ca50648dba45418d87635d8d5bf0f3729d58e55 + + + 3336588083b538bc5c739b6593ba24f1fe60d0c8 - - <_3:fileName>./src-separate/duk_heap.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS262"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/helper-snippets/DUK_F_WINDOWS.h.in + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>db1f3e76b30212cb07e32d85c585160bb3681407 + + + 61043b4a6f3cf86375ea6e34ebf83b550a1935b2 - - <_3:fileName>./config/header-snippets/architecture_fillins.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS728"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./tools/extract_caseconv.py + - - <_3:fileName>./config/config-options/DUK_USE_BYTEORDER_FORCED.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1250"/> + + + 0ec6da5d51a0fbe7ad3725af169a2808665ee75f + - - <_3:fileName>./src-separate/duk_selftest.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS362"/> + + + + f74f5ce8723609bb319befd4ea08fad5e4565c50 - - <_3:fileName>./config/platforms/platform_windows.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./config/examples/disable_bufferobjects.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS792"/> + - - <_3:fileName>./debugger/duk_classnames.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + 3105fff8fd515c3e8158f29e2bf1741e183f3e9b + + + + ebe2924771df79f3fc41663c50e17688c95c5d08 + + + + + + 21ecc0bf6c79ab5f8a10fffe109cb22422c2fa80 + + + + + 3f899f6333159173bdb8165e48350567c34d14dc + + + ./config/config-options/DUK_USE_COROUTINE_SUPPORT.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./config/feature-options/DUK_OPT_FORCE_ALIGN.yaml + + + + + b0ac5a30d9424a3ce1591e9ecc33ca4eff9d3b11 + + + + + ./src-input/duk_lexer.h + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./config/examples/shallow_c_stack.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS62"/> + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./src-separate/duk_regexp.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./polyfills/duktape-isfastint.js + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS266"/> + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2b673980d07bab3ac5cc916c6c9537343b3ca53f + + ./examples/codepage-conv/duk_codepage_conv.c + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + 5d5e2dac5c9d27d2d0cfcca8dc83937d8429eb96 + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/architectures/architecture_generic.h.in + + + + + + + + + d8b699b9aa839228e9713c3edd6af63b67406c66 + + + 38ceb89e840618ba30fa19731672f73f2c9ce7e8 + - - <_3:fileName>./config/feature-options/DUK_OPT_NO_JX.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + + ./config/feature-options/DUK_OPT_DPRINT.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS580"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>61382194a27752d9017644923295650cecccfe08 + + 39377ca5ad8255d31ae2862d872151e035f2df6e + - - <_3:fileName>./src-input/duk_util_hashbytes.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + d1aa83335e2cecb5ce01d40c0c5eea72cb171972 + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1740"/> + + + ./config/feature-options/DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + 821d0801ed06574f5503b9d5b76eebc2f3347328 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>28dc111c6a0c6bc4b041108eaf74b08167d0a4fa + + 083790fe736c0775c1a1f2990df9cfef516dea66 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>3b8236810650f4e28bd84984b3c7e55029f241b0 + + 7cf8f3c5463080cc45a18dd08c05681bcd662ec1 + - - <_3:fileName>./examples/eventloop/socket.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + 8eb48fb0706391e81cd9edbeb52c9bfd7848e951 + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS106"/> + ./config/config-options/DUK_USE_DATE_TZO_GMTIME_S.yaml + + + + + cb53b7840e10a86a1ac15e0ee6319b36a24ba924 - - <_3:fileName>./src-separate/duk_debug_vsnprintf.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS338"/> + ./config/config-options/DUK_USE_ES6_OBJECT_PROTO_PROPERTY.yaml + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2c4d73775edda84d8664b58be73f92f22cd6db49 + + 1f3860956ae1463e3c886d9d0efaf69ca56805de + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0eecd473f41f67d6ffb1d1cd71c0e9ccf8645fe7 + + + + + ./src-input/duk_js_compiler.h + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + 58abb86f759d552a92afdb9154b3f6ec3df9c50a + - - <_3:fileName>./tools/json2yaml.py - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./config/helper-snippets/DUK_F_TINSPIRE.h.in + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1778"/> + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>628cfed456403b766eddbfb9bcafa9f0c671bded + + + 35269945cbb0f6d7168b069c19eadbd27afd6df3 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9d97cd24eba146d098b88505afb3e9d9c71fb05a + + + 07a167411a356aebfbe987353846a9c711998f20 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>eea884435be2c4143d8aea493762a6f39d69d7e0 + + + + + ./config/config-options/DUK_USE_BUFLEN16.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + 46186f8bd845acc9cca22d6d74b4aa0fa97a8ea5 - - <_3:fileName>./config/config-options/DUK_USE_GCC_PRAGMAS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1170"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/feature-options/DUK_OPT_FASTINT.yaml - - <_3:fileName>./examples/guide/fib.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./config/feature-options/DUK_OPT_DEBUGGER_SUPPORT.yaml + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS144"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>4c1e8fec92758cfe3d88e5dfb814d1dee05090b8 + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_REGEXP_COMPILER_RECLIMIT.yaml + + + + + + + + + 3598716936eb6899da06ecea0877ea5f103a4735 + + + + 75d1b90f973098d6549bee80963392803e6ea25c + + + + + 398a2f235ced56eeee14280fce550b2ebd99306c + + + + + 4239a907720cf3620bd0b03eb43981e7182e305a + + + + ./config/feature-options/DUK_OPT_DATAPTR_DEC16.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + + ./config/config-options/DUK_USE_UNION_INITIALIZERS.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2e5c2e2f810e1bd3ecb804bd9eb73089a08b5e17 + + + 8e1a45476cf90a37c853d201c5bc07aec22b52b8 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8417da6962eaf68b15198ff92662cc53c9af80dc + + 98dbef461e39c4f07265b19fb5301401003e569e + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0e590fee39698aec4b1dbfbbcfe311f2d96ee795 + + 9c8de726c693d9c8a92af959c8f41d19276f77e1 + - - <_3:fileName>./src-input/duk_js.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1530"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_DEBUG_WRITE.yaml - - <_3:fileName>./src-input/duk_jmpbuf.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + ./src-input/duk_error_misc.c - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1506"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>87b1de3429de499a85dad75b2d0297461a87c523 + + 1cec45c2d1998fa704e215a832b96856886d8aec + - - <_3:fileName>./config/config-options/DUK_USE_POW_NETBSD_WORKAROUND.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + bdeb29fd0b17ff588e3b27c9ad421c8862130648 + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS938"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_EXTSTR_INTERN_CHECK.yaml + + + + + f789d1a5eb5d77bba4cced563970d4dcd2c44d68 + - - <_3:fileName>./config/header-snippets/gcc_clang_visibility.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + 9b6e480763339e9e249e47755c80c198b0fac72a + + + + + ./config/config-options/DUK_USE_DATE_TZO_WINDOWS.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS752"/> + - - <_3:fileName>./src-separate/duk_bi_date_windows.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS410"/> + ./config/feature-options/DUK_OPT_NO_NONSTD_FUNC_STMT.yaml + + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>734d4f4a2f28b6b3df4db12a5bc6b2b84816370b + + f441f79468112b6d4002e64fc6043c96c9bfdbf1 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>31d70a7dd733490756255949aaa1b787317a684d + + + 3f071e817cbb7f9f143bfa02b44c0841f5880a18 - - <_3:fileName>./examples/eval/eval.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS132"/> + + + + + ./config/README.rst - - <_3:fileName>./config/config-options/DUK_USE_STRHASH16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1096"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./config/feature-options/DUK_OPT_GC_TORTURE.yaml + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>279fd7202e72b7796a1147428885fd6d54c2fc7e + + + 7a4fc9dbd0f9085a75d0482bc8748b203ec9c2fd - - <_3:fileName>./config/config-options/DUK_USE_TAILCALL.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./src-input/duk_error_augment.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS896"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9f7e8ddbdc36ed74fdaa2aa612014ebe390be1d7 + + + + 5d39fe44693e51bd001edf38cbd0d41d43b27451 + + + a15c8491351869c1529bf5748f554039cf1018eb + - - <_3:fileName>./config/feature-options/DUK_OPT_FORCE_ALIGN.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./src-input/duk_heap_misc.c + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS520"/> + - - <_3:fileName>./src-input/duk_js_call.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_ARRAY_FASTPATH.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1572"/> + + + + + + + 09d5941728d8b74cd13c9faacaade4fba1ddb8f3 + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./src-separate/duktape.h + + + + + + 8fb178a8b3c0efede2a2773c11d97918fecb3528 + + + + + + fdea20e9cbcd771f4dc1495f079f64a2a91a501f - - <_3:fileName>./src-separate/duk_tval.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + c9b507a62367956d2c2f431c7cb07e7a1a7987ab + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS364"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/examples/enable_debug_print2.yaml - - <_3:fileName>./tools/prepare_unicode_data.py - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + + ./config/config-options/DUK_USE_REPL_ISINF.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1806"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8582bfc803d76c8ac75c0aca4007ebc6d9815c41 + + + + 7acd860e0b93fc4bed4960be0c9421cd544d9180 + + + + 2a55284f755fd8367399510daa3570a93203d6ff - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>648ba478fe390a171f7464f0ffee3e003d9de3ab + + + 87801faec7afe7e24b542bacd2baf09afc3b386a - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>ee95cfadbff61990ae6b33f8b7f3fcd61f563533 + + aa852ff18f4abd7522d0ee91a5887e9dd6431b54 + - - <_3:fileName>./config/config-options/DUK_USE_DATAPTR_DEC16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + 3bdd7c854685790ca254429f2a17e32907f7db90 + + + + + ./config/config-options/DUK_USE_DEBUG_BUFSIZE.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS980"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>04f3dcbfb48e51f40e6eb0fe471fbfb01c71d9f5 + + 49bb057bdaef78d25b9b1735faa05ad518f4ee6b + + + + + ./config/architectures/architecture_x64.h.in + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>47b8e367d396cb47bc96a77576863c68cb940bbe + + c633f8619ed0e75a43d42d966d7834e526827dda + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>dd07e72d680a378b1ecd916611c888013051d1bd + + ca9e1a8f73c5dcbe2e8c45d25ce9865cd93866e6 + - - <_3:fileName>./config/config-options/DUK_USE_NUMBER_BUILTIN.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1182"/> + + + ./config/feature-options/DUK_OPT_OBJSIZES16.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./polyfills/object-prototype-definegetter.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + ./config/config-options/DUK_USE_BROWSER_LIKE.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS460"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./src-input/duk_api_call.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + bda50b818153f21b2be45976a6ac18f33b6c263d + + + + + ./debugger/duk_debug_meta.json + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + + + + + ./config/config-options/DUK_USE_STRICT_DECL.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1548"/> - - <_3:fileName>./src-input/duk_hobject_class.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + 7110f0a065541b2d2eb169badb3f6eaa5505032b + + + + + + ff9118d49ebfa3557c4248f16fe3364ad976ed44 + + + + + + 6bc73cdb2ca01065f1e4cf4485f898ea54697b70 + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-separate/duk_forwdecl.h + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1600"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>e3bd3ac7d5fbf9ec5dc1f956d44f3625d0398bb5 + + + 1b8efcf511e3221b9e8cb9c47efc15935aace099 - - <_3:fileName>./src-separate/duk_error_misc.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + ./config/config-options/DUK_USE_OS_STRING.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS348"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b5431113b654283649516b9d9ce9d7a572a2ced3 + + + dafd4cd29ec8e228ab44be3c92e8ad7b8969fcde - - <_3:fileName>./src-input/duk_api_codec.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + ./config/config-options/DUK_USE_SYMBOL_BUILTIN.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1690"/> + + ./config/config-options/DUK_USE_BOOLEAN_BUILTIN.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + 2cb272bdfc795d393db8d0550e4abce3499da203 + + + + + 684084c3a1a8199ed44c0b5b725f7f5a78a98fb2 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f34df48d9f648285023482412ed825ffc5f00e98 + + + e5cc9b34109a953f0535a7d709b20be822f29827 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>456a80344432f219c4456fc9f323644343604b0a + + 2df5c51b4a62d1aa3d9573c9005c71d839cbee19 + - - <_3:fileName>./config/config-options/DUK_USE_ROM_PTRCOMP_FIRST.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./examples/alloc-hybrid/README.rst + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + ./src-input/duk_error_throw.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-separate/duk_bi_thrower.c + + + + + + + + ./config/feature-options/DUK_OPT_STRTAB_CHAIN.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1038"/> + ./config/config-options/DUK_USE_TARGET_INFO.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:fileName>./config/architectures/architecture_x64.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS836"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-input/duk_selftest.h + - - <_3:fileName>./debugger/duk_debug_proxy.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS50"/> + + + ./examples/guide/prime.js + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0082c3a06e9d1a3ed3fd6b647f96315eb5f6c9e9 + + + + ./config/config-options/DUK_USE_LEXER_SLIDING_WINDOW.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./config/config-options/DUK_USE_DEBUGGER_FWD_PRINTALERT.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-input/duk_bi_date_unix.c + + + + + + + + b63bb52ba6f8661feafc2f6bf42110725b590abf + + + + 7c37c53045b0a73662504f26697b7e711a7510fe - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>224f71b8e1183ec2feec467bf79e065184a61b56 + + + + ./examples/coffee/mandel.coffee + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + 1cd731519543ce78141971d455e806db68d719f1 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d273b0e72994792e9c30e2a77a2495040e896e53 + + + 90a82bf9ef21b2d0517a3bc4fa47a39a24d833da - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>31d70a7dd733490756255949aaa1b787317a684d + + + ba8248d12aa1af3bb74fade616001c0666a9129e - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9a21e86bf65e62f1f979246134e511a0d8108f46 + + + 3838f84ea655e7c239dd59cdc4cebcfb871b3973 - - <_3:fileName>./examples/eventloop/server-socket-test.js - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/helper-snippets/DUK_F_SPARC.h.in + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS124"/> - - <_3:fileName>./examples/eventloop/ncurses.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + d01da2742622d5f681c612196b3bfab050c1aaf1 + + + 2da49f0d383feb4e2862bde546acde9bbc010057 + + + + + ./config/config-options/DUK_USE_LIGHTFUNC_BUILTINS.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS104"/> - - <_3:fileName>./config/config-options/DUK_USE_HSTRING_ARRIDX.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/helper-snippets/DUK_F_APPLE.h.in + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1048"/> - - <_3:fileName>./src-input/duk_hstring_misc.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + 4b7b9d8d4cb87befce317fdc38e96f40e13cdd05 + + + + + + + 243068f15319fcc7e73189a7bb67781fe23cec5f + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1526"/> + + ./Makefile.sandbox + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + 3bdd7c854685790ca254429f2a17e32907f7db90 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>024cd43cdffd9101905babfce42500e78fb46dba + + 9da72a89b2c26a4073408299b29a74d8e8e0effd + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>3336588083b538bc5c739b6593ba24f1fe60d0c8 + + + 763b6705afa7b6c6d028da04bb669e0e9fc11eb3 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>44055c77862ea08c6135ae4a1f66e19cba163445 + + + c4f7aeabb2dd685b624b85a77fe677086c69d5ef - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>bbc5a800cc28683a58279cca5b21269a7266ba71 + + + + + + + ./extras/minimal-printf/test.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + 27bd858100fa17bbb03f741eae0fd3aad9a1f310 + + + + ./src-input/duk_js_var.c + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:fileName>./src-separate/duk_hobject_misc.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./config/config-options/DUK_USE_DATE_NOW_GETTIMEOFDAY.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS216"/> - - <_3:fileName>./tools/yaml2json.py - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + e3bd3ac7d5fbf9ec5dc1f956d44f3625d0398bb5 + + + + f02e11dc0003c18558fc9fb59cbd39363eda6518 + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./extras/module-duktape/duk_module_duktape.c + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1804"/> + - - <_3:fileName>./src-separate/duk_error_longjmp.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + cba2de26d84acf9af3cc3950ce739864dd6e6307 + + + + + + + + ./src-input/duk_replacements.c - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS286"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/feature-options/DUK_OPT_FUNCPTR16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_ROM_STRINGS.yaml + + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS610"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7c37c53045b0a73662504f26697b7e711a7510fe + + + 46ec9c220610b64fc5a3df2cc608b7ffa810c181 - - <_3:fileName>./config/feature-options/DUK_OPT_NO_FUNC_STMT.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + ./src-separate/duk_bi_number.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS656"/> + + + + + + 8417da6962eaf68b15198ff92662cc53c9af80dc - - <_3:fileName>./src-input/duk_hthread_misc.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + 8348ebca89bdf8d42ea995bbb249f326257c823b + + + + 23cf8b40dbb8e07a2e4ad7333aa4db6756ca8242 + + + + 19f689b750db15a7cca576a630a249db15bcd32e + + + + + + + bd938d928e81e72389fd32c90c0f4524594aaf19 + + + + + f9ea98185af04c0785a8ba19569c0715647709d2 + + + + + 59c2a146022c8f01d10d3663460b1917d7879392 + + + 7232f08a0e94ff9a904cfeb1ac6d727f289f0076 + + + + + + + 3d3e1ac9abf52775453307faf0a168fee177e645 + + + + + e1b1b68e35d34b283b18d25f1128db72ae59c5cc + + + + ./src-input/duk_hobject_pc2line.c + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1528"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + c7dc5159da983151a1718707eb5009570318b546 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1f42c900d10898702dd7959f06ae1fdc7b3df3a6 + + + 9cf89b0c8a1188f8bdca7a68c69c54fe73cd45ed - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9bad9281c81e26cc8fd9e4cebf22791a3c58953a + + 8e79a19c02102b9abeb8ce79394c090fe9bb336a + - - <_3:fileName>./src-separate/duk_numconv.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + 6d6a0ed935fc74ff5163e40366294a0f759501f2 + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS416"/> + + ./config/helper-snippets/DUK_F_MINGW.h.in + + + + + + 615baeec8dd79a073bd53eab2b8f81516c8a03dd - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>3e7d1f96ac9d7e182071c310a8e41b535d635507 + + + af6b0cd61c02efa575b9106682606297d26f013b - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8eb48fb0706391e81cd9edbeb52c9bfd7848e951 + + + 7d69dfa4ed9ac49764f35ea4311614da1913a9e2 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7054031543b78b05ce4dbb8beb15e4bfda8ae282 + + + 39ba23af6c40e9e63b4a5668b667c5e8874293d2 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>8483a2211d6323480efa605ee646959695b742c6 + + + a64d1131ed6e0af992703e4113c30fcf1e64bdfe - - <_3:fileName>./src/duktape.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-separate/duk_debugger.h - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1772"/> + + - - <_3:fileName>./src-input/duk_unicode_support.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + 7ea5ab3fc207fd794cc26141a2f130ae55af1db1 + + + 78a78b9ca07b9288621ccc098650870f566eaa92 + + + + + + + + ./config/config-options/DUK_USE_VOLUNTARY_GC.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1496"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a0633e6b3a780281a34f293b5476aacb6047974f + + + 456a80344432f219c4456fc9f323644343604b0a - - <_3:fileName>./config/config-options/DUK_USE_DATE_BUILTIN.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./config/config-options/DUK_USE_DPRINT_RDTSC.yaml + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1280"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>eae356dfdf5fefa117c90c67113de4f7d3fdeff7 + + + 04f3dcbfb48e51f40e6eb0fe471fbfb01c71d9f5 - - <_3:fileName>./config/architectures/architecture_powerpc32.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS818"/> + + ./config/feature-options/DUK_OPT_NO_REFERENCE_COUNTING.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>13165d92cb30f0ac3aa1e6c9234fbc2d07d36d7d + + 268d0dab85b69247ce036eaa197728702d290845 + - - <_3:fileName>./config/config-options/DUK_USE_DATE_TZO_WINDOWS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + ./config/config-options/DUK_USE_VERBOSE_EXECUTOR_ERRORS.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1046"/> + + + + + 68fc322fe33c22d75a188881f8e618cb392e2d8a + + + + + 6eb3ac68f1ef4456c94c518c3a7afaeae48d1a69 + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>fff1d3ee981ee7305fae3812925d7d08b19823c5 + + 0125ebcabe62cef4923e75527d3128e8c48cdf1f + - - <_3:fileName>./config/config-options/DUK_USE_GC_TORTURE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + c2892039e196ae0703757e0c0b039d4ead70fd84 + + + + + + + ./config/config-options/DUK_USE_REFCOUNT16.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS926"/> - - <_3:fileName>./src-input/duk_exception.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1608"/> + ./config/config-options/DUK_USE_JSON_SUPPORT.yaml + - - <_3:fileName>./src-input/duk_bi_reflect.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + ./src-separate/duk_hstring_misc.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1626"/> + + + + + 9e401b9c2bfc0c884067440ca4654fc34efac9ad + + + + + + 235c35fc0a44ba78b50a392af5d936c62b46775a + + + + + + 68e5fbde6514a3c3d381035077213e7ada956bd0 - - <_3:fileName>./config/architectures/architecture_mips32.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./config/examples/rom_builtins.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS820"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>600af9478922de1fed14dce44859b0182f67865b + + + + 97ea8e8de93864cfcce483b0066bdcdb2c8af2ce + + + 7d97be886ccadc59e0f53aa1aebc3fd05a16a384 + + + + + + 8c23d8568a42ac3a5aeefb138396a29d69186569 + + + + + + b70b8ae4fd674cc8163b5b5e5e08541c560c12df + + + + 96ce130a3826b71c0f71bcf17c52cb76a7c8c26f - - <_3:fileName>./config/config-options/DUK_USE_ALIGN_4.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + 666f157dda4c3d1dea5ffbc7be7c5abb343481e4 + + + + + + + 9dd1ed891714d3c8542185cb6cf059826a5a115a + + + + ./config/config-options/DUK_USE_USER_INITJS.yaml - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1228"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>5d2bf5b2953a619bd1cd156ab6ce47140336eba2 + + f17e8fc258e9d616bf681e4d1775684b9faa8cbf + - - <_3:fileName>./config/config-options/DUK_USE_REPL_FPCLASSIFY.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./polyfills/object-prototype-definegetter.js + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS894"/> + + - - <_3:fileName>./src-separate/duk_bi_thread.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS426"/> + ./src-input/duk_js_ops.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + + + + ./config/config-options/DUK_USE_COMMONJS_MODULES.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + be0e7eb2cebe3402a9c67065a051b343c2f38d46 - - <_3:fileName>./config/config-options/DUK_USE_HEAPPTR_DEC16.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + + ./config/config-options/DUK_USE_ALIGN_BY.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1090"/> - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a06c61bed150ef8a0cc494579e1d0cf035acf13e + + c421588cff2ced0f938f3aa073f0ce48a553c935 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9b254d86bac8eb249de6789e8521c0441220e383 + + d869c0f8797a659124b3ba31c75f494b15bea5e6 + - - <_3:fileName>./src-input/duk_bi_math.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1592"/> + ./config/config-options/DUK_USE_STRTAB_PTRCOMP.yaml + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a8cd1862fa60306cb9570def08974137866c09fb + + + 87f123156442e97bb503f76578a90d678a8cf8dd - - <_3:fileName>./examples/hello/hello.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS158"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./examples/debug-trans-dvalue/README.rst + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2b9167f66a35d1e5ea97fc23ec4ecae4782f0e7d + + + 28520ba887f6790e82c5edf9f8ef12db692922b7 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>c66e7d39f7dce513264d511f05dcc60934a5d7d5 + + 04645d3ee7dc5fd11e81ec78e72bbd311fb076b5 + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7ca24bea45b703a038057539d69673e78482553c + + + + ./config/config-options/DUK_USE_POW_NETBSD_WORKAROUND.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + ./config/header-snippets/gcc_clang_visibility.h.in + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + b7c5ed9b13ef4ca70acfcb47988d07cb2bfe28e6 + - - <_3:fileName>./config/config-options/DUK_USE_CPP_EXCEPTIONS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + f0ded24e507b30368469fc37873f43866f7263bb + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/feature-options/DUK_OPT_USER_INITJS.yaml + + + + + + + ./config/config-options/DUK_USE_JSON_DECNUMBER_FASTPATH.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1106"/> - - <_3:fileName>./examples/cpp-exceptions/cpp_exceptions.cpp - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + ed963c1624c91a6c0a2717e75a26ea84c9672df6 + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_FILE_IO.yaml + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS136"/> - - <_3:fileName>./src-input/duk_selftest.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1662"/> + + ./examples/alloc-logging/duk_alloc_logging.c + + + ebe6476a85dd433c66abffbeca6c6105285824bf + + + + + + + fda701fd3552814b654b4a2a42b197eaa370100e + + + + + 91dcb532a638b99224e822369549cd9b4cd07499 + + + + fb913b14a8e2827fc9c4c1f7d9eb1278bd102d1a + + + + + 03513d7b6fc13d8cf6781cc682800ce6f8468d53 + + + + + bc70d7db67fa486267b644b48840784d66111cef + + + + 53b98a94c0c26af0b4217b23f231c25d3de26be5 + + - - <_3:fileName>./config/feature-options/DUK_OPT_NO_TRACEBACKS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./src-separate/duk_js.h + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS670"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>34ade3ad11cbaee09d7495fc67a012971f134b02 + + + e023af5c2fb4b1efab74a230c552f1eb1b37fc10 - - <_3:fileName>./config/examples/low_memory.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS698"/> + ./config/platforms/platform_qnx.h.in + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f88d68880f451267e7e2eca4b6c4191e8c3fe011 + + + aa1f72e7a2b4891ec1f445eb031dfba69bdc85de - - <_3:fileName>./config/config-options/DUK_USE_DATE_NOW_WINDOWS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + + 771d3e86b837d865d5aeb54be91f7ffedc9fdaad + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_UNALIGNED_ACCESSES_POSSIBLE.yaml + + + + + + ./config/helper-snippets/DUK_F_MINT.h.in + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1256"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./src-input/duk_api_time.c + + + + + + 27947f5e5888d7bd7d413963318d76c4c81a9adf - - <_3:fileName>./config/feature-options/DUK_OPT_JSON_STRINGIFY_FASTPATH.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + f9072f5c361c86887b57ce662b3cd7211b4ce346 + + + + + + ./src-separate/duk_bi_date_unix.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS614"/> + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>0cc625a8d72def6d789f26930691c72953954361 + + + 2faa38660857db0600b15f0870fb2adde485fb8d - - <_3:fileName>./src/duktape.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./extras/minimal-printf/Makefile + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1770"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a75d516be529be065841333b9ea3d8fb6ce6d2bf + + 36f51bfa3c9d50eedf7183315f08196d27e4f154 + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + ./config/helper-snippets/DUK_F_NO_STDINT_H.h.in - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>98f108d8a5c41d1f577601983a383c9c38643521 + + 0811e545a133c3a62672e239624a0c1f11478b8d + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>38ac8f6fca8cc656ae35e420ac89d0d05814ddf1 + + + 49aa732e520ec7e16b799dc16240fa8d6394a649 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>9c8de726c693d9c8a92af959c8f41d19276f77e1 + + + c2deb792abf0153293226495ae6bcdcd9c729fac - - <_3:fileName>./config/config-options/DUK_USE_BRANCH_HINTS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + ./src-separate/duk_unicode.h - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1030"/> + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./src-input/duk_bi_thrower.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./examples/codepage-conv/test.c - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1668"/> + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>7881506e8ff2479944166f80633183dce0b92628 + + + bd0ae6d792a55411d1d601e9bc3dc8f7b41f8135 - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>2cb272bdfc795d393db8d0550e4abce3499da203 + + + 2d1d9cf996f6ad45bd65d4f9f135e3f3381de575 - - <_3:fileName>./examples/debug-trans-dvalue/README.rst - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS178"/> + + + 80fa455402d3c9d0003aac90591ce218e3333cec + + + + + + 5d53f0e4d2c41c70c9891e530c16dac7354889ac - - <_3:fileName>./config/config-options/DUK_USE_FLEX_ONESIZE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS922"/> + + + + ./config/config-options/DUK_USE_DATAPTR_DEC16.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>1fcf367a04cc09f979e97f25fffe9d6b9959b5c5 + + + 1b789c31109dc1dbca88058996e8e8213cee9140 - - <_3:fileName>./config/helper-snippets/DUK_F_VBCC.h.in - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + d45f24269cb41394de0c5c7a647e20db063f2b1c + + + + + + ./src/duktape.h + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1388"/> + + + ./config/config-options/DUK_USE_UNDERSCORE_SETJMP.yaml + - - <_3:fileName>./config/config-options/DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS908"/> + + ./src-input/duk_exception.h + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>b571340e3398d99e5c44eef1d12ef40198454406 + + ./config/platforms/platform_flashplayer.h.in + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + c9ba7a80e622c1b182f1683728f8154e876ecf0e + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a649e32bea73f77a7decfc83d465dd2ef9a47794 + + + 3a3d4617a9f48298cc4461920d8acc8dec0dd536 + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./extras/duk-v1-compat/duk_v1_compat.h - - <_3:fileName>./src-separate/duk_bi_array.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS388"/> + ./config/config-options/DUK_USE_PACK_GCC_ATTR.yaml - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>83a4f859444591fb0661eecf3be4aa937918c166 + + + 216ab11eadd49bdc7dc37e18c0de0e8d41c60d91 - - <_3:fileName>./src-input/duk_api_compile.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1692"/> + + 23575db7cd88e42c0c3fc1630f44bf608fcec76d + + - - <_3:fileName>./src-input/duk_api_string.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> - - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1728"/> + + + + 5d39fe44693e51bd001edf38cbd0d41d43b27451 - - <_3:fileName>./extras/print-alert/duk_print_alert.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + 19debd472907a63a41a9af9347cd1a2c6c41ff7a + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_INTERRUPT_COUNTER.yaml + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1476"/> + - - <_3:fileName>./src-input/duk_api_internal.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + ./src-separate/duk_hobject_props.c + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1590"/> + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + 91dcb532a638b99224e822369549cd9b4cd07499 + + - - <_3:fileName>./src-input/duk_hbufobj.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + c6a642bf872ab5b98f2441e98c79d2af2fb2bded + + + + 7f5238fdc9fc1e0e362ebe9660135b4a868c2661 + + + + + + bd3d0e5ba2b68864d8bde1f91e6310c04d56224e + + + + 44055c77862ea08c6135ae4a1f66e19cba163445 + + + + + + cef3eff34957436e126465462367875569963db7 + + + + 17e392f86eeef77b2a608f66b14a4c9354bd5f83 + + + + ./config/config-options/DUK_USE_STRTAB_PROBE.yaml + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1582"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>f694db88f8f386765f48a44d846b3660d8139ff1 + + + 4091a3a23fe8d47432e6c6fe73d27590e31ce214 - - <_3:fileName>./src-separate/duk_bi_date.c - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS278"/> + + + + + ./src-input/duk_error_longjmp.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:fileName>./config/config-options/DUK_USE_BROWSER_LIKE.yaml - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/> + + + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS1288"/> + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_DATE_FMT_STRFTIME.yaml + - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>3c6d9c22cfc8850cb8a4ebb5169a9f8eb570132d + + + bd50c5d463e5e0af70c431bb415f823d634408cf - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>d1b470355a5fee93adb31032e455446005ca2d10 + + + 832543d9949cf7ca5791e704e39e7837d93cd4c9 + + + 01c0fcd4dc6762d4be2946af802e6acaadec993c + + + + + + + + + ./Makefile.codepage + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - - <_3:algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/> - <_3:checksumValue>a8e303629c820f11766517de993860897a35b022 + + + 2616aabef11957037b1427f23da12b968c05d9c1 - - <_3:fileName>./src-separate/duk_error.h - <_3:licenseConcluded rdf:resource="http://spdx.org/licenses/MIT"/> - <_3:licenseInfoInFile rdf:resource="http://spdx.org/rdf/terms#none"/> - <_3:fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/> + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + - <_3:copyrightText>Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) - <_3:checksum rdf:nodeID="IPWfDqBS222"/> + + ./extras/console/duk_console.c + + + + 4a9ef686f4680d9a05c42f82067b4cebe4fa695f + + + + + 180ddee3e437f0caee5fe06aa9cb427455318d2a + + + + + + + ./src-separate/duk_strings.h + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + 771d3e86b837d865d5aeb54be91f7ffedc9fdaad + + + + + + 8cff533c618fccd4b0b57cd2548cc089155dd823 + + + + bab68aa1ba162bf165d48d8bc33e60cb305228c3 + + + + + ./Makefile.sharedlibrary + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + ./src-separate/duk_lexer.c + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./extras/alloc-pool/Makefile + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./debugger/package.json + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_TRACEBACKS.yaml + + + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-input/duk_bi_global.c + + + + + + 089c395fca3cedceec09fd38d32d0c77dc8658f4 + + + + + + + 23bb2a117ca989acb17aa740425dd46a020ccb6a + + + + + 99d36e3da909a12bd064806397804efa6f6e17c3 + + + + + a0cf25ef6d0b2816f79c1e1c42e08fbe8ce91d8b + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_STRTAB_GROW_LIMIT.yaml + + + + + + 0e120595fb9cf6b883f3a408c157403eae5d7468 + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/helper-snippets/DUK_F_HPUX.h.in + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_PACKED_TVAL_POSSIBLE.yaml + + + + + f0a507897ed04be93d20edd14439310c5373e48a + + + + + f6c9fca4e362ec09c551e923d51d7093c1a264d5 + + + + + + 7750412047b5bbd94475d0217d5dca5c4ac3c6ee + + + + + f7a55a3fd14359cb9e72c2a5c9417560410a6044 + + + + + 324239d893eafa800800faa764908d6ea232d78c + + + + b3ca8c4271d84ae7c27a7a8f739969a3581ba6b2 + + + + + 55c5af54de6869b35ba055476780a924bb5b746d + + + + + 0e2c0f34a387336aed77a3dd3f67ebe3f527ccb5 + + + + + + f1020eedf224158992a70be40cfb1267e806399f + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_ASSERTIONS.yaml + + + + + + + + + + ./config/config-options/DUK_USE_JX.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + a536fe74c5574b2abcaf15e0f12ca3a705878bb2 + + + + + + 5c1f5491c0f39e04f769dd4d3708b0a1908142c0 + + + aa8fc5e5443a5aa1c2c3a49c929bc2678652255e + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-input/builtins.yaml + + + + + + + + + 76e65516ead3c23b5c18959e0056580c345daf0c + + + ./src-separate/duk_heap_hashstring.c + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + + 1b365f83282745659aa239b8d5993fb8e7df1fca + + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./extras/alloc-pool/ptrcomp.yaml + + + + + 6868285482bd505c881a7a924e12520b99bd787b + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-input/UnicodeData.txt + + + + + + + 654592b896f142417be178b910cf35beb0c8dcf3 + + + + + + 733d6afac621170edff24ebb5cd5f9cbabcbf8b7 + + + + + + + ./src-input/duk_bi_thrower.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + aa39823cbb0e62aeba077a6e9510d0906a195bf2 + + + + + 083790fe736c0775c1a1f2990df9cfef516dea66 + + + 99928d954c5b34b61e98d61534282905989ca671 + + + + + + + d01a2c6f4fac3af3b23710131662ccf7a59c6761 + + + + ec4eb4acda5042e218ce3f3d68d34e2c83a0f9f9 + + + + 5b9a67e5f2de5fe5aa46ab3958dd629a7dc3f614 + + + + + ./examples/eventloop/ncurses.c + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + b648ee8ed5f3f43b10480bbcb068a436d379bc09 + + + + + + b5431113b654283649516b9d9ce9d7a572a2ced3 + + + + 0ee226edb0ea3c35fc0ff28499241a6dde397b38 + + + + + 8831625bce38f3db331e3d4b6656640659237de5 + + + + d53085a45e5f62dc5b3dca1f9f1e1bdb305fd5bc + + + + + + + a016e3fdb90c643b12f8ab9000b499e9248bf03d + + + + 6994cdb0af2435f070a870ce854b81072cff02a4 + + + + + + + ./config/examples/enable_fastint.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + 149fd21526c90d52b22e77b297f76e6da3e656ff + + + + ./config/config-options/DUK_USE_ES6_OBJECT_SETPROTOTYPEOF.yaml + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./config/config-options/DUK_USE_NO_DOUBLE_ALIASING_SELFTEST.yaml + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./src-input/duk_debugger.h + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + + + 895bd58e08b961fdb938f83648059c42b7e38255 + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + ./config/feature-options/DUK_OPT_DDPRINT.yaml + + + ./config/config-options/DUK_USE_DATE_TZO_WINDOWS_NO_DST.yaml + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-separate/duk_tval.c + + + + + f80f5ef421c8fea695b8028754704c22c3dad74d + + + + + + ab62f0df98070e3087a0fb8b2824e81f5e246fd8 + + + + 34af4d8a5e26158d762ca27598c6278fcd572b4f + + + + + + + 2e5c2e2f810e1bd3ecb804bd9eb73089a08b5e17 + + + + + 74a734b4fbba511d2fbf80d360ff6bd5302ebad7 + + + + + ea413ed7d47cf27c6f3ffe25956b1370b653c200 + + + + + 30dcbb117fc56033879a4daac636b0fa23e0f8a5 + + + + ddcdbc041baddc866b2864c8e68255fdf0dccde0 + + + + d273b0e72994792e9c30e2a77a2495040e896e53 + + + + + ./config/helper-snippets/DUK_F_FLASHPLAYER.h.in + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + + + + 234952538660f1f936bad7165e349ce48c575bd2 + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + ./src-input/duk_bi_buffer.c + + + + + + + 15ad80be0261075ecc86742df352f3bac2fd3217 + + + + cc59276261320c29a5168ede62c55b921b11cd37 + + + + + + f5b5b79a655e7fbfd11fe94b5e1d97ed45f15267 + + + b75a923c01d2a8997257370fefe859b43ae8ff8e + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./config/config-options/DUK_USE_ES6.yaml + + + + + + + + f5036786154c7b87d513d25e87d3cfa1ea0b9d64 + + + + + + + + ./config/helper-snippets/DUK_F_MIPS.h.in + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + f8e4195b4b2ada6059072839c62fb73d2354019c + + + ./src-separate/duk_builtins.h + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + + + + 0a5ace48a14ab0f5d41cc1ef8b4f9a99a975dee7 + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./config/config-options/DUK_USE_REPL_SIGNBIT.yaml + + + + + 2b673980d07bab3ac5cc916c6c9537343b3ca53f + + + + + Organization: duktape.org + 1.20 + 2017-07-28T22:05:07+00:00 + + + + + + 0eecd473f41f67d6ffb1d1cd71c0e9ccf8645fe7 + + + + 523e4f8a77802ab002b00257f92d44f4a91e3a95 + + + + + + ./src-input/duk_refcount.h + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + + + 3a81b3aa623cc81a9a80f40db3dd6c32b3f26c6c + + + ./examples/coffee/README.rst + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + + + ./config/config-options/DUK_USE_EXAMPLE.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./src-separate/duk_heap_markandsweep.c + + + + + 2685bcf2640692a14198527c0d5dc3262b2ed061 + + + + + 8c1194195935a066a30992f4d13690f700a22349 + + + + 75c61dd080cd643b7449f673105b7b7e4bdda0f5 + + + + + c6a642bf872ab5b98f2441e98c79d2af2fb2bded + + + + + + + ./src-input/duk_util_bufwriter.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_PARANOID_ERRORS.yaml + + + + + + 37bf12aa9253008f5b763d9f5d2d2ad26335ec7c + + + 8fd242cf73e663d4b76d5b2a2ec5f78250a1fc65 + + + + + + b571340e3398d99e5c44eef1d12ef40198454406 + + + + + + f1020eedf224158992a70be40cfb1267e806399f + + + + 3e7d1f96ac9d7e182071c310a8e41b535d635507 + + + + + + ab83cd50472dcb13efa4a74a718740256ef3b1f3 + + + + + + + ./src-input/duk_util_misc.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + 63ded311f7b05332e068906d8667c466ab671873 + + + + f02e11dc0003c18558fc9fb59cbd39363eda6518 + + + + + 76e65516ead3c23b5c18959e0056580c345daf0c + + + + + + 8582bfc803d76c8ac75c0aca4007ebc6d9815c41 + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_JSON_DECSTRING_FASTPATH.yaml + + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_PANIC_EXIT.yaml + + + + + + + + + 216ab11eadd49bdc7dc37e18c0de0e8d41c60d91 + + + 76d282992e2f312cde96ed6de39863883d0c36e9 + + + + + + 38f2e3331c3288003417442dbb6ddabb3c42b352 + + + + + ./src-separate/duk_bi_symbol.c + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./src-separate/duk_api_stack.c + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + caada55e058253f6ff08ba15730be8c0e8b0f082 + + + + + + fcdcbfbbd41900345ea4d1656857d1e365d3e5cb + + + 149584de234020f72f4b5c5fa23357d351de1ab7 + + + + + + f982055fcb3a2931e97d3ca184b471a4f4d3267b + + + + + 0ad527dbcc75e2d10787a0eae8ac8e09e9a31221 + + + + + + 0fcd418bc6efe63f95bf4cdc1538dfd5f0ce6478 + + + a739735783e9ca0c43981fb9c8c5e3be06e94c1f + + + + + + 76deaceac1803dc35ad32593a3961f2ac3b3acd9 + + + + + + 26e5fb2f31b011884e8d178f0e6d7b3b8cfdb864 + + + + + e36b278271ad5c367fde67e1dc637e7e5f1e1ca4 + + + 257477affc6974925dfdd8f182596fd923773ca9 + + + + + + + cf5cb3be898bfd3410e218750667856fb954cb98 + + + + + + ./src-input/SpecialCasing.txt + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + a9b7b714143adc2d874e328413e3d5399fda8abd + + + + + feca5644b37aca10a7bd2fee0551f255169b99ca + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + ./src-separate/duk_api_internal.h + + + bab68aa1ba162bf165d48d8bc33e60cb305228c3 + + + + + + + 4392fa63e6e9174ec09ef2e3a4e4e3bd03e94126 + + + + + 6620f1f2d0714ae0c83d6585590c2e5883cf4a0a + + + + + 63fbd4cac6fe8395feffdb3a009441a136036a3a + + + + c33c3a2cd1e25510334842e603084b033204db4f + + + + + 2da826dfc0ccd82b32412fc19c18746cffabd3de + + + + + ./config/examples/enable_debug_print1.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + 17f922490479e0e7875258fe338a1a75c88f64f3 + + + + + + 684084c3a1a8199ed44c0b5b725f7f5a78a98fb2 + + + + + dbea11328269ff4e954fcac30c38d1310d028677 + + + + + + 3a0f7d3f3186b920867e4b3ac5767364005865e1 + + + + + ddea7d3a3c3f4494eead71cbc61239771e656514 + + + d49c1cdb51b3a4fdd823c13831617a1f0a93edd1 + + + + + + + 4db4ca2d7ce3f076fd195372d53e8bc5714d2597 + + + 604f325ae4c368ca973bd122e7a98071fe9d1027 + + + + + 1c245898a94c4ab12cda618dfe42ac8c48682c77 + + + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./tools/extract_unique_options.py + + + 3c7e23532004e30b22be7e5487ac97802b26bc11 + + + + + 0c192f3df7ed956fb60437fc98b7c933d3673255 + + + + + + + 49d0b785377b9d56cb70bbed74cd34c0d1c64b32 + + + + + 8c1194195935a066a30992f4d13690f700a22349 + + + + d44321a56226e925dc5f54d3ef827cc610ca4c0c + + + + + 9b316a4606c3b7c5938aa709b53a6972e9240711 + + + + + + 379b72c9dc094ae724828facc127d6e3c9eb6bda + + + + + + + ./config/examples/timing_sensitive.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + fd51ec0049e1ce34f0afc9c01a8206cd6072cdf7 + + + + + 3c9206cd78f5f7c45714d935978bd2c9e6aa52a3 + + + + + dba3498081d653af079d08ea87c777b20f704593 + + + + + + b0cf0b5dc8b49ec61eded030c0d010f70198f0bf + + + + + d5c2fa62ed03af9de803157b465588e3ceb3787b + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./extras/duk-v1-compat/Makefile + + + + + + + + + 536cb431ce24b3032601b548479b6fb6f8764e51 + + + + + 39fd549c28f19dc9f0c93cce1fca50ef64f7ca83 + + + + 4a1c5e238c44e75ac93bfb1edcdcde2f26954b5b + + + + + + ./config/config-options/DUK_USE_FUNCPTR16.yaml + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + b3aa4396aa5da8b8e81301fb7f27cdd8063d1e78 + + + + + + + 272265025f87ee803a2f4ee2f9711083ac1f5da7 + + + 067a800a9f5db1ec8328d8748483a53f5f13dd95 + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./tools/dump_bytecode.py + + + + + + a1ab4d59eb5cb3d84ec103e48bbf0f74e5da725f + + + + + 936bfde4d1f27bf7427f5cd05dce0ce75a31f610 + + + + + + ba8d5c0458e36b58d580a0d1f4d8b1e94f7d9d09 + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./config/config-options/DUK_USE_BYTEORDER.yaml + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/helper-snippets/DUK_F_UNIX.h.in + + + + + + + + ./config/config-options/DUK_USE_RDTSC.yaml + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + 098248571205603dcd74f158406faac5c1e9e4db + + + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_REFCOUNT32.yaml + + + + + + 0082c3a06e9d1a3ed3fd6b647f96315eb5f6c9e9 + + + + + fff1d3ee981ee7305fae3812925d7d08b19823c5 + + + + 4c1e8fec92758cfe3d88e5dfb814d1dee05090b8 + + + + + + f68b056e907f117d869d5ee9c8016427e8f7d088 + + + 11a7a5b6b1557adeca8a9def51cb44282f24c853 + + + + + ./src-input/duk_heap_memory.c + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + 66bd2a379a8bfbc380d816c2395a94b011a5d2ee + + + + ./extras/logging/README.rst + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + + + d791ee30f44f9b4960a7f03ab5dc9e4b6e8e2536 + + + + be9d6af3be87f2fbf4813c2ec8c8d38d43b1cd58 + + + + + 2dbad78514e12776ffca096e1a898d8b53607b4b + + + + + 9bcbdd7d6fed9271f4bff23a23c6cad5e43c569d + + + + + + + c1c79add4fb512b7a46ac71abd688c77df8e107e + + + + 0bf9287bdff77a59737ae2dc00ed983faab89c1c + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./src-input/duk_heap_hashstring.c + + + f406f7db9beb9a66addefafd9a03d29365f2660c + + + + + + c46260b8734e0db2e7c5a4a628c9fab0bc7b669a + + + + + b3db58b9744de8c3afcc2fbadd38cedfc6a3d0d5 + + + + + + 1b789c31109dc1dbca88058996e8e8213cee9140 + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./src-input/duk_api_stack.c + + + + + f977bedf2631aca7493ce2d1cc2dd253e93cc566 + + + + ebec67f0e7e3c393f01dd50f9c661fca6b779328 + + + + a534e0108c394ab49c72dc9dec62029f2bf91406 + + + + + + + 0a0b92d48449a1bc52e8be419a60ef27a9d5a41f + + + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/helper-snippets/DUK_F_M68K.h.in + + + + + d2ac6ac9e93fac629050fc83d39363863d879ba8 + + + + + f79136aef9fb5e548d63b9520af7f4600207faa7 + + + + c6ecd2e0444e5984e1c568fc2103a28e61df67d5 + + + + + + 4d02f921b99409a38de077aca279f9513645cf88 + + + be0e7eb2cebe3402a9c67065a051b343c2f38d46 + + + + + + + 55aa8c67f1fa418f8d625a32a9d6268e9d94429c + + + + 884bb62571381479dd69caad82eb6523b45aec70 + + + + 5b2e82eceb788df59bd57e7708c116e46a860072 + + + + + + + f828e5a5a88f63e033c8bb91587fd65f1a6463aa + + + + + 58143c765e94cde57b4328d6de6a716bb14e598f + + + + + b281e4ffffc9d6ec26f69e009b14831b426c144f + + + + + c9c65b1bc315afaaf70a219969ff3c95425ef628 + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-input/duk_debug_macros.c + + + + + + + + b70b8ae4fd674cc8163b5b5e5e08541c560c12df + + + + 26c211f6a2f663d1fa48d938f5484f4060d8ff3d + + + + 0ec6da5d51a0fbe7ad3725af169a2808665ee75f + + + + + + + c640b61e3177c48c1e4aa319155dc33502161be1 + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + ./src-input/duk_lexer.c + + + + + 7067e460242aeaf79d594a5aa741344b2fa70c51 + + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/config-options/DUK_USE_PACK_CLANG_ATTR.yaml + + + + + + + + 93573df8348a41adb790f59e39bf99d9a7bf3a3d + + + + + 9dec1b34df7a0d6773a1367000d7c27dd0894454 + + + + + 61382194a27752d9017644923295650cecccfe08 + + + + + + + ./config/config-options/DUK_USE_REGEXP_SUPPORT.yaml + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + 10bb35bc195325b56271971f1b12640a7bde4d2d + + + + + 58193cfef36035e44c517256a84bc5e4da3dc6a7 + + + e1b1b68e35d34b283b18d25f1128db72ae59c5cc + + + + + + 4e5a54de08355669dc98b5d4ad379384b33da4e5 + + + + + + dfbbd8bc95a46f832c67ebf680b0c9b0888f6245 + + + ba01693a576afdd00bbddf3bb3b558d89a132137 + + + + + + + ./extras/duk-v1-compat/test_eval1.js + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + d6f91292a6be62b7dda15ef5fcee1a8f570a33ec + + + + + 0e4fd82c8f6a18bfef5fede40307ed460b7212c7 + + + + f2805a6ce52407091fb7b145d0a81fcd5c84e513 + + + + + f74f5ce8723609bb319befd4ea08fad5e4565c50 + + + + + + a0660bd79f4d47b95a6db98ccce46a6e95ab6a80 + + + + c7dc5159da983151a1718707eb5009570318b546 + + + + b80c8be283c2ad3501e422d39508a7cfa765d632 + + + + + + + c8c8034feefe02c4c453c33b95be3056e4ced520 + + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./src-input/duk_bi_array.c + + + + + + + 113e9dce2fc881206ea51ac5723a3f2044be9b9f + + + + 3cdf24c947702ea84c7e7829f9c62333c701d21c + + + + + 95f0e467f3a04245b061f3ca47cf4c5a33e61bd6 + + + + + ccbe1785277c59b6193f562d04b8e41d3dc7f531 + + + + + 35f7195d949252ea6bc9c25360941a4141886346 + + + + + + ceaa461d035b4428a0165cd432eea13f664e05d0 + + + + + 9f3e1e77e31ce573126abe1e7adba02261e34ee9 + + + + 099a3237525b972082568a8aefcbb4264b3d47ba + + + + + + dfbbd8bc95a46f832c67ebf680b0c9b0888f6245 + + + fd9e637eeb76970ee8979e633ad14fb8373f7a07 + + + + + 49dcd350a10ed1fd7ffc5bf021f1b0dfc5a37446 + + + + + + + 5f0c8d2d314be55ac5418e841ddcdb1dfbad2f75 + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + ./polyfills/performance-now.js + + + + + + + + c6481ef081e76cf3c06586bc6ec54b8b084df161 + + + 215f6fec820889330048f7f2c1b5a220eb963657 + + + + + 6e2af71ada62c408d30381e5330c4369aff3bae4 + + + + + 497ee6ace70fe75d9fc25ce0bd1c3ba4f3518c87 + + + + + + + 1d944d89920dd9e46233c81d78ab8a60141faa40 + + + + c3057ade4eeaeefbf2c59026cd6729b6a2882d3a + + + + + 7d0d6e5c35e543326fc4f335ea92b5dd1c630d3e + + + + + + c8714b619f0c719857cce2ffebff43a54fded469 + + + 1dd90f5fc7f34d0f138dbb7b11d53392f002db0c + + + + + + + aae91fcfae368779341f8c7dd5a4f31595927da7 + + + + 6868285482bd505c881a7a924e12520b99bd787b + + + + + 094eb07738bc769a2f096e01d7de5deb7ed1bf7f + + + + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + ./config/feature-options/DUK_OPT_REFCOUNT16.yaml + + + + + + + + + + fb4f806e7282dd3cb2df04e228672d8b0b1b8eb4 + + + + 3ee8cbebe37e0827b04d002290095a23cc82e5f6 + + + + + 4b03ca29c30e2b3434b3f5c930eed2fb44504b62 + + + + cc84b5894800d434ab9ce8ab3a1aef077f709506 + + + + + d664591350383e69ece0d236f7b894f7d4480825 + + + + + ac022f3e4f0eab8c6b25c2f575b93961dccee24b + + + + + + + a80d9739d96708035b6a7d05f66337af84aa602f + + + + + + + ./extras/duk-v1-compat/duk_v1_compat.c + Copyright 2013-2017 Duktape authors (see AUTHORS.rst in the Duktape distributable) + + + + + + 83bfbbdd3274c936a98649b5f119ec9e4b62b7e4 + + + + + f694db88f8f386765f48a44d846b3660d8139ff1 + + + + + c2223c5141efb9a995688c6e9b57fca2a06175d5 + + + 7216d147f8036390c8b6b2e32daa9cf30c5432fb + + + + + + + ed5f57f06ed4c688667789d238c7dcbf53741a7f + + + + + 97f183cd870ccdfcd5335c6c8a2cf4ce6bd79345 + + + + + 53977e24e3f60006deb0d7dc6760e1373487e77c + + + + ec4eb4acda5042e218ce3f3d68d34e2c83a0f9f9 + + + + + + bc37be576519d2713e5f18496e6ad167978d0785 + + + 668528794e352f0feabf78b468367d28edd237d1 + ./license.spdx + + + + 00b024d1353868edf2fe4c7d35d57218f14be057 + + + + 953bf4a23e29bbd4b7b0a4995601c260df36dc2e + + + + + + + 7ed28894fd636d138d031ca9c80efa4e80b51cf1 + + + 734d4f4a2f28b6b3df4db12a5bc6b2b84816370b + + + + + + + fec8c0387ddc9798b79b51f6f6f0a8303e8c8a54 + + + 3105fff8fd515c3e8158f29e2bf1741e183f3e9b + + + + + + 953bf4a23e29bbd4b7b0a4995601c260df36dc2e + + + + + + 5f89917c0262574a299a19edd39ed1d4802162f3 + + + + + 276b3344cb3ec7e583a4aaac7d227fa072a5cfa9 + + + + + 6b2c192574f557fed386580cf37d682a80e0140c + + + 5c1f5491c0f39e04f769dd4d3708b0a1908142c0 + + + + + + + 8a0985b15edda0391b5dda6b84a20fdc89376cc2 + + + + bb94ce16f0e382c5f77d3f25b34f98dbb3774c0f + + + + + + 160be49b60f1ff1e125f0524859e86644ca5bf43 + + + 1eb50379d9666232283722a2b9e18ebbd8a4d036 + + + + + + + 4db06fd9d96853165d9c5bb92d722ee87649081a + + + + 654056dc71de1907e361d2b599340fe38b220560 + + + + + + 2223a8b8b21e21ef47c78aa41fa9627bee40b06a + + + 684fe1ca1b6a79846dbe3abe73d96283f56a4b83 + + + + + + + 13165d92cb30f0ac3aa1e6c9234fbc2d07d36d7d + + + + + 628cfed456403b766eddbfb9bcafa9f0c671bded + + + + + 9a21e86bf65e62f1f979246134e511a0d8108f46 + + + 734d4f4a2f28b6b3df4db12a5bc6b2b84816370b + + + + + + + 18a9c1521f2a53697cf6ccf61aa850e7e0b8b362 + + + bd26962a105f83f1e4df97454ac7fdc01ed2454a + + + + + + 965499f07831f2cb69ad089d16ae8f9facffcaf0 + + + + a08e43879af86c86670dbbaa10af31e4ad8e5951 + + + + + + dfc0b1246ddd75506dc4b3794f906baf7f5c687e + + + + + b3f724fbb8bb68408ab3050e12f8e99e98994847 + + + + da20e9f1611f46a870cad37c93aeaf0c1cdde7aa + + + + + 5d593ae6316ed7a3ea6e7ed0a47267745d79d12d + + + + + + 7d69dfa4ed9ac49764f35ea4311614da1913a9e2 + + + + 887a666e371f4aa5b2f5617f1a8bd10a270b4521 + + + + + 60725c57ad6151972c19a7610899387b488ec288 + + + + + + b6d0d99431d64f47e5a8086a8ca2d7b5af5f1568 + + + + 4baffeb2aa785bdc1065eb9ddb8c64c8a028655d + + + + + + + 87f41b56b797d2de4b8b4d1e50582eebe6cbb736 + + + + bc37be576519d2713e5f18496e6ad167978d0785 + + + + 24f7bfa5a1caaf8b8f82d94641cc753712890e41 + + + + + + + 733d6afac621170edff24ebb5cd5f9cbabcbf8b7 + + + + 325633587f490f79810f78f19ef7ca4b263b4847 + diff -Nru duktape-2.0.0/Makefile.sharedlibrary duktape-2.1.1/Makefile.sharedlibrary --- duktape-2.0.0/Makefile.sharedlibrary 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/Makefile.sharedlibrary 2017-07-28 22:05:08.000000000 +0000 @@ -24,8 +24,8 @@ # convention is to set soname version to (100*MAJOR + MINOR), e.g. 104 for # Duktape 1.4.x, so that it gets automatically bumped for major and minor # releases (potentially binary incompatible), but not for patch releases. -DUK_VERSION=20000 -SONAME_VERSION=200 +DUK_VERSION=20101 +SONAME_VERSION=201 REAL_VERSION=$(SONAME_VERSION).$(DUK_VERSION) # Change to actual path for actual distribution packaging. diff -Nru duktape-2.0.0/polyfills/global.js duktape-2.1.1/polyfills/global.js --- duktape-2.0.0/polyfills/global.js 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/polyfills/global.js 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,15 @@ +/* + * Duktape 2.1.0 adds a 'global' binding. Polyfill for earlier versions. + */ + +if (typeof global === 'undefined') { + (function () { + var global = new Function('return this;')(); + Object.defineProperty(global, 'global', { + value: global, + writable: true, + enumerable: false, + configurable: true + }); + })(); +} diff -Nru duktape-2.0.0/README.rst duktape-2.1.1/README.rst --- duktape-2.0.0/README.rst 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/README.rst 2017-07-28 22:05:08.000000000 +0000 @@ -116,9 +116,13 @@ You can find release notes at: * https://github.com/svaarala/duktape/blob/master/RELEASES.rst + (summary of all versions) -This distributable contains Duktape version 2.0.0, created from git -commit 4180966c47d6d87106008dd4338de8d507c8072b (v2.0.0). +* https://github.com/svaarala/duktape/blob/master/doc/release-notes-v2-1.rst + (more detailed notes for this version) + +This distributable contains Duktape version 2.1.1, created from git +commit 9c8fba6392d1913cb5359be7b8f386fa3cdd8b4d (v2.1.1). Duktape is copyrighted by its authors (see ``AUTHORS.rst``) and licensed under the MIT license (see ``LICENSE.txt``). String hashing algorithms are diff -Nru duktape-2.0.0/src/duk_config.h duktape-2.1.1/src/duk_config.h --- duktape-2.0.0/src/duk_config.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src/duk_config.h 2017-07-28 22:05:08.000000000 +0000 @@ -1,9 +1,9 @@ /* * duk_config.h configuration header generated by genconfig.py. * - * Git commit: 4180966c47d6d87106008dd4338de8d507c8072b - * Git describe: v2.0.0 - * Git branch: master + * Git commit: 9c8fba6392d1913cb5359be7b8f386fa3cdd8b4d + * Git describe: v2.1.1 + * Git branch: v2.1-maintenance * * Supported platforms: * - Mac OSX, iPhone, Darwin @@ -12,6 +12,7 @@ * - Generic BSD * - Atari ST TOS * - AmigaOS + * - Durango (XboxOne) * - Windows * - Flashplayer (Crossbridge) * - QNX @@ -19,6 +20,8 @@ * - Emscripten * - Linux * - Solaris + * - AIX + * - HPUX * - Generic POSIX * - Cygwin * - Generic UNIX @@ -126,6 +129,11 @@ #endif #endif +/* Durango (Xbox One) */ +#if defined(_DURANGO) || defined(_XBOX_ONE) +#define DUK_F_DURANGO +#endif + /* Windows, both 32-bit and 64-bit */ #if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || \ defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__) @@ -170,6 +178,28 @@ /* illumos / Solaris */ #if defined(__sun) && defined(__SVR4) #define DUK_F_SUN +#if defined(__SUNPRO_C) && (__SUNPRO_C < 0x550) +#define DUK_F_OLD_SOLARIS +/* Defines _ILP32 / _LP64 required by DUK_F_X86/DUK_F_X64. Platforms + * are processed before architectures, so this happens before the + * DUK_F_X86/DUK_F_X64 detection is emitted. + */ +#include +#endif +#endif + +/* AIX */ +#if defined(_AIX) +/* defined(__xlc__) || defined(__IBMC__): works but too wide */ +#define DUK_F_AIX +#endif + +/* HPUX */ +#if defined(__hpux) +#define DUK_F_HPUX +#if defined(__ia64) +#define DUK_F_HPUX_ITANIUM +#endif #endif /* POSIX */ @@ -188,17 +218,6 @@ #define DUK_F_UNIX #endif -/* stdint.h not available */ -#if defined(DUK_F_WINDOWS) && defined(_MSC_VER) -#if (_MSC_VER < 1700) -/* VS2012+ has stdint.h, < VS2012 does not (but it's available for download). */ -#define DUK_F_NO_STDINT_H -#endif -#endif -#if !defined(DUK_F_NO_STDINT_H) && (defined(DUK_F_TOS) || defined(DUK_F_BCC)) -#define DUK_F_NO_STDINT_H -#endif - /* C++ */ #undef DUK_F_CPP #if defined(__cplusplus) @@ -208,6 +227,9 @@ /* Intel x86 (32-bit), x64 (64-bit) or x32 (64-bit but 32-bit pointers), * define only one of DUK_F_X86, DUK_F_X64, DUK_F_X32. * https://sites.google.com/site/x32abi/ + * + * With DUK_F_OLD_SOLARIS the header must be included + * before this. */ #if defined(__amd64__) || defined(__amd64) || \ defined(__x86_64__) || defined(__x86_64) || \ @@ -334,6 +356,15 @@ #define DUK_F_VBCC #endif +#if defined(ANDROID) || defined(__ANDROID__) +#define DUK_F_ANDROID +#endif + +/* Atari Mint */ +#if defined(__MINT__) +#define DUK_F_MINT +#endif + /* * Platform autodetection */ @@ -458,6 +489,40 @@ #if !defined(DUK_USE_BYTEORDER) && (defined(DUK_F_M68K) || defined(DUK_F_PPC)) #define DUK_USE_BYTEORDER 3 #endif +#elif defined(DUK_F_DURANGO) +/* --- Durango (XboxOne) --- */ +/* Durango = XboxOne + * Configuration is nearly identical to Windows, except for + * DUK_USE_DATE_TZO_WINDOWS. + */ + +/* Initial fix: disable secure CRT related warnings when compiling Duktape + * itself (must be defined before including Windows headers). Don't define + * for user code including duktape.h. + */ +#if defined(DUK_COMPILING_DUKTAPE) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +/* MSVC does not have sys/param.h */ +#define DUK_USE_DATE_NOW_WINDOWS +#define DUK_USE_DATE_TZO_WINDOWS_NO_DST +/* Note: PRS and FMT are intentionally left undefined for now. This means + * there is no platform specific date parsing/formatting but there is still + * the ISO 8601 standard format. + */ +#if defined(DUK_COMPILING_DUKTAPE) +/* Only include when compiling Duktape to avoid polluting application build + * with a lot of unnecessary defines. + */ +#include +#endif + +#define DUK_USE_OS_STRING "durango" + +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif #elif defined(DUK_F_WINDOWS) /* --- Windows --- */ /* Initial fix: disable secure CRT related warnings when compiling Duktape @@ -527,6 +592,10 @@ #define DUK_USE_OS_STRING "qnx" #elif defined(DUK_F_TINSPIRE) /* --- TI-Nspire --- */ +#if defined(DUK_COMPILING_DUKTAPE) && !defined(_XOPEN_SOURCE) +#define _XOPEN_SOURCE /* e.g. strptime */ +#endif + #define DUK_USE_DATE_NOW_GETTIMEOFDAY #define DUK_USE_DATE_TZO_GMTIME_R #define DUK_USE_DATE_PRS_STRPTIME @@ -607,12 +676,50 @@ #define DUK_USE_DATE_FMT_STRFTIME #include +#if defined(DUK_F_OLD_SOLARIS) +/* Old Solaris with no endian.h, stdint.h */ +#define DUK_F_NO_STDINT_H +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#else /* DUK_F_OLD_SOLARIS */ #include +#endif /* DUK_F_OLD_SOLARIS */ + #include #include #include #define DUK_USE_OS_STRING "solaris" +#elif defined(DUK_F_AIX) +/* --- AIX --- */ +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include + +#define DUK_USE_OS_STRING "aix" +#elif defined(DUK_F_HPUX) +/* --- HPUX --- */ +#define DUK_F_NO_STDINT_H +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include + +#define DUK_USE_OS_STRING "hpux" #elif defined(DUK_F_POSIX) /* --- Generic POSIX --- */ #define DUK_USE_DATE_NOW_GETTIMEOFDAY @@ -769,12 +876,8 @@ /* --- MIPS 32-bit --- */ #define DUK_USE_ARCH_STRING "mips32" /* MIPS byte order varies so rely on autodetection. */ -/* Based on 'make checkalign' there are no alignment requirements on - * Linux MIPS except for doubles, which need align by 4. Alignment - * requirements vary based on target though. - */ #if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 4 +#define DUK_USE_ALIGN_BY 8 #endif #define DUK_USE_PACKED_TVAL #define DUK_F_PACKED_TVAL_PROVIDED @@ -782,9 +885,6 @@ /* --- MIPS 64-bit --- */ #define DUK_USE_ARCH_STRING "mips64" /* MIPS byte order varies so rely on autodetection. */ -/* Good default is a bit arbitrary because alignment requirements - * depend on target. See https://github.com/svaarala/duktape/issues/102. - */ #if !defined(DUK_USE_ALIGN_BY) #define DUK_USE_ALIGN_BY 8 #endif @@ -908,6 +1008,9 @@ #define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) #endif +/* DUK_HOT */ +/* DUK_COLD */ + #if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) /* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're * compiling Duktape or the application. @@ -1018,6 +1121,12 @@ #define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) #endif +#if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && \ + defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40300) +#define DUK_HOT __attribute__((hot)) +#define DUK_COLD __attribute__((cold)) +#endif + #if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) /* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're * compiling Duktape or the application. @@ -1424,10 +1533,14 @@ #if defined(DUK_F_X86) || defined(DUK_F_X32) || \ defined(DUK_F_M68K) || defined(DUK_F_PPC32) || \ defined(DUK_F_BCC) || \ - (defined(__WORDSIZE) && (__WORDSIZE == 32)) + (defined(__WORDSIZE) && (__WORDSIZE == 32)) || \ + ((defined(DUK_F_OLD_SOLARIS) || defined(DUK_F_AIX) || \ + defined(DUK_F_HPUX)) && defined(_ILP32)) #define DUK_F_32BIT_PTRS #elif defined(DUK_F_X64) || \ - (defined(__WORDSIZE) && (__WORDSIZE == 64)) + (defined(__WORDSIZE) && (__WORDSIZE == 64)) || \ + ((defined(DUK_F_OLD_SOLARIS) || defined(DUK_F_AIX) || \ + defined(DUK_F_HPUX)) && defined(_LP64)) #define DUK_F_64BIT_PTRS #else /* not sure, not needed with C99 anyway */ @@ -2050,7 +2163,8 @@ #define DUK_DOUBLE_INFINITY (__builtin_inf()) #elif defined(INFINITY) #define DUK_DOUBLE_INFINITY ((double) INFINITY) -#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) +#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) && \ + !defined(DUK_F_OLD_SOLARIS) && !defined(DUK_F_AIX) #define DUK_DOUBLE_INFINITY (1.0 / 0.0) #else /* In VBCC (1.0 / 0.0) results in a warning and 0.0 instead of infinity. @@ -2066,7 +2180,8 @@ #undef DUK_USE_COMPUTED_NAN #if defined(NAN) #define DUK_DOUBLE_NAN NAN -#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) +#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) && \ + !defined(DUK_F_OLD_SOLARIS) && !defined(DUK_F_AIX) #define DUK_DOUBLE_NAN (0.0 / 0.0) #else /* In VBCC (0.0 / 0.0) results in a warning and 0.0 instead of NaN. @@ -2115,6 +2230,9 @@ * To be safe, use replacements. */ #define DUK_F_USE_REPL_ALL +#elif defined(DUK_F_AIX) +/* Older versions may be missing isnan(), etc. */ +#define DUK_F_USE_REPL_ALL #endif #if defined(DUK_F_USE_REPL_ALL) @@ -2203,9 +2321,10 @@ /* The functions below exist only in C99/C++11 or later and need a workaround * for platforms that don't include them. MSVC isn't detected as C99, but * these functions also exist in MSVC 2013 and later so include a clause for - * that too. + * that too. Android doesn't have log2; disable all of these for Android. */ -#if defined(DUK_F_C99) || defined(DUK_F_CPP11) || (defined(_MSC_VER) && (_MSC_VER >= 1800)) +#if (defined(DUK_F_C99) || defined(DUK_F_CPP11) || (defined(_MSC_VER) && (_MSC_VER >= 1800))) && \ + !defined(DUK_F_ANDROID) && !defined(DUK_F_MINT) #if !defined(DUK_CBRT) #define DUK_CBRT cbrt #endif @@ -2218,7 +2337,7 @@ #if !defined(DUK_TRUNC) #define DUK_TRUNC trunc #endif -#endif /* DUK_F_C99 */ +#endif /* DUK_F_C99 etc */ /* NetBSD 6.0 x86 (at least) has a few problems with pow() semantics, * see test-bug-netbsd-math-pow.js. MinGW has similar (but different) @@ -2431,7 +2550,8 @@ /* Macro for suppressing warnings for potentially unreferenced variables. * The variables can be actually unreferenced or unreferenced in some * specific cases only; for instance, if a variable is only debug printed, - * it is unreferenced when debug printing is disabled. + * it is unreferenced when debug printing is disabled. May cause warnings + * for volatile arguments. */ #define DUK_UNREF(x) do { (void) (x); } while (0) #endif @@ -2473,6 +2593,13 @@ #define DUK_ALWAYS_INLINE /*nop*/ #endif +#if !defined(DUK_HOT) +#define DUK_HOT /*nop*/ +#endif +#if !defined(DUK_COLD) +#define DUK_COLD /*nop*/ +#endif + #if !defined(DUK_EXTERNAL_DECL) #define DUK_EXTERNAL_DECL extern #endif @@ -2696,6 +2823,7 @@ #define DUK_USE_FAST_REFCOUNT_DEFAULT #undef DUK_USE_FATAL_HANDLER #define DUK_USE_FINALIZER_SUPPORT +#undef DUK_USE_FINALIZER_TORTURE #undef DUK_USE_FUNCPTR16 #undef DUK_USE_FUNCPTR_DEC16 #undef DUK_USE_FUNCPTR_ENC16 @@ -2704,16 +2832,26 @@ #define DUK_USE_FUNC_NAME_PROPERTY #undef DUK_USE_GC_TORTURE #undef DUK_USE_GET_RANDOM_DOUBLE +#undef DUK_USE_GLOBAL_BINDING #define DUK_USE_GLOBAL_BUILTIN #undef DUK_USE_HEAPPTR16 #undef DUK_USE_HEAPPTR_DEC16 #undef DUK_USE_HEAPPTR_ENC16 #define DUK_USE_HEX_FASTPATH +#define DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT 2 +#define DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT 9 +#define DUK_USE_HOBJECT_ARRAY_MINGROW_ADD 16 +#define DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR 8 +#define DUK_USE_HOBJECT_ENTRY_MINGROW_ADD 16 +#define DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR 8 #define DUK_USE_HOBJECT_HASH_PART +#define DUK_USE_HOBJECT_HASH_PROP_LIMIT 8 #define DUK_USE_HSTRING_ARRIDX #define DUK_USE_HSTRING_CLEN #undef DUK_USE_HSTRING_EXTDATA +#define DUK_USE_HTML_COMMENTS #define DUK_USE_IDCHAR_FASTPATH +#undef DUK_USE_INJECT_HEAP_ALLOC_ERROR #undef DUK_USE_INTERRUPT_COUNTER #undef DUK_USE_INTERRUPT_DEBUG_FIXUP #define DUK_USE_JC @@ -2729,10 +2867,8 @@ #define DUK_USE_JX #define DUK_USE_LEXER_SLIDING_WINDOW #undef DUK_USE_LIGHTFUNC_BUILTINS -#undef DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE #define DUK_USE_MARK_AND_SWEEP_RECLIMIT 256 #define DUK_USE_MATH_BUILTIN -#define DUK_USE_MS_STRINGTABLE_RESIZE #define DUK_USE_NATIVE_CALL_RECLIMIT 1000 #define DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER #define DUK_USE_NONSTD_ARRAY_MAP_TRAILER @@ -2752,9 +2888,9 @@ #undef DUK_USE_PREFER_SIZE #define DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS #undef DUK_USE_REFCOUNT16 +#define DUK_USE_REFCOUNT32 #define DUK_USE_REFERENCE_COUNTING #define DUK_USE_REFLECT_BUILTIN -#undef DUK_USE_REFZERO_FINALIZER_TORTURE #undef DUK_USE_REGEXP_CANON_WORKAROUND #define DUK_USE_REGEXP_COMPILER_RECLIMIT 10000 #define DUK_USE_REGEXP_EXECUTOR_RECLIMIT 10000 @@ -2766,6 +2902,7 @@ #undef DUK_USE_ROM_STRINGS #define DUK_USE_SECTION_B #undef DUK_USE_SELF_TESTS +#define DUK_USE_SHEBANG_COMMENTS #undef DUK_USE_SHUFFLE_TORTURE #define DUK_USE_SOURCE_NONBMP #undef DUK_USE_STRHASH16 @@ -2775,9 +2912,13 @@ #undef DUK_USE_STRICT_UTF8_SOURCE #define DUK_USE_STRING_BUILTIN #undef DUK_USE_STRLEN16 -#undef DUK_USE_STRTAB_CHAIN -#undef DUK_USE_STRTAB_CHAIN_SIZE -#define DUK_USE_STRTAB_PROBE +#define DUK_USE_STRTAB_GROW_LIMIT 17 +#define DUK_USE_STRTAB_MAXSIZE 268435456L +#define DUK_USE_STRTAB_MINSIZE 1024 +#undef DUK_USE_STRTAB_PTRCOMP +#define DUK_USE_STRTAB_RESIZE_CHECK_MASK 255 +#define DUK_USE_STRTAB_SHRINK_LIMIT 6 +#undef DUK_USE_STRTAB_TORTURE #undef DUK_USE_SYMBOL_BUILTIN #define DUK_USE_TAILCALL #define DUK_USE_TARGET_INFO "unknown" @@ -2822,10 +2963,12 @@ #if defined(DUK_USE_DATE_GET_LOCAL_TZOFFSET) /* External provider already defined. */ -#elif defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME) +#elif defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S) || defined(DUK_USE_DATE_TZO_GMTIME) #define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_gmtime((d)) #elif defined(DUK_USE_DATE_TZO_WINDOWS) #define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows((d)) +#elif defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST) +#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows_no_dst((d)) #else #error no provider for DUK_USE_DATE_GET_LOCAL_TZOFFSET() #endif @@ -3307,6 +3450,9 @@ #if defined(DUK_USE_INTEGER_ME) && defined(DUK_USE_INTEGER_BE) #error config option DUK_USE_INTEGER_ME conflicts with option DUK_USE_INTEGER_BE (which is also defined) #endif +#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE) +#error unsupported config option used (option has been removed): DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE +#endif #if defined(DUK_USE_MARK_AND_SWEEP) #error unsupported config option used (option has been removed): DUK_USE_MARK_AND_SWEEP #endif @@ -3319,6 +3465,9 @@ #if defined(DUK_USE_MATH_ROUND) #error unsupported config option used (option has been removed): DUK_USE_MATH_ROUND #endif +#if defined(DUK_USE_MS_STRINGTABLE_RESIZE) +#error unsupported config option used (option has been removed): DUK_USE_MS_STRINGTABLE_RESIZE +#endif #if defined(DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE) #error unsupported config option used (option has been removed): DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE #endif @@ -3349,6 +3498,9 @@ #if defined(DUK_USE_RDTSC) #error unsupported config option used (option has been removed): DUK_USE_RDTSC #endif +#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE) +#error unsupported config option used (option has been removed): DUK_USE_REFZERO_FINALIZER_TORTURE +#endif #if defined(DUK_USE_ROM_GLOBAL_CLONE) && !defined(DUK_USE_ROM_STRINGS) #error config option DUK_USE_ROM_GLOBAL_CLONE requires option DUK_USE_ROM_STRINGS (which is missing) #endif @@ -3379,9 +3531,21 @@ #if defined(DUK_USE_SIGSETJMP) #error unsupported config option used (option has been removed): DUK_USE_SIGSETJMP #endif +#if defined(DUK_USE_STRTAB_CHAIN) +#error unsupported config option used (option has been removed): DUK_USE_STRTAB_CHAIN +#endif +#if defined(DUK_USE_STRTAB_CHAIN_SIZE) +#error unsupported config option used (option has been removed): DUK_USE_STRTAB_CHAIN_SIZE +#endif #if defined(DUK_USE_STRTAB_CHAIN_SIZE) && !defined(DUK_USE_STRTAB_CHAIN) #error config option DUK_USE_STRTAB_CHAIN_SIZE requires option DUK_USE_STRTAB_CHAIN (which is missing) #endif +#if defined(DUK_USE_STRTAB_PROBE) +#error unsupported config option used (option has been removed): DUK_USE_STRTAB_PROBE +#endif +#if defined(DUK_USE_STRTAB_PTRCOMP) && !defined(DUK_USE_HEAPPTR16) +#error config option DUK_USE_STRTAB_PTRCOMP requires option DUK_USE_HEAPPTR16 (which is missing) +#endif #if defined(DUK_USE_TAILCALL) && defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) #error config option DUK_USE_TAILCALL conflicts with option DUK_USE_NONSTD_FUNC_CALLER_PROPERTY (which is also defined) #endif diff -Nru duktape-2.0.0/src/duk_source_meta.json duktape-2.1.1/src/duk_source_meta.json --- duktape-2.0.0/src/duk_source_meta.json 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src/duk_source_meta.json 2017-07-28 22:05:08.000000000 +0000 @@ -1,652 +1,662 @@ { - "comment": "Metadata for Duktape build", - "duk_version_string": "2.0.0", + "comment": "Metadata for Duktape sources", + "duk_version_string": "2.1.1", "type": "duk_source_meta", "line_map": [ { "original_line": 1, - "combined_line": 129, + "combined_line": 131, "original_file": "duk_replacements.c" }, { "original_line": 1, - "combined_line": 139, + "combined_line": 141, "original_file": "duk_internal.h" }, { "original_line": 1, - "combined_line": 184, + "combined_line": 186, + "original_file": "duk_dblunion.h" + }, + { + "original_line": 1, + "combined_line": 611, "original_file": "duk_replacements.h" }, { "original_line": 1, - "combined_line": 215, + "combined_line": 642, "original_file": "duk_jmpbuf.h" }, { "original_line": 1, - "combined_line": 241, + "combined_line": 668, "original_file": "duk_exception.h" }, { "original_line": 1, - "combined_line": 261, + "combined_line": 688, "original_file": "duk_forwdecl.h" }, { "original_line": 1, - "combined_line": 387, + "combined_line": 818, "original_file": "duk_tval.h" }, { "original_line": 1, - "combined_line": 1021, + "combined_line": 1452, "original_file": "duk_builtins.h" }, { - "original_line": 50, - "combined_line": 1815, + "original_line": 51, + "combined_line": 2239, "original_file": "duk_internal.h" }, { "original_line": 1, - "combined_line": 1818, + "combined_line": 2242, "original_file": "duk_util.h" }, { "original_line": 1, - "combined_line": 2386, + "combined_line": 2803, "original_file": "duk_strings.h" }, { "original_line": 1, - "combined_line": 2547, + "combined_line": 2965, "original_file": "duk_js_bytecode.h" }, { "original_line": 1, - "combined_line": 3021, + "combined_line": 3438, "original_file": "duk_lexer.h" }, { "original_line": 1, - "combined_line": 3457, + "combined_line": 3876, "original_file": "duk_js_compiler.h" }, { "original_line": 1, - "combined_line": 3690, + "combined_line": 4105, "original_file": "duk_regexp.h" }, { "original_line": 1, - "combined_line": 3776, + "combined_line": 4191, "original_file": "duk_heaphdr.h" }, { "original_line": 1, - "combined_line": 4712, + "combined_line": 4498, + "original_file": "duk_refcount.h" + }, + { + "original_line": 1, + "combined_line": 5198, "original_file": "duk_api_internal.h" }, { "original_line": 1, - "combined_line": 5024, + "combined_line": 5512, "original_file": "duk_hstring.h" }, { "original_line": 1, - "combined_line": 5259, + "combined_line": 5740, "original_file": "duk_hobject.h" }, { "original_line": 1, - "combined_line": 6222, + "combined_line": 6696, "original_file": "duk_hcompfunc.h" }, { "original_line": 1, - "combined_line": 6487, + "combined_line": 6961, "original_file": "duk_hnatfunc.h" }, { "original_line": 1, - "combined_line": 6521, + "combined_line": 6995, "original_file": "duk_hbufobj.h" }, { "original_line": 1, - "combined_line": 6665, + "combined_line": 7139, "original_file": "duk_hthread.h" }, { "original_line": 1, - "combined_line": 7067, + "combined_line": 7547, "original_file": "duk_harray.h" }, { "original_line": 1, - "combined_line": 7116, + "combined_line": 7596, + "original_file": "duk_henv.h" + }, + { + "original_line": 1, + "combined_line": 7646, "original_file": "duk_hbuffer.h" }, { "original_line": 1, - "combined_line": 7446, + "combined_line": 7976, "original_file": "duk_heap.h" }, { "original_line": 1, - "combined_line": 8058, + "combined_line": 8584, "original_file": "duk_debugger.h" }, { "original_line": 1, - "combined_line": 8205, + "combined_line": 8737, "original_file": "duk_debug.h" }, { "original_line": 1, - "combined_line": 8391, + "combined_line": 8923, "original_file": "duk_error.h" }, { "original_line": 1, - "combined_line": 8875, + "combined_line": 9410, "original_file": "duk_unicode.h" }, { "original_line": 1, - "combined_line": 9155, + "combined_line": 9690, "original_file": "duk_json.h" }, { "original_line": 1, - "combined_line": 9225, + "combined_line": 9760, "original_file": "duk_js.h" }, { "original_line": 1, - "combined_line": 9330, + "combined_line": 9868, "original_file": "duk_numconv.h" }, { "original_line": 1, - "combined_line": 9432, + "combined_line": 9970, "original_file": "duk_bi_protos.h" }, { "original_line": 1, - "combined_line": 9502, + "combined_line": 10043, "original_file": "duk_selftest.h" }, { - "original_line": 77, - "combined_line": 9518, + "original_line": 80, + "combined_line": 10059, "original_file": "duk_internal.h" }, { "original_line": 10, - "combined_line": 9521, + "combined_line": 10062, "original_file": "duk_replacements.c" }, { "original_line": 1, - "combined_line": 9595, + "combined_line": 10136, "original_file": "duk_debug_macros.c" }, { "original_line": 1, - "combined_line": 9687, + "combined_line": 10228, "original_file": "duk_builtins.c" }, { "original_line": 1, - "combined_line": 10450, + "combined_line": 11008, "original_file": "duk_error_macros.c" }, { "original_line": 1, - "combined_line": 10587, + "combined_line": 11145, "original_file": "duk_unicode_support.c" }, { "original_line": 1, - "combined_line": 11771, + "combined_line": 12329, "original_file": "duk_util_misc.c" }, { "original_line": 1, - "combined_line": 12177, - "original_file": "duk_util_hashprime.c" - }, - { - "original_line": 1, - "combined_line": 12258, + "combined_line": 12735, "original_file": "duk_hobject_class.c" }, { "original_line": 1, - "combined_line": 12388, + "combined_line": 12865, "original_file": "duk_alloc_default.c" }, { "original_line": 1, - "combined_line": 12423, + "combined_line": 12900, "original_file": "duk_api_buffer.c" }, { "original_line": 1, - "combined_line": 12497, + "combined_line": 12974, "original_file": "duk_api_bytecode.c" }, { "original_line": 1, - "combined_line": 13270, + "combined_line": 13767, "original_file": "duk_api_call.c" }, { "original_line": 1, - "combined_line": 13881, + "combined_line": 14396, "original_file": "duk_api_codec.c" }, { "original_line": 1, - "combined_line": 14537, + "combined_line": 15055, "original_file": "duk_api_compile.c" }, { "original_line": 1, - "combined_line": 14723, + "combined_line": 15228, "original_file": "duk_api_debug.c" }, { "original_line": 1, - "combined_line": 14993, + "combined_line": 15502, "original_file": "duk_api_heap.c" }, { "original_line": 1, - "combined_line": 15183, + "combined_line": 15712, "original_file": "duk_api_inspect.c" }, { "original_line": 1, - "combined_line": 15430, + "combined_line": 15960, "original_file": "duk_api_memory.c" }, { "original_line": 1, - "combined_line": 15525, + "combined_line": 16055, "original_file": "duk_api_object.c" }, { "original_line": 1, - "combined_line": 16257, + "combined_line": 16809, "original_file": "duk_api_stack.c" }, { "original_line": 1, - "combined_line": 21637, + "combined_line": 22651, "original_file": "duk_api_string.c" }, { "original_line": 1, - "combined_line": 21974, + "combined_line": 22990, "original_file": "duk_api_time.c" }, { "original_line": 1, - "combined_line": 22045, + "combined_line": 23061, "original_file": "duk_bi_array.c" }, { "original_line": 1, - "combined_line": 23664, + "combined_line": 24680, "original_file": "duk_bi_boolean.c" }, { "original_line": 1, - "combined_line": 23737, + "combined_line": 24753, "original_file": "duk_bi_buffer.c" }, { "original_line": 1, - "combined_line": 26721, + "combined_line": 27747, "original_file": "duk_bi_date.c" }, { "original_line": 1, - "combined_line": 28484, + "combined_line": 29511, "original_file": "duk_bi_date_unix.c" }, { "original_line": 1, - "combined_line": 28798, + "combined_line": 29825, "original_file": "duk_bi_date_windows.c" }, { "original_line": 1, - "combined_line": 28897, + "combined_line": 29956, "original_file": "duk_bi_duktape.c" }, { "original_line": 1, - "combined_line": 29063, + "combined_line": 30122, "original_file": "duk_bi_encoding.c" }, { "original_line": 1, - "combined_line": 29597, + "combined_line": 30659, "original_file": "duk_bi_error.c" }, { "original_line": 1, - "combined_line": 29994, + "combined_line": 31057, "original_file": "duk_bi_function.c" }, { "original_line": 1, - "combined_line": 30416, + "combined_line": 31481, "original_file": "duk_bi_global.c" }, { "original_line": 1, - "combined_line": 31141, + "combined_line": 32211, "original_file": "duk_bi_json.c" }, { "original_line": 1, - "combined_line": 34355, + "combined_line": 35485, "original_file": "duk_bi_math.c" }, { "original_line": 1, - "combined_line": 34781, + "combined_line": 35911, "original_file": "duk_bi_number.c" }, { "original_line": 1, - "combined_line": 35025, + "combined_line": 36155, "original_file": "duk_bi_object.c" }, { "original_line": 1, - "combined_line": 35832, + "combined_line": 36964, "original_file": "duk_bi_pointer.c" }, { "original_line": 1, - "combined_line": 35907, + "combined_line": 37040, "original_file": "duk_bi_proxy.c" }, { "original_line": 1, - "combined_line": 36057, + "combined_line": 37191, "original_file": "duk_bi_reflect.c" }, { "original_line": 1, - "combined_line": 36163, + "combined_line": 37297, "original_file": "duk_bi_regexp.c" }, { "original_line": 1, - "combined_line": 36392, + "combined_line": 37526, "original_file": "duk_bi_string.c" }, { "original_line": 1, - "combined_line": 37844, + "combined_line": 39089, "original_file": "duk_bi_symbol.c" }, { "original_line": 1, - "combined_line": 38016, + "combined_line": 39263, "original_file": "duk_bi_thread.c" }, { "original_line": 1, - "combined_line": 38326, + "combined_line": 39575, "original_file": "duk_bi_thrower.c" }, { "original_line": 1, - "combined_line": 38336, + "combined_line": 39585, "original_file": "duk_debug_fixedbuffer.c" }, { "original_line": 1, - "combined_line": 38406, + "combined_line": 39655, "original_file": "duk_debug_vsnprintf.c" }, { "original_line": 1, - "combined_line": 39433, + "combined_line": 40695, "original_file": "duk_debugger.c" }, { "original_line": 1, - "combined_line": 42242, + "combined_line": 43549, "original_file": "duk_error_augment.c" }, { "original_line": 1, - "combined_line": 42832, + "combined_line": 44139, "original_file": "duk_error_longjmp.c" }, { "original_line": 1, - "combined_line": 42920, + "combined_line": 44246, "original_file": "duk_error_misc.c" }, { "original_line": 1, - "combined_line": 43046, + "combined_line": 44424, "original_file": "duk_error_throw.c" }, { "original_line": 1, - "combined_line": 43208, + "combined_line": 44600, "original_file": "duk_hbuffer_alloc.c" }, { "original_line": 1, - "combined_line": 43341, + "combined_line": 44733, "original_file": "duk_hbuffer_ops.c" }, { "original_line": 2, - "combined_line": 43425, + "combined_line": 44817, "original_file": "duk_hbufobj_misc.c" }, { "original_line": 1, - "combined_line": 43445, + "combined_line": 44837, "original_file": "duk_heap_alloc.c" }, { "original_line": 1, - "combined_line": 44505, + "combined_line": 45950, + "original_file": "duk_heap_finalize.c" + }, + { + "original_line": 1, + "combined_line": 46400, "original_file": "duk_heap_hashstring.c" }, { "original_line": 1, - "combined_line": 44627, + "combined_line": 46522, "original_file": "duk_heap_markandsweep.c" }, { "original_line": 1, - "combined_line": 46063, + "combined_line": 47759, "original_file": "duk_heap_memory.c" }, { "original_line": 1, - "combined_line": 46407, + "combined_line": 48121, "original_file": "duk_heap_misc.c" }, { "original_line": 1, - "combined_line": 46487, + "combined_line": 48303, "original_file": "duk_heap_refcount.c" }, { "original_line": 1, - "combined_line": 47249, + "combined_line": 49119, "original_file": "duk_heap_stringcache.c" }, { "original_line": 1, - "combined_line": 47548, + "combined_line": 49429, "original_file": "duk_heap_stringtable.c" }, { "original_line": 1, - "combined_line": 48709, + "combined_line": 50405, "original_file": "duk_hobject_alloc.c" }, { "original_line": 1, - "combined_line": 48927, + "combined_line": 50645, "original_file": "duk_hobject_enum.c" }, { "original_line": 1, - "combined_line": 49701, - "original_file": "duk_hobject_finalizer.c" - }, - { - "original_line": 1, - "combined_line": 49815, + "combined_line": 51422, "original_file": "duk_hobject_misc.c" }, { "original_line": 1, - "combined_line": 49868, + "combined_line": 51475, "original_file": "duk_hobject_pc2line.c" }, { "original_line": 1, - "combined_line": 50118, + "combined_line": 51725, "original_file": "duk_hobject_props.c" }, { "original_line": 1, - "combined_line": 56166, + "combined_line": 57817, "original_file": "duk_hstring_misc.c" }, { "original_line": 1, - "combined_line": 56230, + "combined_line": 57956, "original_file": "duk_hthread_alloc.c" }, { "original_line": 1, - "combined_line": 56326, + "combined_line": 58054, "original_file": "duk_hthread_builtins.c" }, { "original_line": 1, - "combined_line": 57151, + "combined_line": 58899, "original_file": "duk_hthread_misc.c" }, { "original_line": 1, - "combined_line": 57260, + "combined_line": 59001, "original_file": "duk_hthread_stacks.c" }, { "original_line": 1, - "combined_line": 57737, + "combined_line": 59583, "original_file": "duk_js_arith.c" }, { "original_line": 1, - "combined_line": 57875, + "combined_line": 59721, "original_file": "duk_js_call.c" }, { "original_line": 1, - "combined_line": 60604, + "combined_line": 62496, "original_file": "duk_js_compiler.c" }, { "original_line": 1, - "combined_line": 68541, + "combined_line": 70454, "original_file": "duk_js_executor.c" }, { "original_line": 1, - "combined_line": 73651, + "combined_line": 75637, "original_file": "duk_js_ops.c" }, { "original_line": 1, - "combined_line": 75032, + "combined_line": 77063, "original_file": "duk_js_var.c" }, { "original_line": 1, - "combined_line": 76858, + "combined_line": 78821, "original_file": "duk_lexer.c" }, { "original_line": 1, - "combined_line": 79226, + "combined_line": 81281, "original_file": "duk_numconv.c" }, { "original_line": 1, - "combined_line": 81504, + "combined_line": 83559, "original_file": "duk_regexp_compiler.c" }, { "original_line": 1, - "combined_line": 82648, + "combined_line": 84703, "original_file": "duk_regexp_executor.c" }, { "original_line": 1, - "combined_line": 83674, + "combined_line": 85730, "original_file": "duk_selftest.c" }, { "original_line": 2, - "combined_line": 84303, + "combined_line": 86359, "original_file": "duk_tval.c" }, { "original_line": 1, - "combined_line": 84445, + "combined_line": 86501, "original_file": "duk_unicode_tables.c" }, { "original_line": 1, - "combined_line": 90587, + "combined_line": 92643, "original_file": "duk_util_bitdecoder.c" }, { "original_line": 1, - "combined_line": 90750, + "combined_line": 92810, "original_file": "duk_util_bitencoder.c" }, { "original_line": 1, - "combined_line": 90794, + "combined_line": 92854, "original_file": "duk_util_bufwriter.c" }, { "original_line": 1, - "combined_line": 91155, + "combined_line": 93215, "original_file": "duk_util_hashbytes.c" }, { "original_line": 1, - "combined_line": 91217, + "combined_line": 93277, "original_file": "duk_util_tinyrandom.c" } ], - "duk_version": 20000, - "git_branch": "master", - "git_commit": "4180966c47d6d87106008dd4338de8d507c8072b", + "duk_version": 20101, + "git_branch": "v2.1-maintenance", + "git_commit": "9c8fba6392d1913cb5359be7b8f386fa3cdd8b4d", "builtin_strings_info": [ { "plain": "Undefined", @@ -1129,6 +1139,11 @@ "define": "DUK_STRIDX_INT_PC2LINE" }, { + "plain": "\u00ffThis", + "base64": "/1RoaXM=", + "define": "DUK_STRIDX_INT_THIS" + }, + { "plain": "\u00ffArgs", "base64": "/0FyZ3M=", "define": "DUK_STRIDX_INT_ARGS" @@ -1149,34 +1164,14 @@ "define": "DUK_STRIDX_INT_FINALIZER" }, { - "plain": "\u00ffHandler", - "base64": "/0hhbmRsZXI=", - "define": "DUK_STRIDX_INT_HANDLER" - }, - { - "plain": "\u00ffCallee", - "base64": "/0NhbGxlZQ==", - "define": "DUK_STRIDX_INT_CALLEE" - }, - { - "plain": "\u00ffThread", - "base64": "/1RocmVhZA==", - "define": "DUK_STRIDX_INT_THREAD" - }, - { - "plain": "\u00ffRegbase", - "base64": "/1JlZ2Jhc2U=", - "define": "DUK_STRIDX_INT_REGBASE" - }, - { "plain": "\u00ffTarget", "base64": "/1RhcmdldA==", "define": "DUK_STRIDX_INT_TARGET" }, { - "plain": "\u00ffThis", - "base64": "/1RoaXM=", - "define": "DUK_STRIDX_INT_THIS" + "plain": "\u00ffHandler", + "base64": "/0hhbmRsZXI=", + "define": "DUK_STRIDX_INT_HANDLER" }, { "plain": "compile", @@ -1581,16 +1576,13 @@ "/1Zhcm1hcA==", "/1NvdXJjZQ==", "/1BjMmxpbmU=", + "/1RoaXM=", "/0FyZ3M=", "/01hcA==", "/1ZhcmVudg==", "/0ZpbmFsaXplcg==", - "/0hhbmRsZXI=", - "/0NhbGxlZQ==", - "/1RocmVhZA==", - "/1JlZ2Jhc2U=", "/1RhcmdldA==", - "/1RoaXM=", + "/0hhbmRsZXI=", "Y29tcGlsZQ==", "aW5wdXQ=", "ZXJyQ3JlYXRl", @@ -1653,7 +1645,7 @@ "c3RhdGlj", "eWllbGQ=" ], - "git_describe": "v2.0.0", + "git_describe": "v2.1.1", "builtin_strings": [ "Undefined", "Null", @@ -1751,16 +1743,13 @@ "\u00ffVarmap", "\u00ffSource", "\u00ffPc2line", + "\u00ffThis", "\u00ffArgs", "\u00ffMap", "\u00ffVarenv", "\u00ffFinalizer", - "\u00ffHandler", - "\u00ffCallee", - "\u00ffThread", - "\u00ffRegbase", "\u00ffTarget", - "\u00ffThis", + "\u00ffHandler", "compile", "input", "errCreate", diff -Nru duktape-2.0.0/src/duktape.c duktape-2.1.1/src/duktape.c --- duktape-2.0.0/src/duktape.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src/duktape.c 2017-07-28 22:05:08.000000000 +0000 @@ -1,8 +1,8 @@ /* - * Single source autogenerated distributable for Duktape 2.0.0. + * Single source autogenerated distributable for Duktape 2.1.1. * - * Git commit 4180966c47d6d87106008dd4338de8d507c8072b (v2.0.0). - * Git branch master. + * Git commit 9c8fba6392d1913cb5359be7b8f386fa3cdd8b4d (v2.1.1). + * Git branch v2.1-maintenance. * * See Duktape AUTHORS.rst and LICENSE.txt for copyright and * licensing information. @@ -82,6 +82,8 @@ * * Brett Vickers (https://github.com/beevik) * * Dominik Okwieka (https://github.com/okitec) * * Remko Tron\u00e7on (https://el-tramo.be) +* * Romero Malaquias (rbsm@ic.ufal.br) +* * Michael Drake * * Other contributions * =================== @@ -179,6 +181,431 @@ * dependencies. */ +/* #include duk_dblunion.h */ +#line 1 "duk_dblunion.h" +/* + * 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/cross endian (e.g. ARM) DUK_USE_DOUBLE_ME + * + * ARM is a special case: ARM double values are in mixed/cross 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. + * + * 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] = 0x000000007ff80000ULL; \ + } while (0) +#define DUK__DBLUNION_IS_NAN_FULL(u) \ + ((((u)->ull[DUK_DBL_IDX_ULL0] & 0x000000007ff00000ULL) == 0x000000007ff00000ULL) && \ + ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0xffffffff000fffffULL) != 0)) +#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x000000007ff80000ULL) +#define DUK__DBLUNION_IS_ANYINF(u) \ + (((u)->ull[DUK_DBL_IDX_ULL0] & 0xffffffff7fffffffULL) == 0x000000007ff00000ULL) +#define DUK__DBLUNION_IS_POSINF(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x000000007ff00000ULL) +#define DUK__DBLUNION_IS_NEGINF(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x00000000fff00000ULL) +#define DUK__DBLUNION_IS_ANYZERO(u) \ + (((u)->ull[DUK_DBL_IDX_ULL0] & 0xffffffff7fffffffULL) == 0x0000000000000000ULL) +#define DUK__DBLUNION_IS_POSZERO(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000000000000ULL) +#define DUK__DBLUNION_IS_NEGZERO(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000080000000ULL) +#else +/* Macros for 64-bit ops + big/little endian doubles. */ +#define DUK__DBLUNION_SET_NAN_FULL(u) do { \ + (u)->ull[DUK_DBL_IDX_ULL0] = 0x7ff8000000000000ULL; \ + } while (0) +#define DUK__DBLUNION_IS_NAN_FULL(u) \ + ((((u)->ull[DUK_DBL_IDX_ULL0] & 0x7ff0000000000000ULL) == 0x7ff0000000000000UL) && \ + ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0x000fffffffffffffULL) != 0)) +#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x7ff8000000000000ULL) +#define DUK__DBLUNION_IS_ANYINF(u) \ + (((u)->ull[DUK_DBL_IDX_ULL0] & 0x7fffffffffffffffULL) == 0x7ff0000000000000ULL) +#define DUK__DBLUNION_IS_POSINF(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x7ff0000000000000ULL) +#define DUK__DBLUNION_IS_NEGINF(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0xfff0000000000000ULL) +#define DUK__DBLUNION_IS_ANYZERO(u) \ + (((u)->ull[DUK_DBL_IDX_ULL0] & 0x7fffffffffffffffULL) == 0x0000000000000000ULL) +#define DUK__DBLUNION_IS_POSZERO(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000000000000ULL) +#define DUK__DBLUNION_IS_NEGZERO(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x8000000000000000ULL) +#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] & 0x8000000000000000ULL) != 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 */ /* #include duk_replacements.h */ #line 1 "duk_replacements.h" #if !defined(DUK_REPLACEMENTS_H_INCLUDED) @@ -286,6 +713,8 @@ struct duk_hnatfunc; struct duk_hthread; struct duk_hbufobj; +struct duk_hdecenv; +struct duk_hobjenv; struct duk_hbuffer; struct duk_hbuffer_fixed; struct duk_hbuffer_dynamic; @@ -340,8 +769,10 @@ typedef struct duk_hobject duk_hobject; typedef struct duk_hcompfunc duk_hcompfunc; typedef struct duk_hnatfunc duk_hnatfunc; -typedef struct duk_hbufobj duk_hbufobj; 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_hbuffer duk_hbuffer; typedef struct duk_hbuffer_fixed duk_hbuffer_fixed; typedef struct duk_hbuffer_dynamic duk_hbuffer_dynamic; @@ -1316,233 +1747,224 @@ #define DUK_STRIDX_INT_PC2LINE 95 /* '\xffPc2line' */ #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_ARGS 96 /* '\xffArgs' */ +#define DUK_STRIDX_INT_THIS 96 /* '\xffThis' */ +#define DUK_HEAP_STRING_INT_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THIS) +#define DUK_HTHREAD_STRING_INT_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THIS) +#define DUK_STRIDX_INT_ARGS 97 /* '\xffArgs' */ #define DUK_HEAP_STRING_INT_ARGS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_ARGS) #define DUK_HTHREAD_STRING_INT_ARGS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_ARGS) -#define DUK_STRIDX_INT_MAP 97 /* '\xffMap' */ +#define DUK_STRIDX_INT_MAP 98 /* '\xffMap' */ #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 98 /* '\xffVarenv' */ +#define DUK_STRIDX_INT_VARENV 99 /* '\xffVarenv' */ #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 99 /* '\xffFinalizer' */ +#define DUK_STRIDX_INT_FINALIZER 100 /* '\xffFinalizer' */ #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_HANDLER 100 /* '\xffHandler' */ -#define DUK_HEAP_STRING_INT_HANDLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_HANDLER) -#define DUK_HTHREAD_STRING_INT_HANDLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_HANDLER) -#define DUK_STRIDX_INT_CALLEE 101 /* '\xffCallee' */ -#define DUK_HEAP_STRING_INT_CALLEE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_CALLEE) -#define DUK_HTHREAD_STRING_INT_CALLEE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_CALLEE) -#define DUK_STRIDX_INT_THREAD 102 /* '\xffThread' */ -#define DUK_HEAP_STRING_INT_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THREAD) -#define DUK_HTHREAD_STRING_INT_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THREAD) -#define DUK_STRIDX_INT_REGBASE 103 /* '\xffRegbase' */ -#define DUK_HEAP_STRING_INT_REGBASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_REGBASE) -#define DUK_HTHREAD_STRING_INT_REGBASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_REGBASE) -#define DUK_STRIDX_INT_TARGET 104 /* '\xffTarget' */ +#define DUK_STRIDX_INT_TARGET 101 /* '\xffTarget' */ #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_THIS 105 /* '\xffThis' */ -#define DUK_HEAP_STRING_INT_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THIS) -#define DUK_HTHREAD_STRING_INT_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THIS) -#define DUK_STRIDX_COMPILE 106 /* 'compile' */ +#define DUK_STRIDX_INT_HANDLER 102 /* '\xffHandler' */ +#define DUK_HEAP_STRING_INT_HANDLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_HANDLER) +#define DUK_HTHREAD_STRING_INT_HANDLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_HANDLER) +#define DUK_STRIDX_COMPILE 103 /* '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 107 /* 'input' */ +#define DUK_STRIDX_INPUT 104 /* '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 108 /* 'errCreate' */ +#define DUK_STRIDX_ERR_CREATE 105 /* '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 109 /* 'errThrow' */ +#define DUK_STRIDX_ERR_THROW 106 /* '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 110 /* 'env' */ +#define DUK_STRIDX_ENV 107 /* '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 111 /* 'hex' */ +#define DUK_STRIDX_HEX 108 /* '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 112 /* 'base64' */ +#define DUK_STRIDX_BASE64 109 /* '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 113 /* 'jx' */ +#define DUK_STRIDX_JX 110 /* '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 114 /* 'jc' */ +#define DUK_STRIDX_JC 111 /* '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_RESUME 115 /* 'resume' */ +#define DUK_STRIDX_RESUME 112 /* 'resume' */ #define DUK_HEAP_STRING_RESUME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RESUME) #define DUK_HTHREAD_STRING_RESUME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RESUME) -#define DUK_STRIDX_JSON_EXT_UNDEFINED 116 /* '{"_undef":true}' */ +#define DUK_STRIDX_JSON_EXT_UNDEFINED 113 /* '{"_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_STRIDX_JSON_EXT_NAN 114 /* '{"_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_STRIDX_JSON_EXT_POSINF 115 /* '{"_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_STRIDX_JSON_EXT_NEGINF 116 /* '{"_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_STRIDX_JSON_EXT_FUNCTION1 117 /* '{"_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_STRIDX_JSON_EXT_FUNCTION2 118 /* '{_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_STRIDX_BREAK 119 /* '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_STRIDX_CASE 120 /* '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_STRIDX_CATCH 121 /* '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_STRIDX_CONTINUE 122 /* '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_STRIDX_DEBUGGER 123 /* '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_STRIDX_DEFAULT 124 /* '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_STRIDX_DELETE 125 /* '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_STRIDX_DO 126 /* '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_STRIDX_ELSE 127 /* '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_STRIDX_FINALLY 128 /* '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_STRIDX_FOR 129 /* '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_STRIDX_LC_FUNCTION 130 /* '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_STRIDX_IF 131 /* '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_STRIDX_IN 132 /* '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_STRIDX_INSTANCEOF 133 /* '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_STRIDX_NEW 134 /* '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_STRIDX_RETURN 135 /* '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_STRIDX_SWITCH 136 /* '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_STRIDX_THIS 137 /* '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_STRIDX_THROW 138 /* '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_STRIDX_TRY 139 /* '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_STRIDX_TYPEOF 140 /* '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_STRIDX_VAR 141 /* '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_STRIDX_CONST 142 /* '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_STRIDX_VOID 143 /* '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_STRIDX_WHILE 144 /* '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_STRIDX_WITH 145 /* '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_STRIDX_CLASS 146 /* '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_STRIDX_ENUM 147 /* '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_STRIDX_EXPORT 148 /* '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_STRIDX_EXTENDS 149 /* '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_STRIDX_IMPORT 150 /* '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_STRIDX_SUPER 151 /* '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_STRIDX_LC_NULL 152 /* '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_STRIDX_TRUE 153 /* '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_STRIDX_FALSE 154 /* '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_STRIDX_IMPLEMENTS 155 /* '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_STRIDX_INTERFACE 156 /* '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_STRIDX_LET 157 /* '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_STRIDX_PACKAGE 158 /* '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_STRIDX_PRIVATE 159 /* '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_STRIDX_PROTECTED 160 /* '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_STRIDX_PUBLIC 161 /* '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_STRIDX_STATIC 162 /* '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_STRIDX_YIELD 163 /* '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 */ +#define DUK_HEAP_NUM_STRINGS 164 +#define DUK_STRIDX_START_RESERVED 119 +#define DUK_STRIDX_START_STRICT_RESERVED 155 +#define DUK_STRIDX_END_RESERVED 164 /* 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[921]; +DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[903]; #endif /* !DUK_SINGLE_FILE */ #define DUK_STRDATA_MAX_STRLEN 17 -#define DUK_STRDATA_DATA_LENGTH 921 +#define DUK_STRDATA_DATA_LENGTH 903 #endif /* DUK_USE_ROM_STRINGS */ #if defined(DUK_USE_ROM_OBJECTS) @@ -1634,6 +2056,8 @@ 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_prototype_to_string(duk_context *ctx); @@ -1712,7 +2136,7 @@ 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); #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[164]; +DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[166]; #endif /* !DUK_SINGLE_FILE */ #define DUK_BIDX_GLOBAL 0 #define DUK_BIDX_GLOBAL_ENV 1 @@ -1793,25 +2217,25 @@ #define DUK_NUM_ALL_BUILTINS 74 #if defined(DUK_USE_DOUBLE_LE) #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3790]; +DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3819]; #endif /* !DUK_SINGLE_FILE */ -#define DUK_BUILTINS_DATA_LENGTH 3790 +#define DUK_BUILTINS_DATA_LENGTH 3819 #elif defined(DUK_USE_DOUBLE_BE) #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3790]; +DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3819]; #endif /* !DUK_SINGLE_FILE */ -#define DUK_BUILTINS_DATA_LENGTH 3790 +#define DUK_BUILTINS_DATA_LENGTH 3819 #elif defined(DUK_USE_DOUBLE_ME) #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3790]; +DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3819]; #endif /* !DUK_SINGLE_FILE */ -#define DUK_BUILTINS_DATA_LENGTH 3790 +#define DUK_BUILTINS_DATA_LENGTH 3819 #else #error invalid endianness defines #endif #endif /* DUK_USE_ROM_OBJECTS */ #endif /* DUK_BUILTINS_H_INCLUDED */ -#line 50 "duk_internal.h" +#line 51 "duk_internal.h" /* #include duk_util.h */ #line 1 "duk_util.h" @@ -1822,10 +2246,6 @@ #if !defined(DUK_UTIL_H_INCLUDED) #define DUK_UTIL_H_INCLUDED -#define DUK_UTIL_MIN_HASH_PRIME 17 /* must match genhashsizes.py */ - -#define DUK_UTIL_GET_HASH_PROBE_STEP(hash) (duk_util_probe_steps[(hash) & 0x1f]) - #if defined(DUK_USE_GET_RANDOM_DOUBLE) #define DUK_UTIL_GET_RANDOM_DOUBLE(thr) DUK_USE_GET_RANDOM_DOUBLE((thr)->heap_udata) #else @@ -2311,7 +2731,7 @@ #endif /* !DUK_SINGLE_FILE */ /* Note: assumes that duk_util_probe_steps size is 32 */ -#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE) +#if defined(DUK_USE_HOBJECT_HASH_PART) #if !defined(DUK_SINGLE_FILE) DUK_INTERNAL_DECL duk_uint8_t duk_util_probe_steps[32]; #endif /* !DUK_SINGLE_FILE */ @@ -2321,13 +2741,10 @@ DUK_INTERNAL_DECL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed); #endif -#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE) -DUK_INTERNAL_DECL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size); -#endif - DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits); DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx); DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value); +DUK_INTERNAL_DECL duk_int32_t duk_bd_decode_flagged_signed(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value); DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx); DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_bitpacked_string(duk_bitdecoder_ctx *bd, duk_uint8_t *out); @@ -2521,6 +2938,7 @@ #define DUK_STR_INVALID_REGEXP_ESCAPE "invalid regexp escape" #define DUK_STR_INVALID_BACKREFS "invalid backreference(s)" #define DUK_STR_INVALID_REGEXP_CHARACTER "invalid regexp character" +#define DUK_STR_INVALID_REGEXP_GROUP "invalid regexp group" #define DUK_STR_UNTERMINATED_CHARCLASS "unterminated character class" #define DUK_STR_INVALID_RANGE "invalid range" @@ -3007,8 +3425,7 @@ #define DUK_BC_TRYCATCH_FLAG_WITH_BINDING (1 << 3) /* DUK_OP_DECLVAR flags in A; bottom bits are reserved for propdesc flags (DUK_PROPDESC_FLAG_XXX) */ -#define DUK_BC_DECLVAR_FLAG_UNDEF_VALUE (1 << 4) /* use 'undefined' for value automatically */ -#define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1 << 5) /* function declaration */ +#define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1 << 4) /* function declaration */ /* Misc constants and helper macros. */ #define DUK_BC_LDINT_BIAS (1L << 15) @@ -3052,7 +3469,7 @@ #define DUK_LEXER_GETPOINT(ctx,pt) duk_lexer_getpoint((ctx), (pt)) -/* currently 6 characters of lookup are actually needed (duk_lexer.c) */ +/* Currently 6 characters of lookup are actually needed (duk_lexer.c). */ #define DUK_LEXER_WINDOW_SIZE 6 #if defined(DUK_USE_LEXER_SLIDING_WINDOW) #define DUK_LEXER_BUFFER_SIZE 64 @@ -3430,6 +3847,8 @@ duk_int_t token_count; /* number of tokens parsed */ duk_int_t token_limit; /* maximum token count before error (sanity backstop) */ + + duk_small_uint_t flags; /* lexer flags, use compiler flag defines for now */ }; /* @@ -3678,10 +4097,6 @@ * Prototypes */ -#define DUK_JS_COMPILE_FLAG_EVAL (1 << 0) /* source is eval code (not global) */ -#define DUK_JS_COMPILE_FLAG_STRICT (1 << 1) /* strict outer context */ -#define DUK_JS_COMPILE_FLAG_FUNCEXPR (1 << 2) /* source is a function expression (used for Function constructor) */ - DUK_INTERNAL_DECL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer, duk_size_t src_length, duk_small_uint_t flags); #endif /* DUK_JS_COMPILER_H_INCLUDED */ @@ -3786,30 +4201,45 @@ * * 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 are held in the - * heap-wide string table so they don't need link 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). This - * means essentially that the refcount field must be as wide as data pointers. - * On 64-bit platforms this means that the refcount needs to be 64 bits even - * if an 'int' is 32 bits. This is a bit unfortunate, and compromising on - * this might be reasonable in the future. + * 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_refcount16; + duk_uint16_t h_refcount; +#elif defined(DUK_USE_REFCOUNT32) + duk_uint32_t h_refcount; #else duk_size_t h_refcount; #endif -#endif +#endif /* DUK_USE_REFERENCE_COUNTING */ #if defined(DUK_USE_HEAPPTR16) duk_uint16_t h_next16; @@ -3849,15 +4279,26 @@ 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_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 +#endif /* DUK_USE_REFERENCE_COUNTING */ + + duk_hstring *h_next; + /* No 'h_prev' pointer for strings. */ }; #define DUK_HEAPHDR_FLAGS_TYPE_MASK 0x00000003UL @@ -3913,21 +4354,13 @@ #endif #if defined(DUK_USE_REFERENCE_COUNTING) -#if defined(DUK_USE_REFCOUNT16) -#define DUK_HEAPHDR_GET_REFCOUNT(h) ((h)->h_refcount16) -#define DUK_HEAPHDR_SET_REFCOUNT(h,val) do { \ - (h)->h_refcount16 = (val); \ - } while (0) -#define DUK_HEAPHDR_PREINC_REFCOUNT(h) (++(h)->h_refcount16) /* result: updated refcount */ -#define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount16) /* result: updated refcount */ -#else #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 */ -#endif #else /* refcount macros not defined without refcounting, caller must #if defined() now */ #endif /* DUK_USE_REFERENCE_COUNTING */ @@ -4015,18 +4448,23 @@ } while (0) #endif -#define DUK_HEAPHDR_STRING_INIT_NULLS(h) /* currently nop */ +#define DUK_HEAPHDR_STRING_INIT_NULLS(h) do { \ + (h)->h_next = NULL; \ + } while (0) /* * Type tests */ -#define DUK_HEAPHDR_IS_OBJECT(h) \ - (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_OBJECT) -#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) +/* 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 @@ -4049,17 +4487,24 @@ #define DUK_ASSERT_HEAPHDR_LINKS(heap,h) do {} while (0) #endif +#define DUK_ASSERT_HEAPHDR_VALID(h) do { \ + DUK_ASSERT((h) != NULL); \ + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID((h))); \ + } while (0) + +#endif /* DUK_HEAPHDR_H_INCLUDED */ +/* #include duk_refcount.h */ +#line 1 "duk_refcount.h" /* * Reference counting helper macros. The macros take a thread argument * and must thus always be executed in a specific thread context. The - * thread argument is needed for features like finalization. Currently - * it is not required for INCREF, but it is included just in case. - * - * 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. + * thread argument is not really needed anymore: DECREF can operate with + * a heap pointer only, and INCREF needs neither. */ +#if !defined(DUK_REFCOUNT_H_INCLUDED) +#define DUK_REFCOUNT_H_INCLUDED + #if defined(DUK_USE_REFERENCE_COUNTING) #if defined(DUK_USE_ROM_OBJECTS) @@ -4089,6 +4534,7 @@ DUK_ASSERT(duk__h != NULL); \ DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \ + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) != 0); /* No wrapping. */ \ } \ } while (0) #define DUK_TVAL_DECREF_FAST(thr,tv) do { \ @@ -4123,6 +4569,7 @@ DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \ DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \ + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) != 0); /* No wrapping. */ \ } \ } while (0) #define DUK_HEAPHDR_DECREF_FAST_RAW(thr,h,rzcall,rzcast) do { \ @@ -4289,17 +4736,22 @@ } \ } while (0) -/* Free pending refzero entries; quick check to avoid call because often - * the queue is empty. +/* Called after one or more DECREF NORZ calls to handle pending side effects. + * At present DECREF NORZ does freeing inline but doesn't execute finalizers, + * so these macros check for pending finalizers and execute them. The FAST + * variant is performance critical. */ +#if defined(DUK_USE_FINALIZER_SUPPORT) #define DUK_REFZERO_CHECK_FAST(thr) do { \ - if ((thr)->heap->refzero_list != NULL) { \ - duk_refzero_free_pending((thr)); \ - } \ + duk_refzero_check_fast((thr)); \ } while (0) #define DUK_REFZERO_CHECK_SLOW(thr) do { \ - duk_refzero_free_pending((thr)); \ + duk_refzero_check_slow((thr)); \ } while (0) +#else /* DUK_USE_FINALIZER_SUPPORT */ +#define DUK_REFZERO_CHECK_FAST(thr) do { } while (0) +#define DUK_REFZERO_CHECK_SLOW(thr) do { } while (0) +#endif /* DUK_USE_FINALIZER_SUPPORT */ /* * Macros to set a duk_tval and update refcount of the target (decref the @@ -4706,7 +5158,41 @@ #endif /* DUK_USE_REFERENCE_COUNTING */ -#endif /* DUK_HEAPHDR_H_INCLUDED */ +#if defined(DUK_USE_REFERENCE_COUNTING) +#if defined(DUK_USE_FINALIZER_SUPPORT) +DUK_INTERNAL_DECL void duk_refzero_check_slow(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_refzero_check_fast(duk_hthread *thr); +#endif +DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize_norz(duk_heap *heap, duk_heaphdr *hdr); +DUK_INTERNAL_DECL void duk_hobject_refcount_finalize_norz(duk_heap *heap, duk_hobject *h); +#if 0 /* Not needed: fast path handles inline; slow path uses duk_heaphdr_decref() which is needed anyway. */ +DUK_INTERNAL_DECL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h); +DUK_INTERNAL_DECL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h); +DUK_INTERNAL_DECL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h); +DUK_INTERNAL_DECL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h); +DUK_INTERNAL_DECL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h); +DUK_INTERNAL_DECL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h); +#endif +DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h); +DUK_INTERNAL_DECL void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h); +#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) +DUK_INTERNAL_DECL void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h); /* no 'norz' variant */ +DUK_INTERNAL_DECL void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h); /* no 'norz' variant */ +DUK_INTERNAL_DECL void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h); +DUK_INTERNAL_DECL void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h); +#else +DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv); +DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv); +DUK_INTERNAL_DECL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv); +DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h); +DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h); +DUK_INTERNAL_DECL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h); +#endif +#else /* DUK_USE_REFERENCE_COUNTING */ +/* no refcounting */ +#endif /* DUK_USE_REFERENCE_COUNTING */ + +#endif /* DUK_REFCOUNT_H_INCLUDED */ /* #include duk_api_internal.h */ #line 1 "duk_api_internal.h" /* @@ -4812,7 +5298,7 @@ DUK_INTERNAL_DECL duk_hcompfunc *duk_get_hcompfunc(duk_context *ctx, duk_idx_t idx); DUK_INTERNAL_DECL duk_hnatfunc *duk_get_hnatfunc(duk_context *ctx, duk_idx_t idx); -DUK_INTERNAL_DECL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_bool_t throw_flag, duk_bool_t *out_found); +DUK_INTERNAL_DECL void *duk_get_buffer_data_raw(duk_context *ctx, 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_context *ctx, duk_idx_t idx, duk_small_uint_t classnum); @@ -4992,6 +5478,8 @@ DUK_INTERNAL_DECL duk_idx_t duk_get_top_require_min(duk_context *ctx, duk_idx_t min_top); DUK_INTERNAL_DECL duk_idx_t duk_get_top_index_unsafe(duk_context *ctx); +DUK_INTERNAL_DECL void duk_pop_n_unsafe(duk_context *ctx, duk_idx_t count); +DUK_INTERNAL_DECL void duk_pop_n_nodecref_unsafe(duk_context *ctx, duk_idx_t count); DUK_INTERNAL_DECL void duk_pop_unsafe(duk_context *ctx); DUK_INTERNAL_DECL void duk_compact_m1(duk_context *ctx); @@ -5102,7 +5590,7 @@ */ #define DUK_HSTRING_IS_ASCII(x) (DUK_HSTRING_GET_BYTELEN((x)) == DUK_HSTRING_GET_CHARLEN((x))) #endif -#define DUK_HSTRING_IS_ASCII(x) DUK_HSTRING_HAS_ASCII((x)) +#define DUK_HSTRING_IS_ASCII(x) DUK_HSTRING_HAS_ASCII((x)) /* lazily set! */ #define DUK_HSTRING_IS_EMPTY(x) (DUK_HSTRING_GET_BYTELEN((x)) == 0) #if defined(DUK_USE_STRHASH16) @@ -5123,7 +5611,7 @@ (x)->hdr.h_strextra16 = (v); \ } while (0) #if defined(DUK_USE_HSTRING_CLEN) -#define DUK_HSTRING_GET_CHARLEN(x) ((x)->clen16) +#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x)) #define DUK_HSTRING_SET_CHARLEN(x,v) do { \ (x)->clen16 = (v); \ } while (0) @@ -5138,7 +5626,7 @@ #define DUK_HSTRING_SET_BYTELEN(x,v) do { \ (x)->blen = (v); \ } while (0) -#define DUK_HSTRING_GET_CHARLEN(x) ((x)->clen) +#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x)) #define DUK_HSTRING_SET_CHARLEN(x,v) do { \ (x)->clen = (v); \ } while (0) @@ -5169,11 +5657,11 @@ * avoids helper call if string has no array index value. */ #define DUK_HSTRING_GET_ARRIDX_FAST(h) \ - (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_string_helper((h)) : DUK_HSTRING_NO_ARRAY_INDEX) + (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_hstring_fast_known((h)) : DUK_HSTRING_NO_ARRAY_INDEX) /* Slower but more compact variant. */ #define DUK_HSTRING_GET_ARRIDX_SLOW(h) \ - (duk_js_to_arrayindex_string_helper((h))) + (duk_js_to_arrayindex_hstring_fast((h))) #endif /* @@ -5188,30 +5676,26 @@ */ duk_heaphdr_string hdr; - /* Note: we could try to stuff a partial hash (e.g. 16 bits) into the - * shared heap header. Good hashing needs more hash bits though. - */ - - /* string hash */ + /* String hash. */ #if defined(DUK_USE_STRHASH16) /* If 16-bit hash is in use, stuff it into duk_heaphdr_string flags. */ #else duk_uint32_t hash; #endif - /* precomputed array index (or DUK_HSTRING_NO_ARRAY_INDEX) */ + /* Precomputed array index (or DUK_HSTRING_NO_ARRAY_INDEX). */ #if defined(DUK_USE_HSTRING_ARRIDX) duk_uarridx_t arridx; #endif - /* length in bytes (not counting NUL term) */ + /* Length in bytes (not counting NUL term). */ #if defined(DUK_USE_STRLEN16) /* placed in duk_heaphdr_string */ #else duk_uint32_t blen; #endif - /* length in codepoints (must be E5 compatible) */ + /* Length in codepoints (must be E5 compatible). */ #if defined(DUK_USE_STRLEN16) #if defined(DUK_USE_HSTRING_CLEN) duk_uint16_t clen16; @@ -5223,7 +5707,7 @@ #endif /* - * String value of 'blen+1' bytes follows (+1 for NUL termination + * String data of 'blen+1' bytes follows (+1 for NUL termination * convenience for C API). No alignment needs to be guaranteed * for strings, but fields above should guarantee alignment-by-4 * (but not alignment-by-8). @@ -5248,10 +5732,7 @@ */ DUK_INTERNAL_DECL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos, duk_bool_t surrogate_aware); - -#if !defined(DUK_USE_HSTRING_CLEN) DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h); -#endif #endif /* DUK_HSTRING_H_INCLUDED */ /* #include duk_hobject.h */ @@ -5290,8 +5771,8 @@ #if !defined(DUK_HOBJECT_H_INCLUDED) #define DUK_HOBJECT_H_INCLUDED -/* Object flag. There are currently 25 flag bits available. Make sure - * this stays in sync with debugger object inspection code. +/* 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 @@ -5303,14 +5784,14 @@ #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_THREAD DUK_HEAPHDR_USER_FLAG(7) /* object is a thread (duk_hthread) */ +#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_ENVRECCLOSED DUK_HEAPHDR_USER_FLAG(14) /* envrec: (declarative) record is closed */ +#define DUK_HOBJECT_FLAG_HAVE_FINALIZER DUK_HEAPHDR_USER_FLAG(14) /* object has a callable 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) */ @@ -5390,7 +5871,6 @@ #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_THREAD (1UL << DUK_HOBJECT_CLASS_THREAD) #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) @@ -5424,7 +5904,7 @@ #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) #define DUK_HOBJECT_IS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) -#define DUK_HOBJECT_IS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) +#define DUK_HOBJECT_IS_THREAD(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_THREAD) #define DUK_HOBJECT_IS_NONBOUND_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \ DUK_HOBJECT_FLAG_COMPFUNC | \ @@ -5462,14 +5942,14 @@ #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) #define DUK_HOBJECT_HAS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) -#define DUK_HOBJECT_HAS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) +#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_ENVRECCLOSED(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED) +#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) @@ -5482,14 +5962,14 @@ #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) #define DUK_HOBJECT_SET_BUFOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) -#define DUK_HOBJECT_SET_THREAD(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) +#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_ENVRECCLOSED(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED) +#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) @@ -5502,20 +5982,28 @@ #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) #define DUK_HOBJECT_CLEAR_BUFOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) -#define DUK_HOBJECT_CLEAR_THREAD(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) +#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_ENVRECCLOSED(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED) +#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) #define DUK_HOBJECT_CLEAR_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC) #define DUK_HOBJECT_CLEAR_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ) +/* Object can/cannot use FASTREFS, i.e. has no strong reference fields beyond + * duk_hobject base header. + */ +#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))) +#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. */ @@ -5897,6 +6385,16 @@ #define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr,h,p) duk_hobject_set_prototype_updref((thr), (h), (p)) /* + * 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 */ @@ -5909,22 +6407,9 @@ #if defined(DUK_USE_OBJSIZES16) #define DUK_HOBJECT_MAX_PROPERTIES 0x0000ffffUL #else -#define DUK_HOBJECT_MAX_PROPERTIES 0x7fffffffUL /* 2**31-1 ~= 2G properties */ +#define DUK_HOBJECT_MAX_PROPERTIES 0x3fffffffUL /* 2**30-1 ~= 1G properties */ #endif -/* higher value conserves memory; also note that linear scan is cache friendly */ -#define DUK_HOBJECT_E_USE_HASH_LIMIT 32 - -/* hash size relative to entries size: for value X, approx. hash_prime(e_size + e_size / X) */ -#define DUK_HOBJECT_H_SIZE_DIVISOR 4 /* hash size approx. 1.25 times entries size */ - -/* if new_size < L * old_size, resize without abandon check; L = 3-bit fixed point, e.g. 9 -> 9/8 = 112.5% */ -#define DUK_HOBJECT_A_FAST_RESIZE_LIMIT 9 /* 112.5%, i.e. new size less than 12.5% higher -> fast resize */ - -/* if density < L, abandon array part, L = 3-bit fixed point, e.g. 2 -> 2/8 = 25% */ -/* limit is quite low: one array entry is 8 bytes, one normal entry is 4+1+8+4 = 17 bytes (with hash entry) */ -#define DUK_HOBJECT_A_ABANDON_LIMIT 2 /* 25%, i.e. less than 25% used -> abandon */ - /* 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 @@ -5936,18 +6421,6 @@ #error invalid DUK_USE_ALIGN_BY #endif -/* controls for minimum entry part growth */ -#define DUK_HOBJECT_E_MIN_GROW_ADD 16 -#define DUK_HOBJECT_E_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */ - -/* controls for minimum array part growth */ -#define DUK_HOBJECT_A_MIN_GROW_ADD 16 -#define DUK_HOBJECT_A_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */ - -/* probe sequence */ -#define DUK_HOBJECT_HASH_INITIAL(hash,h_size) ((hash) % (h_size)) -#define DUK_HOBJECT_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash)) - /* * PC-to-line constants */ @@ -5977,7 +6450,7 @@ struct duk_propdesc { /* read-only values 'lifted' for ease of use */ - duk_small_int_t flags; + duk_small_uint_t flags; duk_hobject *get; duk_hobject *set; @@ -6101,17 +6574,18 @@ */ /* alloc and init */ -DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags); -#if 0 /* unused */ -DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags); -#endif -DUK_INTERNAL_DECL duk_harray *duk_harray_alloc(duk_heap *heap, duk_uint_t hobject_flags); -DUK_INTERNAL_DECL duk_hcompfunc *duk_hcompfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags); -DUK_INTERNAL_DECL duk_hnatfunc *duk_hnatfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags); +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); #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL_DECL duk_hbufobj *duk_hbufobj_alloc(duk_heap *heap, duk_uint_t hobject_flags); +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(duk_heap *heap, duk_uint_t hobject_flags); +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); /* resize */ DUK_INTERNAL_DECL void duk_hobject_realloc_props(duk_hthread *thr, @@ -6148,6 +6622,11 @@ 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 @@ -6194,11 +6673,6 @@ /* macros */ DUK_INTERNAL_DECL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p); -/* finalization */ -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_INTERNAL_DECL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj); -#endif - /* 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); @@ -6798,8 +7272,6 @@ #endif #endif /* DUK_USE_ROM_STRINGS */ -#define DUK_HTHREAD_GET_CURRENT_ACTIVATION(thr) (&(thr)->callstack[(thr)->callstack_top - 1]) - /* values for the state field */ #define DUK_HTHREAD_STATE_INACTIVE 1 /* thread not currently running */ #define DUK_HTHREAD_STATE_RUNNING 2 /* thread currently running (only one at a time) */ @@ -6981,8 +7453,9 @@ /* Call stack. [0,callstack_top[ is GC reachable. */ duk_activation *callstack; + duk_activation *callstack_curr; /* current activation (or NULL if none) */ duk_size_t callstack_size; /* allocation size */ - duk_size_t callstack_top; /* next to use, highest used is top - 1 */ + duk_size_t callstack_top; /* next to use, highest used is top - 1 (or none if top == 0) */ duk_size_t callstack_preventcount; /* number of activation records in callstack preventing a yield */ /* Catch stack. [0,catchstack_top[ is GC reachable. */ @@ -7044,12 +7517,19 @@ DUK_INTERNAL_DECL void duk_hthread_callstack_grow(duk_hthread *thr); DUK_INTERNAL_DECL void duk_hthread_callstack_shrink_check(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_hthread_callstack_unwind_norz(duk_hthread *thr, duk_size_t new_top); DUK_INTERNAL_DECL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top); DUK_INTERNAL_DECL void duk_hthread_catchstack_grow(duk_hthread *thr); DUK_INTERNAL_DECL void duk_hthread_catchstack_shrink_check(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_hthread_catchstack_unwind_norz(duk_hthread *thr, duk_size_t new_top); DUK_INTERNAL_DECL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top); -DUK_INTERNAL_DECL duk_activation *duk_hthread_get_current_activation(duk_hthread *thr); +#if defined(DUK_USE_FINALIZER_TORTURE) +DUK_INTERNAL_DECL void duk_hthread_valstack_torture_realloc(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_hthread_callstack_torture_realloc(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_hthread_catchstack_torture_realloc(duk_hthread *thr); +#endif + DUK_INTERNAL_DECL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */ DUK_INTERNAL_DECL void *duk_hthread_get_callstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */ DUK_INTERNAL_DECL void *duk_hthread_get_catchstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */ @@ -7111,6 +7591,56 @@ }; #endif /* DUK_HARRAY_H_INCLUDED */ +/* #include duk_henv.h */ +#line 1 "duk_henv.h" +/* + * Environment object representation. + */ + +#if !defined(DUK_HENV_H_INCLUDED) +#define DUK_HENV_H_INCLUDED + +#define DUK_ASSERT_HDECENV_VALID(h) do { \ + DUK_ASSERT((h) != NULL); \ + DUK_ASSERT(DUK_HOBJECT_IS_DECENV((duk_hobject *) (h))); \ + DUK_ASSERT((h)->thread == NULL || (h)->varmap != NULL); \ + } while (0) + +#define DUK_ASSERT_HOBJENV_VALID(h) do { \ + 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); \ + } while (0) + +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; +}; + +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 */ /* #include duk_hbuffer.h */ #line 1 "duk_hbuffer.h" /* @@ -7459,13 +7989,11 @@ * Heap flags */ -#define DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING (1 << 0) /* mark-and-sweep is currently running */ -#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1 << 1) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */ -#define DUK_HEAP_FLAG_REFZERO_FREE_RUNNING (1 << 2) /* refcount code is processing refzero list */ -#define DUK_HEAP_FLAG_ERRHANDLER_RUNNING (1 << 3) /* an error handler (user callback to augment/replace error) is running */ -#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1 << 4) /* executor interrupt running (used to avoid nested interrupts) */ -#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1 << 5) /* heap destruction ongoing, finalizer rescue no longer possible */ -#define DUK_HEAP_FLAG_DEBUGGER_PAUSED (1 << 6) /* debugger is paused: talk with debug client until step/resume */ +#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1 << 0) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */ +#define DUK_HEAP_FLAG_ERRHANDLER_RUNNING (1 << 1) /* an error handler (user callback to augment/replace error) is running */ +#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1 << 2) /* executor interrupt running (used to avoid nested interrupts) */ +#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1 << 3) /* heap destruction ongoing, finalizer rescue no longer possible */ +#define DUK_HEAP_FLAG_DEBUGGER_PAUSED (1 << 4) /* 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 { \ @@ -7475,25 +8003,19 @@ (heap)->flags &= ~(bits); \ } while (0) -#define DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) #define DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) -#define DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) #define DUK_HEAP_HAS_ERRHANDLER_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) #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_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) #define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) -#define DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) #define DUK_HEAP_SET_ERRHANDLER_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) #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_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) #define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) -#define DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) #define DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) #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) @@ -7520,11 +8042,25 @@ * field and the GC caller can impose further flags. */ -#define DUK_MS_FLAG_EMERGENCY (1 << 0) /* emergency mode: try extra hard */ -#define DUK_MS_FLAG_NO_STRINGTABLE_RESIZE (1 << 1) /* don't resize stringtable (but may sweep it); needed during stringtable resize */ -#define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1 << 2) /* don't compact objects; needed during object property allocation resize */ -#define DUK_MS_FLAG_NO_FINALIZERS (1 << 3) /* don't run finalizers; leave finalizable objects in finalize_list for next round */ -#define DUK_MS_FLAG_SKIP_FINALIZERS (1 << 4) /* don't run finalizers; queue finalizable objects back to heap_allocated */ +/* Emergency mark-and-sweep: try extra hard, even at the cost of + * performance. + */ +#define DUK_MS_FLAG_EMERGENCY (1 << 0) + +/* Voluntary mark-and-sweep: triggered periodically. */ +#define DUK_MS_FLAG_VOLUNTARY (1 << 1) + +/* 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 (1 << 2) + +/* 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 (1 << 2) /* * Thread switching @@ -7566,39 +8102,28 @@ #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 */ -/* helper to insert a (non-string) heap object into heap allocated list */ -#define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap,hdr) duk_heap_insert_into_heap_allocated((heap),(hdr)) - -/* - * Stringtable - */ - -/* initial stringtable size, must be prime and higher than DUK_UTIL_MIN_HASH_PRIME */ -#define DUK_STRTAB_INITIAL_SIZE 17 - -/* indicates a deleted string; any fixed non-NULL, non-hstring pointer works */ -#define DUK_STRTAB_DELETED_MARKER(heap) ((duk_hstring *) heap) - -/* resizing parameters */ -#define DUK_STRTAB_MIN_FREE_DIVISOR 4 /* load factor max 75% */ -#define DUK_STRTAB_MIN_USED_DIVISOR 4 /* load factor min 25% */ -#define DUK_STRTAB_GROW_ST_SIZE(n) ((n) + (n)) /* used entries + approx 100% -> reset load to 50% */ - -#define DUK_STRTAB_U32_MAX_STRLEN 10 /* 4'294'967'295 */ -#define DUK_STRTAB_HIGHEST_32BIT_PRIME 0xfffffffbUL - -/* probe sequence (open addressing) */ -#define DUK_STRTAB_HASH_INITIAL(hash,h_size) ((hash) % (h_size)) -#define DUK_STRTAB_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash)) - -/* fixed top level hashtable size (separate chaining) */ -#define DUK_STRTAB_CHAIN_SIZE DUK_USE_STRTAB_CHAIN_SIZE +/* 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 @@ -7669,10 +8194,17 @@ #define DUK_FREE(heap,ptr) duk_heap_mem_free((heap), (ptr)) /* + * Checked allocation, relative to a thread + */ + +#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)) + +/* * Memory constants */ -#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT 5 /* Retry allocation after mark-and-sweep for this +#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 @@ -7713,27 +8245,6 @@ duk_uint32_t line; }; -#if defined(DUK_USE_DEBUGGER_SUPPORT) -#define DUK_HEAP_IS_DEBUGGER_ATTACHED(heap) ((heap)->dbg_read_cb != NULL) -#define DUK_HEAP_CLEAR_STEP_STATE(heap) do { \ - (heap)->dbg_step_type = DUK_STEP_TYPE_NONE; \ - (heap)->dbg_step_thread = NULL; \ - (heap)->dbg_step_csindex = 0; \ - (heap)->dbg_step_startline = 0; \ - } while (0) -#define DUK_HEAP_SET_PAUSED(heap) do { \ - DUK_HEAP_SET_DEBUGGER_PAUSED(heap); \ - (heap)->dbg_state_dirty = 1; \ - DUK_HEAP_CLEAR_STEP_STATE((heap)); \ - } while (0) -#define DUK_HEAP_CLEAR_PAUSED(heap) do { \ - DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap); \ - (heap)->dbg_state_dirty = 1; \ - DUK_HEAP_CLEAR_STEP_STATE((heap)); \ - } while (0) -#define DUK_HEAP_IS_PAUSED(heap) (DUK_HEAP_HAS_DEBUGGER_PAUSED((heap))) -#endif /* DUK_USE_DEBUGGER_SUPPORT */ - /* * String cache should ideally be at duk_hthread level, but that would * cause string finalization to slow down relative to the number of @@ -7762,28 +8273,17 @@ duk_tval value2; /* 2nd related value (type specific) */ }; -/* - * Stringtable entry for fixed size stringtable - */ - -struct duk_strtab_entry { -#if defined(DUK_USE_HEAPPTR16) - /* A 16-bit listlen makes sense with 16-bit heap pointers: there - * won't be space for 64k strings anyway. - */ - duk_uint16_t listlen; /* if 0, 'str16' used, if > 0, 'strlist16' used */ - union { - duk_uint16_t strlist16; - duk_uint16_t str16; - } u; -#else - duk_size_t listlen; /* if 0, 'str' used, if > 0, 'strlist' used */ - union { - duk_hstring **strlist; - duk_hstring *str; - } u; -#endif -}; +#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) /* * Main heap structure @@ -7802,12 +8302,6 @@ */ void *heap_udata; - /* Precomputed pointers when using 16-bit heap pointer packing. */ -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t heapptr_null16; - duk_uint16_t heapptr_deleted16; -#endif - /* 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 @@ -7815,53 +8309,114 @@ */ duk_fatal_function fatal_func; - /* allocated heap objects */ + /* 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; - /* work list for objects whose refcounts are zero but which have not been - * "finalized"; avoids recursive C calls when refcounts go to zero in a - * chain of objects. + /* 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; - duk_heaphdr *refzero_list_tail; #endif - /* mark-and-sweep control */ +#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 + + /* 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 mark_and_sweep_trigger_counter; + duk_int_t ms_trigger_counter; #endif - duk_int_t mark_and_sweep_recursion_depth; - /* mark-and-sweep flags automatically active (used for critical sections) */ - duk_small_uint_t mark_and_sweep_base_flags; + /* 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; - /* work list for objects to be finalized (by mark-and-sweep) */ - duk_heaphdr *finalize_list; + /* Mark-and-sweep flags automatically active (used for critical sections). */ + duk_small_uint_t ms_base_flags; - /* longjmp state */ - duk_ljstate lj; + /* Mark-and-sweep running flag. Prevents re-entry, and also causes + * refzero events to be ignored (= objects won't be queued to refzero_list). + */ + 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; - /* marker for detecting internal "double faults", see duk_error_throw.c */ - duk_bool_t handling_error; +#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; + + /* Longjmp state. */ + duk_ljstate lj; - /* heap thread, used internally and for finalization */ + /* Heap thread, used internally and for finalization. */ duk_hthread *heap_thread; - /* current thread */ - duk_hthread *curr_thread; /* currently running thread */ + /* Current running thread. */ + duk_hthread *curr_thread; - /* heap level "stash" object (e.g., various reachability roots) */ + /* 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 */ + /* Mix-in value for computing string hashes; should be reasonably unpredictable. */ duk_uint32_t hash_seed; - /* rnd_state for duk_util_tinyrandom.c */ + /* 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 */ @@ -7870,7 +8425,7 @@ #endif #endif - /* counter for unique local symbol creation */ + /* 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. @@ -7886,10 +8441,9 @@ duk_int_t inst_count_interrupt; #endif - /* debugger */ - + /* Debugger state. */ #if defined(DUK_USE_DEBUGGER_SUPPORT) - /* callbacks and udata; dbg_read_cb != NULL is used to indicate attached state */ + /* 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; @@ -7899,7 +8453,7 @@ duk_debug_detached_function dbg_detached_cb; void *dbg_udata; - /* debugger state, only relevant when attached */ + /* 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) */ @@ -7923,30 +8477,25 @@ duk_uint8_t dbg_next_byte; #endif - /* string intern table (weak refs) */ -#if defined(DUK_USE_STRTAB_PROBE) -#if defined(DUK_USE_HEAPPTR16) + /* String intern table (weak refs). */ +#if defined(DUK_USE_STRTAB_PTRCOMP) duk_uint16_t *strtable16; #else duk_hstring **strtable; #endif - duk_uint32_t st_size; /* alloc size in elements */ - duk_uint32_t st_used; /* used elements (includes DELETED) */ -#endif - - /* XXX: static alloc is OK until separate chaining stringtable - * resizing is implemented. - */ -#if defined(DUK_USE_STRTAB_CHAIN) - duk_strtab_entry strtable[DUK_STRTAB_CHAIN_SIZE]; + 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 + /* String access cache (codepoint offset -> byte offset) for fast string * character looping; 'weak' reference which needs special handling in GC. */ duk_strcache strcache[DUK_HEAP_STRCACHE_SIZE]; - /* built-in strings */ + /* Built-in strings. */ #if defined(DUK_USE_ROM_STRINGS) /* No field needed when strings are in ROM. */ #else @@ -7975,32 +8524,32 @@ 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_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING) -DUK_INTERNAL_DECL void duk_heap_remove_any_from_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 -#if 0 /*unused*/ -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen); -#endif -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen); -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t len); -#if 0 /*unused*/ -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val); -#endif -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val); -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val); +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); +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_string_remove(duk_heap *heap, duk_hstring *h); +DUK_INTERNAL_DECL void duk_heap_strtable_unlink(duk_heap *heap, duk_hstring *h); #endif -#if defined(DUK_USE_MS_STRINGTABLE_RESIZE) -DUK_INTERNAL_DECL void duk_heap_force_strtab_resize(duk_heap *heap); -#endif -DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap); +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_dump_strtab(duk_heap *heap); +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); @@ -8014,41 +8563,18 @@ 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); -#if defined(DUK_USE_REFERENCE_COUNTING) -DUK_INTERNAL_DECL void duk_refzero_free_pending(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr); -#if 0 /* Not needed: fast path handles inline; slow path uses duk_heaphdr_decref() which is needed anyway. */ -DUK_INTERNAL_DECL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h); -DUK_INTERNAL_DECL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h); -DUK_INTERNAL_DECL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h); -DUK_INTERNAL_DECL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h); -DUK_INTERNAL_DECL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h); -DUK_INTERNAL_DECL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h); -#endif -DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h); -DUK_INTERNAL_DECL void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h); -#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) -DUK_INTERNAL_DECL void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h); /* no 'norz' variant */ -DUK_INTERNAL_DECL void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h); /* no 'norz' variant */ -DUK_INTERNAL_DECL void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h); -DUK_INTERNAL_DECL void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h); -#else -DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv); -DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv); -DUK_INTERNAL_DECL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv); -DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h); -DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h); -DUK_INTERNAL_DECL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h); -#endif -#else /* DUK_USE_REFERENCE_COUNTING */ -/* no refcounting */ -#endif /* DUK_USE_REFERENCE_COUNTING */ +#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 duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags); +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); @@ -8197,7 +8723,13 @@ 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); -#endif + +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_step_state(duk_heap *heap); +#endif /* DUK_USE_DEBUGGER_SUPPORT */ #endif /* DUK_DEBUGGER_H_INCLUDED */ /* #include duk_debug.h */ @@ -8865,7 +9397,10 @@ DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_fatal_handler(void *udata, const char *msg)); -DUK_INTERNAL_DECL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t lj_type); +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); @@ -9252,8 +9787,11 @@ DUK_INTERNAL_DECL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv); DUK_INTERNAL_DECL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv); DUK_INTERNAL_DECL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv); -DUK_INTERNAL_DECL duk_small_int_t duk_js_to_arrayindex_raw_string(const duk_uint8_t *str, duk_uint32_t blen, duk_uarridx_t *out_idx); -DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h); +DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string(const duk_uint8_t *str, duk_uint32_t blen); +#if !defined(DUK_USE_HSTRING_ARRIDX) +DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_hstring_fast_known(duk_hstring *h); +DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_hstring_fast(duk_hstring *h); +#endif DUK_INTERNAL_DECL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags); DUK_INTERNAL_DECL duk_small_int_t duk_js_data_compare(const duk_uint8_t *buf1, const duk_uint8_t *buf2, duk_size_t len1, duk_size_t len2); DUK_INTERNAL_DECL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2); @@ -9306,7 +9844,7 @@ DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name); DUK_INTERNAL_DECL duk_bool_t duk_js_declvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_small_int_t prop_flags, duk_bool_t is_func_decl); DUK_INTERNAL_DECL void duk_js_init_activation_environment_records_delayed(duk_hthread *thr, duk_activation *act); -DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env, duk_hobject *func, duk_size_t regbase); +DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env); DUK_INTERNAL_DECL duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_size_t idx_bottom); DUK_INTERNAL_DECL void duk_js_push_closure(duk_hthread *thr, @@ -9468,6 +10006,9 @@ #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_context *ctx, const char *str); #endif @@ -9514,7 +10055,7 @@ #endif #endif /* DUK_SELFTEST_H_INCLUDED */ -#line 77 "duk_internal.h" +#line 80 "duk_internal.h" #endif /* DUK_INTERNAL_H_INCLUDED */ #line 10 "duk_replacements.c" @@ -9690,10 +10231,16 @@ /* #include duk_internal.h -> already included */ +#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[921] = { +DUK_INTERNAL const duk_uint8_t duk_strings_data[903] = { 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, @@ -9721,31 +10268,31 @@ 171,115,147,136,4,65,130,96,35,64,194,32,168,89,56,208,48,135,123,144,217, 146,38,220,229,64,186,16,187,156,105,47,52,238,112,56,153,4,225,145,27,156, 43,162,192,46,71,220,229,65,22,1,231,220,228,157,72,136,136,220,227,197, -164,180,52,133,220,224,34,105,19,115,140,3,207,185,202,130,36,109,85,185, -194,161,160,90,50,72,163,115,135,3,70,178,68,251,156,16,22,178,16,251,156, -153,226,64,13,27,156,137,12,16,72,135,220,228,193,19,18,101,220,228,206, -137,28,78,99,208,178,21,13,125,38,146,70,60,20,72,9,145,4,140,121,51,197, -214,25,27,81,156,151,48,65,34,107,106,9,55,18,68,104,146,84,97,31,191,189, -181,70,140,133,222,249,212,227,66,125,245,187,251,219,77,3,119,190,117,56, -208,159,125,110,254,246,210,26,93,239,157,78,52,39,223,93,191,189,180,212, -52,187,223,58,156,104,79,190,187,127,123,104,180,104,183,190,117,56,208, -159,125,102,254,209,104,209,124,234,113,161,62,250,80,196,128,81,4,9,16, -162,4,196,116,9,205,154,27,66,32,100,13,12,98,68,227,33,65,69,204,195,34, -201,50,8,110,33,23,34,28,168,104,22,188,12,174,138,11,70,138,104,115,68, -130,137,13,82,27,41,129,162,35,138,54,146,198,137,39,72,180,210,178,38,35, -146,103,68,139,51,197,214,28,227,131,79,15,35,138,58,130,37,19,155,41,146, -174,64,203,99,161,100,37,145,51,148,75,4,164,66,54,140,49,46,247,70,103,37, -230,70,142,70,67,30,232,204,178,163,201,18,54,139,89,39,26,16,165,2,228,69, -33,143,89,24,70,206,73,67,102,72,148,2,32,214,73,157,224,18,128,98,29,241, -69,65,50,37,241,116,200,41,144,102,125,2,180,8,210,152,38,129,23,8,34,198, +164,180,52,133,220,228,206,137,23,115,128,137,164,77,206,48,15,62,231,42,8, +145,181,86,231,10,134,129,104,201,34,125,206,76,17,49,38,141,206,28,13,26, +201,19,137,204,122,22,66,161,175,164,210,72,199,130,137,1,50,32,145,143,38, +120,186,195,35,106,51,146,230,8,36,77,109,65,38,226,72,141,18,74,140,35, +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: 164 */ -DUK_INTERNAL const duk_c_function duk_bi_native_functions[164] = { +/* native functions: 166 */ +DUK_INTERNAL const duk_c_function duk_bi_native_functions[166] = { NULL, duk_bi_array_constructor, duk_bi_array_constructor_is_array, @@ -9880,6 +10427,7 @@ 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, @@ -9888,6 +10436,7 @@ 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, @@ -9912,540 +10461,549 @@ duk_bi_uint8array_plainof, }; #if defined(DUK_USE_DOUBLE_LE) -DUK_INTERNAL const duk_uint8_t duk_builtins_data[3790] = { +DUK_INTERNAL const duk_uint8_t duk_builtins_data[3819] = { 144,148,105,221,32,68,52,228,62,12,104,200,165,134,148,248,81,77,61,191, 135,35,154,103,34,72,6,157,159,197,145,77,245,126,52,130,106,234,163,196, 52,226,18,51,161,26,113,1,60,37,64,190,18,49,116,116,33,26,113,1,92,136,26, 98,112,145,139,163,165,8,211,136,14,228,72,82,68,141,17,56,72,197,209,212, 132,105,196,5,242,88,108,193,126,18,49,116,117,161,26,113,1,60,158,30,78, -18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,224,59, -147,60,93,110,79,15,39,9,24,186,33,13,63,79,185,39,26,121,223,110,77,66,53, -116,1,120,248,186,248,136,67,76,196,200,134,186,137,177,13,31,192,174,79, -15,32,248,8,196,24,8,107,254,39,97,161,175,248,159,16,215,252,80,186,26, -255,138,57,136,107,254,41,100,33,175,248,167,170,134,191,226,166,138,26, -255,138,187,40,107,254,43,111,33,171,86,181,16,209,241,11,228,201,121,240, -141,19,134,72,196,52,123,168,95,38,75,207,131,32,156,50,70,33,195,3,152, -128,0,0,0,0,0,1,240,255,153,128,0,0,0,0,0,1,224,255,151,137,0,214,9,188,35, -131,12,225,196,56,177,78,60,99,147,28,229,200,57,162,120,74,129,124,36,98, -232,156,241,92,136,26,98,112,145,139,162,116,71,114,36,41,34,70,136,156,36, -98,232,157,49,124,150,27,48,95,132,140,93,19,170,39,147,195,201,194,70,46, -137,215,17,218,69,4,236,98,232,157,153,39,110,81,220,15,193,209,83,3,200, -119,130,241,241,117,240,120,80,252,137,10,178,10,103,134,180,122,9,135,136, -154,120,169,199,142,158,121,10,7,146,162,121,74,71,150,166,121,138,135,154, -170,121,202,199,158,23,201,146,243,225,26,39,12,145,61,16,190,76,151,159,6, -65,56,100,137,233,35,93,205,144,33,224,140,137,196,54,121,244,5,60,17,145, -56,85,184,19,207,16,21,18,227,65,198,231,72,16,137,112,168,106,38,76,225,2, -70,65,56,100,237,34,140,177,4,134,65,56,100,237,34,129,117,204,123,154,70, -207,46,64,146,52,78,25,59,72,163,48,65,34,52,78,25,59,72,160,93,115,30,230, -145,179,204,144,24,146,16,30,76,209,2,40,210,72,64,121,52,4,0,156,88,97,5, -194,96,227,18,124,124,93,55,79,15,39,28,94,49,38,159,154,136,96,196,159,29, -102,241,241,115,201,25,227,131,36,133,20,62,110,142,253,2,102,36,248,235, -55,143,139,158,72,207,28,104,24,73,112,201,3,2,82,65,155,187,94,6,20,72,9, -147,120,128,225,144,168,105,56,248,185,228,140,241,190,96,128,200,84,52, -156,124,92,242,70,104,36,183,168,4,145,0,190,41,1,139,18,19,36,226,146,17, -124,73,82,54,124,37,230,70,201,14,108,184,132,8,68,185,34,1,100,31,8,129,8, -151,11,23,100,141,225,18,12,68,184,75,204,141,146,2,178,112,72,8,162,98,92, -50,10,152,147,227,172,222,62,46,121,35,60,114,88,96,92,185,112,201,65,34, -92,4,1,147,81,159,141,205,32,234,121,96,97,57,64,97,121,128,14,56,37,199, -89,188,124,92,242,70,120,227,144,53,18,227,226,233,186,120,121,56,226,242, -8,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,36,136,48,64,114,0, -250,156,168,1,64,247,175,25,36,2,8,11,94,80,248,16,40,104,242,103,200,48, -193,3,162,92,4,98,12,41,14,66,40,106,101,1,132,130,8,24,78,104,129,54,62, -96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,178, -58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,129, -232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,201, -126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,132, -0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,46, -36,29,4,78,69,6,60,226,31,192,7,255,252,24,160,163,11,23,51,130,56,35,193, -56,100,238,31,6,150,46,103,4,225,147,143,114,27,62,233,241,200,137,182,133, -42,142,167,216,6,23,216,0,97,28,17,224,39,223,32,80,142,8,240,78,25,56,9, -248,8,22,39,12,156,123,144,217,240,19,240,18,6,19,154,32,79,194,124,14,134, -140,151,227,139,226,52,11,88,37,62,33,163,37,248,226,248,141,32,213,184,64, -89,56,39,49,224,137,60,100,5,96,38,35,249,8,15,18,61,96,17,60,200,6,145,1, -17,31,206,64,89,45,2,39,161,0,178,122,209,63,74,2,101,64,202,113,67,77,235, -64,92,221,197,186,196,143,4,9,19,188,1,25,187,139,112,128,178,113,110,177, -35,193,2,68,239,0,46,110,229,30,242,71,130,4,137,222,4,35,55,113,110,16,22, -78,81,239,36,120,32,72,157,224,64,147,138,25,237,0,52,72,242,2,126,82,3,74, -129,148,227,234,66,12,112,28,140,155,104,203,169,158,9,133,158,4,25,36,1, -61,96,47,181,80,46,132,129,255,255,255,255,255,255,222,254,39,172,67,118, -170,5,208,144,0,64,0,0,0,0,0,0,51,16,0,0,0,0,0,0,62,31,200,245,238,146,38, -138,147,105,13,42,26,137,226,0,0,0,0,0,0,7,131,249,30,180,134,4,209,82,109, -33,165,67,81,60,64,0,0,0,0,0,0,240,255,28,144,155,104,0,0,0,0,0,0,0,0,16, -117,59,130,48,155,98,48,187,144,3,205,220,42,46,65,237,72,27,55,112,151, -123,154,70,205,0,94,208,129,115,119,31,18,9,18,67,155,183,34,12,176,96,175, -4,100,74,228,3,237,38,43,31,192,109,117,171,0,228,164,219,72,0,0,0,0,0,0, -248,127,196,234,111,0,50,110,224,193,50,114,83,138,26,107,192,131,38,238, -77,12,39,37,56,161,166,188,11,132,188,12,74,110,226,220,32,44,156,24,38,78, -74,113,67,77,120,28,148,221,197,184,64,89,57,52,48,156,148,226,134,154,240, -64,195,94,8,56,123,193,11,85,116,140,45,240,3,152,147,228,208,194,95,0,89, -137,62,22,139,95,48,64,70,200,67,28,98,79,180,152,139,218,45,124,193,1,27, -33,16,65,137,62,49,205,153,236,132,81,102,36,251,73,137,157,115,102,123,33, -24,57,137,62,12,19,37,144,142,40,196,159,105,49,15,160,153,44,132,128,198, -36,248,48,98,200,73,18,98,79,180,152,135,208,98,200,74,16,98,79,135,117,35, -43,33,44,89,137,62,210,98,63,93,72,202,200,76,20,98,79,140,67,105,50,74, -200,77,26,98,79,180,152,153,212,54,147,36,172,132,225,70,36,249,34,9,205, -28,172,132,241,166,36,251,73,138,93,32,156,209,202,200,80,30,98,79,140,66, -214,137,16,78,104,229,100,40,146,49,39,218,76,76,234,22,180,72,130,115,71, -43,33,72,137,137,62,77,12,38,92,210,113,197,44,137,59,64,7,145,39,201,161, -132,184,64,249,18,124,98,22,180,72,130,115,71,43,101,76,148,137,62,210,98, -103,80,181,162,68,19,154,57,91,42,130,164,73,242,68,19,154,57,91,95,84,108, -137,62,210,98,151,72,39,52,114,182,190,176,169,18,124,98,27,73,146,86,223, -215,27,34,79,180,152,153,212,54,147,36,173,191,176,34,68,159,14,234,70,86, -231,217,23,34,79,180,152,143,215,82,50,183,62,208,121,18,124,24,38,75,101, -108,84,137,62,210,98,31,65,50,91,43,130,36,73,241,142,108,207,109,125,209, -114,36,251,73,137,157,115,102,123,107,239,11,145,39,194,209,107,230,8,8, -219,127,124,116,137,62,210,98,47,104,181,243,4,4,109,191,192,135,49,39,204, -16,17,178,24,32,242,36,249,130,2,54,203,7,6,104,14,76,131,140,144,0,0,0,0, -0,0,0,1,141,207,215,12,78,126,193,46,190,126,192,98,179,246,4,197,231,236, -10,193,9,114,11,172,64,73,146,83,236,145,169,237,1,6,120,14,78,129,179,40, -249,18,149,175,207,141,199,27,76,248,156,81,177,207,139,198,9,169,199,129, -58,136,19,202,11,179,20,240,149,2,248,72,197,209,200,148,162,117,48,39,148, -151,102,42,228,64,211,19,132,140,93,28,137,74,39,85,2,121,81,118,98,238,68, -133,36,72,209,19,132,140,93,28,137,74,39,87,2,121,89,118,98,190,75,13,152, -47,194,70,46,142,68,165,19,172,129,60,176,187,49,79,39,135,147,132,140,93, -28,137,74,39,91,2,121,105,118,98,142,210,40,39,99,23,71,34,82,135,8,128, -120,72,13,42,226,145,97,87,224,168,1,58,182,232,232,64,22,85,181,187,177, -107,2,64,7,213,183,74,7,121,207,215,242,17,119,49,248,94,173,198,210,36,15, -232,34,182,84,113,95,115,240,221,91,141,163,160,72,1,220,164,194,175,121, -123,103,224,186,244,64,24,45,68,84,251,33,9,64,15,217,66,51,209,218,210, -129,154,118,254,205,61,65,204,126,23,178,132,103,165,3,52,237,253,154,122, -131,216,252,167,224,121,44,48,46,95,203,166,238,74,113,67,77,201,128,219, -152,164,82,6,0,203,76,64,64,9,210,211,18,4,4,144,221,49,40,64,76,13,211,19, -5,4,192,221,45,66,1,4,24,207,76,82,2,8,136,94,152,156,24,157,45,49,64,6,75, -191,76,80,66,149,110,116,116,197,8,41,240,247,79,70,188,6,183,27,76,80,194, -45,198,210,211,20,144,171,113,180,116,52,197,40,27,1,125,34,240,27,16,221, -42,240,27,221,109,66,32,104,129,163,115,52,224,5,139,168,209,233,138,32,57, -33,186,98,138,18,80,140,244,197,24,28,192,221,49,71,11,56,209,162,211,20, -183,1,66,188,17,145,52,40,9,148,226,134,153,5,198,137,136,32,14,12,30,164, -140,144,230,192,0,0,0,0,0,136,211,64,182,120,43,135,126,16,68,52,174,195, -144,12,2,158,4,128,70,22,24,128,101,67,112,163,192,100,104,176,131,192,99, -32,176,99,192,226,115,30,1,79,4,68,28,16,54,0,0,41,254,232,116,62,204,7,21, -35,18,54,127,80,28,192,132,28,32,14,96,197,212,243,193,48,188,240,39,130, -236,224,175,131,117,2,178,112,145,139,163,145,131,114,70,46,142,218,27,182, -72,197,209,219,56,26,53,161,166,32,128,56,18,2,129,239,94,50,76,130,68,230, -202,113,160,167,146,94,163,134,66,161,164,227,226,231,146,51,198,249,147, -71,209,67,73,210,94,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15, -155,163,191,68,28,98,79,143,139,166,233,225,228,227,139,198,37,210,244,208, -24,137,112,151,153,27,36,5,100,224,146,105,184,100,196,95,18,84,141,159,9, -121,145,178,67,155,46,33,38,187,168,252,211,243,81,92,2,14,40,16,50,37,202, -160,150,154,67,152,148,20,28,76,156,89,26,105,158,63,232,16,44,150,129,18, -146,44,28,96,14,98,216,80,113,50,113,100,105,166,120,255,160,20,28,76,156, -113,75,34,78,63,236,3,6,133,41,35,31,242,18,195,152,147,226,27,61,138,41, -140,16,98,79,148,67,103,177,69,45,136,49,39,196,54,122,58,212,83,26,36,196, -159,40,134,207,71,90,138,92,16,98,79,136,108,244,244,168,166,56,73,137,62, -81,13,158,158,149,20,186,40,196,159,10,183,2,122,122,84,82,240,163,18,124, -42,220,9,235,106,81,75,225,228,73,241,13,158,197,54,198,8,145,39,202,33, -179,216,166,214,196,72,147,226,27,61,29,106,109,141,19,34,79,148,67,103, -163,173,77,174,8,145,39,196,54,122,122,84,219,28,38,68,159,40,134,207,79, -74,155,93,21,34,79,133,91,129,61,61,42,109,120,84,137,62,21,110,4,245,181, -41,181,248,56,224,28,24,80,113,50,113,100,105,166,120,255,160,20,28,76,156, -113,75,34,78,63,236,3,6,133,41,35,31,242,11,174,254,160,34,84,8,35,16,98, -146,38,55,32,33,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,0,0,0,0,30, -7,230,56,199,161,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,0,0,0,0, -30,7,230,55,36,33,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,0,0,0,0, -30,7,234,40,11,91,133,199,172,8,111,248,128,239,88,16,222,56,191,242,49, -198,69,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,240,63, -49,185,65,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,240, -63,49,198,77,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0, -240,63,49,185,97,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0, -0,0,64,49,198,85,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0, -0,0,64,49,185,129,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0, -0,0,0,64,49,198,93,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0, -0,0,0,64,49,185,161,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0, -0,0,0,16,64,49,198,101,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0, -0,0,0,0,16,64,49,185,193,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0, -0,0,0,0,0,16,64,49,198,109,8,244,56,153,37,180,242,71,104,139,35,8,217,192, -0,0,0,0,0,0,16,64,49,185,225,8,244,56,153,37,180,242,71,104,139,35,8,217, -192,0,0,0,0,0,0,16,64,49,198,117,8,244,56,153,37,180,242,71,104,139,35,8, -217,192,0,0,0,0,0,0,16,64,49,186,1,8,244,56,153,37,180,242,71,104,139,35,8, -217,192,0,0,0,0,0,0,32,64,49,198,125,8,244,56,153,37,180,242,71,104,139,35, -8,217,192,0,0,0,0,0,0,32,64,32,232,130,0,97,57,162,4,245,72,10,68,184,70, -137,195,67,77,175,32,66,37,192,208,165,36,117,196,10,14,38,78,44,141,52, -207,169,64,56,156,199,130,36,160,141,146,52,38,32,76,72,1,246,136,235,103, -177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,171,37, -20,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,158,142, -183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,246,136, -235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,37,20, -138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,75,161, -37,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,39,208, -146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,129,89, -58,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,17,214, -207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,207, -161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,207, -98,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,78, -209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,146, -155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,104, -142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,146, -155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,217, -233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,162, -137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,77, -156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,117, -179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,162, -100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,59,22, -53,91,0,2,21,11,94,181,128,196,133,0,185,80,32,56,156,199,130,36,160,72,16, -78,126,53,144,5,146,208,34,82,72,1,109,20,76,155,40,32,233,0,115,70,130,8, -209,56,104,105,187,252,193,3,17,162,112,201,242,18,65,211,0,230,149,132,17, -162,112,208,211,119,248,0,82,130,96,95,127,128,130,80,102,186,36,232,92, -206,255,1,80,48,200,39,12,158,241,64, +18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,232,59, +147,60,93,110,79,15,39,9,24,186,33,13,63,111,185,16,211,206,251,114,98,17, +171,160,11,199,197,215,196,66,26,102,38,68,53,212,77,136,104,255,5,114,120, +121,7,192,70,32,192,67,95,249,59,13,13,127,228,248,134,191,242,133,208,215, +254,81,204,67,95,249,75,33,13,127,229,61,84,53,255,149,52,80,215,254,85, +217,67,95,249,91,121,13,90,181,168,134,143,152,95,38,75,207,132,104,156,50, +70,33,163,225,66,249,50,94,124,25,4,225,146,49,14,24,28,196,0,0,0,0,0,0,15, +135,252,204,0,0,0,0,0,0,15,7,252,188,72,6,176,77,225,28,24,103,14,33,197, +138,113,227,28,152,231,46,65,205,19,194,84,11,225,35,23,68,231,138,228,64, +211,19,132,140,93,19,162,59,145,33,73,18,52,68,225,35,23,68,233,139,228, +176,217,130,252,36,98,232,157,81,60,158,30,78,18,49,116,78,184,142,210,40, +39,99,23,68,236,201,59,114,142,224,126,14,138,152,30,67,188,23,143,139,175, +131,194,135,228,72,85,144,83,60,53,163,208,76,60,68,211,197,78,60,116,243, +200,80,60,149,19,202,82,60,181,51,204,84,60,213,83,206,86,60,240,190,76, +151,159,8,209,56,100,137,232,133,242,100,188,248,50,9,195,36,79,73,26,238, +108,129,15,4,100,78,33,179,207,160,41,224,140,137,194,173,192,158,120,128, +168,151,26,14,55,58,64,132,75,133,67,81,50,103,8,18,50,9,195,39,105,20,101, +136,36,50,9,195,39,105,20,11,174,99,220,210,54,121,114,4,145,162,112,201, +218,69,25,130,9,17,162,112,201,218,69,2,235,152,247,52,141,158,100,128,196, +144,128,242,102,136,17,70,146,66,3,201,160,32,0,130,225,48,113,137,62,62, +46,155,167,135,147,142,47,24,147,79,205,68,48,98,79,142,179,120,248,185, +228,140,241,193,146,66,138,31,55,71,126,129,51,18,124,117,155,199,197,207, +36,103,142,52,12,36,184,100,129,129,41,32,205,221,175,3,10,36,4,201,188,64, +112,200,84,52,156,124,92,242,70,120,223,48,64,100,42,26,78,62,46,121,35,52, +18,91,212,2,72,128,95,20,128,197,137,9,146,113,73,8,190,36,169,27,62,18, +243,35,100,135,54,92,66,4,34,92,145,0,178,15,132,64,132,75,133,139,178,70, +240,137,6,34,92,37,230,70,201,1,89,56,36,4,81,49,46,25,5,76,73,241,214,111, +31,23,60,145,158,57,44,48,46,92,184,100,160,145,46,2,0,201,168,207,198,230, +144,117,60,176,48,156,160,48,188,192,7,28,18,227,172,222,62,46,121,35,60, +113,200,26,137,113,241,116,221,60,60,156,113,121,4,20,124,92,242,70,120, +226,37,194,54,140,36,64,21,147,146,68,24,32,57,0,125,78,84,0,160,123,215, +140,146,1,4,5,175,40,124,8,20,52,121,51,228,24,96,129,209,46,2,49,6,20,135, +33,20,53,50,128,194,65,4,12,39,52,64,155,31,48,112,72,6,247,62,16,1,31,73, +30,25,240,60,73,82,70,68,138,0,89,29,5,156,96,2,201,104,17,35,160,18,78, +140,228,16,26,79,90,4,73,43,192,244,108,142,130,206,89,240,58,26,50,95,142, +43,159,65,107,4,167,196,52,100,191,28,87,63,128,15,255,240,164,169,35,136, +6,128,146,115,9,0,210,7,43,163,194,0,71,128,105,65,176,15,128,105,131,21, +11,153,35,0,211,134,137,7,65,18,33,244,23,18,14,130,39,34,131,30,113,15, +224,3,255,254,12,80,81,133,139,153,193,28,17,224,156,50,119,15,131,75,23, +51,130,112,201,199,185,13,159,116,248,228,68,219,66,149,83,83,238,3,11,238, +0,48,142,8,240,19,239,144,40,71,4,120,39,12,156,4,252,4,11,19,134,78,61, +200,108,248,9,248,9,3,9,205,16,39,225,62,7,67,70,75,241,197,241,154,5,172, +18,159,16,209,146,252,113,124,102,144,106,220,32,44,156,19,152,240,68,158, +66,2,176,19,17,252,164,7,137,30,176,8,158,116,3,72,128,136,143,232,32,44, +150,129,19,210,128,89,61,104,159,169,1,50,160,101,56,161,166,246,160,46, +110,226,221,98,71,130,4,137,222,0,140,221,197,184,64,89,56,183,88,145,224, +129,34,119,128,23,55,114,143,121,35,193,2,68,239,2,17,155,184,183,8,11,39, +40,247,146,60,16,36,78,240,32,73,197,12,247,128,26,36,121,1,63,49,2,165,48, +70,114,229,145,51,250,205,2,8,209,203,150,68,207,235,52,130,16,209,46,131, +36,188,70,128,210,160,101,56,251,16,131,28,7,35,38,218,50,234,103,130,97, +103,129,6,73,0,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,199,36,38, +218,0,0,0,0,0,0,0,0,4,29,78,224,140,38,216,140,46,228,0,243,119,10,139,144, +123,82,6,205,220,37,222,230,145,179,64,23,180,32,92,221,199,196,130,68,144, +230,237,200,131,44,24,43,193,25,18,185,0,251,73,138,199,240,27,93,106,192, +57,41,54,210,0,0,0,0,0,0,62,31,241,58,155,192,12,155,184,48,76,156,148,226, +134,154,240,32,201,187,147,67,9,201,78,40,105,175,2,225,47,3,18,155,184, +183,8,11,39,6,9,147,146,156,80,211,94,7,37,55,113,110,16,22,78,77,12,39,37, +56,161,166,188,16,48,215,130,14,30,240,66,213,93,35,11,124,0,230,36,249,52, +48,151,192,22,98,79,133,162,215,204,16,17,178,16,199,24,147,237,38,34,246, +139,95,48,64,70,200,68,16,98,79,140,115,102,123,33,20,89,137,62,210,98,103, +92,217,158,200,70,14,98,79,131,4,201,100,35,138,49,39,218,76,67,232,38,75, +33,32,49,137,62,12,24,178,18,68,152,147,237,38,33,244,24,178,18,132,24,147, +225,221,72,202,200,75,22,98,79,180,152,143,215,82,50,178,19,5,24,147,227, +16,218,76,146,178,19,70,152,147,237,38,38,117,13,164,201,43,33,56,81,137, +62,72,130,115,71,43,33,60,105,137,62,210,98,151,72,39,52,114,178,20,7,152, +147,227,16,181,162,68,19,154,57,89,10,36,140,73,246,147,19,58,133,173,18, +32,156,209,202,200,82,34,98,79,147,67,9,151,52,156,113,75,34,78,208,1,228, +73,242,104,97,46,16,62,68,159,24,133,173,18,32,156,209,202,217,83,37,34,79, +180,152,153,212,45,104,145,4,230,142,86,202,160,169,18,124,145,4,230,142, +86,215,213,27,34,79,180,152,165,210,9,205,28,173,175,172,42,68,159,24,134, +210,100,149,183,245,198,200,147,237,38,38,117,13,164,201,43,111,236,8,145, +39,195,186,145,149,185,246,69,200,147,237,38,35,245,212,140,173,207,180,30, +68,159,6,9,146,217,91,21,34,79,180,152,135,208,76,150,202,224,137,18,124, +99,155,51,219,95,116,92,137,62,210,98,103,92,217,158,218,251,194,228,73, +240,180,90,249,130,2,54,223,223,29,34,79,180,152,139,218,45,124,193,1,27, +111,240,33,204,73,243,4,4,108,134,8,60,137,62,96,128,141,178,193,193,154,3, +147,32,227,36,0,0,0,0,0,0,0,0,99,115,245,195,19,159,176,75,175,159,176,24, +172,253,129,49,121,251,2,176,66,92,130,235,16,18,100,148,251,36,106,123,64, +65,158,3,147,160,108,202,62,68,165,107,243,227,113,198,211,62,39,20,108, +115,226,241,130,106,113,224,78,162,4,242,130,236,197,60,37,64,190,18,49, +116,114,37,40,157,76,9,229,37,217,138,185,16,52,196,225,35,23,71,34,82,137, +213,64,158,84,93,152,187,145,33,73,18,52,68,225,35,23,71,34,82,137,213,192, +158,86,93,152,175,146,195,102,11,240,145,139,163,145,41,68,235,32,79,44,46, +204,83,201,225,228,225,35,23,71,34,82,137,214,192,158,90,93,152,163,180, +138,9,216,197,209,200,148,161,194,32,30,18,3,74,184,164,88,85,248,42,0,78, +173,186,58,16,5,149,109,110,236,90,192,144,1,245,109,210,129,222,115,245, +252,132,93,204,126,23,171,113,180,137,3,250,8,173,149,28,87,220,252,55,86, +227,104,232,18,0,119,41,48,171,222,94,217,248,46,189,16,6,11,81,21,62,200, +66,80,3,246,80,140,244,118,180,160,102,157,191,179,79,80,115,31,133,236, +161,25,233,64,205,59,127,102,158,160,246,63,41,248,30,75,12,11,151,242,233, +187,146,156,80,211,114,96,54,230,41,20,129,128,50,211,16,16,2,116,180,196, +129,1,36,55,76,74,16,19,3,116,196,193,65,48,55,75,80,128,65,6,51,211,20, +128,130,34,23,166,39,6,39,75,76,80,1,146,239,211,20,16,165,91,157,29,49,66, +10,124,61,211,209,175,1,173,198,211,20,48,139,113,180,180,197,36,42,220, +109,29,13,49,74,6,192,95,72,188,6,196,55,74,188,6,247,91,80,136,26,32,104, +220,205,56,1,98,234,52,122,98,136,14,72,110,152,162,132,148,35,61,49,70,7, +48,55,76,81,194,206,52,104,180,197,45,192,80,175,4,100,77,10,2,101,56,161, +166,65,113,162,98,8,3,131,7,169,35,36,57,176,0,0,0,0,16,40,116,208,45,158, +10,225,223,132,17,13,43,176,228,3,0,167,129,32,17,133,134,32,25,80,220,40, +240,25,26,44,32,240,24,200,44,24,240,56,156,199,128,83,193,17,7,4,13,128,0, +10,79,202,28,223,195,1,197,72,196,141,159,220,7,48,33,7,8,3,152,49,117,60, +240,76,47,60,9,224,187,56,43,224,221,64,172,156,36,98,232,228,96,220,145, +139,163,182,134,237,146,49,116,118,206,6,141,104,105,136,32,14,4,128,160, +123,215,140,147,32,145,57,178,156,104,41,228,151,168,225,144,168,105,56, +248,185,228,140,241,190,100,209,244,80,210,116,151,134,12,73,241,214,111, +31,23,60,145,158,56,50,72,81,67,230,232,239,209,7,24,147,227,226,233,186, +120,121,56,226,241,137,116,189,52,6,34,92,37,230,70,201,1,89,56,36,154,110, +25,49,23,196,149,35,103,194,94,100,108,144,230,203,136,73,174,234,63,52, +252,212,87,0,131,138,4,12,137,114,168,37,166,144,230,37,5,7,19,39,22,70, +154,103,143,252,4,11,37,160,68,164,139,7,24,3,152,182,20,28,76,156,89,26, +105,158,63,240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253,132, +176,230,36,248,134,207,98,138,99,4,24,147,229,16,217,236,81,75,98,12,73, +241,13,158,142,181,20,198,137,49,39,202,33,179,209,214,162,151,4,24,147, +226,27,61,61,42,41,142,18,98,79,148,67,103,167,165,69,46,138,49,39,194,173, +192,158,158,149,20,188,40,196,159,10,183,2,122,218,148,82,248,121,18,124, +67,103,177,77,177,130,36,73,242,136,108,246,41,181,177,18,36,248,134,207, +71,90,155,99,68,200,147,229,16,217,232,235,83,107,130,36,73,241,13,158,158, +149,54,199,9,145,39,202,33,179,211,210,166,215,69,72,147,225,86,224,79,79, +74,155,94,21,34,79,133,91,129,61,109,74,109,126,14,56,7,6,20,28,76,156,89, +26,105,158,63,240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253, +130,235,191,232,8,149,2,8,196,24,164,137,141,200,8,71,161,196,201,45,167, +146,59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,142,49,232,71,161,196,201,45, +167,146,59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,141,201,8,71,161,196,201, +45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,7,129,250,138,2,214,225,113,235, +2,27,128,0,10,66,3,189,96,67,120,226,224,0,2,148,140,113,145,66,61,14,38, +73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,60,15,204,110,80,66,61,14, +38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,60,15,204,113,147,66,61, +14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,60,15,204,110,88,66, +61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,0,16,12,113,149, +66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,0,16,12,110,96, +66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,0,16,12,113, +151,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,0,16,12, +110,104,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,4,16, +12,113,153,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,4, +16,12,110,112,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0, +4,16,12,113,155,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0, +0,4,16,12,110,120,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0, +0,0,4,16,12,113,157,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0, +0,0,0,4,16,12,110,128,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0, +0,0,0,0,8,16,12,113,159,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0, +0,0,0,0,0,8,16,8,58,32,128,24,78,104,129,61,82,2,145,46,17,162,112,208,211, +107,200,16,137,112,52,41,73,29,113,2,131,137,147,139,35,77,51,234,80,14,39, +49,224,137,40,35,100,141,9,136,19,18,0,125,162,58,217,236,81,64,68,72,1, +241,13,158,197,20,150,50,36,0,251,68,117,179,209,214,234,201,69,16,100,72, +1,246,136,235,103,163,173,208,146,138,68,23,18,0,124,67,103,163,173,213, +146,138,76,23,18,0,124,67,103,163,173,208,146,138,84,25,18,0,125,162,58, +217,233,233,117,100,162,138,50,36,0,251,68,117,179,211,210,232,73,69,34, +139,137,0,62,33,179,211,210,234,201,69,38,139,137,0,62,33,179,211,210,232, +73,69,42,139,137,0,62,21,110,4,250,178,81,70,23,18,0,124,42,220,9,244,36, +162,145,134,68,128,31,6,234,5,100,234,201,69,28,100,72,1,240,110,160,86,78, +132,148,82,56,168,144,3,237,17,214,207,171,37,22,128,42,36,0,251,68,117, +179,232,73,69,164,9,137,0,62,33,179,234,201,69,168,9,137,0,62,33,179,232, +73,69,172,10,180,81,50,118,136,235,103,177,77,129,54,138,38,78,33,179,216, +166,210,198,218,40,153,59,68,117,179,209,214,234,201,77,144,109,162,137, +147,180,71,91,61,29,110,132,148,218,32,203,69,19,39,16,217,232,235,117,100, +166,211,6,90,40,153,56,134,207,71,91,161,37,54,168,54,209,68,201,218,35, +173,158,158,151,86,74,108,163,109,20,76,157,162,58,217,233,233,116,36,166, +209,70,90,40,153,56,134,207,79,75,171,37,54,154,50,209,68,201,196,54,122, +122,93,9,41,181,81,150,138,38,78,21,110,4,250,178,83,102,25,104,162,100, +225,86,224,79,161,37,54,140,54,209,68,201,193,186,129,89,58,178,83,103,27, +104,162,100,224,221,64,172,157,9,41,180,113,118,138,38,78,209,29,108,250, +178,83,136,2,237,20,76,157,162,58,217,244,36,167,18,5,90,40,153,56,134,207, +171,37,56,160,42,209,68,201,196,54,125,9,41,197,141,78,197,141,86,192,0, +133,66,215,173,96,49,33,64,46,84,8,14,39,49,224,137,40,18,4,19,159,141,100, +1,100,180,8,148,146,0,91,69,19,38,202,8,58,64,28,209,160,130,52,78,26,26, +110,255,80,64,196,104,156,50,125,4,144,116,192,57,165,97,4,104,156,52,52, +221,254,64,20,160,152,23,223,228,32,148,25,174,137,58,23,51,191,200,84,12, +50,9,195,39,196,80, }; #elif defined(DUK_USE_DOUBLE_BE) -DUK_INTERNAL const duk_uint8_t duk_builtins_data[3790] = { +DUK_INTERNAL const duk_uint8_t duk_builtins_data[3819] = { 144,148,105,221,32,68,52,228,62,12,104,200,165,134,148,248,81,77,61,191, 135,35,154,103,34,72,6,157,159,197,145,77,245,126,52,130,106,234,163,196, 52,226,18,51,161,26,113,1,60,37,64,190,18,49,116,116,33,26,113,1,92,136,26, 98,112,145,139,163,165,8,211,136,14,228,72,82,68,141,17,56,72,197,209,212, 132,105,196,5,242,88,108,193,126,18,49,116,117,161,26,113,1,60,158,30,78, -18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,224,59, -147,60,93,110,79,15,39,9,24,186,33,13,63,79,185,39,26,121,223,110,77,66,53, -116,1,120,248,186,248,136,67,76,196,200,134,186,137,177,13,31,192,174,79, -15,32,248,8,196,24,8,107,254,39,97,161,175,248,159,16,215,252,80,186,26, -255,138,57,136,107,254,41,100,33,175,248,167,170,134,191,226,166,138,26, -255,138,187,40,107,254,43,111,33,171,86,181,16,209,241,11,228,201,121,240, -141,19,134,72,196,52,123,168,95,38,75,207,131,32,156,50,70,33,195,3,152, -128,255,240,0,0,0,0,0,1,153,128,255,224,0,0,0,0,0,1,151,137,0,214,9,188,35, -131,12,225,196,56,177,78,60,99,147,28,229,200,57,162,120,74,129,124,36,98, -232,156,241,92,136,26,98,112,145,139,162,116,71,114,36,41,34,70,136,156,36, -98,232,157,49,124,150,27,48,95,132,140,93,19,170,39,147,195,201,194,70,46, -137,215,17,218,69,4,236,98,232,157,153,39,110,81,220,15,193,209,83,3,200, -119,130,241,241,117,240,120,80,252,137,10,178,10,103,134,180,122,9,135,136, -154,120,169,199,142,158,121,10,7,146,162,121,74,71,150,166,121,138,135,154, -170,121,202,199,158,23,201,146,243,225,26,39,12,145,61,16,190,76,151,159,6, -65,56,100,137,233,35,93,205,144,33,224,140,137,196,54,121,244,5,60,17,145, -56,85,184,19,207,16,21,18,227,65,198,231,72,16,137,112,168,106,38,76,225,2, -70,65,56,100,237,34,140,177,4,134,65,56,100,237,34,129,117,204,123,154,70, -207,46,64,146,52,78,25,59,72,163,48,65,34,52,78,25,59,72,160,93,115,30,230, -145,179,204,144,24,146,16,30,76,209,2,40,210,72,64,121,52,4,0,156,88,97,5, -194,96,227,18,124,124,93,55,79,15,39,28,94,49,38,159,154,136,96,196,159,29, -102,241,241,115,201,25,227,131,36,133,20,62,110,142,253,2,102,36,248,235, -55,143,139,158,72,207,28,104,24,73,112,201,3,2,82,65,155,187,94,6,20,72,9, -147,120,128,225,144,168,105,56,248,185,228,140,241,190,96,128,200,84,52, -156,124,92,242,70,104,36,183,168,4,145,0,190,41,1,139,18,19,36,226,146,17, -124,73,82,54,124,37,230,70,201,14,108,184,132,8,68,185,34,1,100,31,8,129,8, -151,11,23,100,141,225,18,12,68,184,75,204,141,146,2,178,112,72,8,162,98,92, -50,10,152,147,227,172,222,62,46,121,35,60,114,88,96,92,185,112,201,65,34, -92,4,1,147,81,159,141,205,32,234,121,96,97,57,64,97,121,128,14,56,37,199, -89,188,124,92,242,70,120,227,144,53,18,227,226,233,186,120,121,56,226,242, -8,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,36,136,48,64,114,0, -250,156,168,1,64,247,175,25,36,2,8,11,94,80,248,16,40,104,242,103,200,48, -193,3,162,92,4,98,12,41,14,66,40,106,101,1,132,130,8,24,78,104,129,54,62, -96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,178, -58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,129, -232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,201, -126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,132, -0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,46, -36,29,4,78,69,6,60,226,31,192,7,255,252,24,160,163,11,23,51,130,56,35,193, -56,100,238,31,6,150,46,103,4,225,147,143,114,27,62,233,241,200,137,182,133, -42,142,167,216,6,23,216,0,97,28,17,224,39,223,32,80,142,8,240,78,25,56,9, -248,8,22,39,12,156,123,144,217,240,19,240,18,6,19,154,32,79,194,124,14,134, -140,151,227,139,226,52,11,88,37,62,33,163,37,248,226,248,141,32,213,184,64, -89,56,39,49,224,137,60,100,5,96,38,35,249,8,15,18,61,96,17,60,200,6,145,1, -17,31,206,64,89,45,2,39,161,0,178,122,209,63,74,2,101,64,202,113,67,77,235, -64,92,221,197,186,196,143,4,9,19,188,1,25,187,139,112,128,178,113,110,177, -35,193,2,68,239,0,46,110,229,30,242,71,130,4,137,222,4,35,55,113,110,16,22, -78,81,239,36,120,32,72,157,224,64,147,138,25,237,0,52,72,242,2,126,82,3,74, -129,148,227,234,66,12,112,28,140,155,104,203,169,158,9,133,158,4,25,36,1, -61,96,47,181,80,46,132,128,255,223,255,255,255,255,255,254,39,172,67,118, -170,5,208,144,0,0,0,0,0,0,0,0,115,16,31,254,0,0,0,0,0,0,8,245,238,146,38, -138,147,105,13,42,26,137,226,3,255,128,0,0,0,0,0,1,30,180,134,4,209,82,109, -33,165,67,81,60,64,255,240,0,0,0,0,0,0,28,144,155,104,0,0,0,0,0,0,0,0,16, -117,59,130,48,155,98,48,187,144,3,205,220,42,46,65,237,72,27,55,112,151, -123,154,70,205,0,94,208,129,115,119,31,18,9,18,67,155,183,34,12,176,96,175, -4,100,74,228,3,237,38,43,31,192,109,117,171,0,228,164,219,72,127,248,0,0,0, -0,0,0,196,234,111,0,50,110,224,193,50,114,83,138,26,107,192,131,38,238,77, -12,39,37,56,161,166,188,11,132,188,12,74,110,226,220,32,44,156,24,38,78,74, -113,67,77,120,28,148,221,197,184,64,89,57,52,48,156,148,226,134,154,240,64, -195,94,8,56,123,193,11,85,116,140,45,240,3,152,147,228,208,194,95,0,89,137, -62,22,139,95,48,64,70,200,67,28,98,79,180,152,139,218,45,124,193,1,27,33, -16,65,137,62,49,205,153,236,132,81,102,36,251,73,137,157,115,102,123,33,24, -57,137,62,12,19,37,144,142,40,196,159,105,49,15,160,153,44,132,128,198,36, -248,48,98,200,73,18,98,79,180,152,135,208,98,200,74,16,98,79,135,117,35,43, -33,44,89,137,62,210,98,63,93,72,202,200,76,20,98,79,140,67,105,50,74,200, -77,26,98,79,180,152,153,212,54,147,36,172,132,225,70,36,249,34,9,205,28, -172,132,241,166,36,251,73,138,93,32,156,209,202,200,80,30,98,79,140,66,214, -137,16,78,104,229,100,40,146,49,39,218,76,76,234,22,180,72,130,115,71,43, -33,72,137,137,62,77,12,38,92,210,113,197,44,137,59,64,7,145,39,201,161,132, -184,64,249,18,124,98,22,180,72,130,115,71,43,101,76,148,137,62,210,98,103, -80,181,162,68,19,154,57,91,42,130,164,73,242,68,19,154,57,91,95,84,108,137, -62,210,98,151,72,39,52,114,182,190,176,169,18,124,98,27,73,146,86,223,215, -27,34,79,180,152,153,212,54,147,36,173,191,176,34,68,159,14,234,70,86,231, -217,23,34,79,180,152,143,215,82,50,183,62,208,121,18,124,24,38,75,101,108, -84,137,62,210,98,31,65,50,91,43,130,36,73,241,142,108,207,109,125,209,114, -36,251,73,137,157,115,102,123,107,239,11,145,39,194,209,107,230,8,8,219, -127,124,116,137,62,210,98,47,104,181,243,4,4,109,191,192,135,49,39,204,16, -17,178,24,32,242,36,249,130,2,54,203,7,6,104,14,76,131,140,144,0,0,0,0,0,0, -0,1,141,207,215,12,78,126,193,46,190,126,192,98,179,246,4,197,231,236,10, -193,9,114,11,172,64,73,146,83,236,145,169,237,1,6,120,14,78,129,179,40,249, -18,149,175,207,141,199,27,76,248,156,81,177,207,139,198,9,169,199,129,58, -136,19,202,11,179,20,240,149,2,248,72,197,209,200,148,162,117,48,39,148, -151,102,42,228,64,211,19,132,140,93,28,137,74,39,85,2,121,81,118,98,238,68, -133,36,72,209,19,132,140,93,28,137,74,39,87,2,121,89,118,98,190,75,13,152, -47,194,70,46,142,68,165,19,172,129,60,176,187,49,79,39,135,147,132,140,93, -28,137,74,39,91,2,121,105,118,98,142,210,40,39,99,23,71,34,82,135,8,128, -120,72,8,0,183,225,81,98,138,237,33,58,182,232,232,64,64,2,107,177,187,181, -85,22,7,213,183,74,1,255,49,114,23,247,209,207,120,94,173,198,210,36,3,255, -113,84,118,82,184,47,224,221,91,141,163,160,72,7,251,121,111,98,164,220, -161,192,186,244,64,64,9,33,251,84,68,45,24,15,217,66,51,209,218,210,128, -127,205,65,60,204,254,119,154,23,178,132,103,165,0,255,218,130,121,153,252, -239,52,167,224,121,44,48,46,95,203,166,238,74,113,67,77,201,128,219,152, -164,82,6,0,203,76,64,64,9,210,211,18,4,4,144,221,49,40,64,76,13,211,19,5,4, -192,221,45,66,1,4,24,207,76,82,2,8,136,94,152,156,24,157,45,49,64,6,75,191, -76,80,66,149,110,116,116,197,8,41,240,247,79,70,188,6,183,27,76,80,194,45, -198,210,211,20,144,171,113,180,116,52,197,40,27,1,125,34,240,27,16,221,42, -240,27,221,109,66,32,104,129,163,115,52,224,5,139,168,209,233,138,32,57,33, -186,98,138,18,80,140,244,197,24,28,192,221,49,71,11,56,209,162,211,20,183, -1,66,188,17,145,52,40,9,148,226,134,153,5,198,137,136,32,14,12,30,164,140, -144,230,192,64,211,136,0,0,0,0,0,182,120,43,135,126,16,68,52,174,195,144, -12,2,158,4,128,70,22,24,128,101,67,112,163,192,100,104,176,131,192,99,32, -176,99,192,226,115,30,1,79,4,68,28,16,54,0,0,41,254,232,116,62,204,7,21,35, -18,54,127,80,28,192,132,28,32,14,96,197,212,243,193,48,188,240,39,130,236, -224,175,131,117,2,178,112,145,139,163,145,131,114,70,46,142,218,27,182,72, -197,209,219,56,26,53,161,166,32,128,56,18,2,129,239,94,50,76,130,68,230, -202,113,160,167,146,94,163,134,66,161,164,227,226,231,146,51,198,249,147, -71,209,67,73,210,94,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15, -155,163,191,68,28,98,79,143,139,166,233,225,228,227,139,198,37,210,244,208, -24,137,112,151,153,27,36,5,100,224,146,105,184,100,196,95,18,84,141,159,9, -121,145,178,67,155,46,33,38,187,168,252,211,243,81,92,2,14,40,16,50,37,202, -160,150,154,67,152,148,20,28,76,156,89,26,105,158,63,232,16,44,150,129,18, -146,44,28,96,14,98,216,80,113,50,113,100,105,166,120,255,160,20,28,76,156, -113,75,34,78,63,236,3,6,133,41,35,31,242,18,195,152,147,226,27,61,138,41, -140,16,98,79,148,67,103,177,69,45,136,49,39,196,54,122,58,212,83,26,36,196, -159,40,134,207,71,90,138,92,16,98,79,136,108,244,244,168,166,56,73,137,62, -81,13,158,158,149,20,186,40,196,159,10,183,2,122,122,84,82,240,163,18,124, -42,220,9,235,106,81,75,225,228,73,241,13,158,197,54,198,8,145,39,202,33, -179,216,166,214,196,72,147,226,27,61,29,106,109,141,19,34,79,148,67,103, -163,173,77,174,8,145,39,196,54,122,122,84,219,28,38,68,159,40,134,207,79, -74,155,93,21,34,79,133,91,129,61,61,42,109,120,84,137,62,21,110,4,245,181, -41,181,248,56,224,28,24,80,113,50,113,100,105,166,120,255,160,20,28,76,156, -113,75,34,78,63,236,3,6,133,41,35,31,242,11,174,254,160,34,84,8,35,16,98, -146,38,55,32,33,30,135,19,36,182,158,72,237,17,100,97,27,56,7,254,0,0,0,0, -0,0,6,56,199,161,30,135,19,36,182,158,72,237,17,100,97,27,56,7,254,0,0,0,0, -0,0,6,55,36,33,30,135,19,36,182,158,72,237,17,100,97,27,56,7,254,0,0,0,0,0, -0,10,40,11,91,133,199,172,8,111,248,128,239,88,16,222,56,191,242,49,198,69, -8,244,56,153,37,180,242,71,104,139,35,8,217,192,63,240,0,0,0,0,0,0,49,185, -65,8,244,56,153,37,180,242,71,104,139,35,8,217,192,63,240,0,0,0,0,0,0,49, -198,77,8,244,56,153,37,180,242,71,104,139,35,8,217,192,63,240,0,0,0,0,0,0, -49,185,97,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0,0, -49,198,85,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0,0, -49,185,129,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0, -0,49,198,93,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0, -0,49,185,161,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0,0,0, -0,0,49,198,101,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0,0, -0,0,0,49,185,193,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0, -0,0,0,0,49,198,109,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0, -0,0,0,0,0,49,185,225,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16, -0,0,0,0,0,0,49,198,117,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64, -16,0,0,0,0,0,0,49,186,1,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64, -32,0,0,0,0,0,0,49,198,125,8,244,56,153,37,180,242,71,104,139,35,8,217,192, -64,32,0,0,0,0,0,0,32,232,130,0,97,57,162,4,245,72,10,68,184,70,137,195,67, -77,175,32,66,37,192,208,165,36,117,196,10,14,38,78,44,141,52,207,169,64,56, -156,199,130,36,160,141,146,52,38,32,76,72,1,246,136,235,103,177,69,1,17,32, -7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,171,37,20,65,145,32,7, -218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,158,142,183,86,74,41,48, -92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,246,136,235,103,167,165, -213,146,138,40,200,144,3,237,17,214,207,79,75,161,37,20,138,46,36,0,248, -134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,75,161,37,20,170,46,36, -0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,39,208,146,138,70,25,18, -0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,129,89,58,18,81,72,226, -162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,17,214,207,161,37,22,144, -38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,207,161,37,22,176,42,209, -68,201,218,35,173,158,197,54,4,218,40,153,56,134,207,98,155,75,27,104,162, -100,237,17,214,207,71,91,171,37,54,65,182,138,38,78,209,29,108,244,117,186, -18,83,104,131,45,20,76,156,67,103,163,173,213,146,155,76,25,104,162,100, -226,27,61,29,110,132,148,218,160,219,69,19,39,104,142,182,122,122,93,89,41, -178,141,180,81,50,118,136,235,103,167,165,208,146,155,69,25,104,162,100, -226,27,61,61,46,172,148,218,104,203,69,19,39,16,217,233,233,116,36,166,213, -70,90,40,153,56,85,184,19,234,201,77,152,101,162,137,147,133,91,129,62,132, -148,218,48,219,69,19,39,6,234,5,100,234,201,77,156,109,162,137,147,131,117, -2,178,116,36,166,209,197,218,40,153,59,68,117,179,234,201,78,32,11,180,81, -50,118,136,235,103,208,146,156,72,21,104,162,100,226,27,62,172,148,226,128, -171,69,19,39,16,217,244,36,167,22,53,59,22,53,91,0,2,21,11,94,181,128,196, -133,0,185,80,32,56,156,199,130,36,160,72,16,78,126,53,144,5,146,208,34,82, -72,1,109,20,76,155,40,32,233,0,115,70,130,8,209,56,104,105,187,252,193,3, -17,162,112,201,242,18,65,211,0,230,149,132,17,162,112,208,211,119,248,0,82, -130,96,95,127,128,130,80,102,186,36,232,92,206,255,1,80,48,200,39,12,158, -241,64, +18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,232,59, +147,60,93,110,79,15,39,9,24,186,33,13,63,111,185,16,211,206,251,114,98,17, +171,160,11,199,197,215,196,66,26,102,38,68,53,212,77,136,104,255,5,114,120, +121,7,192,70,32,192,67,95,249,59,13,13,127,228,248,134,191,242,133,208,215, +254,81,204,67,95,249,75,33,13,127,229,61,84,53,255,149,52,80,215,254,85, +217,67,95,249,91,121,13,90,181,168,134,143,152,95,38,75,207,132,104,156,50, +70,33,163,225,66,249,50,94,124,25,4,225,146,49,14,24,28,196,7,255,128,0,0, +0,0,0,12,204,7,255,0,0,0,0,0,0,12,188,72,6,176,77,225,28,24,103,14,33,197, +138,113,227,28,152,231,46,65,205,19,194,84,11,225,35,23,68,231,138,228,64, +211,19,132,140,93,19,162,59,145,33,73,18,52,68,225,35,23,68,233,139,228, +176,217,130,252,36,98,232,157,81,60,158,30,78,18,49,116,78,184,142,210,40, +39,99,23,68,236,201,59,114,142,224,126,14,138,152,30,67,188,23,143,139,175, +131,194,135,228,72,85,144,83,60,53,163,208,76,60,68,211,197,78,60,116,243, +200,80,60,149,19,202,82,60,181,51,204,84,60,213,83,206,86,60,240,190,76, +151,159,8,209,56,100,137,232,133,242,100,188,248,50,9,195,36,79,73,26,238, +108,129,15,4,100,78,33,179,207,160,41,224,140,137,194,173,192,158,120,128, +168,151,26,14,55,58,64,132,75,133,67,81,50,103,8,18,50,9,195,39,105,20,101, +136,36,50,9,195,39,105,20,11,174,99,220,210,54,121,114,4,145,162,112,201, +218,69,25,130,9,17,162,112,201,218,69,2,235,152,247,52,141,158,100,128,196, +144,128,242,102,136,17,70,146,66,3,201,160,32,0,130,225,48,113,137,62,62, +46,155,167,135,147,142,47,24,147,79,205,68,48,98,79,142,179,120,248,185, +228,140,241,193,146,66,138,31,55,71,126,129,51,18,124,117,155,199,197,207, +36,103,142,52,12,36,184,100,129,129,41,32,205,221,175,3,10,36,4,201,188,64, +112,200,84,52,156,124,92,242,70,120,223,48,64,100,42,26,78,62,46,121,35,52, +18,91,212,2,72,128,95,20,128,197,137,9,146,113,73,8,190,36,169,27,62,18, +243,35,100,135,54,92,66,4,34,92,145,0,178,15,132,64,132,75,133,139,178,70, +240,137,6,34,92,37,230,70,201,1,89,56,36,4,81,49,46,25,5,76,73,241,214,111, +31,23,60,145,158,57,44,48,46,92,184,100,160,145,46,2,0,201,168,207,198,230, +144,117,60,176,48,156,160,48,188,192,7,28,18,227,172,222,62,46,121,35,60, +113,200,26,137,113,241,116,221,60,60,156,113,121,4,20,124,92,242,70,120, +226,37,194,54,140,36,64,21,147,146,68,24,32,57,0,125,78,84,0,160,123,215, +140,146,1,4,5,175,40,124,8,20,52,121,51,228,24,96,129,209,46,2,49,6,20,135, +33,20,53,50,128,194,65,4,12,39,52,64,155,31,48,112,72,6,247,62,16,1,31,73, +30,25,240,60,73,82,70,68,138,0,89,29,5,156,96,2,201,104,17,35,160,18,78, +140,228,16,26,79,90,4,73,43,192,244,108,142,130,206,89,240,58,26,50,95,142, +43,159,65,107,4,167,196,52,100,191,28,87,63,128,15,255,240,164,169,35,136, +6,128,146,115,9,0,210,7,43,163,194,0,71,128,105,65,176,15,128,105,131,21, +11,153,35,0,211,134,137,7,65,18,33,244,23,18,14,130,39,34,131,30,113,15, +224,3,255,254,12,80,81,133,139,153,193,28,17,224,156,50,119,15,131,75,23, +51,130,112,201,199,185,13,159,116,248,228,68,219,66,149,83,83,238,3,11,238, +0,48,142,8,240,19,239,144,40,71,4,120,39,12,156,4,252,4,11,19,134,78,61, +200,108,248,9,248,9,3,9,205,16,39,225,62,7,67,70,75,241,197,241,154,5,172, +18,159,16,209,146,252,113,124,102,144,106,220,32,44,156,19,152,240,68,158, +66,2,176,19,17,252,164,7,137,30,176,8,158,116,3,72,128,136,143,232,32,44, +150,129,19,210,128,89,61,104,159,169,1,50,160,101,56,161,166,246,160,46, +110,226,221,98,71,130,4,137,222,0,140,221,197,184,64,89,56,183,88,145,224, +129,34,119,128,23,55,114,143,121,35,193,2,68,239,2,17,155,184,183,8,11,39, +40,247,146,60,16,36,78,240,32,73,197,12,247,128,26,36,121,1,63,49,2,165,48, +70,114,229,145,51,250,205,2,8,209,203,150,68,207,235,52,130,16,209,46,131, +36,188,70,128,210,160,101,56,251,16,131,28,7,35,38,218,50,234,103,130,97, +103,129,6,73,0,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,7,36,38,218,0, +0,0,0,0,0,0,0,4,29,78,224,140,38,216,140,46,228,0,243,119,10,139,144,123, +82,6,205,220,37,222,230,145,179,64,23,180,32,92,221,199,196,130,68,144,230, +237,200,131,44,24,43,193,25,18,185,0,251,73,138,199,240,27,93,106,192,57, +41,54,210,31,254,0,0,0,0,0,0,49,58,155,192,12,155,184,48,76,156,148,226, +134,154,240,32,201,187,147,67,9,201,78,40,105,175,2,225,47,3,18,155,184, +183,8,11,39,6,9,147,146,156,80,211,94,7,37,55,113,110,16,22,78,77,12,39,37, +56,161,166,188,16,48,215,130,14,30,240,66,213,93,35,11,124,0,230,36,249,52, +48,151,192,22,98,79,133,162,215,204,16,17,178,16,199,24,147,237,38,34,246, +139,95,48,64,70,200,68,16,98,79,140,115,102,123,33,20,89,137,62,210,98,103, +92,217,158,200,70,14,98,79,131,4,201,100,35,138,49,39,218,76,67,232,38,75, +33,32,49,137,62,12,24,178,18,68,152,147,237,38,33,244,24,178,18,132,24,147, +225,221,72,202,200,75,22,98,79,180,152,143,215,82,50,178,19,5,24,147,227, +16,218,76,146,178,19,70,152,147,237,38,38,117,13,164,201,43,33,56,81,137, +62,72,130,115,71,43,33,60,105,137,62,210,98,151,72,39,52,114,178,20,7,152, +147,227,16,181,162,68,19,154,57,89,10,36,140,73,246,147,19,58,133,173,18, +32,156,209,202,200,82,34,98,79,147,67,9,151,52,156,113,75,34,78,208,1,228, +73,242,104,97,46,16,62,68,159,24,133,173,18,32,156,209,202,217,83,37,34,79, +180,152,153,212,45,104,145,4,230,142,86,202,160,169,18,124,145,4,230,142, +86,215,213,27,34,79,180,152,165,210,9,205,28,173,175,172,42,68,159,24,134, +210,100,149,183,245,198,200,147,237,38,38,117,13,164,201,43,111,236,8,145, +39,195,186,145,149,185,246,69,200,147,237,38,35,245,212,140,173,207,180,30, +68,159,6,9,146,217,91,21,34,79,180,152,135,208,76,150,202,224,137,18,124, +99,155,51,219,95,116,92,137,62,210,98,103,92,217,158,218,251,194,228,73, +240,180,90,249,130,2,54,223,223,29,34,79,180,152,139,218,45,124,193,1,27, +111,240,33,204,73,243,4,4,108,134,8,60,137,62,96,128,141,178,193,193,154,3, +147,32,227,36,0,0,0,0,0,0,0,0,99,115,245,195,19,159,176,75,175,159,176,24, +172,253,129,49,121,251,2,176,66,92,130,235,16,18,100,148,251,36,106,123,64, +65,158,3,147,160,108,202,62,68,165,107,243,227,113,198,211,62,39,20,108, +115,226,241,130,106,113,224,78,162,4,242,130,236,197,60,37,64,190,18,49, +116,114,37,40,157,76,9,229,37,217,138,185,16,52,196,225,35,23,71,34,82,137, +213,64,158,84,93,152,187,145,33,73,18,52,68,225,35,23,71,34,82,137,213,192, +158,86,93,152,175,146,195,102,11,240,145,139,163,145,41,68,235,32,79,44,46, +204,83,201,225,228,225,35,23,71,34,82,137,214,192,158,90,93,152,163,180, +138,9,216,197,209,200,148,161,194,32,30,18,2,0,45,248,84,88,162,187,72,78, +173,186,58,16,16,0,154,236,110,237,85,69,129,245,109,210,128,127,204,92, +133,253,244,115,222,23,171,113,180,137,0,255,220,85,29,148,174,11,248,55, +86,227,104,232,18,1,254,222,91,216,169,55,40,112,46,189,16,16,2,72,126,213, +17,11,70,3,246,80,140,244,118,180,160,31,243,80,79,51,63,157,230,133,236, +161,25,233,64,63,246,160,158,102,127,59,205,41,248,30,75,12,11,151,242,233, +187,146,156,80,211,114,96,54,230,41,20,129,128,50,211,16,16,2,116,180,196, +129,1,36,55,76,74,16,19,3,116,196,193,65,48,55,75,80,128,65,6,51,211,20, +128,130,34,23,166,39,6,39,75,76,80,1,146,239,211,20,16,165,91,157,29,49,66, +10,124,61,211,209,175,1,173,198,211,20,48,139,113,180,180,197,36,42,220, +109,29,13,49,74,6,192,95,72,188,6,196,55,74,188,6,247,91,80,136,26,32,104, +220,205,56,1,98,234,52,122,98,136,14,72,110,152,162,132,148,35,61,49,70,7, +48,55,76,81,194,206,52,104,180,197,45,192,80,175,4,100,77,10,2,101,56,161, +166,65,113,162,98,8,3,131,7,169,35,36,57,176,16,52,232,80,0,0,0,0,45,158, +10,225,223,132,17,13,43,176,228,3,0,167,129,32,17,133,134,32,25,80,220,40, +240,25,26,44,32,240,24,200,44,24,240,56,156,199,128,83,193,17,7,4,13,128,0, +10,79,202,28,223,195,1,197,72,196,141,159,220,7,48,33,7,8,3,152,49,117,60, +240,76,47,60,9,224,187,56,43,224,221,64,172,156,36,98,232,228,96,220,145, +139,163,182,134,237,146,49,116,118,206,6,141,104,105,136,32,14,4,128,160, +123,215,140,147,32,145,57,178,156,104,41,228,151,168,225,144,168,105,56, +248,185,228,140,241,190,100,209,244,80,210,116,151,134,12,73,241,214,111, +31,23,60,145,158,56,50,72,81,67,230,232,239,209,7,24,147,227,226,233,186, +120,121,56,226,241,137,116,189,52,6,34,92,37,230,70,201,1,89,56,36,154,110, +25,49,23,196,149,35,103,194,94,100,108,144,230,203,136,73,174,234,63,52, +252,212,87,0,131,138,4,12,137,114,168,37,166,144,230,37,5,7,19,39,22,70, +154,103,143,252,4,11,37,160,68,164,139,7,24,3,152,182,20,28,76,156,89,26, +105,158,63,240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253,132, +176,230,36,248,134,207,98,138,99,4,24,147,229,16,217,236,81,75,98,12,73, +241,13,158,142,181,20,198,137,49,39,202,33,179,209,214,162,151,4,24,147, +226,27,61,61,42,41,142,18,98,79,148,67,103,167,165,69,46,138,49,39,194,173, +192,158,158,149,20,188,40,196,159,10,183,2,122,218,148,82,248,121,18,124, +67,103,177,77,177,130,36,73,242,136,108,246,41,181,177,18,36,248,134,207, +71,90,155,99,68,200,147,229,16,217,232,235,83,107,130,36,73,241,13,158,158, +149,54,199,9,145,39,202,33,179,211,210,166,215,69,72,147,225,86,224,79,79, +74,155,94,21,34,79,133,91,129,61,109,74,109,126,14,56,7,6,20,28,76,156,89, +26,105,158,63,240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253, +130,235,191,232,8,149,2,8,196,24,164,137,141,200,8,71,161,196,201,45,167, +146,59,68,89,24,70,206,1,255,128,0,0,0,0,0,1,142,49,232,71,161,196,201,45, +167,146,59,68,89,24,70,206,1,255,128,0,0,0,0,0,1,141,201,8,71,161,196,201, +45,167,146,59,68,89,24,70,206,1,255,128,0,0,0,0,0,2,138,2,214,225,113,235, +2,27,128,0,10,66,3,189,96,67,120,226,224,0,2,148,140,113,145,66,61,14,38, +73,109,60,145,218,34,200,194,54,112,15,252,0,0,0,0,0,0,12,110,80,66,61,14, +38,73,109,60,145,218,34,200,194,54,112,15,252,0,0,0,0,0,0,12,113,147,66,61, +14,38,73,109,60,145,218,34,200,194,54,112,15,252,0,0,0,0,0,0,12,110,88,66, +61,14,38,73,109,60,145,218,34,200,194,54,112,16,0,0,0,0,0,0,0,12,113,149, +66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,0,0,0,0,0,0,0,12,110,96, +66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,0,0,0,0,0,0,0,12,113, +151,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,0,0,0,0,0,0,0,12, +110,104,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0,0,0,0,0,0, +12,113,153,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0,0,0,0,0, +0,12,110,112,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0,0,0,0, +0,0,12,113,155,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0,0,0, +0,0,0,12,110,120,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0,0, +0,0,0,0,12,113,157,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0, +0,0,0,0,0,12,110,128,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,8, +0,0,0,0,0,0,12,113,159,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16, +8,0,0,0,0,0,0,8,58,32,128,24,78,104,129,61,82,2,145,46,17,162,112,208,211, +107,200,16,137,112,52,41,73,29,113,2,131,137,147,139,35,77,51,234,80,14,39, +49,224,137,40,35,100,141,9,136,19,18,0,125,162,58,217,236,81,64,68,72,1, +241,13,158,197,20,150,50,36,0,251,68,117,179,209,214,234,201,69,16,100,72, +1,246,136,235,103,163,173,208,146,138,68,23,18,0,124,67,103,163,173,213, +146,138,76,23,18,0,124,67,103,163,173,208,146,138,84,25,18,0,125,162,58, +217,233,233,117,100,162,138,50,36,0,251,68,117,179,211,210,232,73,69,34, +139,137,0,62,33,179,211,210,234,201,69,38,139,137,0,62,33,179,211,210,232, +73,69,42,139,137,0,62,21,110,4,250,178,81,70,23,18,0,124,42,220,9,244,36, +162,145,134,68,128,31,6,234,5,100,234,201,69,28,100,72,1,240,110,160,86,78, +132,148,82,56,168,144,3,237,17,214,207,171,37,22,128,42,36,0,251,68,117, +179,232,73,69,164,9,137,0,62,33,179,234,201,69,168,9,137,0,62,33,179,232, +73,69,172,10,180,81,50,118,136,235,103,177,77,129,54,138,38,78,33,179,216, +166,210,198,218,40,153,59,68,117,179,209,214,234,201,77,144,109,162,137, +147,180,71,91,61,29,110,132,148,218,32,203,69,19,39,16,217,232,235,117,100, +166,211,6,90,40,153,56,134,207,71,91,161,37,54,168,54,209,68,201,218,35, +173,158,158,151,86,74,108,163,109,20,76,157,162,58,217,233,233,116,36,166, +209,70,90,40,153,56,134,207,79,75,171,37,54,154,50,209,68,201,196,54,122, +122,93,9,41,181,81,150,138,38,78,21,110,4,250,178,83,102,25,104,162,100, +225,86,224,79,161,37,54,140,54,209,68,201,193,186,129,89,58,178,83,103,27, +104,162,100,224,221,64,172,157,9,41,180,113,118,138,38,78,209,29,108,250, +178,83,136,2,237,20,76,157,162,58,217,244,36,167,18,5,90,40,153,56,134,207, +171,37,56,160,42,209,68,201,196,54,125,9,41,197,141,78,197,141,86,192,0, +133,66,215,173,96,49,33,64,46,84,8,14,39,49,224,137,40,18,4,19,159,141,100, +1,100,180,8,148,146,0,91,69,19,38,202,8,58,64,28,209,160,130,52,78,26,26, +110,255,80,64,196,104,156,50,125,4,144,116,192,57,165,97,4,104,156,52,52, +221,254,64,20,160,152,23,223,228,32,148,25,174,137,58,23,51,191,200,84,12, +50,9,195,39,196,80, }; #elif defined(DUK_USE_DOUBLE_ME) -DUK_INTERNAL const duk_uint8_t duk_builtins_data[3790] = { +DUK_INTERNAL const duk_uint8_t duk_builtins_data[3819] = { 144,148,105,221,32,68,52,228,62,12,104,200,165,134,148,248,81,77,61,191, 135,35,154,103,34,72,6,157,159,197,145,77,245,126,52,130,106,234,163,196, 52,226,18,51,161,26,113,1,60,37,64,190,18,49,116,116,33,26,113,1,92,136,26, 98,112,145,139,163,165,8,211,136,14,228,72,82,68,141,17,56,72,197,209,212, 132,105,196,5,242,88,108,193,126,18,49,116,117,161,26,113,1,60,158,30,78, -18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,224,59, -147,60,93,110,79,15,39,9,24,186,33,13,63,79,185,39,26,121,223,110,77,66,53, -116,1,120,248,186,248,136,67,76,196,200,134,186,137,177,13,31,192,174,79, -15,32,248,8,196,24,8,107,254,39,97,161,175,248,159,16,215,252,80,186,26, -255,138,57,136,107,254,41,100,33,175,248,167,170,134,191,226,166,138,26, -255,138,187,40,107,254,43,111,33,171,86,181,16,209,241,11,228,201,121,240, -141,19,134,72,196,52,123,168,95,38,75,207,131,32,156,50,70,33,195,3,152, -128,0,1,240,254,0,0,0,1,153,128,0,1,224,254,0,0,0,1,151,137,0,214,9,188,35, -131,12,225,196,56,177,78,60,99,147,28,229,200,57,162,120,74,129,124,36,98, -232,156,241,92,136,26,98,112,145,139,162,116,71,114,36,41,34,70,136,156,36, -98,232,157,49,124,150,27,48,95,132,140,93,19,170,39,147,195,201,194,70,46, -137,215,17,218,69,4,236,98,232,157,153,39,110,81,220,15,193,209,83,3,200, -119,130,241,241,117,240,120,80,252,137,10,178,10,103,134,180,122,9,135,136, -154,120,169,199,142,158,121,10,7,146,162,121,74,71,150,166,121,138,135,154, -170,121,202,199,158,23,201,146,243,225,26,39,12,145,61,16,190,76,151,159,6, -65,56,100,137,233,35,93,205,144,33,224,140,137,196,54,121,244,5,60,17,145, -56,85,184,19,207,16,21,18,227,65,198,231,72,16,137,112,168,106,38,76,225,2, -70,65,56,100,237,34,140,177,4,134,65,56,100,237,34,129,117,204,123,154,70, -207,46,64,146,52,78,25,59,72,163,48,65,34,52,78,25,59,72,160,93,115,30,230, -145,179,204,144,24,146,16,30,76,209,2,40,210,72,64,121,52,4,0,156,88,97,5, -194,96,227,18,124,124,93,55,79,15,39,28,94,49,38,159,154,136,96,196,159,29, -102,241,241,115,201,25,227,131,36,133,20,62,110,142,253,2,102,36,248,235, -55,143,139,158,72,207,28,104,24,73,112,201,3,2,82,65,155,187,94,6,20,72,9, -147,120,128,225,144,168,105,56,248,185,228,140,241,190,96,128,200,84,52, -156,124,92,242,70,104,36,183,168,4,145,0,190,41,1,139,18,19,36,226,146,17, -124,73,82,54,124,37,230,70,201,14,108,184,132,8,68,185,34,1,100,31,8,129,8, -151,11,23,100,141,225,18,12,68,184,75,204,141,146,2,178,112,72,8,162,98,92, -50,10,152,147,227,172,222,62,46,121,35,60,114,88,96,92,185,112,201,65,34, -92,4,1,147,81,159,141,205,32,234,121,96,97,57,64,97,121,128,14,56,37,199, -89,188,124,92,242,70,120,227,144,53,18,227,226,233,186,120,121,56,226,242, -8,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,36,136,48,64,114,0, -250,156,168,1,64,247,175,25,36,2,8,11,94,80,248,16,40,104,242,103,200,48, -193,3,162,92,4,98,12,41,14,66,40,106,101,1,132,130,8,24,78,104,129,54,62, -96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,178, -58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,129, -232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,201, -126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,132, -0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,46, -36,29,4,78,69,6,60,226,31,192,7,255,252,24,160,163,11,23,51,130,56,35,193, -56,100,238,31,6,150,46,103,4,225,147,143,114,27,62,233,241,200,137,182,133, -42,142,167,216,6,23,216,0,97,28,17,224,39,223,32,80,142,8,240,78,25,56,9, -248,8,22,39,12,156,123,144,217,240,19,240,18,6,19,154,32,79,194,124,14,134, -140,151,227,139,226,52,11,88,37,62,33,163,37,248,226,248,141,32,213,184,64, -89,56,39,49,224,137,60,100,5,96,38,35,249,8,15,18,61,96,17,60,200,6,145,1, -17,31,206,64,89,45,2,39,161,0,178,122,209,63,74,2,101,64,202,113,67,77,235, -64,92,221,197,186,196,143,4,9,19,188,1,25,187,139,112,128,178,113,110,177, -35,193,2,68,239,0,46,110,229,30,242,71,130,4,137,222,4,35,55,113,110,16,22, -78,81,239,36,120,32,72,157,224,64,147,138,25,237,0,52,72,242,2,126,82,3,74, -129,148,227,234,66,12,112,28,140,155,104,203,169,158,9,133,158,4,25,36,1, -61,96,47,181,80,46,132,129,255,255,222,255,255,255,255,254,39,172,67,118, -170,5,208,144,0,0,0,0,0,64,0,0,51,16,0,0,62,31,192,0,0,0,8,245,238,146,38, -138,147,105,13,42,26,137,226,0,0,7,131,248,0,0,0,1,30,180,134,4,209,82,109, -33,165,67,81,60,64,0,0,240,255,0,0,0,0,28,144,155,104,0,0,0,0,0,0,0,0,16, -117,59,130,48,155,98,48,187,144,3,205,220,42,46,65,237,72,27,55,112,151, -123,154,70,205,0,94,208,129,115,119,31,18,9,18,67,155,183,34,12,176,96,175, -4,100,74,228,3,237,38,43,31,192,109,117,171,0,228,164,219,72,0,0,248,127,0, -0,0,0,196,234,111,0,50,110,224,193,50,114,83,138,26,107,192,131,38,238,77, -12,39,37,56,161,166,188,11,132,188,12,74,110,226,220,32,44,156,24,38,78,74, -113,67,77,120,28,148,221,197,184,64,89,57,52,48,156,148,226,134,154,240,64, -195,94,8,56,123,193,11,85,116,140,45,240,3,152,147,228,208,194,95,0,89,137, -62,22,139,95,48,64,70,200,67,28,98,79,180,152,139,218,45,124,193,1,27,33, -16,65,137,62,49,205,153,236,132,81,102,36,251,73,137,157,115,102,123,33,24, -57,137,62,12,19,37,144,142,40,196,159,105,49,15,160,153,44,132,128,198,36, -248,48,98,200,73,18,98,79,180,152,135,208,98,200,74,16,98,79,135,117,35,43, -33,44,89,137,62,210,98,63,93,72,202,200,76,20,98,79,140,67,105,50,74,200, -77,26,98,79,180,152,153,212,54,147,36,172,132,225,70,36,249,34,9,205,28, -172,132,241,166,36,251,73,138,93,32,156,209,202,200,80,30,98,79,140,66,214, -137,16,78,104,229,100,40,146,49,39,218,76,76,234,22,180,72,130,115,71,43, -33,72,137,137,62,77,12,38,92,210,113,197,44,137,59,64,7,145,39,201,161,132, -184,64,249,18,124,98,22,180,72,130,115,71,43,101,76,148,137,62,210,98,103, -80,181,162,68,19,154,57,91,42,130,164,73,242,68,19,154,57,91,95,84,108,137, -62,210,98,151,72,39,52,114,182,190,176,169,18,124,98,27,73,146,86,223,215, -27,34,79,180,152,153,212,54,147,36,173,191,176,34,68,159,14,234,70,86,231, -217,23,34,79,180,152,143,215,82,50,183,62,208,121,18,124,24,38,75,101,108, -84,137,62,210,98,31,65,50,91,43,130,36,73,241,142,108,207,109,125,209,114, -36,251,73,137,157,115,102,123,107,239,11,145,39,194,209,107,230,8,8,219, -127,124,116,137,62,210,98,47,104,181,243,4,4,109,191,192,135,49,39,204,16, -17,178,24,32,242,36,249,130,2,54,203,7,6,104,14,76,131,140,144,0,0,0,0,0,0, -0,1,141,207,215,12,78,126,193,46,190,126,192,98,179,246,4,197,231,236,10, -193,9,114,11,172,64,73,146,83,236,145,169,237,1,6,120,14,78,129,179,40,249, -18,149,175,207,141,199,27,76,248,156,81,177,207,139,198,9,169,199,129,58, -136,19,202,11,179,20,240,149,2,248,72,197,209,200,148,162,117,48,39,148, -151,102,42,228,64,211,19,132,140,93,28,137,74,39,85,2,121,81,118,98,238,68, -133,36,72,209,19,132,140,93,28,137,74,39,87,2,121,89,118,98,190,75,13,152, -47,194,70,46,142,68,165,19,172,129,60,176,187,49,79,39,135,147,132,140,93, -28,137,74,39,91,2,121,105,118,98,142,210,40,39,99,23,71,34,82,135,8,128, -120,72,1,87,224,168,13,42,226,145,97,58,182,232,232,64,177,107,2,64,22,85, -181,187,7,213,183,74,2,17,119,49,255,121,207,215,240,94,173,198,210,36,4, -113,95,115,255,232,34,182,80,221,91,141,163,160,72,15,121,123,103,225,220, -164,194,160,186,244,64,251,33,9,64,24,45,68,84,15,217,66,51,209,218,210, -129,61,65,204,127,154,118,254,204,23,178,132,103,165,2,122,131,216,255,52, -237,253,152,167,224,121,44,48,46,95,203,166,238,74,113,67,77,201,128,219, -152,164,82,6,0,203,76,64,64,9,210,211,18,4,4,144,221,49,40,64,76,13,211,19, -5,4,192,221,45,66,1,4,24,207,76,82,2,8,136,94,152,156,24,157,45,49,64,6,75, -191,76,80,66,149,110,116,116,197,8,41,240,247,79,70,188,6,183,27,76,80,194, -45,198,210,211,20,144,171,113,180,116,52,197,40,27,1,125,34,240,27,16,221, -42,240,27,221,109,66,32,104,129,163,115,52,224,5,139,168,209,233,138,32,57, -33,186,98,138,18,80,140,244,197,24,28,192,221,49,71,11,56,209,162,211,20, -183,1,66,188,17,145,52,40,9,148,226,134,153,5,198,137,136,32,14,12,30,164, -140,144,230,192,0,136,211,64,0,0,0,0,182,120,43,135,126,16,68,52,174,195, -144,12,2,158,4,128,70,22,24,128,101,67,112,163,192,100,104,176,131,192,99, -32,176,99,192,226,115,30,1,79,4,68,28,16,54,0,0,41,254,232,116,62,204,7,21, -35,18,54,127,80,28,192,132,28,32,14,96,197,212,243,193,48,188,240,39,130, -236,224,175,131,117,2,178,112,145,139,163,145,131,114,70,46,142,218,27,182, -72,197,209,219,56,26,53,161,166,32,128,56,18,2,129,239,94,50,76,130,68,230, -202,113,160,167,146,94,163,134,66,161,164,227,226,231,146,51,198,249,147, -71,209,67,73,210,94,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15, -155,163,191,68,28,98,79,143,139,166,233,225,228,227,139,198,37,210,244,208, -24,137,112,151,153,27,36,5,100,224,146,105,184,100,196,95,18,84,141,159,9, -121,145,178,67,155,46,33,38,187,168,252,211,243,81,92,2,14,40,16,50,37,202, -160,150,154,67,152,148,20,28,76,156,89,26,105,158,63,232,16,44,150,129,18, -146,44,28,96,14,98,216,80,113,50,113,100,105,166,120,255,160,20,28,76,156, -113,75,34,78,63,236,3,6,133,41,35,31,242,18,195,152,147,226,27,61,138,41, -140,16,98,79,148,67,103,177,69,45,136,49,39,196,54,122,58,212,83,26,36,196, -159,40,134,207,71,90,138,92,16,98,79,136,108,244,244,168,166,56,73,137,62, -81,13,158,158,149,20,186,40,196,159,10,183,2,122,122,84,82,240,163,18,124, -42,220,9,235,106,81,75,225,228,73,241,13,158,197,54,198,8,145,39,202,33, -179,216,166,214,196,72,147,226,27,61,29,106,109,141,19,34,79,148,67,103, -163,173,77,174,8,145,39,196,54,122,122,84,219,28,38,68,159,40,134,207,79, -74,155,93,21,34,79,133,91,129,61,61,42,109,120,84,137,62,21,110,4,245,181, -41,181,248,56,224,28,24,80,113,50,113,100,105,166,120,255,160,20,28,76,156, -113,75,34,78,63,236,3,6,133,41,35,31,242,11,174,254,160,34,84,8,35,16,98, -146,38,55,32,33,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,30,7,224,0, -0,0,6,56,199,161,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,30,7,224, -0,0,0,6,55,36,33,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,30,7,224, -0,0,0,10,40,11,91,133,199,172,8,111,248,128,239,88,16,222,56,191,242,49, -198,69,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,240,63,0,0,0,0, -49,185,65,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,240,63,0,0,0, -0,49,198,77,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,240,63,0,0, -0,0,49,185,97,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,0, -0,0,49,198,85,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,0, -0,0,49,185,129,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0, -0,0,0,49,198,93,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0, -0,0,0,49,185,161,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,16,64, -0,0,0,0,49,198,101,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,16, -64,0,0,0,0,49,185,193,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0, -16,64,0,0,0,0,49,198,109,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0, -0,16,64,0,0,0,0,49,185,225,8,244,56,153,37,180,242,71,104,139,35,8,217,192, -0,0,16,64,0,0,0,0,49,198,117,8,244,56,153,37,180,242,71,104,139,35,8,217, -192,0,0,16,64,0,0,0,0,49,186,1,8,244,56,153,37,180,242,71,104,139,35,8,217, -192,0,0,32,64,0,0,0,0,49,198,125,8,244,56,153,37,180,242,71,104,139,35,8, -217,192,0,0,32,64,0,0,0,0,32,232,130,0,97,57,162,4,245,72,10,68,184,70,137, -195,67,77,175,32,66,37,192,208,165,36,117,196,10,14,38,78,44,141,52,207, -169,64,56,156,199,130,36,160,141,146,52,38,32,76,72,1,246,136,235,103,177, -69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,171,37,20, -65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,158,142,183, -86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,246,136,235, -103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,37,20,138,46, -36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,75,161,37,20, -170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,39,208,146,138, -70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,129,89,58,18, -81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,17,214,207,161, -37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,207,161,37,22, -176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,207,98,155,75, -27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,78,209,29,108, -244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,146,155,76,25, -104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,104,142,182,122, -122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,146,155,69,25, -104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,217,233,233, -116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,162,137,147, -133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,77,156,109, -162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,117,179,234, -201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,162,100,226, -27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,59,22,53,91,0,2, -21,11,94,181,128,196,133,0,185,80,32,56,156,199,130,36,160,72,16,78,126,53, -144,5,146,208,34,82,72,1,109,20,76,155,40,32,233,0,115,70,130,8,209,56,104, -105,187,252,193,3,17,162,112,201,242,18,65,211,0,230,149,132,17,162,112, -208,211,119,248,0,82,130,96,95,127,128,130,80,102,186,36,232,92,206,255,1, -80,48,200,39,12,158,241,64, +18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,232,59, +147,60,93,110,79,15,39,9,24,186,33,13,63,111,185,16,211,206,251,114,98,17, +171,160,11,199,197,215,196,66,26,102,38,68,53,212,77,136,104,255,5,114,120, +121,7,192,70,32,192,67,95,249,59,13,13,127,228,248,134,191,242,133,208,215, +254,81,204,67,95,249,75,33,13,127,229,61,84,53,255,149,52,80,215,254,85, +217,67,95,249,91,121,13,90,181,168,134,143,152,95,38,75,207,132,104,156,50, +70,33,163,225,66,249,50,94,124,25,4,225,146,49,14,24,28,196,0,0,15,135,240, +0,0,0,12,204,0,0,15,7,240,0,0,0,12,188,72,6,176,77,225,28,24,103,14,33,197, +138,113,227,28,152,231,46,65,205,19,194,84,11,225,35,23,68,231,138,228,64, +211,19,132,140,93,19,162,59,145,33,73,18,52,68,225,35,23,68,233,139,228, +176,217,130,252,36,98,232,157,81,60,158,30,78,18,49,116,78,184,142,210,40, +39,99,23,68,236,201,59,114,142,224,126,14,138,152,30,67,188,23,143,139,175, +131,194,135,228,72,85,144,83,60,53,163,208,76,60,68,211,197,78,60,116,243, +200,80,60,149,19,202,82,60,181,51,204,84,60,213,83,206,86,60,240,190,76, +151,159,8,209,56,100,137,232,133,242,100,188,248,50,9,195,36,79,73,26,238, +108,129,15,4,100,78,33,179,207,160,41,224,140,137,194,173,192,158,120,128, +168,151,26,14,55,58,64,132,75,133,67,81,50,103,8,18,50,9,195,39,105,20,101, +136,36,50,9,195,39,105,20,11,174,99,220,210,54,121,114,4,145,162,112,201, +218,69,25,130,9,17,162,112,201,218,69,2,235,152,247,52,141,158,100,128,196, +144,128,242,102,136,17,70,146,66,3,201,160,32,0,130,225,48,113,137,62,62, +46,155,167,135,147,142,47,24,147,79,205,68,48,98,79,142,179,120,248,185, +228,140,241,193,146,66,138,31,55,71,126,129,51,18,124,117,155,199,197,207, +36,103,142,52,12,36,184,100,129,129,41,32,205,221,175,3,10,36,4,201,188,64, +112,200,84,52,156,124,92,242,70,120,223,48,64,100,42,26,78,62,46,121,35,52, +18,91,212,2,72,128,95,20,128,197,137,9,146,113,73,8,190,36,169,27,62,18, +243,35,100,135,54,92,66,4,34,92,145,0,178,15,132,64,132,75,133,139,178,70, +240,137,6,34,92,37,230,70,201,1,89,56,36,4,81,49,46,25,5,76,73,241,214,111, +31,23,60,145,158,57,44,48,46,92,184,100,160,145,46,2,0,201,168,207,198,230, +144,117,60,176,48,156,160,48,188,192,7,28,18,227,172,222,62,46,121,35,60, +113,200,26,137,113,241,116,221,60,60,156,113,121,4,20,124,92,242,70,120, +226,37,194,54,140,36,64,21,147,146,68,24,32,57,0,125,78,84,0,160,123,215, +140,146,1,4,5,175,40,124,8,20,52,121,51,228,24,96,129,209,46,2,49,6,20,135, +33,20,53,50,128,194,65,4,12,39,52,64,155,31,48,112,72,6,247,62,16,1,31,73, +30,25,240,60,73,82,70,68,138,0,89,29,5,156,96,2,201,104,17,35,160,18,78, +140,228,16,26,79,90,4,73,43,192,244,108,142,130,206,89,240,58,26,50,95,142, +43,159,65,107,4,167,196,52,100,191,28,87,63,128,15,255,240,164,169,35,136, +6,128,146,115,9,0,210,7,43,163,194,0,71,128,105,65,176,15,128,105,131,21, +11,153,35,0,211,134,137,7,65,18,33,244,23,18,14,130,39,34,131,30,113,15, +224,3,255,254,12,80,81,133,139,153,193,28,17,224,156,50,119,15,131,75,23, +51,130,112,201,199,185,13,159,116,248,228,68,219,66,149,83,83,238,3,11,238, +0,48,142,8,240,19,239,144,40,71,4,120,39,12,156,4,252,4,11,19,134,78,61, +200,108,248,9,248,9,3,9,205,16,39,225,62,7,67,70,75,241,197,241,154,5,172, +18,159,16,209,146,252,113,124,102,144,106,220,32,44,156,19,152,240,68,158, +66,2,176,19,17,252,164,7,137,30,176,8,158,116,3,72,128,136,143,232,32,44, +150,129,19,210,128,89,61,104,159,169,1,50,160,101,56,161,166,246,160,46, +110,226,221,98,71,130,4,137,222,0,140,221,197,184,64,89,56,183,88,145,224, +129,34,119,128,23,55,114,143,121,35,193,2,68,239,2,17,155,184,183,8,11,39, +40,247,146,60,16,36,78,240,32,73,197,12,247,128,26,36,121,1,63,49,2,165,48, +70,114,229,145,51,250,205,2,8,209,203,150,68,207,235,52,130,16,209,46,131, +36,188,70,128,210,160,101,56,251,16,131,28,7,35,38,218,50,234,103,130,97, +103,129,6,73,0,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,7,36,38,218,0, +0,0,0,0,0,0,0,4,29,78,224,140,38,216,140,46,228,0,243,119,10,139,144,123, +82,6,205,220,37,222,230,145,179,64,23,180,32,92,221,199,196,130,68,144,230, +237,200,131,44,24,43,193,25,18,185,0,251,73,138,199,240,27,93,106,192,57, +41,54,210,0,0,62,31,192,0,0,0,49,58,155,192,12,155,184,48,76,156,148,226, +134,154,240,32,201,187,147,67,9,201,78,40,105,175,2,225,47,3,18,155,184, +183,8,11,39,6,9,147,146,156,80,211,94,7,37,55,113,110,16,22,78,77,12,39,37, +56,161,166,188,16,48,215,130,14,30,240,66,213,93,35,11,124,0,230,36,249,52, +48,151,192,22,98,79,133,162,215,204,16,17,178,16,199,24,147,237,38,34,246, +139,95,48,64,70,200,68,16,98,79,140,115,102,123,33,20,89,137,62,210,98,103, +92,217,158,200,70,14,98,79,131,4,201,100,35,138,49,39,218,76,67,232,38,75, +33,32,49,137,62,12,24,178,18,68,152,147,237,38,33,244,24,178,18,132,24,147, +225,221,72,202,200,75,22,98,79,180,152,143,215,82,50,178,19,5,24,147,227, +16,218,76,146,178,19,70,152,147,237,38,38,117,13,164,201,43,33,56,81,137, +62,72,130,115,71,43,33,60,105,137,62,210,98,151,72,39,52,114,178,20,7,152, +147,227,16,181,162,68,19,154,57,89,10,36,140,73,246,147,19,58,133,173,18, +32,156,209,202,200,82,34,98,79,147,67,9,151,52,156,113,75,34,78,208,1,228, +73,242,104,97,46,16,62,68,159,24,133,173,18,32,156,209,202,217,83,37,34,79, +180,152,153,212,45,104,145,4,230,142,86,202,160,169,18,124,145,4,230,142, +86,215,213,27,34,79,180,152,165,210,9,205,28,173,175,172,42,68,159,24,134, +210,100,149,183,245,198,200,147,237,38,38,117,13,164,201,43,111,236,8,145, +39,195,186,145,149,185,246,69,200,147,237,38,35,245,212,140,173,207,180,30, +68,159,6,9,146,217,91,21,34,79,180,152,135,208,76,150,202,224,137,18,124, +99,155,51,219,95,116,92,137,62,210,98,103,92,217,158,218,251,194,228,73, +240,180,90,249,130,2,54,223,223,29,34,79,180,152,139,218,45,124,193,1,27, +111,240,33,204,73,243,4,4,108,134,8,60,137,62,96,128,141,178,193,193,154,3, +147,32,227,36,0,0,0,0,0,0,0,0,99,115,245,195,19,159,176,75,175,159,176,24, +172,253,129,49,121,251,2,176,66,92,130,235,16,18,100,148,251,36,106,123,64, +65,158,3,147,160,108,202,62,68,165,107,243,227,113,198,211,62,39,20,108, +115,226,241,130,106,113,224,78,162,4,242,130,236,197,60,37,64,190,18,49, +116,114,37,40,157,76,9,229,37,217,138,185,16,52,196,225,35,23,71,34,82,137, +213,64,158,84,93,152,187,145,33,73,18,52,68,225,35,23,71,34,82,137,213,192, +158,86,93,152,175,146,195,102,11,240,145,139,163,145,41,68,235,32,79,44,46, +204,83,201,225,228,225,35,23,71,34,82,137,214,192,158,90,93,152,163,180, +138,9,216,197,209,200,148,161,194,32,30,18,0,85,248,42,3,74,184,164,88,78, +173,186,58,16,44,90,192,144,5,149,109,110,193,245,109,210,128,132,93,204, +127,222,115,245,252,23,171,113,180,137,1,28,87,220,255,250,8,173,148,55,86, +227,104,232,18,3,222,94,217,248,119,41,48,168,46,189,16,62,200,66,80,6,11, +81,21,3,246,80,140,244,118,180,160,79,80,115,31,230,157,191,179,5,236,161, +25,233,64,158,160,246,63,205,59,127,102,41,248,30,75,12,11,151,242,233,187, +146,156,80,211,114,96,54,230,41,20,129,128,50,211,16,16,2,116,180,196,129, +1,36,55,76,74,16,19,3,116,196,193,65,48,55,75,80,128,65,6,51,211,20,128, +130,34,23,166,39,6,39,75,76,80,1,146,239,211,20,16,165,91,157,29,49,66,10, +124,61,211,209,175,1,173,198,211,20,48,139,113,180,180,197,36,42,220,109, +29,13,49,74,6,192,95,72,188,6,196,55,74,188,6,247,91,80,136,26,32,104,220, +205,56,1,98,234,52,122,98,136,14,72,110,152,162,132,148,35,61,49,70,7,48, +55,76,81,194,206,52,104,180,197,45,192,80,175,4,100,77,10,2,101,56,161,166, +65,113,162,98,8,3,131,7,169,35,36,57,176,16,40,116,208,0,0,0,0,45,158,10, +225,223,132,17,13,43,176,228,3,0,167,129,32,17,133,134,32,25,80,220,40,240, +25,26,44,32,240,24,200,44,24,240,56,156,199,128,83,193,17,7,4,13,128,0,10, +79,202,28,223,195,1,197,72,196,141,159,220,7,48,33,7,8,3,152,49,117,60,240, +76,47,60,9,224,187,56,43,224,221,64,172,156,36,98,232,228,96,220,145,139, +163,182,134,237,146,49,116,118,206,6,141,104,105,136,32,14,4,128,160,123, +215,140,147,32,145,57,178,156,104,41,228,151,168,225,144,168,105,56,248, +185,228,140,241,190,100,209,244,80,210,116,151,134,12,73,241,214,111,31,23, +60,145,158,56,50,72,81,67,230,232,239,209,7,24,147,227,226,233,186,120,121, +56,226,241,137,116,189,52,6,34,92,37,230,70,201,1,89,56,36,154,110,25,49, +23,196,149,35,103,194,94,100,108,144,230,203,136,73,174,234,63,52,252,212, +87,0,131,138,4,12,137,114,168,37,166,144,230,37,5,7,19,39,22,70,154,103, +143,252,4,11,37,160,68,164,139,7,24,3,152,182,20,28,76,156,89,26,105,158, +63,240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253,132,176,230, +36,248,134,207,98,138,99,4,24,147,229,16,217,236,81,75,98,12,73,241,13,158, +142,181,20,198,137,49,39,202,33,179,209,214,162,151,4,24,147,226,27,61,61, +42,41,142,18,98,79,148,67,103,167,165,69,46,138,49,39,194,173,192,158,158, +149,20,188,40,196,159,10,183,2,122,218,148,82,248,121,18,124,67,103,177,77, +177,130,36,73,242,136,108,246,41,181,177,18,36,248,134,207,71,90,155,99,68, +200,147,229,16,217,232,235,83,107,130,36,73,241,13,158,158,149,54,199,9, +145,39,202,33,179,211,210,166,215,69,72,147,225,86,224,79,79,74,155,94,21, +34,79,133,91,129,61,109,74,109,126,14,56,7,6,20,28,76,156,89,26,105,158,63, +240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253,130,235,191, +232,8,149,2,8,196,24,164,137,141,200,8,71,161,196,201,45,167,146,59,68,89, +24,70,206,0,0,7,129,248,0,0,0,1,142,49,232,71,161,196,201,45,167,146,59,68, +89,24,70,206,0,0,7,129,248,0,0,0,1,141,201,8,71,161,196,201,45,167,146,59, +68,89,24,70,206,0,0,7,129,248,0,0,0,2,138,2,214,225,113,235,2,27,128,0,10, +66,3,189,96,67,120,226,224,0,2,148,140,113,145,66,61,14,38,73,109,60,145, +218,34,200,194,54,112,0,0,60,15,192,0,0,0,12,110,80,66,61,14,38,73,109,60, +145,218,34,200,194,54,112,0,0,60,15,192,0,0,0,12,113,147,66,61,14,38,73, +109,60,145,218,34,200,194,54,112,0,0,60,15,192,0,0,0,12,110,88,66,61,14,38, +73,109,60,145,218,34,200,194,54,112,0,0,0,16,0,0,0,0,12,113,149,66,61,14, +38,73,109,60,145,218,34,200,194,54,112,0,0,0,16,0,0,0,0,12,110,96,66,61,14, +38,73,109,60,145,218,34,200,194,54,112,0,0,0,16,0,0,0,0,12,113,151,66,61, +14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,16,0,0,0,0,12,110,104,66, +61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0,0,0,12,113,153, +66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0,0,0,12,110, +112,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0,0,0,12, +113,155,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0,0,0, +12,110,120,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0,0, +0,12,113,157,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0, +0,0,12,110,128,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,8,16,0, +0,0,0,12,113,159,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,8,16, +0,0,0,0,8,58,32,128,24,78,104,129,61,82,2,145,46,17,162,112,208,211,107, +200,16,137,112,52,41,73,29,113,2,131,137,147,139,35,77,51,234,80,14,39,49, +224,137,40,35,100,141,9,136,19,18,0,125,162,58,217,236,81,64,68,72,1,241, +13,158,197,20,150,50,36,0,251,68,117,179,209,214,234,201,69,16,100,72,1, +246,136,235,103,163,173,208,146,138,68,23,18,0,124,67,103,163,173,213,146, +138,76,23,18,0,124,67,103,163,173,208,146,138,84,25,18,0,125,162,58,217, +233,233,117,100,162,138,50,36,0,251,68,117,179,211,210,232,73,69,34,139, +137,0,62,33,179,211,210,234,201,69,38,139,137,0,62,33,179,211,210,232,73, +69,42,139,137,0,62,21,110,4,250,178,81,70,23,18,0,124,42,220,9,244,36,162, +145,134,68,128,31,6,234,5,100,234,201,69,28,100,72,1,240,110,160,86,78,132, +148,82,56,168,144,3,237,17,214,207,171,37,22,128,42,36,0,251,68,117,179, +232,73,69,164,9,137,0,62,33,179,234,201,69,168,9,137,0,62,33,179,232,73,69, +172,10,180,81,50,118,136,235,103,177,77,129,54,138,38,78,33,179,216,166, +210,198,218,40,153,59,68,117,179,209,214,234,201,77,144,109,162,137,147, +180,71,91,61,29,110,132,148,218,32,203,69,19,39,16,217,232,235,117,100,166, +211,6,90,40,153,56,134,207,71,91,161,37,54,168,54,209,68,201,218,35,173, +158,158,151,86,74,108,163,109,20,76,157,162,58,217,233,233,116,36,166,209, +70,90,40,153,56,134,207,79,75,171,37,54,154,50,209,68,201,196,54,122,122, +93,9,41,181,81,150,138,38,78,21,110,4,250,178,83,102,25,104,162,100,225,86, +224,79,161,37,54,140,54,209,68,201,193,186,129,89,58,178,83,103,27,104,162, +100,224,221,64,172,157,9,41,180,113,118,138,38,78,209,29,108,250,178,83, +136,2,237,20,76,157,162,58,217,244,36,167,18,5,90,40,153,56,134,207,171,37, +56,160,42,209,68,201,196,54,125,9,41,197,141,78,197,141,86,192,0,133,66, +215,173,96,49,33,64,46,84,8,14,39,49,224,137,40,18,4,19,159,141,100,1,100, +180,8,148,146,0,91,69,19,38,202,8,58,64,28,209,160,130,52,78,26,26,110,255, +80,64,196,104,156,50,125,4,144,116,192,57,165,97,4,104,156,52,52,221,254, +64,20,160,152,23,223,228,32,148,25,174,137,58,23,51,191,200,84,12,50,9,195, +39,196,80, }; #else #error invalid endianness defines #endif #endif /* DUK_USE_ROM_OBJECTS */ + +/* automatic undefs */ +#undef DUK__REFCINIT #line 1 "duk_error_macros.c" /* * Error and fatal handling. @@ -10457,7 +11015,7 @@ #if defined(DUK_USE_VERBOSE_ERRORS) -DUK_INTERNAL void duk_err_handle_error_fmt(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *fmt, ...) { +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); @@ -10467,13 +11025,13 @@ va_end(ap); /* dead code, but ensures portability (see Linux man page notes) */ } -DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg) { +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 void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) { +DUK_INTERNAL DUK_COLD void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) { duk_err_create_and_throw(thr, code); } @@ -10485,41 +11043,41 @@ #if defined(DUK_USE_VERBOSE_ERRORS) #if defined(DUK_USE_PARANOID_ERRORS) -DUK_INTERNAL 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_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((duk_context *) thr, idx), (long) idx); } #else -DUK_INTERNAL 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_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((duk_context *) thr, idx), (long) idx); } #endif -DUK_INTERNAL void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 void duk_err_error_alloc_failed(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 void duk_err_error(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) { +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 void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *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 void duk_err_range_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx) { +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 void duk_err_range_push_beyond(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 void duk_err_type_invalid_args(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 void duk_err_type_invalid_state(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 void duk_err_type_invalid_trap_result(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 @@ -10531,25 +11089,25 @@ DUK_LOCAL void duk__err_shared(duk_hthread *thr, duk_uint_t code) { DUK_ERROR_RAW(thr, NULL, 0, code, NULL); } -DUK_INTERNAL void duk_err_error(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_error(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_ERROR); } -DUK_INTERNAL void duk_err_range(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_range(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_RANGE_ERROR); } -DUK_INTERNAL void duk_err_eval(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_eval(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_EVAL_ERROR); } -DUK_INTERNAL void duk_err_reference(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_reference(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_REFERENCE_ERROR); } -DUK_INTERNAL void duk_err_syntax(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_syntax(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_SYNTAX_ERROR); } -DUK_INTERNAL void duk_err_type(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_type(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_TYPE_ERROR); } -DUK_INTERNAL void duk_err_uri(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_uri(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_URI_ERROR); } #endif @@ -10558,7 +11116,7 @@ * Default fatal error handler */ -DUK_INTERNAL void duk_default_fatal_handler(void *udata, const char *msg) { +DUK_INTERNAL DUK_COLD void duk_default_fatal_handler(void *udata, const char *msg) { DUK_UNREF(udata); DUK_UNREF(msg); @@ -12173,87 +12731,6 @@ */ return (x > y ? x : y); } -#line 1 "duk_util_hashprime.c" -/* - * Round a number upwards to a prime (not usually the nearest one). - * - * Uses a table of successive 32-bit primes whose ratio is roughly - * constant. This keeps the relative upwards 'rounding error' bounded - * and the data size small. A simple 'predict-correct' compression is - * used to compress primes to one byte per prime. See genhashsizes.py - * for details. - * - * The minimum prime returned here must be coordinated with the possible - * probe sequence steps in duk_hobject and duk_heap stringtable. - */ - -/* #include duk_internal.h -> already included */ - -/* Awkward inclusion condition: drop out of compilation if not needed by any - * call site: object hash part or probing stringtable. - */ -#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE) - -/* hash size ratio goal, must match genhashsizes.py */ -#define DUK__HASH_SIZE_RATIO 1177 /* floor(1.15 * (1 << 10)) */ - -/* prediction corrections for prime list (see genhashsizes.py) */ -DUK_LOCAL const duk_int8_t duk__hash_size_corrections[] = { - 17, /* minimum prime */ - 4, 3, 4, 1, 4, 1, 1, 2, 2, 2, 2, 1, 6, 6, 9, 5, 1, 2, 2, 5, 1, 3, 3, 3, - 5, 4, 4, 2, 4, 8, 3, 4, 23, 2, 4, 7, 8, 11, 2, 12, 15, 10, 1, 1, 5, 1, 5, - 8, 9, 17, 14, 10, 7, 5, 2, 46, 21, 1, 9, 9, 4, 4, 10, 23, 36, 6, 20, 29, - 18, 6, 19, 21, 16, 11, 5, 5, 48, 9, 1, 39, 14, 8, 4, 29, 9, 1, 15, 48, 12, - 22, 6, 15, 27, 4, 2, 17, 28, 8, 9, 4, 5, 8, 3, 3, 8, 37, 11, 15, 8, 30, - 43, 6, 33, 41, 5, 20, 32, 41, 38, 24, 77, 14, 19, 11, 4, 35, 18, 19, 41, - 10, 23, 16, 9, 2, - -1 -}; - -/* probe steps (see genhashsizes.py), currently assumed to be 32 entries long - * (DUK_UTIL_GET_HASH_PROBE_STEP macro). - */ -DUK_INTERNAL duk_uint8_t duk_util_probe_steps[32] = { - 2, 3, 5, 7, 11, 13, 19, 31, 41, 47, 59, 67, 73, 79, 89, 101, 103, 107, - 109, 127, 137, 139, 149, 157, 163, 167, 173, 181, 191, 193, 197, 199 -}; - -DUK_INTERNAL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size) { - const duk_int8_t *p = duk__hash_size_corrections; - duk_uint32_t curr; - - curr = (duk_uint32_t) *p++; - for (;;) { - duk_small_int_t t = (duk_small_int_t) *p++; - if (t < 0) { - /* may happen if size is very close to 2^32-1 */ - break; - } - - /* prediction: portable variant using doubles if 64-bit values not available */ -#if defined(DUK_USE_64BIT_OPS) - curr = (duk_uint32_t) ((((duk_uint64_t) curr) * ((duk_uint64_t) DUK__HASH_SIZE_RATIO)) >> 10); -#else - /* 32-bit x 11-bit = 43-bit, fits accurately into a double */ - curr = (duk_uint32_t) DUK_FLOOR(((double) curr) * ((double) DUK__HASH_SIZE_RATIO) / 1024.0); -#endif - - /* correction */ - curr += t; - - DUK_DDD(DUK_DDDPRINT("size=%ld, curr=%ld", (long) size, (long) curr)); - - if (curr >= size) { - return curr; - } - } - return 0; -} - -#endif /* DUK_USE_HOBJECT_HASH_PART || DUK_USE_STRTAB_PROBE */ - -/* automatic undefs */ -#undef DUK__HASH_SIZE_RATIO #line 1 "duk_hobject_class.c" /* * Hobject Ecmascript [[Class]]. @@ -12775,6 +13252,7 @@ DUK_RAW_WRITE_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_WRITE_U32_BE(p, tmp32); /* Bytecode instructions: endian conversion needed unless @@ -12954,7 +13432,7 @@ 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_HAS_THREAD(&h_fun->obj)); + DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(&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)); @@ -13080,14 +13558,23 @@ * Must create a lexical environment on loading to allow * recursive functions like 'function foo() { foo(); }'. */ - duk_hobject *new_env; + duk_hdecenv *new_env; - new_env = duk_push_object_helper_proto(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), - func_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); - func_env = new_env; + DUK_ASSERT(new_env->thread == NULL); /* Closed. */ + DUK_ASSERT(new_env->varmap == NULL); + DUK_ASSERT(new_env->regbase == 0); + DUK_ASSERT_HDECENV_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(ctx, (duk_hobject *) new_env); duk_dup_m2(ctx); /* -> [ func funcname env funcname ] */ duk_dup(ctx, idx_base); /* -> [ func funcname env funcname func ] */ @@ -13144,8 +13631,9 @@ /* If _Formals wasn't present in the original function, the list * here will be empty. Same happens if _Formals was present but - * had zero length. We can omit _Formals from the result if its - * length is zero and matches nargs. + * had zero length. We'll omit the _Formals list if it is empty, + * regardless of whether it was present in the original or not, + * this is a workaround for https://github.com/svaarala/duktape/issues/1513. */ duk_push_array(ctx); /* _Formals */ for (arr_idx = 0; ; arr_idx++) { @@ -13157,7 +13645,16 @@ } duk_put_prop_index(ctx, -2, arr_idx); } - if (arr_idx == 0 && h_fun->nargs == 0) { + if (arr_idx == 0) { + /* Omitting _Formals when the list is empty is technically + * incorrect because the result will differ from the input + * function. This could matter for function templates if: + * _Formals exists, _Formals.length == 0, and nargs > 0. + * This doesn't happen in practice. But if it did, it would + * affect the .length property of function instances created + * from the closure (0 with _Formals present, nargs with + * _Formals absent). + */ duk_pop(ctx); } else { duk_compact_m1(ctx); @@ -13313,7 +13810,7 @@ DUK_ASSERT(thr != NULL); idx_func = duk_get_top(ctx) - nargs - 1; - if (idx_func < 0 || nargs < 0) { + if (DUK_UNLIKELY(idx_func < 0 || nargs < 0)) { /* note that we can't reliably pop anything here */ DUK_ERROR_TYPE_INVALID_ARGS(thr); } @@ -13340,7 +13837,7 @@ DUK_ASSERT(thr != NULL); idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */ - if (idx_func < 0 || nargs < 0) { + if (DUK_UNLIKELY(idx_func < 0 || nargs < 0)) { /* note that we can't reliably pop anything here */ DUK_ERROR_TYPE_INVALID_ARGS(thr); } @@ -13379,7 +13876,7 @@ DUK_ASSERT(thr != NULL); idx_func = duk_get_top(ctx) - nargs - 1; /* must work for nargs <= 0 */ - if (idx_func < 0 || nargs < 0) { + if (DUK_UNLIKELY(idx_func < 0 || nargs < 0)) { /* We can't reliably pop anything here because the stack input * shape is incorrect. So we throw an error; if the caller has * no catch point for this, a fatal error will occur. Another @@ -13417,7 +13914,7 @@ DUK_ASSERT(thr != NULL); idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */ - if (idx_func < 0 || nargs < 0) { + if (DUK_UNLIKELY(idx_func < 0 || nargs < 0)) { /* See comments in duk_pcall(). */ DUK_ERROR_TYPE_INVALID_ARGS(thr); return DUK_EXEC_ERROR; /* unreachable */ @@ -13457,6 +13954,7 @@ } DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t nargs) { + duk_hthread *thr = (duk_hthread *) ctx; duk__pcall_prop_args args; /* @@ -13468,6 +13966,10 @@ args.obj_idx = obj_idx; args.nargs = nargs; + if (DUK_UNLIKELY(nargs < 0)) { + DUK_ERROR_TYPE_INVALID_ARGS(thr); + return DUK_EXEC_ERROR; /* unreachable */ + } /* Inputs: explicit arguments (nargs), +1 for key. If the value stack * does not contain enough args, an error is thrown; this matches @@ -13483,7 +13985,7 @@ DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(thr != NULL); - if (duk_get_top(ctx) < nargs || nrets < 0) { + if (DUK_UNLIKELY(duk_get_top(ctx) < nargs || nargs < 0 || nrets < 0)) { /* See comments in duk_pcall(). */ DUK_ERROR_TYPE_INVALID_ARGS(thr); return DUK_EXEC_ERROR; /* unreachable */ @@ -13548,6 +14050,10 @@ /* [... constructor arg1 ... argN] */ + if (DUK_UNLIKELY(nargs < 0)) { + /* note that we can't reliably pop anything here */ + DUK_ERROR_TYPE_INVALID_ARGS(thr); + } idx_cons = duk_require_normalize_index(ctx, -nargs - 1); DUK_DDD(DUK_DDDPRINT("top=%ld, nargs=%ld, idx_cons=%ld", @@ -13717,6 +14223,7 @@ } DUK_EXTERNAL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs) { + duk_hthread *thr = (duk_hthread *) ctx; duk_int_t rc; DUK_ASSERT_CTX_VALID(ctx); @@ -13729,6 +14236,11 @@ * wrapper. */ + if (DUK_UNLIKELY(nargs < 0)) { + DUK_ERROR_TYPE_INVALID_ARGS(thr); + return DUK_EXEC_ERROR; /* unreachable */ + } + rc = duk_safe_call(ctx, duk__pnew_helper, (void *) &nargs /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/); return rc; } @@ -13741,9 +14253,11 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT_DISABLE(thr->callstack_top >= 0); - act = duk_hthread_get_current_activation(thr); - DUK_ASSERT(act != NULL); /* because callstack_top > 0 */ - return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0); + act = thr->callstack_curr; + if (act != NULL) { + return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0); + } + return 0; } /* XXX: Make this obsolete by adding a function flag for rejecting a @@ -13772,12 +14286,13 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT_DISABLE(thr->callstack_top >= 0); - act = duk_hthread_get_current_activation(thr); - if (act == NULL) { + act = thr->callstack_curr; + if (act != NULL) { + return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0); + } else { /* Strict by default. */ return 1; } - return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0); } /* @@ -13793,7 +14308,7 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT_DISABLE(thr->callstack_top >= 0); - act = duk_hthread_get_current_activation(thr); + act = thr->callstack_curr; if (act) { func = DUK_ACT_GET_FUNC(act); if (!func) { @@ -13898,7 +14413,10 @@ DUK_ASSERT(duk_is_valid_index(ctx, idx)); /* checked by caller */ - ptr = duk_get_buffer_data_raw(ctx, idx, out_len, 0 /*throw_flag*/, &isbuffer); + /* XXX: with def_ptr set to a stack related pointer, isbuffer could + * be removed from the helper? + */ + ptr = duk_get_buffer_data_raw(ctx, idx, out_len, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, &isbuffer); if (isbuffer) { DUK_ASSERT(*out_len == 0 || ptr != NULL); return (const duk_uint8_t *) ptr; @@ -14090,13 +14608,13 @@ t <<= 6; } else { DUK_ASSERT(x == -1); - goto error; + goto decode_error; } } else { DUK_ASSERT(x >= 0 && x <= 63); if (n_equal > 0) { /* Don't allow actual chars after equal sign. */ - goto error; + goto decode_error; } t = (t << 6) + x; } @@ -14122,7 +14640,7 @@ /* XX== */ dst -= 2; } else { - goto error; /* invalid padding */ + goto decode_error; /* invalid padding */ } /* Continue parsing after padding, allows concatenated, @@ -14146,13 +14664,13 @@ * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not * accepted. */ - goto error; + goto decode_error; } *out_dst_final = dst; return 1; - error: + decode_error: return 0; } #else /* DUK_USE_BASE64_FASTPATH */ @@ -14194,12 +14712,12 @@ /* allow basic ASCII whitespace */ continue; } else { - goto error; + goto decode_error; } if (n_equal > 0) { /* Don't allow mixed padding and actual chars. */ - goto error; + goto decode_error; } t = (t << 6) + y; skip_add: @@ -14218,7 +14736,7 @@ } else if (n_equal == 2) { dst -= 2; } else { - goto error; /* invalid padding */ + goto decode_error; /* invalid padding */ } /* Here we can choose either to end parsing and ignore @@ -14241,13 +14759,13 @@ * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not * accepted. */ - goto error; + goto decode_error; } *out_dst_final = dst; return 1; - error: + decode_error: return 0; } #endif /* DUK_USE_BASE64_FASTPATH */ @@ -14549,7 +15067,6 @@ /* Eval is just a wrapper now. */ DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) { - duk_uint_t comp_flags; duk_int_t rc; DUK_ASSERT_CTX_VALID(ctx); @@ -14563,9 +15080,7 @@ /* [ ... source? filename? ] (depends on flags) */ - comp_flags = flags; - comp_flags |= DUK_COMPILE_EVAL; - rc = duk_compile_raw(ctx, src_buffer, src_length, comp_flags); /* may be safe, or non-safe depending on flags */ + rc = duk_compile_raw(ctx, src_buffer, src_length, flags | DUK_COMPILE_EVAL); /* may be safe, or non-safe depending on flags */ /* [ ... closure/error ] */ @@ -14598,7 +15113,6 @@ duk_hthread *thr = (duk_hthread *) ctx; duk__compile_raw_args *comp_args; duk_uint_t flags; - duk_small_uint_t comp_flags; duk_hcompfunc *h_templ; DUK_ASSERT_CTX_VALID(ctx); @@ -14637,22 +15151,13 @@ } DUK_ASSERT(comp_args->src_buffer != NULL); - /* XXX: unnecessary translation of flags */ - comp_flags = 0; - if (flags & DUK_COMPILE_EVAL) { - comp_flags |= DUK_JS_COMPILE_FLAG_EVAL; - } if (flags & DUK_COMPILE_FUNCTION) { - comp_flags |= DUK_JS_COMPILE_FLAG_EVAL | - DUK_JS_COMPILE_FLAG_FUNCEXPR; - } - if (flags & DUK_COMPILE_STRICT) { - comp_flags |= DUK_JS_COMPILE_FLAG_STRICT; + flags |= DUK_COMPILE_EVAL | DUK_COMPILE_FUNCEXPR; } /* [ ... source? filename ] */ - duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, comp_flags); + duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, flags); /* [ ... source? func_template ] */ @@ -14806,16 +15311,16 @@ /* Start in paused state. */ heap->dbg_processing = 0; - DUK_HEAP_SET_DEBUGGER_PAUSED(heap); - heap->dbg_state_dirty = 1; + heap->dbg_state_dirty = 0; heap->dbg_force_restart = 0; - heap->dbg_step_type = 0; + heap->dbg_step_type = DUK_STEP_TYPE_NONE; heap->dbg_step_thread = NULL; heap->dbg_step_csindex = 0; heap->dbg_step_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. @@ -14855,7 +15360,7 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->heap != NULL); - if (!DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + if (!duk_debug_is_attached(thr->heap)) { return; } if (thr->callstack_top > 0 || thr->heap->dbg_processing) { @@ -14888,7 +15393,7 @@ DUK_ERROR_RANGE(thr, "not enough stack values for notify"); return ret; /* unreachable */ } - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + 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(ctx, idx); @@ -14901,7 +15406,7 @@ * a transport error was not indicated by the transport write * callback. This is not a 100% guarantee of course. */ - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + if (duk_debug_is_attached(thr->heap)) { ret = 1; } } @@ -14920,15 +15425,19 @@ DUK_D(DUK_DPRINT("application called duk_debugger_pause()")); /* Treat like a debugger statement: ignore when not attached. */ - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { - DUK_HEAP_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; + 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; + } } } @@ -15000,7 +15509,7 @@ struct duk_internal_thread_state { duk_ljstate lj; - duk_bool_t handling_error; + duk_bool_t creating_error; duk_hthread *curr_thread; duk_int_t call_recursion_depth; }; @@ -15081,14 +15590,27 @@ 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(ctx, &lj->value1); duk_push_tval(ctx, &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->handling_error = heap->handling_error; + snapshot->creating_error = heap->creating_error; snapshot->curr_thread = heap->curr_thread; snapshot->call_recursion_depth = heap->call_recursion_depth; @@ -15096,7 +15618,7 @@ lj->type = DUK_LJ_TYPE_UNKNOWN; DUK_TVAL_SET_UNDEFINED(&lj->value1); DUK_TVAL_SET_UNDEFINED(&lj->value2); - heap->handling_error = 0; + heap->creating_error = 0; heap->curr_thread = NULL; heap->call_recursion_depth = 0; } @@ -15111,10 +15633,16 @@ 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->handling_error = snapshot->handling_error; + heap->creating_error = snapshot->creating_error; heap->curr_thread = snapshot->curr_thread; heap->call_recursion_depth = snapshot->call_recursion_depth; @@ -15126,7 +15654,7 @@ duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h_glob; duk_hobject *h_prev_glob; - duk_hobject *h_env; + duk_hobjenv *h_env; duk_hobject *h_prev_env; DUK_D(DUK_DPRINT("replace global object with: %!T", duk_get_tval(ctx, -1))); @@ -15153,29 +15681,30 @@ * same (initial) built-ins. */ - h_env = duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV), - -1); /* no prototype, updated below */ + 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_dup_m2(ctx); - duk_dup_m3(ctx); - duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); + 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 new_env ] */ + /* [ ... new_glob ] */ h_prev_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; - thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_env; - DUK_HOBJECT_INCREF(thr, h_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 new_env ] */ + /* [ ... new_glob ] */ - duk_pop_2(ctx); + duk_pop(ctx); /* [ ... ] */ } @@ -15248,18 +15777,19 @@ DUK_UNREF(thr); - tv = duk_get_tval_or_unused(ctx, idx); - h = (DUK_TVAL_IS_HEAP_ALLOCATED(tv) ? DUK_TVAL_GET_HEAPHDR(tv) : NULL); - /* 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 */ - duk_push_bare_object(ctx); + tv = duk_get_tval_or_unused(ctx, 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_uint_t) DUK_TVAL_GET_TAG(tv); + duk_push_bare_object(ctx); /* Invalidates 'tv'. */ + tv = NULL; + if (h == NULL) { goto finish; } @@ -16236,9 +16766,31 @@ } DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t idx) { + duk_hobject *h; + duk_bool_t callable; + DUK_ASSERT_CTX_VALID(ctx); + h = duk_require_hobject(ctx, idx); /* Get before 'put' so that 'idx' is correct. */ + callable = duk_is_callable(ctx, -1); duk_put_prop_stridx(ctx, idx, DUK_STRIDX_INT_FINALIZER); + + /* In addition to setting the finalizer property, keep a "have + * finalizer" flag in duk_hobject in sync so that refzero can do + * a very quick finalizer check by walking the prototype chain + * and checking the flag alone. (Note that this means that just + * setting _Finalizer on an object won't affect finalizer checks.) + * + * NOTE: if the argument is a Proxy object, this flag will be set + * on the Proxy, not the target. As a result, the target won't get + * a finalizer flag and the Proxy also won't be finalized as there's + * an explicit Proxy check in finalization now. + */ + if (callable) { + DUK_HOBJECT_SET_HAVE_FINALIZER(h); + } else { + DUK_HOBJECT_CLEAR_HAVE_FINALIZER(h); + } } #else /* DUK_USE_FINALIZER_SUPPORT */ DUK_EXTERNAL void duk_get_finalizer(duk_context *ctx, duk_idx_t idx) { @@ -16332,7 +16884,7 @@ DUK_LOCAL_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t idx, duk_uint_t tag); -DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t idx, duk_bool_t require) { +DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t idx, duk_int_t def_value, duk_bool_t require) { duk_hthread *thr; duk_tval *tv; duk_small_int_t c; @@ -16392,10 +16944,11 @@ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); /* not reachable */ } - return 0; + + return def_value; } -DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t idx, duk_bool_t require) { +DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value, duk_bool_t require) { duk_hthread *thr; duk_tval *tv; duk_small_int_t c; @@ -16445,7 +16998,8 @@ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); /* not reachable */ } - return 0; + + return def_value; } /* @@ -16612,7 +17166,7 @@ DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(DUK_INVALID_INDEX < 0); - if (duk_normalize_index(ctx, idx) < 0) { + if (DUK_UNLIKELY(duk_normalize_index(ctx, idx) < 0)) { DUK_ERROR_RANGE_INDEX(thr, idx); return; /* unreachable */ } @@ -16640,7 +17194,7 @@ DUK_ASSERT_CTX_VALID(ctx); ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); - if (ret < min_top) { + if (DUK_UNLIKELY(ret < min_top)) { DUK_ERROR_TYPE_INVALID_ARGS(thr); } return ret; @@ -16852,7 +17406,7 @@ new_alloc_size = sizeof(duk_tval) * new_size; new_valstack = (duk_tval *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_valstack_ptr, (void *) thr, new_alloc_size); - if (!new_valstack) { + if (DUK_UNLIKELY(new_valstack == NULL)) { /* Because new_size != 0, if condition doesn't need to be * (new_valstack != NULL || new_size == 0). */ @@ -16942,26 +17496,16 @@ return 1; } -DUK_INTERNAL -duk_bool_t duk_valstack_resize_raw(duk_context *ctx, - duk_size_t min_new_size, - duk_small_uint_t flags) { +DUK_LOCAL DUK_COLD DUK_NOINLINE duk_bool_t duk__valstack_do_resize(duk_context *ctx, + duk_size_t min_new_size, + duk_small_uint_t flags) { duk_hthread *thr = (duk_hthread *) ctx; duk_size_t old_size; duk_size_t new_size; - duk_bool_t is_shrink = 0; - duk_small_uint_t shrink_flag = (flags & DUK_VSRESIZE_FLAG_SHRINK); + duk_bool_t is_shrink; duk_small_uint_t compact_flag = (flags & DUK_VSRESIZE_FLAG_COMPACT); duk_small_uint_t throw_flag = (flags & DUK_VSRESIZE_FLAG_THROW); - DUK_DDD(DUK_DDDPRINT("check valstack resize: min_new_size=%lu, curr_size=%ld, curr_top=%ld, " - "curr_bottom=%ld, shrink=%d, compact=%d, throw=%d", - (unsigned long) min_new_size, - (long) (thr->valstack_end - thr->valstack), - (long) (thr->valstack_top - thr->valstack), - (long) (thr->valstack_bottom - thr->valstack), - (int) shrink_flag, (int) compact_flag, (int) throw_flag)); - DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->valstack_bottom >= thr->valstack); @@ -16977,11 +17521,8 @@ if (min_new_size <= old_size) { is_shrink = 1; - if (!shrink_flag || - old_size - min_new_size < DUK_VALSTACK_SHRINK_THRESHOLD) { - DUK_DDD(DUK_DDDPRINT("no need to grow or shrink valstack")); - return 1; - } + } else { + is_shrink = 0; } new_size = min_new_size; @@ -17000,7 +17541,7 @@ (unsigned long) old_size, (unsigned long) new_size, (unsigned long) min_new_size)); - if (new_size > thr->valstack_max) { + if (DUK_UNLIKELY(new_size > thr->valstack_max)) { /* Note: may be triggered even if minimal new_size would not reach the limit, * plan limit accordingly (taking DUK_VALSTACK_GROW_STEP into account). */ @@ -17023,7 +17564,7 @@ * size_t and pointer arithmetic won't wrap in duk__resize_valstack(). */ - if (!duk__resize_valstack(ctx, new_size)) { + if (DUK_UNLIKELY(!duk__resize_valstack(ctx, new_size))) { if (is_shrink) { DUK_DD(DUK_DDPRINT("valstack resize failed, but is a shrink, ignore")); return 1; @@ -17042,15 +17583,53 @@ return 1; } -DUK_EXTERNAL duk_bool_t duk_check_stack(duk_context *ctx, duk_idx_t extra) { +DUK_INTERNAL duk_bool_t duk_valstack_resize_raw(duk_context *ctx, + duk_size_t min_new_size, + duk_small_uint_t flags) { duk_hthread *thr = (duk_hthread *) ctx; - duk_size_t min_new_size; - - DUK_ASSERT_CTX_VALID(ctx); - DUK_ASSERT(thr != NULL); + duk_size_t old_size; - if (DUK_UNLIKELY(extra < 0)) { - /* Clamping to zero makes the API more robust to calling code + DUK_DDD(DUK_DDDPRINT("check valstack resize: min_new_size=%lu, curr_size=%ld, curr_top=%ld, " + "curr_bottom=%ld, flags=%lx", + (unsigned long) min_new_size, + (long) (thr->valstack_end - thr->valstack), + (long) (thr->valstack_top - thr->valstack), + (long) (thr->valstack_bottom - thr->valstack), + (unsigned long) flags)); + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + DUK_ASSERT(thr->valstack_bottom >= thr->valstack); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT(thr->valstack_end >= thr->valstack_top); + +#if defined(DUK_USE_PREFER_SIZE) + old_size = (duk_size_t) (thr->valstack_end - thr->valstack); +#else + DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size); + old_size = thr->valstack_size; +#endif + + if (DUK_LIKELY(min_new_size <= old_size)) { + if (DUK_LIKELY((flags & DUK_VSRESIZE_FLAG_SHRINK) == 0 || + old_size - min_new_size < DUK_VALSTACK_SHRINK_THRESHOLD)) { + DUK_DDD(DUK_DDDPRINT("no need to grow or shrink valstack")); + return 1; + } + } + + return duk__valstack_do_resize(ctx, min_new_size, flags); +} + +DUK_EXTERNAL duk_bool_t duk_check_stack(duk_context *ctx, duk_idx_t extra) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_size_t min_new_size; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + + if (DUK_UNLIKELY(extra < 0)) { + /* Clamping to zero makes the API more robust to calling code * calculation errors. */ extra = 0; @@ -17087,9 +17666,11 @@ } DUK_EXTERNAL duk_bool_t duk_check_stack_top(duk_context *ctx, duk_idx_t top) { + duk_hthread *thr; duk_size_t min_new_size; DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; if (DUK_UNLIKELY(top < 0)) { /* Clamping to zero makes the API more robust to calling code @@ -17098,7 +17679,7 @@ top = 0; } - min_new_size = top + DUK_VALSTACK_INTERNAL_EXTRA; + min_new_size = (thr->valstack_bottom - thr->valstack) + top + DUK_VALSTACK_INTERNAL_EXTRA; return duk_valstack_resize_raw(ctx, min_new_size, /* min_new_size */ 0 /* no shrink */ | /* flags */ @@ -17107,9 +17688,11 @@ } DUK_EXTERNAL void duk_require_stack_top(duk_context *ctx, duk_idx_t top) { + duk_hthread *thr; duk_size_t min_new_size; DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; if (DUK_UNLIKELY(top < 0)) { /* Clamping to zero makes the API more robust to calling code @@ -17118,7 +17701,7 @@ top = 0; } - min_new_size = top + DUK_VALSTACK_INTERNAL_EXTRA; + min_new_size = (thr->valstack_bottom - thr->valstack) + top + DUK_VALSTACK_INTERNAL_EXTRA; (void) duk_valstack_resize_raw(ctx, min_new_size, /* min_new_size */ 0 /* no shrink */ | /* flags */ @@ -17183,7 +17766,7 @@ thr = (duk_hthread *) ctx; DUK__CHECK_SPACE(); - if (thr->valstack_top - thr->valstack_bottom <= 0) { + if (DUK_UNLIKELY(thr->valstack_top - thr->valstack_bottom <= 0)) { DUK_ERROR_RANGE_INDEX(thr, -1); return; /* unreachable */ } @@ -17358,27 +17941,27 @@ DUK_ASSERT(to_ctx != NULL); DUK_ASSERT(from_ctx != NULL); - if (to_ctx == from_ctx) { + if (DUK_UNLIKELY(to_ctx == from_ctx)) { DUK_ERROR_TYPE(to_thr, DUK_STR_INVALID_CONTEXT); return; } - if ((count < 0) || - (count > (duk_idx_t) to_thr->valstack_max)) { + if (DUK_UNLIKELY((count < 0) || + (count > (duk_idx_t) to_thr->valstack_max))) { /* Maximum value check ensures 'nbytes' won't wrap below. */ DUK_ERROR_RANGE_INVALID_COUNT(to_thr); return; } nbytes = sizeof(duk_tval) * count; - if (nbytes == 0) { + if (DUK_UNLIKELY(nbytes == 0)) { return; } DUK_ASSERT(to_thr->valstack_top <= to_thr->valstack_end); - if ((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes) { + if (DUK_UNLIKELY((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes)) { DUK_ERROR_RANGE_PUSH_BEYOND(to_thr); } src = (void *) ((duk_uint8_t *) from_thr->valstack_top - nbytes); - if (src < (void *) from_thr->valstack_bottom) { + if (DUK_UNLIKELY(src < (void *) from_thr->valstack_bottom)) { DUK_ERROR_RANGE_INVALID_COUNT(to_thr); } @@ -17413,7 +17996,7 @@ } /* - * Get/require + * Get/opt/require */ DUK_EXTERNAL void duk_require_undefined(duk_context *ctx, duk_idx_t idx) { @@ -17424,7 +18007,7 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_UNDEFINED(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_UNDEFINED(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "undefined", DUK_STR_NOT_UNDEFINED); } } @@ -17437,13 +18020,13 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_NULL(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_NULL(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "null", DUK_STR_NOT_NULL); } } -DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t idx) { - duk_bool_t ret = 0; /* default: false */ +DUK_LOCAL DUK_ALWAYS_INLINE duk_bool_t duk__get_boolean_raw(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value) { + duk_bool_t ret; duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); @@ -17452,12 +18035,27 @@ DUK_ASSERT(tv != NULL); if (DUK_TVAL_IS_BOOLEAN(tv)) { ret = DUK_TVAL_GET_BOOLEAN(tv); + DUK_ASSERT(ret == 0 || ret == 1); + } else { + ret = def_value; + /* Not guaranteed to be 0 or 1. */ } - DUK_ASSERT(ret == 0 || ret == 1); return ret; } +DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t idx) { + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_boolean_raw(ctx, idx, 0); /* default: false */ +} + +DUK_EXTERNAL duk_bool_t duk_get_boolean_default(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_boolean_raw(ctx, idx, def_value); +} + DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -17467,35 +18065,61 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_BOOLEAN(tv)) { + if (DUK_LIKELY(DUK_TVAL_IS_BOOLEAN(tv))) { + ret = DUK_TVAL_GET_BOOLEAN(tv); + DUK_ASSERT(ret == 0 || ret == 1); + return ret; + } else { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "boolean", DUK_STR_NOT_BOOLEAN); } - ret = DUK_TVAL_GET_BOOLEAN(tv); - DUK_ASSERT(ret == 0 || ret == 1); - return ret; } -DUK_EXTERNAL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t idx) { +DUK_EXTERNAL duk_bool_t duk_opt_boolean(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_boolean(ctx, idx); +} + +DUK_LOCAL DUK_ALWAYS_INLINE duk_double_t duk__get_number_raw(duk_context *ctx, duk_idx_t idx, duk_double_t def_value) { duk_double_union ret; duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); - ret.d = DUK_DOUBLE_NAN; /* default: NaN */ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (DUK_TVAL_IS_NUMBER(tv)) { - ret.d = DUK_TVAL_GET_NUMBER(tv); +#if defined(DUK_USE_FASTINT) + if (DUK_TVAL_IS_FASTINT(tv)) { + ret.d = (duk_double_t) DUK_TVAL_GET_FASTINT(tv); /* XXX: cast trick */ + } + else +#endif + if (DUK_TVAL_IS_DOUBLE(tv)) { + /* When using packed duk_tval, number must be in NaN-normalized form + * for it to be a duk_tval, so no need to normalize. NOP for unpacked + * duk_tval. + */ + ret.d = DUK_TVAL_GET_DOUBLE(tv); + DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret)); + } else { + ret.d = def_value; + /* Default value (including NaN) may not be normalized. */ } - /* When using packed duk_tval, number must be in NaN-normalized form - * for it to be a duk_tval, so no need to normalize. NOP for unpacked - * duk_tval. - */ - DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret)); return ret.d; } +DUK_EXTERNAL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t idx) { + return duk__get_number_raw(ctx, idx, DUK_DOUBLE_NAN); /* default: NaN */ +} + +DUK_EXTERNAL duk_double_t duk_get_number_default(duk_context *ctx, duk_idx_t idx, duk_double_t def_value) { + return duk__get_number_raw(ctx, idx, def_value); +} + DUK_EXTERNAL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -17505,7 +18129,7 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_NUMBER(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_NUMBER(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); } @@ -17519,56 +18143,89 @@ return ret.d; } +DUK_EXTERNAL duk_double_t duk_opt_number(duk_context *ctx, duk_idx_t idx, duk_double_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + /* User provided default is not NaN normalized. */ + return def_value; + } + return duk_require_number(ctx, idx); +} + DUK_EXTERNAL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t idx) { - /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*require*/); + + return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*def_value*/, 0 /*require*/); } DUK_EXTERNAL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t idx) { - /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*require*/); + + return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*def_value*/, 0 /*require*/); +} + +DUK_EXTERNAL duk_int_t duk_get_int_default(duk_context *ctx, duk_idx_t idx, duk_int_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + return (duk_int_t) duk__api_coerce_d2i(ctx, idx, def_value, 0 /*require*/); +} + +DUK_EXTERNAL duk_uint_t duk_get_uint_default(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, def_value, 0 /*require*/); } DUK_EXTERNAL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t idx) { - /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 1 /*require*/); + + return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*def_value*/, 1 /*require*/); } DUK_EXTERNAL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t idx) { - /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 1 /*require*/); + + return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*def_value*/, 1 /*require*/); } -DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) { - const char *ret; - duk_tval *tv; +DUK_EXTERNAL duk_int_t duk_opt_int(duk_context *ctx, duk_idx_t idx, duk_int_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_int(ctx, idx); +} + +DUK_EXTERNAL duk_uint_t duk_opt_uint(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value) { DUK_ASSERT_CTX_VALID(ctx); - /* default: NULL, length 0 */ - ret = NULL; - if (out_len) { - *out_len = 0; + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; } + return duk_require_uint(ctx, idx); +} - tv = duk_get_tval_or_unused(ctx, idx); - DUK_ASSERT(tv != NULL); - if (DUK_TVAL_IS_STRING(tv)) { - /* Here we rely on duk_hstring instances always being zero - * terminated even if the actual string is not. - */ - duk_hstring *h = DUK_TVAL_GET_STRING(tv); - DUK_ASSERT(h != NULL); +DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) { + duk_hstring *h; + const char *ret; + duk_size_t len; + + DUK_ASSERT_CTX_VALID(ctx); + + h = duk_get_hstring(ctx, idx); + if (h != NULL) { + len = DUK_HSTRING_GET_BYTELEN(h); ret = (const char *) DUK_HSTRING_GET_DATA(h); - if (out_len) { - *out_len = DUK_HSTRING_GET_BYTELEN(h); - } + } else { + len = 0; + ret = NULL; } + if (out_len != NULL) { + *out_len = len; + } return ret; } @@ -17599,9 +18256,72 @@ } DUK_EXTERNAL const char *duk_get_string(duk_context *ctx, duk_idx_t idx) { + duk_hstring *h; + + DUK_ASSERT_CTX_VALID(ctx); + + h = duk_get_hstring(ctx, idx); + if (h != NULL) { + return (const char *) DUK_HSTRING_GET_DATA(h); + } else { + return NULL; + } +} + +DUK_EXTERNAL const char *duk_opt_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + if (out_len != NULL) { + *out_len = def_len; + } + return def_ptr; + } + return duk_require_lstring(ctx, idx, out_len); +} + +DUK_EXTERNAL const char *duk_opt_string(duk_context *ctx, duk_idx_t idx, const char *def_ptr) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_ptr; + } + return duk_require_string(ctx, idx); +} + +DUK_EXTERNAL const char *duk_get_lstring_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) { + duk_hstring *h; + const char *ret; + duk_size_t len; + + DUK_ASSERT_CTX_VALID(ctx); + + h = duk_get_hstring(ctx, idx); + if (h != NULL) { + len = DUK_HSTRING_GET_BYTELEN(h); + ret = (const char *) DUK_HSTRING_GET_DATA(h); + } else { + len = def_len; + ret = def_ptr; + } + + if (out_len != NULL) { + *out_len = len; + } + return ret; +} + +DUK_EXTERNAL const char *duk_get_string_default(duk_context *ctx, duk_idx_t idx, const char *def_value) { + duk_hstring *h; + DUK_ASSERT_CTX_VALID(ctx); - return duk_get_lstring(ctx, idx, NULL); + h = duk_get_hstring(ctx, idx); + if (h != NULL) { + return (const char *) DUK_HSTRING_GET_DATA(h); + } else { + return def_value; + } } DUK_INTERNAL const char *duk_get_string_notsymbol(duk_context *ctx, duk_idx_t idx) { @@ -17633,7 +18353,7 @@ return (const char *) DUK_HSTRING_GET_DATA(h); } -DUK_EXTERNAL void *duk_get_pointer(duk_context *ctx, duk_idx_t idx) { +DUK_LOCAL void *duk__get_pointer_raw(duk_context *ctx, duk_idx_t idx, void *def_value) { duk_tval *tv; void *p; @@ -17642,13 +18362,30 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); if (!DUK_TVAL_IS_POINTER(tv)) { - return NULL; + return def_value; } p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */ return p; } +DUK_EXTERNAL void *duk_get_pointer(duk_context *ctx, duk_idx_t idx) { + return duk__get_pointer_raw(ctx, idx, NULL /*def_value*/); +} + +DUK_EXTERNAL void *duk_opt_pointer(duk_context *ctx, duk_idx_t idx, void *def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_pointer(ctx, idx); +} + +DUK_EXTERNAL void *duk_get_pointer_default(duk_context *ctx, duk_idx_t idx, void *def_value) { + return duk__get_pointer_raw(ctx, idx, def_value); +} + DUK_EXTERNAL void *duk_require_pointer(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -17661,7 +18398,7 @@ */ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_POINTER(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_POINTER(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "pointer", DUK_STR_NOT_POINTER); } p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */ @@ -17687,10 +18424,12 @@ } #endif -DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_bool_t throw_flag) { +DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag) { duk_hthread *thr = (duk_hthread *) ctx; - duk_tval *tv; duk_hbuffer *h; + void *ret; + duk_size_t len; + duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); DUK_UNREF(thr); @@ -17701,27 +18440,54 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_BUFFER(tv)) { + if (DUK_LIKELY(DUK_TVAL_IS_BUFFER(tv))) { + h = DUK_TVAL_GET_BUFFER(tv); + DUK_ASSERT(h != NULL); + + len = DUK_HBUFFER_GET_SIZE(h); + ret = DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); + } else { if (throw_flag) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER); } - return NULL; + len = def_size; + ret = def_ptr; } - h = DUK_TVAL_GET_BUFFER(tv); - DUK_ASSERT(h != NULL); - if (out_size) { - *out_size = DUK_HBUFFER_GET_SIZE(h); + if (out_size != NULL) { + *out_size = len; } - return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */ + return ret; } DUK_EXTERNAL void *duk_get_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { - return duk__get_buffer_helper(ctx, idx, out_size, 0 /*throw_flag*/); + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_buffer_helper(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/); +} + +DUK_EXTERNAL void *duk_opt_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + if (out_size != NULL) { + *out_size = def_size; + } + return def_ptr; + } + return duk_require_buffer(ctx, idx, out_size); +} + +DUK_EXTERNAL void *duk_get_buffer_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len) { + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_buffer_helper(ctx, idx, out_size, def_ptr, def_len, 0 /*throw_flag*/); } DUK_EXTERNAL void *duk_require_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { - return duk__get_buffer_helper(ctx, idx, out_size, 1 /*throw_flag*/); + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_buffer_helper(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/); } /* Get the active buffer data area for a plain buffer or a buffer object. @@ -17729,7 +18495,7 @@ * have a NULL data pointer when its size is zero, the optional 'out_isbuffer' * argument allows caller to detect this reliably. */ -DUK_INTERNAL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_bool_t throw_flag, duk_bool_t *out_isbuffer) { +DUK_INTERNAL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag, duk_bool_t *out_isbuffer) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -17740,7 +18506,7 @@ *out_isbuffer = 0; } if (out_size != NULL) { - *out_size = 0; + *out_size = def_size; } tv = duk_get_tval_or_unused(ctx, idx); @@ -17789,15 +18555,31 @@ if (throw_flag) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER); } - return NULL; + return def_ptr; } DUK_EXTERNAL void *duk_get_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { - return duk_get_buffer_data_raw(ctx, idx, out_size, 0 /*throw_flag*/, NULL); + return duk_get_buffer_data_raw(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, NULL); +} + +DUK_EXTERNAL void *duk_get_buffer_data_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) { + return duk_get_buffer_data_raw(ctx, idx, out_size, def_ptr, def_size, 0 /*throw_flag*/, NULL); +} + +DUK_EXTERNAL void *duk_opt_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + if (out_size != NULL) { + *out_size = def_size; + } + return def_ptr; + } + return duk_require_buffer_data(ctx, idx, out_size); } DUK_EXTERNAL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { - return duk_get_buffer_data_raw(ctx, idx, out_size, 1 /*throw_flag*/, NULL); + return duk_get_buffer_data_raw(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/, NULL); } /* Raw helper for getting a value from the stack, checking its tag. @@ -17829,7 +18611,7 @@ DUK_INTERNAL duk_hstring *duk_get_hstring_notsymbol(duk_context *ctx, duk_idx_t idx) { duk_hstring *res = (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING); - if (res && DUK_HSTRING_HAS_SYMBOL(res)) { + if (DUK_UNLIKELY(res && DUK_HSTRING_HAS_SYMBOL(res))) { return NULL; } return res; @@ -17838,7 +18620,7 @@ DUK_INTERNAL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t idx) { duk_hstring *h; h = (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING); - if (h == NULL) { + if (DUK_UNLIKELY(h == NULL)) { DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "string", DUK_STR_NOT_STRING); } return h; @@ -17847,7 +18629,7 @@ DUK_INTERNAL duk_hstring *duk_require_hstring_notsymbol(duk_context *ctx, duk_idx_t idx) { duk_hstring *h; h = (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING); - if (h == NULL || DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(h == NULL || DUK_HSTRING_HAS_SYMBOL(h))) { DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "string", DUK_STR_NOT_STRING); } return h; @@ -17860,7 +18642,7 @@ DUK_INTERNAL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t idx) { duk_hobject *h; h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (h == NULL) { + if (DUK_UNLIKELY(h == NULL)) { DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "object", DUK_STR_NOT_OBJECT); } return h; @@ -17873,7 +18655,7 @@ DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t idx) { duk_hbuffer *h; h = (duk_hbuffer *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_BUFFER); - if (h == NULL) { + if (DUK_UNLIKELY(h == NULL)) { DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "buffer", DUK_STR_NOT_BUFFER); } return h; @@ -17881,7 +18663,7 @@ DUK_INTERNAL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t idx) { duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (h != NULL && !DUK_HOBJECT_IS_THREAD(h)) { + if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_THREAD(h))) { h = NULL; } return (duk_hthread *) h; @@ -17890,7 +18672,7 @@ DUK_INTERNAL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (!(h != NULL && DUK_HOBJECT_IS_THREAD(h))) { + if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_THREAD(h)))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "thread", DUK_STR_NOT_THREAD); } return (duk_hthread *) h; @@ -17898,7 +18680,7 @@ DUK_INTERNAL duk_hcompfunc *duk_get_hcompfunc(duk_context *ctx, duk_idx_t idx) { duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (h != NULL && !DUK_HOBJECT_IS_COMPFUNC(h)) { + if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_COMPFUNC(h))) { h = NULL; } return (duk_hcompfunc *) h; @@ -17907,7 +18689,7 @@ DUK_INTERNAL duk_hcompfunc *duk_require_hcompfunc(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (!(h != NULL && DUK_HOBJECT_IS_COMPFUNC(h))) { + if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_COMPFUNC(h)))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "compiledfunction", DUK_STR_NOT_COMPFUNC); } return (duk_hcompfunc *) h; @@ -17915,7 +18697,7 @@ DUK_INTERNAL duk_hnatfunc *duk_get_hnatfunc(duk_context *ctx, duk_idx_t idx) { duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (h != NULL && !DUK_HOBJECT_IS_NATFUNC(h)) { + if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_NATFUNC(h))) { h = NULL; } return (duk_hnatfunc *) h; @@ -17924,7 +18706,7 @@ DUK_INTERNAL duk_hnatfunc *duk_require_hnatfunc(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (!(h != NULL && DUK_HOBJECT_IS_NATFUNC(h))) { + if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_NATFUNC(h)))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC); } return (duk_hnatfunc *) h; @@ -17939,13 +18721,13 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_OBJECT(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_OBJECT(tv))) { return NULL; } h = DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(h != NULL); - if (!DUK_HOBJECT_IS_NATFUNC(h)) { + if (DUK_UNLIKELY(!DUK_HOBJECT_IS_NATFUNC(h))) { return NULL; } DUK_ASSERT(DUK_HOBJECT_HAS_NATFUNC(h)); @@ -17954,6 +18736,28 @@ return f->func; } +DUK_EXTERNAL duk_c_function duk_opt_c_function(duk_context *ctx, duk_idx_t idx, duk_c_function def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_c_function(ctx, idx); +} + +DUK_EXTERNAL duk_c_function duk_get_c_function_default(duk_context *ctx, duk_idx_t idx, duk_c_function def_value) { + duk_c_function ret; + + DUK_ASSERT_CTX_VALID(ctx); + + ret = duk_get_c_function(ctx, idx); + if (ret != NULL) { + return ret; + } + + return def_value; +} + DUK_EXTERNAL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_c_function ret; @@ -17961,14 +18765,14 @@ DUK_ASSERT_CTX_VALID(ctx); ret = duk_get_c_function(ctx, idx); - if (!ret) { + if (DUK_UNLIKELY(!ret)) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC); } return ret; } DUK_EXTERNAL void duk_require_function(duk_context *ctx, duk_idx_t idx) { - if (!duk_is_function(ctx, idx)) { + if (DUK_UNLIKELY(!duk_is_function(ctx, idx))) { DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, idx, "function", DUK_STR_NOT_FUNCTION); } } @@ -17977,7 +18781,7 @@ duk_hobject *h; h = duk_require_hobject_accept_mask(ctx, idx, DUK_TYPE_MASK_LIGHTFUNC); - if (h != NULL && !DUK_HOBJECT_HAS_CONSTRUCTABLE(h)) { + if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_HAS_CONSTRUCTABLE(h))) { DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, idx, "constructable", DUK_STR_NOT_CONSTRUCTABLE); } /* Lightfuncs (h == NULL) are constructable. */ @@ -17995,6 +18799,28 @@ return (duk_context *) duk_require_hthread(ctx, idx); } +DUK_EXTERNAL duk_context *duk_opt_context(duk_context *ctx, duk_idx_t idx, duk_context *def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_context(ctx, idx); +} + +DUK_EXTERNAL_DECL duk_context *duk_get_context_default(duk_context *ctx, duk_idx_t idx, duk_context *def_value) { + duk_context *ret; + + DUK_ASSERT_CTX_VALID(ctx); + + ret = duk_get_context(ctx, idx); + if (ret != NULL) { + return ret; + } + + return def_value; +} + DUK_EXTERNAL void *duk_get_heapptr(duk_context *ctx, duk_idx_t idx) { duk_tval *tv; void *ret; @@ -18003,7 +18829,7 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) { return (void *) NULL; } @@ -18012,6 +18838,28 @@ return ret; } +DUK_EXTERNAL void *duk_opt_heapptr(duk_context *ctx, duk_idx_t idx, void *def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_heapptr(ctx, idx); +} + +DUK_EXTERNAL_DECL void *duk_get_heapptr_default(duk_context *ctx, duk_idx_t idx, void *def_value) { + void *ret; + + DUK_ASSERT_CTX_VALID(ctx); + + ret = duk_get_heapptr(ctx, idx); + if (ret != NULL) { + return ret; + } + + return def_value; +} + DUK_EXTERNAL void *duk_require_heapptr(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -18021,7 +18869,7 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "heapobject", DUK_STR_UNEXPECTED_TYPE); } @@ -18038,7 +18886,7 @@ DUK_ASSERT_CTX_VALID(ctx); res = duk_get_hobject(ctx, idx); /* common case, not promoted */ - if (res != NULL) { + if (DUK_LIKELY(res != NULL)) { DUK_ASSERT(res != NULL); return res; } @@ -18093,7 +18941,7 @@ DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX); h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum) { + if (DUK_UNLIKELY(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum)) { h = NULL; } return h; @@ -18109,7 +18957,7 @@ thr = (duk_hthread *) ctx; h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum)) { + if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum))) { duk_hstring *h_class; h_class = DUK_HTHREAD_GET_STRING(thr, DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum)); DUK_UNREF(h_class); @@ -18151,7 +18999,7 @@ case DUK_TAG_STRING: { duk_hstring *h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { return 0; } return (duk_size_t) DUK_HSTRING_GET_CHARLEN(h); @@ -18453,6 +19301,16 @@ tv = duk_require_tval(ctx, idx); DUK_ASSERT(tv != NULL); + +#if defined(DUK_USE_FASTINT) + /* If argument is a fastint, guarantee that it remains one. + * There's no downgrade check for other cases. + */ + if (DUK_TVAL_IS_FASTINT(tv)) { + /* XXX: Unnecessary conversion back and forth. */ + return (duk_double_t) DUK_TVAL_GET_FASTINT(tv); + } +#endif d = coerce_func(thr, tv); /* XXX: fastint? */ @@ -18464,21 +19322,21 @@ } DUK_EXTERNAL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t idx) { - /* Value coercion (in stack): ToInteger(), E5 Section 9.4 - * API return value coercion: custom + /* Value coercion (in stack): ToInteger(), E5 Section 9.4, + * API return value coercion: custom. */ DUK_ASSERT_CTX_VALID(ctx); (void) duk__to_int_uint_helper(ctx, idx, duk_js_tointeger); - return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*require*/); + return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*def_value*/, 0 /*require*/); } DUK_EXTERNAL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t idx) { - /* Value coercion (in stack): ToInteger(), E5 Section 9.4 - * API return value coercion: custom + /* Value coercion (in stack): ToInteger(), E5 Section 9.4, + * API return value coercion: custom. */ DUK_ASSERT_CTX_VALID(ctx); (void) duk__to_int_uint_helper(ctx, idx, duk_js_tointeger); - return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*require*/); + return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*def_value*/, 0 /*require*/); } DUK_EXTERNAL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t idx) { @@ -18682,7 +19540,7 @@ duk_hstring *h; h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { stridx = DUK_STRIDX_UC_SYMBOL; } else { stridx = DUK_STRIDX_UC_STRING; @@ -18840,7 +19698,7 @@ duk_hstring *h; h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CANNOT_STRING_COERCE_SYMBOL); } else { goto skip_replace; @@ -18920,7 +19778,7 @@ duk_hstring *ret; DUK_ASSERT_CTX_VALID(ctx); ret = duk_get_hstring(ctx, idx); - if (ret && DUK_HSTRING_HAS_SYMBOL(ret)) { + if (DUK_UNLIKELY(ret && DUK_HSTRING_HAS_SYMBOL(ret))) { return ret; } return duk_to_hstring(ctx, idx); @@ -19073,6 +19931,7 @@ flags = DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_CONSTRUCTABLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_NATFUNC | DUK_HOBJECT_FLAG_NEWENV | DUK_HOBJECT_FLAG_STRICT | @@ -19123,6 +19982,7 @@ } case DUK_TAG_BOOLEAN: { flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BOOLEAN); proto = DUK_BIDX_BOOLEAN_PROTOTYPE; goto create_object; @@ -19131,12 +19991,14 @@ duk_hstring *h; h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_SYMBOL); proto = DUK_BIDX_SYMBOL_PROTOTYPE; } else { flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING); proto = DUK_BIDX_STRING_PROTOTYPE; @@ -19166,6 +20028,7 @@ #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ case DUK_TAG_POINTER: { flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER); proto = DUK_BIDX_POINTER_PROTOTYPE; goto create_object; @@ -19194,7 +20057,8 @@ DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); flags = DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_NUMBER); + DUK_HOBJECT_FLAG_FASTREFS | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_NUMBER); proto = DUK_BIDX_NUMBER_PROTOTYPE; goto create_object; } @@ -19412,7 +20276,7 @@ DUK_ASSERT_CTX_VALID(ctx); - if (duk_get_type_mask(ctx, idx) & mask) { + if (DUK_LIKELY(duk_get_type_mask(ctx, idx) & mask)) { return 1; } if (mask & DUK_TYPE_MASK_THROW) { @@ -19538,7 +20402,10 @@ DUK_ASSERT_CTX_VALID(ctx); h = duk_get_hstring(ctx, idx); - if (h != NULL && DUK_HSTRING_HAS_SYMBOL(h)) { + /* Use DUK_LIKELY() here because caller may be more likely to type + * check an expected symbol than not. + */ + if (DUK_LIKELY(h != NULL && DUK_HSTRING_HAS_SYMBOL(h))) { return 1; } return 0; @@ -19594,10 +20461,15 @@ } DUK_EXTERNAL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t idx) { + duk_hobject *obj; + DUK_ASSERT_CTX_VALID(ctx); - return duk__obj_flag_any_default_false(ctx, - idx, - DUK_HOBJECT_FLAG_THREAD); + + obj = duk_get_hobject(ctx, idx); + if (obj) { + return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_THREAD ? 1 : 0); + } + return 0; } DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t idx) { @@ -19868,9 +20740,7 @@ DUK_ASSERT_CTX_VALID(ctx); /* check stack before interning (avoid hanging temp) */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); /* NULL with zero length represents an empty string; NULL with higher * length is also now trated like an empty string although it is @@ -19882,11 +20752,11 @@ } /* Check for maximum string length */ - if (len > DUK_HSTRING_MAX_BYTELEN) { + if (DUK_UNLIKELY(len > DUK_HSTRING_MAX_BYTELEN)) { DUK_ERROR_RANGE(thr, DUK_STR_STRING_TOO_LONG); } - h = duk_heap_string_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len); + h = duk_heap_strtable_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len); DUK_ASSERT(h != NULL); tv_slot = thr->valstack_top++; @@ -20004,6 +20874,7 @@ thr = (duk_hthread *) ctx; DUK_ASSERT(thr->callstack_top > 0); /* caller required to know */ + DUK_ASSERT(thr->callstack_curr != NULL); DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* consequence of above */ DUK_ASSERT(thr->valstack_bottom - 1 >= thr->valstack); /* 'this' binding exists */ @@ -20019,8 +20890,8 @@ DUK_ASSERT_DISABLE(thr->callstack_top >= 0); DUK_ASSERT(thr->callstack_top <= thr->callstack_size); - act = duk_hthread_get_current_activation(thr); - if (act) { + act = thr->callstack_curr; + if (act != NULL) { duk_push_tval(ctx, &act->tv_func); } else { duk_push_undefined(ctx); @@ -20078,7 +20949,7 @@ DUK_EXTERNAL void duk_push_thread_stash(duk_context *ctx, duk_context *target_ctx) { duk_hthread *thr = (duk_hthread *) ctx; DUK_ASSERT_CTX_VALID(ctx); - if (!target_ctx) { + if (DUK_UNLIKELY(target_ctx == NULL)) { DUK_ERROR_TYPE_INVALID_ARGS(thr); return; /* not reached */ } @@ -20155,7 +21026,7 @@ /* failed, resize and try again */ sz = sz * 2; - if (sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT) { + if (DUK_UNLIKELY(sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT)) { DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG); } } @@ -20193,15 +21064,10 @@ DUK_ASSERT(prototype_bidx == -1 || (prototype_bidx >= 0 && prototype_bidx < DUK_NUM_BUILTINS)); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); - h = duk_hobject_alloc(thr->heap, hobject_flags_and_class); - if (!h) { - DUK_ERROR_ALLOC_FAILED(thr); - } + h = duk_hobject_alloc(thr, hobject_flags_and_class); + DUK_ASSERT(h != NULL); DUK_DDD(DUK_DDDPRINT("created object with flags: 0x%08lx", (unsigned long) h->hdr.h_flags)); @@ -20240,6 +21106,7 @@ (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), DUK_BIDX_OBJECT_PROTOTYPE); return duk_get_top_index_unsafe(ctx); @@ -20255,14 +21122,13 @@ DUK_ASSERT_CTX_VALID(ctx); flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_ARRAY_PART | DUK_HOBJECT_FLAG_EXOTIC_ARRAY | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAY); - obj = duk_harray_alloc(thr->heap, flags); - if (!obj) { - DUK_ERROR_ALLOC_FAILED(thr); - } + obj = duk_harray_alloc(thr, flags); + DUK_ASSERT(obj != NULL); /* XXX: since prototype is NULL, could save a check */ DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_ARRAY_PROTOTYPE]); @@ -20316,18 +21182,12 @@ DUK_ASSERT_CTX_VALID(ctx); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); - obj = duk_hthread_alloc(thr->heap, + obj = duk_hthread_alloc(thr, DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_THREAD | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD)); - if (!obj) { - DUK_ERROR_ALLOC_FAILED(thr); - } + DUK_ASSERT(obj != NULL); obj->state = DUK_HTHREAD_STATE_INACTIVE; #if defined(DUK_USE_ROM_STRINGS) /* Nothing to initialize, strs[] is in ROM. */ @@ -20348,7 +21208,7 @@ thr->valstack_top++; /* important to do this *after* pushing, to make the thread reachable for gc */ - if (!duk_hthread_init_stacks(thr->heap, obj)) { + if (DUK_UNLIKELY(!duk_hthread_init_stacks(thr->heap, obj))) { DUK_ERROR_ALLOC_FAILED(thr); } @@ -20379,21 +21239,18 @@ DUK_ASSERT_CTX_VALID(ctx); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); /* Template functions are not strictly constructable (they don't * have a "prototype" property for instance), so leave the * DUK_HOBJECT_FLAG_CONSRUCTABLE flag cleared here. */ - obj = duk_hcompfunc_alloc(thr->heap, + obj = duk_hcompfunc_alloc(thr, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_COMPFUNC | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION)); - if (!obj) { + if (DUK_UNLIKELY(obj == NULL)) { DUK_ERROR_ALLOC_FAILED(thr); } @@ -20418,11 +21275,9 @@ DUK_ASSERT_CTX_VALID(ctx); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } - if (func == NULL) { + DUK__CHECK_SPACE(); + + if (DUK_UNLIKELY(func == NULL)) { goto api_error; } if (nargs >= 0 && nargs < DUK_HNATFUNC_NARGS_MAX) { @@ -20433,10 +21288,8 @@ goto api_error; } - obj = duk_hnatfunc_alloc(thr->heap, flags); - if (!obj) { - DUK_ERROR_ALLOC_FAILED(thr); - } + obj = duk_hnatfunc_alloc(thr, flags); + DUK_ASSERT(obj != NULL); obj->func = func; obj->nargs = func_nargs; @@ -20467,6 +21320,7 @@ flags = DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_CONSTRUCTABLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_NATFUNC | DUK_HOBJECT_FLAG_NEWENV | DUK_HOBJECT_FLAG_STRICT | @@ -20484,6 +21338,7 @@ flags = DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_CONSTRUCTABLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_NATFUNC | DUK_HOBJECT_FLAG_NEWENV | DUK_HOBJECT_FLAG_STRICT | @@ -20499,6 +21354,7 @@ DUK_ASSERT_CTX_VALID(ctx); flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_NATFUNC | DUK_HOBJECT_FLAG_NEWENV | DUK_HOBJECT_FLAG_STRICT | @@ -20515,10 +21371,7 @@ DUK_ASSERT_CTX_VALID(ctx); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); if (nargs >= DUK_LFUNC_NARGS_MIN && nargs <= DUK_LFUNC_NARGS_MAX) { /* as is */ @@ -20527,10 +21380,10 @@ } else { goto api_error; } - if (!(length >= DUK_LFUNC_LENGTH_MIN && length <= DUK_LFUNC_LENGTH_MAX)) { + if (DUK_UNLIKELY(!(length >= DUK_LFUNC_LENGTH_MIN && length <= DUK_LFUNC_LENGTH_MAX))) { goto api_error; } - if (!(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX)) { + if (DUK_UNLIKELY(!(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX))) { goto api_error; } @@ -20554,15 +21407,10 @@ DUK_ASSERT(ctx != NULL); DUK_ASSERT(prototype_bidx >= 0); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); - obj = duk_hbufobj_alloc(thr->heap, hobject_flags_and_class); - if (!obj) { - DUK_ERROR_ALLOC_FAILED(thr); - } + obj = duk_hbufobj_alloc(thr, hobject_flags_and_class); + DUK_ASSERT(obj != NULL); DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[prototype_bidx]); DUK_ASSERT_HBUFOBJ_VALID(obj); @@ -20622,19 +21470,19 @@ uint_offset = (duk_uint_t) byte_offset; uint_length = (duk_uint_t) byte_length; if (sizeof(duk_size_t) != sizeof(duk_uint_t)) { - if ((duk_size_t) uint_offset != byte_offset || (duk_size_t) uint_length != byte_length) { + if (DUK_UNLIKELY((duk_size_t) uint_offset != byte_offset || (duk_size_t) uint_length != byte_length)) { goto range_error; } } uint_added = uint_offset + uint_length; - if (uint_added < uint_offset) { + if (DUK_UNLIKELY(uint_added < uint_offset)) { goto range_error; } DUK_ASSERT(uint_added >= uint_offset && uint_added >= uint_length); DUK_ASSERT_DISABLE(flags >= 0); /* flags is unsigned */ - lookupidx = flags & 0x0f; /* 4 low bits */ - if (lookupidx >= sizeof(duk__bufobj_flags_lookup) / sizeof(duk_uint32_t)) { + lookupidx = flags; + if (DUK_UNLIKELY(lookupidx >= sizeof(duk__bufobj_flags_lookup) / sizeof(duk_uint32_t))) { goto arg_error; } tmp = duk__bufobj_flags_lookup[lookupidx]; @@ -20663,39 +21511,9 @@ /* TypedArray views need an automatic ArrayBuffer which must be * provided as .buffer property of the view. The ArrayBuffer is * referenced via duk_hbufobj->buf_prop and an inherited .buffer - * accessor returns it. - * - * The ArrayBuffer offset is always set to zero, so that if one - * accesses the ArrayBuffer at the view's .byteOffset, the value - * matches the view at index 0. - */ - if (flags & DUK_BUFOBJ_CREATE_ARRBUF) { - duk_hbufobj *h_arrbuf; - - h_arrbuf = duk_push_bufobj_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), - DUK_BIDX_ARRAYBUFFER_PROTOTYPE); - DUK_ASSERT(h_arrbuf != NULL); - - h_arrbuf->buf = h_val; - DUK_HBUFFER_INCREF(thr, h_val); - h_arrbuf->offset = 0; - h_arrbuf->length = uint_offset + uint_length; /* Wrap checked above. */ - DUK_ASSERT(h_arrbuf->shift == 0); - h_arrbuf->elem_type = DUK_HBUFOBJ_ELEM_UINT8; - DUK_ASSERT(h_arrbuf->is_typedarray == 0); - DUK_ASSERT_HBUFOBJ_VALID(h_arrbuf); - DUK_ASSERT(h_arrbuf->buf_prop == NULL); - - DUK_ASSERT(h_bufobj->buf_prop == NULL); - h_bufobj->buf_prop = (duk_hobject *) h_arrbuf; - DUK_HBUFOBJ_INCREF(thr, h_arrbuf); /* Now reachable and accounted for. */ - - duk_pop(ctx); - } - + * accessor returns it. The ArrayBuffer is created lazily on first + * access so we don't need to do anything more here. + */ return; range_error: @@ -20738,6 +21556,7 @@ proto = duk_error_prototype_from_code(thr, err_code); (void) duk_push_object_helper_proto(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR), proto); @@ -20805,18 +21624,15 @@ DUK_ASSERT_CTX_VALID(ctx); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); /* Check for maximum buffer length. */ - if (size > DUK_HBUFFER_MAX_BYTELEN) { + if (DUK_UNLIKELY(size > DUK_HBUFFER_MAX_BYTELEN)) { DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG); } h = duk_hbuffer_alloc(thr->heap, size, flags, &buf_data); - if (!h) { + if (DUK_UNLIKELY(h == NULL)) { DUK_ERROR_ALLOC_FAILED(thr); } @@ -20844,9 +21660,110 @@ return ptr; } +#if defined(DUK_USE_ASSERTIONS) +DUK_LOCAL void duk__validate_push_heapptr(duk_context *ctx, void *ptr) { + duk_heaphdr *h; + duk_heaphdr *curr; + duk_hthread *thr; + duk_bool_t found = 0; + + thr = (duk_hthread *) ctx; + h = (duk_heaphdr *) ptr; + if (h == NULL) { + /* Allowed. */ + return; + } + DUK_ASSERT(h != NULL); + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); + + /* One particular problem case is where an object has been + * queued for finalization but the finalizer hasn't yet been + * executed. + * + * Corner case: we're running in a finalizer for object X, and + * user code calls duk_push_heapptr() for X itself. In this + * case X will be in finalize_list, and we can detect the case + * by seeing that X's FINALIZED flag is set (which is done before + * the finalizer starts executing). + */ +#if defined(DUK_USE_FINALIZER_SUPPORT) + for (curr = thr->heap->finalize_list; + curr != NULL; + curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) { + /* FINALIZABLE is set for all objects on finalize_list + * except for an object being finalized right now. So + * can't assert here. + */ +#if 0 + DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(curr)); +#endif + + if (curr == h) { + if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h)) { + /* Object is currently being finalized. */ + DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ + found = 1; + } else { + /* Not being finalized but on finalize_list, + * allowed since Duktape 2.1. + */ + DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ + found = 1; + } + } + } +#endif /* DUK_USE_FINALIZER_SUPPORT */ + +#if defined(DUK_USE_REFERENCE_COUNTING) + /* Because refzero_list is now processed to completion inline with + * no side effects, it's always empty here. + */ + DUK_ASSERT(thr->heap->refzero_list == NULL); +#endif + + /* If not present in finalize_list (or refzero_list), it + * must be either in heap_allocated or the string table. + */ + if (DUK_HEAPHDR_IS_STRING(h)) { + duk_uint32_t i; + duk_hstring *str; + duk_heap *heap = thr->heap; + + DUK_ASSERT(found == 0); + for (i = 0; i < heap->st_size; i++) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + str = DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, heap->strtable16[i]); +#else + str = heap->strtable[i]; +#endif + while (str != NULL) { + if (str == (duk_hstring *) h) { + DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ + found = 1; + break; + } + str = str->hdr.h_next; + } + } + DUK_ASSERT(found != 0); + } else { + for (curr = thr->heap->heap_allocated; + curr != NULL; + curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) { + if (curr == h) { + DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ + found = 1; + } + } + DUK_ASSERT(found != 0); + } +} +#endif /* DUK_USE_ASSERTIONS */ + DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr) { duk_hthread *thr = (duk_hthread *) ctx; duk_idx_t ret; + duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); @@ -20858,43 +21775,80 @@ */ #if defined(DUK_USE_ASSERTIONS) - { - /* One particular problem case is where an object has been - * queued for finalization but the finalizer hasn't been - * executed. - */ - duk_heaphdr *curr; - for (curr = thr->heap->finalize_list; - curr != NULL; - curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) { - DUK_ASSERT(curr != (duk_heaphdr *) ptr); - } - } + duk__validate_push_heapptr(ctx, ptr); #endif + DUK__CHECK_SPACE(); + ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); + tv = thr->valstack_top++; if (ptr == NULL) { - goto push_undefined; + DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); + return ret; + } + + DUK_ASSERT_HEAPHDR_VALID((duk_heaphdr *) ptr); + + /* If the argument is on finalize_list it has technically been + * unreachable before duk_push_heapptr() but it's still safe to + * push it. Starting from Duktape 2.1 allow application code to + * do so. There are two main cases: + * + * (1) The object is on the finalize_list and we're called by + * the finalizer for the object being finalized. In this + * case do nothing: finalize_list handling will deal with + * the object queueing. This is detected by the object not + * having a FINALIZABLE flag despite being on the finalize_list; + * the flag is cleared for the object being finalized only. + * + * (2) The object is on the finalize_list but is not currently + * being processed. In this case the object can be queued + * back to heap_allocated with a few flags cleared, in effect + * cancelling the finalizer. + */ + if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) ptr))) { + duk_heaphdr *curr; + + DUK_D(DUK_DPRINT("duk_push_heapptr() with a pointer on finalize_list, autorescue")); + + curr = (duk_heaphdr *) ptr; + DUK_HEAPHDR_CLEAR_FINALIZABLE(curr); + + /* Because FINALIZED is set prior to finalizer call, it will + * be set for the object being currently finalized, but not + * for other objects on finalize_list. + */ + DUK_HEAPHDR_CLEAR_FINALIZED(curr); + + /* Dequeue object from finalize_list and queue it back to + * heap_allocated. + */ +#if defined(DUK_USE_REFERENCE_COUNTING) + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) >= 1); /* Preincremented on finalize_list insert. */ + DUK_HEAPHDR_PREDEC_REFCOUNT(curr); +#endif + DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(thr->heap, curr); + DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(thr->heap, curr); + + /* Continue with the rest. */ } switch (DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) { case DUK_HTYPE_STRING: - duk_push_hstring(ctx, (duk_hstring *) ptr); + DUK_TVAL_SET_STRING(tv, (duk_hstring *) ptr); break; case DUK_HTYPE_OBJECT: - duk_push_hobject(ctx, (duk_hobject *) ptr); - break; - case DUK_HTYPE_BUFFER: - duk_push_hbuffer(ctx, (duk_hbuffer *) ptr); + DUK_TVAL_SET_OBJECT(tv, (duk_hobject *) ptr); break; default: - goto push_undefined; + DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr) == DUK_HTYPE_BUFFER); + DUK_TVAL_SET_BUFFER(tv, (duk_hbuffer *) ptr); + break; } - return ret; - push_undefined: - duk_push_undefined(ctx); + DUK_HEAPHDR_INCREF(thr, (duk_heaphdr *) ptr); + return ret; } @@ -20902,6 +21856,7 @@ DUK_EXTERNAL duk_idx_t duk_push_bare_object(duk_context *ctx) { (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), -1); /* no prototype */ return duk_get_top_index_unsafe(ctx); @@ -20965,28 +21920,52 @@ #endif DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); if (DUK_UNLIKELY(count < 0)) { DUK_ERROR_RANGE_INVALID_COUNT(thr); return; } - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); if (DUK_UNLIKELY((duk_size_t) (thr->valstack_top - thr->valstack_bottom) < (duk_size_t) count)) { DUK_ERROR_RANGE_INVALID_COUNT(thr); } - /* - * Must be very careful here, every DECREF may cause reallocation - * of our valstack. - */ +#if defined(DUK_USE_REFERENCE_COUNTING) + tv = thr->valstack_top; + tv_end = tv - count; + while (tv != tv_end) { + tv--; + DUK_ASSERT(tv >= thr->valstack_bottom); + DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv); + } + thr->valstack_top = tv; + DUK_REFZERO_CHECK_FAST(thr); +#else + tv = thr->valstack_top; + while (count > 0) { + count--; + tv--; + DUK_ASSERT(tv >= thr->valstack_bottom); + DUK_TVAL_SET_UNDEFINED(tv); + } + thr->valstack_top = tv; +#endif - /* XXX: inlined DECREF macro would be nice here: no NULL check, - * refzero queueing but no refzero algorithm run (= no pointer - * instability), inline code. - */ + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); +} - /* XXX: optimize loops */ +DUK_INTERNAL void duk_pop_n_unsafe(duk_context *ctx, duk_idx_t count) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; +#if defined(DUK_USE_REFERENCE_COUNTING) + duk_tval *tv_end; +#endif + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(count >= 0); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count); #if defined(DUK_USE_REFERENCE_COUNTING) tv = thr->valstack_top; @@ -21012,6 +21991,34 @@ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); } +/* Pop N elements without DECREF (in effect "stealing" the refcounts). */ +#if defined(DUK_USE_REFERENCE_COUNTING) +DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_context *ctx, duk_idx_t count) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(count >= 0); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count); + + tv = thr->valstack_top; + while (count > 0) { + count--; + tv--; + DUK_ASSERT(tv >= thr->valstack_bottom); + DUK_TVAL_SET_UNDEFINED(tv); + } + thr->valstack_top = tv; + + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); +} +#else /* DUK_USE_REFERENCE_COUNTING */ +DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_context *ctx, duk_idx_t count) { + duk_pop_n_unsafe(ctx, count); +} +#endif /* DUK_USE_REFERENCE_COUNTING */ + /* Popping one element is called so often that when footprint is not an issue, * compile a specialized function for it. */ @@ -21048,16 +22055,17 @@ #if defined(DUK_USE_PREFER_SIZE) DUK_INTERNAL void duk_pop_unsafe(duk_context *ctx) { DUK_ASSERT_CTX_VALID(ctx); - duk_pop_n(ctx, 1); + duk_pop_n_unsafe(ctx, 1); } #else DUK_INTERNAL void duk_pop_unsafe(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; - DUK_ASSERT_CTX_VALID(ctx); - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(thr->valstack_top != thr->valstack_bottom); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1); tv = --thr->valstack_top; /* tv points to element just below prev top */ DUK_ASSERT(tv >= thr->valstack_bottom); @@ -21066,6 +22074,7 @@ #else DUK_TVAL_SET_UNDEFINED(tv); #endif + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); } #endif /* !DUK_USE_PREFER_SIZE */ @@ -21098,7 +22107,7 @@ thr = (duk_hthread *) ctx; top = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); - if (count < 0 || count > top) { + if (DUK_UNLIKELY(count < 0 || count > top)) { DUK_ERROR_RANGE_INVALID_COUNT(thr); return; } @@ -21161,12 +22170,13 @@ DUK_EXTERNAL void duk_throw_raw(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv_val; DUK_ASSERT(thr->valstack_bottom >= thr->valstack); DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); DUK_ASSERT(thr->valstack_end >= thr->valstack_top); - if (thr->valstack_top == thr->valstack_bottom) { + if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) { DUK_ERROR_TYPE_INVALID_ARGS(thr); } @@ -21187,7 +22197,11 @@ #endif DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (after throw augment)", (duk_tval *) duk_get_tval(ctx, -1))); - duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW); + tv_val = DUK_GET_TVAL_NEGIDX(ctx, -1); + duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, tv_val); +#if defined(DUK_USE_DEBUGGER_SUPPORT) + duk_err_check_debugger_integration(thr); +#endif /* thr->heap->lj.jmpbuf_ptr is checked by duk_err_longjmp() so we don't * need to check that here. If the value is NULL, a fatal error occurs @@ -21331,7 +22345,7 @@ return duk_js_strict_equals(tv1, tv2); } -DUK_EXTERNAL_DECL duk_bool_t duk_samevalue(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) { +DUK_EXTERNAL duk_bool_t duk_samevalue(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) { duk_tval *tv1, *tv2; DUK_ASSERT_CTX_VALID(ctx); @@ -21830,6 +22844,7 @@ duk_hstring *res; duk_size_t start_byte_offset; duk_size_t end_byte_offset; + duk_size_t charlen; DUK_ASSERT_CTX_VALID(ctx); @@ -21837,8 +22852,9 @@ h = duk_require_hstring(ctx, idx); DUK_ASSERT(h != NULL); - if (end_offset >= DUK_HSTRING_GET_CHARLEN(h)) { - end_offset = DUK_HSTRING_GET_CHARLEN(h); + charlen = DUK_HSTRING_GET_CHARLEN(h); + if (end_offset >= charlen) { + end_offset = charlen; } if (start_offset > end_offset) { start_offset = end_offset; @@ -21860,9 +22876,9 @@ DUK_ASSERT(end_byte_offset - start_byte_offset <= DUK_UINT32_MAX); /* Guaranteed by string limits. */ /* No size check is necessary. */ - res = duk_heap_string_intern_checked(thr, - DUK_HSTRING_GET_DATA(h) + start_byte_offset, - (duk_uint32_t) (end_byte_offset - start_byte_offset)); + 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(ctx, res); duk_replace(ctx, idx); @@ -23984,39 +25000,19 @@ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); } -DUK_LOCAL duk_hbufobj *duk__push_arraybuffer_with_length(duk_context *ctx, duk_uint_t len) { - duk_hbuffer *h_val; - duk_hbufobj *h_bufobj; - - (void) duk_push_fixed_buffer_zero(ctx, (duk_size_t) len); - h_val = (duk_hbuffer *) duk_known_hbuffer(ctx, -1); - - h_bufobj = duk_push_bufobj_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), - DUK_BIDX_ARRAYBUFFER_PROTOTYPE); - DUK_ASSERT(h_bufobj != NULL); - - duk__set_bufobj_buffer(ctx, h_bufobj, h_val); - DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); - - return h_bufobj; -} - -/* Shared offset/length coercion helper. */ -DUK_LOCAL void duk__resolve_offset_opt_length(duk_context *ctx, - duk_hbufobj *h_bufarg, - duk_idx_t idx_offset, - duk_idx_t idx_length, - duk_uint_t *out_offset, - duk_uint_t *out_length, - duk_bool_t throw_flag) { - duk_hthread *thr; - duk_int_t offset_signed; - duk_int_t length_signed; - duk_uint_t offset; - duk_uint_t length; +/* Shared offset/length coercion helper. */ +DUK_LOCAL void duk__resolve_offset_opt_length(duk_context *ctx, + duk_hbufobj *h_bufarg, + duk_idx_t idx_offset, + duk_idx_t idx_length, + duk_uint_t *out_offset, + duk_uint_t *out_length, + duk_bool_t throw_flag) { + duk_hthread *thr; + duk_int_t offset_signed; + duk_int_t length_signed; + duk_uint_t offset; + duk_uint_t length; thr = (duk_hthread *) ctx; DUK_UNREF(thr); @@ -24457,7 +25453,6 @@ duk_tval *tv; duk_hobject *h_obj; duk_hbufobj *h_bufobj = NULL; - duk_hbufobj *h_bufarr = NULL; duk_hbufobj *h_bufarg = NULL; duk_hbuffer *h_val; duk_small_uint_t magic; @@ -24670,15 +25665,17 @@ /* ArrayBuffer argument is handled specially above; the rest of the * argument variants are handled by shared code below. + * + * ArrayBuffer in h_bufobj->buf_prop is intentionally left unset. + * It will be automatically created by the .buffer accessor on + * first access. */ - /* Push a new ArrayBuffer (becomes view .buffer) */ - h_bufarr = duk__push_arraybuffer_with_length(ctx, byte_length); - DUK_ASSERT(h_bufarr != NULL); - h_val = h_bufarr->buf; + /* Push the resulting view object on top of a plain fixed buffer. */ + (void) duk_push_fixed_buffer(ctx, byte_length); + h_val = duk_known_hbuffer(ctx, -1); DUK_ASSERT(h_val != NULL); - /* Push the resulting view object and attach the ArrayBuffer. */ h_bufobj = duk_push_bufobj_raw(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_BUFOBJ | @@ -24694,12 +25691,6 @@ h_bufobj->is_typedarray = 1; DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); - /* Set .buffer */ - DUK_ASSERT(h_bufobj->buf_prop == NULL); - h_bufobj->buf_prop = (duk_hobject *) h_bufarr; - DUK_ASSERT(h_bufarr != NULL); - DUK_HBUFOBJ_INCREF(thr, h_bufarr); - /* Copy values, the copy method depends on the arguments. * * Copy mode decision may depend on the validity of the underlying @@ -25417,7 +26408,7 @@ } duk_hbufobj_promote_plain(ctx, 0); - h_obj = duk_known_hobject(ctx, 0); + h_obj = duk_require_hobject(ctx, 0); /* XXX: V8 throws a TypeError for negative values. Would it * be more useful to interpret negative offsets here from the @@ -25807,7 +26798,7 @@ res_proto_bidx); DUK_ASSERT(h_bufobj != NULL); - h_bufobj->length = slice_length; + DUK_ASSERT(h_bufobj->length == 0); h_bufobj->shift = h_this->shift; /* inherit */ h_bufobj->elem_type = h_this->elem_type; /* inherit */ h_bufobj->is_typedarray = magic & 0x01; @@ -25838,12 +26829,14 @@ h_bufobj->buf = h_val; DUK_HBUFFER_INCREF(thr, h_val); + h_bufobj->length = slice_length; DUK_ASSERT(h_bufobj->offset == 0); duk_pop(ctx); /* reachable so pop OK */ } else { h_bufobj->buf = h_val; DUK_HBUFFER_INCREF(thr, h_val); + h_bufobj->length = slice_length; h_bufobj->offset = (duk_uint_t) (h_this->offset + start_offset); /* Copy the .buffer property, needed for TypedArray.prototype.subarray(). @@ -26614,30 +27607,63 @@ */ #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_LOCAL duk_hbufobj *duk__autospawn_arraybuffer(duk_context *ctx, duk_hbuffer *h_buf) { + duk_hbufobj *h_res; + + h_res = duk_push_bufobj_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFOBJ | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), + DUK_BIDX_ARRAYBUFFER_PROTOTYPE); + DUK_ASSERT(h_res != NULL); + DUK_UNREF(h_res); + + duk__set_bufobj_buffer(ctx, h_res, h_buf); + DUK_ASSERT_HBUFOBJ_VALID(h_res); + DUK_ASSERT(h_res->buf_prop == NULL); + return h_res; +} + DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_context *ctx) { duk_hbufobj *h_bufobj; h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(ctx, DUK__BUFOBJ_FLAG_THROW /*flags*/); DUK_ASSERT(h_bufobj != NULL); if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) { - duk_hbufobj *h_res; - duk_hbuffer *h_buf; + DUK_DD(DUK_DDPRINT("autospawn ArrayBuffer for plain buffer")); + (void) duk__autospawn_arraybuffer(ctx, (duk_hbuffer *) h_bufobj); + return 1; + } else { + if (h_bufobj->buf_prop == NULL && + DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_bufobj) != DUK_HOBJECT_CLASS_ARRAYBUFFER && + h_bufobj->buf != NULL) { + duk_hbufobj *h_arrbuf; + + DUK_DD(DUK_DDPRINT("autospawn ArrayBuffer for typed array or DataView")); + h_arrbuf = duk__autospawn_arraybuffer(ctx, h_bufobj->buf); + + if (h_bufobj->buf_prop == NULL) { + /* Must recheck buf_prop, in case ArrayBuffer + * alloc had a side effect which already filled + * it! + */ - h_buf = (duk_hbuffer *) h_bufobj; - h_res = duk_push_bufobj_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), - DUK_BIDX_ARRAYBUFFER_PROTOTYPE); - DUK_ASSERT(h_res != NULL); - DUK_UNREF(h_res); + /* Set ArrayBuffer's .byteOffset and .byteLength based + * on the view so that Arraybuffer[view.byteOffset] + * matches view[0]. + */ + h_arrbuf->offset = 0; + DUK_ASSERT(h_bufobj->offset + h_bufobj->length >= h_bufobj->offset); /* Wrap check on creation. */ + h_arrbuf->length = h_bufobj->offset + h_bufobj->length; + DUK_ASSERT(h_arrbuf->buf_prop == NULL); - duk__set_bufobj_buffer(ctx, h_res, h_buf); - DUK_ASSERT_HBUFOBJ_VALID(h_res); + DUK_ASSERT(h_bufobj->buf_prop == NULL); + h_bufobj->buf_prop = (duk_hobject *) h_arrbuf; + DUK_HBUFOBJ_INCREF(thr, h_arrbuf); /* Now reachable and accounted for. */ + } - DUK_DD(DUK_DDPRINT("autospawned .buffer ArrayBuffer: %!iT", duk_get_tval(ctx, -1))); - return 1; - } else { + /* Left on stack; pushed for the second time below (OK). */ + } if (h_bufobj->buf_prop) { duk_push_hobject(ctx, h_bufobj->buf_prop); return 1; @@ -28141,6 +29167,7 @@ (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATE), DUK_BIDX_DATE_PROTOTYPE); @@ -28654,7 +29681,7 @@ * an mktime() error return is the cast above. See e.g.: * http://pubs.opengroup.org/onlinepubs/009695299/functions/mktime.html */ - goto error; + goto mktime_error; } DUK_DDD(DUK_DDDPRINT("t1=%ld (utc), t2=%ld (local)", (long) t1, (long) t2)); @@ -28670,7 +29697,7 @@ #endif return (duk_int_t) difftime(t2, t1); - error: + mktime_error: /* XXX: return something more useful, so that caller can throw? */ DUK_D(DUK_DPRINT("mktime() failed, d=%lf", (double) d)); return 0; @@ -28893,6 +29920,38 @@ return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000000LL); /* seconds */ } #endif /* DUK_USE_DATE_TZO_WINDOWS */ + +#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) { + 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; + FileTimeToLocalFileTime((const FILETIME *) &ft1, &ft2); + + FileTimeToSystemTime((const FILETIME *) &ft2, &st2); + duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2); + + return (duk_int_t) (((LONGLONG) tmp2.QuadPart - (LONGLONG) tmp1.QuadPart) / 10000000LL); /* seconds */ +} +#endif /* DUK_USE_DATE_TZO_WINDOWS_NO_DST */ #line 1 "duk_bi_duktape.c" /* * Duktape built-ins @@ -28925,15 +29984,14 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_small_uint_t flags; - duk_bool_t rc; flags = (duk_small_uint_t) duk_get_uint(ctx, 0); - rc = duk_heap_mark_and_sweep(thr->heap, flags); + duk_heap_mark_and_sweep(thr->heap, flags); /* XXX: Not sure what the best return value would be in the API. - * Return a boolean for now. Note that rc == 0 is success (true). + * Return true for now. */ - duk_push_boolean(ctx, !rc); + duk_push_true(ctx); return 1; } @@ -28945,15 +30003,16 @@ * 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. + * be deleted. Must use duk_set_finalizer() to keep + * DUK_HOBJECT_FLAG_HAVE_FINALIZER in sync. */ duk_set_top(ctx, 2); - (void) duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_INT_FINALIZER); + duk_set_finalizer(ctx, 0); return 0; } else { /* Get. */ DUK_ASSERT(duk_get_top(ctx) == 1); - duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_INT_FINALIZER); + duk_get_finalizer(ctx, 0); return 1; } } @@ -29205,6 +30264,7 @@ } } +#if defined(DUK_USE_ENCODING_BUILTINS) DUK_LOCAL void duk__utf8_encode_char(void *udata, duk_codepoint_t codepoint) { duk__encode_context *enc_ctx; @@ -29259,6 +30319,7 @@ */ enc_ctx->out += duk_unicode_encode_xutf8(codepoint, enc_ctx->out); } +#endif /* DUK_USE_ENCODING_BUILTINS */ /* Shared helper for buffer-to-string using a TextDecoder() compatible UTF-8 * decoder. @@ -29422,7 +30483,6 @@ DUK_ASSERT_TOP(ctx, 1); if (duk_is_undefined(ctx, 0)) { len = 0; - final_len = len; } else { duk_hstring *h_input; @@ -29480,6 +30540,8 @@ final_len = (duk_size_t) (enc_ctx.out - output); duk_resize_buffer(ctx, -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 @@ -29520,8 +30582,8 @@ * initialized explicitly. */ dec_ctx = (duk__decode_context *) duk_push_fixed_buffer(ctx, sizeof(duk__decode_context)); - dec_ctx->fatal = fatal; - dec_ctx->ignore_bom = ignore_bom; + 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_string(ctx, -2, "\xff" "Context"); @@ -29613,6 +30675,7 @@ /* 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); DUK_UNREF(thr); @@ -30054,7 +31117,7 @@ DUK_ASSERT_TOP(ctx, 3); /* strictness is not inherited, intentional */ - comp_flags = DUK_JS_COMPILE_FLAG_FUNCEXPR; + comp_flags = DUK_COMPILE_FUNCEXPR; duk_push_hstring_stridx(ctx, DUK_STRIDX_COMPILE); /* XXX: copy from caller? */ /* XXX: ignored now */ h_sourcecode = duk_require_hstring(ctx, -2); /* no symbol check needed; -2 is concat'd code */ @@ -30195,6 +31258,7 @@ /* XXX: [[Construct]] newTarget currently unsupported */ DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx); } + duk_set_top(ctx, 2); /* chop off extra arguments: [ constructor argArray ] */ idx_args = 1; break; } @@ -30325,6 +31389,7 @@ /* create bound function object */ h_bound = duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_BOUNDFUNC | DUK_HOBJECT_FLAG_CONSTRUCTABLE | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION), @@ -30846,7 +31911,8 @@ DUK_ASSERT(duk_get_top(ctx) == 1 || duk_get_top(ctx) == 2); /* 2 when called by debugger */ DUK_ASSERT(thr->callstack_top >= 1); /* at least this function exists */ - DUK_ASSERT(((thr->callstack + thr->callstack_top - 1)->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0 || /* indirect eval */ + 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 */ /* @@ -30876,8 +31942,9 @@ /* [ source ] */ - comp_flags = DUK_JS_COMPILE_FLAG_EVAL; - act_eval = thr->callstack + thr->callstack_top - 1; /* this function */ + comp_flags = DUK_COMPILE_EVAL; + act_eval = thr->callstack_curr; /* this function */ + DUK_ASSERT(act_eval != NULL); if (thr->callstack_top >= (duk_size_t) -level) { /* Have a calling activation, check for direct eval (otherwise * assume indirect eval. @@ -30888,7 +31955,7 @@ /* Only direct eval inherits strictness from calling code * (E5.1 Section 10.1.1). */ - comp_flags |= DUK_JS_COMPILE_FLAG_STRICT; + comp_flags |= DUK_COMPILE_STRICT; } } else { DUK_ASSERT((act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0); @@ -30908,7 +31975,7 @@ /* E5 Section 10.4.2 */ DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; /* this function */ + act = thr->callstack_curr; /* this function */ if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) { DUK_ASSERT(thr->callstack_top >= 2); act = thr->callstack + thr->callstack_top + level; /* caller */ @@ -30926,26 +31993,29 @@ this_to_global = 0; if (DUK_HOBJECT_HAS_STRICT((duk_hobject *) func)) { - duk_hobject *new_env; + 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 = thr->callstack + thr->callstack_top + level; /* caller */ act_lex_env = act->lex_env; act = NULL; /* invalidated */ - new_env = duk_push_object_helper_proto(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), - act_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(ctx, (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 = new_env; - outer_var_env = new_env; + outer_lex_env = (duk_hobject *) new_env; + outer_var_env = (duk_hobject *) new_env; duk_insert(ctx, 0); /* stash to bottom of value stack to keep new_env reachable for duration of eval */ @@ -30975,7 +32045,7 @@ /* 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*/); - /* [ source template closure ] */ + /* [ env? source template closure ] */ if (this_to_global) { DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); @@ -30994,11 +32064,11 @@ (duk_heaphdr *) outer_var_env, duk_get_tval(ctx, -1))); - /* [ source template closure this ] */ + /* [ env? source template closure this ] */ duk_call_method(ctx, 0); - /* [ source template result ] */ + /* [ env? source template result ] */ return 1; } @@ -31213,12 +32283,15 @@ DUK_LOCAL_DECL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv); #endif #if defined(DUK_USE_JX) || defined(DUK_USE_JC) -DUK_LOCAL_DECL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h); +DUK_LOCAL_DECL void duk__enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h); DUK_LOCAL_DECL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr); #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) DUK_LOCAL_DECL void duk__enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj); #endif #endif +#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) +DUK_LOCAL_DECL void duk__enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h); +#endif DUK_LOCAL_DECL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth); /* @@ -32698,13 +33771,60 @@ DUK_BW_SET_PTR(thr, &js_ctx->bw, q); } -DUK_LOCAL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) { +DUK_LOCAL void duk__enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) { duk__enc_buffer_data(js_ctx, (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h), (duk_size_t) DUK_HBUFFER_GET_SIZE(h)); } #endif /* DUK_USE_JX || DUK_USE_JC */ +#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) +DUK_LOCAL void duk__enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) { + duk_size_t i, n; + const duk_uint8_t *buf; + duk_uint8_t *q; + + n = DUK_HBUFFER_GET_SIZE(h); + if (n == 0) { + DUK__EMIT_2(js_ctx, DUK_ASC_LCURLY, DUK_ASC_RCURLY); + return; + } + + DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY); + + /* Maximum encoded length with 32-bit index: 1 + 10 + 2 + 3 + 1 + 1 = 18, + * with 64-bit index: 1 + 20 + 2 + 3 + 1 + 1 = 28. 32 has some spare. + * + * Note that because the output buffer is reallocated from time to time, + * side effects (such as finalizers) affecting the buffer 'h' must be + * disabled. This is the case in the JSON.stringify() fast path. + */ + + buf = (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h); + if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { + for (i = 0; i < n; i++) { + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth + 1); + q = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, 32); + q += DUK_SPRINTF((char *) q, "\"%lu\": %u,", (unsigned long) i, (unsigned int) buf[i]); + DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, q); + } + } else { + q = DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw); + for (i = 0; i < n; i++) { + q = DUK_BW_ENSURE_RAW(js_ctx->thr, &js_ctx->bw, 32, q); + q += DUK_SPRINTF((char *) q, "\"%lu\":%u,", (unsigned long) i, (unsigned int) buf[i]); + } + DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, q); + } + DUK__UNEMIT_1(js_ctx); /* eat trailing comma */ + + if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth); + } + DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY); +} +#endif /* DUK_USE_JSON_STRINGIFY_FASTPATH */ + #if defined(DUK_USE_JX) || defined(DUK_USE_JC) DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) { char buf[64]; /* XXX: how to figure correct size? */ @@ -33254,7 +34374,7 @@ case DUK_TAG_STRING: { duk_hstring *h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { goto pop2_undef; } duk__enc_quote_string(js_ctx, h); @@ -33285,12 +34405,13 @@ case DUK_TAG_BUFFER: { #if defined(DUK_USE_JX) || defined(DUK_USE_JC) if (js_ctx->flag_ext_custom_or_compatible) { - duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv)); + duk__enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv)); break; } #endif - /* Could implement a fast path, but object coerce and - * serialize the result for now. + + /* Could implement a fastpath, but the fast path would need + * to handle realloc side effects correctly. */ duk_to_object(ctx, -1); duk__enc_object(js_ctx); @@ -33350,7 +34471,7 @@ duk_hstring *h; h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { return 0; } return 1; @@ -33419,7 +34540,7 @@ duk_hstring *h; h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { goto emit_undefined; } duk__enc_quote_string(js_ctx, h); @@ -33584,7 +34705,7 @@ DUK_DD(DUK_DDPRINT("property is an accessor, abort fast path")); goto abort_fastpath; } - if (DUK_HSTRING_HAS_SYMBOL(k)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(k))) { continue; } @@ -33778,13 +34899,16 @@ #if defined(DUK_USE_JX) || defined(DUK_USE_JC) if (js_ctx->flag_ext_custom_or_compatible) { - duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv)); + duk__enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv)); break; } #endif - /* Could implement a fast path, but abort fast path for now. */ - DUK_DD(DUK_DDPRINT("value is a plain buffer and serializing as plain JSON, abort fast path")); - goto abort_fastpath; + + /* Plain buffers mimic Uint8Arrays, and have enumerable index + * properties. + */ + duk__enc_buffer_json_fastpath(js_ctx, DUK_TVAL_GET_BUFFER(tv)); + break; } case DUK_TAG_POINTER: { #if defined(DUK_USE_JX) || defined(DUK_USE_JC) @@ -34181,8 +35305,11 @@ } if (js_ctx->h_gap != NULL) { - /* if gap is empty, behave as if not given at all */ - if (DUK_HSTRING_GET_CHARLEN(js_ctx->h_gap) == 0) { + /* If gap is empty, behave as if not given at all. Check + * against byte length because character length is more + * expensive. + */ + if (DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) == 0) { js_ctx->h_gap = NULL; } } @@ -34198,7 +35325,7 @@ if (js_ctx->h_replacer == NULL && /* replacer is a mutation risk */ js_ctx->idx_proplist == -1) { /* proplist is very rare */ duk_int_t pcall_rc; - duk_small_uint_t prev_mark_and_sweep_base_flags; + duk_small_uint_t prev_ms_base_flags; DUK_DD(DUK_DDPRINT("try JSON.stringify() fast path")); @@ -34220,14 +35347,17 @@ duk_dup(ctx, idx_value); /* Must prevent finalizers which may have arbitrary side effects. */ - prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags; - thr->heap->mark_and_sweep_base_flags |= - DUK_MS_FLAG_NO_FINALIZERS | /* avoid attempts to add/remove object keys */ - DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid attempt to compact any objects */ + prev_ms_base_flags = thr->heap->ms_base_flags; + thr->heap->ms_base_flags |= + DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* Avoid attempt to compact any objects. */ + thr->heap->pf_prevent_count++; /* Prevent finalizers. */ + DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */ pcall_rc = duk_safe_call(ctx, duk__json_stringify_fast, (void *) js_ctx /*udata*/, 1 /*nargs*/, 0 /*nret*/); - thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; + DUK_ASSERT(thr->heap->pf_prevent_count > 0); + thr->heap->pf_prevent_count--; + thr->heap->ms_base_flags = prev_ms_base_flags; if (pcall_rc == DUK_EXEC_SUCCESS) { DUK_DD(DUK_DDPRINT("fast path successful")); @@ -35074,6 +36204,7 @@ (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), DUK_BIDX_OBJECT_PROTOTYPE); return 1; @@ -35136,6 +36267,7 @@ (void) duk_push_object_helper_proto(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), proto); @@ -35855,6 +36987,7 @@ if (duk_is_constructor_call(ctx)) { (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER), DUK_BIDX_POINTER_PROTOTYPE); @@ -35952,7 +37085,7 @@ goto skip_key; } } - if (DUK_HSTRING_HAS_SYMBOL(h)) { + 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(ctx, -1))); goto skip_key; @@ -36029,6 +37162,7 @@ */ (void) duk_push_object_helper_proto(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), NULL); @@ -36411,6 +37545,96 @@ #if defined(DUK_USE_STRING_BUILTIN) /* + * Helpers + */ + +DUK_LOCAL duk_hstring *duk__str_tostring_notregexp(duk_context *ctx, duk_idx_t idx) { + duk_hstring *h; + + if (duk_get_class_number(ctx, idx) == DUK_HOBJECT_CLASS_REGEXP) { + DUK_ERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx); + } + h = duk_to_hstring(ctx, idx); + DUK_ASSERT(h != NULL); + + return h; +} + +DUK_LOCAL duk_int_t duk__str_search_shared(duk_context *ctx, duk_hstring *h_this, duk_hstring *h_search, duk_int_t start_cpos, duk_bool_t backwards) { + duk_int_t cpos; + duk_int_t bpos; + const duk_uint8_t *p_start, *p_end, *p; + const duk_uint8_t *q_start; + duk_int_t q_blen; + duk_uint8_t firstbyte; + duk_uint8_t t; + + cpos = start_cpos; + + /* Empty searchstring always matches; cpos must be clamped here. + * (If q_blen were < 0 due to clamped coercion, it would also be + * caught here.) + */ + q_start = DUK_HSTRING_GET_DATA(h_search); + q_blen = (duk_int_t) DUK_HSTRING_GET_BYTELEN(h_search); + if (q_blen <= 0) { + return cpos; + } + DUK_ASSERT(q_blen > 0); + + bpos = (duk_int_t) duk_heap_strcache_offset_char2byte((duk_hthread *) ctx, h_this, (duk_uint32_t) cpos); + + p_start = DUK_HSTRING_GET_DATA(h_this); + p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_this); + p = p_start + bpos; + + /* This loop is optimized for size. For speed, there should be + * two separate loops, and we should ensure that memcmp() can be + * used without an extra "will searchstring fit" check. Doing + * the preconditioning for 'p' and 'p_end' is easy but cpos + * must be updated if 'p' is wound back (backward scanning). + */ + + firstbyte = q_start[0]; /* leading byte of match string */ + while (p <= p_end && p >= p_start) { + t = *p; + + /* For Ecmascript strings, this check can only match for + * initial UTF-8 bytes (not continuation bytes). For other + * strings all bets are off. + */ + + if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= (duk_size_t) q_blen)) { + DUK_ASSERT(q_blen > 0); /* no issues with memcmp() zero size, even if broken */ + if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { + return cpos; + } + } + + /* track cpos while scanning */ + if (backwards) { + /* when going backwards, we decrement cpos 'early'; + * 'p' may point to a continuation byte of the char + * at offset 'cpos', but that's OK because we'll + * backtrack all the way to the initial byte. + */ + if ((t & 0xc0) != 0x80) { + cpos--; + } + p--; + } else { + if ((t & 0xc0) != 0x80) { + cpos++; + } + p++; + } + } + + /* Not found. Empty string case is handled specially above. */ + return -1; +} + +/* * Constructor */ @@ -36432,7 +37656,7 @@ duk_push_hstring_empty(ctx); } else { h = duk_to_hstring_acceptsymbol(ctx, 0); - if (DUK_HSTRING_HAS_SYMBOL(h) && !duk_is_constructor_call(ctx)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h) && !duk_is_constructor_call(ctx))) { duk_push_symbol_descriptive_string(ctx, h); duk_replace(ctx, 0); } @@ -36444,6 +37668,7 @@ if (duk_is_constructor_call(ctx)) { /* String object internal value is immutable */ flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING); duk_push_object_helper(ctx, flags, DUK_BIDX_STRING_PROTOTYPE); @@ -36593,7 +37818,7 @@ pos = duk_to_int_clamped_raw(ctx, 0 /*index*/, 0 /*min(incl)*/, - DUK_HSTRING_GET_CHARLEN(h) - 1 /*max(incl)*/, + (duk_int_t) DUK_HSTRING_GET_CHARLEN(h) - 1 /*max(incl)*/, &clamped /*out_clamped*/); #if defined(DUK_USE_ES6) magic = duk_get_current_magic(ctx); @@ -36755,17 +37980,10 @@ */ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx) { - duk_hthread *thr = (duk_hthread *) ctx; duk_hstring *h_this; duk_hstring *h_search; duk_int_t clen_this; duk_int_t cpos; - duk_int_t bpos; - const duk_uint8_t *p_start, *p_end, *p; - const duk_uint8_t *q_start; - duk_int_t q_blen; - duk_uint8_t firstbyte; - duk_uint8_t t; duk_small_int_t is_lastindexof = duk_get_current_magic(ctx); /* 0=indexOf, 1=lastIndexOf */ h_this = duk_push_this_coercible_to_string(ctx); @@ -36774,8 +37992,6 @@ h_search = duk_to_hstring(ctx, 0); DUK_ASSERT(h_search != NULL); - q_start = DUK_HSTRING_GET_DATA(h_search); - q_blen = (duk_int_t) DUK_HSTRING_GET_BYTELEN(h_search); duk_to_number(ctx, 1); if (duk_is_nan(ctx, 1) && is_lastindexof) { @@ -36788,67 +38004,8 @@ cpos = duk_to_int_clamped(ctx, 1, 0, clen_this); } - /* Empty searchstring always matches; cpos must be clamped here. - * (If q_blen were < 0 due to clamped coercion, it would also be - * caught here.) - */ - if (q_blen <= 0) { - duk_push_int(ctx, cpos); - return 1; - } - DUK_ASSERT(q_blen > 0); - - bpos = (duk_int_t) duk_heap_strcache_offset_char2byte(thr, h_this, (duk_uint32_t) cpos); - - p_start = DUK_HSTRING_GET_DATA(h_this); - p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_this); - p = p_start + bpos; - - /* This loop is optimized for size. For speed, there should be - * two separate loops, and we should ensure that memcmp() can be - * used without an extra "will searchstring fit" check. Doing - * the preconditioning for 'p' and 'p_end' is easy but cpos - * must be updated if 'p' is wound back (backward scanning). - */ - - firstbyte = q_start[0]; /* leading byte of match string */ - while (p <= p_end && p >= p_start) { - t = *p; - - /* For Ecmascript strings, this check can only match for - * initial UTF-8 bytes (not continuation bytes). For other - * strings all bets are off. - */ - - if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= (duk_size_t) q_blen)) { - DUK_ASSERT(q_blen > 0); /* no issues with memcmp() zero size, even if broken */ - if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { - duk_push_int(ctx, cpos); - return 1; - } - } - - /* track cpos while scanning */ - if (is_lastindexof) { - /* when going backwards, we decrement cpos 'early'; - * 'p' may point to a continuation byte of the char - * at offset 'cpos', but that's OK because we'll - * backtrack all the way to the initial byte. - */ - if ((t & 0xc0) != 0x80) { - cpos--; - } - p--; - } else { - if ((t & 0xc0) != 0x80) { - cpos++; - } - p++; - } - } - - /* Not found. Empty string case is handled specially above. */ - duk_push_int(ctx, -1); + cpos = duk__str_search_shared(ctx, h_this, h_search, cpos, is_lastindexof /*backwards*/); + duk_push_int(ctx, cpos); return 1; } @@ -37145,9 +38302,10 @@ /* Use match charlen instead of bytelen, just in case the input and * match codepoint encodings would have different lengths. */ + /* XXX: charlen computed here, and also in char2byte helper. */ match_end_boff = duk_heap_strcache_offset_char2byte(thr, h_input, - match_start_coff + DUK_HSTRING_GET_CHARLEN(h_match)); + match_start_coff + (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h_match)); tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - match_end_boff); DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + match_end_boff, tmp_sz); @@ -37497,7 +38655,7 @@ DUK_DDD(DUK_DDDPRINT("split trailer; prev_end b=%ld,c=%ld", (long) prev_match_end_boff, (long) prev_match_end_coff)); - if (DUK_HSTRING_GET_CHARLEN(h_input) > 0 || !matched) { + if (DUK_HSTRING_GET_BYTELEN(h_input) > 0 || !matched) { /* Add trailer if: * a) non-empty input * b) empty input and no (zero size) match found (step 11) @@ -37757,10 +38915,10 @@ } else { DUK_MEMCPY((void *) p, (const void *) src, copy_size); p += copy_size; - copy_size *= 2; } src = (const duk_uint8_t *) buf; /* Use buf as source for larger copies. */ + copy_size = (duk_size_t) (p - buf); } #endif /* DUK_USE_PREFER_SIZE */ @@ -37839,6 +38997,93 @@ return 1; } +#if defined(DUK_USE_ES6) +DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_context *ctx) { + duk_int_t magic; + duk_hstring *h; + duk_hstring *h_search; + duk_size_t blen_search; + const duk_uint8_t *p_cmp_start; + duk_bool_t result; + + h = duk_push_this_coercible_to_string(ctx); + DUK_ASSERT(h != NULL); + + h_search = duk__str_tostring_notregexp(ctx, 0); + DUK_ASSERT(h_search != NULL); + + magic = duk_get_current_magic(ctx); + + p_cmp_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h); + blen_search = DUK_HSTRING_GET_BYTELEN(h_search); + + if (duk_is_undefined(ctx, 1)) { + if (magic) { + p_cmp_start += DUK_HSTRING_GET_BYTELEN(h) - blen_search; + } else { + /* p_cmp_start already OK */ + } + } else { + duk_int_t len; + duk_int_t pos; + + DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= DUK_INT_MAX); + len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h); + pos = duk_to_int_clamped(ctx, 1, 0, len); + DUK_ASSERT(pos >= 0 && pos <= len); + + if (magic) { + p_cmp_start -= blen_search; /* Conceptually subtracted last, but do already here. */ + } + DUK_ASSERT(pos >= 0 && pos <= len); + + p_cmp_start += duk_heap_strcache_offset_char2byte((duk_hthread *) ctx, h, pos); + } + + /* The main comparison can be done using a memcmp() rather than + * doing codepoint comparisons: for CESU-8 strings there is a + * canonical representation for every codepoint. But we do need + * to deal with the char/byte offset translation to find the + * comparison range. + */ + + result = 0; + if (p_cmp_start >= DUK_HSTRING_GET_DATA(h) && + p_cmp_start - (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h) + blen_search <= DUK_HSTRING_GET_BYTELEN(h)) { + if (DUK_MEMCMP((const void *) p_cmp_start, + (const void *) DUK_HSTRING_GET_DATA(h_search), + (size_t) blen_search) == 0) { + result = 1; + } + } + + duk_push_boolean(ctx, result); + return 1; +} +#endif /* DUK_USE_ES6 */ + +#if defined(DUK_USE_ES6) +DUK_INTERNAL duk_ret_t duk_bi_string_prototype_includes(duk_context *ctx) { + duk_hstring *h; + duk_hstring *h_search; + duk_int_t len; + duk_int_t pos; + + h = duk_push_this_coercible_to_string(ctx); + DUK_ASSERT(h != NULL); + + h_search = duk__str_tostring_notregexp(ctx, 0); + DUK_ASSERT(h_search != NULL); + + len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h); + pos = duk_to_int_clamped(ctx, 1, 0, len); + DUK_ASSERT(pos >= 0 && pos <= len); + + pos = duk__str_search_shared(ctx, h, h_search, pos, 0 /*backwards*/); + duk_push_boolean(ctx, pos >= 0); + return 1; +} +#endif /* DUK_USE_ES6 */ #endif /* DUK_USE_STRING_BUILTIN */ #line 1 "duk_bi_symbol.c" /* @@ -37947,7 +39192,8 @@ h_str = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h_str != NULL); - if (!DUK_HSTRING_HAS_SYMBOL(h_str)) { + /* Here symbol is more expected than not. */ + if (DUK_UNLIKELY(!DUK_HSTRING_HAS_SYMBOL(h_str))) { return NULL; } @@ -37967,6 +39213,7 @@ duk_push_symbol_descriptive_string(ctx, h_str); } else { /* .valueOf() */ + duk_push_hstring(ctx, h_str); } return 1; } @@ -38094,11 +39341,12 @@ DUK_DD(DUK_DDPRINT("resume state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.resume)")); goto state_error; } - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); /* us */ - DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL); /* caller */ + DUK_ASSERT(thr->callstack_curr != 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 - 1) != NULL); /* caller */ - caller_func = DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2); + caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr - 1); if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) { DUK_DD(DUK_DDPRINT("resume state invalid: caller must be Ecmascript code")); goto state_error; @@ -38248,11 +39496,12 @@ DUK_DD(DUK_DDPRINT("yield state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.yield)")); goto state_error; } - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); /* us */ - DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL); /* caller */ + DUK_ASSERT(thr->callstack_curr != 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 - 1) != NULL); /* caller */ - caller_func = DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2); + caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr - 1); if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) { DUK_DD(DUK_DDPRINT("yield state invalid: caller must be Ecmascript code")); goto state_error; @@ -38830,6 +40079,9 @@ } } if (st->internal) { + if (DUK_HOBJECT_IS_ARRAY(h)) { + DUK__COMMA(); duk_fb_sprintf(fb, "__array:true"); + } if (DUK_HOBJECT_HAS_EXTENSIBLE(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__extensible:true"); } @@ -38848,7 +40100,7 @@ if (DUK_HOBJECT_HAS_BUFOBJ(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__bufobj:true"); } - if (DUK_HOBJECT_HAS_THREAD(h)) { + if (DUK_HOBJECT_IS_THREAD(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__thread:true"); } if (DUK_HOBJECT_HAS_ARRAY_PART(h)) { @@ -38869,9 +40121,6 @@ if (DUK_HOBJECT_HAS_CREATEARGS(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__createargs:true"); } - if (DUK_HOBJECT_HAS_ENVRECCLOSED(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__envrecclosed:true"); - } if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_array:true"); } @@ -38916,6 +40165,15 @@ duk_fb_put_funcptr(fb, (duk_uint8_t *) &f->func, sizeof(f->func)); DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld", (long) f->nargs); DUK__COMMA(); duk_fb_sprintf(fb, "__magic:%ld", (long) f->magic); + } else if (st->internal && DUK_HOBJECT_IS_DECENV(h)) { + duk_hdecenv *e = (duk_hdecenv *) h; + DUK__COMMA(); duk_fb_sprintf(fb, "__thread:"); duk__print_hobject(st, (duk_hobject *) e->thread); + DUK__COMMA(); duk_fb_sprintf(fb, "__varmap:"); duk__print_hobject(st, (duk_hobject *) e->varmap); + DUK__COMMA(); duk_fb_sprintf(fb, "__regbase:%ld", (long) e->regbase); + } else if (st->internal && DUK_HOBJECT_IS_OBJENV(h)) { + duk_hobjenv *e = (duk_hobjenv *) h; + DUK__COMMA(); duk_fb_sprintf(fb, "__target:"); duk__print_hobject(st, (duk_hobject *) e->target); + DUK__COMMA(); duk_fb_sprintf(fb, "__has_this:%ld", (long) e->has_this); #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) } else if (st->internal && DUK_HOBJECT_IS_BUFOBJ(h)) { duk_hbufobj *b = (duk_hbufobj *) h; @@ -39149,6 +40407,10 @@ } #if defined(DUK_USE_FASTINT) case DUK_TAG_FASTINT: + DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); + DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + duk_fb_sprintf(fb, "%.18gF", (double) DUK_TVAL_GET_NUMBER(tv)); + break; #endif default: { /* IEEE double is approximately 16 decimal digits; print a couple extra */ @@ -39242,7 +40504,7 @@ if (ch == DUK_ASC_STAR) { /* unsupported: would consume multiple args */ - goto error; + goto format_error; } else if (ch == DUK_ASC_PERCENT) { duk_fb_put_byte(&fb, (duk_uint8_t) DUK_ASC_PERCENT); break; @@ -39294,7 +40556,7 @@ fmtlen = (duk_size_t) (p - p_begfmt); if (fmtlen >= sizeof(fmtbuf)) { /* format is too large, abort */ - goto error; + goto format_error; } DUK_MEMZERO(fmtbuf, sizeof(fmtbuf)); DUK_MEMCPY(fmtbuf, p_begfmt, fmtlen); @@ -39369,7 +40631,7 @@ } goto done; - error: + format_error: duk_fb_put_cstring(&fb, "FMTERR"); /* fall through */ @@ -39498,7 +40760,6 @@ /* heap->dbg_detached_cb: keep */ /* heap->dbg_udata: keep */ /* heap->dbg_processing: keep on purpose to avoid debugger re-entry in detaching state */ - DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap); heap->dbg_state_dirty = 0; heap->dbg_force_restart = 0; heap->dbg_step_type = 0; @@ -39506,6 +40767,8 @@ heap->dbg_step_csindex = 0; heap->dbg_step_startline = 0; heap->dbg_have_next_byte = 0; + duk_debug_clear_paused(heap); /* XXX: some overlap with field inits above */ + heap->dbg_state_dirty = 0; /* XXX: clear_paused sets dirty; rework? */ /* Ensure there are no stale active breakpoint pointers. * Breakpoint list is currently kept - we could empty it @@ -39524,7 +40787,10 @@ duk_context *ctx; thr = heap->heap_thread; - DUK_ASSERT(thr != NULL); + if (thr == NULL) { + DUK_ASSERT(heap->dbg_detached_cb == NULL); + return; + } ctx = (duk_context *) thr; /* Safe to call multiple times. */ @@ -39558,6 +40824,9 @@ */ DUK_LOCAL void duk__debug_null_most_callbacks(duk_hthread *thr) { duk_heap *heap; + + DUK_ASSERT(thr != NULL); + heap = thr->heap; DUK_D(DUK_DPRINT("transport read/write error, NULL all callbacks expected detached")); heap->dbg_read_cb = NULL; @@ -40405,7 +41674,7 @@ duk_uint_fast32_t line; duk_uint_fast32_t pc; - act = duk_hthread_get_current_activation(thr); /* may be NULL */ + act = thr->callstack_curr; if (act == NULL) { return 0; } @@ -40436,13 +41705,13 @@ duk_debug_write_int(thr, (DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) ? 1 : 0)); DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* unsigned */ - if (thr->callstack_top == 0) { + act = thr->callstack_curr; + if (act == NULL) { duk_debug_write_undefined(thr); duk_debug_write_undefined(thr); duk_debug_write_int(thr, 0); duk_debug_write_int(thr, 0); } else { - act = thr->callstack + thr->callstack_top - 1; duk_push_tval(ctx, &act->tv_func); duk_get_prop_string(ctx, -1, "fileName"); duk__debug_write_hstring_safe_top(thr); @@ -40451,6 +41720,7 @@ duk_pop_3(ctx); /* Report next pc/line to be executed. */ duk_debug_write_uint(thr, (duk_uint32_t) duk_debug_curr_line(thr)); + act = thr->callstack_curr; duk_debug_write_uint(thr, (duk_uint32_t) duk_hthread_get_act_curr_pc(thr, act)); } @@ -40483,18 +41753,29 @@ duk__debug_write_hstring_safe_top(thr); duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_LINE_NUMBER); duk_debug_write_uint(thr, duk_get_uint(ctx, -1)); + duk_pop_2(ctx); } else { - /* For anything other than an Error instance, we calculate the error - * location directly from the current activation. - */ - act = thr->callstack + thr->callstack_top - 1; - duk_push_tval(ctx, &act->tv_func); - duk_get_prop_string(ctx, -1, "fileName"); - duk__debug_write_hstring_safe_top(thr); - pc = duk_hthread_get_act_prev_pc(thr, act); - duk_debug_write_uint(thr, (duk_uint32_t) duk_hobject_pc2line_query(ctx, -2, pc)); + /* For anything other than an Error instance, we calculate the + * error location directly from the current activation if one + * exists. + */ + act = thr->callstack_curr; + if (act != NULL) { + duk_push_tval(ctx, &act->tv_func); + duk_get_prop_string(ctx, -1, "fileName"); + duk__debug_write_hstring_safe_top(thr); + act = thr->callstack_curr; + pc = duk_hthread_get_act_prev_pc(thr, act); + duk_debug_write_uint(thr, (duk_uint32_t) duk_hobject_pc2line_query(ctx, -2, pc)); + duk_pop_2(ctx); + } else { + /* Can happen if duk_throw() is called on an empty + * callstack. + */ + duk_debug_write_cstring(thr, ""); + duk_debug_write_uint(thr, 0); + } } - duk_pop_2(ctx); /* shared pop */ duk_debug_write_eom(thr); } @@ -40634,7 +41915,11 @@ DUK_LOCAL void duk__debug_handle_pause(duk_hthread *thr, duk_heap *heap) { DUK_D(DUK_DPRINT("debug command Pause")); - DUK_HEAP_SET_PAUSED(heap); + if (duk_debug_is_paused(heap)) { + DUK_D(DUK_DPRINT("Pause requested when already paused, ignore")); + } else { + duk_debug_set_paused(heap); + } duk_debug_write_reply(thr); duk_debug_write_eom(thr); } @@ -40642,7 +41927,7 @@ DUK_LOCAL void duk__debug_handle_resume(duk_hthread *thr, duk_heap *heap) { DUK_D(DUK_DPRINT("debug command Resume")); - DUK_HEAP_CLEAR_PAUSED(heap); + duk_debug_clear_paused(heap); duk_debug_write_reply(thr); duk_debug_write_eom(thr); } @@ -40664,7 +41949,7 @@ line = duk_debug_curr_line(thr); if (line > 0) { - DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap); + duk_debug_clear_paused(heap); /* XXX: overlap with fields below; separate macro/helper? */ heap->dbg_step_type = step_type; heap->dbg_step_thread = thr; heap->dbg_step_csindex = thr->callstack_top - 1; @@ -40926,6 +42211,7 @@ /* Read callstack index, if non-null. */ if (duk_debug_peek_byte(thr) == DUK_DBG_IB_NULL) { direct_eval = 0; + level = -1; /* Not needed, but silences warning. */ (void) duk_debug_read_byte(thr); } else { direct_eval = 1; @@ -41168,82 +42454,29 @@ } } -#if defined(DUK_USE_STRTAB_CHAIN) -DUK_LOCAL void duk__debug_dump_strtab_chain(duk_hthread *thr, duk_heap *heap) { - duk_uint_fast32_t i, j; - duk_strtab_entry *e; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t *lst; -#else - duk_hstring **lst; -#endif - duk_hstring *h; - - for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { - e = heap->strtable + i; - if (e->listlen > 0) { -#if defined(DUK_USE_HEAPPTR16) - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); -#else - lst = e->u.strlist; -#endif - DUK_ASSERT(lst != NULL); - - for (j = 0; j < e->listlen; j++) { -#if defined(DUK_USE_HEAPPTR16) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[j]); -#else - h = lst[j]; -#endif - if (h != NULL) { - duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h); - } - } - } else { -#if defined(DUK_USE_HEAPPTR16) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16); -#else - h = e->u.str; -#endif - if (h != NULL) { - duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h); - } - } - } -} -#endif /* DUK_USE_STRTAB_CHAIN */ - -#if defined(DUK_USE_STRTAB_PROBE) -DUK_LOCAL void duk__debug_dump_strtab_probe(duk_hthread *thr, duk_heap *heap) { +DUK_LOCAL void duk__debug_dump_strtab(duk_hthread *thr, duk_heap *heap) { duk_uint32_t i; duk_hstring *h; for (i = 0; i < heap->st_size; i++) { -#if defined(DUK_USE_HEAPPTR16) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); +#if defined(DUK_USE_STRTAB_PTRCOMP) + h = DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, heap->strtable16[i]); #else h = heap->strtable[i]; #endif - if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) { - continue; + while (h != NULL) { + duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h); + h = h->hdr.h_next; } - - duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h); } } -#endif /* DUK_USE_STRTAB_PROBE */ DUK_LOCAL void duk__debug_handle_dump_heap(duk_hthread *thr, duk_heap *heap) { DUK_D(DUK_DPRINT("debug command DumpHeap")); duk_debug_write_reply(thr); duk__debug_dump_heap_allocated(thr, heap); -#if defined(DUK_USE_STRTAB_CHAIN) - duk__debug_dump_strtab_chain(thr, heap); -#endif -#if defined(DUK_USE_STRTAB_PROBE) - duk__debug_dump_strtab_probe(thr, heap); -#endif + duk__debug_dump_strtab(thr, heap); duk_debug_write_eom(thr); } #endif /* DUK_USE_DEBUGGER_DUMPHEAP */ @@ -41381,14 +42614,14 @@ "compfunc", "natfunc", "bufobj", - "thread", + "fastrefs", "array_part", "strict", "notail", "newenv", "namebinding", "createargs", - "envrecclosed", + "have_finalizer", "exotic_array", "exotic_stringobj", "exotic_arguments", @@ -41403,14 +42636,14 @@ DUK_HOBJECT_FLAG_COMPFUNC, DUK_HOBJECT_FLAG_NATFUNC, DUK_HOBJECT_FLAG_BUFOBJ, - DUK_HOBJECT_FLAG_THREAD, + DUK_HOBJECT_FLAG_FASTREFS, DUK_HOBJECT_FLAG_ARRAY_PART, DUK_HOBJECT_FLAG_STRICT, DUK_HOBJECT_FLAG_NOTAIL, DUK_HOBJECT_FLAG_NEWENV, DUK_HOBJECT_FLAG_NAMEBINDING, DUK_HOBJECT_FLAG_CREATEARGS, - DUK_HOBJECT_FLAG_ENVRECCLOSED, + DUK_HOBJECT_FLAG_HAVE_FINALIZER, DUK_HOBJECT_FLAG_EXOTIC_ARRAY, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS, @@ -41458,7 +42691,7 @@ for (;;) { mask = *masks++; - if (!mask) { + if (mask == 0) { break; } key = *keys++; @@ -41540,6 +42773,10 @@ DUK_D(DUK_DPRINT("debug command GetHeapObjInfo")); DUK_UNREF(heap); + DUK_ASSERT(sizeof(duk__debug_getinfo_hstring_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hstring_masks) / sizeof(duk_uint_t) - 1); + DUK_ASSERT(sizeof(duk__debug_getinfo_hobject_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hobject_masks) / sizeof(duk_uint_t) - 1); + DUK_ASSERT(sizeof(duk__debug_getinfo_hbuffer_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hbuffer_masks) / sizeof(duk_uint_t) - 1); + h = duk_debug_read_any_ptr(thr); if (!h) { duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid target"); @@ -41578,9 +42815,9 @@ duk__debug_getinfo_hstring_keys, duk__debug_getinfo_hstring_masks, DUK_HEAPHDR_GET_FLAGS_RAW(h)); - duk__debug_getinfo_prop_uint(thr, "bytelen", DUK_HSTRING_GET_BYTELEN(h_str)); - duk__debug_getinfo_prop_uint(thr, "charlen", DUK_HSTRING_GET_CHARLEN(h_str)); - duk__debug_getinfo_prop_uint(thr, "hash", DUK_HSTRING_GET_HASH(h_str)); + duk__debug_getinfo_prop_uint(thr, "bytelen", (duk_uint_t) DUK_HSTRING_GET_BYTELEN(h_str)); + duk__debug_getinfo_prop_uint(thr, "charlen", (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h_str)); + duk__debug_getinfo_prop_uint(thr, "hash", (duk_uint_t) DUK_HSTRING_GET_HASH(h_str)); duk__debug_getinfo_flags_key(thr, "data"); duk_debug_write_hstring(thr, h_str); break; @@ -41678,6 +42915,26 @@ DUK_UNREF(h_thr); } + if (DUK_HOBJECT_IS_DECENV(h_obj)) { + duk_hdecenv *h_env; + h_env = (duk_hdecenv *) h_obj; + + duk__debug_getinfo_flags_key(thr, "thread"); + duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->thread)); + duk__debug_getinfo_flags_key(thr, "varmap"); + duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->varmap)); + duk__debug_getinfo_prop_uint(thr, "regbase", (duk_uint_t) h_env->regbase); + } + + if (DUK_HOBJECT_IS_OBJENV(h_obj)) { + duk_hobjenv *h_env; + h_env = (duk_hobjenv *) h_obj; + + duk__debug_getinfo_flags_key(thr, "target"); + duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->target)); + duk__debug_getinfo_prop_bool(thr, "has_this", h_env->has_this); + } + #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) { duk_hbufobj *h_bufobj; @@ -42100,12 +43357,13 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)); + DUK_ASSERT(duk_debug_is_attached(thr->heap)); DUK_ASSERT(thr->heap->dbg_processing == 0); + DUK_ASSERT(!duk_debug_is_paused(thr->heap)); - DUK_HEAP_SET_PAUSED(thr->heap); + duk_debug_set_paused(thr->heap); - act = duk_hthread_get_current_activation(thr); + act = thr->callstack_curr; /* NOTE: act may be NULL if an error is thrown outside of any activation, * which may happen in the case of, e.g. syntax errors. @@ -42138,8 +43396,8 @@ thr->heap->dbg_state_dirty = 1; while (DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap)) { - DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)); - DUK_ASSERT(thr->heap->dbg_processing); + DUK_ASSERT(duk_debug_is_attached(thr->heap)); + DUK_ASSERT(thr->heap->dbg_processing == 0); duk_debug_process_messages(thr, 0 /*no_block*/); } @@ -42201,7 +43459,7 @@ DUK_ASSERT(thr != NULL); heap = thr->heap; DUK_ASSERT(heap != NULL); - DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)); + DUK_ASSERT(duk_debug_is_attached(thr->heap)); DUK_ASSERT_DISABLE(breakpoint_index >= 0); /* unsigned */ if (breakpoint_index >= heap->dbg_breakpoint_count) { @@ -42230,6 +43488,55 @@ return 1; } +/* + * Misc state management + */ + +DUK_INTERNAL duk_bool_t duk_debug_is_attached(duk_heap *heap) { + return (heap->dbg_read_cb != NULL); +} + +DUK_INTERNAL duk_bool_t duk_debug_is_paused(duk_heap *heap) { + return (DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) != 0); +} + +DUK_INTERNAL void duk_debug_set_paused(duk_heap *heap) { + if (duk_debug_is_paused(heap)) { + DUK_D(DUK_DPRINT("trying to set paused state when already paused, ignoring")); + } else { + DUK_HEAP_SET_DEBUGGER_PAUSED(heap); + heap->dbg_state_dirty = 1; + duk_debug_clear_step_state(heap); + DUK_ASSERT(heap->ms_running == 0); /* debugger can't be triggered within mark-and-sweep */ + heap->ms_running = 1; /* prevent mark-and-sweep, prevent refzero queueing */ + heap->ms_prevent_count++; + DUK_ASSERT(heap->ms_prevent_count != 0); /* Wrap. */ + DUK_ASSERT(heap->heap_thread != NULL); + } +} + +DUK_INTERNAL void duk_debug_clear_paused(duk_heap *heap) { + if (duk_debug_is_paused(heap)) { + DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap); + heap->dbg_state_dirty = 1; + duk_debug_clear_step_state(heap); + DUK_ASSERT(heap->ms_running == 1); + DUK_ASSERT(heap->ms_prevent_count > 0); + heap->ms_prevent_count--; + heap->ms_running = 0; + DUK_ASSERT(heap->heap_thread != NULL); + } else { + DUK_D(DUK_DPRINT("trying to clear paused state when not paused, ignoring")); + } +} + +DUK_INTERNAL void duk_debug_clear_step_state(duk_heap *heap) { + heap->dbg_step_type = DUK_STEP_TYPE_NONE; + heap->dbg_step_thread = NULL; + heap->dbg_step_csindex = 0; + heap->dbg_step_startline = 0; +} + #else /* DUK_USE_DEBUGGER_SUPPORT */ /* No debugger support. */ @@ -42869,18 +44176,37 @@ 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)); - /* Perform a refzero check before throwing: this catches cases where - * some internal code uses no-refzero (NORZ) macro variants but an - * error occurs before it has the chance to DUK_REFZERO_CHECK_xxx() - * explicitly. Refzero'ed objects would otherwise remain pending - * until the next refzero (which is not a big issue but still). + /* 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_REFZERO_CHECK_SLOW(thr); + + 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 !defined(DUK_USE_CPP_EXCEPTIONS) /* If we don't have a jmpbuf_ptr, there is little we can do except @@ -42980,11 +44306,16 @@ } /* - * Exposed helper for setting up heap longjmp state. + * Helper for debugger throw notify and pause-on-uncaught integration. */ -DUK_INTERNAL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t lj_type) { #if defined(DUK_USE_DEBUGGER_SUPPORT) +#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) +DUK_INTERNAL void duk_err_check_debugger_integration(duk_hthread *thr) { + duk_context *ctx = (duk_context *) thr; + duk_bool_t fatal; + 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 @@ -42992,55 +44323,102 @@ * 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 defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap) && - !thr->heap->dbg_processing && - lj_type == DUK_LJ_TYPE_THROW) { - duk_context *ctx = (duk_context *) thr; - duk_bool_t fatal; - duk_hobject *h_obj; - /* 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. - */ - h_obj = duk_get_hobject(ctx, -1); - if (h_obj == thr->builtins[DUK_BIDX_DOUBLE_ERROR]) { - DUK_D(DUK_DPRINT("built-in DoubleError instance thrown, not intercepting")); - goto skip_throw_intercept; - } + 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; + } + + fatal = !duk__have_active_catcher(thr); - DUK_D(DUK_DPRINT("throw with debugger attached, report to client")); + /* 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(ctx, tv_obj); - fatal = !duk__have_active_catcher(thr); + /* 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_debug_send_throw(thr, fatal); + /* Report it to the debug client */ + DUK_D(DUK_DPRINT("throw with debugger attached, report to client")); + duk_debug_send_throw(thr, fatal); #endif #if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) - if (fatal) { - DUK_D(DUK_DPRINT("throw will be fatal, halt before longjmp")); - duk_debug_halt_execution(thr, 1 /*use_prev_pc*/); - } -#endif + if (fatal) { + DUK_D(DUK_DPRINT("throw will be fatal, halt before longjmp")); + duk_debug_halt_execution(thr, 1 /*use_prev_pc*/); } +#endif - skip_throw_intercept: + /* Restore longjmp state. */ + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + thr->heap->lj.type = DUK_LJ_TYPE_THROW; + tv_obj = DUK_GET_TVAL_NEGIDX(ctx, -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(ctx); +} +#else /* DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT */ +DUK_INTERNAL void duk_err_check_debugger_integration(duk_hthread *thr) { + DUK_UNREF(thr); +} #endif /* DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT */ #endif /* DUK_USE_DEBUGGER_SUPPORT */ - thr->heap->lj.type = lj_type; +/* + * Helpers for setting up heap longjmp state. + */ - DUK_ASSERT(thr->valstack_top > thr->valstack); - DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, thr->valstack_top - 1); /* side effects */ +DUK_INTERNAL void duk_err_setup_ljstate1(duk_hthread *thr, duk_small_uint_t lj_type, duk_tval *tv_val) { + duk_heap *heap; - duk_pop((duk_context *) thr); + 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); } #line 1 "duk_error_throw.c" /* @@ -43061,7 +44439,7 @@ * * 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->handling_error flag; the recursion + * "double fault" through the heap->creating_error flag; the recursion * then stops at the second level. */ @@ -43071,7 +44449,6 @@ DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code) { #endif duk_context *ctx = (duk_context *) thr; - duk_bool_t double_error = thr->heap->handling_error; #if defined(DUK_USE_VERBOSE_ERRORS) DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld, msg=%s, filename=%s, line=%ld", @@ -43084,18 +44461,11 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT(ctx != NULL); - thr->heap->handling_error = 1; - - if (!double_error) { - /* Allow headroom for calls during error handling (see GH-191). - * We allow space for 10 additional recursions, with one extra - * for, e.g. a print() call at the deepest level. - */ - DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX); - thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11; - } - - DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11); /* just making sure */ + /* 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 @@ -43105,29 +44475,50 @@ /* * 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. */ - /* XXX: if attempt to push beyond allocated valstack, this double fault - * handling fails miserably. We should really write the double error - * directly to thr->heap->lj.value1 and avoid valstack use entirely. - */ - - if (double_error) { - if (thr->builtins[DUK_BIDX_DOUBLE_ERROR]) { - DUK_D(DUK_DPRINT("double fault detected -> push built-in fixed 'double error' instance")); - duk_push_hobject_bidx(ctx, DUK_BIDX_DOUBLE_ERROR); + if (thr->heap->creating_error) { + duk_tval tv_val; + duk_hobject *h_err; + +#if 0 /* XXX: not always true because the second throw may come from a different coroutine */ + DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11); +#endif + thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX; + 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 " - "-> push the error code as a number")); - duk_push_int(ctx, (duk_int_t) code); + "-> 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 { - /* Error object is augmented at its creation here. */ + /* Allow headroom for calls during error handling (see GH-191). + * We allow space for 10 additional recursions, with one extra + * for, e.g. a print() call at the deepest level. + */ +#if 0 /* XXX: not always true, second throw may come from a different coroutine */ + DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX); +#endif + thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11; + thr->heap->creating_error = 1; + duk_require_stack(ctx, 1); - /* XXX: unnecessary '%s' formatting here, but cannot use - * 'msg' as a format string directly. + + /* 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(ctx, @@ -43143,37 +44534,38 @@ 0, NULL); #endif - } - - /* - * Augment error (throw time), unless double error - * - * 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 (double_error) { - DUK_D(DUK_DPRINT("double error: skip throw augmenting to avoid further trouble")); - } else { + /* 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(ctx, -1))); duk_err_augment_error_throw(thr); #endif + + duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(ctx, -1)); + thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX; + 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_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW); - - thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX; /* reset callstack limit */ - thr->heap->handling_error = 0; - DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT, %!iT (after throw augment)", (duk_tval *) &thr->heap->lj.value1, (duk_tval *) &thr->heap->lj.value2)); @@ -43248,8 +44640,8 @@ } res = (duk_hbuffer *) DUK_ALLOC(heap, alloc_size); - if (!res) { - goto error; + if (DUK_UNLIKELY(res == NULL)) { + goto alloc_error; } /* zero everything unless requested not to do so */ @@ -43285,9 +44677,9 @@ #else ptr = DUK_ALLOC(heap, size); #endif - if (!ptr) { + if (DUK_UNLIKELY(ptr == NULL)) { /* Because size > 0, NULL check is correct */ - goto error; + goto alloc_error; } *out_bufdata = ptr; @@ -43323,7 +44715,7 @@ DUK_DDD(DUK_DDDPRINT("allocated hbuffer: %p", (void *) res)); return res; - error: + alloc_error: DUK_DD(DUK_DDPRINT("hbuffer allocation failed")); DUK_FREE(heap, res); @@ -43379,7 +44771,7 @@ */ res = DUK_REALLOC_INDIRECT(thr->heap, duk_hbuffer_get_dynalloc_ptr, (void *) buf, new_size); - if (res != NULL || new_size == 0) { + 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", @@ -43536,11 +44928,9 @@ case DUK_HTYPE_OBJECT: duk_free_hobject(heap, (duk_hobject *) hdr); break; - case DUK_HTYPE_BUFFER: - duk_free_hbuffer(heap, (duk_hbuffer *) hdr); - break; default: - DUK_UNREACHABLE(); + DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) == DUK_HTYPE_BUFFER); + duk_free_hbuffer(heap, (duk_hbuffer *) hdr); } } @@ -43576,23 +44966,8 @@ } } -#if defined(DUK_USE_REFERENCE_COUNTING) -DUK_LOCAL void duk__free_refzero_list(duk_heap *heap) { - duk_heaphdr *curr; - duk_heaphdr *next; - - curr = heap->refzero_list; - while (curr) { - DUK_DDD(DUK_DDDPRINT("FINALFREE (refzero_list): %!iO", - (duk_heaphdr *) curr)); - next = DUK_HEAPHDR_GET_NEXT(heap, curr); - duk_heap_free_heaphdr_raw(heap, curr); - curr = next; - } -} -#endif - -DUK_LOCAL void duk__free_markandsweep_finalize_list(duk_heap *heap) { +#if defined(DUK_USE_FINALIZER_SUPPORT) +DUK_LOCAL void duk__free_finalize_list(duk_heap *heap) { duk_heaphdr *curr; duk_heaphdr *next; @@ -43605,15 +44980,15 @@ curr = next; } } +#endif /* DUK_USE_FINALIZER_SUPPORT */ DUK_LOCAL void duk__free_stringtable(duk_heap *heap) { /* strings are only tracked by stringtable */ - duk_heap_free_strtab(heap); + duk_heap_strtable_free(heap); } #if defined(DUK_USE_FINALIZER_SUPPORT) DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) { - duk_hthread *thr; duk_heaphdr *curr; duk_uint_t round_no; duk_size_t count_all; @@ -43621,25 +44996,31 @@ duk_size_t curr_limit; DUK_ASSERT(heap != NULL); - DUK_ASSERT(heap->heap_thread != NULL); #if defined(DUK_USE_REFERENCE_COUNTING) DUK_ASSERT(heap->refzero_list == NULL); /* refzero not running -> must be empty */ #endif - DUK_ASSERT(heap->finalize_list == NULL); /* mark-and-sweep not running -> must be empty */ + DUK_ASSERT(heap->finalize_list == NULL); /* mark-and-sweep last pass */ - /* XXX: here again finalizer thread is the heap_thread which needs - * to be coordinated with finalizer thread fixes. - */ - thr = heap->heap_thread; - DUK_ASSERT(thr != NULL); + if (heap->heap_thread == NULL) { + /* May happen when heap allocation fails right off. There + * cannot be any finalizable objects in this case. + */ + DUK_D(DUK_DPRINT("no heap_thread in heap destruct, assume no finalizable objects")); + return; + } - /* Prevent mark-and-sweep for the pending finalizers, also prevents - * refzero handling from moving objects away from the heap_allocated - * list. (The flag meaning is slightly abused here.) - */ - DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)); - DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap); + /* Prevent finalize_list processing and mark-and-sweep entirely. + * Setting ms_running = 1 also prevents refzero handling from moving + * objects away from the heap_allocated list (the flag name is a bit + * misleading here). + */ + DUK_ASSERT(heap->pf_prevent_count == 0); + heap->pf_prevent_count = 1; + DUK_ASSERT(heap->ms_running == 0); + heap->ms_running = 1; + DUK_ASSERT(heap->ms_prevent_count == 0); + heap->ms_prevent_count = 1; /* Bump, because mark-and-sweep assumes it's bumped when ms_running is set. */ curr_limit = 0; /* suppress warning, not used */ for (round_no = 0; ; round_no++) { @@ -43648,18 +45029,17 @@ count_finalized = 0; while (curr) { count_all++; - if (DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT) { + if (DUK_HEAPHDR_IS_OBJECT(curr)) { /* Only objects in heap_allocated may have finalizers. Check that * the object itself has a _Finalizer property (own or inherited) * so that we don't execute finalizers for e.g. Proxy objects. */ - DUK_ASSERT(thr != NULL); DUK_ASSERT(curr != NULL); - if (duk_hobject_hasprop_raw(thr, (duk_hobject *) curr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) { + if (DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) curr)) { if (!DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) curr)) { DUK_ASSERT(DUK_HEAP_HAS_FINALIZER_NORESCUE(heap)); /* maps to finalizer 2nd argument */ - duk_hobject_run_finalizer(thr, (duk_hobject *) curr); + duk_heap_run_finalizer(heap, (duk_hobject *) curr); count_finalized++; } } @@ -43700,8 +45080,10 @@ } } - DUK_ASSERT(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)); - DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap); + DUK_ASSERT(heap->ms_running == 1); + heap->ms_running = 0; + DUK_ASSERT(heap->pf_prevent_count == 1); + heap->pf_prevent_count = 0; } #endif /* DUK_USE_FINALIZER_SUPPORT */ @@ -43709,7 +45091,7 @@ DUK_D(DUK_DPRINT("free heap: %p", (void *) heap)); #if defined(DUK_USE_DEBUG) - duk_heap_dump_strtab(heap); + duk_heap_strtable_dump(heap); #endif #if defined(DUK_USE_DEBUGGER_SUPPORT) @@ -43723,32 +45105,47 @@ #endif /* Execute finalizers before freeing the heap, even for reachable - * objects, and regardless of whether or not mark-and-sweep is - * enabled. This gives finalizers the chance to free any native + * objects. This gives finalizers the chance to free any native * resources like file handles, allocations made outside Duktape, * etc. This is quite tricky to get right, so that all finalizer * guarantees are honored. * - * XXX: this perhaps requires an execution time limit. - */ - DUK_D(DUK_DPRINT("execute finalizers before freeing heap")); - /* Run mark-and-sweep a few times just in case (unreachable object + * Run mark-and-sweep a few times just in case (unreachable object * finalizers run already here). The last round must rescue objects * from the previous round without running any more finalizers. This * ensures rescued objects get their FINALIZED flag cleared so that * their finalizer is called once more in forced finalization to * satisfy finalizer guarantees. However, we don't want to run any - * more finalizer because that'd required one more loop, and so on. + * more finalizers because that'd required one more loop, and so on. + * + * XXX: this perhaps requires an execution time limit. */ + DUK_D(DUK_DPRINT("execute finalizers before freeing heap")); + DUK_ASSERT(heap->pf_skip_finalizers == 0); DUK_D(DUK_DPRINT("forced gc #1 in heap destruction")); duk_heap_mark_and_sweep(heap, 0); DUK_D(DUK_DPRINT("forced gc #2 in heap destruction")); duk_heap_mark_and_sweep(heap, 0); DUK_D(DUK_DPRINT("forced gc #3 in heap destruction (don't run finalizers)")); - duk_heap_mark_and_sweep(heap, DUK_MS_FLAG_SKIP_FINALIZERS); /* skip finalizers; queue finalizable objects to heap_allocated */ + heap->pf_skip_finalizers = 1; + duk_heap_mark_and_sweep(heap, 0); /* Skip finalizers; queue finalizable objects to heap_allocated. */ + + /* There are never objects in refzero_list at this point, or at any + * point beyond a DECREF (even a DECREF_NORZ). Since Duktape 2.1 + * refzero_list processing is side effect free, so it is always + * processed to completion by a DECREF initially triggering a zero + * refcount. + */ +#if defined(DUK_USE_REFERENCE_COUNTING) + DUK_ASSERT(heap->refzero_list == NULL); /* Always processed to completion inline. */ +#endif +#if defined(DUK_USE_FINALIZER_SUPPORT) + DUK_ASSERT(heap->finalize_list == NULL); /* Last mark-and-sweep with skip_finalizers. */ +#endif #if defined(DUK_USE_FINALIZER_SUPPORT) - DUK_HEAP_SET_FINALIZER_NORESCUE(heap); /* rescue no longer supported */ + DUK_D(DUK_DPRINT("run finalizers for remaining finalizable objects")); + DUK_HEAP_SET_FINALIZER_NORESCUE(heap); /* Rescue no longer supported. */ duk__free_run_finalizers(heap); #endif /* DUK_USE_FINALIZER_SUPPORT */ @@ -43756,17 +45153,18 @@ * are on the heap allocated list. */ - DUK_D(DUK_DPRINT("freeing heap objects of heap: %p", (void *) heap)); + DUK_D(DUK_DPRINT("freeing heap_allocated of heap: %p", (void *) heap)); duk__free_allocated(heap); #if defined(DUK_USE_REFERENCE_COUNTING) - DUK_D(DUK_DPRINT("freeing refzero list of heap: %p", (void *) heap)); - duk__free_refzero_list(heap); + DUK_ASSERT(heap->refzero_list == NULL); /* Always processed to completion inline. */ +#endif + +#if defined(DUK_USE_FINALIZER_SUPPORT) + DUK_D(DUK_DPRINT("freeing finalize_list of heap: %p", (void *) heap)); + duk__free_finalize_list(heap); #endif - DUK_D(DUK_DPRINT("freeing mark-and-sweep finalize list of heap: %p", (void *) heap)); - duk__free_markandsweep_finalize_list(heap); - DUK_D(DUK_DPRINT("freeing string table of heap: %p", (void *) heap)); duk__free_stringtable(heap); @@ -43787,20 +45185,26 @@ duk_small_uint_t i; #endif + DUK_UNREF(heap); + /* With ROM-based strings, heap->strs[] and thr->strs[] are omitted * so nothing to initialize for strs[]. */ #if defined(DUK_USE_ASSERTIONS) - for (i = 0; i < sizeof(duk_rom_strings) / sizeof(const duk_hstring *); i++) { - duk_uint32_t hash; + for (i = 0; i < sizeof(duk_rom_strings_lookup) / sizeof(const duk_hstring *); i++) { const duk_hstring *h; - h = duk_rom_strings[i]; - DUK_ASSERT(h != NULL); - hash = duk_heap_hashstring(heap, (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); - DUK_DD(DUK_DDPRINT("duk_rom_strings[%d] -> hash 0x%08lx, computed 0x%08lx", - (int) i, (unsigned long) DUK_HSTRING_GET_HASH(h), (unsigned long) hash)); - DUK_ASSERT(hash == (duk_uint32_t) DUK_HSTRING_GET_HASH(h)); + duk_uint32_t hash; + + h = duk_rom_strings_lookup[i]; + while (h != NULL) { + hash = duk_heap_hashstring(heap, (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); + DUK_DD(DUK_DDPRINT("duk_rom_strings_lookup[%d] -> hash 0x%08lx, computed 0x%08lx", + (int) i, (unsigned long) DUK_HSTRING_GET_HASH(h), (unsigned long) hash)); + DUK_ASSERT(hash == (duk_uint32_t) DUK_HSTRING_GET_HASH(h)); + + h = (const duk_hstring *) h->hdr.h_next; + } } #endif return 1; @@ -43828,9 +45232,9 @@ */ DUK_ASSERT(len <= 0xffffUL); DUK_DDD(DUK_DDDPRINT("intern built-in string %ld", (long) i)); - h = duk_heap_string_intern(heap, tmp, len); + h = duk_heap_strtable_intern(heap, tmp, len); if (!h) { - goto error; + goto failed; } DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)); @@ -43865,7 +45269,7 @@ return 1; - error: + failed: return 0; } #endif /* DUK_USE_ROM_STRINGS */ @@ -43873,12 +45277,11 @@ DUK_LOCAL duk_bool_t duk__init_heap_thread(duk_heap *heap) { duk_hthread *thr; - DUK_DD(DUK_DDPRINT("heap init: alloc heap thread")); - thr = duk_hthread_alloc(heap, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_THREAD | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD)); - if (!thr) { + DUK_D(DUK_DPRINT("heap init: alloc heap thread")); + thr = duk_hthread_alloc_unchecked(heap, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD)); + if (thr == NULL) { DUK_D(DUK_DPRINT("failed to alloc heap_thread")); return 0; } @@ -43898,6 +45301,7 @@ /* 'thr' is now reachable */ + DUK_D(DUK_DPRINT("heap init: init heap thread stacks")); if (!duk_hthread_init_stacks(heap, thr)) { return 0; } @@ -44016,6 +45420,8 @@ DUK__DUMPSZ(duk_harray); DUK__DUMPSZ(duk_hcompfunc); DUK__DUMPSZ(duk_hnatfunc); + DUK__DUMPSZ(duk_hdecenv); + DUK__DUMPSZ(duk_hobjenv); DUK__DUMPSZ(duk_hthread); #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) DUK__DUMPSZ(duk_hbufobj); @@ -44028,9 +45434,6 @@ DUK__DUMPSZ(duk_propvalue); DUK__DUMPSZ(duk_propdesc); DUK__DUMPSZ(duk_heap); -#if defined(DUK_USE_STRTAB_CHAIN) - DUK__DUMPSZ(duk_strtab_entry); -#endif DUK__DUMPSZ(duk_activation); DUK__DUMPSZ(duk_catcher); DUK__DUMPSZ(duk_strcache); @@ -44139,10 +45542,21 @@ void *heap_udata, duk_fatal_function fatal_func) { duk_heap *res = NULL; + duk_uint32_t st_initsize; DUK_D(DUK_DPRINT("allocate heap")); /* + * Random config sanity asserts + */ + + DUK_ASSERT(DUK_USE_STRTAB_MINSIZE >= 64); + + DUK_ASSERT((DUK_HTYPE_STRING & 0x01U) == 0); + DUK_ASSERT((DUK_HTYPE_BUFFER & 0x01U) == 0); + DUK_ASSERT((DUK_HTYPE_OBJECT & 0x01U) == 1); /* DUK_HEAPHDR_IS_OBJECT() relies ont his. */ + + /* * Debug dump type sizes */ @@ -44157,9 +45571,11 @@ */ #if defined(DUK_USE_SELF_TESTS) + DUK_D(DUK_DPRINT("run self tests")); if (duk_selftest_run_tests(alloc_func, realloc_func, free_func, heap_udata) > 0) { fatal_func(heap_udata, "self test(s) failed"); } + DUK_D(DUK_DPRINT("self tests passed")); #endif /* @@ -44216,9 +45632,13 @@ * Use a raw call, all macros expect the heap to be initialized */ +#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 1) + goto failed; +#endif + DUK_D(DUK_DPRINT("alloc duk_heap object")); res = (duk_heap *) alloc_func(heap_udata, sizeof(duk_heap)); if (!res) { - goto error; + goto failed; } /* @@ -44226,6 +45646,9 @@ */ DUK_MEMZERO(res, sizeof(*res)); +#if defined(DUK_USE_ASSERTIONS) + res->heap_initializing = 1; +#endif /* explicit NULL inits */ #if defined(DUK_USE_EXPLICIT_NULL_INIT) @@ -44233,20 +45656,20 @@ res->heap_allocated = NULL; #if defined(DUK_USE_REFERENCE_COUNTING) res->refzero_list = NULL; - res->refzero_list_tail = NULL; #endif +#if defined(DUK_USE_FINALIZER_SUPPORT) res->finalize_list = NULL; +#if defined(DUK_USE_ASSERTIONS) + res->currently_finalizing = NULL; +#endif +#endif res->heap_thread = NULL; res->curr_thread = NULL; res->heap_object = NULL; -#if defined(DUK_USE_STRTAB_CHAIN) - /* nothing to NULL */ -#elif defined(DUK_USE_STRTAB_PROBE) -#if defined(DUK_USE_HEAPPTR16) - res->strtable16 = (duk_uint16_t *) NULL; +#if defined(DUK_USE_STRTAB_PTRCOMP) + res->strtable16 = NULL; #else - res->strtable = (duk_hstring **) NULL; -#endif + res->strtable = NULL; #endif #if defined(DUK_USE_ROM_STRINGS) /* no res->strs[] */ @@ -44280,13 +45703,21 @@ res->heap_udata = heap_udata; res->fatal_func = fatal_func; -#if defined(DUK_USE_HEAPPTR16) - /* XXX: zero assumption */ - res->heapptr_null16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) NULL); - res->heapptr_deleted16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) DUK_STRTAB_DELETED_MARKER(res)); -#endif + /* XXX: for now there's a pointer packing zero assumption, i.e. + * NULL <=> compressed pointer 0. If this is removed, may need + * to precompute e.g. null16 here. + */ - /* res->mark_and_sweep_trigger_counter == 0 -> now causes immediate GC; which is OK */ + /* res->ms_trigger_counter == 0 -> now causes immediate GC; which is OK */ + + /* Prevent mark-and-sweep and finalizer execution until heap is completely + * initialized. + */ + DUK_ASSERT(res->ms_prevent_count == 0); + DUK_ASSERT(res->pf_prevent_count == 0); + res->ms_prevent_count = 1; + res->pf_prevent_count = 1; + DUK_ASSERT(res->ms_running == 0); res->call_recursion_depth = 0; res->call_recursion_limit = DUK_USE_NATIVE_CALL_RECLIMIT; @@ -44314,71 +45745,49 @@ res->lj.jmpbuf_ptr = NULL; #endif DUK_ASSERT(res->lj.type == DUK_LJ_TYPE_UNKNOWN); /* zero */ - + DUK_ASSERT(res->lj.iserror == 0); DUK_TVAL_SET_UNDEFINED(&res->lj.value1); DUK_TVAL_SET_UNDEFINED(&res->lj.value2); -#if (DUK_STRTAB_INITIAL_SIZE < DUK_UTIL_MIN_HASH_PRIME) -#error initial heap stringtable size is defined incorrectly -#endif + DUK_ASSERT_LJSTATE_UNSET(res); /* * Init stringtable: fixed variant */ -#if defined(DUK_USE_STRTAB_CHAIN) - DUK_MEMZERO(res->strtable, sizeof(duk_strtab_entry) * DUK_STRTAB_CHAIN_SIZE); -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - { - duk_small_uint_t i; - for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { -#if defined(DUK_USE_HEAPPTR16) - res->strtable[i].u.str16 = res->heapptr_null16; + st_initsize = DUK_USE_STRTAB_MINSIZE; +#if defined(DUK_USE_STRTAB_PTRCOMP) + res->strtable16 = (duk_uint16_t *) alloc_func(heap_udata, sizeof(duk_uint16_t) * st_initsize); + if (res->strtable16 == NULL) { + goto failed; + } #else - res->strtable[i].u.str = NULL; -#endif - } + res->strtable = (duk_hstring **) alloc_func(heap_udata, sizeof(duk_hstring *) * st_initsize); + if (res->strtable == NULL) { + goto failed; } -#endif /* DUK_USE_EXPLICIT_NULL_INIT */ -#endif /* DUK_USE_STRTAB_CHAIN */ - - /* - * Init stringtable: probe variant - */ +#endif + res->st_size = st_initsize; + res->st_mask = st_initsize - 1; +#if (DUK_USE_STRTAB_MINSIZE != DUK_USE_STRTAB_MAXSIZE) + DUK_ASSERT(res->st_count == 0); +#endif -#if defined(DUK_USE_STRTAB_PROBE) -#if defined(DUK_USE_HEAPPTR16) - res->strtable16 = (duk_uint16_t *) alloc_func(heap_udata, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE); - if (!res->strtable16) { - goto error; - } -#else /* DUK_USE_HEAPPTR16 */ - res->strtable = (duk_hstring **) alloc_func(heap_udata, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE); - if (!res->strtable) { - goto error; - } -#endif /* DUK_USE_HEAPPTR16 */ - res->st_size = DUK_STRTAB_INITIAL_SIZE; +#if defined(DUK_USE_STRTAB_PTRCOMP) + /* zero assumption */ + DUK_MEMZERO(res->strtable16, sizeof(duk_uint16_t) * st_initsize); +#else #if defined(DUK_USE_EXPLICIT_NULL_INIT) { duk_small_uint_t i; - DUK_ASSERT(res->st_size == DUK_STRTAB_INITIAL_SIZE); - for (i = 0; i < DUK_STRTAB_INITIAL_SIZE; i++) { -#if defined(DUK_USE_HEAPPTR16) - res->strtable16[i] = res->heapptr_null16; -#else + for (i = 0; i < st_initsize; i++) { res->strtable[i] = NULL; -#endif } } -#else /* DUK_USE_EXPLICIT_NULL_INIT */ -#if defined(DUK_USE_HEAPPTR16) - DUK_MEMZERO(res->strtable16, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE); #else - DUK_MEMZERO(res->strtable, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE); -#endif + DUK_MEMZERO(res->strtable, sizeof(duk_hstring *) * st_initsize); #endif /* DUK_USE_EXPLICIT_NULL_INIT */ -#endif /* DUK_USE_STRTAB_PROBE */ +#endif /* DUK_USE_STRTAB_PTRCOMP */ /* * Init stringcache @@ -44403,30 +45812,40 @@ * Init built-in strings */ - DUK_DD(DUK_DDPRINT("HEAP: INIT STRINGS")); +#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 2) + goto failed; +#endif + DUK_D(DUK_DPRINT("heap init: initialize heap strings")); if (!duk__init_heap_strings(res)) { - goto error; + goto failed; } /* * Init the heap thread */ - DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP THREAD")); +#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 3) + goto failed; +#endif + DUK_D(DUK_DPRINT("heap init: initialize heap thread")); if (!duk__init_heap_thread(res)) { - goto error; + goto failed; } /* * Init the heap object */ - DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP OBJECT")); +#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 4) + goto failed; +#endif + DUK_D(DUK_DPRINT("heap init: initialize heap object")); DUK_ASSERT(res->heap_thread != NULL); - res->heap_object = duk_hobject_alloc(res, DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT)); - if (!res->heap_object) { - goto error; + res->heap_object = duk_hobject_alloc_unchecked(res, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT)); + if (res->heap_object == NULL) { + goto failed; } DUK_HOBJECT_INCREF(res->heap_thread, res->heap_object); @@ -44473,24 +45892,50 @@ #endif /* - * All done + * Allow finalizer and mark-and-sweep processing. + */ + + DUK_D(DUK_DPRINT("heap init: allow finalizer/mark-and-sweep processing")); + DUK_ASSERT(res->ms_prevent_count == 1); + DUK_ASSERT(res->pf_prevent_count == 1); + res->ms_prevent_count = 0; + res->pf_prevent_count = 0; + DUK_ASSERT(res->ms_running == 0); +#if defined(DUK_USE_ASSERTIONS) + res->heap_initializing = 0; +#endif + + /* + * All done. */ DUK_D(DUK_DPRINT("allocated heap: %p", (void *) res)); return res; - error: + failed: DUK_D(DUK_DPRINT("heap allocation failed")); - if (res) { - /* assumes that allocated pointers and alloc funcs are valid - * if res exists + if (res != NULL) { + /* Assumes that allocated pointers and alloc funcs are valid + * if res exists. */ + DUK_ASSERT(res->ms_prevent_count == 1); + DUK_ASSERT(res->pf_prevent_count == 1); + DUK_ASSERT(res->ms_running == 0); + if (res->heap_thread != NULL) { + res->ms_prevent_count = 0; + res->pf_prevent_count = 0; + } +#if defined(DUK_USE_ASSERTIONS) + res->heap_initializing = 0; +#endif + DUK_ASSERT(res->alloc_func != NULL); DUK_ASSERT(res->realloc_func != NULL); DUK_ASSERT(res->free_func != NULL); duk_heap_free(res); } + return NULL; } @@ -44501,6 +45946,456 @@ #undef DUK__DUMPLM_UNSIGNED_RAW #undef DUK__DUMPSZ #undef DUK__FIXED_HASH_SEED +#line 1 "duk_heap_finalize.c" +/* + * Finalizer handling. + */ + +/* #include duk_internal.h -> already included */ + +#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_context *ctx) { + DUK_DD(DUK_DDPRINT("fake global torture finalizer executed")); + + /* Require a lot of stack to force a value stack grow/shrink. */ + duk_require_stack(ctx, 100000); + + /* Force a reallocation with pointer change for value, call, and + * catch stacks to maximize side effects. + */ + duk_hthread_valstack_torture_realloc((duk_hthread *) ctx); + duk_hthread_callstack_torture_realloc((duk_hthread *) ctx); + duk_hthread_catchstack_torture_realloc((duk_hthread *) ctx); + + /* Inner function call, error throw. */ + duk_eval_string_noresult(ctx, + "(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 has been reached. + * Otherwise a callstack limit error will be created, then refzero'ed. + */ + if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit || + thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) { + DUK_D(DUK_DPRINT("skip global torture finalizer because of call recursion or call stack size limit")); + return; + } + + /* Run fake finalizer. Avoid creating unnecessary garbage. */ + duk_push_c_function((duk_context *) thr, duk__fake_global_finalizer, 0 /*nargs*/); + (void) duk_pcall((duk_context *) thr, 0 /*nargs*/); + duk_pop((duk_context *) 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); + DUK_ASSERT(heap->heap_thread->callstack != NULL); + DUK_ASSERT(heap->heap_thread->catchstack != 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_context *ctx, void *udata) { + duk_hthread *thr; + + DUK_ASSERT(ctx != NULL); + thr = (duk_hthread *) ctx; + 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(ctx, -1, DUK_STRIDX_INT_FINALIZER); /* -> [... obj finalizer] */ + duk_dup_m2(ctx); + duk_push_boolean(ctx, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap)); + DUK_DDD(DUK_DDDPRINT("calling finalizer")); + duk_call(ctx, 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_context *ctx; + 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); + ctx = (duk_context *) 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(ctx); +#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 (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(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; + } + + duk_push_hobject(ctx, obj); /* this also increases refcount by one */ + rc = duk_safe_call(ctx, duk__finalize_helper, NULL /*udata*/, 0 /*nargs*/, 1 /*nrets*/); /* -> [... obj retval/error] */ + DUK_ASSERT_TOP(ctx, 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(ctx, -1))); + } + duk_pop_2(ctx); /* -> [...] */ + + DUK_ASSERT_TOP(ctx, entry_top); +} + +#else /* DUK_USE_FINALIZER_SUPPORT */ + +/* nothing */ + +#endif /* DUK_USE_FINALIZER_SUPPORT */ #line 1 "duk_heap_hashstring.c" /* * String hash computation (interning). @@ -44634,22 +46529,7 @@ DUK_LOCAL_DECL void duk__mark_tval(duk_heap *heap, duk_tval *tv); /* - * Misc - */ - -/* Select a thread for mark-and-sweep use. - * - * XXX: This needs to change later. - */ -DUK_LOCAL duk_hthread *duk__get_temp_hthread(duk_heap *heap) { - if (heap->curr_thread) { - return heap->curr_thread; - } - return heap->heap_thread; /* may be NULL, too */ -} - -/* - * Marking functions for heap types: mark children recursively + * Marking functions for heap types: mark children recursively. */ DUK_LOCAL void duk__mark_hstring(duk_heap *heap, duk_hstring *h) { @@ -44673,7 +46553,7 @@ for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) { duk_hstring *key = DUK_HOBJECT_E_GET_KEY(heap, h, i); - if (!key) { + if (key == NULL) { continue; } duk__mark_heaphdr(heap, (duk_heaphdr *) key); @@ -44689,15 +46569,19 @@ duk__mark_tval(heap, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i)); } - /* hash part is a 'weak reference' and does not contribute */ + /* Hash part is a 'weak reference' and does not contribute. */ duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h)); - /* XXX: rearrange bits to allow a switch case to be used here? */ - /* XXX: add a fast path for objects (and arrays)? */ - /* DUK_HOBJECT_IS_ARRAY(h): needs no special handling now as there are - * no extra fields in need of marking. + /* Fast path for objects which don't have a subclass struct, or have a + * subclass struct but nothing that needs marking in the subclass struct. */ + if (DUK_HOBJECT_HAS_FASTREFS(h)) { + DUK_ASSERT(DUK_HOBJECT_ALLOWS_FASTREFS(h)); + return; + } + DUK_ASSERT(DUK_HOBJECT_PROHIBITS_FASTREFS(h)); + if (DUK_HOBJECT_IS_COMPFUNC(h)) { duk_hcompfunc *f = (duk_hcompfunc *) h; duk_tval *tv, *tv_end; @@ -44729,16 +46613,21 @@ /* May happen in some out-of-memory corner cases. */ DUK_D(DUK_DPRINT("duk_hcompfunc 'data' is NULL, skipping marking")); } - } else if (DUK_HOBJECT_IS_NATFUNC(h)) { - duk_hnatfunc *f = (duk_hnatfunc *) h; - DUK_UNREF(f); - /* nothing to mark */ #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) } else if (DUK_HOBJECT_IS_BUFOBJ(h)) { duk_hbufobj *b = (duk_hbufobj *) h; duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf); duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf_prop); #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + } else if (DUK_HOBJECT_IS_DECENV(h)) { + duk_hdecenv *e = (duk_hdecenv *) h; + DUK_ASSERT_HDECENV_VALID(e); + duk__mark_heaphdr(heap, (duk_heaphdr *) e->thread); + duk__mark_heaphdr(heap, (duk_heaphdr *) e->varmap); + } else if (DUK_HOBJECT_IS_OBJENV(h)) { + duk_hobjenv *e = (duk_hobjenv *) h; + DUK_ASSERT_HOBJENV_VALID(e); + duk__mark_heaphdr(heap, (duk_heaphdr *) e->target); } else if (DUK_HOBJECT_IS_THREAD(h)) { duk_hthread *t = (duk_hthread *) h; duk_tval *tv; @@ -44767,19 +46656,25 @@ duk__mark_heaphdr(heap, (duk_heaphdr *) t->resumer); - /* XXX: duk_small_uint_t would be enough for this loop */ for (i = 0; i < DUK_NUM_BUILTINS; i++) { duk__mark_heaphdr(heap, (duk_heaphdr *) t->builtins[i]); } + } 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); } } -/* recursion tracking happens here only */ +/* Mark any duk_heaphdr type. Recursion tracking happens only here. */ DUK_LOCAL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h) { DUK_DDD(DUK_DDDPRINT("duk__mark_heaphdr %p, type %ld", (void *) h, (h != NULL ? (long) DUK_HEAPHDR_GET_TYPE(h) : (long) -1))); - if (!h) { + if (h == NULL) { return; } #if defined(DUK_USE_ROM_OBJECTS) @@ -44788,21 +46683,24 @@ return; } #endif +#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) + h->h_assert_refcount++; /* Comparison refcount: bump even if already reachable. */ +#endif if (DUK_HEAPHDR_HAS_REACHABLE(h)) { DUK_DDD(DUK_DDDPRINT("already marked reachable, skip")); return; } DUK_HEAPHDR_SET_REACHABLE(h); - if (heap->mark_and_sweep_recursion_depth >= DUK_USE_MARK_AND_SWEEP_RECLIMIT) { - /* log this with a normal debug level because this should be relatively rare */ + if (heap->ms_recursion_depth >= DUK_USE_MARK_AND_SWEEP_RECLIMIT) { DUK_D(DUK_DPRINT("mark-and-sweep recursion limit reached, marking as temproot: %p", (void *) h)); DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap); DUK_HEAPHDR_SET_TEMPROOT(h); return; } - heap->mark_and_sweep_recursion_depth++; + heap->ms_recursion_depth++; + DUK_ASSERT(heap->ms_recursion_depth != 0); /* Wrap. */ switch (DUK_HEAPHDR_GET_TYPE(h)) { case DUK_HTYPE_STRING: @@ -44819,12 +46717,13 @@ DUK_UNREACHABLE(); } - heap->mark_and_sweep_recursion_depth--; + DUK_ASSERT(heap->ms_recursion_depth > 0); + heap->ms_recursion_depth--; } DUK_LOCAL void duk__mark_tval(duk_heap *heap, duk_tval *tv) { DUK_DDD(DUK_DDDPRINT("duk__mark_tval %p", (void *) tv)); - if (!tv) { + if (tv == NULL) { return; } if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { @@ -44860,37 +46759,12 @@ } /* - * Mark refzero_list objects. - * - * Objects on the refzero_list have no inbound references. They might have - * outbound references to objects that we might free, which would invalidate - * any references held by the refzero objects. A refzero object might also - * be rescued by refcount finalization. Refzero objects are treated as - * reachability roots to ensure they (or anything they point to) are not - * freed in mark-and-sweep. - */ - -#if defined(DUK_USE_REFERENCE_COUNTING) -DUK_LOCAL void duk__mark_refzero_list(duk_heap *heap) { - duk_heaphdr *hdr; - - DUK_DD(DUK_DDPRINT("duk__mark_refzero_list: %p", (void *) heap)); - - hdr = heap->refzero_list; - while (hdr) { - duk__mark_heaphdr(heap, hdr); - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -} -#endif - -/* * Mark unreachable, finalizable objects. * - * Such objects will be moved aside and their finalizers run later. They have - * to be treated as reachability roots for their properties etc to remain - * allocated. This marking is only done for unreachable values which would - * be swept later (refzero_list is thus excluded). + * Such objects will be moved aside and their finalizers run later. They + * have to be treated as reachability roots for their properties etc to + * remain allocated. This marking is only done for unreachable values which + * would be swept later. * * Objects are first marked FINALIZABLE and only then marked as reachability * roots; otherwise circular references might be handled inconsistently. @@ -44898,32 +46772,30 @@ #if defined(DUK_USE_FINALIZER_SUPPORT) DUK_LOCAL void duk__mark_finalizable(duk_heap *heap) { - duk_hthread *thr; duk_heaphdr *hdr; duk_size_t count_finalizable = 0; DUK_DD(DUK_DDPRINT("duk__mark_finalizable: %p", (void *) heap)); - thr = duk__get_temp_hthread(heap); - DUK_ASSERT(thr != NULL); + DUK_ASSERT(heap->heap_thread != NULL); hdr = heap->heap_allocated; - while (hdr) { - /* A finalizer is looked up from the object and up its prototype chain - * (which allows inherited finalizers). A prototype loop must not cause - * an error to be thrown here; duk_hobject_hasprop_raw() will ignore a - * prototype loop silently and indicate that the property doesn't exist. + while (hdr != NULL) { + /* A finalizer is looked up from the object and up its + * prototype chain (which allows inherited finalizers). + * The finalizer is checked for using a duk_hobject flag + * which is kept in sync with the presence and callability + * of a _Finalizer hidden symbol. */ if (!DUK_HEAPHDR_HAS_REACHABLE(hdr) && - DUK_HEAPHDR_GET_TYPE(hdr) == DUK_HTYPE_OBJECT && + DUK_HEAPHDR_IS_OBJECT(hdr) && !DUK_HEAPHDR_HAS_FINALIZED(hdr) && - duk_hobject_hasprop_raw(thr, (duk_hobject *) hdr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) { - + DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) hdr)) { /* heaphdr: * - is not reachable * - is an object - * - is not a finalized object + * - is not a finalized object waiting for rescue/keep decision * - has a finalizer */ @@ -44933,7 +46805,7 @@ (void *) hdr)); DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr)); DUK_HEAPHDR_SET_FINALIZABLE(hdr); - count_finalizable ++; + count_finalizable++; } hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); @@ -44947,7 +46819,7 @@ (long) count_finalizable)); hdr = heap->heap_allocated; - while (hdr) { + while (hdr != NULL) { if (DUK_HEAPHDR_HAS_FINALIZABLE(hdr)) { duk__mark_heaphdr(heap, hdr); } @@ -44961,7 +46833,6 @@ /* * Mark objects on finalize_list. - * */ #if defined(DUK_USE_FINALIZER_SUPPORT) @@ -44974,7 +46845,7 @@ DUK_DD(DUK_DDPRINT("duk__mark_finalize_list: %p", (void *) heap)); hdr = heap->finalize_list; - while (hdr) { + while (hdr != NULL) { duk__mark_heaphdr(heap, hdr); hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); #if defined(DUK_USE_DEBUG) @@ -44994,15 +46865,18 @@ /* * Fallback marking handler if recursion limit is reached. * - * Iterates 'temproots' until recursion limit is no longer hit. Note - * that temproots may reside either in heap allocated list or the - * refzero work list. This is a slow scan, but guarantees that we - * finish with a bounded C stack. - * - * Note that nodes may have been marked as temproots before this - * scan begun, OR they may have been marked during the scan (as - * we process nodes recursively also during the scan). This is - * intended behavior. + * Iterates 'temproots' until recursion limit is no longer hit. Temproots + * can be in heap_allocated or finalize_list; refzero_list is now always + * empty for mark-and-sweep. A temproot may occur in finalize_list now if + * there are objects on the finalize_list and user code creates a reference + * from an object in heap_allocated to the object in finalize_list (which is + * now allowed), and it happened to coincide with the recursion depth limit. + * + * This is a slow scan, but guarantees that we finish with a bounded C stack. + * + * Note that nodes may have been marked as temproots before this scan begun, + * OR they may have been marked during the scan (as we process nodes + * recursively also during the scan). This is intended behavior. */ #if defined(DUK_USE_DEBUG) @@ -45017,7 +46891,10 @@ DUK_DDD(DUK_DDDPRINT("found a temp root: %p", (void *) hdr)); DUK_HEAPHDR_CLEAR_TEMPROOT(hdr); - DUK_HEAPHDR_CLEAR_REACHABLE(hdr); /* done so that duk__mark_heaphdr() works correctly */ + DUK_HEAPHDR_CLEAR_REACHABLE(hdr); /* Done so that duk__mark_heaphdr() works correctly. */ +#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) + hdr->h_assert_refcount--; /* Same node visited twice. */ +#endif duk__mark_heaphdr(heap, hdr); #if defined(DUK_USE_DEBUG) @@ -45051,9 +46928,8 @@ hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); } - /* must also check refzero_list */ -#if defined(DUK_USE_REFERENCE_COUNTING) - hdr = heap->refzero_list; +#if defined(DUK_USE_FINALIZER_SUPPORT) + hdr = heap->finalize_list; while (hdr) { #if defined(DUK_USE_DEBUG) duk__handle_temproot(heap, hdr, &count); @@ -45062,7 +46938,7 @@ #endif hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); } -#endif /* DUK_USE_REFERENCE_COUNTING */ +#endif #if defined(DUK_USE_DEBUG) DUK_DD(DUK_DDPRINT("temproot mark heap scan processed %ld temp roots", (long) count)); @@ -45081,14 +46957,11 @@ #if defined(DUK_USE_REFERENCE_COUNTING) DUK_LOCAL void duk__finalize_refcounts(duk_heap *heap) { - duk_hthread *thr; duk_heaphdr *hdr; - thr = duk__get_temp_hthread(heap); - DUK_ASSERT(thr != NULL); + DUK_ASSERT(heap->heap_thread != NULL); - DUK_DD(DUK_DDPRINT("duk__finalize_refcounts: heap=%p, hthread=%p", - (void *) heap, (void *) thr)); + DUK_DD(DUK_DDPRINT("duk__finalize_refcounts: heap=%p", (void *) heap)); hdr = heap->heap_allocated; while (hdr) { @@ -45104,37 +46977,21 @@ */ DUK_DDD(DUK_DDDPRINT("unreachable object, refcount finalize before sweeping: %p", (void *) hdr)); - duk_heaphdr_refcount_finalize(thr, hdr); - } - - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -} -#endif /* DUK_USE_REFERENCE_COUNTING */ - -/* - * Clear (reachable) flags of refzero work list. - */ -#if defined(DUK_USE_REFERENCE_COUNTING) -DUK_LOCAL void duk__clear_refzero_list_flags(duk_heap *heap) { - duk_heaphdr *hdr; - - DUK_DD(DUK_DDPRINT("duk__clear_refzero_list_flags: %p", (void *) heap)); + /* Finalize using heap->heap_thread; DECREF has a + * suppress check for mark-and-sweep which is based + * on heap->ms_running. + */ + duk_heaphdr_refcount_finalize_norz(heap, hdr); + } - hdr = heap->refzero_list; - while (hdr) { - DUK_HEAPHDR_CLEAR_REACHABLE(hdr); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr)); hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); } } #endif /* DUK_USE_REFERENCE_COUNTING */ /* - * Clear (reachable) flags of finalize_list + * Clear (reachable) flags of finalize_list. * * We could mostly do in the sweep phase when we move objects from the * heap into the finalize_list. However, if a finalizer run is skipped @@ -45153,8 +47010,11 @@ hdr = heap->finalize_list; while (hdr) { DUK_HEAPHDR_CLEAR_REACHABLE(hdr); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr)); +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(hdr) || \ + (heap->currently_finalizing == hdr)); +#endif + /* DUK_HEAPHDR_FLAG_FINALIZED may be set. */ DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr)); hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); } @@ -45162,191 +47022,85 @@ #endif /* DUK_USE_FINALIZER_SUPPORT */ /* - * Sweep stringtable + * Sweep stringtable. */ -#if defined(DUK_USE_STRTAB_CHAIN) - -/* XXX: skip count_free w/o debug? */ -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL void duk__sweep_string_chain16(duk_heap *heap, duk_uint16_t *slot, duk_size_t *count_keep, duk_size_t *count_free) { - duk_uint16_t h16 = *slot; +DUK_LOCAL void duk__sweep_stringtable(duk_heap *heap, duk_size_t *out_count_keep) { duk_hstring *h; - duk_uint16_t null16 = heap->heapptr_null16; - - if (h16 == null16) { - /* nop */ - return; - } - h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, h16); - DUK_ASSERT(h != NULL); - - if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) { - DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h); - (*count_keep)++; - } else { -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0); -#endif - /* deal with weak references first */ - duk_heap_strcache_string_remove(heap, (duk_hstring *) h); - *slot = null16; - - /* free inner references (these exist e.g. when external - * strings are enabled) - */ - duk_free_hstring(heap, h); - (*count_free)++; - } -} -#else /* DUK_USE_HEAPPTR16 */ -DUK_LOCAL void duk__sweep_string_chain(duk_heap *heap, duk_hstring **slot, duk_size_t *count_keep, duk_size_t *count_free) { - duk_hstring *h = *slot; - - if (h == NULL) { - /* nop */ - return; - } - - if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) { - DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h); - (*count_keep)++; - } else { -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0); -#endif - /* deal with weak references first */ - duk_heap_strcache_string_remove(heap, (duk_hstring *) h); - *slot = NULL; - - /* free inner references (these exist e.g. when external - * strings are enabled) - */ - duk_free_hstring(heap, h); - (*count_free)++; - } -} -#endif /* DUK_USE_HEAPPTR16 */ - -DUK_LOCAL void duk__sweep_stringtable_chain(duk_heap *heap, duk_size_t *out_count_keep) { - duk_strtab_entry *e; - duk_uint_fast32_t i; + duk_hstring *prev; + duk_uint32_t i; +#if defined(DUK_USE_DEBUG) duk_size_t count_free = 0; - duk_size_t count_keep = 0; - duk_size_t j, n; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t *lst; -#else - duk_hstring **lst; #endif + duk_size_t count_keep = 0; DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap)); - /* Non-zero refcounts should not happen for unreachable strings, - * because we refcount finalize all unreachable objects which - * should have decreased unreachable string refcounts to zero - * (even for cycles). - */ - - for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { - e = heap->strtable + i; - if (e->listlen == 0) { -#if defined(DUK_USE_HEAPPTR16) - duk__sweep_string_chain16(heap, &e->u.str16, &count_keep, &count_free); -#else - duk__sweep_string_chain(heap, &e->u.str, &count_keep, &count_free); -#endif - } else { -#if defined(DUK_USE_HEAPPTR16) - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); -#else - lst = e->u.strlist; -#endif - for (j = 0, n = e->listlen; j < n; j++) { -#if defined(DUK_USE_HEAPPTR16) - duk__sweep_string_chain16(heap, lst + j, &count_keep, &count_free); +#if defined(DUK_USE_STRTAB_PTRCOMP) + if (heap->strtable16 == NULL) { #else - duk__sweep_string_chain(heap, lst + j, &count_keep, &count_free); + if (heap->strtable == NULL) { #endif - } - } + goto done; } - DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept", - (long) count_free, (long) count_keep)); - *out_count_keep = count_keep; -} -#endif /* DUK_USE_STRTAB_CHAIN */ - -#if defined(DUK_USE_STRTAB_PROBE) -DUK_LOCAL void duk__sweep_stringtable_probe(duk_heap *heap, duk_size_t *out_count_keep) { - duk_hstring *h; - duk_uint_fast32_t i; -#if defined(DUK_USE_DEBUG) - duk_size_t count_free = 0; -#endif - duk_size_t count_keep = 0; - - DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap)); - for (i = 0; i < heap->st_size; i++) { -#if defined(DUK_USE_HEAPPTR16) - h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); +#if defined(DUK_USE_STRTAB_PTRCOMP) + h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); #else h = heap->strtable[i]; #endif - if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) { - continue; - } else if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) { - DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h); - count_keep++; - continue; - } - + prev = NULL; + while (h != NULL) { + duk_hstring *next; + next = h->hdr.h_next; + + if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) { + DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h); + count_keep++; + prev = h; + } else { #if defined(DUK_USE_DEBUG) - count_free++; + count_free++; #endif #if defined(DUK_USE_REFERENCE_COUNTING) - /* Non-zero refcounts should not happen for unreachable strings, - * because we refcount finalize all unreachable objects which - * should have decreased unreachable string refcounts to zero - * (even for cycles). - */ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0); + /* Non-zero refcounts should not happen for unreachable strings, + * because we refcount finalize all unreachable objects which + * should have decreased unreachable string refcounts to zero + * (even for cycles). + */ + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0); #endif - DUK_DDD(DUK_DDDPRINT("sweep string, not reachable: %p", (void *) h)); + /* Deal with weak references first. */ + duk_heap_strcache_string_remove(heap, (duk_hstring *) h); - /* deal with weak references first */ - duk_heap_strcache_string_remove(heap, (duk_hstring *) h); + /* Remove the string from the string table. */ + duk_heap_strtable_unlink_prev(heap, (duk_hstring *) h, (duk_hstring *) prev); - /* remove the string (mark DELETED), could also call - * duk_heap_string_remove() but that would be slow and - * pointless because we already know the slot. - */ -#if defined(DUK_USE_HEAPPTR16) - heap->strtable16[i] = heap->heapptr_deleted16; -#else - heap->strtable[i] = DUK_STRTAB_DELETED_MARKER(heap); -#endif + /* Free inner references (these exist e.g. when external + * strings are enabled) and the struct itself. + */ + duk_free_hstring(heap, (duk_hstring *) h); - /* free inner references (these exist e.g. when external - * strings are enabled) and the struct itself. - */ - duk_free_hstring(heap, (duk_hstring *) h); + /* Don't update 'prev'; it should be last string kept. */ + } + + h = next; + } } + done: #if defined(DUK_USE_DEBUG) DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept", (long) count_free, (long) count_keep)); #endif *out_count_keep = count_keep; } -#endif /* DUK_USE_STRTAB_PROBE */ /* - * Sweep heap + * Sweep heap. */ DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_count_keep) { @@ -45375,65 +47129,62 @@ if (DUK_HEAPHDR_HAS_REACHABLE(curr)) { /* - * Reachable object, keep + * Reachable object: + * - If FINALIZABLE -> actually unreachable (but marked + * artificially reachable), queue to finalize_list. + * - If !FINALIZABLE but FINALIZED -> rescued after + * finalizer execution. + * - Otherwise just a normal, reachable object. + * + * Objects which are kept are queued to heap_allocated + * tail (we're essentially filtering heap_allocated in + * practice). */ - DUK_DDD(DUK_DDDPRINT("sweep, reachable: %p", (void *) curr)); - - if (DUK_HEAPHDR_HAS_FINALIZABLE(curr)) { - /* - * If object has been marked finalizable, move it to the - * "to be finalized" work list. It will be collected on - * the next mark-and-sweep if it is still unreachable - * after running the finalizer. - */ - +#if defined(DUK_USE_FINALIZER_SUPPORT) + if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZABLE(curr))) { DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); - DUK_DDD(DUK_DDDPRINT("object has finalizer, move to finalization work list: %p", (void *) curr)); + DUK_DD(DUK_DDPRINT("sweep; reachable, finalizable --> move to finalize_list: %p", (void *) curr)); -#if defined(DUK_USE_DOUBLE_LINKED_HEAP) - if (heap->finalize_list) { - DUK_HEAPHDR_SET_PREV(heap, heap->finalize_list, curr); - } - DUK_HEAPHDR_SET_PREV(heap, curr, NULL); +#if defined(DUK_USE_REFERENCE_COUNTING) + DUK_HEAPHDR_PREINC_REFCOUNT(curr); /* Bump refcount so that refzero never occurs when pending a finalizer call. */ #endif - DUK_HEAPHDR_SET_NEXT(heap, curr, heap->finalize_list); - DUK_ASSERT_HEAPHDR_LINKS(heap, curr); - heap->finalize_list = curr; + DUK_HEAP_INSERT_INTO_FINALIZE_LIST(heap, curr); #if defined(DUK_USE_DEBUG) count_finalize++; #endif - } else { - /* - * Object will be kept; queue object back to heap_allocated (to tail) - */ - - if (DUK_HEAPHDR_HAS_FINALIZED(curr)) { - /* - * Object's finalizer was executed on last round, and - * object has been happily rescued. - */ - + } + else +#endif /* DUK_USE_FINALIZER_SUPPORT */ + { + if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZED(curr))) { DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); - DUK_DD(DUK_DDPRINT("object rescued during mark-and-sweep finalization: %p", (void *) curr)); + + if (flags & DUK_MS_FLAG_POSTPONE_RESCUE) { + DUK_DD(DUK_DDPRINT("sweep; reachable, finalized, but postponing rescue decisions --> keep object (with FINALIZED set): %!iO", curr)); + count_keep++; + } else { + DUK_DD(DUK_DDPRINT("sweep; reachable, finalized --> rescued after finalization: %p", (void *) curr)); +#if defined(DUK_USE_FINALIZER_SUPPORT) + DUK_HEAPHDR_CLEAR_FINALIZED(curr); +#endif #if defined(DUK_USE_DEBUG) - count_rescue++; + count_rescue++; #endif + } } else { - /* - * Plain, boring reachable object. - */ - DUK_DD(DUK_DDPRINT("keep object: %!iO", curr)); + DUK_DD(DUK_DDPRINT("sweep; reachable --> keep: %!iO", curr)); count_keep++; } - if (!heap->heap_allocated) { - heap->heap_allocated = curr; - } - if (prev) { + if (prev != NULL) { + DUK_ASSERT(heap->heap_allocated != NULL); DUK_HEAPHDR_SET_NEXT(heap, prev, curr); + } else { + DUK_ASSERT(heap->heap_allocated == NULL); + heap->heap_allocated = curr; } #if defined(DUK_USE_DOUBLE_LINKED_HEAP) DUK_HEAPHDR_SET_PREV(heap, curr, prev); @@ -45444,21 +47195,23 @@ } DUK_HEAPHDR_CLEAR_REACHABLE(curr); - DUK_HEAPHDR_CLEAR_FINALIZED(curr); - DUK_HEAPHDR_CLEAR_FINALIZABLE(curr); - + /* Keep FINALIZED if set, used if rescue decisions are postponed. */ + /* Keep FINALIZABLE for objects on finalize_list. */ DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); - - curr = next; } else { /* - * Unreachable object, free + * Unreachable object: + * - If FINALIZED, object was finalized but not + * rescued. This doesn't affect freeing. + * - Otherwise normal unreachable object. + * + * There's no guard preventing a FINALIZED object + * from being freed while finalizers execute: the + * artificial finalize_list reachability roots can't + * cause an incorrect free decision (but can cause + * an incorrect rescue decision). */ - DUK_DDD(DUK_DDDPRINT("sweep, not reachable: %p", (void *) curr)); - #if defined(DUK_USE_REFERENCE_COUNTING) /* Non-zero refcounts should not happen because we refcount * finalize all unreachable objects which should cancel out @@ -45468,10 +47221,15 @@ #endif DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); +#if defined(DUK_USE_DEBUG) if (DUK_HEAPHDR_HAS_FINALIZED(curr)) { - DUK_DDD(DUK_DDDPRINT("finalized object not rescued: %p", (void *) curr)); + DUK_DD(DUK_DDPRINT("sweep; unreachable, finalized --> finalized object not rescued: %p", (void *) curr)); + } else { + DUK_DD(DUK_DDPRINT("sweep; not reachable --> free: %p", (void *) curr)); } +#endif + /* Note: object cannot be a finalizable unreachable object, as * they have been marked temporarily reachable for this round, * and are handled above. @@ -45481,17 +47239,18 @@ count_free++; #endif - /* weak refs should be handled here, but no weak refs for + /* Weak refs should be handled here, but no weak refs for * any non-string objects exist right now. */ - /* free object and all auxiliary (non-heap) allocs */ + /* Free object and all auxiliary (non-heap) allocs. */ duk_heap_free_heaphdr_raw(heap, curr); - - curr = next; } + + curr = next; } - if (prev) { + + if (prev != NULL) { DUK_HEAPHDR_SET_NEXT(heap, prev, NULL); } DUK_ASSERT_HEAPHDR_LINKS(heap, prev); @@ -45504,71 +47263,6 @@ } /* - * Run (object) finalizers in the "to be finalized" work list. - */ - -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_LOCAL void duk__run_object_finalizers(duk_heap *heap, duk_small_uint_t flags) { - duk_heaphdr *curr; - duk_heaphdr *next; -#if defined(DUK_USE_DEBUG) - duk_size_t count = 0; -#endif - duk_hthread *thr; - - DUK_DD(DUK_DDPRINT("duk__run_object_finalizers: %p", (void *) heap)); - - thr = duk__get_temp_hthread(heap); - DUK_ASSERT(thr != NULL); - - curr = heap->finalize_list; - while (curr) { - DUK_DDD(DUK_DDDPRINT("mark-and-sweep finalize: %p", (void *) curr)); - - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* only objects have finalizers */ - DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr)); /* flags have been already cleared */ - DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr)); /* No finalizers for ROM objects */ - - if (DUK_LIKELY((flags & DUK_MS_FLAG_SKIP_FINALIZERS) == 0)) { - /* Run the finalizer, duk_hobject_run_finalizer() sets FINALIZED. - * Next mark-and-sweep will collect the object unless it has - * become reachable (i.e. rescued). FINALIZED prevents the - * finalizer from being executed again before that. - */ - duk_hobject_run_finalizer(thr, (duk_hobject *) curr); /* must never longjmp */ - DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(curr)); - } 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)); - } - - /* queue back to heap_allocated */ - next = DUK_HEAPHDR_GET_NEXT(heap, curr); - DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr); - - curr = next; -#if defined(DUK_USE_DEBUG) - count++; -#endif - } - - /* finalize_list will always be processed completely */ - heap->finalize_list = NULL; - -#if defined(DUK_USE_DEBUG) - DUK_D(DUK_DPRINT("mark-and-sweep finalize objects: %ld finalizers called", (long) count)); -#endif -} -#endif /* DUK_USE_FINALIZER_SUPPORT */ - -/* * Object compaction. * * Compaction is assumed to never throw an error. @@ -45643,26 +47337,25 @@ duk_size_t count_compact = 0; duk_size_t count_bytes_saved = 0; #endif - duk_hthread *thr; DUK_DD(DUK_DDPRINT("duk__compact_objects: %p", (void *) heap)); - thr = duk__get_temp_hthread(heap); - DUK_ASSERT(thr != NULL); + DUK_ASSERT(heap->heap_thread != NULL); #if defined(DUK_USE_DEBUG) - duk__compact_object_list(heap, thr, heap->heap_allocated, &count_check, &count_compact, &count_bytes_saved); - duk__compact_object_list(heap, thr, heap->finalize_list, &count_check, &count_compact, &count_bytes_saved); -#if defined(DUK_USE_REFERENCE_COUNTING) - duk__compact_object_list(heap, thr, heap->refzero_list, &count_check, &count_compact, &count_bytes_saved); + duk__compact_object_list(heap, heap->heap_thread, heap->heap_allocated, &count_check, &count_compact, &count_bytes_saved); +#if defined(DUK_USE_FINALIZER_SUPPORT) + duk__compact_object_list(heap, heap->heap_thread, heap->finalize_list, &count_check, &count_compact, &count_bytes_saved); #endif #else - duk__compact_object_list(heap, thr, heap->heap_allocated); - duk__compact_object_list(heap, thr, heap->finalize_list); -#if defined(DUK_USE_REFERENCE_COUNTING) - duk__compact_object_list(heap, thr, heap->refzero_list); + duk__compact_object_list(heap, heap->heap_thread, heap->heap_allocated); +#if defined(DUK_USE_FINALIZER_SUPPORT) + duk__compact_object_list(heap, heap->heap_thread, heap->finalize_list); #endif #endif +#if defined(DUK_USE_REFERENCE_COUNTING) + DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ +#endif #if defined(DUK_USE_DEBUG) DUK_D(DUK_DPRINT("mark-and-sweep compact objects: %ld checked, %ld compaction attempts, %ld bytes saved by compaction", @@ -45688,166 +47381,189 @@ } #if defined(DUK_USE_REFERENCE_COUNTING) - hdr = heap->refzero_list; - while (hdr) { - DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr)); - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -#endif /* DUK_USE_REFERENCE_COUNTING */ + DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ +#endif } #if defined(DUK_USE_REFERENCE_COUNTING) DUK_LOCAL void duk__assert_valid_refcounts(duk_heap *heap) { duk_heaphdr *hdr = heap->heap_allocated; while (hdr) { + /* Cannot really assert much w.r.t. refcounts now. */ + if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0 && DUK_HEAPHDR_HAS_FINALIZED(hdr)) { /* An object may be in heap_allocated list with a zero * refcount if it has just been finalized and is waiting * to be collected by the next cycle. + * (This doesn't currently happen however.) */ } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0) { /* An object may be in heap_allocated list with a zero - * refcount also if it is a temporary object created by - * a finalizer; because finalization now runs inside - * mark-and-sweep, such objects will not be queued to - * refzero_list and will thus appear here with refcount - * zero. - */ -#if 0 /* this case can no longer occur because refcount is unsigned */ - } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) < 0) { - DUK_D(DUK_DPRINT("invalid refcount: %ld, %p -> %!O", - (hdr != NULL ? (long) DUK_HEAPHDR_GET_REFCOUNT(hdr) : (long) 0), - (void *) hdr, (duk_heaphdr *) hdr)); - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(hdr) > 0); -#endif + * refcount also if it is a temporary object created + * during debugger paused state. It will get collected + * by mark-and-sweep based on its reachability status + * (presumably not reachable because refcount is 0). + */ } + DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(hdr) >= 0); /* Unsigned. */ hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); } } -#endif /* DUK_USE_REFERENCE_COUNTING */ -#endif /* DUK_USE_ASSERTIONS */ -/* - * Finalizer torture. Do one fake finalizer call which causes side effects - * similar to one or more finalizers on actual objects. - */ +DUK_LOCAL void duk__clear_assert_refcounts(duk_heap *heap) { + duk_heaphdr *curr; + duk_uint32_t i; + for (curr = heap->heap_allocated; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { + curr->h_assert_refcount = 0; + } #if defined(DUK_USE_FINALIZER_SUPPORT) -#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE) -DUK_LOCAL duk_ret_t duk__markandsweep_fake_finalizer(duk_context *ctx) { - DUK_D(DUK_DPRINT("fake mark-and-sweep torture finalizer executed")); - - /* Require a lot of stack to force a value stack grow/shrink. - * Recursive mark-and-sweep is prevented by allocation macros - * so this won't trigger another mark-and-sweep. - */ - duk_require_stack(ctx, 100000); + for (curr = heap->finalize_list; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { + curr->h_assert_refcount = 0; + } +#endif +#if defined(DUK_USE_REFERENCE_COUNTING) + for (curr = heap->refzero_list; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { + curr->h_assert_refcount = 0; + } +#endif - /* XXX: do something to force a callstack grow/shrink, perhaps - * just a manual forced resize or a forced relocating realloc? - */ + for (i = 0; i < heap->st_size; i++) { + duk_hstring *h; - return 0; +#if defined(DUK_USE_STRTAB_PTRCOMP) + h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); +#else + h = heap->strtable[i]; +#endif + while (h != NULL) { + ((duk_heaphdr *) h)->h_assert_refcount = 0; + h = h->hdr.h_next; + } + } } -DUK_LOCAL void duk__markandsweep_torture_finalizer(duk_hthread *thr) { - duk_context *ctx; - duk_int_t rc; +DUK_LOCAL void duk__check_refcount_heaphdr(duk_heaphdr *hdr) { + duk_bool_t count_ok; - DUK_ASSERT(thr != NULL); - ctx = (duk_context *) thr; + /* The refcount check only makes sense for reachable objects on + * heap_allocated or string table, after the sweep phase. Prior to + * sweep phase refcounts will include references that are not visible + * via reachability roots. + * + * Because we're called after the sweep phase, all heap objects on + * heap_allocated are reachable. REACHABLE flags have already been + * cleared so we can't check them. + */ - /* Avoid fake finalization when callstack limit has been reached. - * Otherwise a callstack limit error will be created, then refzero'ed. + /* ROM objects have intentionally incorrect refcount (1), but we won't + * check them. */ - if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit || - thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) { - DUK_D(DUK_DPRINT("call recursion depth reached, avoid fake mark-and-sweep torture finalizer")); - return; + DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr)); + + count_ok = ((duk_size_t) DUK_HEAPHDR_GET_REFCOUNT(hdr) == hdr->h_assert_refcount); + if (!count_ok) { + DUK_D(DUK_DPRINT("refcount mismatch for: %p: header=%ld counted=%ld --> %!iO", + (void *) hdr, (long) DUK_HEAPHDR_GET_REFCOUNT(hdr), + (long) hdr->h_assert_refcount, hdr)); + DUK_ASSERT(0); } +} - /* Run fake finalizer. Avoid creating unnecessary garbage. */ - duk_push_c_function(ctx, duk__markandsweep_fake_finalizer, 0 /*nargs*/); - rc = duk_pcall(ctx, 0 /*nargs*/); - DUK_UNREF(rc); /* ignored */ - duk_pop(ctx); +DUK_LOCAL void duk__check_assert_refcounts(duk_heap *heap) { + duk_heaphdr *curr; + duk_uint32_t i; + + for (curr = heap->heap_allocated; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { + duk__check_refcount_heaphdr(curr); + } +#if defined(DUK_USE_FINALIZER_SUPPORT) + for (curr = heap->finalize_list; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { + duk__check_refcount_heaphdr(curr); + } +#endif + + for (i = 0; i < heap->st_size; i++) { + duk_hstring *h; + +#if defined(DUK_USE_STRTAB_PTRCOMP) + h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); +#else + h = heap->strtable[i]; +#endif + while (h != NULL) { + duk__check_refcount_heaphdr((duk_heaphdr *) h); + h = h->hdr.h_next; + } + } } -#endif /* DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE */ -#endif /* DUK_USE_FINALIZER_SUPPORT */ +#endif /* DUK_USE_REFERENCE_COUNTING */ +#endif /* DUK_USE_ASSERTIONS */ /* * Main mark-and-sweep function. * * 'flags' represents the features requested by the caller. The current - * heap->mark_and_sweep_base_flags is ORed automatically into the flags; - * the base flags mask typically prevents certain mark-and-sweep operations - * to avoid trouble. + * heap->ms_base_flags is ORed automatically into the flags; the base flags + * mask typically prevents certain mark-and-sweep operation to avoid trouble. */ -DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags) { - duk_hthread *thr; +DUK_INTERNAL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags) { duk_size_t count_keep_obj; duk_size_t count_keep_str; #if defined(DUK_USE_VOLUNTARY_GC) duk_size_t tmp; #endif - /* XXX: thread selection for mark-and-sweep is currently a hack. - * If we don't have a thread, the entire mark-and-sweep is now - * skipped (although we could just skip finalizations). + /* If debugger is paused, garbage collection is disabled by default. + * This is achieved by bumping ms_prevent_count when becoming paused. */ + DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) || heap->ms_prevent_count > 0); - /* If thr != NULL, the thr may still be in the middle of - * initialization. - * XXX: Improve the thread viability test. + /* Prevention/recursion check as soon as possible because we may + * be called a number of times when voluntary mark-and-sweep is + * pending. */ - thr = duk__get_temp_hthread(heap); - if (thr == NULL) { - DUK_D(DUK_DPRINT("gc skipped because we don't have a temp thread")); - - /* reset voluntary gc trigger count */ -#if defined(DUK_USE_VOLUNTARY_GC) - heap->mark_and_sweep_trigger_counter = DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP; -#endif - return 0; /* OK */ + if (heap->ms_prevent_count != 0) { + DUK_DD(DUK_DDPRINT("reject recursive mark-and-sweep")); + return; } + DUK_ASSERT(heap->ms_running == 0); /* ms_prevent_count is bumped when ms_running is set */ - /* If debugger is paused, garbage collection is disabled by default. */ - /* XXX: will need a force flag if garbage collection is triggered - * explicitly during paused state. + /* Heap_thread is used during mark-and-sweep for refcount finalization + * (it's also used for finalizer execution once mark-and-sweep is + * complete). Heap allocation code ensures heap_thread is set and + * properly initialized before setting ms_prevent_count to 0. */ -#if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_HEAP_IS_PAUSED(heap)) { - /* Checking this here rather that in memory alloc primitives - * reduces checking code there but means a failed allocation - * will go through a few retries before giving up. That's - * fine because this only happens during debugging. - */ - DUK_D(DUK_DPRINT("gc skipped because debugger is paused")); - return 0; - } -#endif + DUK_ASSERT(heap->heap_thread != NULL); + DUK_ASSERT(heap->heap_thread->valstack != NULL); + DUK_ASSERT(heap->heap_thread->callstack != NULL); + DUK_ASSERT(heap->heap_thread->catchstack != NULL); DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) starting, requested flags: 0x%08lx, effective flags: 0x%08lx", - (unsigned long) flags, (unsigned long) (flags | heap->mark_and_sweep_base_flags))); + (unsigned long) flags, (unsigned long) (flags | heap->ms_base_flags))); - flags |= heap->mark_and_sweep_base_flags; + flags |= heap->ms_base_flags; +#if defined(DUK_USE_FINALIZER_SUPPORT) + if (heap->finalize_list != NULL) { + flags |= DUK_MS_FLAG_POSTPONE_RESCUE; + } +#endif /* * Assertions before */ #if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)); + DUK_ASSERT(heap->ms_prevent_count == 0); + DUK_ASSERT(heap->ms_running == 0); + DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(heap)); DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)); - DUK_ASSERT(heap->mark_and_sweep_recursion_depth == 0); + DUK_ASSERT(heap->ms_recursion_depth == 0); duk__assert_heaphdr_flags(heap); #if defined(DUK_USE_REFERENCE_COUNTING) - /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount + /* Note: heap->refzero_free_running may be true; a refcount * finalizer may trigger a mark-and-sweep. */ duk__assert_valid_refcounts(heap); @@ -45858,7 +47574,10 @@ * Begin */ - DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap); + DUK_ASSERT(heap->ms_prevent_count == 0); + DUK_ASSERT(heap->ms_running == 0); + heap->ms_prevent_count = 1; + heap->ms_running = 1; /* * Mark roots, hoping that recursion limit is not normally hit. @@ -45876,17 +47595,20 @@ * previous run had finalizer skip flag. */ - duk__mark_roots_heap(heap); /* main reachability roots */ +#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) + duk__clear_assert_refcounts(heap); +#endif + duk__mark_roots_heap(heap); /* Mark main reachability roots. */ #if defined(DUK_USE_REFERENCE_COUNTING) - duk__mark_refzero_list(heap); /* refzero_list treated as reachability roots */ + DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ #endif - duk__mark_temproots_by_heap_scan(heap); /* temproots */ + duk__mark_temproots_by_heap_scan(heap); /* Temproots. */ #if defined(DUK_USE_FINALIZER_SUPPORT) - duk__mark_finalizable(heap); /* mark finalizable as reachability roots */ - duk__mark_finalize_list(heap); /* mark finalizer work list as reachability roots */ + duk__mark_finalizable(heap); /* Mark finalizable as reachability roots. */ + duk__mark_finalize_list(heap); /* Mark finalizer work list as reachability roots. */ #endif - duk__mark_temproots_by_heap_scan(heap); /* temproots */ + duk__mark_temproots_by_heap_scan(heap); /* Temproots. */ /* * Sweep garbage and remove marking flags, and move objects with @@ -45908,15 +47630,12 @@ duk__finalize_refcounts(heap); #endif duk__sweep_heap(heap, flags, &count_keep_obj); -#if defined(DUK_USE_STRTAB_CHAIN) - duk__sweep_stringtable_chain(heap, &count_keep_str); -#elif defined(DUK_USE_STRTAB_PROBE) - duk__sweep_stringtable_probe(heap, &count_keep_str); -#else -#error internal error, invalid strtab options + duk__sweep_stringtable(heap, &count_keep_str); +#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) + duk__check_assert_refcounts(heap); #endif #if defined(DUK_USE_REFERENCE_COUNTING) - duk__clear_refzero_list_flags(heap); + DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ #endif #if defined(DUK_USE_FINALIZER_SUPPORT) duk__clear_finalize_list_flags(heap); @@ -45947,94 +47666,39 @@ /* * String table resize check. * - * Note: this may silently (and safely) fail if GC is caused by an - * allocation call in stringtable resize_hash(). Resize_hash() - * will prevent a recursive call to itself by setting the - * DUK_MS_FLAG_NO_STRINGTABLE_RESIZE in heap->mark_and_sweep_base_flags. - */ - - /* XXX: stringtable emergency compaction? */ - - /* XXX: remove this feature entirely? it would only matter for - * emergency GC. Disable for lowest memory builds. - */ -#if defined(DUK_USE_MS_STRINGTABLE_RESIZE) - if (!(flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE)) { - DUK_DD(DUK_DDPRINT("resize stringtable: %p", (void *) heap)); - duk_heap_force_strtab_resize(heap); - } else { - DUK_D(DUK_DPRINT("stringtable resize skipped because DUK_MS_FLAG_NO_STRINGTABLE_RESIZE is set")); - } -#endif - - /* - * Finalize objects in the finalization work list. Finalized - * objects are queued back to heap_allocated with FINALIZED set. - * - * Since finalizers may cause arbitrary side effects, they are - * prevented during string table and object property allocation - * resizing using the DUK_MS_FLAG_NO_FINALIZERS flag in - * heap->mark_and_sweep_base_flags. In this case the objects - * remain in the finalization work list after mark-and-sweep - * exits and they may be finalized on the next pass. - * - * Finalization currently happens inside "MARKANDSWEEP_RUNNING" - * protection (no mark-and-sweep may be triggered by the - * finalizers). As a side effect: - * - * 1) an out-of-memory error inside a finalizer will not - * cause a mark-and-sweep and may cause the finalizer - * to fail unnecessarily - * - * 2) any temporary objects whose refcount decreases to zero - * during finalization will not be put into refzero_list; - * they can only be collected by another mark-and-sweep - * - * This is not optimal, but since the sweep for this phase has - * already happened, this is probably good enough for now. + * This is mainly useful in emergency GC: if the string table load + * factor is really low for some reason, we can shrink the string + * table to a smaller size and free some memory in the process. + * Only execute in emergency GC. String table has internal flags + * to protect against recursive resizing if this mark-and-sweep pass + * was triggered by a string table resize. */ -#if defined(DUK_USE_FINALIZER_SUPPORT) -#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE) - /* Cannot simulate individual finalizers because finalize_list only - * contains objects with actual finalizers. But simulate side effects - * from finalization by doing a bogus function call and resizing the - * stacks. - */ - if (flags & DUK_MS_FLAG_NO_FINALIZERS) { - DUK_D(DUK_DPRINT("skip mark-and-sweep torture finalizer, DUK_MS_FLAG_NO_FINALIZERS is set")); - } else if (!(thr->valstack != NULL && thr->callstack != NULL && thr->catchstack != NULL)) { - DUK_D(DUK_DPRINT("skip mark-and-sweep torture finalizer, thread not yet viable")); - } else { - DUK_D(DUK_DPRINT("run mark-and-sweep torture finalizer")); - duk__markandsweep_torture_finalizer(thr); - } -#endif /* DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE */ - - if (flags & DUK_MS_FLAG_NO_FINALIZERS) { - DUK_D(DUK_DPRINT("finalizer run skipped because DUK_MS_FLAG_NO_FINALIZERS is set")); - } else { - duk__run_object_finalizers(heap, flags); + if (flags & DUK_MS_FLAG_EMERGENCY) { + DUK_D(DUK_DPRINT("stringtable resize check in emergency gc")); + duk_heap_strtable_force_resize(heap); } -#endif /* DUK_USE_FINALIZER_SUPPORT */ /* * Finish */ - DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap); + DUK_ASSERT(heap->ms_prevent_count == 1); + heap->ms_prevent_count = 0; + DUK_ASSERT(heap->ms_running == 1); + heap->ms_running = 0; /* * Assertions after */ #if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)); + DUK_ASSERT(heap->ms_prevent_count == 0); DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)); - DUK_ASSERT(heap->mark_and_sweep_recursion_depth == 0); + DUK_ASSERT(heap->ms_recursion_depth == 0); duk__assert_heaphdr_flags(heap); #if defined(DUK_USE_REFERENCE_COUNTING) - /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount + /* Note: heap->refzero_free_running may be true; a refcount * finalizer may trigger a mark-and-sweep. */ duk__assert_valid_refcounts(heap); @@ -46047,17 +47711,49 @@ #if defined(DUK_USE_VOLUNTARY_GC) tmp = (count_keep_obj + count_keep_str) / 256; - heap->mark_and_sweep_trigger_counter = (duk_int_t) ( + heap->ms_trigger_counter = (duk_int_t) ( (tmp * DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT) + DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD); DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, trigger reset to %ld", - (long) count_keep_obj, (long) count_keep_str, (long) heap->mark_and_sweep_trigger_counter)); + (long) count_keep_obj, (long) count_keep_str, (long) heap->ms_trigger_counter)); #else DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, no voluntary trigger", (long) count_keep_obj, (long) count_keep_str)); #endif - return 0; /* OK */ + /* + * Finalize objects in the finalization work list. Finalized + * objects are queued back to heap_allocated with FINALIZED set. + * + * Since finalizers may cause arbitrary side effects, they are + * prevented e.g. during string table and object property allocation + * resizing using heap->pf_prevent_count. In this case the objects + * remain in the finalization work list after mark-and-sweep exits + * and they may be finalized on the next pass or any DECREF checking + * for finalize_list. + * + * As of Duktape 2.1 finalization happens outside mark-and-sweep + * protection. Mark-and-sweep is allowed while the finalize_list + * is being processed, but no rescue decisions are done while the + * process is on-going. This avoids incorrect rescue decisions + * if an object is considered reachable (and thus rescued) because + * of a reference via finalize_list (which is considered a reachability + * root). When finalize_list is being processed, reachable objects + * with FINALIZED set will just keep their FINALIZED flag for later + * mark-and-sweep processing. + * + * This could also be handled (a bit better) by having a more refined + * notion of reachability for rescue/free decisions. + * + * XXX: avoid finalizer execution when doing emergency GC? + */ + +#if defined(DUK_USE_FINALIZER_SUPPORT) + /* Attempt to process finalize_list, pf_prevent_count check + * is inside the target. + */ + duk_heap_process_finalize_list(heap); +#endif /* DUK_USE_FINALIZER_SUPPORT */ } #line 1 "duk_heap_memory.c" /* @@ -46067,34 +47763,28 @@ /* #include duk_internal.h -> already included */ /* - * Helpers - * - * The fast path checks are done within a macro to ensure "inlining" - * while the slow path actions use a helper (which won't typically be - * inlined in size optimized builds). + * Voluntary GC check */ #if defined(DUK_USE_VOLUNTARY_GC) -#define DUK__VOLUNTARY_PERIODIC_GC(heap) do { \ - (heap)->mark_and_sweep_trigger_counter--; \ - if ((heap)->mark_and_sweep_trigger_counter <= 0) { \ - duk__run_voluntary_gc(heap); \ - } \ - } while (0) - -DUK_LOCAL void duk__run_voluntary_gc(duk_heap *heap) { - if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { - DUK_DD(DUK_DDPRINT("mark-and-sweep in progress -> skip voluntary mark-and-sweep now")); - } else { - duk_small_uint_t flags; - duk_bool_t rc; +DUK_LOCAL DUK_INLINE void duk__check_voluntary_gc(duk_heap *heap) { + if (DUK_UNLIKELY(--(heap)->ms_trigger_counter < 0)) { +#if defined(DUK_USE_DEBUG) + if (heap->ms_prevent_count == 0) { + DUK_D(DUK_DPRINT("triggering voluntary mark-and-sweep")); + } else { + DUK_DD(DUK_DDPRINT("gc blocked -> skip voluntary mark-and-sweep now")); + } +#endif - DUK_D(DUK_DPRINT("triggering voluntary mark-and-sweep")); - flags = 0; - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); + /* Prevention checks in the call target handle cases where + * voluntary GC is not allowed. The voluntary GC trigger + * counter is only rewritten if mark-and-sweep actually runs. + */ + duk_heap_mark_and_sweep(heap, DUK_MS_FLAG_VOLUNTARY /*flags*/); } } +#define DUK__VOLUNTARY_PERIODIC_GC(heap) do { duk__check_voluntary_gc((heap)); } while (0) #else #define DUK__VOLUNTARY_PERIODIC_GC(heap) /* no voluntary gc */ #endif /* DUK_USE_VOLUNTARY_GC */ @@ -46105,7 +47795,6 @@ DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) { void *res; - duk_bool_t rc; duk_small_int_t i; DUK_ASSERT(heap != NULL); @@ -46123,7 +47812,7 @@ #if defined(DUK_USE_GC_TORTURE) /* simulate alloc failure on every alloc (except when mark-and-sweep is running) */ - if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + if (heap->ms_prevent_count == 0) { DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first alloc attempt fails")); res = NULL; DUK_UNREF(res); @@ -46131,7 +47820,7 @@ } #endif res = heap->alloc_func(heap->heap_udata, size); - if (res || size == 0) { + if (DUK_LIKELY(res || size == 0)) { /* for zero size allocations NULL is allowed */ return res; } @@ -46141,16 +47830,22 @@ DUK_D(DUK_DPRINT("first alloc attempt failed, attempt to gc and retry")); +#if 0 /* * Avoid a GC if GC is already running. This can happen at a late * stage in a GC when we try to e.g. resize the stringtable * or compact objects. + * + * NOTE: explicit handling isn't actually be needed: if the GC is + * not allowed, duk_heap_mark_and_sweep() will reject it for every + * attempt in the loop below, resulting in a NULL same as here. */ - if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + 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 @@ -46166,8 +47861,7 @@ flags |= DUK_MS_FLAG_EMERGENCY; } - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); + duk_heap_mark_and_sweep(heap, flags); res = heap->alloc_func(heap->heap_udata, size); if (res) { @@ -46188,20 +47882,43 @@ DUK_ASSERT_DISABLE(size >= 0); res = DUK_ALLOC(heap, size); - if (res) { + if (DUK_LIKELY(res != NULL)) { /* assume memset with zero size is OK */ DUK_MEMZERO(res, size); } return res; } +DUK_INTERNAL void *duk_heap_mem_alloc_checked(duk_hthread *thr, duk_size_t size) { + void *res; + + DUK_ASSERT(thr != NULL); + res = duk_heap_mem_alloc(thr->heap, size); + if (DUK_LIKELY(res != NULL || size == 0)) { + return res; + } + DUK_ERROR_ALLOC_FAILED(thr); + return NULL; +} + +DUK_INTERNAL void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, duk_size_t size) { + void *res; + + DUK_ASSERT(thr != NULL); + res = duk_heap_mem_alloc_zeroed(thr->heap, size); + if (DUK_LIKELY(res != NULL || size == 0)) { + return res; + } + DUK_ERROR_ALLOC_FAILED(thr); + return NULL; +} + /* * Reallocate memory with garbage collection */ DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize) { void *res; - duk_bool_t rc; duk_small_int_t i; DUK_ASSERT(heap != NULL); @@ -46220,7 +47937,7 @@ #if defined(DUK_USE_GC_TORTURE) /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */ - if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + if (heap->ms_prevent_count == 0) { DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first realloc attempt fails")); res = NULL; DUK_UNREF(res); @@ -46228,7 +47945,7 @@ } #endif res = heap->realloc_func(heap->heap_udata, ptr, newsize); - if (res || newsize == 0) { + if (DUK_LIKELY(res || newsize == 0)) { /* for zero size allocations NULL is allowed */ return res; } @@ -46238,14 +47955,16 @@ 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 (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + 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 @@ -46261,8 +47980,7 @@ flags |= DUK_MS_FLAG_EMERGENCY; } - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); + duk_heap_mark_and_sweep(heap, flags); res = heap->realloc_func(heap->heap_udata, ptr, newsize); if (res || newsize == 0) { @@ -46284,7 +48002,6 @@ DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize) { void *res; - duk_bool_t rc; duk_small_int_t i; DUK_ASSERT(heap != NULL); @@ -46302,7 +48019,7 @@ #if defined(DUK_USE_GC_TORTURE) /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */ - if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + 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); @@ -46310,7 +48027,7 @@ } #endif res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize); - if (res || newsize == 0) { + if (DUK_LIKELY(res || newsize == 0)) { /* for zero size allocations NULL is allowed */ return res; } @@ -46320,14 +48037,16 @@ 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 (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + 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 @@ -46351,8 +48070,7 @@ flags |= DUK_MS_FLAG_EMERGENCY; } - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); + duk_heap_mark_and_sweep(heap, flags); #if defined(DUK_USE_ASSERTIONS) ptr_post = cb(heap, ud); if (ptr_pre != ptr_post) { @@ -46391,14 +48109,10 @@ */ heap->free_func(heap->heap_udata, ptr); - /* Count free operations toward triggering a GC but never actually trigger - * a GC from a free. Otherwise code which frees internal structures would - * need to put in NULLs at every turn to ensure the object is always in - * consistent state for a mark-and-sweep. + /* 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. */ -#if defined(DUK_USE_VOLUNTARY_GC) - heap->mark_and_sweep_trigger_counter--; -#endif } /* automatic undefs */ @@ -46410,44 +48124,146 @@ /* #include duk_internal.h -> already included */ -#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING) -/* arbitrary remove only works with double linked heap, and is only required by - * reference counting so far. - */ -DUK_INTERNAL void duk_heap_remove_any_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) { +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_ASSERT_HEAPHDR_LINKS(heap, hdr); + DUK_ASSERT_HEAPHDR_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); - if (DUK_HEAPHDR_GET_PREV(heap, hdr)) { - DUK_HEAPHDR_SET_NEXT(heap, DUK_HEAPHDR_GET_PREV(heap, hdr), DUK_HEAPHDR_GET_NEXT(heap, hdr)); + /* 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 { - heap->heap_allocated = DUK_HEAPHDR_GET_NEXT(heap, hdr); + DUK_ASSERT(heap->heap_allocated == hdr); + heap->heap_allocated = next; } - if (DUK_HEAPHDR_GET_NEXT(heap, hdr)) { - DUK_HEAPHDR_SET_PREV(heap, DUK_HEAPHDR_GET_NEXT(heap, hdr), DUK_HEAPHDR_GET_PREV(heap, hdr)); + if (next != NULL) { + DUK_HEAPHDR_SET_PREV(heap, next, prev); } else { ; } - - /* The prev/next pointers of the removed duk_heaphdr are left as garbage. - * It's up to the caller to ensure they're written before inserting the - * object back. - */ } -#endif +#endif /* DUK_USE_REFERENCE_COUNTING */ -DUK_INTERNAL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) { - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING); +#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) - if (heap->heap_allocated) { - DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, heap->heap_allocated) == NULL); - DUK_HEAPHDR_SET_PREV(heap, heap->heap_allocated, hdr); - } 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_ASSERT_HEAPHDR_LINKS(heap, hdr); + DUK_ASSERT_HEAPHDR_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 - DUK_HEAPHDR_SET_NEXT(heap, hdr, heap->heap_allocated); - heap->heap_allocated = hdr; } +#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) { @@ -46486,6 +48302,10 @@ #line 1 "duk_heap_refcount.c" /* * 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 duk_internal.h -> already included */ @@ -46497,36 +48317,6 @@ #endif /* - * Misc - */ - -DUK_LOCAL void duk__queue_refzero(duk_heap *heap, duk_heaphdr *hdr) { - /* tail insert: don't disturb head in case refzero is running */ - - if (heap->refzero_list != NULL) { - duk_heaphdr *hdr_prev; - - hdr_prev = heap->refzero_list_tail; - DUK_ASSERT(hdr_prev != NULL); - DUK_ASSERT(DUK_HEAPHDR_GET_NEXT(heap, hdr_prev) == NULL); - - DUK_HEAPHDR_SET_NEXT(heap, hdr, NULL); - DUK_HEAPHDR_SET_PREV(heap, hdr, hdr_prev); - DUK_HEAPHDR_SET_NEXT(heap, hdr_prev, hdr); - DUK_ASSERT_HEAPHDR_LINKS(heap, hdr); - DUK_ASSERT_HEAPHDR_LINKS(heap, hdr_prev); - heap->refzero_list_tail = hdr; - } else { - DUK_ASSERT(heap->refzero_list_tail == NULL); - DUK_HEAPHDR_SET_NEXT(heap, hdr, NULL); - DUK_HEAPHDR_SET_PREV(heap, hdr, NULL); - DUK_ASSERT_HEAPHDR_LINKS(heap, hdr); - heap->refzero_list = hdr; - heap->refzero_list_tail = hdr; - } -} - -/* * Heap object refcount finalization. * * When an object is about to be freed, all other objects it refers to must @@ -46534,41 +48324,47 @@ * allocations (mark-and-sweep shares these helpers), it just manipulates * the refcounts. * - * Note that any of the decref's may cause a refcount to drop to zero, BUT - * it will not be processed inline. If refcount finalization is triggered - * by refzero processing, the objects will be just queued to the refzero - * list and processed later which eliminates C recursion. If refcount - * finalization is triggered by mark-and-sweep, any refzero situations are - * ignored because mark-and-sweep will deal with them. NORZ variants can - * be used here in both cases. + * 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__refcount_finalize_hobject(duk_hthread *thr, duk_hobject *h) { +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); - /* XXX: better to get base and walk forwards? */ + thr = heap->heap_thread; + DUK_ASSERT(thr != NULL); - p_key = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, h); - p_val = DUK_HOBJECT_E_GET_VALUE_BASE(thr->heap, h); - p_flag = DUK_HOBJECT_E_GET_FLAGS_BASE(thr->heap, h); + 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 (!key) { + if (DUK_UNLIKELY(key == NULL)) { continue; } DUK_HSTRING_DECREF_NORZ(thr, key); - if (p_flag[n] & DUK_PROPDESC_FLAG_ACCESSOR) { + 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)); @@ -46583,7 +48379,7 @@ } } - p_tv = DUK_HOBJECT_A_GET_BASE(thr->heap, h); + p_tv = DUK_HOBJECT_A_GET_BASE(heap, h); n = DUK_HOBJECT_GET_ASIZE(h); while (n-- > 0) { duk_tval *tv_val; @@ -46591,39 +48387,49 @@ DUK_TVAL_DECREF_NORZ(thr, tv_val); } - /* hash part is a 'weak reference' and does not contribute */ + /* Hash part is a 'weak reference' and doesn't contribute to refcounts. */ - { - duk_hobject *h_proto; - h_proto = (duk_hobject *) DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h); - DUK_ASSERT(h_proto == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_proto)); - DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_proto); + 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)); - /* XXX: rearrange bits to allow a switch case to be used here? */ - /* XXX: add a fast path for objects (and arrays)? */ + /* Slow path: special object, start bit checks from most likely. */ - /* DUK_HOBJECT_IS_ARRAY(h): needs no special handling now as there are - * no extra fields in need of decref. - */ if (DUK_HOBJECT_IS_COMPFUNC(h)) { duk_hcompfunc *f = (duk_hcompfunc *) h; duk_tval *tv, *tv_end; duk_hobject **funcs, **funcs_end; - if (DUK_HCOMPFUNC_GET_DATA(thr->heap, f) != NULL) { - tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, f); - tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, 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(thr->heap, f); - funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, f); + 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++; @@ -46633,13 +48439,19 @@ DUK_D(DUK_DPRINT("duk_hcompfunc 'data' is NULL, skipping decref")); } - DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_heaphdr *) DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f)); - DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_heaphdr *) DUK_HCOMPFUNC_GET_VARENV(thr->heap, f)); - DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(thr->heap, f)); - } else if (DUK_HOBJECT_IS_NATFUNC(h)) { - duk_hnatfunc *f = (duk_hnatfunc *) h; - DUK_UNREF(f); - /* nothing to finalize */ + 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_ASSERT_HDECENV_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_ASSERT_HOBJENV_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; @@ -46677,264 +48489,284 @@ } 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(duk_hthread *thr, duk_heaphdr *hdr) { - DUK_ASSERT(hdr); +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_GET_TYPE(hdr) == DUK_HTYPE_OBJECT) { - duk__refcount_finalize_hobject(thr, (duk_hobject *) hdr); + 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 */ } -#if defined(DUK_USE_FINALIZER_SUPPORT) -#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE) -DUK_LOCAL duk_ret_t duk__refcount_fake_finalizer(duk_context *ctx) { - DUK_UNREF(ctx); - DUK_D(DUK_DPRINT("fake refcount torture finalizer executed")); -#if 0 - DUK_DD(DUK_DDPRINT("fake torture finalizer for: %!T", duk_get_tval(ctx, 0))); -#endif - /* Require a lot of stack to force a value stack grow/shrink. */ - duk_require_stack(ctx, 100000); - - /* XXX: do something to force a callstack grow/shrink, perhaps - * just a manual forced resize? - */ - return 0; -} - -DUK_LOCAL void duk__refcount_run_torture_finalizer(duk_hthread *thr, duk_hobject *obj) { - duk_context *ctx; - duk_int_t rc; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(obj != NULL); - ctx = (duk_context *) thr; - - /* Avoid fake finalization for the duk__refcount_fake_finalizer function - * itself, otherwise we're in infinite recursion. - */ - if (DUK_HOBJECT_HAS_NATFUNC(obj)) { - if (((duk_hnatfunc *) obj)->func == duk__refcount_fake_finalizer) { - DUK_DD(DUK_DDPRINT("avoid fake torture finalizer for duk__refcount_fake_finalizer itself")); - return; - } - } - /* Avoid fake finalization when callstack limit has been reached. - * Otherwise a callstack limit error will be created, then refzero'ed, - * and we're in an infinite loop. - */ - if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit || - thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) { - DUK_D(DUK_DPRINT("call recursion depth reached, avoid fake torture finalizer")); - return; - } - - /* Run fake finalizer. Avoid creating new refzero queue entries - * so that we are not forced into a forever loop. - */ - duk_push_c_function(ctx, duk__refcount_fake_finalizer, 1 /*nargs*/); - duk_push_hobject(ctx, obj); - rc = duk_pcall(ctx, 1); - DUK_UNREF(rc); /* ignored */ - duk_pop(ctx); -} -#endif /* DUK_USE_REFZERO_FINALIZER_TORTURE */ -#endif /* DUK_USE_FINALIZER_SUPPORT */ - /* - * Refcount memory freeing loop. - * - * Frees objects in the refzero_pending list until the list becomes - * empty. When an object is freed, its references get decref'd and - * may cause further objects to be queued for freeing. + * 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. + * 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_INTERNAL void duk_refzero_free_pending(duk_hthread *thr) { - duk_heaphdr *h1, *h2; - duk_heap *heap; +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(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - heap = thr->heap; DUK_ASSERT(heap != NULL); - /* - * Detect recursive invocation - */ + 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. */ - if (DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap)) { - DUK_DDD(DUK_DDDPRINT("refzero free running, skip run")); - return; - } + do { + duk_heaphdr *prev; - /* - * Churn refzero_list until empty - */ + DUK_DDD(DUK_DDDPRINT("refzero processing %p: %!O", (void *) curr, (duk_heaphdr *) curr)); - DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap); - while (heap->refzero_list) { - duk_hobject *obj; -#if defined(DUK_USE_FINALIZER_SUPPORT) - duk_bool_t rescued = 0; -#endif /* DUK_USE_FINALIZER_SUPPORT */ +#if defined(DUK_USE_DEBUG) + count++; +#endif - /* - * Pick an object from the head (don't remove yet). + 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); - h1 = heap->refzero_list; - obj = (duk_hobject *) h1; - DUK_DD(DUK_DDPRINT("refzero processing %p: %!O", (void *) h1, (duk_heaphdr *) h1)); - DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, h1) == NULL); - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(h1) == DUK_HTYPE_OBJECT); /* currently, always the case */ + 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. */ -#if defined(DUK_USE_FINALIZER_SUPPORT) -#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE) - /* Torture option to shake out finalizer side effect issues: - * make a bogus function call for every finalizable object, - * essentially simulating the case where everything has a - * finalizer. - */ - DUK_DD(DUK_DDPRINT("refzero torture enabled, fake finalizer")); - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h1) == 0); - DUK_HEAPHDR_PREINC_REFCOUNT(h1); /* bump refcount to prevent refzero during finalizer processing */ - duk__refcount_run_torture_finalizer(thr, obj); /* must never longjmp */ - DUK_HEAPHDR_PREDEC_REFCOUNT(h1); /* remove artificial bump */ - DUK_ASSERT_DISABLE(h1->h_refcount >= 0); /* refcount is unsigned, so always true */ -#endif /* DUK_USE_REFZERO_FINALIZER_TORTURE */ -#endif /* DUK_USE_FINALIZER_SUPPORT */ + duk_free_hobject(heap, (duk_hobject *) curr); /* Invalidates 'curr'. */ - /* - * Finalizer check. - * - * Note: running a finalizer may have arbitrary side effects, e.g. - * queue more objects on refzero_list (tail), or even trigger a - * mark-and-sweep. - * - * Note: quick reject check should match vast majority of - * objects and must be safe (not throw any errors, ever). - * - * An object may have FINALIZED here if it was finalized by mark-and-sweep - * on a previous run and refcount then decreased to zero. We won't run the - * finalizer again here. - * - * A finalizer is looked up from the object and up its prototype chain - * (which allows inherited finalizers). - */ + curr = prev; + } while (curr != NULL); -#if defined(DUK_USE_FINALIZER_SUPPORT) - if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) { - DUK_DDD(DUK_DDDPRINT("object has a finalizer, run it")); + 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(DUK_HEAPHDR_GET_REFCOUNT(h1) == 0); - DUK_HEAPHDR_PREINC_REFCOUNT(h1); /* bump refcount to prevent refzero during finalizer processing */ + 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); - duk_hobject_run_finalizer(thr, obj); /* must never longjmp */ - DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1)); /* duk_hobject_run_finalizer() sets */ + hdr = (duk_heaphdr *) obj; - DUK_HEAPHDR_PREDEC_REFCOUNT(h1); /* remove artificial bump */ - DUK_ASSERT_DISABLE(h1->h_refcount >= 0); /* refcount is unsigned, so always true */ + /* 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 - if (DUK_HEAPHDR_GET_REFCOUNT(h1) != 0) { - DUK_DDD(DUK_DDDPRINT("-> object refcount after finalization non-zero, object will be rescued")); - rescued = 1; - } else { - DUK_DDD(DUK_DDDPRINT("-> object refcount still zero after finalization, object will be freed")); + 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))) { + /* 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 */ - /* Refzero head is still the same. This is the case even if finalizer - * inserted more refzero objects; they are inserted to the tail. - */ - DUK_ASSERT(h1 == heap->refzero_list); + /* No need to finalize, free object via refzero_list. */ - /* - * Remove the object from the refzero list. This cannot be done - * before a possible finalizer has been executed; the finalizer - * may trigger a mark-and-sweep, and mark-and-sweep must be able - * to traverse a complete refzero_list. - */ + root = heap->refzero_list; - h2 = DUK_HEAPHDR_GET_NEXT(heap, h1); - if (h2) { - DUK_HEAPHDR_SET_PREV(heap, h2, NULL); /* not strictly necessary */ - heap->refzero_list = h2; - } else { - heap->refzero_list = NULL; - heap->refzero_list_tail = NULL; - } + DUK_HEAPHDR_SET_PREV(heap, hdr, NULL); + /* 'next' is left as GARBAGE. */ + heap->refzero_list = hdr; - /* - * Rescue or free. + 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 (rescued) { - /* yes -> move back to heap allocated */ - DUK_DD(DUK_DDPRINT("object rescued during refcount finalization: %p", (void *) h1)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(h1)); - DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1)); - DUK_HEAPHDR_CLEAR_FINALIZED(h1); - h2 = heap->heap_allocated; - DUK_HEAPHDR_SET_PREV(heap, h1, NULL); - if (h2) { - DUK_HEAPHDR_SET_PREV(heap, h2, h1); - } - DUK_HEAPHDR_SET_NEXT(heap, h1, h2); - DUK_ASSERT_HEAPHDR_LINKS(heap, h1); - DUK_ASSERT_HEAPHDR_LINKS(heap, h2); - heap->heap_allocated = h1; - } else -#endif /* DUK_USE_FINALIZER_SUPPORT */ - { - /* no -> decref members, then free */ - duk__refcount_finalize_hobject(thr, obj); - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(h1) == DUK_HTYPE_OBJECT); /* currently, always the case */ - duk_free_hobject(heap, (duk_hobject *) h1); + 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); - count++; + /* 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. + */ } - DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap); +} - DUK_DDD(DUK_DDDPRINT("refzero processed %ld objects", (long) count)); +#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. */ - /* - * Once the whole refzero cascade has been freed, check for - * a voluntary mark-and-sweep. - */ + if (DUK_UNLIKELY(thr->heap->finalize_list != NULL)) { + duk_heap_process_finalize_list(thr->heap); + } +} -#if defined(DUK_USE_VOLUNTARY_GC) - /* 'count' is more or less comparable to normal trigger counter update - * which happens in memory block (re)allocation. - */ - heap->mark_and_sweep_trigger_counter -= count; - if (heap->mark_and_sweep_trigger_counter <= 0) { - duk_bool_t rc; - duk_small_uint_t flags = 0; /* not emergency */ - DUK_D(DUK_DPRINT("refcount triggering mark-and-sweep")); - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); - DUK_D(DUK_DPRINT("refcount triggered mark-and-sweep => rc %ld", (long) rc)); +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_VOLUNTARY_GC */ +} +#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. + * 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, @@ -46947,46 +48779,67 @@ * mark-and-sweep also calls finalizers which would use the ordinary decref * macros anyway. * - * The DUK__RZ_SUPPRESS_CHECK() must be enabled also when mark-and-sweep - * support has been disabled: the flag is also used in heap destruction when - * running finalizers for remaining objects, and the flag prevents objects - * from being moved around in heap linked lists. + * 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. */ -/* The suppress condition is important to performance. The flags being tested - * are in the same duk_heap field so a single TEST instruction (on x86) tests - * for them. - */ +#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); \ + /* When mark-and-sweep runs, the 'thr' argument always matches heap_thread. \ + * This could be used to e.g. suppress check against 'thr' directly (and \ + * knowing it would be heap_thread); not really used now. \ + */ \ + DUK_ASSERT(thr->heap->ms_running == 0 || 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_COND() \ - (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) || DUK_HEAP_IS_PAUSED(heap)) +#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_COND() \ - (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) -#endif +#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 when mark-and-sweep running, object: %p", (void *) h)); \ + 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_heap_strcache_string_remove(thr->heap, (duk_hstring *) h); \ - duk_heap_string_remove(heap, (duk_hstring *) h); \ - duk_free_hstring(heap, (duk_hstring *) h); \ + duk__refcount_refzero_hstring(heap, (duk_hstring *) h); \ } while (0) #define DUK__RZ_BUFFER() do { \ - duk_heap_remove_any_from_heap_allocated(heap, (duk_heaphdr *) h); \ - duk_free_hbuffer(heap, (duk_hbuffer *) h); \ + duk__refcount_refzero_hbuffer(heap, (duk_hbuffer *) h); \ } while (0) #define DUK__RZ_OBJECT() do { \ - duk_heap_remove_any_from_heap_allocated(heap, (duk_heaphdr *) h); \ - duk__queue_refzero(heap, (duk_heaphdr *) h); \ - if (!skip_free_pending) { \ - duk_refzero_free_pending(thr); \ - } \ + 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 @@ -47056,42 +48909,39 @@ DUK__RZ_OBJECT(); break; - case DUK_HTYPE_BUFFER: + 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; - - default: - DUK_D(DUK_DPRINT("invalid heap type in decref: %ld", (long) DUK_HEAPHDR_GET_TYPE(h))); - DUK_UNREACHABLE(); } } -DUK_INTERNAL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h) { +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 void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h) { +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 void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h) { +DUK_INTERNAL DUK_NOINLINE void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h) { duk__hstring_refzero_helper(thr, h); } -DUK_INTERNAL void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h) { +DUK_INTERNAL DUK_NOINLINE void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h) { duk__hbuffer_refzero_helper(thr, h); } -DUK_INTERNAL void duk_hobject_refzero(duk_hthread *thr, duk_hobject *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 void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h) { +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*/); } @@ -47105,6 +48955,7 @@ 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. */ } } @@ -47143,7 +48994,7 @@ } duk_heaphdr_refzero_norz(thr, h); #else - duk_heaphdr_decref(thr, h); + duk_heaphdr_decref_norz(thr, h); #endif } } @@ -47157,6 +49008,13 @@ 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; \ @@ -47166,6 +49024,10 @@ } \ } 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; \ @@ -47182,13 +49044,18 @@ DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0); - DUK_HEAPHDR_PREINC_REFCOUNT(h); + 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(); @@ -47239,10 +49106,13 @@ /* automatic undefs */ #undef DUK__DECREF_ASSERTS #undef DUK__DECREF_SHARED +#undef DUK__INCREF_SHARED #undef DUK__RZ_BUFFER #undef DUK__RZ_INLINE #undef DUK__RZ_OBJECT #undef DUK__RZ_STRING +#undef DUK__RZ_SUPPRESS_ASSERT1 +#undef DUK__RZ_SUPPRESS_ASSERT2 #undef DUK__RZ_SUPPRESS_CHECK #undef DUK__RZ_SUPPRESS_COND #line 1 "duk_heap_stringcache.c" @@ -47332,6 +49202,10 @@ * * 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) { @@ -47341,20 +49215,27 @@ duk_small_int_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; - if (char_offset > DUK_HSTRING_GET_CHARLEN(h)) { - goto error; - } - /* * For ASCII strings, the answer is simple. */ - if (DUK_HSTRING_IS_ASCII(h)) { - /* clen == blen -> pure ascii */ + 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; } @@ -47376,7 +49257,7 @@ heap = thr->heap; sce = NULL; - use_cache = (DUK_HSTRING_GET_CHARLEN(h) > DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT); + use_cache = (char_length > DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT); if (use_cache) { #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) @@ -47407,7 +49288,7 @@ DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h) >= char_offset); dist_start = char_offset; - dist_end = DUK_HSTRING_GET_CHARLEN(h) - 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); @@ -47480,12 +49361,12 @@ scan_done: - if (!p_found) { + 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 error; + goto scan_error; } DUK_ASSERT(p_found >= p_start); @@ -47540,65 +49421,177 @@ return byte_offset; - error: + scan_error: DUK_ERROR_INTERNAL(thr); return 0; } #line 1 "duk_heap_stringtable.c" /* - * Heap stringtable handling, string interning. + * Heap string table handling, string interning. */ /* #include duk_internal.h -> already included */ -#if defined(DUK_USE_STRTAB_PROBE) -#define DUK__HASH_INITIAL(hash,h_size) DUK_STRTAB_HASH_INITIAL((hash),(h_size)) -#define DUK__HASH_PROBE_STEP(hash) DUK_STRTAB_HASH_PROBE_STEP((hash)) -#define DUK__DELETED_MARKER(heap) DUK_STRTAB_DELETED_MARKER((heap)) +/* Resize checks not needed if minsize == maxsize, typical for low memory + * targets. + */ +#define DUK__STRTAB_RESIZE_CHECK +#if (DUK_USE_STRTAB_MINSIZE == DUK_USE_STRTAB_MAXSIZE) +#undef DUK__STRTAB_RESIZE_CHECK #endif -#define DUK__PREVENT_MS_SIDE_EFFECTS(heap) do { \ - (heap)->mark_and_sweep_base_flags |= \ - DUK_MS_FLAG_NO_STRINGTABLE_RESIZE | /* avoid recursive string table call */ \ - DUK_MS_FLAG_NO_FINALIZERS | /* avoid pressure to add/remove strings, invalidation of call data argument, etc. */ \ - DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid array abandoning which interns strings */ \ - } while (0) +#if defined(DUK_USE_STRTAB_PTRCOMP) +#define DUK__HEAPPTR_ENC16(heap,ptr) DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (ptr)) +#define DUK__HEAPPTR_DEC16(heap,val) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (val)) +#define DUK__GET_STRTABLE(heap) ((heap)->strtable16) +#else +#define DUK__HEAPPTR_ENC16(heap,ptr) (ptr) +#define DUK__HEAPPTR_DEC16(heap,val) (val) +#define DUK__GET_STRTABLE(heap) ((heap)->strtable) +#endif + +#define DUK__STRTAB_U32_MAX_STRLEN 10 /* 4'294'967'295 */ /* - * Create a hstring and insert into the heap. The created object - * is directly garbage collectable with reference count zero. + * Debug dump stringtable. + */ + +#if defined(DUK_USE_DEBUG) +DUK_INTERNAL void duk_heap_strtable_dump(duk_heap *heap) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *strtable; +#else + duk_hstring **strtable; +#endif + duk_uint32_t i; + duk_hstring *h; + duk_size_t count_total = 0; + duk_size_t count_chain; + duk_size_t count_chain_min = DUK_SIZE_MAX; + duk_size_t count_chain_max = 0; + duk_size_t count_len[8]; /* chain lengths from 0 to 7 */ + + if (heap == NULL) { + DUK_D(DUK_DPRINT("string table, heap=NULL")); + return; + } + + strtable = DUK__GET_STRTABLE(heap); + if (strtable == NULL) { + DUK_D(DUK_DPRINT("string table, strtab=NULL")); + return; + } + + DUK_MEMZERO((void *) count_len, sizeof(count_len)); + for (i = 0; i < heap->st_size; i++) { + h = DUK__HEAPPTR_DEC16(heap, strtable[i]); + count_chain = 0; + while (h != NULL) { + count_chain++; + h = h->hdr.h_next; + } + if (count_chain < sizeof(count_len) / sizeof(duk_size_t)) { + count_len[count_chain]++; + } + count_chain_max = (count_chain > count_chain_max ? count_chain : count_chain_max); + count_chain_min = (count_chain < count_chain_min ? count_chain : count_chain_min); + count_total += count_chain; + } + + DUK_D(DUK_DPRINT("string table, strtab=%p, count=%lu, chain min=%lu max=%lu avg=%lf: " + "counts: %lu %lu %lu %lu %lu %lu %lu %lu ...", + (void *) heap->strtable, (unsigned long) count_total, + (unsigned long) count_chain_min, (unsigned long) count_chain_max, + (double) count_total / (double) heap->st_size, + (unsigned long) count_len[0], (unsigned long) count_len[1], + (unsigned long) count_len[2], (unsigned long) count_len[3], + (unsigned long) count_len[4], (unsigned long) count_len[5], + (unsigned long) count_len[6], (unsigned long) count_len[7])); +} +#endif /* DUK_USE_DEBUG */ + +/* + * Assertion helper to ensure strtable is populated correctly. + */ + +#if defined(DUK_USE_ASSERTIONS) +DUK_LOCAL void duk__strtable_assert_checks(duk_heap *heap) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *strtable; +#else + duk_hstring **strtable; +#endif + duk_uint32_t i; + duk_hstring *h; + duk_size_t count = 0; + + DUK_ASSERT(heap != NULL); + + strtable = DUK__GET_STRTABLE(heap); + if (strtable != NULL) { + DUK_ASSERT(heap->st_size != 0); + DUK_ASSERT(heap->st_mask == heap->st_size - 1); + + for (i = 0; i < heap->st_size; i++) { + h = DUK__HEAPPTR_DEC16(heap, strtable[i]); + while (h != NULL) { + DUK_ASSERT((DUK_HSTRING_GET_HASH(h) & heap->st_mask) == i); + count++; + h = h->hdr.h_next; + } + } + } else { + DUK_ASSERT(heap->st_size == 0); + DUK_ASSERT(heap->st_mask == 0); + } + +#if defined(DUK__STRTAB_RESIZE_CHECK) + DUK_ASSERT(count == (duk_size_t) heap->st_count); +#endif +} +#endif /* DUK_USE_ASSERTIONS */ + +/* + * Allocate and initialize a duk_hstring. * - * The caller must place the interned string into the stringtable - * immediately (without chance of a longjmp); otherwise the string - * is lost. + * Returns a NULL if allocation or initialization fails for some reason. + * + * The string won't be inserted into the string table and isn't tracked in + * any way (link pointers will be NULL). The caller must place the string + * into the string table without any risk of a longjmp, otherwise the string + * is leaked. */ -DUK_LOCAL -duk_hstring *duk__alloc_init_hstring(duk_heap *heap, - const duk_uint8_t *str, - duk_uint32_t blen, - duk_uint32_t strhash, - const duk_uint8_t *extdata) { - duk_hstring *res = NULL; - duk_uint8_t *data; - duk_size_t alloc_size; +DUK_LOCAL duk_hstring *duk__strtable_alloc_hstring(duk_heap *heap, + const duk_uint8_t *str, + duk_uint32_t blen, + duk_uint32_t strhash, + const duk_uint8_t *extdata) { + duk_hstring *res; + const duk_uint8_t *data; #if !defined(DUK_USE_HSTRING_ARRIDX) duk_uarridx_t dummy; #endif - duk_uint32_t clen; + + DUK_ASSERT(heap != NULL); + DUK_UNREF(extdata); #if defined(DUK_USE_STRLEN16) /* If blen <= 0xffffUL, clen is also guaranteed to be <= 0xffffUL. */ if (blen > 0xffffUL) { DUK_D(DUK_DPRINT("16-bit string blen/clen active and blen over 16 bits, reject intern")); - return NULL; + goto alloc_error; } #endif + /* XXX: Memzeroing the allocated structure is not really necessary + * because we could just initialize all fields explicitly (almost + * all fields are initialized explicitly anyway). + */ +#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) if (extdata) { - alloc_size = (duk_size_t) sizeof(duk_hstring_external); - res = (duk_hstring *) DUK_ALLOC(heap, alloc_size); - if (!res) { + res = (duk_hstring *) DUK_ALLOC(heap, sizeof(duk_hstring_external)); + if (DUK_UNLIKELY(res == NULL)) { goto alloc_error; } DUK_MEMZERO(res, sizeof(duk_hstring_external)); @@ -47607,12 +49600,18 @@ #endif DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, DUK_HSTRING_FLAG_EXTDATA); + DUK_ASSERT(extdata[blen] == 0); /* Application responsibility. */ + data = extdata; ((duk_hstring_external *) res)->extdata = extdata; - } else { + } else +#endif /* DUK_USE_HSTRING_EXTDATA && DUK_USE_EXTSTR_INTERN_CHECK */ + { + duk_uint8_t *data_tmp; + /* NUL terminate for convenient C access */ - alloc_size = (duk_size_t) (sizeof(duk_hstring) + blen + 1); - res = (duk_hstring *) DUK_ALLOC(heap, alloc_size); - if (!res) { + DUK_ASSERT(sizeof(duk_hstring) + blen + 1 > blen); /* No wrap, limits ensure. */ + res = (duk_hstring *) DUK_ALLOC(heap, sizeof(duk_hstring) + blen + 1); + if (DUK_UNLIKELY(res == NULL)) { goto alloc_error; } DUK_MEMZERO(res, sizeof(duk_hstring)); @@ -47621,1090 +49620,787 @@ #endif DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, 0); - data = (duk_uint8_t *) (res + 1); - DUK_MEMCPY(data, str, blen); - data[blen] = (duk_uint8_t) 0; + data_tmp = (duk_uint8_t *) (res + 1); + DUK_MEMCPY(data_tmp, str, blen); + data_tmp[blen] = (duk_uint8_t) 0; + data = (const duk_uint8_t *) data_tmp; } + DUK_HSTRING_SET_BYTELEN(res, blen); + DUK_HSTRING_SET_HASH(res, strhash); + DUK_ASSERT(!DUK_HSTRING_HAS_ARRIDX(res)); #if defined(DUK_USE_HSTRING_ARRIDX) - if (duk_js_to_arrayindex_raw_string(str, blen, &res->arridx)) { + res->arridx = duk_js_to_arrayindex_string(data, blen); + if (res->arridx != DUK_HSTRING_NO_ARRAY_INDEX) { #else - if (duk_js_to_arrayindex_raw_string(str, blen, &dummy)) { + dummy = duk_js_to_arrayindex_string(data, blen); + if (dummy != DUK_HSTRING_NO_ARRAY_INDEX) { #endif + /* Array index strings cannot be symbol strings, + * and they're always pure ASCII so blen == clen. + */ DUK_HSTRING_SET_ARRIDX(res); - } - - /* All strings beginning with specific (invalid UTF-8) byte prefixes - * are treated as symbols. - */ - DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(res)); - DUK_ASSERT(!DUK_HSTRING_HAS_HIDDEN(res)); - if (blen > 0) { - if (str[0] == 0xffU) { - DUK_HSTRING_SET_SYMBOL(res); - DUK_HSTRING_SET_HIDDEN(res); - } else if ((str[0] & 0xc0U) == 0x80U) { - DUK_HSTRING_SET_SYMBOL(res); + DUK_HSTRING_SET_ASCII(res); + DUK_ASSERT(duk_unicode_unvalidated_utf8_length(data, (duk_size_t) blen) == blen); + } else { + /* Because 'data' is NUL-terminated, we don't need a + * blen > 0 check here. For NUL (0x00) the symbol + * checks will be false. + */ + if (DUK_UNLIKELY(data[0] >= 0x80U)) { + if (data[0] == 0xffU) { + DUK_HSTRING_SET_SYMBOL(res); + DUK_HSTRING_SET_HIDDEN(res); + } else if (data[0] <= 0xbf) { + /* Check equivalent to: (data[0] & 0xc0U) == 0x80U. */ + DUK_HSTRING_SET_SYMBOL(res); + } } - } - - DUK_HSTRING_SET_HASH(res, strhash); - DUK_HSTRING_SET_BYTELEN(res, blen); - - clen = (duk_uint32_t) duk_unicode_unvalidated_utf8_length(str, (duk_size_t) blen); - DUK_ASSERT(clen <= blen); -#if defined(DUK_USE_HSTRING_CLEN) - DUK_HSTRING_SET_CHARLEN(res, clen); -#endif - /* Using an explicit 'ASCII' flag has larger footprint (one call site - * only) but is quite useful for the case when there's no explicit - * 'clen' in duk_hstring. - */ - DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(res)); - if (clen == blen) { - DUK_HSTRING_SET_ASCII(res); + /* Using an explicit 'ASCII' flag has larger footprint (one call site + * only) but is quite useful for the case when there's no explicit + * 'clen' in duk_hstring. + * + * The flag is set lazily for RAM strings. + */ + DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(res)); } - DUK_DDD(DUK_DDDPRINT("interned string, hash=0x%08lx, blen=%ld, clen=%ld, has_arridx=%ld, has_extdata=%ld", + DUK_DDD(DUK_DDDPRINT("interned string, hash=0x%08lx, blen=%ld, has_arridx=%ld, has_extdata=%ld", (unsigned long) DUK_HSTRING_GET_HASH(res), (long) DUK_HSTRING_GET_BYTELEN(res), - (long) DUK_HSTRING_GET_CHARLEN(res), (long) (DUK_HSTRING_HAS_ARRIDX(res) ? 1 : 0), (long) (DUK_HSTRING_HAS_EXTDATA(res) ? 1 : 0))); + DUK_ASSERT(res != NULL); return res; alloc_error: - DUK_FREE(heap, res); return NULL; } /* - * String table algorithm: fixed size string table with array chaining - * - * The top level string table has a fixed size, with each slot holding - * either NULL, string pointer, or pointer to a separately allocated - * string pointer list. - * - * This is good for low memory environments using a pool allocator: the - * top level allocation has a fixed size and the pointer lists have quite - * small allocation size, which further matches the typical pool sizes - * needed by objects, strings, property tables, etc. + * Grow strtable allocation in-place. */ -#if defined(DUK_USE_STRTAB_CHAIN) +#if defined(DUK__STRTAB_RESIZE_CHECK) +DUK_LOCAL void duk__strtable_grow_inplace(duk_heap *heap) { + duk_uint32_t new_st_size; + duk_uint32_t old_st_size; + duk_uint32_t i; + duk_hstring *h; + duk_hstring *next; + duk_hstring *prev; +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *new_ptr; + duk_uint16_t *new_ptr_high; +#else + duk_hstring **new_ptr; + duk_hstring **new_ptr_high; +#endif -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL duk_bool_t duk__insert_hstring_chain(duk_heap *heap, duk_hstring *h) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_uint16_t *lst; - duk_uint16_t *new_lst; - duk_size_t i, n; - duk_uint16_t null16 = heap->heapptr_null16; - duk_uint16_t h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h); + DUK_DD(DUK_DDPRINT("grow in-place: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size * 2)); DUK_ASSERT(heap != NULL); - DUK_ASSERT(h != NULL); + DUK_ASSERT(heap->st_resizing == 1); + DUK_ASSERT(heap->st_size >= 2); + DUK_ASSERT((heap->st_size & (heap->st_size - 1)) == 0); /* 2^N */ + DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL); - slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); - - e = heap->strtable + slotidx; - if (e->listlen == 0) { - if (e->u.str16 == null16) { - e->u.str16 = h16; - } else { - /* Now two entries in the same slot, alloc list */ - lst = (duk_uint16_t *) DUK_ALLOC(heap, sizeof(duk_uint16_t) * 2); - if (lst == NULL) { - return 1; /* fail */ - } - lst[0] = e->u.str16; - lst[1] = h16; - e->u.strlist16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) lst); - e->listlen = 2; - } - } else { - DUK_ASSERT(e->u.strlist16 != null16); - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); - DUK_ASSERT(lst != NULL); - for (i = 0, n = e->listlen; i < n; i++) { - if (lst[i] == null16) { - lst[i] = h16; - return 0; - } - } + new_st_size = heap->st_size << 1U; + DUK_ASSERT(new_st_size > heap->st_size); /* No overflow. */ - if (e->listlen + 1 == 0) { - /* Overflow, relevant mainly when listlen is 16 bits. */ - return 1; /* fail */ - } + /* Reallocate the strtable first and then work in-place to rehash + * strings. We don't need an indirect allocation here: even if GC + * is triggered to satisfy the allocation, recursive strtable resize + * is prevented by flags. This is also why we don't need to use + * DUK_REALLOC_INDIRECT(). + */ - new_lst = (duk_uint16_t *) DUK_REALLOC(heap, lst, sizeof(duk_uint16_t) * (e->listlen + 1)); - if (new_lst == NULL) { - return 1; /* fail */ - } - new_lst[e->listlen++] = h16; - e->u.strlist16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) new_lst); +#if defined(DUK_USE_STRTAB_PTRCOMP) + new_ptr = (duk_uint16_t *) DUK_REALLOC(heap, heap->strtable16, sizeof(duk_uint16_t) * new_st_size); +#else + new_ptr = (duk_hstring **) DUK_REALLOC(heap, heap->strtable, sizeof(duk_hstring *) * new_st_size); +#endif + if (DUK_UNLIKELY(new_ptr == NULL)) { + /* If realloc fails we can continue normally: the string table + * won't "fill up" although chains will gradually get longer. + * When string insertions continue, we'll quite soon try again + * with no special handling. + */ + DUK_D(DUK_DPRINT("string table grow failed, ignoring")); + return; } - return 0; -} -#else /* DUK_USE_HEAPPTR16 */ -DUK_LOCAL duk_bool_t duk__insert_hstring_chain(duk_heap *heap, duk_hstring *h) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_hstring **lst; - duk_hstring **new_lst; - duk_size_t i, n; - - DUK_ASSERT(heap != NULL); - DUK_ASSERT(h != NULL); - - slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); - - e = heap->strtable + slotidx; - if (e->listlen == 0) { - if (e->u.str == NULL) { - e->u.str = h; - } else { - /* Now two entries in the same slot, alloc list */ - lst = (duk_hstring **) DUK_ALLOC(heap, sizeof(duk_hstring *) * 2); - if (lst == NULL) { - return 1; /* fail */ - } - lst[0] = e->u.str; - lst[1] = h; - e->u.strlist = lst; - e->listlen = 2; - } - } else { - DUK_ASSERT(e->u.strlist != NULL); - lst = e->u.strlist; - for (i = 0, n = e->listlen; i < n; i++) { - if (lst[i] == NULL) { - lst[i] = h; - return 0; - } - } +#if defined(DUK_USE_STRTAB_PTRCOMP) + heap->strtable16 = new_ptr; +#else + heap->strtable = new_ptr; +#endif - if (e->listlen + 1 == 0) { - /* Overflow, relevant mainly when listlen is 16 bits. */ - return 1; /* fail */ - } + /* Rehash a single bucket into two separate ones. When we grow + * by x2 the highest 'new' bit determines whether a string remains + * in its old position (bit is 0) or goes to a new one (bit is 1). + */ - new_lst = (duk_hstring **) DUK_REALLOC(heap, e->u.strlist, sizeof(duk_hstring *) * (e->listlen + 1)); - if (new_lst == NULL) { - return 1; /* fail */ - } - new_lst[e->listlen++] = h; - e->u.strlist = new_lst; - } - return 0; -} -#endif /* DUK_USE_HEAPPTR16 */ + old_st_size = heap->st_size; + new_ptr_high = new_ptr + old_st_size; + for (i = 0; i < old_st_size; i++) { + duk_hstring *new_root; + duk_hstring *new_root_high; -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_uint16_t *lst; - duk_size_t i, n; - duk_uint16_t null16 = heap->heapptr_null16; + h = DUK__HEAPPTR_DEC16(heap, new_ptr[i]); + new_root = h; + new_root_high = NULL; - DUK_ASSERT(heap != NULL); + prev = NULL; + while (h != NULL) { + duk_uint32_t mask; - slotidx = strhash % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); + DUK_ASSERT((DUK_HSTRING_GET_HASH(h) & heap->st_mask) == i); + next = h->hdr.h_next; - e = heap->strtable + slotidx; - if (e->listlen == 0) { - if (e->u.str16 != null16) { - duk_hstring *h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16); - DUK_ASSERT(h != NULL); - if (DUK_HSTRING_GET_BYTELEN(h) == blen && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) { - return h; - } - } - } else { - DUK_ASSERT(e->u.strlist16 != null16); - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); - DUK_ASSERT(lst != NULL); - for (i = 0, n = e->listlen; i < n; i++) { - if (lst[i] != null16) { - duk_hstring *h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[i]); - DUK_ASSERT(h != NULL); - if (DUK_HSTRING_GET_BYTELEN(h) == blen && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) { - return h; + /* Example: if previous size was 256, previous mask is 0xFF + * and size is 0x100 which corresponds to the new bit that + * comes into play. + */ + DUK_ASSERT(heap->st_mask == old_st_size - 1); + mask = old_st_size; + if (DUK_HSTRING_GET_HASH(h) & mask) { + if (prev != NULL) { + prev->hdr.h_next = h->hdr.h_next; + } else { + DUK_ASSERT(h == new_root); + new_root = h->hdr.h_next; } - } - } - } - return NULL; -} -#else /* DUK_USE_HEAPPTR16 */ -DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_hstring **lst; - duk_size_t i, n; - - DUK_ASSERT(heap != NULL); - - slotidx = strhash % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); - - e = heap->strtable + slotidx; - if (e->listlen == 0) { - if (e->u.str != NULL && - DUK_HSTRING_GET_BYTELEN(e->u.str) == blen && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(e->u.str), (size_t) blen) == 0) { - return e->u.str; - } - } else { - DUK_ASSERT(e->u.strlist != NULL); - lst = e->u.strlist; - for (i = 0, n = e->listlen; i < n; i++) { - if (lst[i] != NULL && - DUK_HSTRING_GET_BYTELEN(lst[i]) == blen && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(lst[i]), (size_t) blen) == 0) { - return lst[i]; + h->hdr.h_next = new_root_high; + new_root_high = h; + } else { + prev = h; } + h = next; } - } - return NULL; -} -#endif /* DUK_USE_HEAPPTR16 */ - -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL void duk__remove_matching_hstring_chain(duk_heap *heap, duk_hstring *h) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_uint16_t *lst; - duk_size_t i, n; - duk_uint16_t h16; - duk_uint16_t null16 = heap->heapptr_null16; - - DUK_ASSERT(heap != NULL); - DUK_ASSERT(h != NULL); - - slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); - - DUK_ASSERT(h != NULL); - h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h); - - e = heap->strtable + slotidx; - if (e->listlen == 0) { - if (e->u.str16 == h16) { - e->u.str16 = null16; - return; - } - } else { - DUK_ASSERT(e->u.strlist16 != null16); - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); - DUK_ASSERT(lst != NULL); - for (i = 0, n = e->listlen; i < n; i++) { - if (lst[i] == h16) { - lst[i] = null16; - return; - } - } + new_ptr[i] = DUK__HEAPPTR_ENC16(heap, new_root); + new_ptr_high[i] = DUK__HEAPPTR_ENC16(heap, new_root_high); } - DUK_D(DUK_DPRINT("failed to find string that should be in stringtable")); - DUK_UNREACHABLE(); - return; -} -#else /* DUK_USE_HEAPPTR16 */ -DUK_LOCAL void duk__remove_matching_hstring_chain(duk_heap *heap, duk_hstring *h) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_hstring **lst; - duk_size_t i, n; + heap->st_size = new_st_size; + heap->st_mask = new_st_size - 1; - DUK_ASSERT(heap != NULL); - DUK_ASSERT(h != NULL); - - slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); - - e = heap->strtable + slotidx; - if (e->listlen == 0) { - DUK_ASSERT(h != NULL); - if (e->u.str == h) { - e->u.str = NULL; - return; - } - } else { - DUK_ASSERT(e->u.strlist != NULL); - lst = e->u.strlist; - for (i = 0, n = e->listlen; i < n; i++) { - DUK_ASSERT(h != NULL); - if (lst[i] == h) { - lst[i] = NULL; - return; - } - } - } - - DUK_D(DUK_DPRINT("failed to find string that should be in stringtable")); - DUK_UNREACHABLE(); - return; +#if defined(DUK_USE_ASSERTIONS) + duk__strtable_assert_checks(heap); +#endif } -#endif /* DUK_USE_HEAPPTR16 */ +#endif /* DUK__STRTAB_RESIZE_CHECK */ -#if defined(DUK_USE_DEBUG) -DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap) { - duk_strtab_entry *e; - duk_small_uint_t i; - duk_size_t j, n, used; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t *lst; - duk_uint16_t null16 = heap->heapptr_null16; -#else - duk_hstring **lst; +/* + * Shrink strtable allocation in-place. + */ + +#if defined(DUK__STRTAB_RESIZE_CHECK) +DUK_LOCAL void duk__strtable_shrink_inplace(duk_heap *heap) { + duk_uint32_t new_st_size; + duk_uint32_t i; + duk_hstring *h; + duk_hstring *other; + duk_hstring *root; +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *old_ptr; + duk_uint16_t *old_ptr_high; + duk_uint16_t *new_ptr; +#else + duk_hstring **old_ptr; + duk_hstring **old_ptr_high; + duk_hstring **new_ptr; #endif - DUK_ASSERT(heap != NULL); + DUK_DD(DUK_DDPRINT("shrink in-place: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size / 2)); - for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { - e = heap->strtable + i; + DUK_ASSERT(heap != NULL); + DUK_ASSERT(heap->st_resizing == 1); + DUK_ASSERT(heap->st_size >= 2); + DUK_ASSERT((heap->st_size & (heap->st_size - 1)) == 0); /* 2^N */ + DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL); + + new_st_size = heap->st_size >> 1U; + + /* Combine two buckets into a single one. When we shrink, one hash + * bit (highest) disappears. + */ + old_ptr = DUK__GET_STRTABLE(heap); + old_ptr_high = old_ptr + new_st_size; + for (i = 0; i < new_st_size; i++) { + h = DUK__HEAPPTR_DEC16(heap, old_ptr[i]); + other = DUK__HEAPPTR_DEC16(heap, old_ptr_high[i]); - if (e->listlen == 0) { -#if defined(DUK_USE_HEAPPTR16) - DUK_DD(DUK_DDPRINT("[%03d] -> plain %d", (int) i, (int) (e->u.str16 != null16 ? 1 : 0))); -#else - DUK_DD(DUK_DDPRINT("[%03d] -> plain %d", (int) i, (int) (e->u.str ? 1 : 0))); -#endif + if (h == NULL) { + /* First chain is empty, so use second one as is. */ + root = other; } else { - used = 0; -#if defined(DUK_USE_HEAPPTR16) - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); -#else - lst = e->u.strlist; -#endif - DUK_ASSERT(lst != NULL); - for (j = 0, n = e->listlen; j < n; j++) { -#if defined(DUK_USE_HEAPPTR16) - if (lst[j] != null16) { -#else - if (lst[j] != NULL) { -#endif - used++; - } + /* Find end of first chain, and link in the second. */ + root = h; + while (h->hdr.h_next != NULL) { + h = h->hdr.h_next; } - DUK_DD(DUK_DDPRINT("[%03d] -> array %d/%d", (int) i, (int) used, (int) e->listlen)); + h->hdr.h_next = other; } - } -} -#endif /* DUK_USE_DEBUG */ -#endif /* DUK_USE_STRTAB_CHAIN */ + old_ptr[i] = DUK__HEAPPTR_ENC16(heap, root); + } -/* - * String table algorithm: closed hashing with a probe sequence - * - * This is the default algorithm and works fine for environments with - * minimal memory constraints. - */ + heap->st_size = new_st_size; + heap->st_mask = new_st_size - 1; -#if defined(DUK_USE_STRTAB_PROBE) + /* The strtable is now consistent and we can realloc safely. Even + * if side effects cause string interning or removal the strtable + * updates are safe. Recursive resize has been prevented by caller. + * This is also why we don't need to use DUK_REALLOC_INDIRECT(). + * + * We assume a realloc() to a smaller size is guaranteed to succeed. + * It would be relatively straightforward to handle the error by + * essentially performing a "grow" step to recover. + */ -/* Count actually used (non-NULL, non-DELETED) entries. */ -DUK_LOCAL duk_int_t duk__count_used_probe(duk_heap *heap) { - duk_int_t res = 0; - duk_uint_fast32_t i, n; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t null16 = heap->heapptr_null16; - duk_uint16_t deleted16 = heap->heapptr_deleted16; +#if defined(DUK_USE_STRTAB_PTRCOMP) + new_ptr = (duk_uint16_t *) DUK_REALLOC(heap, heap->strtable16, sizeof(duk_uint16_t) * new_st_size); + DUK_ASSERT(new_ptr != NULL); + heap->strtable16 = new_ptr; +#else + new_ptr = (duk_hstring **) DUK_REALLOC(heap, heap->strtable, sizeof(duk_hstring *) * new_st_size); + DUK_ASSERT(new_ptr != NULL); + heap->strtable = new_ptr; #endif - n = (duk_uint_fast32_t) heap->st_size; - for (i = 0; i < n; i++) { -#if defined(DUK_USE_HEAPPTR16) - if (heap->strtable16[i] != null16 && heap->strtable16[i] != deleted16) { -#else - if (heap->strtable[i] != NULL && heap->strtable[i] != DUK__DELETED_MARKER(heap)) { +#if defined(DUK_USE_ASSERTIONS) + duk__strtable_assert_checks(heap); #endif - res++; - } - } - return res; } +#endif /* DUK__STRTAB_RESIZE_CHECK */ -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL void duk__insert_hstring_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, duk_uint32_t *p_used, duk_hstring *h) { -#else -DUK_LOCAL void duk__insert_hstring_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, duk_uint32_t *p_used, duk_hstring *h) { -#endif - duk_uint32_t i; - duk_uint32_t step; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t null16 = heap->heapptr_null16; - duk_uint16_t deleted16 = heap->heapptr_deleted16; -#endif +/* + * Grow/shrink check. + */ - DUK_ASSERT(size > 0); +#if defined(DUK__STRTAB_RESIZE_CHECK) +DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__strtable_resize_check(duk_heap *heap) { + duk_uint32_t load_factor; /* fixed point */ - i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(h), size); - step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(h)); - for (;;) { -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t e16 = entries16[i]; -#else - duk_hstring *e = entries[i]; -#endif - -#if defined(DUK_USE_HEAPPTR16) - /* XXX: could check for e16 == 0 because NULL is guaranteed to - * encode to zero. - */ - if (e16 == null16) { -#else - if (e == NULL) { -#endif - DUK_DDD(DUK_DDDPRINT("insert hit (null): %ld", (long) i)); -#if defined(DUK_USE_HEAPPTR16) - entries16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h); -#else - entries[i] = h; -#endif - (*p_used)++; - break; -#if defined(DUK_USE_HEAPPTR16) - } else if (e16 == deleted16) { -#else - } else if (e == DUK__DELETED_MARKER(heap)) { -#endif - /* st_used remains the same, DELETED is counted as used */ - DUK_DDD(DUK_DDDPRINT("insert hit (deleted): %ld", (long) i)); -#if defined(DUK_USE_HEAPPTR16) - entries16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h); + DUK_ASSERT(heap != NULL); +#if defined(DUK_USE_STRTAB_PTRCOMP) + DUK_ASSERT(heap->strtable16 != NULL); #else - entries[i] = h; + DUK_ASSERT(heap->strtable != NULL); #endif - break; - } - DUK_DDD(DUK_DDDPRINT("insert miss: %ld", (long) i)); - i = (i + step) % size; - /* looping should never happen */ - DUK_ASSERT(i != DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(h), size)); + /* Prevent recursive resizing. */ + if (DUK_UNLIKELY(heap->st_resizing)) { + DUK_D(DUK_DPRINT("prevent recursive strtable resize")); + return; } -} -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL duk_hstring *duk__find_matching_string_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { -#else -DUK_LOCAL duk_hstring *duk__find_matching_string_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { -#endif - duk_uint32_t i; - duk_uint32_t step; + heap->st_resizing = 1; - DUK_ASSERT(size > 0); - - i = DUK__HASH_INITIAL(strhash, size); - step = DUK__HASH_PROBE_STEP(strhash); - for (;;) { - duk_hstring *e; -#if defined(DUK_USE_HEAPPTR16) - e = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, entries16[i]); -#else - e = entries[i]; + DUK_ASSERT(heap->st_size >= 16U); + DUK_ASSERT((heap->st_size >> 4U) >= 1); + load_factor = heap->st_count / (heap->st_size >> 4U); + + DUK_DD(DUK_DDPRINT("resize check string table: size=%lu, count=%lu, load_factor=%lu (fixed point .4; float %lf)", + (unsigned long) heap->st_size, (unsigned long) heap->st_count, + (unsigned long) load_factor, + (double) heap->st_count / (double) heap->st_size)); + + if (load_factor >= DUK_USE_STRTAB_GROW_LIMIT) { + if (heap->st_size >= DUK_USE_STRTAB_MAXSIZE) { + DUK_DD(DUK_DDPRINT("want to grow strtable (based on load factor) but already maximum size")); + } else { + DUK_D(DUK_DPRINT("grow string table: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size * 2)); +#if defined(DUK_USE_DEBUG) + duk_heap_strtable_dump(heap); #endif - - if (!e) { - return NULL; + duk__strtable_grow_inplace(heap); } - if (e != DUK__DELETED_MARKER(heap) && DUK_HSTRING_GET_BYTELEN(e) == blen) { - if (DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(e), (size_t) blen) == 0) { - DUK_DDD(DUK_DDDPRINT("find matching hit: %ld (step %ld, size %ld)", - (long) i, (long) step, (long) size)); - return e; - } + } else if (load_factor <= DUK_USE_STRTAB_SHRINK_LIMIT) { + if (heap->st_size <= DUK_USE_STRTAB_MINSIZE) { + DUK_DD(DUK_DDPRINT("want to shrink strtable (based on load factor) but already minimum size")); + } else { + DUK_D(DUK_DPRINT("shrink string table: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size / 2)); +#if defined(DUK_USE_DEBUG) + duk_heap_strtable_dump(heap); +#endif + duk__strtable_shrink_inplace(heap); } - DUK_DDD(DUK_DDDPRINT("find matching miss: %ld (step %ld, size %ld)", - (long) i, (long) step, (long) size)); - i = (i + step) % size; - - /* looping should never happen */ - DUK_ASSERT(i != DUK__HASH_INITIAL(strhash, size)); + } else { + DUK_DD(DUK_DDPRINT("no need for strtable resize")); } - DUK_UNREACHABLE(); -} -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL void duk__remove_matching_hstring_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, duk_hstring *h) { -#else -DUK_LOCAL void duk__remove_matching_hstring_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, duk_hstring *h) { -#endif - duk_uint32_t i; - duk_uint32_t step; - duk_uint32_t hash; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t null16 = heap->heapptr_null16; - duk_uint16_t h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h); -#endif + heap->st_resizing = 0; +} +#endif /* DUK__STRTAB_RESIZE_CHECK */ - DUK_ASSERT(size > 0); +/* + * Torture grow/shrink: unconditionally grow and shrink back. + */ - hash = DUK_HSTRING_GET_HASH(h); - i = DUK__HASH_INITIAL(hash, size); - step = DUK__HASH_PROBE_STEP(hash); - for (;;) { -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t e16 = entries16[i]; -#else - duk_hstring *e = entries[i]; -#endif +#if defined(DUK_USE_STRTAB_TORTURE) && defined(DUK__STRTAB_RESIZE_CHECK) +DUK_LOCAL void duk__strtable_resize_torture(duk_heap *heap) { + duk_uint32_t old_st_size; -#if defined(DUK_USE_HEAPPTR16) - if (e16 == null16) { -#else - if (!e) { -#endif - DUK_UNREACHABLE(); - break; - } -#if defined(DUK_USE_HEAPPTR16) - if (e16 == h16) { -#else - if (e == h) { -#endif - /* st_used remains the same, DELETED is counted as used */ - DUK_DDD(DUK_DDDPRINT("free matching hit: %ld", (long) i)); -#if defined(DUK_USE_HEAPPTR16) - entries16[i] = heap->heapptr_deleted16; -#else - entries[i] = DUK__DELETED_MARKER(heap); -#endif - break; - } + DUK_ASSERT(heap != NULL); - DUK_DDD(DUK_DDDPRINT("free matching miss: %ld", (long) i)); - i = (i + step) % size; + old_st_size = heap->st_size; + if (old_st_size >= DUK_USE_STRTAB_MAXSIZE) { + return; + } - /* looping should never happen */ - DUK_ASSERT(i != DUK__HASH_INITIAL(hash, size)); + heap->st_resizing = 1; + duk__strtable_grow_inplace(heap); + if (heap->st_size > old_st_size) { + duk__strtable_shrink_inplace(heap); } + heap->st_resizing = 0; } +#endif /* DUK_USE_STRTAB_TORTURE && DUK__STRTAB_RESIZE_CHECK */ -DUK_LOCAL duk_bool_t duk__resize_strtab_raw_probe(duk_heap *heap, duk_uint32_t new_size) { -#if defined(DUK_USE_DEBUG) - duk_uint32_t old_used = heap->st_used; -#endif - duk_uint32_t old_size = heap->st_size; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t *old_entries = heap->strtable16; - duk_uint16_t *new_entries = NULL; -#else - duk_hstring **old_entries = heap->strtable; - duk_hstring **new_entries = NULL; -#endif - duk_uint32_t new_used = 0; - duk_uint32_t i; +/* + * Raw intern; string already checked not to be present. + */ -#if defined(DUK_USE_DEBUG) - DUK_UNREF(old_used); /* unused with some debug level combinations */ +DUK_LOCAL duk_hstring *duk__strtable_do_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { + duk_hstring *res; + const duk_uint8_t *extdata; +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *slot; +#else + duk_hstring **slot; #endif -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) - DUK_DDD(DUK_DDDPRINT("attempt to resize stringtable: %ld entries, %ld bytes, %ld used, %ld%% load -> %ld entries, %ld bytes, %ld used, %ld%% load", - (long) old_size, (long) (sizeof(duk_hstring *) * old_size), (long) old_used, - (long) (((double) old_used) / ((double) old_size) * 100.0), - (long) new_size, (long) (sizeof(duk_hstring *) * new_size), (long) duk__count_used_probe(heap), - (long) (((double) duk__count_used_probe(heap)) / ((double) new_size) * 100.0))); -#endif + DUK_DDD(DUK_DDDPRINT("do_intern: heap=%p, str=%p, blen=%lu, strhash=%lx, st_size=%lu, st_count=%lu, load=%lf", + (void *) heap, (const void *) str, (unsigned long) blen, (unsigned long) strhash, + (unsigned long) heap->st_size, (unsigned long) heap->st_count, + (double) heap->st_count / (double) heap->st_size)); - DUK_ASSERT(new_size > (duk_uint32_t) duk__count_used_probe(heap)); /* required for rehash to succeed, equality not that useful */ - DUK_ASSERT(old_entries); + DUK_ASSERT(heap != NULL); - /* - * The attempt to allocate may cause a GC. Such a GC must not attempt to resize - * the stringtable (though it can be swept); finalizer execution and object - * compaction must also be postponed to avoid the pressure to add strings to the - * string table. Call site must prevent these. + /* Prevent any side effects on the string table and the caller provided + * str/blen arguments while interning is in progress. For example, if + * the caller provided str/blen from a dynamic buffer, a finalizer + * might resize or modify that dynamic buffer, invalidating the call + * arguments. + * + * While finalizers must be prevented, mark-and-sweep itself is fine. + * Recursive string table resize is prevented explicitly here. */ - DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE); - DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_FINALIZERS); - DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_OBJECT_COMPACTION); + heap->pf_prevent_count++; + DUK_ASSERT(heap->pf_prevent_count != 0); /* Wrap. */ -#if defined(DUK_USE_HEAPPTR16) - new_entries = (duk_uint16_t *) DUK_ALLOC(heap, sizeof(duk_uint16_t) * new_size); -#else - new_entries = (duk_hstring **) DUK_ALLOC(heap, sizeof(duk_hstring *) * new_size); +#if defined(DUK_USE_STRTAB_TORTURE) && defined(DUK__STRTAB_RESIZE_CHECK) + duk__strtable_resize_torture(heap); #endif - if (!new_entries) { - goto resize_error; - } + /* String table grow/shrink check. Because of chaining (and no + * accumulation issues as with hash probe chains and DELETED + * markers) there's never a mandatory need to resize right now. + * Check for the resize only periodically, based on st_count + * bit pattern. Because string table removal doesn't do a shrink + * check, we do that also here. + * + * Do the resize and possible grow/shrink before the new duk_hstring + * has been allocated. Otherwise we may trigger a GC when the result + * duk_hstring is not yet strongly referenced. + */ -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - for (i = 0; i < new_size; i++) { -#if defined(DUK_USE_HEAPPTR16) - new_entries[i] = heap->heapptr_null16; -#else - new_entries[i] = NULL; -#endif +#if defined(DUK__STRTAB_RESIZE_CHECK) + if (DUK_UNLIKELY((heap->st_count & DUK_USE_STRTAB_RESIZE_CHECK_MASK) == 0)) { + duk__strtable_resize_check(heap); } -#else -#if defined(DUK_USE_HEAPPTR16) - /* Relies on NULL encoding to zero. */ - DUK_MEMZERO(new_entries, sizeof(duk_uint16_t) * new_size); -#else - DUK_MEMZERO(new_entries, sizeof(duk_hstring *) * new_size); -#endif #endif - /* Because new_size > duk__count_used_probe(heap), guaranteed to work */ - for (i = 0; i < old_size; i++) { - duk_hstring *e; + /* External string check (low memory optimization). */ -#if defined(DUK_USE_HEAPPTR16) - e = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, old_entries[i]); -#else - e = old_entries[i]; -#endif - if (e == NULL || e == DUK__DELETED_MARKER(heap)) { - continue; - } - /* checking for DUK__DELETED_MARKER is not necessary here, but helper does it now */ - duk__insert_hstring_probe(heap, new_entries, new_size, &new_used, e); - } - -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1) - DUK_DD(DUK_DDPRINT("resized stringtable: %ld entries, %ld bytes, %ld used, %ld%% load -> %ld entries, %ld bytes, %ld used, %ld%% load", - (long) old_size, (long) (sizeof(duk_hstring *) * old_size), (long) old_used, - (long) (((double) old_used) / ((double) old_size) * 100.0), - (long) new_size, (long) (sizeof(duk_hstring *) * new_size), (long) new_used, - (long) (((double) new_used) / ((double) new_size) * 100.0))); -#endif - -#if defined(DUK_USE_HEAPPTR16) - DUK_FREE(heap, heap->strtable16); - heap->strtable16 = new_entries; +#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) + extdata = (const duk_uint8_t *) DUK_USE_EXTSTR_INTERN_CHECK(heap->heap_udata, (void *) DUK_LOSE_CONST(str), (duk_size_t) blen); #else - DUK_FREE(heap, heap->strtable); - heap->strtable = new_entries; + extdata = (const duk_uint8_t *) NULL; #endif - heap->st_size = new_size; - heap->st_used = new_used; /* may be less, since DELETED entries are NULLed by rehash */ - - return 0; /* OK */ - resize_error: - DUK_FREE(heap, new_entries); - return 1; /* FAIL */ -} - -DUK_LOCAL duk_bool_t duk__resize_strtab_probe(duk_heap *heap) { - duk_uint32_t new_size; - duk_bool_t ret; - - new_size = (duk_uint32_t) duk__count_used_probe(heap); - if (new_size >= 0x80000000UL) { - new_size = DUK_STRTAB_HIGHEST_32BIT_PRIME; - } else { - new_size = duk_util_get_hash_prime(DUK_STRTAB_GROW_ST_SIZE(new_size)); - new_size = duk_util_get_hash_prime(new_size); - } - DUK_ASSERT(new_size > 0); - - /* rehash even if old and new sizes are the same to get rid of - * DELETED entries. - */ - - ret = duk__resize_strtab_raw_probe(heap, new_size); - - return ret; -} - -DUK_LOCAL duk_bool_t duk__recheck_strtab_size_probe(duk_heap *heap, duk_uint32_t new_used) { - duk_uint32_t new_free; - duk_uint32_t tmp1; - duk_uint32_t tmp2; + /* Allocate and initialize string, not yet linked. This may cause a + * GC which may cause other strings to be interned and inserted into + * the string table before we insert our string. Finalizer execution + * is disabled intentionally to avoid a finalizer from e.g. resizing + * a buffer used as a data area for 'str'. + */ - DUK_ASSERT(new_used <= heap->st_size); /* grow by at most one */ - new_free = heap->st_size - new_used; /* unsigned intentionally */ + res = duk__strtable_alloc_hstring(heap, str, blen, strhash, extdata); - /* new_free / size <= 1 / DIV <=> new_free <= size / DIV */ - /* new_used / size <= 1 / DIV <=> new_used <= size / DIV */ + /* Allow side effects again: GC must be avoided until duk_hstring + * result (if successful) has been INCREF'd. + */ + DUK_ASSERT(heap->pf_prevent_count > 0); + heap->pf_prevent_count--; - tmp1 = heap->st_size / DUK_STRTAB_MIN_FREE_DIVISOR; - tmp2 = heap->st_size / DUK_STRTAB_MIN_USED_DIVISOR; + /* Alloc error handling. */ - if (new_free <= tmp1 || new_used <= tmp2) { - /* load factor too low or high, count actually used entries and resize */ - return duk__resize_strtab_probe(heap); - } else { - return 0; /* OK */ + if (DUK_UNLIKELY(res == NULL)) { +#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) + if (extdata != NULL) { + DUK_USE_EXTSTR_FREE(heap->heap_udata, (const void *) extdata); + } +#endif + return NULL; } -} -#if defined(DUK_USE_DEBUG) -DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap) { - duk_uint32_t i; - duk_hstring *h; + /* Insert into string table. */ - DUK_ASSERT(heap != NULL); -#if defined(DUK_USE_HEAPPTR16) - DUK_ASSERT(heap->strtable16 != NULL); +#if defined(DUK_USE_STRTAB_PTRCOMP) + slot = heap->strtable16 + (strhash & heap->st_mask); #else - DUK_ASSERT(heap->strtable != NULL); + slot = heap->strtable + (strhash & heap->st_mask); #endif - DUK_UNREF(h); + DUK_ASSERT(res->hdr.h_next == NULL); /* This is the case now, but unnecessary zeroing/NULLing. */ + res->hdr.h_next = DUK__HEAPPTR_DEC16(heap, *slot); + *slot = DUK__HEAPPTR_ENC16(heap, res); - for (i = 0; i < heap->st_size; i++) { -#if defined(DUK_USE_HEAPPTR16) - h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->strtable16[i]); -#else - h = heap->strtable[i]; + /* Update string count only for successful inserts. */ + +#if defined(DUK__STRTAB_RESIZE_CHECK) + heap->st_count++; #endif - DUK_DD(DUK_DDPRINT("[%03d] -> %p", (int) i, (void *) h)); - } -} -#endif /* DUK_USE_DEBUG */ + /* The duk_hstring is in the string table but is not yet strongly + * reachable. Calling code MUST NOT make any allocations or other + * side effects before the duk_hstring has been INCREF'd and made + * reachable. + */ -#endif /* DUK_USE_STRTAB_PROBE */ + return res; +} /* - * Raw intern and lookup + * Intern a string from str/blen, returning either an existing duk_hstring + * or adding a new one into the string table. The input string does -not- + * need to be NUL terminated. + * + * The input 'str' argument may point to a Duktape managed data area such as + * the data area of a dynamic buffer. It's crucial to avoid any side effects + * that might affect the data area (e.g. resize the dynamic buffer, or write + * to the buffer) before the string is fully interned. */ -DUK_LOCAL duk_hstring *duk__do_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { - duk_hstring *res; - const duk_uint8_t *extdata; - duk_small_uint_t prev_mark_and_sweep_base_flags; +#if defined(DUK_USE_ROM_STRINGS) +DUK_LOCAL duk_hstring *duk__strtab_romstring_lookup(duk_heap *heap, const duk_uint8_t *str, duk_size_t blen, duk_uint32_t strhash) { + duk_size_t lookup_hash; + duk_hstring *curr; - /* Prevent any side effects on the string table and the caller provided - * str/blen arguments while interning is in progress. For example, if - * the caller provided str/blen from a dynamic buffer, a finalizer might - * resize that dynamic buffer, invalidating the call arguments. - */ - DUK_ASSERT((heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE) == 0); - prev_mark_and_sweep_base_flags = heap->mark_and_sweep_base_flags; - DUK__PREVENT_MS_SIDE_EFFECTS(heap); + DUK_ASSERT(heap != NULL); + DUK_UNREF(heap); -#if defined(DUK_USE_STRTAB_PROBE) - if (duk__recheck_strtab_size_probe(heap, heap->st_used + 1)) { - goto failed; + lookup_hash = (blen << 4); + if (blen > 0) { + lookup_hash += str[0]; } -#endif + lookup_hash &= 0xff; -#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) - extdata = (const duk_uint8_t *) DUK_USE_EXTSTR_INTERN_CHECK(heap->heap_udata, (void *) DUK_LOSE_CONST(str), (duk_size_t) blen); -#else - extdata = (const duk_uint8_t *) NULL; -#endif - res = duk__alloc_init_hstring(heap, str, blen, strhash, extdata); - if (!res) { - goto failed; + curr = DUK_LOSE_CONST(duk_rom_strings_lookup[lookup_hash]); + while (curr != NULL) { + if (strhash == DUK_HSTRING_GET_HASH(curr) && + blen == DUK_HSTRING_GET_BYTELEN(curr) && + DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(curr), blen) == 0) { + DUK_DDD(DUK_DDDPRINT("intern check: rom string: %!O, computed hash 0x%08lx, rom hash 0x%08lx", + curr, (unsigned long) strhash, (unsigned long) DUK_HSTRING_GET_HASH(curr))); + return curr; + } + curr = curr->hdr.h_next; } -#if defined(DUK_USE_STRTAB_CHAIN) - if (duk__insert_hstring_chain(heap, res)) { - /* failed */ - DUK_FREE(heap, res); - goto failed; - } -#elif defined(DUK_USE_STRTAB_PROBE) - /* guaranteed to succeed */ - duk__insert_hstring_probe(heap, -#if defined(DUK_USE_HEAPPTR16) - heap->strtable16, -#else - heap->strtable, -#endif - heap->st_size, - &heap->st_used, - res); -#else -#error internal error, invalid strtab options -#endif - - /* Note: hstring is in heap but has refcount zero and is not strongly reachable. - * Caller should increase refcount and make the hstring reachable before any - * operations which require allocation (and possible gc). - */ + return NULL; +} +#endif /* DUK_USE_ROM_STRINGS */ - done: - heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; - return res; +DUK_INTERNAL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) { + duk_uint32_t strhash; + duk_hstring *h; - failed: - res = NULL; - goto done; -} + DUK_DDD(DUK_DDDPRINT("intern check: heap=%p, str=%p, blen=%lu", (void *) heap, (const void *) str, (unsigned long) blen)); -DUK_LOCAL duk_hstring *duk__do_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t *out_strhash) { - duk_hstring *res; + /* Preliminaries. */ - DUK_ASSERT(out_strhash); + DUK_ASSERT(heap != NULL); + DUK_ASSERT(blen == 0 || str != NULL); + DUK_ASSERT(blen <= DUK_HSTRING_MAX_BYTELEN); /* Caller is responsible for ensuring this. */ + strhash = duk_heap_hashstring(heap, str, (duk_size_t) blen); - *out_strhash = duk_heap_hashstring(heap, str, (duk_size_t) blen); + /* String table lookup. */ -#if defined(DUK_USE_ROM_STRINGS) - { - duk_small_uint_t i; - /* XXX: This is VERY inefficient now, and should be e.g. a - * binary search or perfect hash, to be fixed. - */ - for (i = 0; i < (duk_small_uint_t) (sizeof(duk_rom_strings) / sizeof(duk_hstring *)); i++) { - duk_hstring *romstr; - romstr = (duk_hstring *) DUK_LOSE_CONST(duk_rom_strings[i]); - if (blen == DUK_HSTRING_GET_BYTELEN(romstr) && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(romstr), blen) == 0) { - DUK_DD(DUK_DDPRINT("intern check: rom string: %!O, computed hash 0x%08lx, rom hash 0x%08lx", - romstr, (unsigned long) *out_strhash, (unsigned long) DUK_HSTRING_GET_HASH(romstr))); - DUK_ASSERT(*out_strhash == DUK_HSTRING_GET_HASH(romstr)); - *out_strhash = DUK_HSTRING_GET_HASH(romstr); - return romstr; - } + DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL); + DUK_ASSERT(heap->st_size > 0); + DUK_ASSERT(heap->st_size == heap->st_mask + 1); +#if defined(DUK_USE_STRTAB_PTRCOMP) + h = DUK__HEAPPTR_DEC16(heap, heap->strtable16[strhash & heap->st_mask]); +#else + h = heap->strtable[strhash & heap->st_mask]; +#endif + while (h != NULL) { + if (DUK_HSTRING_GET_HASH(h) == strhash && + DUK_HSTRING_GET_BYTELEN(h) == blen && + DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) { + /* Found existing entry. */ + return h; } + h = h->hdr.h_next; } -#endif /* DUK_USE_ROM_STRINGS */ -#if defined(DUK_USE_STRTAB_CHAIN) - res = duk__find_matching_string_chain(heap, str, blen, *out_strhash); -#elif defined(DUK_USE_STRTAB_PROBE) - res = duk__find_matching_string_probe(heap, -#if defined(DUK_USE_HEAPPTR16) - heap->strtable16, -#else - heap->strtable, -#endif - heap->st_size, - str, - blen, - *out_strhash); -#else -#error internal error, invalid strtab options + /* ROM table lookup. Because this lookup is slower, do it only after + * RAM lookup. This works because no ROM string is ever interned into + * the RAM string table. + */ + +#if defined(DUK_USE_ROM_STRINGS) + h = duk__strtab_romstring_lookup(heap, str, blen, strhash); + if (h != NULL) { + return h; + } #endif - return res; + /* Not found in string table; insert. */ + + h = duk__strtable_do_intern(heap, str, blen, strhash); + return h; /* may be NULL */ } /* - * Exposed calls + * Intern a string from u32. */ -#if 0 /*unused*/ -DUK_INTERNAL duk_hstring *duk_heap_string_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) { - duk_uint32_t strhash; /* dummy */ - return duk__do_lookup(heap, str, blen, &strhash); -} -#endif +/* XXX: Could arrange some special handling because we know that the result + * will have an arridx flag and an ASCII flag, won't need a clen check, etc. + */ -DUK_INTERNAL duk_hstring *duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) { - duk_hstring *res; - duk_uint32_t strhash; +DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32(duk_heap *heap, duk_uint32_t val) { + char buf[DUK__STRTAB_U32_MAX_STRLEN]; + char *p; - /* caller is responsible for ensuring this */ - DUK_ASSERT(blen <= DUK_HSTRING_MAX_BYTELEN); + DUK_ASSERT(heap != NULL); - res = duk__do_lookup(heap, str, blen, &strhash); - if (res) { - return res; - } + /* This is smaller and faster than a %lu sprintf. */ + p = buf + sizeof(buf); + do { + p--; + *p = duk_lc_digits[val % 10]; + val = val / 10; + } while (val != 0); /* For val == 0, emit exactly one '0'. */ + DUK_ASSERT(p >= buf); - res = duk__do_intern(heap, str, blen, strhash); - return res; /* may be NULL */ + return duk_heap_strtable_intern(heap, (const duk_uint8_t *) p, (duk_uint32_t) ((buf + sizeof(buf)) - p)); } -DUK_INTERNAL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) { - duk_hstring *res = duk_heap_string_intern(thr->heap, str, blen); - if (!res) { +/* + * Checked convenience variants. + * + * XXX: Because the main use case is for the checked variants, make them the + * main functionality and provide a safe variant separately (it is only needed + * during heap init). The problem with that is that longjmp state and error + * creation must already be possible to throw. + */ + +DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) { + duk_hstring *res; + + DUK_ASSERT(thr != NULL); + DUK_ASSERT(thr->heap != NULL); + DUK_ASSERT(blen == 0 || str != NULL); + + res = duk_heap_strtable_intern(thr->heap, str, blen); + if (DUK_UNLIKELY(res == NULL)) { DUK_ERROR_ALLOC_FAILED(thr); } return res; } -#if 0 /*unused*/ -DUK_INTERNAL duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val) { - char buf[DUK_STRTAB_U32_MAX_STRLEN+1]; - DUK_SNPRINTF(buf, sizeof(buf), "%lu", (unsigned long) val); - buf[sizeof(buf) - 1] = (char) 0; - DUK_ASSERT(DUK_STRLEN(buf) <= DUK_UINT32_MAX); /* formatted result limited */ - return duk_heap_string_lookup(heap, (const duk_uint8_t *) buf, (duk_uint32_t) DUK_STRLEN(buf)); -} -#endif +DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32_checked(duk_hthread *thr, duk_uint32_t val) { + duk_hstring *res; -DUK_INTERNAL duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val) { - char buf[DUK_STRTAB_U32_MAX_STRLEN+1]; - DUK_SNPRINTF(buf, sizeof(buf), "%lu", (unsigned long) val); - buf[sizeof(buf) - 1] = (char) 0; - DUK_ASSERT(DUK_STRLEN(buf) <= DUK_UINT32_MAX); /* formatted result limited */ - return duk_heap_string_intern(heap, (const duk_uint8_t *) buf, (duk_uint32_t) DUK_STRLEN(buf)); -} + DUK_ASSERT(thr != NULL); + DUK_ASSERT(thr->heap != NULL); -DUK_INTERNAL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val) { - duk_hstring *res = duk_heap_string_intern_u32(thr->heap, val); - if (!res) { + res = duk_heap_strtable_intern_u32(thr->heap, val); + if (DUK_UNLIKELY(res == NULL)) { DUK_ERROR_ALLOC_FAILED(thr); } return res; } -/* find and remove string from stringtable; caller must free the string itself */ +/* + * Remove (unlink) a string from the string table. + * + * Just unlinks the duk_hstring, leaving link pointers as garbage. + * Caller must free the string itself. + */ + #if defined(DUK_USE_REFERENCE_COUNTING) -DUK_INTERNAL void duk_heap_string_remove(duk_heap *heap, duk_hstring *h) { - DUK_DDD(DUK_DDDPRINT("remove string from stringtable: %!O", (duk_heaphdr *) h)); +/* Unlink without a 'prev' pointer. */ +DUK_INTERNAL void duk_heap_strtable_unlink(duk_heap *heap, duk_hstring *h) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *slot; +#else + duk_hstring **slot; +#endif + duk_hstring *other; + duk_hstring *prev; + + DUK_DDD(DUK_DDDPRINT("remove: heap=%p, h=%p, blen=%lu, strhash=%lx", + (void *) heap, (void *) h, + (unsigned long) (h != NULL ? DUK_HSTRING_GET_BYTELEN(h) : 0), + (unsigned long) (h != NULL ? DUK_HSTRING_GET_HASH(h) : 0))); -#if defined(DUK_USE_STRTAB_CHAIN) - duk__remove_matching_hstring_chain(heap, h); -#elif defined(DUK_USE_STRTAB_PROBE) - duk__remove_matching_hstring_probe(heap, -#if defined(DUK_USE_HEAPPTR16) - heap->strtable16, -#else - heap->strtable, + DUK_ASSERT(heap != NULL); + DUK_ASSERT(h != NULL); + +#if defined(DUK__STRTAB_RESIZE_CHECK) + DUK_ASSERT(heap->st_count > 0); + heap->st_count--; #endif - heap->st_size, - h); + +#if defined(DUK_USE_STRTAB_PTRCOMP) + slot = heap->strtable16 + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); #else -#error internal error, invalid strtab options + slot = heap->strtable + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); #endif + other = DUK__HEAPPTR_DEC16(heap, *slot); + DUK_ASSERT(other != NULL); /* At least argument string is in the chain. */ + + prev = NULL; + while (other != h) { + prev = other; + other = other->hdr.h_next; + DUK_ASSERT(other != NULL); /* We'll eventually find 'h'. */ + } + if (prev != NULL) { + /* Middle of list. */ + prev->hdr.h_next = h->hdr.h_next; + } else { + /* Head of list. */ + *slot = DUK__HEAPPTR_ENC16(heap, h->hdr.h_next); + } + + /* There's no resize check on a string free. The next string + * intern will do one. + */ } +#endif /* DUK_USE_REFERENCE_COUNTING */ + +/* Unlink with a 'prev' pointer. */ +DUK_INTERNAL void duk_heap_strtable_unlink_prev(duk_heap *heap, duk_hstring *h, duk_hstring *prev) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *slot; +#else + duk_hstring **slot; #endif -#if defined(DUK_USE_MS_STRINGTABLE_RESIZE) -DUK_INTERNAL void duk_heap_force_strtab_resize(duk_heap *heap) { - duk_small_uint_t prev_mark_and_sweep_base_flags; - /* Force a resize so that DELETED entries are eliminated. - * Another option would be duk__recheck_strtab_size_probe(); - * but since that happens on every intern anyway, this whole - * check can now be disabled. - */ + DUK_DDD(DUK_DDDPRINT("remove: heap=%p, prev=%p, h=%p, blen=%lu, strhash=%lx", + (void *) heap, (void *) prev, (void *) h, + (unsigned long) (h != NULL ? DUK_HSTRING_GET_BYTELEN(h) : 0), + (unsigned long) (h != NULL ? DUK_HSTRING_GET_HASH(h) : 0))); - DUK_ASSERT((heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE) == 0); - prev_mark_and_sweep_base_flags = heap->mark_and_sweep_base_flags; - DUK__PREVENT_MS_SIDE_EFFECTS(heap); + DUK_ASSERT(heap != NULL); + DUK_ASSERT(h != NULL); + DUK_ASSERT(prev == NULL || prev->hdr.h_next == h); -#if defined(DUK_USE_STRTAB_CHAIN) - DUK_UNREF(heap); -#elif defined(DUK_USE_STRTAB_PROBE) - (void) duk__resize_strtab_probe(heap); +#if defined(DUK__STRTAB_RESIZE_CHECK) + DUK_ASSERT(heap->st_count > 0); + heap->st_count--; #endif - heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; -} + if (prev != NULL) { + /* Middle of list. */ + prev->hdr.h_next = h->hdr.h_next; + } else { + /* Head of list. */ +#if defined(DUK_USE_STRTAB_PTRCOMP) + slot = heap->strtable16 + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); +#else + slot = heap->strtable + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); #endif + DUK_ASSERT(DUK__HEAPPTR_DEC16(heap, *slot) == h); + *slot = DUK__HEAPPTR_ENC16(heap, h->hdr.h_next); + } +} + +/* + * Force string table resize check in mark-and-sweep. + */ -#if defined(DUK_USE_STRTAB_CHAIN) -DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap) { - /* Free strings in the stringtable and any allocations needed - * by the stringtable itself. +DUK_INTERNAL void duk_heap_strtable_force_resize(duk_heap *heap) { + /* Does only one grow/shrink step if needed. The heap->st_resizing + * flag protects against recursive resizing. */ - duk_uint_fast32_t i, j; - duk_strtab_entry *e; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t *lst; - duk_uint16_t null16 = heap->heapptr_null16; -#else - duk_hstring **lst; -#endif - duk_hstring *h; - for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { - e = heap->strtable + i; - if (e->listlen > 0) { -#if defined(DUK_USE_HEAPPTR16) - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); -#else - lst = e->u.strlist; -#endif - DUK_ASSERT(lst != NULL); + DUK_ASSERT(heap != NULL); + DUK_UNREF(heap); - for (j = 0; j < e->listlen; j++) { -#if defined(DUK_USE_HEAPPTR16) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[j]); - lst[j] = null16; -#else - h = lst[j]; - lst[j] = NULL; -#endif - /* strings may have inner refs (extdata) in some cases */ - if (h != NULL) { - duk_free_hstring(heap, h); - } - } -#if defined(DUK_USE_HEAPPTR16) - e->u.strlist16 = null16; -#else - e->u.strlist = NULL; -#endif - DUK_FREE(heap, lst); - } else { -#if defined(DUK_USE_HEAPPTR16) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16); - e->u.str16 = null16; +#if defined(DUK__STRTAB_RESIZE_CHECK) +#if defined(DUK_USE_STRTAB_PTRCOMP) + if (heap->strtable16 != NULL) { #else - h = e->u.str; - e->u.str = NULL; + if (heap->strtable != NULL) { #endif - if (h != NULL) { - duk_free_hstring(heap, h); - } - } - e->listlen = 0; + duk__strtable_resize_check(heap); } +#endif } -#endif /* DUK_USE_STRTAB_CHAIN */ -#if defined(DUK_USE_STRTAB_PROBE) -DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap) { - duk_uint_fast32_t i; - duk_hstring *h; +/* + * Free strings in the string table and the string table itself. + */ -#if defined(DUK_USE_HEAPPTR16) - if (heap->strtable16) { +DUK_INTERNAL void duk_heap_strtable_free(duk_heap *heap) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *strtable; + duk_uint16_t *st; #else - if (heap->strtable) { + duk_hstring **strtable; + duk_hstring **st; #endif - for (i = 0; i < (duk_uint_fast32_t) heap->st_size; i++) { -#if defined(DUK_USE_HEAPPTR16) - h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); -#else - h = heap->strtable[i]; + duk_hstring *h; + + DUK_ASSERT(heap != NULL); + +#if defined(DUK_USE_ASSERTIONS) + duk__strtable_assert_checks(heap); #endif - if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) { - continue; - } - DUK_ASSERT(h != NULL); - /* strings may have inner refs (extdata) in some cases */ + /* Strtable can be NULL if heap init fails. However, in that case + * heap->st_size is 0, so strtable == strtable_end and we skip the + * loop without a special check. + */ + strtable = DUK__GET_STRTABLE(heap); + st = strtable + heap->st_size; + DUK_ASSERT(strtable != NULL || heap->st_size == 0); + + while (strtable != st) { + --st; + h = DUK__HEAPPTR_DEC16(heap, *st); + while (h) { + duk_hstring *h_next; + h_next = h->hdr.h_next; + + /* Strings may have inner refs (extdata) in some cases. */ duk_free_hstring(heap, h); -#if 0 /* not strictly necessary */ - heap->strtable[i] = NULL; -#endif + + h = h_next; } -#if defined(DUK_USE_HEAPPTR16) - DUK_FREE(heap, heap->strtable16); -#else - DUK_FREE(heap, heap->strtable); -#endif -#if 0 /* not strictly necessary */ - heap->strtable = NULL; -#endif } + + DUK_FREE(heap, strtable); } -#endif /* DUK_USE_STRTAB_PROBE */ /* automatic undefs */ -#undef DUK__DELETED_MARKER -#undef DUK__HASH_INITIAL -#undef DUK__HASH_PROBE_STEP -#undef DUK__PREVENT_MS_SIDE_EFFECTS +#undef DUK__GET_STRTABLE +#undef DUK__HEAPPTR_DEC16 +#undef DUK__HEAPPTR_ENC16 +#undef DUK__STRTAB_U32_MAX_STRLEN #line 1 "duk_hobject_alloc.c" /* * Hobject allocation. @@ -48714,19 +50410,29 @@ * 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 duk_internal.h -> already included */ -DUK_LOCAL void duk__init_object_parts(duk_heap *heap, duk_hobject *obj, duk_uint_t hobject_flags) { +/* + * 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 - - /* XXX: macro? sets both heaphdr and object flags */ - obj->hdr.h_flags = hobject_flags; - DUK_HEAPHDR_SET_TYPE(&obj->hdr, DUK_HTYPE_OBJECT); /* also goes into flags */ - #if defined(DUK_USE_HEAPPTR16) - /* Zero encoded pointer is required to match NULL */ + /* 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); @@ -48735,14 +50441,22 @@ DUK_ASSERT_HEAPHDR_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. + /* 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. * @@ -48754,7 +50468,7 @@ * count before invoking any operation that might require memory allocation. */ -DUK_INTERNAL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags) { +DUK_INTERNAL duk_hobject *duk_hobject_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags) { duk_hobject *res; DUK_ASSERT(heap != NULL); @@ -48762,30 +50476,30 @@ /* 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_THREAD) == 0); - res = (duk_hobject *) DUK_ALLOC(heap, sizeof(duk_hobject)); - if (!res) { + res = (duk_hobject *) DUK_ALLOC_ZEROED(heap, sizeof(duk_hobject)); + if (DUK_UNLIKELY(res == NULL)) { return NULL; } - DUK_MEMZERO(res, sizeof(duk_hobject)); + DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(res)); - duk__init_object_parts(heap, res, hobject_flags); + duk__init_object_parts(heap, hobject_flags, res); + DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(res)); return res; } -DUK_INTERNAL duk_hcompfunc *duk_hcompfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags) { - duk_hcompfunc *res; +DUK_INTERNAL duk_hobject *duk_hobject_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { + duk_hobject *res; - res = (duk_hcompfunc *) DUK_ALLOC(heap, sizeof(duk_hcompfunc)); - if (!res) { - return NULL; - } - DUK_MEMZERO(res, sizeof(duk_hcompfunc)); + res = (duk_hobject *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hobject)); + return res; +} - duk__init_object_parts(heap, &res->obj, hobject_flags); +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. */ @@ -48801,17 +50515,10 @@ return res; } -DUK_INTERNAL duk_hnatfunc *duk_hnatfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags) { +DUK_INTERNAL duk_hnatfunc *duk_hnatfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { duk_hnatfunc *res; - res = (duk_hnatfunc *) DUK_ALLOC(heap, sizeof(duk_hnatfunc)); - if (!res) { - return NULL; - } - DUK_MEMZERO(res, sizeof(duk_hnatfunc)); - - duk__init_object_parts(heap, &res->obj, hobject_flags); - + res = (duk_hnatfunc *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hnatfunc)); #if defined(DUK_USE_EXPLICIT_NULL_INIT) res->func = NULL; #endif @@ -48820,17 +50527,10 @@ } #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_hbufobj *duk_hbufobj_alloc(duk_heap *heap, duk_uint_t hobject_flags) { +DUK_INTERNAL duk_hbufobj *duk_hbufobj_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { duk_hbufobj *res; - res = (duk_hbufobj *) DUK_ALLOC(heap, sizeof(duk_hbufobj)); - if (!res) { - return NULL; - } - DUK_MEMZERO(res, sizeof(duk_hbufobj)); - - duk__init_object_parts(heap, &res->obj, hobject_flags); - + 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; @@ -48841,24 +50541,22 @@ } #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ -/* - * Allocate a new thread. +/* 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. + * 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(duk_heap *heap, duk_uint_t hobject_flags) { +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 (!res) { + if (DUK_UNLIKELY(res == NULL)) { return NULL; } DUK_MEMZERO(res, sizeof(duk_hthread)); - duk__init_object_parts(heap, &res->obj, hobject_flags); + duk__init_object_parts(heap, hobject_flags, &res->obj); #if defined(DUK_USE_EXPLICIT_NULL_INIT) res->ptr_curr_pc = NULL; @@ -48868,6 +50566,7 @@ res->valstack_bottom = NULL; res->valstack_top = NULL; res->callstack = NULL; + res->callstack_curr = NULL; res->catchstack = NULL; res->resumer = NULL; res->compile_ctx = NULL, @@ -48877,7 +50576,7 @@ res->strs = NULL; #endif { - int i; + duk_small_uint_t i; for (i = 0; i < DUK_NUM_BUILTINS; i++) { res->builtins[i] = NULL; } @@ -48894,32 +50593,51 @@ return res; } -#if 0 /* unused now */ -DUK_INTERNAL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags) { - duk_hobject *res = duk_hobject_alloc(thr->heap, hobject_flags); - if (!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); } 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 -/* - * Allocate a new array. - */ + DUK_ASSERT(res->thread == NULL); + DUK_ASSERT(res->varmap == NULL); + DUK_ASSERT(res->regbase == 0); -DUK_INTERNAL duk_harray *duk_harray_alloc(duk_heap *heap, duk_uint_t hobject_flags) { - duk_harray *res; + return res; +} - res = (duk_harray *) DUK_ALLOC(heap, sizeof(duk_harray)); - if (!res) { - return NULL; - } - DUK_MEMZERO(res, sizeof(duk_harray)); +DUK_INTERNAL duk_hobjenv *duk_hobjenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { + duk_hobjenv *res; - duk__init_object_parts(heap, &res->obj, hobject_flags); + 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->length == 0); + DUK_ASSERT(res->target == NULL); return res; } @@ -49168,6 +50886,9 @@ */ DUK_LOCAL void duk__add_enum_key(duk_context *ctx, duk_hstring *k) { + /* 'k' may be unreachable on entry so must push without any + * potential for GC. + */ duk_push_hstring(ctx, k); duk_push_true(ctx); duk_put_prop(ctx, -3); @@ -49368,7 +51089,7 @@ /* This is a bit fragile: the string is not * reachable until it is pushed by the helper. */ - k = duk_heap_string_intern_u32_checked(thr, i); + k = duk_heap_strtable_intern_u32_checked(thr, i); DUK_ASSERT(k); duk__add_enum_key(ctx, k); @@ -49402,7 +51123,7 @@ if (DUK_TVAL_IS_UNUSED(tv)) { continue; } - k = duk_heap_string_intern_u32_checked(thr, i); /* Fragile reachability. */ + k = duk_heap_strtable_intern_u32_checked(thr, i); /* Fragile reachability. */ DUK_ASSERT(k); duk__add_enum_key(ctx, k); @@ -49432,7 +51153,7 @@ !DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(thr->heap, curr, i)) { continue; } - if (DUK_HSTRING_HAS_SYMBOL(k)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(k))) { if (!(enum_flags & DUK_ENUM_INCLUDE_HIDDEN) && DUK_HSTRING_HAS_HIDDEN(k)) { continue; @@ -49697,120 +51418,6 @@ /* automatic undefs */ #undef DUK__ENUM_START_INDEX -#line 1 "duk_hobject_finalizer.c" -/* - * Run an duk_hobject finalizer. Used for both reference counting - * and mark-and-sweep algorithms. Must never throw an error. - * - * There is no return value. Any return value or error thrown by - * the finalizer is ignored (although errors are debug logged). - * - * Notes: - * - * - The thread used for calling the finalizer is the same as the - * 'thr' argument. This may need to change later. - * - * - 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). - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_LOCAL duk_ret_t duk__finalize_helper(duk_context *ctx, void *udata) { - duk_hthread *thr; - - DUK_ASSERT(ctx != NULL); - thr = (duk_hthread *) ctx; - DUK_UNREF(udata); - - DUK_DDD(DUK_DDDPRINT("protected finalization helper running")); - - /* [... obj] */ - - /* 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(ctx, -1, DUK_STRIDX_INT_FINALIZER); /* -> [... obj finalizer] */ - if (!duk_is_callable(ctx, -1)) { - DUK_DDD(DUK_DDDPRINT("-> no finalizer or finalizer not callable")); - return 0; - } - duk_dup_m2(ctx); - duk_push_boolean(ctx, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap)); - DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling finalizer")); - duk_call(ctx, 2); /* [ ... obj finalizer obj heapDestruct ] -> [ ... obj retval ] */ - DUK_DDD(DUK_DDDPRINT("finalizer finished 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_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj) { - duk_context *ctx = (duk_context *) thr; - duk_ret_t rc; -#if defined(DUK_USE_ASSERTIONS) - duk_idx_t entry_top; -#endif - - DUK_DDD(DUK_DDDPRINT("running object finalizer for object: %p", (void *) obj)); - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(ctx != NULL); - DUK_ASSERT(obj != NULL); - DUK_ASSERT_VALSTACK_SPACE(thr, 1); - -#if defined(DUK_USE_ASSERTIONS) - entry_top = duk_get_top(ctx); -#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). - */ - - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); - if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj)) { - DUK_D(DUK_DPRINT("object already finalized, avoid running finalizer twice: %!O", obj)); - return; - } - DUK_HEAPHDR_SET_FINALIZED((duk_heaphdr *) obj); /* ensure never re-entered until rescue cycle complete */ - if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj)) { - /* This shouldn't happen; call sites should avoid looking up - * _Finalizer "through" a Proxy, but ignore if we come here - * with a Proxy to avoid finalizer re-entry. - */ - DUK_D(DUK_DPRINT("object is a proxy, skip finalizer call")); - return; - } - - /* XXX: use a NULL error handler for the finalizer call? */ - - DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling wrapped finalize helper")); - duk_push_hobject(ctx, obj); /* this also increases refcount by one */ - rc = duk_safe_call(ctx, duk__finalize_helper, NULL /*udata*/, 0 /*nargs*/, 1 /*nrets*/); /* -> [... obj retval/error] */ - DUK_ASSERT_TOP(ctx, 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(ctx, -1))); - } - duk_pop_2(ctx); /* -> [...] */ - - DUK_ASSERT_TOP(ctx, entry_top); -} -#endif /* DUK_USE_FINALIZER_SUPPORT */ #line 1 "duk_hobject_misc.c" /* * Misc support functions @@ -50017,7 +51624,7 @@ 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 error; + goto pc2line_error; } hdr = (duk_uint32_t *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, buf); @@ -50026,7 +51633,7 @@ /* 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 error; + goto pc2line_error; } curr_line = hdr[1 + hdr_index * 2]; @@ -50034,7 +51641,7 @@ 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 error; + goto pc2line_error; } /* @@ -50085,7 +51692,7 @@ DUK_DDD(DUK_DDDPRINT("pc2line lookup result: pc %ld -> line %ld", (long) pc, (long) curr_line)); return curr_line; - error: + pc2line_error: DUK_D(DUK_DPRINT("pc2line conversion failed for pc=%ld", (long) pc)); return 0; } @@ -50116,7 +51723,7 @@ #endif /* DUK_USE_PC2LINE */ #line 1 "duk_hobject_props.c" /* - * Hobject property set/get functionality. + * duk_hobject property access functionality. * * This is very central functionality for size, performance, and compliance. * It is also rather intricate; see hobject-algorithms.rst for discussion on @@ -50157,10 +51764,6 @@ * might be more appropriate. */ -/* - * XXX: duk_uint_fast32_t should probably be used in many places here. - */ - /* #include duk_internal.h -> already included */ /* @@ -50169,10 +51772,6 @@ #define DUK__NO_ARRAY_INDEX DUK_HSTRING_NO_ARRAY_INDEX -/* hash probe sequence */ -#define DUK__HASH_INITIAL(hash,h_size) DUK_HOBJECT_HASH_INITIAL((hash),(h_size)) -#define DUK__HASH_PROBE_STEP(hash) DUK_HOBJECT_HASH_PROBE_STEP((hash)) - /* marker values for hash part */ #define DUK__HASH_UNUSED DUK_HOBJECT_HASHIDX_UNUSED #define DUK__HASH_DELETED DUK_HOBJECT_HASHIDX_DELETED @@ -50335,14 +51934,26 @@ DUK_LOCAL duk_uint32_t duk__get_default_h_size(duk_uint32_t e_size) { DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES); - if (e_size >= DUK_HOBJECT_E_USE_HASH_LIMIT) { + if (e_size >= DUK_USE_HOBJECT_HASH_PROP_LIMIT) { duk_uint32_t res; + duk_uint32_t tmp; - /* result: hash_prime(floor(1.2 * e_size)) */ - res = duk_util_get_hash_prime(e_size + e_size / DUK_HOBJECT_H_SIZE_DIVISOR); - - /* if fails, e_size will be zero = not an issue, except performance-wise */ - DUK_ASSERT(res == 0 || res > e_size); + /* Hash size should be 2^N where N is chosen so that 2^N is + * larger than e_size. Extra shifting is used to ensure hash + * is relatively sparse. + */ + tmp = e_size; + res = 2; /* Result will be 2 ** (N + 1). */ + while (tmp >= 0x40) { + tmp >>= 6; + res <<= 6; + } + while (tmp != 0) { + tmp >>= 1; + res <<= 1; + } + DUK_ASSERT((DUK_HOBJECT_MAX_PROPERTIES << 2U) > DUK_HOBJECT_MAX_PROPERTIES); /* Won't wrap, even shifted by 2. */ + DUK_ASSERT(res > e_size); return res; } else { return 0; @@ -50356,7 +51967,7 @@ DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES); - res = (e_size + DUK_HOBJECT_E_MIN_GROW_ADD) / DUK_HOBJECT_E_MIN_GROW_DIVISOR; + res = (e_size + DUK_USE_HOBJECT_ENTRY_MINGROW_ADD) / DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR; DUK_ASSERT(res >= 1); /* important for callers */ return res; } @@ -50367,7 +51978,7 @@ DUK_ASSERT((duk_size_t) a_size <= DUK_HOBJECT_MAX_PROPERTIES); - res = (a_size + DUK_HOBJECT_A_MIN_GROW_ADD) / DUK_HOBJECT_A_MIN_GROW_DIVISOR; + res = (a_size + DUK_USE_HOBJECT_ARRAY_MINGROW_ADD) / DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR; DUK_ASSERT(res >= 1); /* important for callers */ return res; } @@ -50442,7 +52053,7 @@ * of the check, but may confuse debugging. */ - return (a_used < DUK_HOBJECT_A_ABANDON_LIMIT * (a_size >> 3)); + return (a_used < DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT * (a_size >> 3)); } /* Fast check for extending array: check whether or not a slow density check is required. */ @@ -50468,7 +52079,7 @@ * arr_idx > limit'' * ((old_size + 7) / 8) */ - return (arr_idx > DUK_HOBJECT_A_FAST_RESIZE_LIMIT * ((old_size + 7) >> 3)); + return (arr_idx > DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT * ((old_size + 7) >> 3)); } /* @@ -50620,29 +52231,26 @@ /* * Reallocate property allocation, moving properties to the new allocation. * - * Includes key compaction, rehashing, and can also optionally abandoning + * Includes key compaction, rehashing, and can also optionally abandon * the array part, 'migrating' array entries into the beginning of the - * new entry part. Arguments are not validated here, so e.g. new_h_size - * MUST be a valid prime. + * new entry part. * * There is no support for in-place reallocation or just compacting keys * without resizing the property allocation. This is intentional to keep - * code size minimal. + * code size minimal, but would be useful future work. * * The implementation is relatively straightforward, except for the array * abandonment process. Array abandonment requires that new string keys * are interned, which may trigger GC. All keys interned so far must be - * reachable for GC at all times; valstack is used for that now. + * reachable for GC at all times and correctly refcounted for; valstack is + * used for that now. * * Also, a GC triggered during this reallocation process must not interfere - * with the object being resized. This is currently controlled by using - * heap->mark_and_sweep_base_flags to indicate that no finalizers will be - * executed (as they can affect ANY object) and no objects are compacted - * (it would suffice to protect this particular object only, though). - * - * Note: a non-checked variant would be nice but is a bit tricky to - * implement for the array abandonment process. It's easy for - * everything else. + * with the object being resized. This is currently controlled by preventing + * finalizers (as they may affect ANY object) and object compaction in + * mark-and-sweep. It would suffice to protect only this particular object + * from compaction, however. DECREF refzero cascades are side effect free + * and OK. * * Note: because we need to potentially resize the valstack (as part * of abandoning the array part), any tval pointers to the valstack @@ -50656,7 +52264,7 @@ duk_uint32_t new_h_size, duk_bool_t abandon_array) { duk_context *ctx = (duk_context *) thr; - duk_small_uint_t prev_mark_and_sweep_base_flags; + duk_small_uint_t prev_ms_base_flags; duk_uint32_t new_alloc_size; duk_uint32_t new_e_size_adjusted; duk_uint8_t *new_p; @@ -50667,6 +52275,10 @@ duk_uint32_t *new_h; duk_uint32_t new_e_next; duk_uint_fast32_t i; + duk_size_t array_copy_size; +#if defined(DUK_USE_ASSERTIONS) + duk_bool_t prev_error_not_allowed; +#endif DUK_ASSERT(thr != NULL); DUK_ASSERT(ctx != NULL); @@ -50736,9 +52348,8 @@ /* * Property count check. This is the only point where we ensure that * we don't get more (allocated) property space that we can handle. - * There aren't hard limits as such, but some algorithms fail (e.g. - * finding next higher prime, selecting hash part size) if we get too - * close to the 4G property limit. + * There aren't hard limits as such, but some algorithms may fail + * if we get too close to the 4G property limit. * * Since this works based on allocation size (not actually used size), * the limit is a bit approximate but good enough in practice. @@ -50751,43 +52362,46 @@ /* * Compute new alloc size and alloc new area. * - * The new area is allocated as a dynamic buffer and placed into the - * valstack for reachability. The actual buffer is then detached at - * the end. - * - * Note: heap_mark_and_sweep_base_flags are altered here to ensure - * no-one touches this object while we're resizing and rehashing it. - * The flags must be reset on every exit path after it. Finalizers - * and compaction is prevented currently for all objects while it - * would be enough to restrict it only for the current object. + * The new area is not tracked in the heap at all, so it's critical + * we get to free/keep it in a controlled manner. */ - prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags; - thr->heap->mark_and_sweep_base_flags |= - DUK_MS_FLAG_NO_FINALIZERS | /* avoid attempts to add/remove object keys */ - DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid attempt to compact the current object */ +#if defined(DUK_USE_ASSERTIONS) + /* Whole path must be error throw free, but we may be called from + * within error handling so can't assert for error_not_allowed == 0. + */ + prev_error_not_allowed = thr->heap->error_not_allowed; + thr->heap->error_not_allowed = 1; +#endif + prev_ms_base_flags = thr->heap->ms_base_flags; + thr->heap->ms_base_flags |= + DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* Avoid attempt to compact the current object (all objects really). */ + thr->heap->pf_prevent_count++; /* Avoid finalizers. */ + DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */ new_alloc_size = DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size); DUK_DDD(DUK_DDDPRINT("new hobject allocation size is %ld", (long) new_alloc_size)); if (new_alloc_size == 0) { - /* for zero size, don't push anything on valstack */ DUK_ASSERT(new_e_size_adjusted == 0); DUK_ASSERT(new_a_size == 0); DUK_ASSERT(new_h_size == 0); new_p = NULL; } else { - /* This may trigger mark-and-sweep with arbitrary side effects, - * including an attempted resize of the object we're resizing, - * executing a finalizer which may add or remove properties of - * the object we're resizing etc. - */ - - /* Note: buffer is dynamic so that we can 'steal' the actual - * allocation later. + /* Alloc may trigger mark-and-sweep but no compaction, and + * cannot throw. */ - - new_p = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, new_alloc_size); /* errors out if out of memory */ - DUK_ASSERT(new_p != NULL); /* since new_alloc_size > 0 */ +#if 0 /* XXX: inject test */ + if (1) { + goto alloc_failed; + } +#endif + new_p = (duk_uint8_t *) DUK_ALLOC(thr->heap, new_alloc_size); + if (new_p == NULL) { + /* NULL always indicates alloc failure because + * new_alloc_size > 0. + */ + goto alloc_failed; + } } /* Set up pointers to the new property area: this is hidden behind a macro @@ -50808,27 +52422,27 @@ (void *) new_a, (void *) new_h)); /* - * Migrate array to start of entries if requested. + * Migrate array part to start of entries if requested. * * Note: from an enumeration perspective the order of entry keys matters. * Array keys should appear wherever they appeared before the array abandon - * operation. + * operation. (This no longer matters much because keys are ES2015 sorted.) */ if (abandon_array) { - /* - * Note: assuming new_a_size == 0, and that entry part contains - * no conflicting keys, refcounts do not need to be adjusted for - * the values, as they remain exactly the same. + /* Assuming new_a_size == 0, and that entry part contains + * no conflicting keys, refcounts do not need to be adjusted for + * the values, as they remain exactly the same. * - * The keys, however, need to be interned, incref'd, and be - * reachable for GC. Any intern attempt may trigger a GC and - * claim any non-reachable strings, so every key must be reachable - * at all times. + * The keys, however, need to be interned, incref'd, and be + * reachable for GC. Any intern attempt may trigger a GC and + * claim any non-reachable strings, so every key must be reachable + * at all times. Refcounts must be correct to satisfy refcount + * assertions. * - * A longjmp must not occur here, as the new_p allocation would - * be freed without these keys being decref'd, hence the messy - * decref handling if intern fails. + * A longjmp must not occur here, as the new_p allocation would + * leak. Refcounts would come out correctly as the interned + * strings are valstack tracked. */ DUK_ASSERT(new_a_size == 0); @@ -50857,20 +52471,29 @@ * must be careful. */ - /* never shrinks; auto-adds DUK_VALSTACK_INTERNAL_EXTRA, which is generous */ +#if 0 /* XXX: inject test */ + if (1) { + goto abandon_error; + } +#endif + /* Never shrinks; auto-adds DUK_VALSTACK_INTERNAL_EXTRA, which + * is generous. + */ if (!duk_check_stack(ctx, 1)) { goto abandon_error; } DUK_ASSERT_VALSTACK_SPACE(thr, 1); - key = duk_heap_string_intern_u32(thr->heap, i); - if (!key) { + key = duk_heap_strtable_intern_u32(thr->heap, i); + if (key == NULL) { goto abandon_error; } duk_push_hstring(ctx, key); /* keep key reachable for GC etc; guaranteed not to fail */ - /* key is now reachable in the valstack */ + /* Key is now reachable in the valstack, don't INCREF + * the new allocation yet (we'll steal the refcounts + * from the value stack once all keys are done). + */ - DUK_HSTRING_INCREF(thr, key); /* second incref for the entry reference */ new_e_k[new_e_next] = key; tv2 = &new_e_pv[new_e_next].v; /* array entries are all plain values */ DUK_TVAL_SET_TVAL(tv2, tv1); @@ -50884,8 +52507,9 @@ */ } + /* Steal refcounts from value stack. */ DUK_DDD(DUK_DDDPRINT("abandon array: pop %ld key temps from valstack", (long) new_e_next)); - duk_pop_n(ctx, new_e_next); + duk_pop_n_nodecref_unsafe(ctx, new_e_next); } /* @@ -50898,7 +52522,7 @@ DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL); key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i); - if (!key) { + if (key == NULL) { continue; } @@ -50913,53 +52537,46 @@ /* the entries [new_e_next, new_e_size_adjusted[ are left uninitialized on purpose (ok, not gc reachable) */ /* - * Copy array elements to new array part. + * Copy array elements to new array part. If the new array part is + * larger, initialize the unused entries as UNUSED because they are + * GC reachable. */ - if (new_a_size > DUK_HOBJECT_GET_ASIZE(obj)) { - /* copy existing entries as is */ - DUK_ASSERT(new_p != NULL && new_a != NULL); - if (DUK_HOBJECT_GET_ASIZE(obj) > 0) { - /* Avoid zero copy with an invalid pointer. If obj->p is NULL, - * the 'new_a' pointer will be invalid which is not allowed even - * when copy size is zero. - */ - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL); - DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0); - DUK_MEMCPY((void *) new_a, (void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), sizeof(duk_tval) * DUK_HOBJECT_GET_ASIZE(obj)); - } - - /* fill new entries with -unused- (required, gc reachable) */ - for (i = DUK_HOBJECT_GET_ASIZE(obj); i < new_a_size; i++) { - duk_tval *tv = &new_a[i]; - DUK_TVAL_SET_UNUSED(tv); - } - } else { #if defined(DUK_USE_ASSERTIONS) - /* caller must have decref'd values above new_a_size (if that is necessary) */ - if (!abandon_array) { - for (i = new_a_size; i < DUK_HOBJECT_GET_ASIZE(obj); i++) { - duk_tval *tv; - tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i); - - /* current assertion is quite strong: decref's and set to unused */ - DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv)); - } + /* Caller must have decref'd values above new_a_size (if that is necessary). */ + if (!abandon_array) { + for (i = new_a_size; i < DUK_HOBJECT_GET_ASIZE(obj); i++) { + duk_tval *tv; + tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i); + DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv)); } + } #endif - if (new_a_size > 0) { - /* Avoid zero copy with an invalid pointer. If obj->p is NULL, - * the 'new_a' pointer will be invalid which is not allowed even - * when copy size is zero. - */ - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL); - DUK_ASSERT(new_a_size > 0); - DUK_MEMCPY((void *) new_a, (void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), sizeof(duk_tval) * new_a_size); - } + if (new_a_size > DUK_HOBJECT_GET_ASIZE(obj)) { + array_copy_size = sizeof(duk_tval) * DUK_HOBJECT_GET_ASIZE(obj); + } else { + array_copy_size = sizeof(duk_tval) * new_a_size; + } + if (array_copy_size > 0) { + /* Avoid zero copy with an invalid pointer. If obj->p is NULL, + * the 'new_a' pointer will be invalid which is not allowed even + * when copy size is zero. + */ + DUK_ASSERT(new_a != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0); + DUK_MEMCPY((void *) new_a, + (const void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), + array_copy_size); + } + for (i = DUK_HOBJECT_GET_ASIZE(obj); i < new_a_size; i++) { + duk_tval *tv = &new_a[i]; + DUK_TVAL_SET_UNUSED(tv); } /* - * Rebuild the hash part always from scratch (guaranteed to finish). + * Rebuild the hash part always from scratch (guaranteed to finish + * as long as caller gave consistent parameters). * * Any resize of hash part requires rehashing. In addition, by rehashing * get rid of any elements marked deleted (DUK__HASH_DELETED) which is critical @@ -50967,7 +52584,11 @@ */ #if defined(DUK_USE_HOBJECT_HASH_PART) - if (DUK_UNLIKELY(new_h_size > 0)) { + if (new_h_size == 0) { + DUK_DDD(DUK_DDDPRINT("no hash part, no rehash")); + } else { + duk_uint32_t mask; + DUK_ASSERT(new_h != NULL); /* fill new_h with u32 0xff = UNUSED */ @@ -50976,13 +52597,15 @@ DUK_MEMSET(new_h, 0xff, sizeof(duk_uint32_t) * new_h_size); DUK_ASSERT(new_e_next <= new_h_size); /* equality not actually possible */ + + mask = new_h_size - 1; for (i = 0; i < new_e_next; i++) { duk_hstring *key = new_e_k[i]; duk_uint32_t j, step; DUK_ASSERT(key != NULL); - j = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), new_h_size); - step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key)); + j = DUK_HSTRING_GET_HASH(key) & mask; + step = 1; /* Cache friendly but clustering prone. */ for (;;) { DUK_ASSERT(new_h[j] != DUK__HASH_DELETED); /* should never happen */ @@ -50992,14 +52615,11 @@ break; } DUK_DDD(DUK_DDDPRINT("rebuild miss %ld, step %ld", (long) j, (long) step)); - j = (j + step) % new_h_size; + j = (j + step) & mask; - /* guaranteed to finish */ - DUK_ASSERT(j != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), new_h_size)); + /* Guaranteed to finish (hash is larger than #props). */ } } - } else { - DUK_DDD(DUK_DDDPRINT("no hash part, no rehash")); } #endif /* DUK_USE_HOBJECT_HASH_PART */ @@ -51038,30 +52658,20 @@ DUK_HOBJECT_SET_ASIZE(obj, new_a_size); DUK_HOBJECT_SET_HSIZE(obj, new_h_size); - if (new_p) { - /* - * Detach actual buffer from dynamic buffer in valstack, and - * pop it from the stack. - * - * XXX: the buffer object is certainly not reachable at this point, - * so it would be nice to free it forcibly even with only - * mark-and-sweep enabled. Not a big issue though. - */ - (void) duk_steal_buffer(ctx, -1, NULL); - duk_pop(ctx); - } else { - DUK_ASSERT(new_alloc_size == 0); - /* no need to pop, nothing was pushed */ - } - - /* clear array part flag only after switching */ + /* Clear array part flag only after switching. */ if (abandon_array) { DUK_HOBJECT_CLEAR_ARRAY_PART(obj); } DUK_DDD(DUK_DDDPRINT("resize result: %!O", (duk_heaphdr *) obj)); - thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; + DUK_ASSERT(thr->heap->pf_prevent_count > 0); + thr->heap->pf_prevent_count--; + thr->heap->ms_base_flags = prev_ms_base_flags; +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(thr->heap->error_not_allowed == 1); + thr->heap->error_not_allowed = prev_error_not_allowed; +#endif /* * Post resize assertions. @@ -51073,21 +52683,25 @@ return; /* - * Abandon array failed, need to decref keys already inserted - * into the beginning of new_e_k before unwinding valstack. + * Abandon array failed. We don't need to DECREF anything + * because the references in the new allocation are not + * INCREF'd until abandon is complete. The string interned + * keys are on the value stack and are handled normally by + * unwind. */ abandon_error: - DUK_D(DUK_DPRINT("hobject resize failed during abandon array, decref keys")); - i = new_e_next; - while (i > 0) { - i--; - DUK_ASSERT(new_e_k != NULL); - DUK_ASSERT(new_e_k[i] != NULL); - DUK_HSTRING_DECREF(thr, new_e_k[i]); /* side effects */ - } + alloc_failed: + DUK_D(DUK_DPRINT("object property table resize failed")); - thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; + DUK_FREE(thr->heap, new_p); /* OK for NULL. */ + + thr->heap->pf_prevent_count--; + thr->heap->ms_base_flags = prev_ms_base_flags; +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(thr->heap->error_not_allowed == 1); + thr->heap->error_not_allowed = prev_error_not_allowed; +#endif DUK_ERROR_ALLOC_FAILED(thr); } @@ -51239,7 +52853,7 @@ } #if defined(DUK_USE_HOBJECT_HASH_PART) - if (e_size >= DUK_HOBJECT_E_USE_HASH_LIMIT) { + if (e_size >= DUK_USE_HOBJECT_HASH_PROP_LIMIT) { h_size = duk__get_default_h_size(e_size); } else { h_size = 0; @@ -51300,13 +52914,15 @@ duk_uint32_t n; duk_uint32_t i, step; duk_uint32_t *h_base; + duk_uint32_t mask; DUK_DDD(DUK_DDDPRINT("duk_hobject_find_existing_entry() using hash part for lookup")); h_base = DUK_HOBJECT_H_GET_BASE(heap, obj); n = DUK_HOBJECT_GET_HSIZE(obj); - i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n); - step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key)); + mask = n - 1; + i = DUK_HSTRING_GET_HASH(key) & mask; + step = 1; /* Cache friendly but clustering prone. */ for (;;) { duk_uint32_t t; @@ -51334,10 +52950,9 @@ DUK_DDD(DUK_DDDPRINT("lookup miss i=%ld, t=%ld", (long) i, (long) t)); } - i = (i + step) % n; + i = (i + step) & mask; - /* guaranteed to finish, as hash is never full */ - DUK_ASSERT(i != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n)); + /* Guaranteed to finish (hash is larger than #props). */ } } #endif /* DUK_USE_HOBJECT_HASH_PART */ @@ -51442,13 +53057,14 @@ #if defined(DUK_USE_HOBJECT_HASH_PART) if (DUK_UNLIKELY(DUK_HOBJECT_GET_HSIZE(obj) > 0)) { - duk_uint32_t n; + duk_uint32_t n, mask; duk_uint32_t i, step; duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(thr->heap, obj); n = DUK_HOBJECT_GET_HSIZE(obj); - i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n); - step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key)); + mask = n - 1; + i = DUK_HSTRING_GET_HASH(key) & mask; + step = 1; /* Cache friendly but clustering prone. */ for (;;) { duk_uint32_t t = h_base[i]; @@ -51463,10 +53079,9 @@ break; } DUK_DDD(DUK_DDDPRINT("duk__alloc_entry_checked() miss %ld", (long) i)); - i = (i + step) % n; + i = (i + step) & mask; - /* guaranteed to find an empty slot */ - DUK_ASSERT(i != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), DUK_HOBJECT_GET_HSIZE(obj))); + /* Guaranteed to finish (hash is larger than #props). */ } } #endif /* DUK_USE_HOBJECT_HASH_PART */ @@ -51866,6 +53481,8 @@ DUK_DDD(DUK_DDDPRINT("string object exotic property get for key: %!O, arr_idx: %ld", (duk_heaphdr *) key, (long) arr_idx)); + /* XXX: charlen; avoid multiple lookups? */ + if (arr_idx != DUK__NO_ARRAY_INDEX) { duk_hstring *h_val; @@ -52106,7 +53723,7 @@ } /* not found in 'curr', next in prototype chain; impose max depth */ - if (sanity-- == 0) { + if (DUK_UNLIKELY(sanity-- == 0)) { if (flags & DUK_GETDESC_FLAG_IGNORE_PROTOLOOP) { /* treat like property not found */ break; @@ -52115,7 +53732,7 @@ } } curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); - } while (curr); + } while (curr != NULL); /* out_desc is left untouched (possibly garbage), caller must use return * value to determine whether out_desc can be looked up @@ -52465,7 +54082,7 @@ duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj); duk_int_t pop_count; - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { /* Symbols (ES2015 or hidden) don't have virtual properties. */ DUK_DDD(DUK_DDDPRINT("base object is a symbol, start lookup from symbol prototype")); curr = thr->builtins[DUK_BIDX_SYMBOL_PROTOTYPE]; @@ -52806,11 +54423,11 @@ /* XXX: option to pretend property doesn't exist if sanity limit is * hit might be useful. */ - if (sanity-- == 0) { + if (DUK_UNLIKELY(sanity-- == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); } curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); - } while (curr); + } while (curr != NULL); /* * Not found @@ -53490,7 +55107,7 @@ arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key); DUK_ASSERT(key != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { /* Symbols (ES2015 or hidden) don't have virtual properties. */ curr = thr->builtins[DUK_BIDX_SYMBOL_PROTOTYPE]; goto lookup; @@ -53906,11 +55523,11 @@ /* XXX: option to pretend property doesn't exist if sanity limit is * hit might be useful. */ - if (sanity-- == 0) { + if (DUK_UNLIKELY(sanity-- == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); } curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); - } while (curr); + } while (curr != NULL); /* * Property not found in prototype chain. @@ -54537,10 +56154,10 @@ /* Note: proxy handling must happen before key is string coerced. */ if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_DELETE_PROPERTY, tv_key, &h_target)) { - /* -> [ ... trap handler ] */ + /* -> [ ... obj key trap handler ] */ DUK_DDD(DUK_DDDPRINT("-> proxy object 'deleteProperty' for key %!T", (duk_tval *) tv_key)); duk_push_hobject(ctx, h_target); /* target */ - duk_push_tval(ctx, tv_key); /* P */ + duk_dup_m4(ctx); /* P */ duk_call_method(ctx, 2 /*nargs*/); tmp_bool = duk_to_boolean(ctx, -1); duk_pop(ctx); @@ -54551,6 +56168,7 @@ /* Target object must be checked for a conflicting * non-configurable property. */ + tv_key = DUK_GET_TVAL_NEGIDX(ctx, -1); arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key); DUK_ASSERT(key != NULL); @@ -54899,6 +56517,41 @@ } /* + * Fast finalizer check for an object. Walks the prototype chain, checking + * for finalizer presence using DUK_HOBJECT_FLAG_HAVE_FINALIZER which is kept + * in sync with the actual property when setting/removing the finalizer. + */ + +#if defined(DUK_USE_HEAPPTR16) +DUK_INTERNAL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_heap *heap, duk_hobject *obj) { +#else +DUK_INTERNAL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_hobject *obj) { +#endif + duk_uint_t sanity; + + DUK_ASSERT(obj != NULL); + + sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; + do { + if (DUK_UNLIKELY(DUK_HOBJECT_HAS_HAVE_FINALIZER(obj))) { + return 1; + } + if (DUK_UNLIKELY(sanity-- == 0)) { + DUK_D(DUK_DPRINT("prototype loop when checking for finalizer existence; returning false")); + return 0; + } +#if defined(DUK_USE_HEAPPTR16) + DUK_ASSERT(heap != NULL); + obj = DUK_HOBJECT_GET_PROTOTYPE(heap, obj); +#else + obj = DUK_HOBJECT_GET_PROTOTYPE(NULL, obj); /* 'heap' arg ignored */ +#endif + } while (obj != NULL); + + return 0; +} + +/* * Object.getOwnPropertyDescriptor() (E5 Sections 15.2.3.3, 8.10.4) * * [ ... key ] -> [ ... desc/undefined ] @@ -56156,8 +57809,6 @@ /* automatic undefs */ #undef DUK__HASH_DELETED -#undef DUK__HASH_INITIAL -#undef DUK__HASH_PROBE_STEP #undef DUK__HASH_UNUSED #undef DUK__NO_ARRAY_INDEX #undef DUK__VALSTACK_PROXY_LOOKUP @@ -56169,6 +57820,10 @@ /* #include duk_internal.h -> already included */ +/* + * duk_hstring charCodeAt, with and without surrogate awareness + */ + DUK_INTERNAL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos, duk_bool_t surrogate_aware) { duk_uint32_t boff; const duk_uint8_t *p, *p_start, *p_end; @@ -56216,16 +57871,87 @@ return cp1; } -#if !defined(DUK_USE_HSTRING_CLEN) -DUK_INTERNAL duk_size_t duk_hstring_get_charlen(duk_hstring *h) { - if (DUK_HSTRING_HAS_ASCII(h)) { +/* + * duk_hstring charlen access + */ + +#if defined(DUK_USE_HSTRING_CLEN) +DUK_LOCAL DUK_COLD duk_size_t duk__hstring_get_charlen_slowpath(duk_hstring *h) { + duk_size_t res; + + DUK_ASSERT(h->clen == 0); /* Checked by caller. */ + +#if defined(DUK_USE_ROM_STRINGS) + /* ROM strings have precomputed clen, but if the computed clen is zero + * we can still come here and can't write anything. + */ + if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { + return 0; + } +#endif + + res = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); +#if defined(DUK_USE_STRLEN16) + DUK_ASSERT(res <= 0xffffUL); /* Bytelength checked during interning. */ + h->clen16 = (duk_uint16_t) res; +#else + h->clen = (duk_uint32_t) res; +#endif + if (DUK_LIKELY(res == DUK_HSTRING_GET_BYTELEN(h))) { + DUK_HSTRING_SET_ASCII(h); + } + return res; +} +#else /* DUK_USE_HSTRING_CLEN */ +DUK_LOCAL duk_size_t duk__hstring_get_charlen_slowpath(duk_hstring *h) { + if (DUK_LIKELY(DUK_HSTRING_HAS_ASCII(h))) { /* Most practical strings will go here. */ return DUK_HSTRING_GET_BYTELEN(h); } else { - return duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); + /* ASCII flag is lazy, so set it here. */ + duk_size_t res; + + /* XXX: here we could use the strcache to speed up the + * computation (matters for 'i < str.length' loops). + */ + + res = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); + +#if defined(DUK_USE_ROM_STRINGS) + if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { + /* For ROM strings, can't write anything; ASCII flag + * is preset so we don't need to update it. + */ + return res; + } +#endif + if (DUK_LIKELY(res == DUK_HSTRING_GET_BYTELEN(h))) { + DUK_HSTRING_SET_ASCII(h); + } + return res; + } +} +#endif /* DUK_USE_HSTRING_CLEN */ + +#if defined(DUK_USE_HSTRING_CLEN) +DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) { +#if defined(DUK_USE_STRLEN16) + if (DUK_LIKELY(h->clen16 != 0)) { + return h->clen16; + } +#else + if (DUK_LIKELY(h->clen != 0)) { + return h->clen; } +#endif + return duk__hstring_get_charlen_slowpath(h); +} +#else /* DUK_USE_HSTRING_CLEN */ +DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) { + /* Always use slow path. */ + return duk__hstring_get_charlen_slowpath(h); } -#endif /* !DUK_USE_HSTRING_CLEN */ +#endif /* DUK_USE_HSTRING_CLEN */ #line 1 "duk_hthread_alloc.c" /* * duk_hthread allocation and freeing. @@ -56250,6 +57976,7 @@ DUK_ASSERT(thr->valstack_bottom == NULL); DUK_ASSERT(thr->valstack_top == NULL); DUK_ASSERT(thr->callstack == NULL); + DUK_ASSERT(thr->callstack_curr == NULL); DUK_ASSERT(thr->catchstack == NULL); /* valstack */ @@ -56279,6 +58006,7 @@ DUK_MEMZERO(thr->callstack, alloc_size); thr->callstack_size = DUK_CALLSTACK_INITIAL_SIZE; DUK_ASSERT(thr->callstack_top == 0); + DUK_ASSERT(thr->callstack_curr == NULL); /* catchstack */ alloc_size = sizeof(duk_catcher) * DUK_CATCHSTACK_INITIAL_SIZE; @@ -56360,12 +58088,13 @@ #if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT) DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) { duk_context *ctx; - duk_hobject *h1; + duk_hobject *h_global; #if defined(DUK_USE_ROM_GLOBAL_CLONE) - duk_hobject *h2; + duk_hobject *h_oldglobal; duk_uint8_t *props; duk_size_t alloc_size; #endif + duk_hobject *h_objenv; ctx = (duk_context *) thr; @@ -56373,83 +58102,84 @@ #if defined(DUK_USE_ROM_GLOBAL_INHERIT) /* Inherit from ROM-based global object: less RAM usage, less transparent. */ - h1 = duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL), - DUK_BIDX_GLOBAL); - DUK_ASSERT(h1 != NULL); + h_global = duk_push_object_helper(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL), + DUK_BIDX_GLOBAL); + DUK_ASSERT(h_global != NULL); #elif defined(DUK_USE_ROM_GLOBAL_CLONE) /* Clone the properties of the ROM-based global object to create a * fully RAM-based global object. Uses more memory than the inherit * model but more compliant. */ - h1 = duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL), - DUK_BIDX_OBJECT_PROTOTYPE); - DUK_ASSERT(h1 != NULL); - h2 = thr->builtins[DUK_BIDX_GLOBAL]; - DUK_ASSERT(h2 != NULL); + h_global = duk_push_object_helper(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL), + DUK_BIDX_OBJECT_PROTOTYPE); + DUK_ASSERT(h_global != NULL); + h_oldglobal = thr->builtins[DUK_BIDX_GLOBAL]; + DUK_ASSERT(h_oldglobal != NULL); /* Copy the property table verbatim; this handles attributes etc. * For ROM objects it's not necessary (or possible) to update * refcounts so leave them as is. */ - alloc_size = DUK_HOBJECT_P_ALLOC_SIZE(h2); + alloc_size = DUK_HOBJECT_P_ALLOC_SIZE(h_oldglobal); DUK_ASSERT(alloc_size > 0); - props = DUK_ALLOC(thr->heap, alloc_size); - if (!props) { - DUK_ERROR_ALLOC_FAILED(thr); - return; - } - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h2) != NULL); - DUK_MEMCPY((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h2), alloc_size); + props = DUK_ALLOC_CHECKED(thr, alloc_size); + DUK_ASSERT(props != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal) != NULL); + DUK_MEMCPY((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal), alloc_size); /* XXX: keep property attributes or tweak them here? * Properties will now be non-configurable even when they're * normally configurable for the global object. */ - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h1) == NULL); - DUK_HOBJECT_SET_PROPS(thr->heap, h1, props); - DUK_HOBJECT_SET_ESIZE(h1, DUK_HOBJECT_GET_ESIZE(h2)); - DUK_HOBJECT_SET_ENEXT(h1, DUK_HOBJECT_GET_ENEXT(h2)); - DUK_HOBJECT_SET_ASIZE(h1, DUK_HOBJECT_GET_ASIZE(h2)); - DUK_HOBJECT_SET_HSIZE(h1, DUK_HOBJECT_GET_HSIZE(h2)); + DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h_global) == NULL); + DUK_HOBJECT_SET_PROPS(thr->heap, h_global, props); + DUK_HOBJECT_SET_ESIZE(h_global, DUK_HOBJECT_GET_ESIZE(h_oldglobal)); + DUK_HOBJECT_SET_ENEXT(h_global, DUK_HOBJECT_GET_ENEXT(h_oldglobal)); + DUK_HOBJECT_SET_ASIZE(h_global, DUK_HOBJECT_GET_ASIZE(h_oldglobal)); + DUK_HOBJECT_SET_HSIZE(h_global, DUK_HOBJECT_GET_HSIZE(h_oldglobal)); #else -#error internal error in defines +#error internal error in config defines #endif - duk_hobject_compact_props(thr, h1); + duk_hobject_compact_props(thr, h_global); DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); - DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL])); /* no need to decref */ - thr->builtins[DUK_BIDX_GLOBAL] = h1; - DUK_HOBJECT_INCREF(thr, h1); - DUK_D(DUK_DPRINT("duplicated global object: %!O", h1)); - + DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL])); /* no need to decref: ROM object */ + thr->builtins[DUK_BIDX_GLOBAL] = h_global; + DUK_HOBJECT_INCREF(thr, h_global); + DUK_D(DUK_DPRINT("duplicated global object: %!O", h_global)); /* Create a fresh object environment for the global scope. This is * needed so that the global scope points to the newly created RAM-based * global object. */ - h1 = duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV), - -1); /* no prototype */ - DUK_ASSERT(h1 != NULL); - duk_dup_m2(ctx); - duk_dup_top(ctx); /* -> [ ... new_global new_globalenv new_global new_global ] */ - duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); /* always provideThis=true */ + h_objenv = (duk_hobject *) duk_hobjenv_alloc(thr, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV)); + DUK_ASSERT(h_objenv != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_objenv) == NULL); + duk_push_hobject(ctx, h_objenv); + + DUK_ASSERT(h_global != NULL); + ((duk_hobjenv *) h_objenv)->target = h_global; + DUK_HOBJECT_INCREF(thr, h_global); + DUK_ASSERT(((duk_hobjenv *) h_objenv)->has_this == 0); - duk_hobject_compact_props(thr, h1); DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL); - DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL_ENV])); /* no need to decref */ - thr->builtins[DUK_BIDX_GLOBAL_ENV] = h1; - DUK_HOBJECT_INCREF(thr, h1); - DUK_D(DUK_DPRINT("duplicated global env: %!O", h1)); + DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL_ENV])); /* no need to decref: ROM object */ + thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_objenv; + DUK_HOBJECT_INCREF(thr, h_objenv); + DUK_D(DUK_DPRINT("duplicated global env: %!O", h_objenv)); - duk_pop_2(ctx); + DUK_ASSERT_HOBJENV_VALID((duk_hobjenv *) h_objenv); + + duk_pop_2(ctx); /* Pop global object and global env. */ } #endif /* DUK_USE_ROM_GLOBAL_CLONE || DUK_USE_ROM_GLOBAL_INHERIT */ @@ -56555,11 +58285,11 @@ duk_small_int_t len = -1; /* must be signed */ class_num = (duk_small_uint_t) duk_bd_decode_varuint(bd); - len = (duk_small_int_t) duk_bd_decode_flagged(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/); + len = (duk_small_int_t) duk_bd_decode_flagged_signed(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/); if (class_num == DUK_HOBJECT_CLASS_FUNCTION) { duk_small_uint_t natidx; - duk_int_t c_nargs; /* must hold DUK_VARARGS */ + duk_small_int_t c_nargs; /* must hold DUK_VARARGS */ duk_c_function c_func; duk_int16_t magic; @@ -56571,7 +58301,7 @@ c_func = duk_bi_native_functions[natidx]; DUK_ASSERT(c_func != NULL); - c_nargs = (duk_small_uint_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, len /*def_value*/); + c_nargs = (duk_small_int_t) duk_bd_decode_flagged_signed(bd, DUK__NARGS_BITS, len /*def_value*/); if (c_nargs == DUK__NARGS_VARARGS_MARKER) { c_nargs = DUK_VARARGS; } @@ -56614,8 +58344,31 @@ ((duk_hnatfunc *) h)->magic = magic; } else if (class_num == DUK_HOBJECT_CLASS_ARRAY) { duk_push_array(ctx); + } else if (class_num == DUK_HOBJECT_CLASS_OBJENV) { + duk_hobjenv *env; + duk_hobject *global; + + DUK_ASSERT(i == DUK_BIDX_GLOBAL_ENV); + DUK_ASSERT(DUK_BIDX_GLOBAL_ENV > DUK_BIDX_GLOBAL); + + env = duk_hobjenv_alloc(thr, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV)); + DUK_ASSERT(env->target == NULL); + duk_push_hobject(ctx, (duk_hobject *) env); + + global = duk_known_hobject(ctx, DUK_BIDX_GLOBAL); + DUK_ASSERT(global != NULL); + env->target = global; + DUK_HOBJECT_INCREF(thr, global); + DUK_ASSERT(env->has_this == 0); + + DUK_ASSERT_HOBJENV_VALID(env); } else { + DUK_ASSERT(class_num != DUK_HOBJECT_CLASS_DECENV); + (void) duk_push_object_helper(ctx, + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_EXTENSIBLE, -1); /* no prototype or class yet */ @@ -56664,14 +58417,13 @@ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_COMPFUNC(h)); /* DUK_HOBJECT_FLAG_NATFUNC varies */ - DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(h)); + DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(h) || class_num == DUK_HOBJECT_CLASS_ARRAY); /* DUK_HOBJECT_FLAG_STRICT varies */ DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(h) || /* all native functions have NEWENV */ DUK_HOBJECT_HAS_NEWENV(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(h)); - DUK_ASSERT(!DUK_HOBJECT_HAS_ENVRECCLOSED(h)); /* DUK_HOBJECT_FLAG_EXOTIC_ARRAY varies */ /* DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ varies */ DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h)); @@ -57020,12 +58772,8 @@ #endif " " /* Low memory options */ -#if defined(DUK_USE_STRTAB_CHAIN) - "c" /* chain */ -#elif defined(DUK_USE_STRTAB_PROBE) - "p" /* probe */ -#else - "?" +#if defined(DUK_USE_STRTAB_PTRCOMP) + "s" #endif #if !defined(DUK_USE_HEAPPTR16) && !defined(DUK_DATAPTR16) && !defined(DUK_FUNCPTR16) "n" @@ -57160,7 +58908,6 @@ /* Order of unwinding is important */ duk_hthread_catchstack_unwind(thr, 0); - duk_hthread_callstack_unwind(thr, 0); /* side effects, possibly errors */ thr->valstack_bottom = thr->valstack; @@ -57183,16 +58930,6 @@ */ } -DUK_INTERNAL duk_activation *duk_hthread_get_current_activation(duk_hthread *thr) { - DUK_ASSERT(thr != NULL); - - if (thr->callstack_top > 0) { - return thr->callstack + thr->callstack_top - 1; - } else { - return NULL; - } -} - #if defined(DUK_USE_DEBUGGER_SUPPORT) DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act) { duk_instr_t *bcode; @@ -57238,7 +58975,9 @@ if (thr->ptr_curr_pc != NULL) { /* ptr_curr_pc != NULL only when bytecode executor is active. */ DUK_ASSERT(thr->callstack_top > 0); - act = thr->callstack + thr->callstack_top - 1; + DUK_ASSERT(thr->callstack_curr != NULL); + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); act->curr_pc = *thr->ptr_curr_pc; } } @@ -57251,7 +58990,9 @@ if (thr->ptr_curr_pc != NULL) { /* ptr_curr_pc != NULL only when bytecode executor is active. */ DUK_ASSERT(thr->callstack_top > 0); - act = thr->callstack + thr->callstack_top - 1; + DUK_ASSERT(thr->callstack_curr != NULL); + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); act->curr_pc = *thr->ptr_curr_pc; thr->ptr_curr_pc = NULL; } @@ -57281,8 +59022,7 @@ /* #include duk_internal.h -> already included */ -/* check that there is space for at least one new entry */ -DUK_INTERNAL void duk_hthread_callstack_grow(duk_hthread *thr) { +DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__hthread_do_callstack_grow(duk_hthread *thr) { duk_activation *new_ptr; duk_size_t old_size; duk_size_t new_size; @@ -57291,10 +59031,6 @@ DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */ DUK_ASSERT(thr->callstack_size >= thr->callstack_top); - if (thr->callstack_top < thr->callstack_size) { - return; - } - old_size = thr->callstack_size; new_size = old_size + DUK_CALLSTACK_GROW_STEP; @@ -57319,10 +59055,28 @@ thr->callstack = new_ptr; thr->callstack_size = new_size; + if (thr->callstack_top > 0) { + thr->callstack_curr = thr->callstack + thr->callstack_top - 1; + } else { + thr->callstack_curr = NULL; + } + /* note: any entries above the callstack top are garbage and not zeroed */ } -DUK_INTERNAL void duk_hthread_callstack_shrink_check(duk_hthread *thr) { +/* check that there is space for at least one new entry */ +DUK_INTERNAL void duk_hthread_callstack_grow(duk_hthread *thr) { + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */ + DUK_ASSERT(thr->callstack_size >= thr->callstack_top); + + if (DUK_LIKELY(thr->callstack_top < thr->callstack_size)) { + return; + } + duk__hthread_do_callstack_grow(thr); +} + +DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__hthread_do_callstack_shrink(duk_hthread *thr) { duk_size_t new_size; duk_activation *p; @@ -57330,10 +59084,6 @@ DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */ DUK_ASSERT(thr->callstack_size >= thr->callstack_top); - if (thr->callstack_size - thr->callstack_top < DUK_CALLSTACK_SHRINK_THRESHOLD) { - return; - } - new_size = thr->callstack_top + DUK_CALLSTACK_SHRINK_SPARE; DUK_ASSERT(new_size >= thr->callstack_top); @@ -57349,6 +59099,12 @@ if (p) { thr->callstack = p; thr->callstack_size = new_size; + + if (thr->callstack_top > 0) { + thr->callstack_curr = thr->callstack + thr->callstack_top - 1; + } else { + thr->callstack_curr = NULL; + } } else { /* Because new_size != 0, if condition doesn't need to be * (p != NULL || new_size == 0). @@ -57360,7 +59116,19 @@ /* note: any entries above the callstack top are garbage and not zeroed */ } -DUK_INTERNAL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top) { +DUK_INTERNAL void duk_hthread_callstack_shrink_check(duk_hthread *thr) { + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */ + DUK_ASSERT(thr->callstack_size >= thr->callstack_top); + + if (DUK_LIKELY(thr->callstack_size - thr->callstack_top < DUK_CALLSTACK_SHRINK_THRESHOLD)) { + return; + } + + duk__hthread_do_callstack_shrink(thr); +} + +DUK_INTERNAL void duk_hthread_callstack_unwind_norz(duk_hthread *thr, duk_size_t new_top) { duk_size_t idx; DUK_DDD(DUK_DDDPRINT("unwind callstack top of thread %p from %ld to %ld", @@ -57389,9 +59157,7 @@ while (idx > new_top) { duk_activation *act; duk_hobject *func; -#if defined(DUK_USE_REFERENCE_COUNTING) duk_hobject *tmp; -#endif #if defined(DUK_USE_DEBUGGER_SUPPORT) duk_heap *heap; #endif @@ -57433,12 +59199,12 @@ DUK_TVAL_SET_NULL(tv_caller); /* no incref needed */ DUK_ASSERT(act->prev_caller == NULL); } - DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */ + DUK_TVAL_DECREF_NORZ(thr, &tv_tmp); } else { h_tmp = act->prev_caller; if (h_tmp) { act->prev_caller = NULL; - DUK_HOBJECT_DECREF(thr, h_tmp); /* side effects */ + DUK_HOBJECT_DECREF_NORZ(thr, h_tmp); } } act = thr->callstack + idx; /* avoid side effects */ @@ -57458,8 +59224,12 @@ /* Pause for all step types: step into, step over, step out. * This is the only place explicitly handling a step out. */ - DUK_HEAP_SET_PAUSED(heap); - DUK_ASSERT(heap->dbg_step_thread == NULL); + if (duk_debug_is_paused(heap)) { + DUK_D(DUK_DPRINT("step pause trigger but already paused, ignoring")); + } else { + duk_debug_set_paused(heap); + DUK_ASSERT(heap->dbg_step_thread == NULL); + } } #endif @@ -57480,42 +59250,19 @@ } /* func is NULL for lightfunc */ + /* Catch sites are required to clean up their environments + * in FINALLY part before propagating, so this should + * always hold here. + */ DUK_ASSERT(act->lex_env == act->var_env); + if (act->var_env != NULL) { DUK_DDD(DUK_DDDPRINT("closing var_env record %p -> %!O", (void *) act->var_env, (duk_heaphdr *) act->var_env)); - duk_js_close_environment_record(thr, act->var_env, func, act->idx_bottom); + duk_js_close_environment_record(thr, act->var_env); act = thr->callstack + idx; /* avoid side effect issues */ } -#if 0 - if (act->lex_env != NULL) { - if (act->lex_env == act->var_env) { - /* common case, already closed, so skip */ - DUK_DD(DUK_DDPRINT("lex_env and var_env are the same and lex_env " - "already closed -> skip closing lex_env")); - ; - } else { - DUK_DD(DUK_DDPRINT("closing lex_env record %p -> %!O", - (void *) act->lex_env, (duk_heaphdr *) act->lex_env)); - duk_js_close_environment_record(thr, act->lex_env, DUK_ACT_GET_FUNC(act), act->idx_bottom); - act = thr->callstack + idx; /* avoid side effect issues */ - } - } -#endif - - DUK_ASSERT((act->lex_env == NULL) || - ((duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_VARMAP(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL))); - - DUK_ASSERT((act->var_env == NULL) || - ((duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_VARMAP(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL))); - skip_env_close: /* @@ -57528,55 +59275,38 @@ } /* - * Reference count updates - * - * Note: careful manipulation of refcounts. The top is - * not updated yet, so all the activations are reachable - * for mark-and-sweep (which may be triggered by decref). - * However, the pointers are NULL so this is not an issue. + * Reference count updates, using NORZ macros so we don't + * need to handle side effects. */ -#if defined(DUK_USE_REFERENCE_COUNTING) - tmp = act->var_env; -#endif + DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, act->var_env); act->var_env = NULL; -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); - act = thr->callstack + idx; /* avoid side effect issues */ -#endif - -#if defined(DUK_USE_REFERENCE_COUNTING) - tmp = act->lex_env; -#endif + DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, act->lex_env); act->lex_env = NULL; -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); - act = thr->callstack + idx; /* avoid side effect issues */ -#endif /* Note: this may cause a corner case situation where a finalizer * may see a currently reachable activation whose 'func' is NULL. */ -#if defined(DUK_USE_REFERENCE_COUNTING) tmp = DUK_ACT_GET_FUNC(act); -#endif + DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp); + DUK_UNREF(tmp); act->func = NULL; -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); - act = thr->callstack + idx; /* avoid side effect issues */ - DUK_UNREF(act); -#endif } thr->callstack_top = new_top; + if (new_top > 0) { + thr->callstack_curr = thr->callstack + new_top - 1; + } else { + thr->callstack_curr = NULL; + } /* * We could clear the book-keeping variables for the topmost activation, * but don't do so now. */ #if 0 - if (thr->callstack_top > 0) { - duk_activation *act = thr->callstack + thr->callstack_top - 1; + if (thr->callstack_curr != NULL) { + duk_activation *act = thr->callstack_curr; act->idx_retval = 0; } #endif @@ -57587,7 +59317,12 @@ */ } -DUK_INTERNAL void duk_hthread_catchstack_grow(duk_hthread *thr) { +DUK_INTERNAL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top) { + duk_hthread_callstack_unwind_norz(thr, new_top); + DUK_REFZERO_CHECK_FAST(thr); +} + +DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__hthread_do_catchstack_grow(duk_hthread *thr) { duk_catcher *new_ptr; duk_size_t old_size; duk_size_t new_size; @@ -57596,10 +59331,6 @@ DUK_ASSERT_DISABLE(thr->catchstack_top); /* avoid warning (unsigned) */ DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top); - if (thr->catchstack_top < thr->catchstack_size) { - return; - } - old_size = thr->catchstack_size; new_size = old_size + DUK_CATCHSTACK_GROW_STEP; @@ -57627,7 +59358,19 @@ /* note: any entries above the catchstack top are garbage and not zeroed */ } -DUK_INTERNAL void duk_hthread_catchstack_shrink_check(duk_hthread *thr) { +DUK_INTERNAL void duk_hthread_catchstack_grow(duk_hthread *thr) { + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->catchstack_top); /* avoid warning (unsigned) */ + DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top); + + if (DUK_LIKELY(thr->catchstack_top < thr->catchstack_size)) { + return; + } + + duk__hthread_do_catchstack_grow(thr); +} + +DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__hthread_do_catchstack_shrink(duk_hthread *thr) { duk_size_t new_size; duk_catcher *p; @@ -57635,10 +59378,6 @@ DUK_ASSERT_DISABLE(thr->catchstack_top >= 0); /* avoid warning (unsigned) */ DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top); - if (thr->catchstack_size - thr->catchstack_top < DUK_CATCHSTACK_SHRINK_THRESHOLD) { - return; - } - new_size = thr->catchstack_top + DUK_CATCHSTACK_SHRINK_SPARE; DUK_ASSERT(new_size >= thr->catchstack_top); @@ -57665,7 +59404,19 @@ /* note: any entries above the catchstack top are garbage and not zeroed */ } -DUK_INTERNAL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top) { +DUK_INTERNAL void duk_hthread_catchstack_shrink_check(duk_hthread *thr) { + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->catchstack_top >= 0); /* avoid warning (unsigned) */ + DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top); + + if (DUK_LIKELY(thr->catchstack_size - thr->catchstack_top < DUK_CATCHSTACK_SHRINK_THRESHOLD)) { + return; + } + + duk__hthread_do_catchstack_shrink(thr); +} + +DUK_INTERNAL void duk_hthread_catchstack_unwind_norz(duk_hthread *thr, duk_size_t new_top) { duk_size_t idx; DUK_DDD(DUK_DDDPRINT("unwind catchstack top of thread %p from %ld to %ld", @@ -57721,7 +59472,8 @@ env = act->lex_env; /* current lex_env of the activation (created for catcher) */ DUK_ASSERT(env != NULL); /* must be, since env was created when catcher was created */ act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env); /* prototype is lex_env before catcher created */ - DUK_HOBJECT_DECREF(thr, env); + DUK_HOBJECT_INCREF(thr, act->lex_env); + DUK_HOBJECT_DECREF_NORZ(thr, env); /* There is no need to decref anything else than 'env': if 'env' * becomes unreachable, refzero will handle decref'ing its prototype. @@ -57733,6 +59485,100 @@ /* note: any entries above the catchstack top are garbage and not zeroed */ } + +DUK_INTERNAL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top) { + duk_hthread_catchstack_unwind_norz(thr, new_top); + DUK_REFZERO_CHECK_FAST(thr); +} + +#if defined(DUK_USE_FINALIZER_TORTURE) +DUK_INTERNAL void duk_hthread_valstack_torture_realloc(duk_hthread *thr) { + duk_size_t alloc_size; + duk_tval *new_ptr; + duk_ptrdiff_t end_off; + duk_ptrdiff_t bottom_off; + duk_ptrdiff_t top_off; + + if (thr->valstack == NULL) { + return; + } + + end_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack); + bottom_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack); + top_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack); + alloc_size = (duk_size_t) end_off; + if (alloc_size == 0) { + return; + } + + new_ptr = (duk_tval *) DUK_ALLOC(thr->heap, alloc_size); + if (new_ptr != NULL) { + DUK_MEMCPY((void *) new_ptr, (const void *) thr->valstack, alloc_size); + DUK_MEMSET((void *) thr->valstack, 0x55, alloc_size); + DUK_FREE(thr->heap, (void *) thr->valstack); + thr->valstack = new_ptr; + thr->valstack_end = (duk_tval *) ((duk_uint8_t *) new_ptr + end_off); + thr->valstack_bottom = (duk_tval *) ((duk_uint8_t *) new_ptr + bottom_off); + thr->valstack_top = (duk_tval *) ((duk_uint8_t *) new_ptr + top_off); + /* No change in size. */ + } else { + DUK_D(DUK_DPRINT("failed to realloc valstack for torture, ignore")); + } +} + +DUK_INTERNAL void duk_hthread_callstack_torture_realloc(duk_hthread *thr) { + duk_size_t alloc_size; + duk_activation *new_ptr; + duk_ptrdiff_t curr_off; + + if (thr->callstack == NULL) { + return; + } + + curr_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->callstack_curr - (duk_uint8_t *) thr->callstack); + alloc_size = sizeof(duk_activation) * thr->callstack_size; + if (alloc_size == 0) { + return; + } + + new_ptr = (duk_activation *) DUK_ALLOC(thr->heap, alloc_size); + if (new_ptr != NULL) { + DUK_MEMCPY((void *) new_ptr, (const void *) thr->callstack, alloc_size); + DUK_MEMSET((void *) thr->callstack, 0x55, alloc_size); + DUK_FREE(thr->heap, (void *) thr->callstack); + thr->callstack = new_ptr; + thr->callstack_curr = (duk_activation *) ((duk_uint8_t *) new_ptr + curr_off); + /* No change in size. */ + } else { + DUK_D(DUK_DPRINT("failed to realloc callstack for torture, ignore")); + } +} + +DUK_INTERNAL void duk_hthread_catchstack_torture_realloc(duk_hthread *thr) { + duk_size_t alloc_size; + duk_catcher *new_ptr; + + if (thr->catchstack == NULL) { + return; + } + + alloc_size = sizeof(duk_catcher) * thr->catchstack_size; + if (alloc_size == 0) { + return; + } + + new_ptr = (duk_catcher *) DUK_ALLOC(thr->heap, alloc_size); + if (new_ptr != NULL) { + DUK_MEMCPY((void *) new_ptr, (const void *) thr->catchstack, alloc_size); + DUK_MEMSET((void *) thr->catchstack, 0x55, alloc_size); + DUK_FREE(thr->heap, (void *) thr->catchstack); + thr->catchstack = new_ptr; + /* No change in size. */ + } else { + DUK_D(DUK_DPRINT("failed to realloc catchstack for torture, ignore")); + } +} +#endif /* DUK_USE_FINALIZER_TORTURE */ #line 1 "duk_js_arith.c" /* * Shared helpers for arithmetic operations @@ -57895,6 +59741,8 @@ /* #include duk_internal.h -> already included */ +/* XXX: heap->error_not_allowed for success path too? */ + /* * Forward declarations. */ @@ -58050,16 +59898,19 @@ arg = duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_ARRAY_PART | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARGUMENTS), DUK_BIDX_OBJECT_PROTOTYPE); DUK_ASSERT(arg != NULL); (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), -1); /* no prototype */ (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), -1); /* no prototype */ i_arg = duk_get_top(ctx) - 3; @@ -58347,6 +60198,8 @@ duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_LENGTH); /* -> [ ... func this arg1 ... argN _Args length ] */ len = (duk_idx_t) duk_require_int(ctx, -1); duk_pop(ctx); + + duk_require_stack(ctx, len); for (i = 0; i < len; i++) { /* XXX: very slow - better to bulk allocate a gap, and copy * from args_array directly (we know it has a compact array @@ -58369,7 +60222,7 @@ (long) num_stack_args, (long) idx_func, duk_get_tval(ctx, idx_func))); } while (--sanity > 0); - if (sanity == 0) { + if (DUK_UNLIKELY(sanity == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_BOUND_CHAIN_LIMIT); } @@ -58443,7 +60296,9 @@ return; } - act_callee = thr->callstack + thr->callstack_top - 1; + DUK_ASSERT(thr->callstack_top > 0); + act_callee = thr->callstack_curr; + DUK_ASSERT(act_callee != NULL); act_caller = (thr->callstack_top >= 2 ? act_callee - 1 : NULL); /* XXX: check .caller writability? */ @@ -58924,16 +60779,6 @@ */ duk__handle_call_inner(thr, num_stack_args, call_flags, idx_func); - /* Success path handles */ - DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth); - DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc); - - /* Longjmp state is kept clean in success path */ - DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN); - DUK_ASSERT(thr->heap->lj.iserror == 0); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1)); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); - thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr; return DUK_EXEC_SUCCESS; @@ -58960,11 +60805,6 @@ idx_func, old_jmpbuf_ptr); - /* Longjmp state is cleaned up by error handling */ - DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN); - DUK_ASSERT(thr->heap->lj.iserror == 0); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1)); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); return DUK_EXEC_ERROR; } #if defined(DUK_USE_CPP_EXCEPTIONS) @@ -58990,6 +60830,7 @@ entry_ptr_curr_pc, idx_func, old_jmpbuf_ptr); + return DUK_EXEC_ERROR; } } catch (...) { @@ -59010,6 +60851,7 @@ entry_ptr_curr_pc, idx_func, old_jmpbuf_ptr); + return DUK_EXEC_ERROR; } } @@ -59200,7 +61042,8 @@ duk_hthread_callstack_grow(thr); - if (thr->callstack_top > 0) { + act = thr->callstack_curr; + if (act != NULL) { /* * Update idx_retval of current activation. * @@ -59211,12 +61054,13 @@ * the Ecmascript call's idx_retval must be set for things to work. */ - (thr->callstack + thr->callstack_top - 1)->idx_retval = entry_valstack_bottom_index + idx_func; + act->idx_retval = entry_valstack_bottom_index + idx_func; } DUK_ASSERT(thr->callstack_top < thr->callstack_size); act = thr->callstack + thr->callstack_top; thr->callstack_top++; + thr->callstack_curr = act; DUK_ASSERT(thr->callstack_top <= thr->callstack_size); DUK_ASSERT(thr->valstack_top > thr->valstack_bottom); /* at least effective 'this' */ DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func)); @@ -59307,8 +61151,8 @@ #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) if (func) { duk__update_func_caller_prop(thr, func); + act = thr->callstack_curr; } - act = thr->callstack + thr->callstack_top - 1; #endif /* [ ... func this arg1 ... argN ] */ @@ -59353,7 +61197,7 @@ /* [ ... func this arg1 ... argN envobj ] */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; act->lex_env = env; act->var_env = env; DUK_HOBJECT_INCREF(thr, env); @@ -59368,6 +61212,7 @@ DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func)); duk__handle_oldenv_for_call(thr, func, act); + /* No need to re-lookup 'act' at present: no side effects. */ DUK_ASSERT(act->lex_env != NULL); DUK_ASSERT(act->var_env != NULL); @@ -59404,6 +61249,7 @@ * new value stack bottom, and call the target. */ + act = thr->callstack_curr; if (func != NULL && DUK_HOBJECT_IS_COMPFUNC(func)) { /* * Ecmascript call @@ -59446,10 +61292,9 @@ DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); /* may need unwind */ DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1); - DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1); - duk_hthread_catchstack_unwind(thr, entry_catchstack_top); + duk_hthread_catchstack_unwind_norz(thr, entry_catchstack_top); duk_hthread_catchstack_shrink_check(thr); - duk_hthread_callstack_unwind(thr, entry_callstack_top); + duk_hthread_callstack_unwind_norz(thr, entry_callstack_top); /* XXX: may now fail */ duk_hthread_callstack_shrink_check(thr); thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index; @@ -59511,7 +61356,7 @@ DUK_ASSERT(thr->catchstack_top == entry_catchstack_top); /* no need to unwind */ DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1); - duk_hthread_callstack_unwind(thr, entry_callstack_top); + duk_hthread_callstack_unwind_norz(thr, entry_callstack_top); duk_hthread_callstack_shrink_check(thr); thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index; @@ -59566,9 +61411,12 @@ DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */ thr->state = (duk_uint8_t) entry_thread_state; + /* Disabled assert: triggered with some torture tests. */ +#if 0 DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */ (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */ (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */ +#endif thr->heap->call_recursion_depth = entry_call_recursion_depth; @@ -59581,7 +61429,7 @@ * on every return should have no ill effect. */ #if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + if (duk_debug_is_attached(thr->heap)) { DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt")); DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init); thr->interrupt_init -= thr->interrupt_counter; @@ -59594,6 +61442,14 @@ duk__interrupt_fixup(thr, entry_curr_thread); #endif + /* Restored by success path. */ + DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth); + DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc); + + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + + DUK_REFZERO_CHECK_FAST(thr); + return; thread_state_error: @@ -59625,6 +61481,7 @@ * the error here. */ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW); + DUK_ASSERT_LJSTATE_SET(thr->heap); DUK_ASSERT(thr->callstack_top >= entry_callstack_top); DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); @@ -59646,9 +61503,9 @@ * scopes; this is a sandboxing issue, described in: * https://github.com/svaarala/duktape/issues/476 */ - duk_hthread_catchstack_unwind(thr, entry_catchstack_top); + duk_hthread_catchstack_unwind_norz(thr, entry_catchstack_top); duk_hthread_catchstack_shrink_check(thr); - duk_hthread_callstack_unwind(thr, entry_callstack_top); + duk_hthread_callstack_unwind_norz(thr, entry_callstack_top); duk_hthread_callstack_shrink_check(thr); thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index; @@ -59699,9 +61556,12 @@ DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */ thr->state = (duk_uint8_t) entry_thread_state; + /* Disabled assert: triggered with some torture tests. */ +#if 0 DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */ (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */ (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */ +#endif thr->heap->call_recursion_depth = entry_call_recursion_depth; @@ -59714,7 +61574,7 @@ * on every return should have no ill effect. */ #if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + if (duk_debug_is_attached(thr->heap)) { DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt")); DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init); thr->interrupt_init -= thr->interrupt_counter; @@ -59726,6 +61586,21 @@ #if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG) duk__interrupt_fixup(thr, entry_curr_thread); #endif + + /* Error handling complete, remove side effect protections and + * process pending finalizers. + */ +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(thr->heap->error_not_allowed == 1); + thr->heap->error_not_allowed = 0; +#endif + DUK_ASSERT(thr->heap->pf_prevent_count > 0); + thr->heap->pf_prevent_count--; + DUK_DD(DUK_DDPRINT("call error handled, pf_prevent_count updated to %ld", (long) thr->heap->pf_prevent_count)); + + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + + DUK_REFZERO_CHECK_SLOW(thr); } /* @@ -59823,12 +61698,6 @@ entry_callstack_top, entry_catchstack_top); - /* Longjmp state is kept clean in success path */ - DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN); - DUK_ASSERT(thr->heap->lj.iserror == 0); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1)); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); - /* Note: either pointer may be NULL (at entry), so don't assert */ thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr; @@ -59848,12 +61717,6 @@ entry_catchstack_top, old_jmpbuf_ptr); - /* Longjmp state is cleaned up by error handling */ - DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN); - DUK_ASSERT(thr->heap->lj.iserror == 0); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1)); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); - retval = DUK_EXEC_ERROR; } #if defined(DUK_USE_CPP_EXCEPTIONS) @@ -59898,6 +61761,8 @@ DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == old_jmpbuf_ptr); /* success/error path both do this */ + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + duk__handle_safe_call_shared(thr, idx_retbase, num_stack_rets, @@ -60012,6 +61877,10 @@ DUK_ASSERT(thr->callstack_top == entry_callstack_top); duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, rc); + + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + + DUK_REFZERO_CHECK_FAST(thr); return; thread_state_error: @@ -60046,6 +61915,7 @@ * the error here. */ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW); + DUK_ASSERT_LJSTATE_SET(thr->heap); DUK_ASSERT(thr->callstack_top >= entry_callstack_top); DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); @@ -60054,9 +61924,9 @@ DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); DUK_ASSERT(thr->callstack_top >= entry_callstack_top); - duk_hthread_catchstack_unwind(thr, entry_catchstack_top); + duk_hthread_catchstack_unwind_norz(thr, entry_catchstack_top); duk_hthread_catchstack_shrink_check(thr); - duk_hthread_callstack_unwind(thr, entry_callstack_top); + duk_hthread_callstack_unwind_norz(thr, entry_callstack_top); duk_hthread_callstack_shrink_check(thr); thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index; @@ -60088,6 +61958,21 @@ thr->heap->lj.iserror = 0; DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */ + + /* Error handling complete, remove side effect protections and + * process pending finalizers. + */ +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(thr->heap->error_not_allowed == 1); + thr->heap->error_not_allowed = 0; +#endif + DUK_ASSERT(thr->heap->pf_prevent_count > 0); + thr->heap->pf_prevent_count--; + DUK_DD(DUK_DDPRINT("safe call error handled, pf_prevent_count updated to %ld", (long) thr->heap->pf_prevent_count)); + + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + + DUK_REFZERO_CHECK_SLOW(thr); } DUK_LOCAL void duk__handle_safe_call_shared(duk_hthread *thr, @@ -60134,6 +62019,8 @@ #if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG) duk__interrupt_fixup(thr, entry_curr_thread); #endif + + DUK_ASSERT_LJSTATE_UNSET(thr->heap); } /* @@ -60321,7 +62208,8 @@ DUK_ASSERT(thr->callstack_top >= 1); DUK_ASSERT((call_flags & DUK_CALL_FLAG_IS_RESUME) == 0); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) { /* See: test-bug-tailcall-preventyield-assert.c. */ DUK_DDD(DUK_DDDPRINT("tail call prevented by current activation having DUK_ACT_FLAG_PREVENTYIELD")); @@ -60368,16 +62256,17 @@ break; } } - duk_hthread_catchstack_unwind(thr, i_stk + 1); + duk_hthread_catchstack_unwind_norz(thr, i_stk + 1); /* Unwind the topmost callstack entry before reusing it */ DUK_ASSERT(thr->callstack_top > 0); - duk_hthread_callstack_unwind(thr, thr->callstack_top - 1); + duk_hthread_callstack_unwind_norz(thr, thr->callstack_top - 1); /* Then reuse the unwound activation; callstack was not shrunk so there is always space */ + DUK_ASSERT(thr->callstack_top < thr->callstack_size); + act = thr->callstack + thr->callstack_top; thr->callstack_top++; - DUK_ASSERT(thr->callstack_top <= thr->callstack_size); - act = thr->callstack + thr->callstack_top - 1; + thr->callstack_curr = act; /* Start filling in the activation */ act->func = func; /* don't want an intermediate exposed state with func == NULL */ @@ -60394,7 +62283,7 @@ DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */ #if defined(DUK_USE_REFERENCE_COUNTING) DUK_HOBJECT_INCREF(thr, func); - act = thr->callstack + thr->callstack_top - 1; /* side effects (currently none though) */ + act = thr->callstack_curr; /* side effects (currently none though) */ #endif #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) @@ -60406,7 +62295,7 @@ * is in use. */ duk__update_func_caller_prop(thr, func); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; #endif act->flags = (DUK_HOBJECT_HAS_STRICT(func) ? @@ -60463,7 +62352,7 @@ DUK_DDD(DUK_DDDPRINT("update to current activation idx_retval")); DUK_ASSERT(thr->callstack_top < thr->callstack_size); DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL); DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act))); act->idx_retval = entry_valstack_bottom_index + idx_func; @@ -60472,6 +62361,7 @@ DUK_ASSERT(thr->callstack_top < thr->callstack_size); act = thr->callstack + thr->callstack_top; thr->callstack_top++; + thr->callstack_curr = act; DUK_ASSERT(thr->callstack_top <= thr->callstack_size); DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); @@ -60504,7 +62394,7 @@ #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) duk__update_func_caller_prop(thr, func); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; #endif } @@ -60533,6 +62423,7 @@ */ duk__handle_oldenv_for_call(thr, func, act); + /* No need to re-lookup 'act' at present: no side effects. */ DUK_ASSERT(act->lex_env != NULL); DUK_ASSERT(act->var_env != NULL); @@ -60562,7 +62453,7 @@ /* [ ... arg1 ... argN envobj ] */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; act->lex_env = env; act->var_env = env; DUK_HOBJECT_INCREF(thr, act->lex_env); @@ -60598,6 +62489,7 @@ * the topmost activation. */ + DUK_REFZERO_CHECK_FAST(thr); return 1; } #line 1 "duk_js_compiler.c" @@ -62601,6 +64493,8 @@ duk_pop(ctx); return ret; #else + DUK_UNREF(comp_ctx); + DUK_UNREF(rc); DUK_ASSERT((rc & DUK__CONST_MARKER) == 0); /* caller removes const marker */ return 0; #endif @@ -62852,15 +64746,31 @@ DUK_DDD(DUK_DDDPRINT("arith inline check: d1=%lf, d2=%lf, op=%ld", (double) d1, (double) d2, (long) x->op)); switch (x->op) { - case DUK_OP_ADD: d3 = d1 + d2; break; - case DUK_OP_SUB: d3 = d1 - d2; break; - case DUK_OP_MUL: d3 = d1 * d2; break; - case DUK_OP_DIV: d3 = d1 / d2; break; + case DUK_OP_ADD: { + d3 = d1 + d2; + break; + } + case DUK_OP_SUB: { + d3 = d1 - d2; + break; + } + case DUK_OP_MUL: { + d3 = d1 * d2; + break; + } + case DUK_OP_DIV: { + d3 = d1 / d2; + break; + } case DUK_OP_EXP: { d3 = (duk_double_t) duk_js_arith_pow((double) d1, (double) d2); break; } - default: accept_fold = 0; break; + default: { + d3 = 0.0; /* Won't be used, but silence MSVC /W4 warning. */ + accept_fold = 0; + break; + } } if (accept_fold) { @@ -66774,6 +68684,7 @@ duk_small_uint_t stmt_flags = 0; duk_int_t label_id = -1; duk_small_uint_t tok; + duk_bool_t test_func_decl; DUK__RECURSION_INCREASE(comp_ctx, thr); @@ -66839,17 +68750,15 @@ * for function statements are modelled after V8, see * test-dev-func-decl-outside-top.js. */ - + test_func_decl = allow_source_elem; #if defined(DUK_USE_NONSTD_FUNC_STMT) /* Lenient: allow function declarations outside top level in * non-strict mode but reject them in strict mode. */ - if (allow_source_elem || !comp_ctx->curr_func.is_strict) -#else /* DUK_USE_NONSTD_FUNC_STMT */ - /* Strict: never allow function declarations outside top level. */ - if (allow_source_elem) + test_func_decl = test_func_decl || !comp_ctx->curr_func.is_strict; #endif /* DUK_USE_NONSTD_FUNC_STMT */ - { + /* Strict: never allow function declarations outside top level. */ + if (test_func_decl) { /* FunctionDeclaration: not strictly a statement but handled as such. * * O(depth^2) parse count for inner functions is handled by recording a @@ -67561,6 +69470,9 @@ (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1))); +#if defined(DUK_USE_FASTINT) + DUK_ASSERT(DUK_TVAL_IS_NULL(duk_get_tval(ctx, -1)) || DUK_TVAL_IS_FASTINT(duk_get_tval(ctx, -1))); +#endif duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */ } @@ -67626,8 +69538,7 @@ duk_push_null(ctx); declvar_flags = DUK_PROPDESC_FLAG_WRITABLE | - DUK_PROPDESC_FLAG_ENUMERABLE | - DUK_BC_DECLVAR_FLAG_UNDEF_VALUE; + DUK_PROPDESC_FLAG_ENUMERABLE; if (configurable_bindings) { declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE; } @@ -68304,9 +70215,9 @@ DUK_ASSERT(lex_pt != NULL); flags = comp_stk->flags; - is_eval = (flags & DUK_JS_COMPILE_FLAG_EVAL ? 1 : 0); - is_strict = (flags & DUK_JS_COMPILE_FLAG_STRICT ? 1 : 0); - is_funcexpr = (flags & DUK_JS_COMPILE_FLAG_FUNCEXPR ? 1 : 0); + is_eval = (flags & DUK_COMPILE_EVAL ? 1 : 0); + is_strict = (flags & DUK_COMPILE_STRICT ? 1 : 0); + is_funcexpr = (flags & DUK_COMPILE_FUNCEXPR ? 1 : 0); h_filename = duk_get_hstring(ctx, -1); /* may be undefined */ @@ -68382,7 +70293,7 @@ */ DUK_ASSERT(func->is_setget == 0); - func->is_strict = is_strict; + func->is_strict = (duk_uint8_t) is_strict; DUK_ASSERT(func->is_notail == 0); if (is_funcexpr) { @@ -68397,8 +70308,9 @@ (void) duk__parse_func_like_raw(comp_ctx, 0 /*flags*/); } else { DUK_ASSERT(func->is_function == 0); - func->is_eval = is_eval; - func->is_global = !is_eval; + DUK_ASSERT(is_eval == 0 || is_eval == 1); + func->is_eval = (duk_uint8_t) is_eval; + func->is_global = (duk_uint8_t) !is_eval; DUK_ASSERT(func->is_namebinding == 0); DUK_ASSERT(func->is_constructable == 0); @@ -68438,6 +70350,7 @@ DUK_LEXER_INITCTX(&comp_stk.comp_ctx_alloc.lex); comp_stk.comp_ctx_alloc.lex.input = src_buffer; comp_stk.comp_ctx_alloc.lex.input_length = src_length; + comp_stk.comp_ctx_alloc.lex.flags = flags; /* Forward flags directly for now. */ /* [ ... filename ] */ @@ -68816,7 +70729,7 @@ break; } default: { - DUK_UNREACHABLE(); + /* Possible with DUK_OP_EXP. */ goto skip_fastint; } } @@ -69073,8 +70986,7 @@ if (DUK_TVAL_IS_NUMBER(tv)) { d1 = DUK_TVAL_GET_NUMBER(tv); } else { - d1 = duk_to_number(ctx, idx_src); /* side effects, perform in-place */ - DUK_ASSERT(DUK_TVAL_IS_NUMBER(DUK_GET_TVAL_POSIDX(ctx, idx_src))); + d1 = duk_to_number_tval(ctx, tv); /* side effects */ } if (opcode == DUK_OP_UNP) { @@ -69126,7 +71038,9 @@ else #endif /* DUK_USE_FASTINT */ { - i1 = duk_to_int32(ctx, idx_src); /* side effects */ + duk_push_tval(ctx, tv); + i1 = duk_to_int32(ctx, -1); /* side effects */ + duk_pop_unsafe(ctx); } /* Result is always fastint compatible. */ @@ -69269,7 +71183,7 @@ DUK_ASSERT(DUK_TVAL_IS_STRING(tv_id)); name = DUK_TVAL_GET_STRING(tv_id); DUK_ASSERT(name != NULL); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [ ... val this ] */ /* XXX: Fastint fast path would be useful here. Also fastints @@ -69288,11 +71202,13 @@ if (op & 0x02) { duk_push_number(ctx, y); /* -> [ ... x this y ] */ + act = thr->callstack_curr; duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(ctx, -1), is_strict); duk_pop_2(ctx); /* -> [ ... x ] */ } else { duk_pop_2(ctx); /* -> [ ... ] */ duk_push_number(ctx, y); /* -> [ ... y ] */ + act = thr->callstack_curr; duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(ctx, -1), is_strict); } @@ -69422,17 +71338,19 @@ duk__set_catcher_regs(thr, cat_idx, tv_val_unstable, lj_type); - duk_hthread_catchstack_unwind(thr, cat_idx + 1); - duk_hthread_callstack_unwind(thr, thr->catchstack[cat_idx].callstack_index + 1); + duk_hthread_catchstack_unwind_norz(thr, cat_idx + 1); + duk_hthread_callstack_unwind_norz(thr, thr->catchstack[cat_idx].callstack_index + 1); DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))); + DUK_ASSERT(thr->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); duk__reconfig_valstack_ecma_catcher(thr, thr->callstack_top - 1, cat_idx); DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); act->curr_pc = thr->catchstack[cat_idx].pc_base + 0; /* +0 = catch */ act = NULL; @@ -69447,8 +71365,7 @@ */ if (DUK_CAT_HAS_CATCH_BINDING_ENABLED(&thr->catchstack[cat_idx])) { - duk_hobject *new_env; - duk_hobject *act_lex_env; + duk_hdecenv *new_env; DUK_DDD(DUK_DDDPRINT("catcher has an automatic catch binding")); @@ -69456,7 +71373,8 @@ * points, so we re-lookup it multiple times. */ DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); if (act->lex_env == NULL) { DUK_ASSERT(act->var_env == NULL); @@ -69464,22 +71382,26 @@ /* this may have side effects, so re-lookup act */ duk_js_init_activation_environment_records_delayed(thr, act); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); } DUK_ASSERT(act->lex_env != NULL); DUK_ASSERT(act->var_env != NULL); DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL); DUK_UNREF(act); /* unreferenced without assertions */ - act = thr->callstack + thr->callstack_top - 1; - act_lex_env = act->lex_env; - act = NULL; /* invalidated */ - - new_env = duk_push_object_helper_proto(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), - act_lex_env); + /* XXX: If an out-of-memory happens here, longjmp state asserts + * will be triggered at present and a try-catch fails to catch. + * That's not sandboxing fatal (C API protected calls are what + * matters), and script catch code can immediately throw anyway + * for almost any operation. + */ + 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(ctx, (duk_hobject *) new_env); + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL); DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", (duk_heaphdr *) new_env)); /* Note: currently the catch binding is handled without a register @@ -69488,14 +71410,20 @@ * record regbases etc. */ + /* XXX: duk_xdef_prop() may cause an out-of-memory, see above. */ DUK_ASSERT(thr->catchstack[cat_idx].h_varname != NULL); duk_push_hstring(ctx, thr->catchstack[cat_idx].h_varname); duk_push_tval(ctx, thr->valstack + thr->catchstack[cat_idx].idx_base); duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_W); /* writable, not configurable */ - act = thr->callstack + thr->callstack_top - 1; - act->lex_env = new_env; - DUK_HOBJECT_INCREF(thr, new_env); /* reachable through activation */ + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); + DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, act->lex_env); + act->lex_env = (duk_hobject *) new_env; + DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env); /* reachable through activation */ + /* Net refcount change to act->lex_env is 0: incref for new_env's + * prototype, decref for act->lex_env overwrite. + */ DUK_CAT_SET_LEXENV_ACTIVE(&thr->catchstack[cat_idx]); @@ -69515,17 +71443,19 @@ duk__set_catcher_regs(thr, cat_idx, tv_val_unstable, lj_type); - duk_hthread_catchstack_unwind(thr, cat_idx + 1); /* cat_idx catcher is kept, even for finally */ - duk_hthread_callstack_unwind(thr, thr->catchstack[cat_idx].callstack_index + 1); + duk_hthread_catchstack_unwind_norz(thr, cat_idx + 1); /* cat_idx catcher is kept, even for finally */ + duk_hthread_callstack_unwind_norz(thr, thr->catchstack[cat_idx].callstack_index + 1); DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))); + DUK_ASSERT(thr->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); duk__reconfig_valstack_ecma_catcher(thr, thr->callstack_top - 1, cat_idx); DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); act->curr_pc = thr->catchstack[cat_idx].pc_base + 1; /* +1 = finally */ act = NULL; @@ -69538,7 +71468,8 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL); DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(DUK_ACT_GET_FUNC(act))); @@ -69547,13 +71478,14 @@ act->curr_pc = thr->catchstack[cat_idx].pc_base + (lj_type == DUK_LJ_TYPE_CONTINUE ? 1 : 0); act = NULL; /* invalidated */ - duk_hthread_catchstack_unwind(thr, cat_idx + 1); /* keep label catcher */ + duk_hthread_catchstack_unwind_norz(thr, cat_idx + 1); /* keep label catcher */ /* no need to unwind callstack */ /* valstack should not need changes */ #if defined(DUK_USE_ASSERTIONS) DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) == (duk_size_t) ((duk_hcompfunc *) DUK_ACT_GET_FUNC(act))->nregs); #endif @@ -69575,7 +71507,7 @@ tv1 = resumer->valstack + resumer->callstack[act_idx].idx_retval; /* return value from Duktape.Thread.resume() */ DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable); /* side effects */ - duk_hthread_callstack_unwind(resumer, act_idx + 1); /* unwind to 'resume' caller */ + duk_hthread_callstack_unwind_norz(resumer, act_idx + 1); /* unwind to 'resume' caller */ /* no need to unwind catchstack */ duk__reconfig_valstack_ecma_return(resumer, act_idx); @@ -69638,10 +71570,11 @@ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged by Duktape.Thread.resume() */ DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))->func == duk_bi_thread_resume); - DUK_ASSERT_DISABLE((thr->callstack + thr->callstack_top - 2)->idx_retval >= 0); /* unsigned */ + DUK_ASSERT(thr->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack_curr))->func == duk_bi_thread_resume); + DUK_ASSERT_DISABLE((thr->callstack_curr - 1)->idx_retval >= 0); /* unsigned */ tv = &thr->heap->lj.value2; /* resumee */ DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); @@ -69656,11 +71589,11 @@ DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED || resumee->callstack_top >= 2); /* YIELDED: Ecmascript activation + Duktape.Thread.yield() activation */ DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED || - (DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1))->func == duk_bi_thread_yield)); + (DUK_ACT_GET_FUNC(resumee->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumee->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumee->callstack_curr))->func == duk_bi_thread_yield)); DUK_ASSERT_DISABLE(resumee->state != DUK_HTHREAD_STATE_YIELDED || - (resumee->callstack + resumee->callstack_top - 2)->idx_retval >= 0); /* idx_retval unsigned */ + (resumee->callstack_curr - 1)->idx_retval >= 0); /* idx_retval unsigned */ DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_INACTIVE || resumee->callstack_top == 0); /* INACTIVE: no activation, single function value on valstack */ @@ -69675,7 +71608,9 @@ * which we simply ignore. */ + DUK_ASSERT(resumee->resumer == NULL); resumee->resumer = thr; + DUK_HTHREAD_INCREF(thr, thr); resumee->state = DUK_HTHREAD_STATE_RUNNING; thr->state = DUK_HTHREAD_STATE_RESUMED; DUK_HEAP_SWITCH_THREAD(thr->heap, resumee); @@ -69699,13 +71634,15 @@ tv2 = &thr->heap->lj.value1; DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv2); /* side effects */ - duk_hthread_callstack_unwind(resumee, act_idx + 1); /* unwind to 'yield' caller */ + duk_hthread_callstack_unwind_norz(resumee, act_idx + 1); /* unwind to 'yield' caller */ /* no need to unwind catchstack */ duk__reconfig_valstack_ecma_return(resumee, act_idx); + DUK_ASSERT(resumee->resumer == NULL); resumee->resumer = thr; + DUK_HTHREAD_INCREF(thr, thr); resumee->state = DUK_HTHREAD_STATE_RUNNING; thr->state = DUK_HTHREAD_STATE_RESUMED; DUK_HEAP_SWITCH_THREAD(thr->heap, resumee); @@ -69741,7 +71678,9 @@ DUK_ERROR_INTERNAL(thr); } + DUK_ASSERT(resumee->resumer == NULL); resumee->resumer = thr; + DUK_HTHREAD_INCREF(thr, thr); resumee->state = DUK_HTHREAD_STATE_RUNNING; thr->state = DUK_HTHREAD_STATE_RESUMED; DUK_HEAP_SWITCH_THREAD(thr->heap, resumee); @@ -69774,28 +71713,31 @@ DUK_ASSERT(thr != entry_thread); /* Duktape.Thread.yield() should prevent */ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged from Duktape.Thread.yield() */ DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.yield() activation */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))->func == duk_bi_thread_yield); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2))); /* an Ecmascript function */ - DUK_ASSERT_DISABLE((thr->callstack + thr->callstack_top - 2)->idx_retval >= 0); /* unsigned */ + DUK_ASSERT(thr->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack_curr))->func == duk_bi_thread_yield); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr - 1) != NULL && + DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr - 1))); /* an Ecmascript function */ + DUK_ASSERT_DISABLE((thr->callstack_curr - 1)->idx_retval >= 0); /* unsigned */ resumer = thr->resumer; DUK_ASSERT(resumer != NULL); DUK_ASSERT(resumer->state == DUK_HTHREAD_STATE_RESUMED); /* written by a previous RESUME handling */ DUK_ASSERT(resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ - DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1))->func == duk_bi_thread_resume); - DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 2) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 2))); /* an Ecmascript function */ - DUK_ASSERT_DISABLE((resumer->callstack + resumer->callstack_top - 2)->idx_retval >= 0); /* unsigned */ + DUK_ASSERT(resumer->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumer->callstack_curr))->func == duk_bi_thread_resume); + DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr - 1) != NULL && + DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr - 1))); /* an Ecmascript function */ + DUK_ASSERT_DISABLE((resumer->callstack_curr - 1)->idx_retval >= 0); /* unsigned */ if (thr->heap->lj.iserror) { thr->state = DUK_HTHREAD_STATE_YIELDED; thr->resumer = NULL; + DUK_HTHREAD_DECREF_NORZ(thr, resumer); resumer->state = DUK_HTHREAD_STATE_RUNNING; DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); thr = resumer; @@ -69811,6 +71753,7 @@ thr->state = DUK_HTHREAD_STATE_YIELDED; thr->resumer = NULL; + DUK_HTHREAD_DECREF_NORZ(thr, resumer); resumer->state = DUK_HTHREAD_STATE_RUNNING; DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); #if 0 @@ -69891,9 +71834,9 @@ * final catcher unwind everything */ #if 0 - duk_hthread_catchstack_unwind(thr, (cat - thr->catchstack) + 1); /* leave 'cat' as top catcher (also works if catchstack exhausted) */ - duk_hthread_callstack_unwind(thr, entry_callstack_index + 1); - + duk_hthread_catchstack_unwind_norz(thr, (cat - thr->catchstack) + 1); /* leave 'cat' as top catcher (also works if catchstack exhausted) */ + duk_hthread_callstack_unwind_norz(thr, entry_callstack_index + 1); + DUK_REFZERO_CHECK_SLOW(thr); #endif DUK_D(DUK_DPRINT("-> throw propagated up to entry level, rethrow and exit bytecode executor")); retval = DUK__LONGJMP_RETHROW; @@ -69910,11 +71853,12 @@ DUK_ASSERT(thr->resumer != NULL); DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2))); /* an Ecmascript function */ + DUK_ASSERT(thr->resumer->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack_curr))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */ + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr - 1) != NULL && + DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr - 1))); /* an Ecmascript function */ resumer = thr->resumer; @@ -69927,6 +71871,7 @@ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED); thr->resumer = NULL; + DUK_HTHREAD_DECREF_NORZ(thr, resumer); resumer->state = DUK_HTHREAD_STATE_RUNNING; DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); thr = resumer; @@ -69955,6 +71900,8 @@ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */ + DUK_GC_TORTURE(thr->heap); + just_return: return retval; @@ -70095,6 +72042,7 @@ cat = thr->catchstack + thr->catchstack_top - 1; /* may be < thr->catchstack initially */ DUK_ASSERT(thr->callstack_top > 0); /* ensures callstack_top - 1 >= 0 */ + DUK_ASSERT(thr->callstack_curr != NULL); orig_callstack_index = thr->callstack_top - 1; while (cat >= thr->catchstack) { @@ -70142,22 +72090,22 @@ */ DUK_DDD(DUK_DDDPRINT("return to Ecmascript caller, idx_retval=%ld, lj_value1=%!T", - (long) (thr->callstack + thr->callstack_top - 2)->idx_retval, + (long) (thr->callstack_curr - 1)->idx_retval, (duk_tval *) &thr->heap->lj.value1)); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2))); /* must be ecmascript */ + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr - 1))); /* must be ecmascript */ - tv1 = thr->valstack + (thr->callstack + thr->callstack_top - 2)->idx_retval; + tv1 = thr->valstack + (thr->callstack_curr - 1)->idx_retval; DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom); tv2 = thr->valstack_top - 1; DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */ DUK_DDD(DUK_DDDPRINT("return value at idx_retval=%ld is %!T", - (long) (thr->callstack + thr->callstack_top - 2)->idx_retval, - (duk_tval *) (thr->valstack + (thr->callstack + thr->callstack_top - 2)->idx_retval))); + (long) (thr->callstack_curr - 1)->idx_retval, + (duk_tval *) (thr->valstack + (thr->callstack_curr - 1)->idx_retval))); - duk_hthread_catchstack_unwind(thr, new_cat_top); /* leave 'cat' as top catcher (also works if catchstack exhausted) */ - duk_hthread_callstack_unwind(thr, thr->callstack_top - 1); + duk_hthread_catchstack_unwind_norz(thr, new_cat_top); /* leave 'cat' as top catcher (also works if catchstack exhausted) */ + duk_hthread_callstack_unwind_norz(thr, thr->callstack_top - 1); duk__reconfig_valstack_ecma_return(thr, thr->callstack_top - 1); DUK_DD(DUK_DDPRINT("-> return not intercepted, restart execution in caller")); @@ -70169,12 +72117,13 @@ DUK_ASSERT(thr->resumer != NULL); DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2))); /* an Ecmascript function */ - DUK_ASSERT_DISABLE((thr->resumer->callstack + thr->resumer->callstack_top - 2)->idx_retval >= 0); /* unsigned */ + DUK_ASSERT(thr->resumer->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack_curr))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */ + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr - 1) != NULL && + DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr - 1))); /* an Ecmascript function */ + DUK_ASSERT_DISABLE((thr->resumer->callstack_curr - 1)->idx_retval >= 0); /* unsigned */ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED); @@ -70188,6 +72137,7 @@ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED); thr->resumer = NULL; + DUK_HTHREAD_DECREF(thr, resumer); resumer->state = DUK_HTHREAD_STATE_RUNNING; DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); #if 0 @@ -70246,7 +72196,8 @@ DUK_ASSERT(thr->heap->dbg_processing == 0); /* don't re-enter e.g. during Eval */ ctx = (duk_context *) thr; - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); /* It might seem that replacing 'thr->heap' with just 'heap' below * might be a good idea, but it increases code size slightly @@ -70271,8 +72222,7 @@ (line != thr->heap->dbg_step_startline)) { DUK_D(DUK_DPRINT("STEP STATE TRIGGERED PAUSE at line %ld", (long) line)); - - DUK_HEAP_SET_PAUSED(thr->heap); + duk_debug_set_paused(thr->heap); } /* Check for breakpoints only on line transition. @@ -70298,8 +72248,7 @@ if (act->prev_line != bp->line && line == bp->line) { DUK_D(DUK_DPRINT("BREAKPOINT TRIGGERED at %!O:%ld", (duk_heaphdr *) bp->filename, (long) bp->line)); - - DUK_HEAP_SET_PAUSED(thr->heap); + duk_debug_set_paused(thr->heap); } } } else { @@ -70386,8 +72335,9 @@ * above, so we must recheck attach status. */ - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { - act = thr->callstack + thr->callstack_top - 1; /* relookup, may have changed */ + if (duk_debug_is_attached(thr->heap)) { + act = thr->callstack_curr; /* relookup, may have changed */ + DUK_ASSERT(act != NULL); if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE || ((thr->heap->dbg_step_type == DUK_STEP_TYPE_INTO || thr->heap->dbg_step_type == DUK_STEP_TYPE_OVER) && @@ -70410,7 +72360,7 @@ } #endif /* DUK_USE_DEBUGGER_SUPPORT */ -DUK_LOCAL duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) { +DUK_LOCAL DUK_NOINLINE DUK_COLD duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) { duk_int_t ctr; duk_activation *act; duk_hcompfunc *fun; @@ -70460,7 +72410,8 @@ } DUK_HEAP_SET_INTERRUPT_RUNNING(thr->heap); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC((duk_hobject *) fun)); @@ -70496,7 +72447,7 @@ * detaching (to finish off the pending detach). */ duk__interrupt_handle_debugger(thr, &immediate, &retval); - act = thr->callstack + thr->callstack_top - 1; /* relookup if changed */ + act = thr->callstack_curr; /* relookup if changed */ DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */ } #endif /* DUK_USE_DEBUGGER_SUPPORT */ @@ -70638,7 +72589,7 @@ (thr->heap->dbg_step_thread != thr || thr->heap->dbg_step_csindex != thr->callstack_top - 1)) { DUK_D(DUK_DPRINT("STEP INTO ACTIVE, FORCE PAUSED")); - DUK_HEAP_SET_PAUSED(thr->heap); + duk_debug_set_paused(thr->heap); } /* Force interrupt right away if we're paused or in "checked mode". @@ -70693,7 +72644,7 @@ #if defined(DUK_USE_EXEC_FUN_LOCAL) #define DUK__FUN() fun #else -#define DUK__FUN() ((duk_hcompfunc *) DUK_ACT_GET_FUNC((thr)->callstack + (thr)->callstack_top - 1)) +#define DUK__FUN() ((duk_hcompfunc *) DUK_ACT_GET_FUNC((thr)->callstack_curr)) #endif #define DUK__STRICT() (DUK_HOBJECT_HAS_STRICT((duk_hobject *) DUK__FUN())) @@ -70770,12 +72721,12 @@ #define DUK__SYNC_CURR_PC() do { \ duk_activation *act; \ - act = thr->callstack + thr->callstack_top - 1; \ + act = thr->callstack_curr; \ act->curr_pc = curr_pc; \ } while (0) #define DUK__SYNC_AND_NULL_CURR_PC() do { \ duk_activation *act; \ - act = thr->callstack + thr->callstack_top - 1; \ + act = thr->callstack_curr; \ act->curr_pc = curr_pc; \ thr->ptr_curr_pc = NULL; \ } while (0) @@ -70827,15 +72778,27 @@ lj_ret = duk__handle_longjmp(heap->curr_thread, entry_thread, entry_callstack_top); + /* Error handling complete, remove side effect protections. + */ +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(heap->error_not_allowed == 1); + heap->error_not_allowed = 0; +#endif + DUK_ASSERT(heap->pf_prevent_count > 0); + heap->pf_prevent_count--; + DUK_DD(DUK_DDPRINT("executor error handled, pf_prevent_count updated to %ld", (long) heap->pf_prevent_count)); + if (lj_ret == DUK__LONGJMP_RESTART) { /* Restart bytecode execution, possibly with a changed thread. */ - ; + DUK_REFZERO_CHECK_SLOW(heap->curr_thread); } else { - /* Rethrow error to calling state. */ - DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW); + /* If an error is propagated, don't run refzero checks here. + * The next catcher will deal with that. Pf_prevent_count + * will be re-bumped by the longjmp. + */ - /* Longjmp handling has restored jmpbuf_ptr. */ - DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr); + DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW); /* Rethrow error to calling state. */ + DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr); /* Longjmp handling has restored jmpbuf_ptr. */ /* Thread may have changed, e.g. YIELD converted to THROW. */ duk_err_longjmp(heap->curr_thread); @@ -70858,8 +72821,10 @@ DUK_ASSERT(exec_thr->heap->curr_thread != NULL); DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR((duk_heaphdr *) exec_thr); DUK_ASSERT(exec_thr->callstack_top >= 1); /* at least one activation, ours */ - DUK_ASSERT(DUK_ACT_GET_FUNC(exec_thr->callstack + exec_thr->callstack_top - 1) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(exec_thr->callstack + exec_thr->callstack_top - 1))); + DUK_ASSERT(DUK_ACT_GET_FUNC(exec_thr->callstack_curr) != NULL); + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(exec_thr->callstack_curr))); + + DUK_GC_TORTURE(exec_thr->heap); entry_thread = exec_thr; heap = entry_thread->heap; @@ -70950,7 +72915,7 @@ } /* Inner executor, performance critical. */ -DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_size_t entry_callstack_top) { +DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_size_t entry_callstack_top) { /* Current PC, accessed by other functions through thr->ptr_to_curr_pc. * Critical for performance. It would be safest to make this volatile, * but that eliminates performance benefits; aliasing guarantees @@ -70991,6 +72956,8 @@ #endif #endif + DUK_GC_TORTURE(entry_thread->heap); + /* * Restart execution by reloading thread state. * @@ -71040,8 +73007,11 @@ thr = entry_thread->heap->curr_thread; DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))); + DUK_ASSERT(thr->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); + + DUK_GC_TORTURE(thr->heap); thr->ptr_curr_pc = &curr_pc; @@ -71055,7 +73025,8 @@ /* Assume interrupt init/counter are properly initialized here. */ /* Assume that thr->valstack_bottom has been set-up before getting here. */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); DUK_ASSERT(fun != NULL); DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == fun->nregs); @@ -71063,9 +73034,10 @@ DUK_ASSERT(consts != NULL); #if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap) && !thr->heap->dbg_processing) { + if (duk_debug_is_attached(thr->heap) && !thr->heap->dbg_processing) { duk__executor_recheck_debugger(thr, act, fun); - act = thr->callstack + thr->callstack_top - 1; /* relookup after side effects (no side effects currently however) */ + act = thr->callstack_curr; /* relookup after side effects (no side effects currently however) */ + DUK_ASSERT(act != NULL); } #endif /* DUK_USE_DEBUGGER_SUPPORT */ @@ -71115,10 +73087,11 @@ duk_small_uint_t exec_int_ret; /* Write curr_pc back for the debugger. */ - DUK_ASSERT(thr->callstack_top > 0); { duk_activation *act; - act = thr->callstack + thr->callstack_top - 1; + DUK_ASSERT(thr->callstack_top > 0); + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); act->curr_pc = (duk_instr_t *) curr_pc; } @@ -71152,7 +73125,7 @@ #if defined(DUK_USE_ASSERTIONS) || defined(DUK_USE_DEBUG) { duk_activation *act; - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; DUK_ASSERT(curr_pc >= DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, DUK__FUN())); DUK_ASSERT(curr_pc < DUK_HCOMPFUNC_GET_CODE_END(thr->heap, DUK__FUN())); DUK_UNREF(act); /* if debugging disabled */ @@ -71444,7 +73417,7 @@ DUK_ASSERT(DUK_TVAL_IS_STRING(tv)); name = DUK_TVAL_GET_STRING(tv); tv = NULL; /* lookup has side effects */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; if (duk_js_getvar_activation(thr, act, name, 0 /*throw*/)) { /* -> [... val this] */ tv = DUK_GET_TVAL_NEGIDX(ctx, -2); @@ -72172,14 +74145,12 @@ duk_hstring *name; duk_small_uint_t prop_flags; duk_bool_t is_func_decl; - duk_bool_t is_undef_value; tv1 = DUK__REGCONSTP_B(ins); DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); name = DUK_TVAL_GET_STRING(tv1); DUK_ASSERT(name != NULL); - is_undef_value = ((a & DUK_BC_DECLVAR_FLAG_UNDEF_VALUE) != 0); is_func_decl = ((a & DUK_BC_DECLVAR_FLAG_FUNC_DECL) != 0); /* XXX: declvar takes an duk_tval pointer, which is awkward and @@ -72191,19 +74162,25 @@ */ prop_flags = a & DUK_PROPDESC_FLAGS_MASK; - if (is_undef_value) { + if (is_func_decl) { + duk_push_tval(ctx, DUK__REGCONSTP_C(ins)); + } else { DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */ thr->valstack_top++; - } else { - duk_push_tval(ctx, DUK__REGCONSTP_C(ins)); } tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; if (duk_js_declvar_activation(thr, act, name, tv1, prop_flags, is_func_decl)) { - /* already declared, must update binding value */ - tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1); - duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT()); + if (is_func_decl) { + /* Already declared, update value. */ + tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1); + duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT()); + } else { + /* Already declared but no initializer value + * (e.g. 'var xyz;'), no-op. + */ + } } duk_pop(ctx); @@ -72257,7 +74234,7 @@ DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); name = DUK_TVAL_GET_STRING(tv1); DUK_ASSERT(name != NULL); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */ idx = (duk_uint_fast_t) DUK_DEC_A(ins); @@ -72284,7 +74261,7 @@ DUK_ASSERT_DISABLE(bc >= 0); /* unsigned */ DUK_ASSERT((duk_uint_t) bc < (duk_uint_t) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, DUK__FUN())); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; fun_act = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); fun_temp = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, fun_act)[bc]; DUK_ASSERT(fun_temp != NULL); @@ -72296,6 +74273,7 @@ if (act->lex_env == NULL) { DUK_ASSERT(act->var_env == NULL); duk_js_init_activation_environment_records_delayed(thr, act); + act = thr->callstack_curr; } DUK_ASSERT(act->lex_env != NULL); DUK_ASSERT(act->var_env != NULL); @@ -72322,7 +74300,7 @@ DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); name = DUK_TVAL_GET_STRING(tv1); DUK_ASSERT(name != NULL); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */ duk_pop(ctx); /* 'this' binding is not needed here */ DUK__REPLACE_TOP_A_BREAK(); @@ -72343,7 +74321,7 @@ */ tv1 = DUK__REGP_A(ins); /* val */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT()); break; } @@ -72358,7 +74336,7 @@ DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); name = DUK_TVAL_GET_STRING(tv1); DUK_ASSERT(name != NULL); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; rc = duk_js_delvar_activation(thr, act, name); DUK__REPLACE_BOOL_A_BREAK(rc); } @@ -72419,6 +74397,7 @@ thr->valstack_top++; DUK__RETURN_SHARED(); } + /* This will be unused without refcounting. */ case DUK_OP_RETCONST: { duk_tval *tv; @@ -72435,7 +74414,10 @@ DUK__SYNC_AND_NULL_CURR_PC(); tv = DUK__CONSTP_BC(ins); DUK_TVAL_SET_TVAL(thr->valstack_top, tv); +#if defined(DUK_USE_REFERENCE_COUNTING) + /* Without refcounting only RETCONSTN is used. */ DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv)); /* no INCREF for this constant */ +#endif thr->valstack_top++; DUK__RETURN_SHARED(); } @@ -72559,57 +74541,44 @@ a = DUK_DEC_A(ins); bc = DUK_DEC_BC(ins); - act = thr->callstack + thr->callstack_top - 1; - DUK_ASSERT(thr->callstack_top >= 1); - - /* 'with' target must be created first, in case we run out of memory */ - /* XXX: refactor out? */ - - if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) { - DUK_DDD(DUK_DDDPRINT("need to initialize a with binding object")); - - if (act->lex_env == NULL) { - DUK_ASSERT(act->var_env == NULL); - DUK_DDD(DUK_DDDPRINT("delayed environment initialization")); - - /* must relookup act in case of side effects */ - duk_js_init_activation_environment_records_delayed(thr, act); - act = thr->callstack + thr->callstack_top - 1; - DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */ - } - DUK_ASSERT(act->lex_env != NULL); - DUK_ASSERT(act->var_env != NULL); - - (void) duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV), - -1); /* no prototype, updated below */ - - duk_push_tval(ctx, DUK__REGP(bc)); - duk_to_object(ctx, -1); - duk_dup_top(ctx); - - /* [ ... env target ] */ - /* [ ... env target target ] */ - - duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); /* always provideThis=true */ - - /* [ ... env ] */ + /* Registers 'bc' and 'bc + 1' are written in longjmp handling + * and if their previous values (which are temporaries) become + * unreachable -and- have a finalizer, there'll be a function + * call during error handling which is not supported now (GH-287). + * Ensure that both 'bc' and 'bc + 1' have primitive values to + * guarantee no finalizer calls in error handling. Scrubbing also + * ensures finalizers for the previous values run here rather than + * later. Error handling related values are also written to 'bc' + * and 'bc + 1' but those values never become unreachable during + * error handling, so there's no side effect problem even if the + * error value has a finalizer. + */ + duk_dup(ctx, bc); /* Stabilize value. */ + duk_to_undefined(ctx, bc); + duk_to_undefined(ctx, bc + 1); - DUK_DDD(DUK_DDDPRINT("environment for with binding: %!iT", - (duk_tval *) duk_get_tval(ctx, -1))); - } + /* Ensure a catchstack entry is available. One entry + * is guaranteed even if side effects cause function + * calls and the catchstack is shrunk because some + * spare room is left behind by a shrink operation. + */ + duk_hthread_catchstack_grow(thr); - /* allocate catcher and populate it (should be atomic) */ + /* Allocate catcher and populate it. Doesn't have to + * be fully atomic, but the catcher must be in a + * consistent state if side effects (such as finalizer + * calls) occur. + */ - duk_hthread_catchstack_grow(thr); - cat = thr->catchstack + thr->catchstack_top; DUK_ASSERT(thr->catchstack_top + 1 <= thr->catchstack_size); + cat = thr->catchstack + thr->catchstack_top; thr->catchstack_top++; cat->flags = DUK_CAT_TYPE_TCF; cat->h_varname = NULL; + cat->callstack_index = thr->callstack_top - 1; + cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */ + cat->idx_base = (duk_size_t) (thr->valstack_bottom - thr->valstack) + bc; if (a & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) { cat->flags |= DUK_CAT_FLAG_CATCH_ENABLED; @@ -72620,7 +74589,7 @@ if (a & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING) { DUK_DDD(DUK_DDDPRINT("catch binding flag set to catcher")); cat->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED; - tv1 = DUK__REGP(bc); + tv1 = DUK_GET_TVAL_NEGIDX(thr, -1); DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); /* borrowed reference; although 'tv1' comes from a register, @@ -72629,54 +74598,69 @@ */ cat->h_varname = DUK_TVAL_GET_STRING(tv1); } else if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) { - /* env created above to stack top */ - duk_hobject *new_env; + duk_hobjenv *env; + duk_hobject *target; - DUK_DDD(DUK_DDDPRINT("lexenv active flag set to catcher")); - cat->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE; + /* Delayed env initialization for activation (if needed). */ + DUK_ASSERT(thr->callstack_top >= 1); + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); + if (act->lex_env == NULL) { + DUK_DDD(DUK_DDDPRINT("delayed environment initialization")); + DUK_ASSERT(act->var_env == NULL); - DUK_DDD(DUK_DDDPRINT("activating object env: %!iT", - (duk_tval *) duk_get_tval(ctx, -1))); + duk_js_init_activation_environment_records_delayed(thr, act); + act = thr->callstack_curr; /* relookup, side effects */ + DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */ + } DUK_ASSERT(act->lex_env != NULL); - new_env = DUK_GET_HOBJECT_NEGIDX(ctx, -1); - DUK_ASSERT(new_env != NULL); + DUK_ASSERT(act->var_env != NULL); - act = thr->callstack + thr->callstack_top - 1; /* relookup (side effects) */ - DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, new_env, act->lex_env); /* side effects */ + /* Coerce 'with' target. */ + target = duk_to_hobject(ctx, -1); + DUK_ASSERT(target != NULL); + + /* Create an object environment; it is not pushed + * so avoid side effects very carefully until it is + * referenced. + */ + env = duk_hobjenv_alloc(thr, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV)); + DUK_ASSERT(env != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL); + env->target = target; /* always provideThis=true */ + DUK_HOBJECT_INCREF(thr, target); + env->has_this = 1; + DUK_ASSERT_HOBJENV_VALID(env); + DUK_DDD(DUK_DDDPRINT("environment for with binding: %!iO", env)); - act = thr->callstack + thr->callstack_top - 1; /* relookup (side effects) */ - act->lex_env = new_env; - DUK_HOBJECT_INCREF(thr, new_env); - duk_pop(ctx); + act = thr->callstack_curr; /* relookup (side effects) */ + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL); + DUK_ASSERT(act->lex_env != NULL); + DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) env, act->lex_env); + act->lex_env = (duk_hobject *) env; /* Now reachable. */ + DUK_HOBJECT_INCREF(thr, (duk_hobject *) env); + /* Net refcount change to act->lex_env is 0: incref for env's + * prototype, decref for act->lex_env overwrite. + */ + + /* Set catcher lex_env active (affects unwind) + * only when the whole setup is complete. + */ + cat = thr->catchstack + thr->catchstack_top - 1; + cat->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE; } else { ; } - /* Registers 'bc' and 'bc + 1' are written in longjmp handling - * and if their previous values (which are temporaries) become - * unreachable -and- have a finalizer, there'll be a function - * call during error handling which is not supported now (GH-287). - * Ensure that both 'bc' and 'bc + 1' have primitive values to - * guarantee no finalizer calls in error handling. Scrubbing also - * ensures finalizers for the previous values run here rather than - * later. Error handling related values are also written to 'bc' - * and 'bc + 1' but those values never become unreachable during - * error handling, so there's no side effect problem even if the - * error value has a finalizer. - */ - duk_to_undefined(ctx, bc); - duk_to_undefined(ctx, bc + 1); - - cat = thr->catchstack + thr->catchstack_top - 1; /* relookup (side effects) */ - cat->callstack_index = thr->callstack_top - 1; - cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */ - cat->idx_base = (duk_size_t) (thr->valstack_bottom - thr->valstack) + bc; - DUK_DDD(DUK_DDDPRINT("TRYCATCH catcher: flags=0x%08lx, callstack_index=%ld, pc_base=%ld, " "idx_base=%ld, h_varname=%!O", (unsigned long) cat->flags, (long) cat->callstack_index, (long) cat->pc_base, (long) cat->idx_base, (duk_heaphdr *) cat->h_varname)); + duk_pop(ctx); + curr_pc += 2; /* skip jump slots */ break; } @@ -72730,7 +74714,8 @@ cat = thr->catchstack + thr->catchstack_top - 1; DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat)); /* cleared before entering catch part */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) { duk_hobject *prev_env; @@ -72745,6 +74730,7 @@ DUK_ASSERT(prev_env != NULL); act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, prev_env); DUK_CAT_CLEAR_LEXENV_ACTIVE(cat); + DUK_HOBJECT_INCREF(thr, act->lex_env); DUK_HOBJECT_DECREF(thr, prev_env); /* side effects */ } @@ -72869,7 +74855,8 @@ duk_push_tval(ctx, thr->valstack + cat->idx_base); - duk_err_setup_heap_ljstate(thr, (duk_small_int_t) cont_type); + duk_err_setup_ljstate1(thr, (duk_small_int_t) cont_type, thr->valstack + cat->idx_base); + /* No debugger Throw notify check on purpose (rethrow). */ DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */ duk_err_longjmp(thr); @@ -72906,7 +74893,10 @@ (duk_tval *) duk_get_tval(ctx, -1))); #endif - duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW); + duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(ctx, -1)); +#if defined(DUK_USE_DEBUGGER_SUPPORT) + duk_err_check_debugger_integration(thr); +#endif DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */ duk_err_longjmp(thr); @@ -73443,7 +75433,7 @@ * from precompiled bytecode. */ #if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + if (duk_debug_is_attached(thr->heap)) { DUK_D(DUK_DPRINT("DEBUGGER statement encountered, halt execution")); DUK__SYNC_AND_NULL_CURR_PC(); duk_debug_halt_execution(thr, 1 /*use_prev_pc*/); @@ -73536,22 +75526,18 @@ case DUK_OP_UNUSED252: case DUK_OP_UNUSED253: case DUK_OP_UNUSED254: - case DUK_OP_UNUSED255: { - /* Force all case clauses to map to an actual handler - * so that the compiler can emit a jump without a bounds - * check: the switch argument is a duk_uint8_t so that - * the compiler may be able to figure it out. This is - * a small detail and obviously compiler dependent. - */ - volatile duk_small_int_t dummy_volatile; - dummy_volatile = 0; - DUK_UNREF(dummy_volatile); - DUK_D(DUK_DPRINT("invalid opcode: %ld - %!I", (long) op, ins)); - DUK__INTERNAL_ERROR("invalid opcode"); - break; - } + case DUK_OP_UNUSED255: + /* Force all case clauses to map to an actual handler + * so that the compiler can emit a jump without a bounds + * check: the switch argument is a duk_uint8_t so that + * the compiler may be able to figure it out. This is + * a small detail and obviously compiler dependent. + */ + /* default: clause omitted on purpose */ +#else + default: #endif /* DUK_USE_EXEC_PREFER_SIZE */ - default: { + { /* Default case catches invalid/unsupported opcodes. */ DUK_D(DUK_DPRINT("invalid opcode: %ld - %!I", (long) op, ins)); DUK__INTERNAL_ERROR("invalid opcode"); @@ -73868,7 +75854,7 @@ case DUK_TAG_STRING: { /* For Symbols ToNumber() is always a TypeError. */ duk_hstring *h = DUK_TVAL_GET_STRING(tv); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { DUK_ERROR_TYPE(thr, DUK_STR_CANNOT_NUMBER_COERCE_SYMBOL); } duk_push_hstring(ctx, h); @@ -74600,7 +76586,7 @@ DUK_ASSERT(h1 != NULL); DUK_ASSERT(h2 != NULL); - if (!DUK_HSTRING_HAS_SYMBOL(h1) && !DUK_HSTRING_HAS_SYMBOL(h2)) { + if (DUK_LIKELY(!DUK_HSTRING_HAS_SYMBOL(h1) && !DUK_HSTRING_HAS_SYMBOL(h2))) { rc = duk_js_string_compare(h1, h2); duk_pop_2(ctx); if (rc < 0) { @@ -74730,7 +76716,7 @@ /* func support for [[HasInstance]] checked in the beginning of the loop */ } while (--sanity > 0); - if (sanity == 0) { + if (DUK_UNLIKELY(sanity == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_BOUND_CHAIN_LIMIT); } @@ -74816,7 +76802,7 @@ val = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, val); } while (--sanity > 0); - if (sanity == 0) { + if (DUK_UNLIKELY(sanity == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); } DUK_UNREACHABLE(); @@ -74917,7 +76903,7 @@ /* All internal keys are identified as Symbols. */ str = DUK_TVAL_GET_STRING(tv_x); DUK_ASSERT(str != NULL); - if (DUK_HSTRING_HAS_SYMBOL(str)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(str))) { stridx = DUK_STRIDX_LC_SYMBOL; } else { stridx = DUK_STRIDX_LC_STRING; @@ -74967,67 +76953,112 @@ * * Array index: E5 Section 15.4 * Array length: E5 Section 15.4.5.1 steps 3.c - 3.d (array length write) - * - * duk_js_to_arrayindex_string_helper() computes the array index from - * string contents alone. Depending on options it's only called during - * string intern (and value stored to duk_hstring) or it's called also - * at runtime. */ -DUK_INTERNAL duk_small_int_t duk_js_to_arrayindex_raw_string(const duk_uint8_t *str, duk_uint32_t blen, duk_uarridx_t *out_idx) { - duk_uarridx_t res, new_res; - - if (blen == 0 || blen > 10) { - goto parse_fail; - } - if (str[0] == (duk_uint8_t) '0' && blen > 1) { - goto parse_fail; - } +/* Compure array index from string context, or return a "not array index" + * indicator. + */ +DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_string(const duk_uint8_t *str, duk_uint32_t blen) { + duk_uarridx_t res; - /* Accept 32-bit decimal integers, no leading zeroes, signs, etc. - * Leading zeroes are not accepted (zero index "0" is an exception - * handled above). + /* Only strings with byte length 1-10 can be 32-bit array indices. + * Leading zeroes (except '0' alone), plus/minus signs are not allowed. + * We could do a lot of prechecks here, but since most strings won't + * start with any digits, it's simpler to just parse the number and + * fail quickly. */ res = 0; - while (blen-- > 0) { - duk_uint8_t c = *str++; - if (c >= (duk_uint8_t) '0' && c <= (duk_uint8_t) '9') { - new_res = res * 10 + (duk_uint32_t) (c - (duk_uint8_t) '0'); - if (new_res < res) { - /* overflow, more than 32 bits -> not an array index */ - goto parse_fail; + if (blen == 0) { + goto parse_fail; + } + do { + duk_uarridx_t dig; + dig = (duk_uarridx_t) (*str++) - DUK_ASC_0; + + if (dig <= 9U) { + /* Careful overflow handling. When multiplying by 10: + * - 0x19999998 x 10 = 0xfffffff0: no overflow, and adding + * 0...9 is safe. + * - 0x19999999 x 10 = 0xfffffffa: no overflow, adding + * 0...5 is safe, 6...9 overflows. + * - 0x1999999a x 10 = 0x100000004: always overflow. + */ + if (DUK_UNLIKELY(res >= 0x19999999UL)) { + if (res >= 0x1999999aUL) { + /* Always overflow. */ + goto parse_fail; + } + DUK_ASSERT(res == 0x19999999UL); + if (dig >= 6U) { + goto parse_fail; + } + res = 0xfffffffaUL + dig; + DUK_ASSERT(res >= 0xfffffffaUL); + DUK_ASSERT_DISABLE(res <= 0xffffffffUL); /* range */ + } else { + res = res * 10U + dig; + if (DUK_UNLIKELY(res == 0)) { + /* If 'res' is 0, previous 'res' must + * have been 0 and we scanned in a zero. + * This is only allowed if blen == 1, + * i.e. the exact string '0'. + */ + if (blen == (duk_uint32_t) 1) { + return 0; + } + goto parse_fail; + } } - res = new_res; } else { + /* Because 'dig' is unsigned, catches both values + * above '9' and below '0'. + */ goto parse_fail; } - } + } while (--blen > 0); - *out_idx = res; - return 1; + return res; parse_fail: - *out_idx = DUK_HSTRING_NO_ARRAY_INDEX; - return 0; + return DUK_HSTRING_NO_ARRAY_INDEX; } -/* Called by duk_hstring.h macros */ -DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h) { +#if !defined(DUK_USE_HSTRING_ARRIDX) +/* Get array index for a string which is known to be an array index. This helper + * is needed when duk_hstring doesn't concretely store the array index, but strings + * are flagged as array indices at intern time. + */ +DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_hstring_fast_known(duk_hstring *h) { + const duk_uint8_t *p; duk_uarridx_t res; - duk_small_int_t rc; + duk_uint8_t t; + + DUK_ASSERT(h != NULL); + DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(h)); + + p = DUK_HSTRING_GET_DATA(h); + res = 0; + for (;;) { + t = *p++; + if (DUK_UNLIKELY(t == 0)) { + /* Scanning to NUL is always safe for interned strings. */ + break; + } + DUK_ASSERT(t >= DUK_ASC_0 && t <= DUK_ASC_9); + res = res * 10U + (t - DUK_ASC_0); + } + return res; +} +DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_hstring_fast(duk_hstring *h) { + DUK_ASSERT(h != NULL); if (!DUK_HSTRING_HAS_ARRIDX(h)) { return DUK_HSTRING_NO_ARRAY_INDEX; } - - rc = duk_js_to_arrayindex_raw_string(DUK_HSTRING_GET_DATA(h), - DUK_HSTRING_GET_BYTELEN(h), - &res); - DUK_UNREF(rc); - DUK_ASSERT(rc != 0); - return res; + return duk_js_to_arrayindex_hstring_fast_known(h); } +#endif /* DUK_USE_HSTRING_ARRIDX */ #line 1 "duk_js_var.c" /* * Identifier access and function closure handling. @@ -75068,11 +77099,11 @@ */ typedef struct { + duk_hobject *env; duk_hobject *holder; /* for object-bound identifiers */ duk_tval *value; /* for register-bound and declarative env identifiers */ duk_int_t attrs; /* property attributes for identifier (relevant if value != NULL) */ - duk_tval *this_binding; - duk_hobject *env; + duk_bool_t has_this; /* for object-bound identifiers: provide 'this' binding */ } duk__id_lookup_result; /* @@ -75225,7 +77256,7 @@ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&fun_clos->obj)); DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(&fun_clos->obj)); DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(&fun_clos->obj)); - DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(&fun_clos->obj)); + DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(&fun_clos->obj)); /* DUK_HOBJECT_FLAG_ARRAY_PART: don't care */ /* DUK_HOBJECT_FLAG_NEWENV: handled below */ DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&fun_clos->obj)); @@ -75260,7 +77291,7 @@ #if defined(DUK_USE_FUNC_NAME_PROPERTY) if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_clos->obj)) { duk_hobject *proto; - duk_hobject *new_env; + duk_hdecenv *new_env; /* * Named function expression, name needs to be bound @@ -75278,11 +77309,18 @@ } /* -> [ ... closure template env ] */ - new_env = duk_push_object_helper_proto(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), - proto); + 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(ctx, (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, proto); + DUK_HOBJECT_INCREF_ALLOWNULL(thr, proto); + + DUK_ASSERT(new_env->thread == NULL); /* Closed. */ + DUK_ASSERT(new_env->varmap == NULL); /* It's important that duk_xdef_prop() is a 'raw define' so that any * properties in an ancestor are never an issue (they should never be @@ -75301,10 +77339,10 @@ /* [ ... closure template env ] */ - DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, new_env); - DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, new_env); - DUK_HOBJECT_INCREF(thr, new_env); - DUK_HOBJECT_INCREF(thr, new_env); + DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, (duk_hobject *) new_env); + DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, (duk_hobject *) new_env); + DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env); + DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env); duk_pop(ctx); /* [ ... closure template ] */ @@ -75526,10 +77564,11 @@ duk_hobject *func, duk_size_t idx_bottom) { duk_context *ctx = (duk_context *) thr; - duk_hobject *env; + duk_hdecenv *env; duk_hobject *parent; duk_hcompfunc *f; + DUK_ASSERT(ctx != NULL); DUK_ASSERT(thr != NULL); DUK_ASSERT(func != NULL); @@ -75539,25 +77578,44 @@ parent = thr->builtins[DUK_BIDX_GLOBAL_ENV]; } - (void) duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), - -1); /* no prototype, updated below */ - env = duk_known_hobject(ctx, -1); - DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, env, parent); /* parent env is the prototype */ + env = duk_hdecenv_alloc(thr, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV)); + DUK_ASSERT(env != NULL); + duk_push_hobject(ctx, (duk_hobject *) env); + + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL); + DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) env, parent); + DUK_HOBJECT_INCREF_ALLOWNULL(thr, parent); /* parent env is the prototype */ /* open scope information, for compiled functions only */ + DUK_ASSERT(env->thread == NULL); + DUK_ASSERT(env->varmap == NULL); + DUK_ASSERT(env->regbase == 0); if (DUK_HOBJECT_IS_COMPFUNC(func)) { - duk_push_hthread(ctx, thr); - duk_xdef_prop_stridx_short_wec(ctx, -2, DUK_STRIDX_INT_THREAD); - duk_push_hobject(ctx, func); - duk_xdef_prop_stridx_short_wec(ctx, -2, DUK_STRIDX_INT_CALLEE); - duk_push_size_t(ctx, idx_bottom); - duk_xdef_prop_stridx_short_wec(ctx, -2, DUK_STRIDX_INT_REGBASE); + duk_hobject *varmap; + duk_tval *tv; + + tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARMAP(thr)); + if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) { + DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); + varmap = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(varmap != NULL); + env->varmap = varmap; + DUK_HOBJECT_INCREF(thr, varmap); + env->thread = thr; + DUK_HTHREAD_INCREF(thr, thr); + env->regbase = idx_bottom; + } else { + /* If function has no _Varmap, leave the environment closed. */ + DUK_ASSERT(env->thread == NULL); + DUK_ASSERT(env->varmap == NULL); + DUK_ASSERT(env->regbase == 0); + } } - return env; + return (duk_hobject *) env; } DUK_INTERNAL @@ -75566,7 +77624,10 @@ duk_context *ctx = (duk_context *) thr; duk_hobject *func; duk_hobject *env; + duk_size_t act_off; + DUK_ASSERT(act != NULL); + act_off = (duk_size_t) ((duk_uint8_t *) act - (duk_uint8_t *) thr->callstack); func = DUK_ACT_GET_FUNC(act); DUK_ASSERT(func != NULL); DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound functions are never in act 'func' */ @@ -75581,6 +77642,7 @@ env = duk_create_activation_environment_record(thr, func, act->idx_bottom); DUK_ASSERT(env != NULL); + act = (duk_activation *) (void *) ((duk_uint8_t *) thr->callstack + act_off); DUK_DDD(DUK_DDDPRINT("created delayed fresh env: %!ipO", (duk_heaphdr *) env)); #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) @@ -75605,156 +77667,103 @@ * Closing environment records. * * The environment record MUST be closed with the thread where its activation - * is. In other words (if 'env' is open): - * - * - 'thr' must match _env.thread - * - 'func' must match _env.callee - * - 'regbase' must match _env.regbase - * - * These are not looked up from the env to minimize code size. - * - * XXX: should access the own properties directly instead of using the API + * is; i.e. if 'env' is open, 'thr' must match env->thread, and the regbase + * and varmap must still be valid. On entry, 'env' must be reachable. */ -DUK_INTERNAL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env, duk_hobject *func, duk_size_t regbase) { +DUK_INTERNAL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env) { duk_context *ctx = (duk_context *) thr; duk_uint_fast32_t i; + duk_hobject *varmap; + duk_hstring *key; + duk_tval *tv; + duk_uint_t regnum; DUK_ASSERT(thr != NULL); DUK_ASSERT(env != NULL); - /* func is NULL for lightfuncs */ - if (!DUK_HOBJECT_IS_DECENV(env) || DUK_HOBJECT_HAS_ENVRECCLOSED(env)) { - DUK_DDD(DUK_DDDPRINT("environment record not a declarative record, " - "or already closed: %!iO", - (duk_heaphdr *) env)); + if (DUK_UNLIKELY(!DUK_HOBJECT_IS_DECENV(env))) { + DUK_DDD(DUK_DDDPRINT("env not a declarative record: %!iO", (duk_heaphdr *) env)); return; } - DUK_DDD(DUK_DDDPRINT("closing environment record: %!iO, func: %!iO, regbase: %ld", - (duk_heaphdr *) env, (duk_heaphdr *) func, (long) regbase)); - - duk_push_hobject(ctx, env); - - /* assertions: env must be closed in the same thread as where it runs */ -#if defined(DUK_USE_ASSERTIONS) - { - /* [... env] */ - - if (duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_CALLEE)) { - DUK_ASSERT(duk_is_object(ctx, -1)); - DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) func); - } - duk_pop(ctx); - - if (duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_THREAD)) { - DUK_ASSERT(duk_is_object(ctx, -1)); - DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) thr); - } - duk_pop(ctx); - - if (duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_REGBASE)) { - DUK_ASSERT(duk_is_number(ctx, -1)); - DUK_ASSERT(duk_get_number(ctx, -1) == (double) regbase); - } - duk_pop(ctx); + varmap = ((duk_hdecenv *) env)->varmap; + if (varmap == NULL) { + DUK_DDD(DUK_DDDPRINT("env already closed: %!iO", (duk_heaphdr *) env)); - /* [... env] */ + return; } -#endif - - if (func != NULL && DUK_HOBJECT_IS_COMPFUNC(func)) { - duk_hobject *varmap; - duk_hstring *key; - duk_tval *tv; - duk_uint_t regnum; - - /* XXX: additional conditions when to close variables? we don't want to do it - * unless the environment may have "escaped" (referenced in a function closure). - * With delayed environments, the existence is probably good enough of a check. - */ - - /* XXX: any way to detect faster whether something needs to be closed? - * We now look up _Callee and then skip the rest. - */ - - /* Note: we rely on the _Varmap having a bunch of nice properties, like: - * - being compacted and unmodified during this process - * - not containing an array part - * - having correct value types - */ - - /* [... env] */ - - if (!duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_CALLEE)) { - DUK_DDD(DUK_DDDPRINT("env has no callee property, nothing to close; re-delete the control properties just in case")); - duk_pop(ctx); - goto skip_varmap; - } - - /* [... env callee] */ - - if (!duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VARMAP)) { - DUK_DDD(DUK_DDDPRINT("callee has no varmap property, nothing to close; delete the control properties")); - duk_pop_2(ctx); - goto skip_varmap; - } - varmap = duk_require_hobject(ctx, -1); - DUK_ASSERT(varmap != NULL); + DUK_ASSERT(((duk_hdecenv *) env)->thread != NULL); + DUK_ASSERT_HDECENV_VALID((duk_hdecenv *) env); - DUK_DDD(DUK_DDDPRINT("varmap: %!O", (duk_heaphdr *) varmap)); + DUK_DDD(DUK_DDDPRINT("closing env: %!iO", (duk_heaphdr *) env)); + DUK_DDD(DUK_DDDPRINT("varmap: %!O", (duk_heaphdr *) varmap)); - /* [... env callee varmap] */ + /* Env must be closed in the same thread as where it runs. */ + DUK_ASSERT(((duk_hdecenv *) env)->thread == thr); - DUK_DDD(DUK_DDDPRINT("copying bound register values, %ld bound regs", (long) DUK_HOBJECT_GET_ENEXT(varmap))); + /* XXX: additional conditions when to close variables? we don't want to do it + * unless the environment may have "escaped" (referenced in a function closure). + * With delayed environments, the existence is probably good enough of a check. + */ - for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) { - key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i); - DUK_ASSERT(key != NULL); /* assume keys are compacted */ + /* Note: we rely on the _Varmap having a bunch of nice properties, like: + * - being compacted and unmodified during this process + * - not containing an array part + * - having correct value types + */ - DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, varmap, i)); /* assume plain values */ + DUK_DDD(DUK_DDDPRINT("copying bound register values, %ld bound regs", (long) DUK_HOBJECT_GET_ENEXT(varmap))); - tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, varmap, i); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); /* assume value is a number */ - regnum = (duk_uint_t) DUK_TVAL_GET_NUMBER(tv); - DUK_ASSERT_DISABLE(regnum >= 0); /* unsigned */ - DUK_ASSERT(regnum < ((duk_hcompfunc *) func)->nregs); /* regnum is sane */ - DUK_ASSERT(thr->valstack + regbase + regnum >= thr->valstack); - DUK_ASSERT(thr->valstack + regbase + regnum < thr->valstack_top); + /* Copy over current variable values from value stack to the + * environment record. The scope object is empty but may + * inherit from another scope which has conflicting names. + */ - /* XXX: slightly awkward */ - duk_push_hstring(ctx, key); - duk_push_tval(ctx, thr->valstack + regbase + regnum); - DUK_DDD(DUK_DDDPRINT("closing identifier '%s' -> reg %ld, value %!T", - (const char *) duk_require_string(ctx, -2), - (long) regnum, - (duk_tval *) duk_get_tval(ctx, -1))); + /* XXX: Do this using a once allocated entry area, no side effects. + * Hash part would need special treatment however (maybe copy, and + * then realloc with hash part if large enough). + */ + for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) { + duk_size_t regbase; - /* [... env callee varmap key val] */ + key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i); + DUK_ASSERT(key != NULL); /* assume keys are compact in _Varmap */ + DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, varmap, i)); /* assume plain values */ - /* if property already exists, overwrites silently */ - duk_xdef_prop(ctx, -5, DUK_PROPDESC_FLAGS_WE); /* writable but not deletable */ - } + tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, varmap, i); + DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (duk_double_t) DUK_UINT32_MAX); /* limits */ +#if defined(DUK_USE_FASTINT) + DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv)); + regnum = (duk_uint_t) DUK_TVAL_GET_FASTINT_U32(tv); +#else + regnum = (duk_uint_t) DUK_TVAL_GET_NUMBER(tv); +#endif - duk_pop_2(ctx); + regbase = ((duk_hdecenv *) env)->regbase; + DUK_ASSERT(thr->valstack + regbase + regnum >= thr->valstack); + DUK_ASSERT(thr->valstack + regbase + regnum < thr->valstack_top); - /* [... env] */ + /* If property already exists, overwrites silently. + * Property is writable, but not deletable (not configurable + * in terms of property attributes). + */ + duk_push_tval(ctx, thr->valstack + regbase + regnum); + DUK_DDD(DUK_DDDPRINT("closing identifier %!O -> reg %ld, value %!T", + (duk_heaphdr *) key, + (long) regnum, + (duk_tval *) duk_get_tval(ctx, -1))); + duk_hobject_define_property_internal(thr, env, key, DUK_PROPDESC_FLAGS_WE); } - skip_varmap: - - /* [... env] */ - - duk_del_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_CALLEE); - duk_del_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_THREAD); - duk_del_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_REGBASE); - - duk_pop(ctx); - - DUK_HOBJECT_SET_ENVRECCLOSED(env); + /* NULL atomically to avoid inconsistent state + side effects. */ + DUK_HOBJECT_DECREF_NORZ(thr, ((duk_hdecenv *) env)->thread); + DUK_HOBJECT_DECREF_NORZ(thr, ((duk_hdecenv *) env)->varmap); + ((duk_hdecenv *) env)->thread = NULL; + ((duk_hdecenv *) env)->varmap = NULL; - DUK_DDD(DUK_DDDPRINT("environment record after being closed: %!O", - (duk_heaphdr *) env)); + DUK_DDD(DUK_DDDPRINT("env after closing: %!O", (duk_heaphdr *) env)); } /* @@ -75784,12 +77793,8 @@ DUK_LOCAL duk_bool_t duk__getid_open_decl_env_regs(duk_hthread *thr, duk_hstring *name, - duk_hobject *env, + duk_hdecenv *env, duk__id_lookup_result *out) { - duk_hthread *env_thr; - duk_hobject *env_func; - duk_size_t env_regbase; - duk_hobject *varmap; duk_tval *tv; duk_size_t reg_rel; duk_size_t idx; @@ -75799,69 +77804,39 @@ DUK_ASSERT(env != NULL); DUK_ASSERT(out != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_DECENV(env)); + DUK_ASSERT(DUK_HOBJECT_IS_DECENV((duk_hobject *) env)); + DUK_ASSERT_HDECENV_VALID(env); - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_CALLEE(thr)); - if (!tv) { - /* env is closed, should be missing _Callee, _Thread, _Regbase */ - DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL); - DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL); - DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL); + if (env->thread == NULL) { + /* already closed */ return 0; } + DUK_ASSERT(env->varmap != NULL); - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); - DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_TVAL_GET_OBJECT(tv))); - env_func = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(env_func != NULL); - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env_func, DUK_HTHREAD_STRING_INT_VARMAP(thr)); - if (!tv) { + tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env->varmap, name); + if (DUK_UNLIKELY(tv == NULL)) { return 0; } - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); - varmap = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(varmap != NULL); - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, varmap, name); - if (!tv) { - return 0; - } DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (duk_double_t) DUK_UINT32_MAX); /* limits */ +#if defined(DUK_USE_FASTINT) + DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv)); + reg_rel = (duk_size_t) DUK_TVAL_GET_FASTINT_U32(tv); +#else reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv); +#endif DUK_ASSERT_DISABLE(reg_rel >= 0); /* unsigned */ - DUK_ASSERT(reg_rel < ((duk_hcompfunc *) env_func)->nregs); - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THREAD(thr)); - DUK_ASSERT(tv != NULL); - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); - DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_THREAD(DUK_TVAL_GET_OBJECT(tv))); - env_thr = (duk_hthread *) DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(env_thr != NULL); - - /* Note: env_thr != thr is quite possible and normal, so careful - * with what thread is used for valstack lookup. - */ - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_REGBASE(thr)); - DUK_ASSERT(tv != NULL); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); - env_regbase = (duk_size_t) DUK_TVAL_GET_NUMBER(tv); - idx = env_regbase + reg_rel; - tv = env_thr->valstack + idx; - DUK_ASSERT(tv >= env_thr->valstack && tv < env_thr->valstack_end); /* XXX: more accurate? */ + idx = env->regbase + reg_rel; + tv = env->thread->valstack + idx; + DUK_ASSERT(tv >= env->thread->valstack && tv < env->thread->valstack_end); /* XXX: more accurate? */ out->value = tv; out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */ - out->this_binding = NULL; /* implicit this value always undefined for - * declarative environment records. - */ - out->env = env; + out->env = (duk_hobject *) env; out->holder = NULL; - + out->has_this = 0; return 1; } @@ -75890,6 +77865,7 @@ return 0; } + /* XXX: move varmap to duk_hcompfunc struct field. */ tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARMAP(thr)); if (!tv) { return 0; @@ -75913,12 +77889,9 @@ out->value = tv; out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */ - out->this_binding = NULL; /* implicit this value always undefined for - * declarative environment records. - */ out->env = NULL; out->holder = NULL; - + out->has_this = 0; return 1; } @@ -75930,7 +77903,6 @@ duk_bool_t parents, duk__id_lookup_result *out) { duk_tval *tv; - duk_tval *tv_target; duk_tval tv_name; duk_uint_t sanity; @@ -75971,10 +77943,10 @@ if (duk__getid_activation_regs(thr, name, act, out)) { DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " - "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O " + "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " "(found from register bindings when env=NULL)", (duk_heaphdr *) name, (duk_tval *) out->value, - (long) out->attrs, (duk_tval *) out->this_binding, + (long) out->attrs, (long) out->has_this, (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); return 1; } @@ -76051,37 +78023,30 @@ * register-bound variables. */ - if (DUK_HOBJECT_HAS_ENVRECCLOSED(env)) { - /* already closed */ - goto skip_regs; - } - - if (duk__getid_open_decl_env_regs(thr, name, env, out)) { + DUK_ASSERT_HDECENV_VALID((duk_hdecenv *) env); + if (duk__getid_open_decl_env_regs(thr, name, (duk_hdecenv *) env, out)) { DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " - "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O " + "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " "(declarative environment record, scope open, found in regs)", (duk_heaphdr *) name, (duk_tval *) out->value, - (long) out->attrs, (duk_tval *) out->this_binding, + (long) out->attrs, (long) out->has_this, (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); return 1; } - skip_regs: tv = duk_hobject_find_existing_entry_tval_ptr_and_attrs(thr->heap, env, name, &attrs); if (tv) { out->value = tv; out->attrs = attrs; - out->this_binding = NULL; /* implicit this value always undefined for - * declarative environment records. - */ out->env = env; out->holder = env; + out->has_this = 0; DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " - "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O " + "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " "(declarative environment record, found in properties)", (duk_heaphdr *) name, (duk_tval *) out->value, - (long) out->attrs, (duk_tval *) out->this_binding, + (long) out->attrs, (long) out->has_this, (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); return 1; } @@ -76104,11 +78069,9 @@ duk_bool_t found; DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV); + DUK_ASSERT_HOBJENV_VALID((duk_hobjenv *) env); - tv_target = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_TARGET(thr)); - DUK_ASSERT(tv_target != NULL); - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_target)); - target = DUK_TVAL_GET_OBJECT(tv_target); + target = ((duk_hobjenv *) env)->target; DUK_ASSERT(target != NULL); /* Target may be a Proxy or property may be an accessor, so we must @@ -76119,10 +78082,13 @@ */ if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(target)) { + duk_tval tv_target_tmp; + DUK_ASSERT(name != NULL); DUK_TVAL_SET_STRING(&tv_name, name); + DUK_TVAL_SET_OBJECT(&tv_target_tmp, target); - found = duk_hobject_hasprop(thr, tv_target, &tv_name); + found = duk_hobject_hasprop(thr, &tv_target_tmp, &tv_name); } else { /* XXX: duk_hobject_hasprop() would be correct for * non-Proxy objects too, but it is about ~20-25% @@ -76135,16 +78101,15 @@ if (found) { out->value = NULL; /* can't get value, may be accessor */ out->attrs = 0; /* irrelevant when out->value == NULL */ - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THIS(thr)); - out->this_binding = tv; /* may be NULL */ out->env = env; out->holder = target; + out->has_this = ((duk_hobjenv *) env)->has_this; DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " - "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O " + "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " "(object environment record)", (duk_heaphdr *) name, (duk_tval *) out->value, - (long) out->attrs, (duk_tval *) out->this_binding, + (long) out->attrs, (long) out->has_this, (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); return 1; } @@ -76156,11 +78121,11 @@ goto fail_not_found; } - if (sanity-- == 0) { + if (DUK_UNLIKELY(sanity-- == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); } env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env); - }; + } /* * Not found (even in global object) @@ -76267,29 +78232,27 @@ parents = 1; /* follow parent chain */ if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) { if (ref.value) { - DUK_ASSERT(ref.this_binding == NULL); /* always for register bindings */ duk_push_tval(ctx, ref.value); duk_push_undefined(ctx); } else { DUK_ASSERT(ref.holder != NULL); - /* Note: getprop may invoke any getter and invalidate any - * duk_tval pointers, so this must be done first. + /* ref.holder is safe across the getprop call (even + * with side effects) because 'env' is reachable and + * ref.holder is a direct heap pointer. */ - if (ref.this_binding) { - duk_push_tval(ctx, ref.this_binding); - } else { - duk_push_undefined(ctx); - } - DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder); DUK_TVAL_SET_STRING(&tv_tmp_key, name); - (void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key); /* [this value] */ + (void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key); /* [value] */ - /* ref.value, ref.this.binding invalidated here by getprop call */ + if (ref.has_this) { + duk_push_hobject(ctx, ref.holder); + } else { + duk_push_undefined(ctx); + } - duk_insert(ctx, -2); /* [this value] -> [value this] */ + /* [value this] */ } return 1; @@ -76392,13 +78355,11 @@ */ duk_tval *tv_val; - DUK_ASSERT(ref.this_binding == NULL); /* always for register bindings */ - tv_val = ref.value; DUK_ASSERT(tv_val != NULL); DUK_TVAL_SET_TVAL_UPDREF(thr, tv_val, val); /* side effects */ - /* ref.value and ref.this_binding invalidated here */ + /* ref.value invalidated here */ } else { DUK_ASSERT(ref.holder != NULL); @@ -76406,7 +78367,7 @@ DUK_TVAL_SET_STRING(&tv_tmp_key, name); (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, strict); - /* ref.value and ref.this_binding invalidated here */ + /* ref.value invalidated here */ } return; @@ -76779,14 +78740,11 @@ */ if (DUK_HOBJECT_IS_DECENV(env)) { + DUK_ASSERT_HDECENV_VALID((duk_hdecenv *) env); holder = env; } else { - DUK_ASSERT(DUK_HOBJECT_IS_OBJENV(env)); - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_TARGET(thr)); - DUK_ASSERT(tv != NULL); - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); - holder = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT_HOBJENV_VALID((duk_hobjenv *) env); + holder = ((duk_hobjenv *) env)->target; DUK_ASSERT(holder != NULL); } @@ -76828,6 +78786,10 @@ duk_bool_t is_func_decl) { duk_hobject *env; duk_tval tv_val_copy; + duk_size_t act_off; + + DUK_ASSERT(act != NULL); + act_off = (duk_size_t) ((duk_uint8_t *) act - (duk_uint8_t *) thr->callstack); /* * Make a value copy of the input val. This ensures that @@ -76844,6 +78806,7 @@ if (!act->var_env) { DUK_ASSERT(act->lex_env == NULL); duk_js_init_activation_environment_records_delayed(thr, act); + act = (duk_activation *) (void *) ((duk_uint8_t *) thr->callstack + act_off); } DUK_ASSERT(act->lex_env != NULL); DUK_ASSERT(act->var_env != NULL); @@ -77601,6 +79564,68 @@ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE); } +/* Parse legacy octal escape of the form \N{1,3}, e.g. \0, \5, \0377. Maximum + * allowed value is \0377 (U+00FF), longest match is used. Used for both string + * RegExp octal escape parsing. Window[0] must be the slash '\' and the first + * digit must already be validated to be in [0-9] by the caller. + */ +DUK_LOCAL duk_codepoint_t duk__lexer_parse_legacy_octal(duk_lexer_ctx *lex_ctx, duk_small_int_t *out_adv, duk_bool_t reject_annex_b) { + duk_codepoint_t cp; + duk_small_uint_t lookup_idx; + duk_small_int_t adv; + duk_codepoint_t tmp; + + DUK_ASSERT(out_adv != NULL); + DUK_ASSERT(DUK__LOOKUP(lex_ctx, 0) == DUK_ASC_BACKSLASH); + DUK_ASSERT(DUK__LOOKUP(lex_ctx, 1) >= DUK_ASC_0 && DUK__LOOKUP(lex_ctx, 1) <= DUK_ASC_9); + + cp = 0; + for (lookup_idx = 1; lookup_idx <= 3; lookup_idx++) { + DUK_DDD(DUK_DDDPRINT("lookup_idx=%ld, cp=%ld", (long) lookup_idx, (long) cp)); + tmp = DUK__LOOKUP(lex_ctx, lookup_idx); + if (tmp < DUK_ASC_0 || tmp > DUK_ASC_7) { + /* No more valid digits. */ + break; + } + tmp = (cp << 3) + (tmp - DUK_ASC_0); + if (tmp > 0xff) { + /* Three digit octal escapes above \377 (= 0xff) + * are not allowed. + */ + break; + } + cp = tmp; + } + DUK_DDD(DUK_DDDPRINT("final lookup_idx=%ld, cp=%ld", (long) lookup_idx, (long) cp)); + + adv = lookup_idx; + if (lookup_idx == 1) { + DUK_DDD(DUK_DDDPRINT("\\8 or \\9 -> treat as literal, accept in strict mode too")); + DUK_ASSERT(tmp == DUK_ASC_8 || tmp == DUK_ASC_9); + cp = tmp; + adv++; /* correction to above, eat offending character */ + } else if (lookup_idx == 2 && cp == 0) { + /* Note: 'foo\0bar' is OK in strict mode, but 'foo\00bar' is not. + * It won't be interpreted as 'foo\u{0}0bar' but as a SyntaxError. + */ + DUK_DDD(DUK_DDDPRINT("\\0 -> accept in strict mode too")); + } else { + /* This clause also handles non-shortest zero, e.g. \00. */ + if (reject_annex_b) { + DUK_DDD(DUK_DDDPRINT("non-zero octal literal %ld -> reject in strict-mode", (long) cp)); + cp = -1; + } else { + DUK_DDD(DUK_DDDPRINT("non-zero octal literal %ld -> accepted", (long) cp)); + DUK_ASSERT(cp >= 0 && cp <= 0xff); + } + } + + *out_adv = adv; + + DUK_ASSERT((cp >= 0 && cp <= 0xff) || (cp == -1 && reject_annex_b)); + return cp; +} + /* XXX: move strict mode to lex_ctx? */ DUK_LOCAL void duk__lexer_parse_string_literal(duk_lexer_ctx *lex_ctx, duk_token *out_token, duk_small_int_t quote, duk_bool_t strict_mode) { duk_small_int_t adv; @@ -77686,46 +79711,9 @@ * Parse octal (up to 3 digits) from the lookup window. */ - duk_codepoint_t tmp; - duk_small_uint_t lookup_idx; - - emitcp = 0; - for (lookup_idx = 1; lookup_idx <= 3; lookup_idx++) { - DUK_DDD(DUK_DDDPRINT("lookup_idx=%ld, emitcp=%ld", (long) lookup_idx, (long) emitcp)); - tmp = DUK__LOOKUP(lex_ctx, lookup_idx); - if (tmp < DUK_ASC_0 || tmp > DUK_ASC_7) { - /* No more valid digits. */ - break; - } - tmp = (emitcp << 3) + (tmp - DUK_ASC_0); - if (tmp > 0xff) { - /* Three digit octal escapes above \377 (= 0xff) - * are not allowed. - */ - break; - } - emitcp = tmp; - } - DUK_DDD(DUK_DDDPRINT("final lookup_idx=%ld, emitcp=%ld", (long) lookup_idx, (long) emitcp)); - - adv = lookup_idx; - if (lookup_idx == 1) { - /* \8 or \9 -> treat as literal, accept also - * in strict mode. - */ - DUK_DDD(DUK_DDDPRINT("\\8 or \\9 -> treat as literal, accept in strict mode too")); - emitcp = x; - adv++; /* correction to above, eat offending character */ - } else if (lookup_idx == 2 && emitcp == 0) { - /* Zero escape, also allowed in non-strict mode. */ - DUK_DDD(DUK_DDDPRINT("\\0 -> accept in strict mode too")); - } else { - /* Valid octal, only accept in non-strict mode. */ - DUK_DDD(DUK_DDDPRINT("octal literal %ld -> accept only in non-strict-mode", (long) emitcp)); - DUK_ASSERT(emitcp >= 0 && emitcp <= 0xff); - if (strict_mode) { - goto fail_escape; - } + emitcp = duk__lexer_parse_legacy_octal(lex_ctx, &adv, strict_mode /*reject_annex_b*/); + if (emitcp < 0) { + goto fail_escape; } } else if (x < 0) { goto fail_unterminated; @@ -77776,6 +79764,19 @@ return; } +/* Skip to end-of-line (or end-of-file), used for single line comments. */ +DUK_LOCAL void duk__lexer_skip_to_endofline(duk_lexer_ctx *lex_ctx) { + for (;;) { + duk_codepoint_t x; + + x = DUK__L0(); + if (x < 0 || duk_unicode_is_line_terminator(x)) { + break; + } + DUK__ADVANCECHARS(lex_ctx, 1); + } +} + /* * Parse Ecmascript source InputElementDiv or InputElementRegExp * (E5 Section 7), skipping whitespace, comments, and line terminators. @@ -77914,6 +79915,17 @@ DUK__ADVANCECHARS(lex_ctx, 1); got_lineterm = 1; goto restart_lineupdate; +#if defined(DUK_USE_SHEBANG_COMMENTS) + case DUK_ASC_HASH: /* '#' */ + if (DUK__L1() == DUK_ASC_EXCLAMATION && lex_ctx->window[0].offset == 0 && + (lex_ctx->flags & DUK_COMPILE_SHEBANG)) { + /* "Shebang" comment ('#! ...') on first line. */ + /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but not necessary */ + duk__lexer_skip_to_endofline(lex_ctx); + goto restart; /* line terminator will be handled on next round */ + } + goto fail_token; +#endif /* DUK_USE_SHEBANG_COMMENTS */ case DUK_ASC_SLASH: /* '/' */ if (DUK__L1() == DUK_ASC_SLASH) { /* @@ -77921,14 +79933,8 @@ * code point). */ - /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but it unnecessary */ - for (;;) { - x = DUK__L0(); - if (x < 0 || duk_unicode_is_line_terminator(x)) { - break; - } - DUK__ADVANCECHARS(lex_ctx, 1); - } + /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but not necessary */ + duk__lexer_skip_to_endofline(lex_ctx); goto restart; /* line terminator will be handled on next round */ } else if (DUK__L1() == DUK_ASC_STAR) { /* @@ -78113,6 +80119,18 @@ advtok = DUK__ADVTOK(1, DUK_TOK_COMMA); break; case DUK_ASC_LANGLE: /* '<' */ +#if defined(DUK_USE_HTML_COMMENTS) + if (DUK__L1() == DUK_ASC_EXCLAMATION && DUK__L2() == DUK_ASC_MINUS && DUK__L3() == DUK_ASC_MINUS) { + /* + * ES6: B.1.3, handle "" SingleLineHTMLCloseComment + * Only allowed: + * - on new line + * - preceded only by whitespace + * - preceded by end of multiline comment and optional whitespace + * + * Since whitespace generates no tokens, and multiline comments + * are treated as a line ending, consulting `got_lineterm` is + * sufficient to test for these three options. + */ + + /* DUK__ADVANCECHARS(lex_ctx, 3) would be correct here, but not necessary */ + duk__lexer_skip_to_endofline(lex_ctx); + goto restart; /* line terminator will be handled on next round */ + } else +#endif /* DUK_USE_HTML_COMMENTS */ if (DUK__L1() == DUK_ASC_MINUS) { advtok = DUK__ADVTOK(2, DUK_TOK_DECREMENT); } else if (DUK__L1() == DUK_ASC_EQUALS) { @@ -78877,6 +80914,8 @@ } else if (DUK__L2() == DUK_ASC_COLON) { /* (?: */ advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_START_NONCAPTURE_GROUP); + } else { + goto fail_group; } } else { /* ( */ @@ -78944,6 +80983,10 @@ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_ESCAPE); return; + fail_group: + DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_GROUP); + return; + #if !defined(DUK_USE_ES6_REGEXP_SYNTAX) fail_invalid_char: DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_CHARACTER); @@ -79020,7 +81063,7 @@ DUK__ADVANCECHARS(lex_ctx, 1); /* eat ']' before finishing */ break; } else if (x == DUK_ASC_MINUS) { - if (start >= 0 && !dash && DUK__L0() != DUK_ASC_RBRACKET) { + if (start >= 0 && !dash && DUK__L1() != DUK_ASC_RBRACKET) { /* '-' as a range indicator */ dash = 1; continue; @@ -79117,12 +81160,24 @@ sizeof(duk_unicode_re_ranges_not_wordchar) / sizeof(duk_uint16_t)); ch = -1; } else if (DUK__ISDIGIT(x)) { - /* DecimalEscape, only \0 is allowed, no leading zeroes are allowed */ + /* DecimalEscape, only \0 is allowed, no leading + * zeroes are allowed. + * + * ES2015 Annex B also allows (maximal match) legacy + * octal escapes up to \377 and \8 and \9 are + * accepted as literal '8' and '9', also in strict mode. + */ + +#if defined(DUK_USE_ES6_REGEXP_SYNTAX) + ch = duk__lexer_parse_legacy_octal(lex_ctx, &adv, 0 /*reject_annex_b*/); + DUK_ASSERT(ch >= 0); /* no rejections */ +#else if (x == DUK_ASC_0 && !DUK__ISDIGIT(DUK__L2())) { ch = 0x0000; } else { goto fail_escape; } +#endif #if defined(DUK_USE_ES6_REGEXP_SYNTAX) } else if (x >= 0) { /* IdentityEscape: ES2015 Annex B allows almost all @@ -82367,34 +84422,34 @@ switch (c) { case (duk_uint8_t) 'g': { if (flags & DUK_RE_FLAG_GLOBAL) { - goto error; + goto flags_error; } flags |= DUK_RE_FLAG_GLOBAL; break; } case (duk_uint8_t) 'i': { if (flags & DUK_RE_FLAG_IGNORE_CASE) { - goto error; + goto flags_error; } flags |= DUK_RE_FLAG_IGNORE_CASE; break; } case (duk_uint8_t) 'm': { if (flags & DUK_RE_FLAG_MULTILINE) { - goto error; + goto flags_error; } flags |= DUK_RE_FLAG_MULTILINE; break; } default: { - goto error; + goto flags_error; } } } return flags; - error: + flags_error: DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_REGEXP_FLAGS); return 0; /* never here */ } @@ -83465,6 +85520,7 @@ char_offset = (duk_uint32_t) 0; } + DUK_ASSERT(char_offset <= DUK_HSTRING_GET_CHARLEN(h_input)); sp = re_ctx.input + duk_heap_strcache_offset_char2byte(thr, h_input, char_offset); /* @@ -90644,8 +92700,7 @@ } /* Decode a one-bit flag, and if set, decode a value of 'bits', otherwise return - * default value. Return value is signed so that negative marker value can be - * used by caller as a "not present" value. + * default value. */ DUK_INTERNAL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value) { if (duk_bd_decode_flag(ctx)) { @@ -90655,6 +92710,11 @@ } } +/* Signed variant, allows negative marker value. */ +DUK_INTERNAL duk_int32_t duk_bd_decode_flagged_signed(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value) { + return (duk_int32_t) duk_bd_decode_flagged(ctx, bits, (duk_uint32_t) def_value); +} + /* Shared varint encoding. Match dukutil.py BitEncode.varuint(). */ DUK_INTERNAL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx) { duk_small_uint_t t; @@ -90856,7 +92916,7 @@ curr_off = (duk_size_t) (bw_ctx->p - bw_ctx->p_base); add_sz = (curr_off >> DUK_BW_SPARE_SHIFT) + DUK_BW_SPARE_ADD; new_sz = curr_off + sz + add_sz; - if (new_sz < curr_off) { + if (DUK_UNLIKELY(new_sz < curr_off)) { /* overflow */ DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG); return NULL; /* not reachable */ diff -Nru duktape-2.0.0/src/duktape.h duktape-2.1.1/src/duktape.h --- duktape-2.0.0/src/duktape.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src/duktape.h 2017-07-28 22:05:08.000000000 +0000 @@ -1,13 +1,13 @@ /* - * Duktape public API for Duktape 2.0.0. + * Duktape public API for Duktape 2.1.1. * - * See the API reference for documentation on call semantics. - * The exposed API is inside the DUK_API_PUBLIC_H_INCLUDED - * include guard. Other parts of the header are Duktape - * internal and related to platform/compiler/feature detection. + * See the API reference for documentation on call semantics. The exposed, + * supported API is between the "BEGIN PUBLIC API" and "END PUBLIC API" + * comments. Other parts of the header are Duktape internal and related to + * e.g. platform/compiler/feature detection. * - * Git commit 4180966c47d6d87106008dd4338de8d507c8072b (v2.0.0). - * Git branch master. + * Git commit 9c8fba6392d1913cb5359be7b8f386fa3cdd8b4d (v2.1.1). + * Git branch v2.1-maintenance. * * See Duktape AUTHORS.rst and LICENSE.txt for copyright and * licensing information. @@ -87,6 +87,8 @@ * * Brett Vickers (https://github.com/beevik) * * Dominik Okwieka (https://github.com/okitec) * * Remko Tron\u00e7on (https://el-tramo.be) + * * Romero Malaquias (rbsm@ic.ufal.br) + * * Michael Drake * * Other contributions * =================== @@ -135,18 +137,38 @@ #define DUK_SINGLE_FILE -/* External duk_config.h provides platform/compiler/OS dependent - * typedefs and macros, and DUK_USE_xxx config options so that - * the rest of Duktape doesn't need to do any feature detection. +/* + * BEGIN PUBLIC API */ -#include "duk_config.h" /* - * BEGIN PUBLIC API + * Version and Git commit identification + */ + +/* Duktape version, (major * 10000) + (minor * 100) + patch. Allows C code + * to #if (DUK_VERSION >= NNN) against Duktape API version. The same value + * is also available to Ecmascript code in Duktape.version. Unofficial + * development snapshots have 99 for patch level (e.g. 0.10.99 would be a + * development version after 0.10.0 but before the next official release). */ +#define DUK_VERSION 20101L -#if !defined(DUK_API_PUBLIC_H_INCLUDED) -#define DUK_API_PUBLIC_H_INCLUDED +/* Git commit, describe, and branch for Duktape build. Useful for + * non-official snapshot builds so that application code can easily log + * which Duktape snapshot was used. Not available in the Ecmascript + * environment. + */ +#define DUK_GIT_COMMIT "9c8fba6392d1913cb5359be7b8f386fa3cdd8b4d" +#define DUK_GIT_DESCRIBE "v2.1.1" +#define DUK_GIT_BRANCH "v2.1-maintenance" + +/* External duk_config.h provides platform/compiler/OS dependent + * typedefs and macros, and DUK_USE_xxx config options so that + * the rest of Duktape doesn't need to do any feature detection. + * DUK_VERSION is defined before including so that configuration + * snippets can react to it. + */ +#include "duk_config.h" /* * Avoid C++ name mangling @@ -247,23 +269,6 @@ * Constants */ -/* Duktape version, (major * 10000) + (minor * 100) + patch. Allows C code - * to #if (DUK_VERSION >= NNN) against Duktape API version. The same value - * is also available to Ecmascript code in Duktape.version. Unofficial - * development snapshots have 99 for patch level (e.g. 0.10.99 would be a - * development version after 0.10.0 but before the next official release). - */ -#define DUK_VERSION 20000L - -/* Git commit, describe, and branch for Duktape build. Useful for - * non-official snapshot builds so that application code can easily log - * which Duktape snapshot was used. Not available in the Ecmascript - * environment. - */ -#define DUK_GIT_COMMIT "4180966c47d6d87106008dd4338de8d507c8072b" -#define DUK_GIT_DESCRIBE "v2.0.0" -#define DUK_GIT_BRANCH "master" - /* Duktape debug protocol version used by this build. */ #define DUK_DEBUG_PROTOCOL_VERSION 2 @@ -334,11 +339,13 @@ #define DUK_COMPILE_EVAL (1 << 3) /* compile eval code (instead of global code) */ #define DUK_COMPILE_FUNCTION (1 << 4) /* compile function code (instead of global code) */ #define DUK_COMPILE_STRICT (1 << 5) /* use strict (outer) context for global, eval, or function code */ -#define DUK_COMPILE_SAFE (1 << 6) /* (internal) catch compilation errors */ -#define DUK_COMPILE_NORESULT (1 << 7) /* (internal) omit eval result */ -#define DUK_COMPILE_NOSOURCE (1 << 8) /* (internal) no source string on stack */ -#define DUK_COMPILE_STRLEN (1 << 9) /* (internal) take strlen() of src_buffer (avoids double evaluation in macro) */ -#define DUK_COMPILE_NOFILENAME (1 << 10) /* (internal) no filename on stack */ +#define DUK_COMPILE_SHEBANG (1 << 6) /* allow shebang ('#! ...') comment on first line of source */ +#define DUK_COMPILE_SAFE (1 << 7) /* (internal) catch compilation errors */ +#define DUK_COMPILE_NORESULT (1 << 8) /* (internal) omit eval result */ +#define DUK_COMPILE_NOSOURCE (1 << 9) /* (internal) no source string on stack */ +#define DUK_COMPILE_STRLEN (1 << 10) /* (internal) take strlen() of src_buffer (avoids double evaluation in macro) */ +#define DUK_COMPILE_NOFILENAME (1 << 11) /* (internal) no filename on stack */ +#define DUK_COMPILE_FUNCEXPR (1 << 12) /* (internal) source is a function expression (used for Function constructor) */ /* Flags for duk_def_prop() and its variants */ #define DUK_DEFPROP_WRITABLE (1 << 0) /* set writable (effective if DUK_DEFPROP_HAVE_WRITABLE set) */ @@ -445,9 +452,9 @@ DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_fatal_raw(duk_context *ctx, const char *err_msg)); #define duk_fatal(ctx,err_msg) \ (duk_fatal_raw((ctx), (err_msg)), (duk_ret_t) 0) +DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...)); #if defined(DUK_API_VARIADIC_MACROS) -DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...)); #define duk_error(ctx,err_code,...) \ (duk_error_raw((ctx), (duk_errcode_t) (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) #define duk_generic_error(ctx,...) \ @@ -516,6 +523,7 @@ #endif /* DUK_API_VARIADIC_MACROS */ DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap)); + #define duk_error_va(ctx,err_code,fmt,ap) \ (duk_error_va_raw((ctx), (duk_errcode_t) (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) #define duk_generic_error_va(ctx,fmt,ap) \ @@ -663,19 +671,18 @@ #define duk_push_external_buffer(ctx) \ ((void) duk_push_buffer_raw((ctx), 0, DUK_BUF_FLAG_DYNAMIC | DUK_BUF_FLAG_EXTERNAL)) -#define DUK_BUFOBJ_CREATE_ARRBUF (1 << 4) /* internal flag: create backing ArrayBuffer; keep in one byte */ #define DUK_BUFOBJ_ARRAYBUFFER 0 -#define DUK_BUFOBJ_NODEJS_BUFFER (1 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_DATAVIEW (2 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_INT8ARRAY (3 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_UINT8ARRAY (4 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_UINT8CLAMPEDARRAY (5 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_INT16ARRAY (6 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_UINT16ARRAY (7 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_INT32ARRAY (8 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_UINT32ARRAY (9 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_FLOAT32ARRAY (10 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_FLOAT64ARRAY (11 | DUK_BUFOBJ_CREATE_ARRBUF) +#define DUK_BUFOBJ_NODEJS_BUFFER 1 +#define DUK_BUFOBJ_DATAVIEW 2 +#define DUK_BUFOBJ_INT8ARRAY 3 +#define DUK_BUFOBJ_UINT8ARRAY 4 +#define DUK_BUFOBJ_UINT8CLAMPEDARRAY 5 +#define DUK_BUFOBJ_INT16ARRAY 6 +#define DUK_BUFOBJ_UINT16ARRAY 7 +#define DUK_BUFOBJ_INT32ARRAY 8 +#define DUK_BUFOBJ_UINT32ARRAY 9 +#define DUK_BUFOBJ_FLOAT32ARRAY 10 +#define DUK_BUFOBJ_FLOAT64ARRAY 11 DUK_EXTERNAL_DECL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags); @@ -789,8 +796,43 @@ DUK_EXTERNAL_DECL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t idx); DUK_EXTERNAL_DECL duk_context *duk_get_context(duk_context *ctx, duk_idx_t idx); DUK_EXTERNAL_DECL void *duk_get_heapptr(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t idx, duk_size_t len); + +/* + * Get-with-explicit default operations: like get operations but with an + * explicit default value. + */ + +DUK_EXTERNAL_DECL duk_bool_t duk_get_boolean_default(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value); +DUK_EXTERNAL_DECL duk_double_t duk_get_number_default(duk_context *ctx, duk_idx_t idx, duk_double_t def_value); +DUK_EXTERNAL_DECL duk_int_t duk_get_int_default(duk_context *ctx, duk_idx_t idx, duk_int_t def_value); +DUK_EXTERNAL_DECL duk_uint_t duk_get_uint_default(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value); +DUK_EXTERNAL_DECL const char *duk_get_string_default(duk_context *ctx, duk_idx_t idx, const char *def_value); +DUK_EXTERNAL_DECL const char *duk_get_lstring_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len); +DUK_EXTERNAL_DECL void *duk_get_buffer_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len); +DUK_EXTERNAL_DECL void *duk_get_buffer_data_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len); +DUK_EXTERNAL_DECL void *duk_get_pointer_default(duk_context *ctx, duk_idx_t idx, void *def_value); +DUK_EXTERNAL_DECL duk_c_function duk_get_c_function_default(duk_context *ctx, duk_idx_t idx, duk_c_function def_value); +DUK_EXTERNAL_DECL duk_context *duk_get_context_default(duk_context *ctx, duk_idx_t idx, duk_context *def_value); +DUK_EXTERNAL_DECL void *duk_get_heapptr_default(duk_context *ctx, duk_idx_t idx, void *def_value); + +/* + * Opt operations: like require operations but with an explicit default value + * when value is undefined or index is invalid, null and non-matching types + * cause a TypeError. + */ + +DUK_EXTERNAL_DECL duk_bool_t duk_opt_boolean(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value); +DUK_EXTERNAL_DECL duk_double_t duk_opt_number(duk_context *ctx, duk_idx_t idx, duk_double_t def_value); +DUK_EXTERNAL_DECL duk_int_t duk_opt_int(duk_context *ctx, duk_idx_t idx, duk_int_t def_value); +DUK_EXTERNAL_DECL duk_uint_t duk_opt_uint(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value); +DUK_EXTERNAL_DECL const char *duk_opt_string(duk_context *ctx, duk_idx_t idx, const char *def_ptr); +DUK_EXTERNAL_DECL const char *duk_opt_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len); +DUK_EXTERNAL_DECL void *duk_opt_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size); +DUK_EXTERNAL_DECL void *duk_opt_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size); +DUK_EXTERNAL_DECL void *duk_opt_pointer(duk_context *ctx, duk_idx_t idx, void *def_value); +DUK_EXTERNAL_DECL duk_c_function duk_opt_c_function(duk_context *ctx, duk_idx_t idx, duk_c_function def_value); +DUK_EXTERNAL_DECL duk_context *duk_opt_context(duk_context *ctx, duk_idx_t idx, duk_context *def_value); +DUK_EXTERNAL_DECL void *duk_opt_heapptr(duk_context *ctx, duk_idx_t idx, void *def_value); /* * Require operations: no coercion, throw error if index or type @@ -869,6 +911,17 @@ duk_safe_to_lstring((ctx), (idx), NULL) /* + * Value length + */ + +DUK_EXTERNAL_DECL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t idx, duk_size_t len); +#if 0 +/* duk_require_length()? */ +/* duk_opt_length()? */ +#endif + +/* * Misc conversion */ @@ -1228,434 +1281,8 @@ } #endif -#endif /* DUK_API_PUBLIC_H_INCLUDED */ - /* * END PUBLIC API */ -/* - * 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/cross endian (e.g. ARM) DUK_USE_DOUBLE_ME - * - * ARM is a special case: ARM double values are in mixed/cross 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. - * - * 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] = 0x000000007ff80000ULL; \ - } while (0) -#define DUK__DBLUNION_IS_NAN_FULL(u) \ - ((((u)->ull[DUK_DBL_IDX_ULL0] & 0x000000007ff00000ULL) == 0x000000007ff00000ULL) && \ - ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0xffffffff000fffffULL) != 0)) -#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x000000007ff80000ULL) -#define DUK__DBLUNION_IS_ANYINF(u) \ - (((u)->ull[DUK_DBL_IDX_ULL0] & 0xffffffff7fffffffULL) == 0x000000007ff00000ULL) -#define DUK__DBLUNION_IS_POSINF(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x000000007ff00000ULL) -#define DUK__DBLUNION_IS_NEGINF(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x00000000fff00000ULL) -#define DUK__DBLUNION_IS_ANYZERO(u) \ - (((u)->ull[DUK_DBL_IDX_ULL0] & 0xffffffff7fffffffULL) == 0x0000000000000000ULL) -#define DUK__DBLUNION_IS_POSZERO(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000000000000ULL) -#define DUK__DBLUNION_IS_NEGZERO(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000080000000ULL) -#else -/* Macros for 64-bit ops + big/little endian doubles. */ -#define DUK__DBLUNION_SET_NAN_FULL(u) do { \ - (u)->ull[DUK_DBL_IDX_ULL0] = 0x7ff8000000000000ULL; \ - } while (0) -#define DUK__DBLUNION_IS_NAN_FULL(u) \ - ((((u)->ull[DUK_DBL_IDX_ULL0] & 0x7ff0000000000000ULL) == 0x7ff0000000000000UL) && \ - ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0x000fffffffffffffULL) != 0)) -#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x7ff8000000000000ULL) -#define DUK__DBLUNION_IS_ANYINF(u) \ - (((u)->ull[DUK_DBL_IDX_ULL0] & 0x7fffffffffffffffULL) == 0x7ff0000000000000ULL) -#define DUK__DBLUNION_IS_POSINF(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x7ff0000000000000ULL) -#define DUK__DBLUNION_IS_NEGINF(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0xfff0000000000000ULL) -#define DUK__DBLUNION_IS_ANYZERO(u) \ - (((u)->ull[DUK_DBL_IDX_ULL0] & 0x7fffffffffffffffULL) == 0x0000000000000000ULL) -#define DUK__DBLUNION_IS_POSZERO(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000000000000ULL) -#define DUK__DBLUNION_IS_NEGZERO(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x8000000000000000ULL) -#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] & 0x8000000000000000ULL) != 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 */ - #endif /* DUKTAPE_H_INCLUDED */ diff -Nru duktape-2.0.0/src-input/builtins.yaml duktape-2.1.1/src-input/builtins.yaml --- duktape-2.0.0/src-input/builtins.yaml 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/builtins.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -168,6 +168,17 @@ bidx: true properties: + # 'global' binding giving easy to access to the global object. + # Not yet standard, see https://github.com/tc39/proposal-global. + - key: "global" + value: + type: object + id: bi_global + attributes: "wc" + # This could be stripped when DUK_USE_GLOBAL_BUILTIN is disabled + # but keep for now (the property is quite fundamental). + present_if: DUK_USE_GLOBAL_BINDING + - key: "NaN" value: type: double @@ -482,13 +493,14 @@ duktape: true bidx: true - properties: - - key: "\u00ffTarget" - value: - type: object - id: bi_global - attributes: "" - duktape: true + # The internal 'target' property is now part of duk_hobjenv and handled + # specially by RAM built-in init code. ROM built-ins provide an explicit + # initializer based on these properties. + + objenv_target: bi_global + objenv_has_this: 0 + + properties: [] - id: bi_object_constructor class: Function @@ -1225,6 +1237,35 @@ present_if: - DUK_USE_ES6 - DUK_USE_STRING_BUILTIN + - key: "startsWith" + value: + type: function + native: duk_bi_string_prototype_startswith_endswith + length: 1 + nargs: 2 + magic: 0 # 0=startsWith + present_if: + - DUK_USE_ES6 + - DUK_USE_STRING_BUILTIN + - key: "endsWith" + value: + type: function + native: duk_bi_string_prototype_startswith_endswith + length: 1 + nargs: 2 + magic: 1 # 1=endsWith + present_if: + - DUK_USE_ES6 + - DUK_USE_STRING_BUILTIN + - key: "includes" + value: + type: function + native: duk_bi_string_prototype_includes + length: 1 + nargs: 2 + present_if: + - DUK_USE_ES6 + - DUK_USE_STRING_BUILTIN # Non-standard extension: E5 Section B.2.3 @@ -2751,7 +2792,7 @@ present_if: DUK_USE_COROUTINE_SUPPORT - id: bi_thread_prototype - class: Thread + class: Object internal_prototype: bi_object_prototype duktape: true bidx: true diff -Nru duktape-2.0.0/src-input/duk_api_bytecode.c duktape-2.1.1/src-input/duk_api_bytecode.c --- duktape-2.0.0/src-input/duk_api_bytecode.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_api_bytecode.c 2017-07-28 22:05:08.000000000 +0000 @@ -279,6 +279,7 @@ DUK_RAW_WRITE_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_WRITE_U32_BE(p, tmp32); /* Bytecode instructions: endian conversion needed unless @@ -458,7 +459,7 @@ 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_HAS_THREAD(&h_fun->obj)); + DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(&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)); @@ -584,14 +585,23 @@ * Must create a lexical environment on loading to allow * recursive functions like 'function foo() { foo(); }'. */ - duk_hobject *new_env; + duk_hdecenv *new_env; - new_env = duk_push_object_helper_proto(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), - func_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); - func_env = new_env; + DUK_ASSERT(new_env->thread == NULL); /* Closed. */ + DUK_ASSERT(new_env->varmap == NULL); + DUK_ASSERT(new_env->regbase == 0); + DUK_ASSERT_HDECENV_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(ctx, (duk_hobject *) new_env); duk_dup_m2(ctx); /* -> [ func funcname env funcname ] */ duk_dup(ctx, idx_base); /* -> [ func funcname env funcname func ] */ @@ -648,8 +658,9 @@ /* If _Formals wasn't present in the original function, the list * here will be empty. Same happens if _Formals was present but - * had zero length. We can omit _Formals from the result if its - * length is zero and matches nargs. + * had zero length. We'll omit the _Formals list if it is empty, + * regardless of whether it was present in the original or not, + * this is a workaround for https://github.com/svaarala/duktape/issues/1513. */ duk_push_array(ctx); /* _Formals */ for (arr_idx = 0; ; arr_idx++) { @@ -661,7 +672,16 @@ } duk_put_prop_index(ctx, -2, arr_idx); } - if (arr_idx == 0 && h_fun->nargs == 0) { + if (arr_idx == 0) { + /* Omitting _Formals when the list is empty is technically + * incorrect because the result will differ from the input + * function. This could matter for function templates if: + * _Formals exists, _Formals.length == 0, and nargs > 0. + * This doesn't happen in practice. But if it did, it would + * affect the .length property of function instances created + * from the closure (0 with _Formals present, nargs with + * _Formals absent). + */ duk_pop(ctx); } else { duk_compact_m1(ctx); diff -Nru duktape-2.0.0/src-input/duk_api_call.c duktape-2.1.1/src-input/duk_api_call.c --- duktape-2.0.0/src-input/duk_api_call.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_api_call.c 2017-07-28 22:05:08.000000000 +0000 @@ -44,7 +44,7 @@ DUK_ASSERT(thr != NULL); idx_func = duk_get_top(ctx) - nargs - 1; - if (idx_func < 0 || nargs < 0) { + if (DUK_UNLIKELY(idx_func < 0 || nargs < 0)) { /* note that we can't reliably pop anything here */ DUK_ERROR_TYPE_INVALID_ARGS(thr); } @@ -71,7 +71,7 @@ DUK_ASSERT(thr != NULL); idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */ - if (idx_func < 0 || nargs < 0) { + if (DUK_UNLIKELY(idx_func < 0 || nargs < 0)) { /* note that we can't reliably pop anything here */ DUK_ERROR_TYPE_INVALID_ARGS(thr); } @@ -110,7 +110,7 @@ DUK_ASSERT(thr != NULL); idx_func = duk_get_top(ctx) - nargs - 1; /* must work for nargs <= 0 */ - if (idx_func < 0 || nargs < 0) { + if (DUK_UNLIKELY(idx_func < 0 || nargs < 0)) { /* We can't reliably pop anything here because the stack input * shape is incorrect. So we throw an error; if the caller has * no catch point for this, a fatal error will occur. Another @@ -148,7 +148,7 @@ DUK_ASSERT(thr != NULL); idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */ - if (idx_func < 0 || nargs < 0) { + if (DUK_UNLIKELY(idx_func < 0 || nargs < 0)) { /* See comments in duk_pcall(). */ DUK_ERROR_TYPE_INVALID_ARGS(thr); return DUK_EXEC_ERROR; /* unreachable */ @@ -188,6 +188,7 @@ } DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t nargs) { + duk_hthread *thr = (duk_hthread *) ctx; duk__pcall_prop_args args; /* @@ -199,6 +200,10 @@ args.obj_idx = obj_idx; args.nargs = nargs; + if (DUK_UNLIKELY(nargs < 0)) { + DUK_ERROR_TYPE_INVALID_ARGS(thr); + return DUK_EXEC_ERROR; /* unreachable */ + } /* Inputs: explicit arguments (nargs), +1 for key. If the value stack * does not contain enough args, an error is thrown; this matches @@ -214,7 +219,7 @@ DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(thr != NULL); - if (duk_get_top(ctx) < nargs || nrets < 0) { + if (DUK_UNLIKELY(duk_get_top(ctx) < nargs || nargs < 0 || nrets < 0)) { /* See comments in duk_pcall(). */ DUK_ERROR_TYPE_INVALID_ARGS(thr); return DUK_EXEC_ERROR; /* unreachable */ @@ -279,6 +284,10 @@ /* [... constructor arg1 ... argN] */ + if (DUK_UNLIKELY(nargs < 0)) { + /* note that we can't reliably pop anything here */ + DUK_ERROR_TYPE_INVALID_ARGS(thr); + } idx_cons = duk_require_normalize_index(ctx, -nargs - 1); DUK_DDD(DUK_DDDPRINT("top=%ld, nargs=%ld, idx_cons=%ld", @@ -448,6 +457,7 @@ } DUK_EXTERNAL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs) { + duk_hthread *thr = (duk_hthread *) ctx; duk_int_t rc; DUK_ASSERT_CTX_VALID(ctx); @@ -460,6 +470,11 @@ * wrapper. */ + if (DUK_UNLIKELY(nargs < 0)) { + DUK_ERROR_TYPE_INVALID_ARGS(thr); + return DUK_EXEC_ERROR; /* unreachable */ + } + rc = duk_safe_call(ctx, duk__pnew_helper, (void *) &nargs /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/); return rc; } @@ -472,9 +487,11 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT_DISABLE(thr->callstack_top >= 0); - act = duk_hthread_get_current_activation(thr); - DUK_ASSERT(act != NULL); /* because callstack_top > 0 */ - return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0); + act = thr->callstack_curr; + if (act != NULL) { + return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0); + } + return 0; } /* XXX: Make this obsolete by adding a function flag for rejecting a @@ -503,12 +520,13 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT_DISABLE(thr->callstack_top >= 0); - act = duk_hthread_get_current_activation(thr); - if (act == NULL) { + act = thr->callstack_curr; + if (act != NULL) { + return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0); + } else { /* Strict by default. */ return 1; } - return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0); } /* @@ -524,7 +542,7 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT_DISABLE(thr->callstack_top >= 0); - act = duk_hthread_get_current_activation(thr); + act = thr->callstack_curr; if (act) { func = DUK_ACT_GET_FUNC(act); if (!func) { diff -Nru duktape-2.0.0/src-input/duk_api_codec.c duktape-2.1.1/src-input/duk_api_codec.c --- duktape-2.0.0/src-input/duk_api_codec.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_api_codec.c 2017-07-28 22:05:08.000000000 +0000 @@ -18,7 +18,10 @@ DUK_ASSERT(duk_is_valid_index(ctx, idx)); /* checked by caller */ - ptr = duk_get_buffer_data_raw(ctx, idx, out_len, 0 /*throw_flag*/, &isbuffer); + /* XXX: with def_ptr set to a stack related pointer, isbuffer could + * be removed from the helper? + */ + ptr = duk_get_buffer_data_raw(ctx, idx, out_len, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, &isbuffer); if (isbuffer) { DUK_ASSERT(*out_len == 0 || ptr != NULL); return (const duk_uint8_t *) ptr; @@ -210,13 +213,13 @@ t <<= 6; } else { DUK_ASSERT(x == -1); - goto error; + goto decode_error; } } else { DUK_ASSERT(x >= 0 && x <= 63); if (n_equal > 0) { /* Don't allow actual chars after equal sign. */ - goto error; + goto decode_error; } t = (t << 6) + x; } @@ -242,7 +245,7 @@ /* XX== */ dst -= 2; } else { - goto error; /* invalid padding */ + goto decode_error; /* invalid padding */ } /* Continue parsing after padding, allows concatenated, @@ -266,13 +269,13 @@ * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not * accepted. */ - goto error; + goto decode_error; } *out_dst_final = dst; return 1; - error: + decode_error: return 0; } #else /* DUK_USE_BASE64_FASTPATH */ @@ -314,12 +317,12 @@ /* allow basic ASCII whitespace */ continue; } else { - goto error; + goto decode_error; } if (n_equal > 0) { /* Don't allow mixed padding and actual chars. */ - goto error; + goto decode_error; } t = (t << 6) + y; skip_add: @@ -338,7 +341,7 @@ } else if (n_equal == 2) { dst -= 2; } else { - goto error; /* invalid padding */ + goto decode_error; /* invalid padding */ } /* Here we can choose either to end parsing and ignore @@ -361,13 +364,13 @@ * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not * accepted. */ - goto error; + goto decode_error; } *out_dst_final = dst; return 1; - error: + decode_error: return 0; } #endif /* DUK_USE_BASE64_FASTPATH */ diff -Nru duktape-2.0.0/src-input/duk_api_compile.c duktape-2.1.1/src-input/duk_api_compile.c --- duktape-2.0.0/src-input/duk_api_compile.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_api_compile.c 2017-07-28 22:05:08.000000000 +0000 @@ -13,7 +13,6 @@ /* Eval is just a wrapper now. */ DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) { - duk_uint_t comp_flags; duk_int_t rc; DUK_ASSERT_CTX_VALID(ctx); @@ -27,9 +26,7 @@ /* [ ... source? filename? ] (depends on flags) */ - comp_flags = flags; - comp_flags |= DUK_COMPILE_EVAL; - rc = duk_compile_raw(ctx, src_buffer, src_length, comp_flags); /* may be safe, or non-safe depending on flags */ + rc = duk_compile_raw(ctx, src_buffer, src_length, flags | DUK_COMPILE_EVAL); /* may be safe, or non-safe depending on flags */ /* [ ... closure/error ] */ @@ -62,7 +59,6 @@ duk_hthread *thr = (duk_hthread *) ctx; duk__compile_raw_args *comp_args; duk_uint_t flags; - duk_small_uint_t comp_flags; duk_hcompfunc *h_templ; DUK_ASSERT_CTX_VALID(ctx); @@ -101,22 +97,13 @@ } DUK_ASSERT(comp_args->src_buffer != NULL); - /* XXX: unnecessary translation of flags */ - comp_flags = 0; - if (flags & DUK_COMPILE_EVAL) { - comp_flags |= DUK_JS_COMPILE_FLAG_EVAL; - } if (flags & DUK_COMPILE_FUNCTION) { - comp_flags |= DUK_JS_COMPILE_FLAG_EVAL | - DUK_JS_COMPILE_FLAG_FUNCEXPR; - } - if (flags & DUK_COMPILE_STRICT) { - comp_flags |= DUK_JS_COMPILE_FLAG_STRICT; + flags |= DUK_COMPILE_EVAL | DUK_COMPILE_FUNCEXPR; } /* [ ... source? filename ] */ - duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, comp_flags); + duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, flags); /* [ ... source? func_template ] */ diff -Nru duktape-2.0.0/src-input/duk_api_debug.c duktape-2.1.1/src-input/duk_api_debug.c --- duktape-2.0.0/src-input/duk_api_debug.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_api_debug.c 2017-07-28 22:05:08.000000000 +0000 @@ -84,16 +84,16 @@ /* Start in paused state. */ heap->dbg_processing = 0; - DUK_HEAP_SET_DEBUGGER_PAUSED(heap); - heap->dbg_state_dirty = 1; + heap->dbg_state_dirty = 0; heap->dbg_force_restart = 0; - heap->dbg_step_type = 0; + heap->dbg_step_type = DUK_STEP_TYPE_NONE; heap->dbg_step_thread = NULL; heap->dbg_step_csindex = 0; heap->dbg_step_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. @@ -133,7 +133,7 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->heap != NULL); - if (!DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + if (!duk_debug_is_attached(thr->heap)) { return; } if (thr->callstack_top > 0 || thr->heap->dbg_processing) { @@ -166,7 +166,7 @@ DUK_ERROR_RANGE(thr, "not enough stack values for notify"); return ret; /* unreachable */ } - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + 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(ctx, idx); @@ -179,7 +179,7 @@ * a transport error was not indicated by the transport write * callback. This is not a 100% guarantee of course. */ - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + if (duk_debug_is_attached(thr->heap)) { ret = 1; } } @@ -198,15 +198,19 @@ DUK_D(DUK_DPRINT("application called duk_debugger_pause()")); /* Treat like a debugger statement: ignore when not attached. */ - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { - DUK_HEAP_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; + 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; + } } } diff -Nru duktape-2.0.0/src-input/duk_api_heap.c duktape-2.1.1/src-input/duk_api_heap.c --- duktape-2.0.0/src-input/duk_api_heap.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_api_heap.c 2017-07-28 22:05:08.000000000 +0000 @@ -8,7 +8,7 @@ struct duk_internal_thread_state { duk_ljstate lj; - duk_bool_t handling_error; + duk_bool_t creating_error; duk_hthread *curr_thread; duk_int_t call_recursion_depth; }; @@ -89,14 +89,27 @@ 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(ctx, &lj->value1); duk_push_tval(ctx, &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->handling_error = heap->handling_error; + snapshot->creating_error = heap->creating_error; snapshot->curr_thread = heap->curr_thread; snapshot->call_recursion_depth = heap->call_recursion_depth; @@ -104,7 +117,7 @@ lj->type = DUK_LJ_TYPE_UNKNOWN; DUK_TVAL_SET_UNDEFINED(&lj->value1); DUK_TVAL_SET_UNDEFINED(&lj->value2); - heap->handling_error = 0; + heap->creating_error = 0; heap->curr_thread = NULL; heap->call_recursion_depth = 0; } @@ -119,10 +132,16 @@ 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->handling_error = snapshot->handling_error; + heap->creating_error = snapshot->creating_error; heap->curr_thread = snapshot->curr_thread; heap->call_recursion_depth = snapshot->call_recursion_depth; @@ -134,7 +153,7 @@ duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h_glob; duk_hobject *h_prev_glob; - duk_hobject *h_env; + duk_hobjenv *h_env; duk_hobject *h_prev_env; DUK_D(DUK_DPRINT("replace global object with: %!T", duk_get_tval(ctx, -1))); @@ -161,29 +180,30 @@ * same (initial) built-ins. */ - h_env = duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV), - -1); /* no prototype, updated below */ + 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_dup_m2(ctx); - duk_dup_m3(ctx); - duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); + 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 new_env ] */ + /* [ ... new_glob ] */ h_prev_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; - thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_env; - DUK_HOBJECT_INCREF(thr, h_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 new_env ] */ + /* [ ... new_glob ] */ - duk_pop_2(ctx); + duk_pop(ctx); /* [ ... ] */ } diff -Nru duktape-2.0.0/src-input/duk_api_inspect.c duktape-2.1.1/src-input/duk_api_inspect.c --- duktape-2.0.0/src-input/duk_api_inspect.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_api_inspect.c 2017-07-28 22:05:08.000000000 +0000 @@ -66,18 +66,19 @@ DUK_UNREF(thr); - tv = duk_get_tval_or_unused(ctx, idx); - h = (DUK_TVAL_IS_HEAP_ALLOCATED(tv) ? DUK_TVAL_GET_HEAPHDR(tv) : NULL); - /* 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 */ - duk_push_bare_object(ctx); + tv = duk_get_tval_or_unused(ctx, 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_uint_t) DUK_TVAL_GET_TAG(tv); + duk_push_bare_object(ctx); /* Invalidates 'tv'. */ + tv = NULL; + if (h == NULL) { goto finish; } diff -Nru duktape-2.0.0/src-input/duk_api_internal.h duktape-2.1.1/src-input/duk_api_internal.h --- duktape-2.0.0/src-input/duk_api_internal.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_api_internal.h 2017-07-28 22:05:08.000000000 +0000 @@ -101,7 +101,7 @@ DUK_INTERNAL_DECL duk_hcompfunc *duk_get_hcompfunc(duk_context *ctx, duk_idx_t idx); DUK_INTERNAL_DECL duk_hnatfunc *duk_get_hnatfunc(duk_context *ctx, duk_idx_t idx); -DUK_INTERNAL_DECL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_bool_t throw_flag, duk_bool_t *out_found); +DUK_INTERNAL_DECL void *duk_get_buffer_data_raw(duk_context *ctx, 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_context *ctx, duk_idx_t idx, duk_small_uint_t classnum); @@ -281,6 +281,8 @@ DUK_INTERNAL_DECL duk_idx_t duk_get_top_require_min(duk_context *ctx, duk_idx_t min_top); DUK_INTERNAL_DECL duk_idx_t duk_get_top_index_unsafe(duk_context *ctx); +DUK_INTERNAL_DECL void duk_pop_n_unsafe(duk_context *ctx, duk_idx_t count); +DUK_INTERNAL_DECL void duk_pop_n_nodecref_unsafe(duk_context *ctx, duk_idx_t count); DUK_INTERNAL_DECL void duk_pop_unsafe(duk_context *ctx); DUK_INTERNAL_DECL void duk_compact_m1(duk_context *ctx); diff -Nru duktape-2.0.0/src-input/duk_api_object.c duktape-2.1.1/src-input/duk_api_object.c --- duktape-2.0.0/src-input/duk_api_object.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_api_object.c 2017-07-28 22:05:08.000000000 +0000 @@ -712,9 +712,31 @@ } DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t idx) { + duk_hobject *h; + duk_bool_t callable; + DUK_ASSERT_CTX_VALID(ctx); + h = duk_require_hobject(ctx, idx); /* Get before 'put' so that 'idx' is correct. */ + callable = duk_is_callable(ctx, -1); duk_put_prop_stridx(ctx, idx, DUK_STRIDX_INT_FINALIZER); + + /* In addition to setting the finalizer property, keep a "have + * finalizer" flag in duk_hobject in sync so that refzero can do + * a very quick finalizer check by walking the prototype chain + * and checking the flag alone. (Note that this means that just + * setting _Finalizer on an object won't affect finalizer checks.) + * + * NOTE: if the argument is a Proxy object, this flag will be set + * on the Proxy, not the target. As a result, the target won't get + * a finalizer flag and the Proxy also won't be finalized as there's + * an explicit Proxy check in finalization now. + */ + if (callable) { + DUK_HOBJECT_SET_HAVE_FINALIZER(h); + } else { + DUK_HOBJECT_CLEAR_HAVE_FINALIZER(h); + } } #else /* DUK_USE_FINALIZER_SUPPORT */ DUK_EXTERNAL void duk_get_finalizer(duk_context *ctx, duk_idx_t idx) { diff -Nru duktape-2.0.0/src-input/duk_api_public.h.in duktape-2.1.1/src-input/duk_api_public.h.in --- duktape-2.0.0/src-input/duk_api_public.h.in 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_api_public.h.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,1092 +0,0 @@ -/* - * BEGIN PUBLIC API - */ - -#if !defined(DUK_API_PUBLIC_H_INCLUDED) -#define DUK_API_PUBLIC_H_INCLUDED - -/* - * Avoid C++ name mangling - */ - -#if defined(__cplusplus) -extern "C" { -#endif - -/* - * Some defines forwarded from feature detection - */ - -#undef DUK_API_VARIADIC_MACROS -#if defined(DUK_USE_VARIADIC_MACROS) -#define DUK_API_VARIADIC_MACROS -#endif - -#define DUK_API_NORETURN(decl) DUK_NORETURN(decl) - -/* - * Public API specific typedefs - * - * Many types are wrapped by Duktape for portability to rare platforms - * where e.g. 'int' is a 16-bit type. See practical typing discussion - * in Duktape web documentation. - */ - -struct duk_thread_state; -struct duk_memory_functions; -struct duk_function_list_entry; -struct duk_number_list_entry; -struct duk_time_components; - -/* duk_context is now defined in duk_config.h because it may also be - * referenced there by prototypes. - */ -typedef struct duk_thread_state duk_thread_state; -typedef struct duk_memory_functions duk_memory_functions; -typedef struct duk_function_list_entry duk_function_list_entry; -typedef struct duk_number_list_entry duk_number_list_entry; -typedef struct duk_time_components duk_time_components; - -typedef duk_ret_t (*duk_c_function)(duk_context *ctx); -typedef void *(*duk_alloc_function) (void *udata, duk_size_t size); -typedef void *(*duk_realloc_function) (void *udata, void *ptr, duk_size_t size); -typedef void (*duk_free_function) (void *udata, void *ptr); -typedef void (*duk_fatal_function) (void *udata, const char *msg); -typedef void (*duk_decode_char_function) (void *udata, duk_codepoint_t codepoint); -typedef duk_codepoint_t (*duk_map_char_function) (void *udata, duk_codepoint_t codepoint); -typedef duk_ret_t (*duk_safe_call_function) (duk_context *ctx, void *udata); -typedef duk_size_t (*duk_debug_read_function) (void *udata, char *buffer, duk_size_t length); -typedef duk_size_t (*duk_debug_write_function) (void *udata, const char *buffer, duk_size_t length); -typedef duk_size_t (*duk_debug_peek_function) (void *udata); -typedef void (*duk_debug_read_flush_function) (void *udata); -typedef void (*duk_debug_write_flush_function) (void *udata); -typedef duk_idx_t (*duk_debug_request_function) (duk_context *ctx, void *udata, duk_idx_t nvalues); -typedef void (*duk_debug_detached_function) (duk_context *ctx, void *udata); - -struct duk_thread_state { - /* XXX: Enough space to hold internal suspend/resume structure. - * This is rather awkward and to be fixed when the internal - * structure is visible for the public API header. - */ - char data[128]; -}; - -struct duk_memory_functions { - duk_alloc_function alloc_func; - duk_realloc_function realloc_func; - duk_free_function free_func; - void *udata; -}; - -struct duk_function_list_entry { - const char *key; - duk_c_function value; - duk_idx_t nargs; -}; - -struct duk_number_list_entry { - const char *key; - duk_double_t value; -}; - -struct duk_time_components { - duk_double_t year; /* year, e.g. 2016, Ecmascript year range */ - duk_double_t month; /* month: 1-12 */ - duk_double_t day; /* day: 1-31 */ - duk_double_t hours; /* hour: 0-59 */ - duk_double_t minutes; /* minute: 0-59 */ - duk_double_t seconds; /* second: 0-59 (in POSIX time no leap second) */ - duk_double_t milliseconds; /* may contain sub-millisecond fractions */ - duk_double_t weekday; /* weekday: 0-6, 0=Sunday, 1=Monday, ..., 6=Saturday */ -}; - -/* - * Constants - */ - -/* Duktape version, (major * 10000) + (minor * 100) + patch. Allows C code - * to #if (DUK_VERSION >= NNN) against Duktape API version. The same value - * is also available to Ecmascript code in Duktape.version. Unofficial - * development snapshots have 99 for patch level (e.g. 0.10.99 would be a - * development version after 0.10.0 but before the next official release). - */ -#define DUK_VERSION 20000L - -/* Git commit, describe, and branch for Duktape build. Useful for - * non-official snapshot builds so that application code can easily log - * which Duktape snapshot was used. Not available in the Ecmascript - * environment. - */ -#define DUK_GIT_COMMIT @GIT_COMMIT_CSTRING@ -#define DUK_GIT_DESCRIBE @GIT_DESCRIBE_CSTRING@ -#define DUK_GIT_BRANCH @GIT_BRANCH_CSTRING@ - -/* Duktape debug protocol version used by this build. */ -#define DUK_DEBUG_PROTOCOL_VERSION 2 - -/* Used to represent invalid index; if caller uses this without checking, - * this index will map to a non-existent stack entry. Also used in some - * API calls as a marker to denote "no value". - */ -#define DUK_INVALID_INDEX DUK_IDX_MIN - -/* Indicates that a native function does not have a fixed number of args, - * and the argument stack should not be capped/extended at all. - */ -#define DUK_VARARGS ((duk_int_t) (-1)) - -/* Number of value stack entries (in addition to actual call arguments) - * guaranteed to be allocated on entry to a Duktape/C function. - */ -#define DUK_API_ENTRY_STACK 64 - -/* Value types, used by e.g. duk_get_type() */ -#define DUK_TYPE_MIN 0 -#define DUK_TYPE_NONE 0 /* no value, e.g. invalid index */ -#define DUK_TYPE_UNDEFINED 1 /* Ecmascript undefined */ -#define DUK_TYPE_NULL 2 /* Ecmascript null */ -#define DUK_TYPE_BOOLEAN 3 /* Ecmascript boolean: 0 or 1 */ -#define DUK_TYPE_NUMBER 4 /* Ecmascript number: double */ -#define DUK_TYPE_STRING 5 /* Ecmascript string: CESU-8 / extended UTF-8 encoded */ -#define DUK_TYPE_OBJECT 6 /* Ecmascript object: includes objects, arrays, functions, threads */ -#define DUK_TYPE_BUFFER 7 /* fixed or dynamic, garbage collected byte buffer */ -#define DUK_TYPE_POINTER 8 /* raw void pointer */ -#define DUK_TYPE_LIGHTFUNC 9 /* lightweight function pointer */ -#define DUK_TYPE_MAX 9 - -/* Value mask types, used by e.g. duk_get_type_mask() */ -#define DUK_TYPE_MASK_NONE (1 << DUK_TYPE_NONE) -#define DUK_TYPE_MASK_UNDEFINED (1 << DUK_TYPE_UNDEFINED) -#define DUK_TYPE_MASK_NULL (1 << DUK_TYPE_NULL) -#define DUK_TYPE_MASK_BOOLEAN (1 << DUK_TYPE_BOOLEAN) -#define DUK_TYPE_MASK_NUMBER (1 << DUK_TYPE_NUMBER) -#define DUK_TYPE_MASK_STRING (1 << DUK_TYPE_STRING) -#define DUK_TYPE_MASK_OBJECT (1 << DUK_TYPE_OBJECT) -#define DUK_TYPE_MASK_BUFFER (1 << DUK_TYPE_BUFFER) -#define DUK_TYPE_MASK_POINTER (1 << DUK_TYPE_POINTER) -#define DUK_TYPE_MASK_LIGHTFUNC (1 << DUK_TYPE_LIGHTFUNC) -#define DUK_TYPE_MASK_THROW (1 << 10) /* internal flag value: throw if mask doesn't match */ -#define DUK_TYPE_MASK_PROMOTE (1 << 11) /* internal flag value: promote to object if mask matches */ - -/* Coercion hints */ -#define DUK_HINT_NONE 0 /* prefer number, unless input is a Date, in which - * case prefer string (E5 Section 8.12.8) - */ -#define DUK_HINT_STRING 1 /* prefer string */ -#define DUK_HINT_NUMBER 2 /* prefer number */ - -/* Enumeration flags for duk_enum() */ -#define DUK_ENUM_INCLUDE_NONENUMERABLE (1 << 0) /* enumerate non-numerable properties in addition to enumerable */ -#define DUK_ENUM_INCLUDE_HIDDEN (1 << 1) /* enumerate hidden symbols too (in Duktape 1.x called internal properties) */ -#define DUK_ENUM_INCLUDE_SYMBOLS (1 << 2) /* enumerate symbols */ -#define DUK_ENUM_EXCLUDE_STRINGS (1 << 3) /* exclude strings */ -#define DUK_ENUM_OWN_PROPERTIES_ONLY (1 << 4) /* don't walk prototype chain, only check own properties */ -#define DUK_ENUM_ARRAY_INDICES_ONLY (1 << 5) /* only enumerate array indices */ -#define DUK_ENUM_SORT_ARRAY_INDICES (1 << 6) /* sort array indices (applied to full enumeration result, including inherited array indices) */ -#define DUK_ENUM_NO_PROXY_BEHAVIOR (1 << 7) /* enumerate a proxy object itself without invoking proxy behavior */ - -/* Compilation flags for duk_compile() and duk_eval() */ -/* DUK_COMPILE_xxx bits 0-2 are reserved for an internal 'nargs' argument. - */ -#define DUK_COMPILE_EVAL (1 << 3) /* compile eval code (instead of global code) */ -#define DUK_COMPILE_FUNCTION (1 << 4) /* compile function code (instead of global code) */ -#define DUK_COMPILE_STRICT (1 << 5) /* use strict (outer) context for global, eval, or function code */ -#define DUK_COMPILE_SAFE (1 << 6) /* (internal) catch compilation errors */ -#define DUK_COMPILE_NORESULT (1 << 7) /* (internal) omit eval result */ -#define DUK_COMPILE_NOSOURCE (1 << 8) /* (internal) no source string on stack */ -#define DUK_COMPILE_STRLEN (1 << 9) /* (internal) take strlen() of src_buffer (avoids double evaluation in macro) */ -#define DUK_COMPILE_NOFILENAME (1 << 10) /* (internal) no filename on stack */ - -/* Flags for duk_def_prop() and its variants */ -#define DUK_DEFPROP_WRITABLE (1 << 0) /* set writable (effective if DUK_DEFPROP_HAVE_WRITABLE set) */ -#define DUK_DEFPROP_ENUMERABLE (1 << 1) /* set enumerable (effective if DUK_DEFPROP_HAVE_ENUMERABLE set) */ -#define DUK_DEFPROP_CONFIGURABLE (1 << 2) /* set configurable (effective if DUK_DEFPROP_HAVE_CONFIGURABLE set) */ -#define DUK_DEFPROP_HAVE_WRITABLE (1 << 3) /* set/clear writable */ -#define DUK_DEFPROP_HAVE_ENUMERABLE (1 << 4) /* set/clear enumerable */ -#define DUK_DEFPROP_HAVE_CONFIGURABLE (1 << 5) /* set/clear configurable */ -#define DUK_DEFPROP_HAVE_VALUE (1 << 6) /* set value (given on value stack) */ -#define DUK_DEFPROP_HAVE_GETTER (1 << 7) /* set getter (given on value stack) */ -#define DUK_DEFPROP_HAVE_SETTER (1 << 8) /* set setter (given on value stack) */ -#define DUK_DEFPROP_FORCE (1 << 9) /* force change if possible, may still fail for e.g. virtual properties */ -#define DUK_DEFPROP_SET_WRITABLE (DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE) -#define DUK_DEFPROP_CLEAR_WRITABLE DUK_DEFPROP_HAVE_WRITABLE -#define DUK_DEFPROP_SET_ENUMERABLE (DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE) -#define DUK_DEFPROP_CLEAR_ENUMERABLE DUK_DEFPROP_HAVE_ENUMERABLE -#define DUK_DEFPROP_SET_CONFIGURABLE (DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE) -#define DUK_DEFPROP_CLEAR_CONFIGURABLE DUK_DEFPROP_HAVE_CONFIGURABLE - -/* Flags for duk_push_thread_raw() */ -#define DUK_THREAD_NEW_GLOBAL_ENV (1 << 0) /* create a new global environment */ - -/* Flags for duk_gc() */ -#define DUK_GC_COMPACT (1 << 0) /* compact heap objects */ - -/* Error codes (must be 8 bits at most, see duk_error.h) */ -#define DUK_ERR_NONE 0 /* no error (e.g. from duk_get_error_code()) */ -#define DUK_ERR_ERROR 1 /* Error */ -#define DUK_ERR_EVAL_ERROR 2 /* EvalError */ -#define DUK_ERR_RANGE_ERROR 3 /* RangeError */ -#define DUK_ERR_REFERENCE_ERROR 4 /* ReferenceError */ -#define DUK_ERR_SYNTAX_ERROR 5 /* SyntaxError */ -#define DUK_ERR_TYPE_ERROR 6 /* TypeError */ -#define DUK_ERR_URI_ERROR 7 /* URIError */ - -/* Return codes for C functions (shortcut for throwing an error) */ -#define DUK_RET_ERROR (-DUK_ERR_ERROR) -#define DUK_RET_EVAL_ERROR (-DUK_ERR_EVAL_ERROR) -#define DUK_RET_RANGE_ERROR (-DUK_ERR_RANGE_ERROR) -#define DUK_RET_REFERENCE_ERROR (-DUK_ERR_REFERENCE_ERROR) -#define DUK_RET_SYNTAX_ERROR (-DUK_ERR_SYNTAX_ERROR) -#define DUK_RET_TYPE_ERROR (-DUK_ERR_TYPE_ERROR) -#define DUK_RET_URI_ERROR (-DUK_ERR_URI_ERROR) - -/* Return codes for protected calls (duk_safe_call(), duk_pcall()) */ -#define DUK_EXEC_SUCCESS 0 -#define DUK_EXEC_ERROR 1 - -/* Debug levels for DUK_USE_DEBUG_WRITE(). */ -#define DUK_LEVEL_DEBUG 0 -#define DUK_LEVEL_DDEBUG 1 -#define DUK_LEVEL_DDDEBUG 2 - -/* - * If no variadic macros, __FILE__ and __LINE__ are passed through globals - * which is ugly and not thread safe. - */ - -#if !defined(DUK_API_VARIADIC_MACROS) -DUK_EXTERNAL_DECL const char *duk_api_global_filename; -DUK_EXTERNAL_DECL duk_int_t duk_api_global_line; -#endif - -/* - * Context management - */ - -DUK_EXTERNAL_DECL -duk_context *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_EXTERNAL_DECL void duk_destroy_heap(duk_context *ctx); - -DUK_EXTERNAL_DECL void duk_suspend(duk_context *ctx, duk_thread_state *state); -DUK_EXTERNAL_DECL void duk_resume(duk_context *ctx, const duk_thread_state *state); - -#define duk_create_heap_default() \ - duk_create_heap(NULL, NULL, NULL, NULL, NULL) - -/* - * Memory management - * - * Raw functions have no side effects (cannot trigger GC). - */ - -DUK_EXTERNAL_DECL void *duk_alloc_raw(duk_context *ctx, duk_size_t size); -DUK_EXTERNAL_DECL void duk_free_raw(duk_context *ctx, void *ptr); -DUK_EXTERNAL_DECL void *duk_realloc_raw(duk_context *ctx, void *ptr, duk_size_t size); -DUK_EXTERNAL_DECL void *duk_alloc(duk_context *ctx, duk_size_t size); -DUK_EXTERNAL_DECL void duk_free(duk_context *ctx, void *ptr); -DUK_EXTERNAL_DECL void *duk_realloc(duk_context *ctx, void *ptr, duk_size_t size); -DUK_EXTERNAL_DECL void duk_get_memory_functions(duk_context *ctx, duk_memory_functions *out_funcs); -DUK_EXTERNAL_DECL void duk_gc(duk_context *ctx, duk_uint_t flags); - -/* - * Error handling - */ - -DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_throw_raw(duk_context *ctx)); -#define duk_throw(ctx) \ - (duk_throw_raw((ctx)), (duk_ret_t) 0) -DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_fatal_raw(duk_context *ctx, const char *err_msg)); -#define duk_fatal(ctx,err_msg) \ - (duk_fatal_raw((ctx), (err_msg)), (duk_ret_t) 0) - -#if defined(DUK_API_VARIADIC_MACROS) -DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...)); -#define duk_error(ctx,err_code,...) \ - (duk_error_raw((ctx), (duk_errcode_t) (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) -#define duk_generic_error(ctx,...) \ - (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) -#define duk_eval_error(ctx,...) \ - (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_EVAL_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) -#define duk_range_error(ctx,...) \ - (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_RANGE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) -#define duk_reference_error(ctx,...) \ - (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_REFERENCE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) -#define duk_syntax_error(ctx,...) \ - (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_SYNTAX_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) -#define duk_type_error(ctx,...) \ - (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_TYPE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) -#define duk_uri_error(ctx,...) \ - (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_URI_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) -#else /* DUK_API_VARIADIC_MACROS */ -/* For legacy compilers without variadic macros a macro hack is used to allow - * variable arguments. While the macro allows "return duk_error(...)", it - * will fail with e.g. "(void) duk_error(...)". The calls are noreturn but - * with a return value to allow the "return duk_error(...)" idiom. This may - * cause some compiler warnings, but without noreturn the generated code is - * often worse. The same approach as with variadic macros (using - * "(duk_error(...), 0)") won't work due to the macro hack structure. - */ -DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_error_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...)); -DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_generic_error_stash(duk_context *ctx, const char *fmt, ...)); -DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_eval_error_stash(duk_context *ctx, const char *fmt, ...)); -DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_range_error_stash(duk_context *ctx, const char *fmt, ...)); -DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_reference_error_stash(duk_context *ctx, const char *fmt, ...)); -DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_syntax_error_stash(duk_context *ctx, const char *fmt, ...)); -DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_type_error_stash(duk_context *ctx, const char *fmt, ...)); -DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_uri_error_stash(duk_context *ctx, const char *fmt, ...)); -#define duk_error \ - (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ - duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ - duk_error_stash) /* last value is func pointer, arguments follow in parens */ -#define duk_generic_error \ - (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ - duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ - duk_generic_error_stash) -#define duk_eval_error \ - (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ - duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ - duk_eval_error_stash) -#define duk_range_error \ - (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ - duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ - duk_range_error_stash) -#define duk_reference_error \ - (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ - duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ - duk_reference_error_stash) -#define duk_syntax_error \ - (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ - duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ - duk_syntax_error_stash) -#define duk_type_error \ - (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ - duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ - duk_type_error_stash) -#define duk_uri_error \ - (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ - duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ - duk_uri_error_stash) -#endif /* DUK_API_VARIADIC_MACROS */ - -DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap)); -#define duk_error_va(ctx,err_code,fmt,ap) \ - (duk_error_va_raw((ctx), (duk_errcode_t) (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) -#define duk_generic_error_va(ctx,fmt,ap) \ - (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) -#define duk_eval_error_va(ctx,fmt,ap) \ - (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_EVAL_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) -#define duk_range_error_va(ctx,fmt,ap) \ - (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_RANGE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) -#define duk_reference_error_va(ctx,fmt,ap) \ - (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_REFERENCE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) -#define duk_syntax_error_va(ctx,fmt,ap) \ - (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_SYNTAX_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) -#define duk_type_error_va(ctx,fmt,ap) \ - (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_TYPE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) -#define duk_uri_error_va(ctx,fmt,ap) \ - (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_URI_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) - -/* - * Other state related functions - */ - -DUK_EXTERNAL_DECL duk_bool_t duk_is_strict_call(duk_context *ctx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_constructor_call(duk_context *ctx); - -/* - * Stack management - */ - -DUK_EXTERNAL_DECL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_idx_t duk_require_normalize_index(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_valid_index(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_require_valid_index(duk_context *ctx, duk_idx_t idx); - -DUK_EXTERNAL_DECL duk_idx_t duk_get_top(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_set_top(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_idx_t duk_get_top_index(duk_context *ctx); -DUK_EXTERNAL_DECL duk_idx_t duk_require_top_index(duk_context *ctx); - -/* Although extra/top could be an unsigned type here, using a signed type - * makes the API more robust to calling code calculation errors or corner - * cases (where caller might occasionally come up with negative values). - * Negative values are treated as zero, which is better than casting them - * to a large unsigned number. (This principle is used elsewhere in the - * API too.) - */ -DUK_EXTERNAL_DECL duk_bool_t duk_check_stack(duk_context *ctx, duk_idx_t extra); -DUK_EXTERNAL_DECL void duk_require_stack(duk_context *ctx, duk_idx_t extra); -DUK_EXTERNAL_DECL duk_bool_t duk_check_stack_top(duk_context *ctx, duk_idx_t top); -DUK_EXTERNAL_DECL void duk_require_stack_top(duk_context *ctx, duk_idx_t top); - -/* - * Stack manipulation (other than push/pop) - */ - -DUK_EXTERNAL_DECL void duk_swap(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2); -DUK_EXTERNAL_DECL void duk_swap_top(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_dup(duk_context *ctx, duk_idx_t from_idx); -DUK_EXTERNAL_DECL void duk_dup_top(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_insert(duk_context *ctx, duk_idx_t to_idx); -DUK_EXTERNAL_DECL void duk_replace(duk_context *ctx, duk_idx_t to_idx); -DUK_EXTERNAL_DECL void duk_copy(duk_context *ctx, duk_idx_t from_idx, duk_idx_t to_idx); -DUK_EXTERNAL_DECL void duk_remove(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx, duk_idx_t count, duk_bool_t is_copy); - -#define duk_xmove_top(to_ctx,from_ctx,count) \ - duk_xcopymove_raw((to_ctx), (from_ctx), (count), 0 /*is_copy*/) -#define duk_xcopy_top(to_ctx,from_ctx,count) \ - duk_xcopymove_raw((to_ctx), (from_ctx), (count), 1 /*is_copy*/) - -/* - * Push operations - * - * Push functions return the absolute (relative to bottom of frame) - * position of the pushed value for convenience. - * - * Note: duk_dup() is technically a push. - */ - -DUK_EXTERNAL_DECL void duk_push_undefined(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_push_null(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_push_boolean(duk_context *ctx, duk_bool_t val); -DUK_EXTERNAL_DECL void duk_push_true(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_push_false(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_push_number(duk_context *ctx, duk_double_t val); -DUK_EXTERNAL_DECL void duk_push_nan(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_push_int(duk_context *ctx, duk_int_t val); -DUK_EXTERNAL_DECL void duk_push_uint(duk_context *ctx, duk_uint_t val); -DUK_EXTERNAL_DECL const char *duk_push_string(duk_context *ctx, const char *str); -DUK_EXTERNAL_DECL const char *duk_push_lstring(duk_context *ctx, const char *str, duk_size_t len); -DUK_EXTERNAL_DECL void duk_push_pointer(duk_context *ctx, void *p); -DUK_EXTERNAL_DECL const char *duk_push_sprintf(duk_context *ctx, const char *fmt, ...); -DUK_EXTERNAL_DECL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va_list ap); - -DUK_EXTERNAL_DECL void duk_push_this(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_push_current_function(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_push_current_thread(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_push_global_object(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_push_heap_stash(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_push_global_stash(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_push_thread_stash(duk_context *ctx, duk_context *target_ctx); - -DUK_EXTERNAL_DECL duk_idx_t duk_push_object(duk_context *ctx); -DUK_EXTERNAL_DECL duk_idx_t duk_push_bare_object(duk_context *ctx); -DUK_EXTERNAL_DECL duk_idx_t duk_push_array(duk_context *ctx); -DUK_EXTERNAL_DECL duk_idx_t duk_push_c_function(duk_context *ctx, duk_c_function func, duk_idx_t nargs); -DUK_EXTERNAL_DECL duk_idx_t duk_push_c_lightfunc(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_idx_t length, duk_int_t magic); -DUK_EXTERNAL_DECL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags); - -#define duk_push_thread(ctx) \ - duk_push_thread_raw((ctx), 0 /*flags*/) - -#define duk_push_thread_new_globalenv(ctx) \ - duk_push_thread_raw((ctx), DUK_THREAD_NEW_GLOBAL_ENV /*flags*/) - -DUK_EXTERNAL_DECL duk_idx_t duk_push_error_object_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...); - -#if defined(DUK_API_VARIADIC_MACROS) -#define duk_push_error_object(ctx,err_code,...) \ - duk_push_error_object_raw((ctx), (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__) -#else -DUK_EXTERNAL_DECL duk_idx_t duk_push_error_object_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...); -/* Note: parentheses are required so that the comma expression works in assignments. */ -#define duk_push_error_object \ - (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ - duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ - duk_push_error_object_stash) /* last value is func pointer, arguments follow in parens */ -#endif - -DUK_EXTERNAL_DECL duk_idx_t duk_push_error_object_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap); -#define duk_push_error_object_va(ctx,err_code,fmt,ap) \ - duk_push_error_object_va_raw((ctx), (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)) - -#define DUK_BUF_FLAG_DYNAMIC (1 << 0) /* internal flag: dynamic buffer */ -#define DUK_BUF_FLAG_EXTERNAL (1 << 1) /* internal flag: external buffer */ -#define DUK_BUF_FLAG_NOZERO (1 << 2) /* internal flag: don't zero allocated buffer */ - -DUK_EXTERNAL_DECL void *duk_push_buffer_raw(duk_context *ctx, duk_size_t size, duk_small_uint_t flags); - -#define duk_push_buffer(ctx,size,dynamic) \ - duk_push_buffer_raw((ctx), (size), (dynamic) ? DUK_BUF_FLAG_DYNAMIC : 0) -#define duk_push_fixed_buffer(ctx,size) \ - duk_push_buffer_raw((ctx), (size), 0 /*flags*/) -#define duk_push_dynamic_buffer(ctx,size) \ - duk_push_buffer_raw((ctx), (size), DUK_BUF_FLAG_DYNAMIC /*flags*/) -#define duk_push_external_buffer(ctx) \ - ((void) duk_push_buffer_raw((ctx), 0, DUK_BUF_FLAG_DYNAMIC | DUK_BUF_FLAG_EXTERNAL)) - -#define DUK_BUFOBJ_CREATE_ARRBUF (1 << 4) /* internal flag: create backing ArrayBuffer; keep in one byte */ -#define DUK_BUFOBJ_ARRAYBUFFER 0 -#define DUK_BUFOBJ_NODEJS_BUFFER (1 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_DATAVIEW (2 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_INT8ARRAY (3 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_UINT8ARRAY (4 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_UINT8CLAMPEDARRAY (5 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_INT16ARRAY (6 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_UINT16ARRAY (7 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_INT32ARRAY (8 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_UINT32ARRAY (9 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_FLOAT32ARRAY (10 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_FLOAT64ARRAY (11 | DUK_BUFOBJ_CREATE_ARRBUF) - -DUK_EXTERNAL_DECL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags); - -DUK_EXTERNAL_DECL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr); - -/* - * Pop operations - */ - -DUK_EXTERNAL_DECL void duk_pop(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_pop_n(duk_context *ctx, duk_idx_t count); -DUK_EXTERNAL_DECL void duk_pop_2(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_pop_3(duk_context *ctx); - -/* - * Type checks - * - * duk_is_none(), which would indicate whether index it outside of stack, - * is not needed; duk_is_valid_index() gives the same information. - */ - -DUK_EXTERNAL_DECL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_check_type(duk_context *ctx, duk_idx_t idx, duk_int_t type); -DUK_EXTERNAL_DECL duk_uint_t duk_get_type_mask(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_check_type_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t mask); - -DUK_EXTERNAL_DECL duk_bool_t duk_is_undefined(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_null(duk_context *ctx, duk_idx_t idx); -#define duk_is_null_or_undefined(ctx, idx) \ - ((duk_get_type_mask((ctx), (idx)) & (DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_UNDEFINED)) ? 1 : 0) - -DUK_EXTERNAL_DECL duk_bool_t duk_is_boolean(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_number(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_nan(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_string(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_object(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_buffer(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_buffer_data(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_pointer(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_lightfunc(duk_context *ctx, duk_idx_t idx); - -DUK_EXTERNAL_DECL duk_bool_t duk_is_symbol(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_array(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_function(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_c_function(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_ecmascript_function(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_bound_function(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t idx); - -#define duk_is_callable(ctx,idx) \ - duk_is_function((ctx), (idx)) -DUK_EXTERNAL_DECL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t idx); - -/* Buffers and lightfuncs are not considered primitive because they mimic - * objects and e.g. duk_to_primitive() will coerce them instead of returning - * them as is. Symbols are represented as strings internally. - */ -#define duk_is_primitive(ctx,idx) \ - duk_check_type_mask((ctx), (idx), DUK_TYPE_MASK_UNDEFINED | \ - DUK_TYPE_MASK_NULL | \ - DUK_TYPE_MASK_BOOLEAN | \ - DUK_TYPE_MASK_NUMBER | \ - DUK_TYPE_MASK_STRING | \ - DUK_TYPE_MASK_POINTER) - -/* Symbols are object coercible, covered by DUK_TYPE_MASK_STRING. */ -#define duk_is_object_coercible(ctx,idx) \ - duk_check_type_mask((ctx), (idx), DUK_TYPE_MASK_BOOLEAN | \ - DUK_TYPE_MASK_NUMBER | \ - DUK_TYPE_MASK_STRING | \ - DUK_TYPE_MASK_OBJECT | \ - DUK_TYPE_MASK_BUFFER | \ - DUK_TYPE_MASK_POINTER | \ - DUK_TYPE_MASK_LIGHTFUNC) - -DUK_EXTERNAL_DECL duk_errcode_t duk_get_error_code(duk_context *ctx, duk_idx_t idx); -#define duk_is_error(ctx,idx) \ - (duk_get_error_code((ctx), (idx)) != 0) -#define duk_is_eval_error(ctx,idx) \ - (duk_get_error_code((ctx), (idx)) == DUK_ERR_EVAL_ERROR) -#define duk_is_range_error(ctx,idx) \ - (duk_get_error_code((ctx), (idx)) == DUK_ERR_RANGE_ERROR) -#define duk_is_reference_error(ctx,idx) \ - (duk_get_error_code((ctx), (idx)) == DUK_ERR_REFERENCE_ERROR) -#define duk_is_syntax_error(ctx,idx) \ - (duk_get_error_code((ctx), (idx)) == DUK_ERR_SYNTAX_ERROR) -#define duk_is_type_error(ctx,idx) \ - (duk_get_error_code((ctx), (idx)) == DUK_ERR_TYPE_ERROR) -#define duk_is_uri_error(ctx,idx) \ - (duk_get_error_code((ctx), (idx)) == DUK_ERR_URI_ERROR) - -/* - * Get operations: no coercion, returns default value for invalid - * indices and invalid value types. - * - * duk_get_undefined() and duk_get_null() would be pointless and - * are not included. - */ - -DUK_EXTERNAL_DECL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL const char *duk_get_string(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL const char *duk_get_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len); -DUK_EXTERNAL_DECL void *duk_get_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size); -DUK_EXTERNAL_DECL void *duk_get_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size); -DUK_EXTERNAL_DECL void *duk_get_pointer(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_context *duk_get_context(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void *duk_get_heapptr(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t idx, duk_size_t len); - -/* - * Require operations: no coercion, throw error if index or type - * is incorrect. No defaulting. - */ - -#define duk_require_type_mask(ctx,idx,mask) \ - ((void) duk_check_type_mask((ctx), (idx), (mask) | DUK_TYPE_MASK_THROW)) - -DUK_EXTERNAL_DECL void duk_require_undefined(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_require_null(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL const char *duk_require_string(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL const char *duk_require_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len); -DUK_EXTERNAL_DECL void *duk_require_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size); -DUK_EXTERNAL_DECL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size); -DUK_EXTERNAL_DECL void *duk_require_pointer(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_context *duk_require_context(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_require_function(duk_context *ctx, duk_idx_t idx); -#define duk_require_callable(ctx,idx) \ - duk_require_function((ctx), (idx)) -DUK_EXTERNAL_DECL void *duk_require_heapptr(duk_context *ctx, duk_idx_t idx); - -/* Symbols are object coercible and covered by DUK_TYPE_MASK_STRING. */ -#define duk_require_object_coercible(ctx,idx) \ - ((void) duk_check_type_mask((ctx), (idx), DUK_TYPE_MASK_BOOLEAN | \ - DUK_TYPE_MASK_NUMBER | \ - DUK_TYPE_MASK_STRING | \ - DUK_TYPE_MASK_OBJECT | \ - DUK_TYPE_MASK_BUFFER | \ - DUK_TYPE_MASK_POINTER | \ - DUK_TYPE_MASK_LIGHTFUNC | \ - DUK_TYPE_MASK_THROW)) - -/* - * Coercion operations: in-place coercion, return coerced value where - * applicable. If index is invalid, throw error. Some coercions may - * throw an expected error (e.g. from a toString() or valueOf() call) - * or an internal error (e.g. from out of memory). - */ - -DUK_EXTERNAL_DECL void duk_to_undefined(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_to_null(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_bool_t duk_to_boolean(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_double_t duk_to_number(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_uint32_t duk_to_uint32(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_uint16_t duk_to_uint16(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL const char *duk_to_string(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL const char *duk_to_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len); -DUK_EXTERNAL_DECL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_uint_t flags); -DUK_EXTERNAL_DECL void *duk_to_pointer(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_to_object(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_to_primitive(duk_context *ctx, duk_idx_t idx, duk_int_t hint); - -#define DUK_BUF_MODE_FIXED 0 /* internal: request fixed buffer result */ -#define DUK_BUF_MODE_DYNAMIC 1 /* internal: request dynamic buffer result */ -#define DUK_BUF_MODE_DONTCARE 2 /* internal: don't care about fixed/dynamic nature */ - -#define duk_to_buffer(ctx,idx,out_size) \ - duk_to_buffer_raw((ctx), (idx), (out_size), DUK_BUF_MODE_DONTCARE) -#define duk_to_fixed_buffer(ctx,idx,out_size) \ - duk_to_buffer_raw((ctx), (idx), (out_size), DUK_BUF_MODE_FIXED) -#define duk_to_dynamic_buffer(ctx,idx,out_size) \ - duk_to_buffer_raw((ctx), (idx), (out_size), DUK_BUF_MODE_DYNAMIC) - -/* safe variants of a few coercion operations */ -DUK_EXTERNAL_DECL const char *duk_safe_to_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len); -#define duk_safe_to_string(ctx,idx) \ - duk_safe_to_lstring((ctx), (idx), NULL) - -/* - * Misc conversion - */ - -DUK_EXTERNAL_DECL const char *duk_base64_encode(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_base64_decode(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL const char *duk_hex_encode(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_hex_decode(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL const char *duk_json_encode(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_json_decode(duk_context *ctx, duk_idx_t idx); - -DUK_EXTERNAL_DECL const char *duk_buffer_to_string(duk_context *ctx, duk_idx_t idx); - -/* - * Buffer - */ - -DUK_EXTERNAL_DECL void *duk_resize_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t new_size); -DUK_EXTERNAL_DECL void *duk_steal_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size); -DUK_EXTERNAL_DECL void duk_config_buffer(duk_context *ctx, duk_idx_t idx, void *ptr, duk_size_t len); - -/* - * Property access - * - * The basic function assumes key is on stack. The _string variant takes - * a C string as a property name, while the _index variant takes an array - * index as a property name (e.g. 123 is equivalent to the key "123"). - */ - -DUK_EXTERNAL_DECL duk_bool_t duk_get_prop(duk_context *ctx, duk_idx_t obj_idx); -DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key); -DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len); -DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx); -DUK_EXTERNAL_DECL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_idx); -DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key); -DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len); -DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx); -DUK_EXTERNAL_DECL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_idx); -DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key); -DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len); -DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx); -DUK_EXTERNAL_DECL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_idx); -DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key); -DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len); -DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx); - -DUK_EXTERNAL_DECL void duk_get_prop_desc(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t flags); -DUK_EXTERNAL_DECL void duk_def_prop(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t flags); - -DUK_EXTERNAL_DECL duk_bool_t duk_get_global_string(duk_context *ctx, const char *key); -DUK_EXTERNAL_DECL duk_bool_t duk_get_global_lstring(duk_context *ctx, const char *key, duk_size_t key_len); -DUK_EXTERNAL_DECL duk_bool_t duk_put_global_string(duk_context *ctx, const char *key); -DUK_EXTERNAL_DECL duk_bool_t duk_put_global_lstring(duk_context *ctx, const char *key, duk_size_t key_len); - -/* - * Inspection - */ - -DUK_EXTERNAL_DECL void duk_inspect_value(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_inspect_callstack_entry(duk_context *ctx, duk_int_t level); - -/* - * Object prototype - */ - -DUK_EXTERNAL_DECL void duk_get_prototype(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_set_prototype(duk_context *ctx, duk_idx_t idx); - -/* - * Object finalizer - */ - -DUK_EXTERNAL_DECL void duk_get_finalizer(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_set_finalizer(duk_context *ctx, duk_idx_t idx); - -/* - * Global object - */ - -DUK_EXTERNAL_DECL void duk_set_global_object(duk_context *ctx); - -/* - * Duktape/C function magic value - */ - -DUK_EXTERNAL_DECL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_set_magic(duk_context *ctx, duk_idx_t idx, duk_int_t magic); -DUK_EXTERNAL_DECL duk_int_t duk_get_current_magic(duk_context *ctx); - -/* - * Module helpers: put multiple function or constant properties - */ - -DUK_EXTERNAL_DECL void duk_put_function_list(duk_context *ctx, duk_idx_t obj_idx, const duk_function_list_entry *funcs); -DUK_EXTERNAL_DECL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_idx, const duk_number_list_entry *numbers); - -/* - * Object operations - */ - -DUK_EXTERNAL_DECL void duk_compact(duk_context *ctx, duk_idx_t obj_idx); -DUK_EXTERNAL_DECL void duk_enum(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t enum_flags); -DUK_EXTERNAL_DECL duk_bool_t duk_next(duk_context *ctx, duk_idx_t enum_idx, duk_bool_t get_value); - -/* - * String manipulation - */ - -DUK_EXTERNAL_DECL void duk_concat(duk_context *ctx, duk_idx_t count); -DUK_EXTERNAL_DECL void duk_join(duk_context *ctx, duk_idx_t count); -DUK_EXTERNAL_DECL void duk_decode_string(duk_context *ctx, duk_idx_t idx, duk_decode_char_function callback, void *udata); -DUK_EXTERNAL_DECL void duk_map_string(duk_context *ctx, duk_idx_t idx, duk_map_char_function callback, void *udata); -DUK_EXTERNAL_DECL void duk_substring(duk_context *ctx, duk_idx_t idx, duk_size_t start_char_offset, duk_size_t end_char_offset); -DUK_EXTERNAL_DECL void duk_trim(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_codepoint_t duk_char_code_at(duk_context *ctx, duk_idx_t idx, duk_size_t char_offset); - -/* - * Ecmascript operators - */ - -DUK_EXTERNAL_DECL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2); -DUK_EXTERNAL_DECL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2); -DUK_EXTERNAL_DECL duk_bool_t duk_samevalue(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2); -DUK_EXTERNAL_DECL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2); - -/* - * Function (method) calls - */ - -DUK_EXTERNAL_DECL void duk_call(duk_context *ctx, duk_idx_t nargs); -DUK_EXTERNAL_DECL void duk_call_method(duk_context *ctx, duk_idx_t nargs); -DUK_EXTERNAL_DECL void duk_call_prop(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t nargs); -DUK_EXTERNAL_DECL duk_int_t duk_pcall(duk_context *ctx, duk_idx_t nargs); -DUK_EXTERNAL_DECL duk_int_t duk_pcall_method(duk_context *ctx, duk_idx_t nargs); -DUK_EXTERNAL_DECL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t nargs); -DUK_EXTERNAL_DECL void duk_new(duk_context *ctx, duk_idx_t nargs); -DUK_EXTERNAL_DECL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs); -DUK_EXTERNAL_DECL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, void *udata, duk_idx_t nargs, duk_idx_t nrets); - -/* - * Thread management - */ - -/* There are currently no native functions to yield/resume, due to the internal - * limitations on coroutine handling. These will be added later. - */ - -/* - * Compilation and evaluation - */ - -DUK_EXTERNAL_DECL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags); -DUK_EXTERNAL_DECL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags); - -/* plain */ -#define duk_eval(ctx) \ - ((void) duk_eval_raw((ctx), NULL, 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOFILENAME)) - -#define duk_eval_noresult(ctx) \ - ((void) duk_eval_raw((ctx), NULL, 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME)) - -#define duk_peval(ctx) \ - (duk_eval_raw((ctx), NULL, 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOFILENAME)) - -#define duk_peval_noresult(ctx) \ - (duk_eval_raw((ctx), NULL, 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME)) - -#define duk_compile(ctx,flags) \ - ((void) duk_compile_raw((ctx), NULL, 0, 2 /*args*/ | (flags))) - -#define duk_pcompile(ctx,flags) \ - (duk_compile_raw((ctx), NULL, 0, 2 /*args*/ | (flags) | DUK_COMPILE_SAFE)) - -/* string */ -#define duk_eval_string(ctx,src) \ - ((void) duk_eval_raw((ctx), (src), 0, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME)) - -#define duk_eval_string_noresult(ctx,src) \ - ((void) duk_eval_raw((ctx), (src), 0, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME)) - -#define duk_peval_string(ctx,src) \ - (duk_eval_raw((ctx), (src), 0, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME)) - -#define duk_peval_string_noresult(ctx,src) \ - (duk_eval_raw((ctx), (src), 0, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME)) - -#define duk_compile_string(ctx,flags,src) \ - ((void) duk_compile_raw((ctx), (src), 0, 0 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME)) - -#define duk_compile_string_filename(ctx,flags,src) \ - ((void) duk_compile_raw((ctx), (src), 0, 1 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN)) - -#define duk_pcompile_string(ctx,flags,src) \ - (duk_compile_raw((ctx), (src), 0, 0 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME)) - -#define duk_pcompile_string_filename(ctx,flags,src) \ - (duk_compile_raw((ctx), (src), 0, 1 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN)) - -/* lstring */ -#define duk_eval_lstring(ctx,buf,len) \ - ((void) duk_eval_raw((ctx), buf, len, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NOFILENAME)) - -#define duk_eval_lstring_noresult(ctx,buf,len) \ - ((void) duk_eval_raw((ctx), buf, len, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME)) - -#define duk_peval_lstring(ctx,buf,len) \ - (duk_eval_raw((ctx), buf, len, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_SAFE | DUK_COMPILE_NOFILENAME)) - -#define duk_peval_lstring_noresult(ctx,buf,len) \ - (duk_eval_raw((ctx), buf, len, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME)) - -#define duk_compile_lstring(ctx,flags,buf,len) \ - ((void) duk_compile_raw((ctx), buf, len, 0 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NOFILENAME)) - -#define duk_compile_lstring_filename(ctx,flags,buf,len) \ - ((void) duk_compile_raw((ctx), buf, len, 1 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE)) - -#define duk_pcompile_lstring(ctx,flags,buf,len) \ - (duk_compile_raw((ctx), buf, len, 0 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NOFILENAME)) - -#define duk_pcompile_lstring_filename(ctx,flags,buf,len) \ - (duk_compile_raw((ctx), buf, len, 1 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE)) - -/* - * Bytecode load/dump - */ - -DUK_EXTERNAL_DECL void duk_dump_function(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_load_function(duk_context *ctx); - -/* - * Debugging - */ - -DUK_EXTERNAL_DECL void duk_push_context_dump(duk_context *ctx); - -/* - * Debugger (debug protocol) - */ - -DUK_EXTERNAL_DECL void duk_debugger_attach(duk_context *ctx, - 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_EXTERNAL_DECL void duk_debugger_detach(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_debugger_cooperate(duk_context *ctx); -DUK_EXTERNAL_DECL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues); -DUK_EXTERNAL_DECL void duk_debugger_pause(duk_context *ctx); - -/* - * Time handling - */ - -DUK_EXTERNAL_DECL duk_double_t duk_get_now(duk_context *ctx); -DUK_EXTERNAL_DECL void duk_time_to_components(duk_context *ctx, duk_double_t timeval, duk_time_components *comp); -DUK_EXTERNAL_DECL duk_double_t duk_components_to_time(duk_context *ctx, duk_time_components *comp); - -/* - * Date provider related constants - * - * NOTE: These are "semi public" - you should only use these if you write - * your own platform specific Date provider, see doc/datetime.rst. - */ - -/* Millisecond count constants. */ -#define DUK_DATE_MSEC_SECOND 1000L -#define DUK_DATE_MSEC_MINUTE (60L * 1000L) -#define DUK_DATE_MSEC_HOUR (60L * 60L * 1000L) -#define DUK_DATE_MSEC_DAY (24L * 60L * 60L * 1000L) - -/* Ecmascript date range is 100 million days from Epoch: - * > 100e6 * 24 * 60 * 60 * 1000 // 100M days in millisecs - * 8640000000000000 - * (= 8.64e15) - */ -#define DUK_DATE_MSEC_100M_DAYS (8.64e15) -#define DUK_DATE_MSEC_100M_DAYS_LEEWAY (8.64e15 + 24 * 3600e3) - -/* Ecmascript year range: - * > new Date(100e6 * 24 * 3600e3).toISOString() - * '+275760-09-13T00:00:00.000Z' - * > new Date(-100e6 * 24 * 3600e3).toISOString() - * '-271821-04-20T00:00:00.000Z' - */ -#define DUK_DATE_MIN_ECMA_YEAR (-271821L) -#define DUK_DATE_MAX_ECMA_YEAR 275760L - -/* Part indices for internal breakdowns. Part order from DUK_DATE_IDX_YEAR - * to DUK_DATE_IDX_MILLISECOND matches argument ordering of Ecmascript API - * calls (like Date constructor call). Some functions in duk_bi_date.c - * depend on the specific ordering, so change with care. 16 bits are not - * enough for all parts (year, specifically). - * - * Must be in-sync with genbuiltins.py. - */ -#define DUK_DATE_IDX_YEAR 0 /* year */ -#define DUK_DATE_IDX_MONTH 1 /* month: 0 to 11 */ -#define DUK_DATE_IDX_DAY 2 /* day within month: 0 to 30 */ -#define DUK_DATE_IDX_HOUR 3 -#define DUK_DATE_IDX_MINUTE 4 -#define DUK_DATE_IDX_SECOND 5 -#define DUK_DATE_IDX_MILLISECOND 6 -#define DUK_DATE_IDX_WEEKDAY 7 /* weekday: 0 to 6, 0=sunday, 1=monday, etc */ -#define DUK_DATE_IDX_NUM_PARTS 8 - -/* Internal API call flags, used for various functions in duk_bi_date.c. - * Certain flags are used by only certain functions, but since the flags - * don't overlap, a single flags value can be passed around to multiple - * functions. - * - * The unused top bits of the flags field are also used to pass values - * to helpers (duk__get_part_helper() and duk__set_part_helper()). - * - * Must be in-sync with genbuiltins.py. - */ - -/* NOTE: when writing a Date provider you only need a few specific - * flags from here, the rest are internal. Avoid using anything you - * don't need. - */ - -#define DUK_DATE_FLAG_NAN_TO_ZERO (1 << 0) /* timeval breakdown: internal time value NaN -> zero */ -#define DUK_DATE_FLAG_NAN_TO_RANGE_ERROR (1 << 1) /* timeval breakdown: internal time value NaN -> RangeError (toISOString) */ -#define DUK_DATE_FLAG_ONEBASED (1 << 2) /* timeval breakdown: convert month and day-of-month parts to one-based (default is zero-based) */ -#define DUK_DATE_FLAG_EQUIVYEAR (1 << 3) /* timeval breakdown: replace year with equivalent year in the [1971,2037] range for DST calculations */ -#define DUK_DATE_FLAG_LOCALTIME (1 << 4) /* convert time value to local time */ -#define DUK_DATE_FLAG_SUB1900 (1 << 5) /* getter: subtract 1900 from year when getting year part */ -#define DUK_DATE_FLAG_TOSTRING_DATE (1 << 6) /* include date part in string conversion result */ -#define DUK_DATE_FLAG_TOSTRING_TIME (1 << 7) /* include time part in string conversion result */ -#define DUK_DATE_FLAG_TOSTRING_LOCALE (1 << 8) /* use locale specific formatting if available */ -#define DUK_DATE_FLAG_TIMESETTER (1 << 9) /* setter: call is a time setter (affects hour, min, sec, ms); otherwise date setter (affects year, month, day-in-month) */ -#define DUK_DATE_FLAG_YEAR_FIXUP (1 << 10) /* setter: perform 2-digit year fixup (00...99 -> 1900...1999) */ -#define DUK_DATE_FLAG_SEP_T (1 << 11) /* string conversion: use 'T' instead of ' ' as a separator */ -#define DUK_DATE_FLAG_VALUE_SHIFT 12 /* additional values begin at bit 12 */ - -/* - * ROM pointer compression - */ - -/* Support array for ROM pointer compression. Only declared when ROM - * pointer compression is active. - */ -#if defined(DUK_USE_ROM_OBJECTS) && defined(DUK_USE_HEAPPTR16) -DUK_EXTERNAL_DECL const void * const duk_rom_compressed_pointers[]; -#endif - -/* - * C++ name mangling - */ - -#if defined(__cplusplus) -/* end 'extern "C"' wrapper */ -} -#endif - -#endif /* DUK_API_PUBLIC_H_INCLUDED */ - -/* - * END PUBLIC API - */ diff -Nru duktape-2.0.0/src-input/duk_api_stack.c duktape-2.1.1/src-input/duk_api_stack.c --- duktape-2.0.0/src-input/duk_api_stack.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_api_stack.c 2017-07-28 22:05:08.000000000 +0000 @@ -76,7 +76,7 @@ DUK_LOCAL_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t idx, duk_uint_t tag); -DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t idx, duk_bool_t require) { +DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t idx, duk_int_t def_value, duk_bool_t require) { duk_hthread *thr; duk_tval *tv; duk_small_int_t c; @@ -136,10 +136,11 @@ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); /* not reachable */ } - return 0; + + return def_value; } -DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t idx, duk_bool_t require) { +DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value, duk_bool_t require) { duk_hthread *thr; duk_tval *tv; duk_small_int_t c; @@ -189,7 +190,8 @@ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); /* not reachable */ } - return 0; + + return def_value; } /* @@ -356,7 +358,7 @@ DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(DUK_INVALID_INDEX < 0); - if (duk_normalize_index(ctx, idx) < 0) { + if (DUK_UNLIKELY(duk_normalize_index(ctx, idx) < 0)) { DUK_ERROR_RANGE_INDEX(thr, idx); return; /* unreachable */ } @@ -384,7 +386,7 @@ DUK_ASSERT_CTX_VALID(ctx); ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); - if (ret < min_top) { + if (DUK_UNLIKELY(ret < min_top)) { DUK_ERROR_TYPE_INVALID_ARGS(thr); } return ret; @@ -596,7 +598,7 @@ new_alloc_size = sizeof(duk_tval) * new_size; new_valstack = (duk_tval *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_valstack_ptr, (void *) thr, new_alloc_size); - if (!new_valstack) { + if (DUK_UNLIKELY(new_valstack == NULL)) { /* Because new_size != 0, if condition doesn't need to be * (new_valstack != NULL || new_size == 0). */ @@ -686,26 +688,16 @@ return 1; } -DUK_INTERNAL -duk_bool_t duk_valstack_resize_raw(duk_context *ctx, - duk_size_t min_new_size, - duk_small_uint_t flags) { +DUK_LOCAL DUK_COLD DUK_NOINLINE duk_bool_t duk__valstack_do_resize(duk_context *ctx, + duk_size_t min_new_size, + duk_small_uint_t flags) { duk_hthread *thr = (duk_hthread *) ctx; duk_size_t old_size; duk_size_t new_size; - duk_bool_t is_shrink = 0; - duk_small_uint_t shrink_flag = (flags & DUK_VSRESIZE_FLAG_SHRINK); + duk_bool_t is_shrink; duk_small_uint_t compact_flag = (flags & DUK_VSRESIZE_FLAG_COMPACT); duk_small_uint_t throw_flag = (flags & DUK_VSRESIZE_FLAG_THROW); - DUK_DDD(DUK_DDDPRINT("check valstack resize: min_new_size=%lu, curr_size=%ld, curr_top=%ld, " - "curr_bottom=%ld, shrink=%d, compact=%d, throw=%d", - (unsigned long) min_new_size, - (long) (thr->valstack_end - thr->valstack), - (long) (thr->valstack_top - thr->valstack), - (long) (thr->valstack_bottom - thr->valstack), - (int) shrink_flag, (int) compact_flag, (int) throw_flag)); - DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->valstack_bottom >= thr->valstack); @@ -721,11 +713,8 @@ if (min_new_size <= old_size) { is_shrink = 1; - if (!shrink_flag || - old_size - min_new_size < DUK_VALSTACK_SHRINK_THRESHOLD) { - DUK_DDD(DUK_DDDPRINT("no need to grow or shrink valstack")); - return 1; - } + } else { + is_shrink = 0; } new_size = min_new_size; @@ -744,7 +733,7 @@ (unsigned long) old_size, (unsigned long) new_size, (unsigned long) min_new_size)); - if (new_size > thr->valstack_max) { + if (DUK_UNLIKELY(new_size > thr->valstack_max)) { /* Note: may be triggered even if minimal new_size would not reach the limit, * plan limit accordingly (taking DUK_VALSTACK_GROW_STEP into account). */ @@ -767,7 +756,7 @@ * size_t and pointer arithmetic won't wrap in duk__resize_valstack(). */ - if (!duk__resize_valstack(ctx, new_size)) { + if (DUK_UNLIKELY(!duk__resize_valstack(ctx, new_size))) { if (is_shrink) { DUK_DD(DUK_DDPRINT("valstack resize failed, but is a shrink, ignore")); return 1; @@ -786,6 +775,44 @@ return 1; } +DUK_INTERNAL duk_bool_t duk_valstack_resize_raw(duk_context *ctx, + duk_size_t min_new_size, + duk_small_uint_t flags) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_size_t old_size; + + DUK_DDD(DUK_DDDPRINT("check valstack resize: min_new_size=%lu, curr_size=%ld, curr_top=%ld, " + "curr_bottom=%ld, flags=%lx", + (unsigned long) min_new_size, + (long) (thr->valstack_end - thr->valstack), + (long) (thr->valstack_top - thr->valstack), + (long) (thr->valstack_bottom - thr->valstack), + (unsigned long) flags)); + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + DUK_ASSERT(thr->valstack_bottom >= thr->valstack); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT(thr->valstack_end >= thr->valstack_top); + +#if defined(DUK_USE_PREFER_SIZE) + old_size = (duk_size_t) (thr->valstack_end - thr->valstack); +#else + DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size); + old_size = thr->valstack_size; +#endif + + if (DUK_LIKELY(min_new_size <= old_size)) { + if (DUK_LIKELY((flags & DUK_VSRESIZE_FLAG_SHRINK) == 0 || + old_size - min_new_size < DUK_VALSTACK_SHRINK_THRESHOLD)) { + DUK_DDD(DUK_DDDPRINT("no need to grow or shrink valstack")); + return 1; + } + } + + return duk__valstack_do_resize(ctx, min_new_size, flags); +} + DUK_EXTERNAL duk_bool_t duk_check_stack(duk_context *ctx, duk_idx_t extra) { duk_hthread *thr = (duk_hthread *) ctx; duk_size_t min_new_size; @@ -831,9 +858,11 @@ } DUK_EXTERNAL duk_bool_t duk_check_stack_top(duk_context *ctx, duk_idx_t top) { + duk_hthread *thr; duk_size_t min_new_size; DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; if (DUK_UNLIKELY(top < 0)) { /* Clamping to zero makes the API more robust to calling code @@ -842,7 +871,7 @@ top = 0; } - min_new_size = top + DUK_VALSTACK_INTERNAL_EXTRA; + min_new_size = (thr->valstack_bottom - thr->valstack) + top + DUK_VALSTACK_INTERNAL_EXTRA; return duk_valstack_resize_raw(ctx, min_new_size, /* min_new_size */ 0 /* no shrink */ | /* flags */ @@ -851,9 +880,11 @@ } DUK_EXTERNAL void duk_require_stack_top(duk_context *ctx, duk_idx_t top) { + duk_hthread *thr; duk_size_t min_new_size; DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; if (DUK_UNLIKELY(top < 0)) { /* Clamping to zero makes the API more robust to calling code @@ -862,7 +893,7 @@ top = 0; } - min_new_size = top + DUK_VALSTACK_INTERNAL_EXTRA; + min_new_size = (thr->valstack_bottom - thr->valstack) + top + DUK_VALSTACK_INTERNAL_EXTRA; (void) duk_valstack_resize_raw(ctx, min_new_size, /* min_new_size */ 0 /* no shrink */ | /* flags */ @@ -927,7 +958,7 @@ thr = (duk_hthread *) ctx; DUK__CHECK_SPACE(); - if (thr->valstack_top - thr->valstack_bottom <= 0) { + if (DUK_UNLIKELY(thr->valstack_top - thr->valstack_bottom <= 0)) { DUK_ERROR_RANGE_INDEX(thr, -1); return; /* unreachable */ } @@ -1102,27 +1133,27 @@ DUK_ASSERT(to_ctx != NULL); DUK_ASSERT(from_ctx != NULL); - if (to_ctx == from_ctx) { + if (DUK_UNLIKELY(to_ctx == from_ctx)) { DUK_ERROR_TYPE(to_thr, DUK_STR_INVALID_CONTEXT); return; } - if ((count < 0) || - (count > (duk_idx_t) to_thr->valstack_max)) { + if (DUK_UNLIKELY((count < 0) || + (count > (duk_idx_t) to_thr->valstack_max))) { /* Maximum value check ensures 'nbytes' won't wrap below. */ DUK_ERROR_RANGE_INVALID_COUNT(to_thr); return; } nbytes = sizeof(duk_tval) * count; - if (nbytes == 0) { + if (DUK_UNLIKELY(nbytes == 0)) { return; } DUK_ASSERT(to_thr->valstack_top <= to_thr->valstack_end); - if ((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes) { + if (DUK_UNLIKELY((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes)) { DUK_ERROR_RANGE_PUSH_BEYOND(to_thr); } src = (void *) ((duk_uint8_t *) from_thr->valstack_top - nbytes); - if (src < (void *) from_thr->valstack_bottom) { + if (DUK_UNLIKELY(src < (void *) from_thr->valstack_bottom)) { DUK_ERROR_RANGE_INVALID_COUNT(to_thr); } @@ -1157,7 +1188,7 @@ } /* - * Get/require + * Get/opt/require */ DUK_EXTERNAL void duk_require_undefined(duk_context *ctx, duk_idx_t idx) { @@ -1168,7 +1199,7 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_UNDEFINED(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_UNDEFINED(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "undefined", DUK_STR_NOT_UNDEFINED); } } @@ -1181,13 +1212,13 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_NULL(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_NULL(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "null", DUK_STR_NOT_NULL); } } -DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t idx) { - duk_bool_t ret = 0; /* default: false */ +DUK_LOCAL DUK_ALWAYS_INLINE duk_bool_t duk__get_boolean_raw(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value) { + duk_bool_t ret; duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); @@ -1196,12 +1227,27 @@ DUK_ASSERT(tv != NULL); if (DUK_TVAL_IS_BOOLEAN(tv)) { ret = DUK_TVAL_GET_BOOLEAN(tv); + DUK_ASSERT(ret == 0 || ret == 1); + } else { + ret = def_value; + /* Not guaranteed to be 0 or 1. */ } - DUK_ASSERT(ret == 0 || ret == 1); return ret; } +DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t idx) { + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_boolean_raw(ctx, idx, 0); /* default: false */ +} + +DUK_EXTERNAL duk_bool_t duk_get_boolean_default(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_boolean_raw(ctx, idx, def_value); +} + DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -1211,35 +1257,61 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_BOOLEAN(tv)) { + if (DUK_LIKELY(DUK_TVAL_IS_BOOLEAN(tv))) { + ret = DUK_TVAL_GET_BOOLEAN(tv); + DUK_ASSERT(ret == 0 || ret == 1); + return ret; + } else { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "boolean", DUK_STR_NOT_BOOLEAN); } - ret = DUK_TVAL_GET_BOOLEAN(tv); - DUK_ASSERT(ret == 0 || ret == 1); - return ret; } -DUK_EXTERNAL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t idx) { +DUK_EXTERNAL duk_bool_t duk_opt_boolean(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_boolean(ctx, idx); +} + +DUK_LOCAL DUK_ALWAYS_INLINE duk_double_t duk__get_number_raw(duk_context *ctx, duk_idx_t idx, duk_double_t def_value) { duk_double_union ret; duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); - ret.d = DUK_DOUBLE_NAN; /* default: NaN */ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (DUK_TVAL_IS_NUMBER(tv)) { - ret.d = DUK_TVAL_GET_NUMBER(tv); +#if defined(DUK_USE_FASTINT) + if (DUK_TVAL_IS_FASTINT(tv)) { + ret.d = (duk_double_t) DUK_TVAL_GET_FASTINT(tv); /* XXX: cast trick */ + } + else +#endif + if (DUK_TVAL_IS_DOUBLE(tv)) { + /* When using packed duk_tval, number must be in NaN-normalized form + * for it to be a duk_tval, so no need to normalize. NOP for unpacked + * duk_tval. + */ + ret.d = DUK_TVAL_GET_DOUBLE(tv); + DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret)); + } else { + ret.d = def_value; + /* Default value (including NaN) may not be normalized. */ } - /* When using packed duk_tval, number must be in NaN-normalized form - * for it to be a duk_tval, so no need to normalize. NOP for unpacked - * duk_tval. - */ - DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret)); return ret.d; } +DUK_EXTERNAL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t idx) { + return duk__get_number_raw(ctx, idx, DUK_DOUBLE_NAN); /* default: NaN */ +} + +DUK_EXTERNAL duk_double_t duk_get_number_default(duk_context *ctx, duk_idx_t idx, duk_double_t def_value) { + return duk__get_number_raw(ctx, idx, def_value); +} + DUK_EXTERNAL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -1249,7 +1321,7 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_NUMBER(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_NUMBER(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); } @@ -1263,56 +1335,89 @@ return ret.d; } +DUK_EXTERNAL duk_double_t duk_opt_number(duk_context *ctx, duk_idx_t idx, duk_double_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + /* User provided default is not NaN normalized. */ + return def_value; + } + return duk_require_number(ctx, idx); +} + DUK_EXTERNAL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t idx) { - /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*require*/); + + return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*def_value*/, 0 /*require*/); } DUK_EXTERNAL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t idx) { - /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*require*/); + + return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*def_value*/, 0 /*require*/); +} + +DUK_EXTERNAL duk_int_t duk_get_int_default(duk_context *ctx, duk_idx_t idx, duk_int_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + return (duk_int_t) duk__api_coerce_d2i(ctx, idx, def_value, 0 /*require*/); +} + +DUK_EXTERNAL duk_uint_t duk_get_uint_default(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, def_value, 0 /*require*/); } DUK_EXTERNAL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t idx) { - /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 1 /*require*/); + + return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*def_value*/, 1 /*require*/); } DUK_EXTERNAL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t idx) { - /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 1 /*require*/); + + return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*def_value*/, 1 /*require*/); } -DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) { - const char *ret; - duk_tval *tv; +DUK_EXTERNAL duk_int_t duk_opt_int(duk_context *ctx, duk_idx_t idx, duk_int_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_int(ctx, idx); +} +DUK_EXTERNAL duk_uint_t duk_opt_uint(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value) { DUK_ASSERT_CTX_VALID(ctx); - /* default: NULL, length 0 */ - ret = NULL; - if (out_len) { - *out_len = 0; + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; } + return duk_require_uint(ctx, idx); +} - tv = duk_get_tval_or_unused(ctx, idx); - DUK_ASSERT(tv != NULL); - if (DUK_TVAL_IS_STRING(tv)) { - /* Here we rely on duk_hstring instances always being zero - * terminated even if the actual string is not. - */ - duk_hstring *h = DUK_TVAL_GET_STRING(tv); - DUK_ASSERT(h != NULL); +DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) { + duk_hstring *h; + const char *ret; + duk_size_t len; + + DUK_ASSERT_CTX_VALID(ctx); + + h = duk_get_hstring(ctx, idx); + if (h != NULL) { + len = DUK_HSTRING_GET_BYTELEN(h); ret = (const char *) DUK_HSTRING_GET_DATA(h); - if (out_len) { - *out_len = DUK_HSTRING_GET_BYTELEN(h); - } + } else { + len = 0; + ret = NULL; } + if (out_len != NULL) { + *out_len = len; + } return ret; } @@ -1343,9 +1448,72 @@ } DUK_EXTERNAL const char *duk_get_string(duk_context *ctx, duk_idx_t idx) { + duk_hstring *h; + + DUK_ASSERT_CTX_VALID(ctx); + + h = duk_get_hstring(ctx, idx); + if (h != NULL) { + return (const char *) DUK_HSTRING_GET_DATA(h); + } else { + return NULL; + } +} + +DUK_EXTERNAL const char *duk_opt_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + if (out_len != NULL) { + *out_len = def_len; + } + return def_ptr; + } + return duk_require_lstring(ctx, idx, out_len); +} + +DUK_EXTERNAL const char *duk_opt_string(duk_context *ctx, duk_idx_t idx, const char *def_ptr) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_ptr; + } + return duk_require_string(ctx, idx); +} + +DUK_EXTERNAL const char *duk_get_lstring_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) { + duk_hstring *h; + const char *ret; + duk_size_t len; + + DUK_ASSERT_CTX_VALID(ctx); + + h = duk_get_hstring(ctx, idx); + if (h != NULL) { + len = DUK_HSTRING_GET_BYTELEN(h); + ret = (const char *) DUK_HSTRING_GET_DATA(h); + } else { + len = def_len; + ret = def_ptr; + } + + if (out_len != NULL) { + *out_len = len; + } + return ret; +} + +DUK_EXTERNAL const char *duk_get_string_default(duk_context *ctx, duk_idx_t idx, const char *def_value) { + duk_hstring *h; + DUK_ASSERT_CTX_VALID(ctx); - return duk_get_lstring(ctx, idx, NULL); + h = duk_get_hstring(ctx, idx); + if (h != NULL) { + return (const char *) DUK_HSTRING_GET_DATA(h); + } else { + return def_value; + } } DUK_INTERNAL const char *duk_get_string_notsymbol(duk_context *ctx, duk_idx_t idx) { @@ -1377,7 +1545,7 @@ return (const char *) DUK_HSTRING_GET_DATA(h); } -DUK_EXTERNAL void *duk_get_pointer(duk_context *ctx, duk_idx_t idx) { +DUK_LOCAL void *duk__get_pointer_raw(duk_context *ctx, duk_idx_t idx, void *def_value) { duk_tval *tv; void *p; @@ -1386,13 +1554,30 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); if (!DUK_TVAL_IS_POINTER(tv)) { - return NULL; + return def_value; } p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */ return p; } +DUK_EXTERNAL void *duk_get_pointer(duk_context *ctx, duk_idx_t idx) { + return duk__get_pointer_raw(ctx, idx, NULL /*def_value*/); +} + +DUK_EXTERNAL void *duk_opt_pointer(duk_context *ctx, duk_idx_t idx, void *def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_pointer(ctx, idx); +} + +DUK_EXTERNAL void *duk_get_pointer_default(duk_context *ctx, duk_idx_t idx, void *def_value) { + return duk__get_pointer_raw(ctx, idx, def_value); +} + DUK_EXTERNAL void *duk_require_pointer(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -1405,7 +1590,7 @@ */ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_POINTER(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_POINTER(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "pointer", DUK_STR_NOT_POINTER); } p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */ @@ -1431,10 +1616,12 @@ } #endif -DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_bool_t throw_flag) { +DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag) { duk_hthread *thr = (duk_hthread *) ctx; - duk_tval *tv; duk_hbuffer *h; + void *ret; + duk_size_t len; + duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); DUK_UNREF(thr); @@ -1445,27 +1632,54 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_BUFFER(tv)) { + if (DUK_LIKELY(DUK_TVAL_IS_BUFFER(tv))) { + h = DUK_TVAL_GET_BUFFER(tv); + DUK_ASSERT(h != NULL); + + len = DUK_HBUFFER_GET_SIZE(h); + ret = DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); + } else { if (throw_flag) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER); } - return NULL; + len = def_size; + ret = def_ptr; } - h = DUK_TVAL_GET_BUFFER(tv); - DUK_ASSERT(h != NULL); - if (out_size) { - *out_size = DUK_HBUFFER_GET_SIZE(h); + if (out_size != NULL) { + *out_size = len; } - return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */ + return ret; } DUK_EXTERNAL void *duk_get_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { - return duk__get_buffer_helper(ctx, idx, out_size, 0 /*throw_flag*/); + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_buffer_helper(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/); +} + +DUK_EXTERNAL void *duk_opt_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + if (out_size != NULL) { + *out_size = def_size; + } + return def_ptr; + } + return duk_require_buffer(ctx, idx, out_size); +} + +DUK_EXTERNAL void *duk_get_buffer_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len) { + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_buffer_helper(ctx, idx, out_size, def_ptr, def_len, 0 /*throw_flag*/); } DUK_EXTERNAL void *duk_require_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { - return duk__get_buffer_helper(ctx, idx, out_size, 1 /*throw_flag*/); + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_buffer_helper(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/); } /* Get the active buffer data area for a plain buffer or a buffer object. @@ -1473,7 +1687,7 @@ * have a NULL data pointer when its size is zero, the optional 'out_isbuffer' * argument allows caller to detect this reliably. */ -DUK_INTERNAL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_bool_t throw_flag, duk_bool_t *out_isbuffer) { +DUK_INTERNAL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag, duk_bool_t *out_isbuffer) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -1484,7 +1698,7 @@ *out_isbuffer = 0; } if (out_size != NULL) { - *out_size = 0; + *out_size = def_size; } tv = duk_get_tval_or_unused(ctx, idx); @@ -1533,15 +1747,31 @@ if (throw_flag) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER); } - return NULL; + return def_ptr; } DUK_EXTERNAL void *duk_get_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { - return duk_get_buffer_data_raw(ctx, idx, out_size, 0 /*throw_flag*/, NULL); + return duk_get_buffer_data_raw(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, NULL); +} + +DUK_EXTERNAL void *duk_get_buffer_data_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) { + return duk_get_buffer_data_raw(ctx, idx, out_size, def_ptr, def_size, 0 /*throw_flag*/, NULL); +} + +DUK_EXTERNAL void *duk_opt_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + if (out_size != NULL) { + *out_size = def_size; + } + return def_ptr; + } + return duk_require_buffer_data(ctx, idx, out_size); } DUK_EXTERNAL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { - return duk_get_buffer_data_raw(ctx, idx, out_size, 1 /*throw_flag*/, NULL); + return duk_get_buffer_data_raw(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/, NULL); } /* Raw helper for getting a value from the stack, checking its tag. @@ -1573,7 +1803,7 @@ DUK_INTERNAL duk_hstring *duk_get_hstring_notsymbol(duk_context *ctx, duk_idx_t idx) { duk_hstring *res = (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING); - if (res && DUK_HSTRING_HAS_SYMBOL(res)) { + if (DUK_UNLIKELY(res && DUK_HSTRING_HAS_SYMBOL(res))) { return NULL; } return res; @@ -1582,7 +1812,7 @@ DUK_INTERNAL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t idx) { duk_hstring *h; h = (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING); - if (h == NULL) { + if (DUK_UNLIKELY(h == NULL)) { DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "string", DUK_STR_NOT_STRING); } return h; @@ -1591,7 +1821,7 @@ DUK_INTERNAL duk_hstring *duk_require_hstring_notsymbol(duk_context *ctx, duk_idx_t idx) { duk_hstring *h; h = (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING); - if (h == NULL || DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(h == NULL || DUK_HSTRING_HAS_SYMBOL(h))) { DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "string", DUK_STR_NOT_STRING); } return h; @@ -1604,7 +1834,7 @@ DUK_INTERNAL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t idx) { duk_hobject *h; h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (h == NULL) { + if (DUK_UNLIKELY(h == NULL)) { DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "object", DUK_STR_NOT_OBJECT); } return h; @@ -1617,7 +1847,7 @@ DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t idx) { duk_hbuffer *h; h = (duk_hbuffer *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_BUFFER); - if (h == NULL) { + if (DUK_UNLIKELY(h == NULL)) { DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "buffer", DUK_STR_NOT_BUFFER); } return h; @@ -1625,7 +1855,7 @@ DUK_INTERNAL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t idx) { duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (h != NULL && !DUK_HOBJECT_IS_THREAD(h)) { + if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_THREAD(h))) { h = NULL; } return (duk_hthread *) h; @@ -1634,7 +1864,7 @@ DUK_INTERNAL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (!(h != NULL && DUK_HOBJECT_IS_THREAD(h))) { + if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_THREAD(h)))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "thread", DUK_STR_NOT_THREAD); } return (duk_hthread *) h; @@ -1642,7 +1872,7 @@ DUK_INTERNAL duk_hcompfunc *duk_get_hcompfunc(duk_context *ctx, duk_idx_t idx) { duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (h != NULL && !DUK_HOBJECT_IS_COMPFUNC(h)) { + if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_COMPFUNC(h))) { h = NULL; } return (duk_hcompfunc *) h; @@ -1651,7 +1881,7 @@ DUK_INTERNAL duk_hcompfunc *duk_require_hcompfunc(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (!(h != NULL && DUK_HOBJECT_IS_COMPFUNC(h))) { + if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_COMPFUNC(h)))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "compiledfunction", DUK_STR_NOT_COMPFUNC); } return (duk_hcompfunc *) h; @@ -1659,7 +1889,7 @@ DUK_INTERNAL duk_hnatfunc *duk_get_hnatfunc(duk_context *ctx, duk_idx_t idx) { duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (h != NULL && !DUK_HOBJECT_IS_NATFUNC(h)) { + if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_NATFUNC(h))) { h = NULL; } return (duk_hnatfunc *) h; @@ -1668,7 +1898,7 @@ DUK_INTERNAL duk_hnatfunc *duk_require_hnatfunc(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (!(h != NULL && DUK_HOBJECT_IS_NATFUNC(h))) { + if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_NATFUNC(h)))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC); } return (duk_hnatfunc *) h; @@ -1683,13 +1913,13 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_OBJECT(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_OBJECT(tv))) { return NULL; } h = DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(h != NULL); - if (!DUK_HOBJECT_IS_NATFUNC(h)) { + if (DUK_UNLIKELY(!DUK_HOBJECT_IS_NATFUNC(h))) { return NULL; } DUK_ASSERT(DUK_HOBJECT_HAS_NATFUNC(h)); @@ -1698,6 +1928,28 @@ return f->func; } +DUK_EXTERNAL duk_c_function duk_opt_c_function(duk_context *ctx, duk_idx_t idx, duk_c_function def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_c_function(ctx, idx); +} + +DUK_EXTERNAL duk_c_function duk_get_c_function_default(duk_context *ctx, duk_idx_t idx, duk_c_function def_value) { + duk_c_function ret; + + DUK_ASSERT_CTX_VALID(ctx); + + ret = duk_get_c_function(ctx, idx); + if (ret != NULL) { + return ret; + } + + return def_value; +} + DUK_EXTERNAL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_c_function ret; @@ -1705,14 +1957,14 @@ DUK_ASSERT_CTX_VALID(ctx); ret = duk_get_c_function(ctx, idx); - if (!ret) { + if (DUK_UNLIKELY(!ret)) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC); } return ret; } DUK_EXTERNAL void duk_require_function(duk_context *ctx, duk_idx_t idx) { - if (!duk_is_function(ctx, idx)) { + if (DUK_UNLIKELY(!duk_is_function(ctx, idx))) { DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, idx, "function", DUK_STR_NOT_FUNCTION); } } @@ -1721,7 +1973,7 @@ duk_hobject *h; h = duk_require_hobject_accept_mask(ctx, idx, DUK_TYPE_MASK_LIGHTFUNC); - if (h != NULL && !DUK_HOBJECT_HAS_CONSTRUCTABLE(h)) { + if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_HAS_CONSTRUCTABLE(h))) { DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, idx, "constructable", DUK_STR_NOT_CONSTRUCTABLE); } /* Lightfuncs (h == NULL) are constructable. */ @@ -1739,6 +1991,28 @@ return (duk_context *) duk_require_hthread(ctx, idx); } +DUK_EXTERNAL duk_context *duk_opt_context(duk_context *ctx, duk_idx_t idx, duk_context *def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_context(ctx, idx); +} + +DUK_EXTERNAL_DECL duk_context *duk_get_context_default(duk_context *ctx, duk_idx_t idx, duk_context *def_value) { + duk_context *ret; + + DUK_ASSERT_CTX_VALID(ctx); + + ret = duk_get_context(ctx, idx); + if (ret != NULL) { + return ret; + } + + return def_value; +} + DUK_EXTERNAL void *duk_get_heapptr(duk_context *ctx, duk_idx_t idx) { duk_tval *tv; void *ret; @@ -1747,7 +2021,7 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) { return (void *) NULL; } @@ -1756,6 +2030,28 @@ return ret; } +DUK_EXTERNAL void *duk_opt_heapptr(duk_context *ctx, duk_idx_t idx, void *def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_heapptr(ctx, idx); +} + +DUK_EXTERNAL_DECL void *duk_get_heapptr_default(duk_context *ctx, duk_idx_t idx, void *def_value) { + void *ret; + + DUK_ASSERT_CTX_VALID(ctx); + + ret = duk_get_heapptr(ctx, idx); + if (ret != NULL) { + return ret; + } + + return def_value; +} + DUK_EXTERNAL void *duk_require_heapptr(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -1765,7 +2061,7 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "heapobject", DUK_STR_UNEXPECTED_TYPE); } @@ -1782,7 +2078,7 @@ DUK_ASSERT_CTX_VALID(ctx); res = duk_get_hobject(ctx, idx); /* common case, not promoted */ - if (res != NULL) { + if (DUK_LIKELY(res != NULL)) { DUK_ASSERT(res != NULL); return res; } @@ -1837,7 +2133,7 @@ DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX); h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum) { + if (DUK_UNLIKELY(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum)) { h = NULL; } return h; @@ -1853,7 +2149,7 @@ thr = (duk_hthread *) ctx; h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum)) { + if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum))) { duk_hstring *h_class; h_class = DUK_HTHREAD_GET_STRING(thr, DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum)); DUK_UNREF(h_class); @@ -1895,7 +2191,7 @@ case DUK_TAG_STRING: { duk_hstring *h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { return 0; } return (duk_size_t) DUK_HSTRING_GET_CHARLEN(h); @@ -2197,6 +2493,16 @@ tv = duk_require_tval(ctx, idx); DUK_ASSERT(tv != NULL); + +#if defined(DUK_USE_FASTINT) + /* If argument is a fastint, guarantee that it remains one. + * There's no downgrade check for other cases. + */ + if (DUK_TVAL_IS_FASTINT(tv)) { + /* XXX: Unnecessary conversion back and forth. */ + return (duk_double_t) DUK_TVAL_GET_FASTINT(tv); + } +#endif d = coerce_func(thr, tv); /* XXX: fastint? */ @@ -2208,21 +2514,21 @@ } DUK_EXTERNAL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t idx) { - /* Value coercion (in stack): ToInteger(), E5 Section 9.4 - * API return value coercion: custom + /* Value coercion (in stack): ToInteger(), E5 Section 9.4, + * API return value coercion: custom. */ DUK_ASSERT_CTX_VALID(ctx); (void) duk__to_int_uint_helper(ctx, idx, duk_js_tointeger); - return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*require*/); + return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*def_value*/, 0 /*require*/); } DUK_EXTERNAL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t idx) { - /* Value coercion (in stack): ToInteger(), E5 Section 9.4 - * API return value coercion: custom + /* Value coercion (in stack): ToInteger(), E5 Section 9.4, + * API return value coercion: custom. */ DUK_ASSERT_CTX_VALID(ctx); (void) duk__to_int_uint_helper(ctx, idx, duk_js_tointeger); - return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*require*/); + return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*def_value*/, 0 /*require*/); } DUK_EXTERNAL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t idx) { @@ -2426,7 +2732,7 @@ duk_hstring *h; h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { stridx = DUK_STRIDX_UC_SYMBOL; } else { stridx = DUK_STRIDX_UC_STRING; @@ -2584,7 +2890,7 @@ duk_hstring *h; h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CANNOT_STRING_COERCE_SYMBOL); } else { goto skip_replace; @@ -2664,7 +2970,7 @@ duk_hstring *ret; DUK_ASSERT_CTX_VALID(ctx); ret = duk_get_hstring(ctx, idx); - if (ret && DUK_HSTRING_HAS_SYMBOL(ret)) { + if (DUK_UNLIKELY(ret && DUK_HSTRING_HAS_SYMBOL(ret))) { return ret; } return duk_to_hstring(ctx, idx); @@ -2817,6 +3123,7 @@ flags = DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_CONSTRUCTABLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_NATFUNC | DUK_HOBJECT_FLAG_NEWENV | DUK_HOBJECT_FLAG_STRICT | @@ -2867,6 +3174,7 @@ } case DUK_TAG_BOOLEAN: { flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BOOLEAN); proto = DUK_BIDX_BOOLEAN_PROTOTYPE; goto create_object; @@ -2875,12 +3183,14 @@ duk_hstring *h; h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_SYMBOL); proto = DUK_BIDX_SYMBOL_PROTOTYPE; } else { flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING); proto = DUK_BIDX_STRING_PROTOTYPE; @@ -2910,6 +3220,7 @@ #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ case DUK_TAG_POINTER: { flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER); proto = DUK_BIDX_POINTER_PROTOTYPE; goto create_object; @@ -2938,7 +3249,8 @@ DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); flags = DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_NUMBER); + DUK_HOBJECT_FLAG_FASTREFS | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_NUMBER); proto = DUK_BIDX_NUMBER_PROTOTYPE; goto create_object; } @@ -3156,7 +3468,7 @@ DUK_ASSERT_CTX_VALID(ctx); - if (duk_get_type_mask(ctx, idx) & mask) { + if (DUK_LIKELY(duk_get_type_mask(ctx, idx) & mask)) { return 1; } if (mask & DUK_TYPE_MASK_THROW) { @@ -3282,7 +3594,10 @@ DUK_ASSERT_CTX_VALID(ctx); h = duk_get_hstring(ctx, idx); - if (h != NULL && DUK_HSTRING_HAS_SYMBOL(h)) { + /* Use DUK_LIKELY() here because caller may be more likely to type + * check an expected symbol than not. + */ + if (DUK_LIKELY(h != NULL && DUK_HSTRING_HAS_SYMBOL(h))) { return 1; } return 0; @@ -3338,10 +3653,15 @@ } DUK_EXTERNAL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t idx) { + duk_hobject *obj; + DUK_ASSERT_CTX_VALID(ctx); - return duk__obj_flag_any_default_false(ctx, - idx, - DUK_HOBJECT_FLAG_THREAD); + + obj = duk_get_hobject(ctx, idx); + if (obj) { + return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_THREAD ? 1 : 0); + } + return 0; } DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t idx) { @@ -3612,9 +3932,7 @@ DUK_ASSERT_CTX_VALID(ctx); /* check stack before interning (avoid hanging temp) */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); /* NULL with zero length represents an empty string; NULL with higher * length is also now trated like an empty string although it is @@ -3626,11 +3944,11 @@ } /* Check for maximum string length */ - if (len > DUK_HSTRING_MAX_BYTELEN) { + if (DUK_UNLIKELY(len > DUK_HSTRING_MAX_BYTELEN)) { DUK_ERROR_RANGE(thr, DUK_STR_STRING_TOO_LONG); } - h = duk_heap_string_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len); + h = duk_heap_strtable_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len); DUK_ASSERT(h != NULL); tv_slot = thr->valstack_top++; @@ -3748,6 +4066,7 @@ thr = (duk_hthread *) ctx; DUK_ASSERT(thr->callstack_top > 0); /* caller required to know */ + DUK_ASSERT(thr->callstack_curr != NULL); DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* consequence of above */ DUK_ASSERT(thr->valstack_bottom - 1 >= thr->valstack); /* 'this' binding exists */ @@ -3763,8 +4082,8 @@ DUK_ASSERT_DISABLE(thr->callstack_top >= 0); DUK_ASSERT(thr->callstack_top <= thr->callstack_size); - act = duk_hthread_get_current_activation(thr); - if (act) { + act = thr->callstack_curr; + if (act != NULL) { duk_push_tval(ctx, &act->tv_func); } else { duk_push_undefined(ctx); @@ -3822,7 +4141,7 @@ DUK_EXTERNAL void duk_push_thread_stash(duk_context *ctx, duk_context *target_ctx) { duk_hthread *thr = (duk_hthread *) ctx; DUK_ASSERT_CTX_VALID(ctx); - if (!target_ctx) { + if (DUK_UNLIKELY(target_ctx == NULL)) { DUK_ERROR_TYPE_INVALID_ARGS(thr); return; /* not reached */ } @@ -3899,7 +4218,7 @@ /* failed, resize and try again */ sz = sz * 2; - if (sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT) { + if (DUK_UNLIKELY(sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT)) { DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG); } } @@ -3937,15 +4256,10 @@ DUK_ASSERT(prototype_bidx == -1 || (prototype_bidx >= 0 && prototype_bidx < DUK_NUM_BUILTINS)); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); - h = duk_hobject_alloc(thr->heap, hobject_flags_and_class); - if (!h) { - DUK_ERROR_ALLOC_FAILED(thr); - } + h = duk_hobject_alloc(thr, hobject_flags_and_class); + DUK_ASSERT(h != NULL); DUK_DDD(DUK_DDDPRINT("created object with flags: 0x%08lx", (unsigned long) h->hdr.h_flags)); @@ -3984,6 +4298,7 @@ (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), DUK_BIDX_OBJECT_PROTOTYPE); return duk_get_top_index_unsafe(ctx); @@ -3999,14 +4314,13 @@ DUK_ASSERT_CTX_VALID(ctx); flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_ARRAY_PART | DUK_HOBJECT_FLAG_EXOTIC_ARRAY | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAY); - obj = duk_harray_alloc(thr->heap, flags); - if (!obj) { - DUK_ERROR_ALLOC_FAILED(thr); - } + obj = duk_harray_alloc(thr, flags); + DUK_ASSERT(obj != NULL); /* XXX: since prototype is NULL, could save a check */ DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_ARRAY_PROTOTYPE]); @@ -4060,18 +4374,12 @@ DUK_ASSERT_CTX_VALID(ctx); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); - obj = duk_hthread_alloc(thr->heap, + obj = duk_hthread_alloc(thr, DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_THREAD | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD)); - if (!obj) { - DUK_ERROR_ALLOC_FAILED(thr); - } + DUK_ASSERT(obj != NULL); obj->state = DUK_HTHREAD_STATE_INACTIVE; #if defined(DUK_USE_ROM_STRINGS) /* Nothing to initialize, strs[] is in ROM. */ @@ -4092,7 +4400,7 @@ thr->valstack_top++; /* important to do this *after* pushing, to make the thread reachable for gc */ - if (!duk_hthread_init_stacks(thr->heap, obj)) { + if (DUK_UNLIKELY(!duk_hthread_init_stacks(thr->heap, obj))) { DUK_ERROR_ALLOC_FAILED(thr); } @@ -4123,21 +4431,18 @@ DUK_ASSERT_CTX_VALID(ctx); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); /* Template functions are not strictly constructable (they don't * have a "prototype" property for instance), so leave the * DUK_HOBJECT_FLAG_CONSRUCTABLE flag cleared here. */ - obj = duk_hcompfunc_alloc(thr->heap, + obj = duk_hcompfunc_alloc(thr, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_COMPFUNC | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION)); - if (!obj) { + if (DUK_UNLIKELY(obj == NULL)) { DUK_ERROR_ALLOC_FAILED(thr); } @@ -4162,11 +4467,9 @@ DUK_ASSERT_CTX_VALID(ctx); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } - if (func == NULL) { + DUK__CHECK_SPACE(); + + if (DUK_UNLIKELY(func == NULL)) { goto api_error; } if (nargs >= 0 && nargs < DUK_HNATFUNC_NARGS_MAX) { @@ -4177,10 +4480,8 @@ goto api_error; } - obj = duk_hnatfunc_alloc(thr->heap, flags); - if (!obj) { - DUK_ERROR_ALLOC_FAILED(thr); - } + obj = duk_hnatfunc_alloc(thr, flags); + DUK_ASSERT(obj != NULL); obj->func = func; obj->nargs = func_nargs; @@ -4211,6 +4512,7 @@ flags = DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_CONSTRUCTABLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_NATFUNC | DUK_HOBJECT_FLAG_NEWENV | DUK_HOBJECT_FLAG_STRICT | @@ -4228,6 +4530,7 @@ flags = DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_CONSTRUCTABLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_NATFUNC | DUK_HOBJECT_FLAG_NEWENV | DUK_HOBJECT_FLAG_STRICT | @@ -4243,6 +4546,7 @@ DUK_ASSERT_CTX_VALID(ctx); flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_NATFUNC | DUK_HOBJECT_FLAG_NEWENV | DUK_HOBJECT_FLAG_STRICT | @@ -4259,10 +4563,7 @@ DUK_ASSERT_CTX_VALID(ctx); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); if (nargs >= DUK_LFUNC_NARGS_MIN && nargs <= DUK_LFUNC_NARGS_MAX) { /* as is */ @@ -4271,10 +4572,10 @@ } else { goto api_error; } - if (!(length >= DUK_LFUNC_LENGTH_MIN && length <= DUK_LFUNC_LENGTH_MAX)) { + if (DUK_UNLIKELY(!(length >= DUK_LFUNC_LENGTH_MIN && length <= DUK_LFUNC_LENGTH_MAX))) { goto api_error; } - if (!(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX)) { + if (DUK_UNLIKELY(!(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX))) { goto api_error; } @@ -4298,15 +4599,10 @@ DUK_ASSERT(ctx != NULL); DUK_ASSERT(prototype_bidx >= 0); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); - obj = duk_hbufobj_alloc(thr->heap, hobject_flags_and_class); - if (!obj) { - DUK_ERROR_ALLOC_FAILED(thr); - } + obj = duk_hbufobj_alloc(thr, hobject_flags_and_class); + DUK_ASSERT(obj != NULL); DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[prototype_bidx]); DUK_ASSERT_HBUFOBJ_VALID(obj); @@ -4366,19 +4662,19 @@ uint_offset = (duk_uint_t) byte_offset; uint_length = (duk_uint_t) byte_length; if (sizeof(duk_size_t) != sizeof(duk_uint_t)) { - if ((duk_size_t) uint_offset != byte_offset || (duk_size_t) uint_length != byte_length) { + if (DUK_UNLIKELY((duk_size_t) uint_offset != byte_offset || (duk_size_t) uint_length != byte_length)) { goto range_error; } } uint_added = uint_offset + uint_length; - if (uint_added < uint_offset) { + if (DUK_UNLIKELY(uint_added < uint_offset)) { goto range_error; } DUK_ASSERT(uint_added >= uint_offset && uint_added >= uint_length); DUK_ASSERT_DISABLE(flags >= 0); /* flags is unsigned */ - lookupidx = flags & 0x0f; /* 4 low bits */ - if (lookupidx >= sizeof(duk__bufobj_flags_lookup) / sizeof(duk_uint32_t)) { + lookupidx = flags; + if (DUK_UNLIKELY(lookupidx >= sizeof(duk__bufobj_flags_lookup) / sizeof(duk_uint32_t))) { goto arg_error; } tmp = duk__bufobj_flags_lookup[lookupidx]; @@ -4407,39 +4703,9 @@ /* TypedArray views need an automatic ArrayBuffer which must be * provided as .buffer property of the view. The ArrayBuffer is * referenced via duk_hbufobj->buf_prop and an inherited .buffer - * accessor returns it. - * - * The ArrayBuffer offset is always set to zero, so that if one - * accesses the ArrayBuffer at the view's .byteOffset, the value - * matches the view at index 0. - */ - if (flags & DUK_BUFOBJ_CREATE_ARRBUF) { - duk_hbufobj *h_arrbuf; - - h_arrbuf = duk_push_bufobj_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), - DUK_BIDX_ARRAYBUFFER_PROTOTYPE); - DUK_ASSERT(h_arrbuf != NULL); - - h_arrbuf->buf = h_val; - DUK_HBUFFER_INCREF(thr, h_val); - h_arrbuf->offset = 0; - h_arrbuf->length = uint_offset + uint_length; /* Wrap checked above. */ - DUK_ASSERT(h_arrbuf->shift == 0); - h_arrbuf->elem_type = DUK_HBUFOBJ_ELEM_UINT8; - DUK_ASSERT(h_arrbuf->is_typedarray == 0); - DUK_ASSERT_HBUFOBJ_VALID(h_arrbuf); - DUK_ASSERT(h_arrbuf->buf_prop == NULL); - - DUK_ASSERT(h_bufobj->buf_prop == NULL); - h_bufobj->buf_prop = (duk_hobject *) h_arrbuf; - DUK_HBUFOBJ_INCREF(thr, h_arrbuf); /* Now reachable and accounted for. */ - - duk_pop(ctx); - } - + * accessor returns it. The ArrayBuffer is created lazily on first + * access so we don't need to do anything more here. + */ return; range_error: @@ -4482,6 +4748,7 @@ proto = duk_error_prototype_from_code(thr, err_code); (void) duk_push_object_helper_proto(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR), proto); @@ -4549,18 +4816,15 @@ DUK_ASSERT_CTX_VALID(ctx); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); /* Check for maximum buffer length. */ - if (size > DUK_HBUFFER_MAX_BYTELEN) { + if (DUK_UNLIKELY(size > DUK_HBUFFER_MAX_BYTELEN)) { DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG); } h = duk_hbuffer_alloc(thr->heap, size, flags, &buf_data); - if (!h) { + if (DUK_UNLIKELY(h == NULL)) { DUK_ERROR_ALLOC_FAILED(thr); } @@ -4588,9 +4852,110 @@ return ptr; } +#if defined(DUK_USE_ASSERTIONS) +DUK_LOCAL void duk__validate_push_heapptr(duk_context *ctx, void *ptr) { + duk_heaphdr *h; + duk_heaphdr *curr; + duk_hthread *thr; + duk_bool_t found = 0; + + thr = (duk_hthread *) ctx; + h = (duk_heaphdr *) ptr; + if (h == NULL) { + /* Allowed. */ + return; + } + DUK_ASSERT(h != NULL); + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); + + /* One particular problem case is where an object has been + * queued for finalization but the finalizer hasn't yet been + * executed. + * + * Corner case: we're running in a finalizer for object X, and + * user code calls duk_push_heapptr() for X itself. In this + * case X will be in finalize_list, and we can detect the case + * by seeing that X's FINALIZED flag is set (which is done before + * the finalizer starts executing). + */ +#if defined(DUK_USE_FINALIZER_SUPPORT) + for (curr = thr->heap->finalize_list; + curr != NULL; + curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) { + /* FINALIZABLE is set for all objects on finalize_list + * except for an object being finalized right now. So + * can't assert here. + */ +#if 0 + DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(curr)); +#endif + + if (curr == h) { + if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h)) { + /* Object is currently being finalized. */ + DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ + found = 1; + } else { + /* Not being finalized but on finalize_list, + * allowed since Duktape 2.1. + */ + DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ + found = 1; + } + } + } +#endif /* DUK_USE_FINALIZER_SUPPORT */ + +#if defined(DUK_USE_REFERENCE_COUNTING) + /* Because refzero_list is now processed to completion inline with + * no side effects, it's always empty here. + */ + DUK_ASSERT(thr->heap->refzero_list == NULL); +#endif + + /* If not present in finalize_list (or refzero_list), it + * must be either in heap_allocated or the string table. + */ + if (DUK_HEAPHDR_IS_STRING(h)) { + duk_uint32_t i; + duk_hstring *str; + duk_heap *heap = thr->heap; + + DUK_ASSERT(found == 0); + for (i = 0; i < heap->st_size; i++) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + str = DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, heap->strtable16[i]); +#else + str = heap->strtable[i]; +#endif + while (str != NULL) { + if (str == (duk_hstring *) h) { + DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ + found = 1; + break; + } + str = str->hdr.h_next; + } + } + DUK_ASSERT(found != 0); + } else { + for (curr = thr->heap->heap_allocated; + curr != NULL; + curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) { + if (curr == h) { + DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ + found = 1; + } + } + DUK_ASSERT(found != 0); + } +} +#endif /* DUK_USE_ASSERTIONS */ + DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr) { duk_hthread *thr = (duk_hthread *) ctx; duk_idx_t ret; + duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); @@ -4602,43 +4967,80 @@ */ #if defined(DUK_USE_ASSERTIONS) - { - /* One particular problem case is where an object has been - * queued for finalization but the finalizer hasn't been - * executed. - */ - duk_heaphdr *curr; - for (curr = thr->heap->finalize_list; - curr != NULL; - curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) { - DUK_ASSERT(curr != (duk_heaphdr *) ptr); - } - } + duk__validate_push_heapptr(ctx, ptr); #endif + DUK__CHECK_SPACE(); + ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); + tv = thr->valstack_top++; if (ptr == NULL) { - goto push_undefined; + DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); + return ret; + } + + DUK_ASSERT_HEAPHDR_VALID((duk_heaphdr *) ptr); + + /* If the argument is on finalize_list it has technically been + * unreachable before duk_push_heapptr() but it's still safe to + * push it. Starting from Duktape 2.1 allow application code to + * do so. There are two main cases: + * + * (1) The object is on the finalize_list and we're called by + * the finalizer for the object being finalized. In this + * case do nothing: finalize_list handling will deal with + * the object queueing. This is detected by the object not + * having a FINALIZABLE flag despite being on the finalize_list; + * the flag is cleared for the object being finalized only. + * + * (2) The object is on the finalize_list but is not currently + * being processed. In this case the object can be queued + * back to heap_allocated with a few flags cleared, in effect + * cancelling the finalizer. + */ + if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) ptr))) { + duk_heaphdr *curr; + + DUK_D(DUK_DPRINT("duk_push_heapptr() with a pointer on finalize_list, autorescue")); + + curr = (duk_heaphdr *) ptr; + DUK_HEAPHDR_CLEAR_FINALIZABLE(curr); + + /* Because FINALIZED is set prior to finalizer call, it will + * be set for the object being currently finalized, but not + * for other objects on finalize_list. + */ + DUK_HEAPHDR_CLEAR_FINALIZED(curr); + + /* Dequeue object from finalize_list and queue it back to + * heap_allocated. + */ +#if defined(DUK_USE_REFERENCE_COUNTING) + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) >= 1); /* Preincremented on finalize_list insert. */ + DUK_HEAPHDR_PREDEC_REFCOUNT(curr); +#endif + DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(thr->heap, curr); + DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(thr->heap, curr); + + /* Continue with the rest. */ } switch (DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) { case DUK_HTYPE_STRING: - duk_push_hstring(ctx, (duk_hstring *) ptr); + DUK_TVAL_SET_STRING(tv, (duk_hstring *) ptr); break; case DUK_HTYPE_OBJECT: - duk_push_hobject(ctx, (duk_hobject *) ptr); - break; - case DUK_HTYPE_BUFFER: - duk_push_hbuffer(ctx, (duk_hbuffer *) ptr); + DUK_TVAL_SET_OBJECT(tv, (duk_hobject *) ptr); break; default: - goto push_undefined; + DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr) == DUK_HTYPE_BUFFER); + DUK_TVAL_SET_BUFFER(tv, (duk_hbuffer *) ptr); + break; } - return ret; - push_undefined: - duk_push_undefined(ctx); + DUK_HEAPHDR_INCREF(thr, (duk_heaphdr *) ptr); + return ret; } @@ -4646,6 +5048,7 @@ DUK_EXTERNAL duk_idx_t duk_push_bare_object(duk_context *ctx) { (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), -1); /* no prototype */ return duk_get_top_index_unsafe(ctx); @@ -4709,28 +5112,52 @@ #endif DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); if (DUK_UNLIKELY(count < 0)) { DUK_ERROR_RANGE_INVALID_COUNT(thr); return; } - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); if (DUK_UNLIKELY((duk_size_t) (thr->valstack_top - thr->valstack_bottom) < (duk_size_t) count)) { DUK_ERROR_RANGE_INVALID_COUNT(thr); } - /* - * Must be very careful here, every DECREF may cause reallocation - * of our valstack. - */ +#if defined(DUK_USE_REFERENCE_COUNTING) + tv = thr->valstack_top; + tv_end = tv - count; + while (tv != tv_end) { + tv--; + DUK_ASSERT(tv >= thr->valstack_bottom); + DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv); + } + thr->valstack_top = tv; + DUK_REFZERO_CHECK_FAST(thr); +#else + tv = thr->valstack_top; + while (count > 0) { + count--; + tv--; + DUK_ASSERT(tv >= thr->valstack_bottom); + DUK_TVAL_SET_UNDEFINED(tv); + } + thr->valstack_top = tv; +#endif - /* XXX: inlined DECREF macro would be nice here: no NULL check, - * refzero queueing but no refzero algorithm run (= no pointer - * instability), inline code. - */ + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); +} + +DUK_INTERNAL void duk_pop_n_unsafe(duk_context *ctx, duk_idx_t count) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; +#if defined(DUK_USE_REFERENCE_COUNTING) + duk_tval *tv_end; +#endif - /* XXX: optimize loops */ + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(count >= 0); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count); #if defined(DUK_USE_REFERENCE_COUNTING) tv = thr->valstack_top; @@ -4756,6 +5183,34 @@ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); } +/* Pop N elements without DECREF (in effect "stealing" the refcounts). */ +#if defined(DUK_USE_REFERENCE_COUNTING) +DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_context *ctx, duk_idx_t count) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(count >= 0); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count); + + tv = thr->valstack_top; + while (count > 0) { + count--; + tv--; + DUK_ASSERT(tv >= thr->valstack_bottom); + DUK_TVAL_SET_UNDEFINED(tv); + } + thr->valstack_top = tv; + + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); +} +#else /* DUK_USE_REFERENCE_COUNTING */ +DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_context *ctx, duk_idx_t count) { + duk_pop_n_unsafe(ctx, count); +} +#endif /* DUK_USE_REFERENCE_COUNTING */ + /* Popping one element is called so often that when footprint is not an issue, * compile a specialized function for it. */ @@ -4792,16 +5247,17 @@ #if defined(DUK_USE_PREFER_SIZE) DUK_INTERNAL void duk_pop_unsafe(duk_context *ctx) { DUK_ASSERT_CTX_VALID(ctx); - duk_pop_n(ctx, 1); + duk_pop_n_unsafe(ctx, 1); } #else DUK_INTERNAL void duk_pop_unsafe(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; - DUK_ASSERT_CTX_VALID(ctx); - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(thr->valstack_top != thr->valstack_bottom); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1); tv = --thr->valstack_top; /* tv points to element just below prev top */ DUK_ASSERT(tv >= thr->valstack_bottom); @@ -4810,6 +5266,7 @@ #else DUK_TVAL_SET_UNDEFINED(tv); #endif + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); } #endif /* !DUK_USE_PREFER_SIZE */ @@ -4842,7 +5299,7 @@ thr = (duk_hthread *) ctx; top = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); - if (count < 0 || count > top) { + if (DUK_UNLIKELY(count < 0 || count > top)) { DUK_ERROR_RANGE_INVALID_COUNT(thr); return; } @@ -4905,12 +5362,13 @@ DUK_EXTERNAL void duk_throw_raw(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv_val; DUK_ASSERT(thr->valstack_bottom >= thr->valstack); DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); DUK_ASSERT(thr->valstack_end >= thr->valstack_top); - if (thr->valstack_top == thr->valstack_bottom) { + if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) { DUK_ERROR_TYPE_INVALID_ARGS(thr); } @@ -4931,7 +5389,11 @@ #endif DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (after throw augment)", (duk_tval *) duk_get_tval(ctx, -1))); - duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW); + tv_val = DUK_GET_TVAL_NEGIDX(ctx, -1); + duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, tv_val); +#if defined(DUK_USE_DEBUGGER_SUPPORT) + duk_err_check_debugger_integration(thr); +#endif /* thr->heap->lj.jmpbuf_ptr is checked by duk_err_longjmp() so we don't * need to check that here. If the value is NULL, a fatal error occurs @@ -5075,7 +5537,7 @@ return duk_js_strict_equals(tv1, tv2); } -DUK_EXTERNAL_DECL duk_bool_t duk_samevalue(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) { +DUK_EXTERNAL duk_bool_t duk_samevalue(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) { duk_tval *tv1, *tv2; DUK_ASSERT_CTX_VALID(ctx); diff -Nru duktape-2.0.0/src-input/duk_api_string.c duktape-2.1.1/src-input/duk_api_string.c --- duktape-2.0.0/src-input/duk_api_string.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_api_string.c 2017-07-28 22:05:08.000000000 +0000 @@ -194,6 +194,7 @@ duk_hstring *res; duk_size_t start_byte_offset; duk_size_t end_byte_offset; + duk_size_t charlen; DUK_ASSERT_CTX_VALID(ctx); @@ -201,8 +202,9 @@ h = duk_require_hstring(ctx, idx); DUK_ASSERT(h != NULL); - if (end_offset >= DUK_HSTRING_GET_CHARLEN(h)) { - end_offset = DUK_HSTRING_GET_CHARLEN(h); + charlen = DUK_HSTRING_GET_CHARLEN(h); + if (end_offset >= charlen) { + end_offset = charlen; } if (start_offset > end_offset) { start_offset = end_offset; @@ -224,9 +226,9 @@ DUK_ASSERT(end_byte_offset - start_byte_offset <= DUK_UINT32_MAX); /* Guaranteed by string limits. */ /* No size check is necessary. */ - res = duk_heap_string_intern_checked(thr, - DUK_HSTRING_GET_DATA(h) + start_byte_offset, - (duk_uint32_t) (end_byte_offset - start_byte_offset)); + 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(ctx, res); duk_replace(ctx, idx); diff -Nru duktape-2.0.0/src-input/duk_bi_buffer.c duktape-2.1.1/src-input/duk_bi_buffer.c --- duktape-2.0.0/src-input/duk_bi_buffer.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_bi_buffer.c 2017-07-28 22:05:08.000000000 +0000 @@ -248,26 +248,6 @@ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); } -DUK_LOCAL duk_hbufobj *duk__push_arraybuffer_with_length(duk_context *ctx, duk_uint_t len) { - duk_hbuffer *h_val; - duk_hbufobj *h_bufobj; - - (void) duk_push_fixed_buffer_zero(ctx, (duk_size_t) len); - h_val = (duk_hbuffer *) duk_known_hbuffer(ctx, -1); - - h_bufobj = duk_push_bufobj_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), - DUK_BIDX_ARRAYBUFFER_PROTOTYPE); - DUK_ASSERT(h_bufobj != NULL); - - duk__set_bufobj_buffer(ctx, h_bufobj, h_val); - DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); - - return h_bufobj; -} - /* Shared offset/length coercion helper. */ DUK_LOCAL void duk__resolve_offset_opt_length(duk_context *ctx, duk_hbufobj *h_bufarg, @@ -721,7 +701,6 @@ duk_tval *tv; duk_hobject *h_obj; duk_hbufobj *h_bufobj = NULL; - duk_hbufobj *h_bufarr = NULL; duk_hbufobj *h_bufarg = NULL; duk_hbuffer *h_val; duk_small_uint_t magic; @@ -934,15 +913,17 @@ /* ArrayBuffer argument is handled specially above; the rest of the * argument variants are handled by shared code below. + * + * ArrayBuffer in h_bufobj->buf_prop is intentionally left unset. + * It will be automatically created by the .buffer accessor on + * first access. */ - /* Push a new ArrayBuffer (becomes view .buffer) */ - h_bufarr = duk__push_arraybuffer_with_length(ctx, byte_length); - DUK_ASSERT(h_bufarr != NULL); - h_val = h_bufarr->buf; + /* Push the resulting view object on top of a plain fixed buffer. */ + (void) duk_push_fixed_buffer(ctx, byte_length); + h_val = duk_known_hbuffer(ctx, -1); DUK_ASSERT(h_val != NULL); - /* Push the resulting view object and attach the ArrayBuffer. */ h_bufobj = duk_push_bufobj_raw(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_BUFOBJ | @@ -958,12 +939,6 @@ h_bufobj->is_typedarray = 1; DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); - /* Set .buffer */ - DUK_ASSERT(h_bufobj->buf_prop == NULL); - h_bufobj->buf_prop = (duk_hobject *) h_bufarr; - DUK_ASSERT(h_bufarr != NULL); - DUK_HBUFOBJ_INCREF(thr, h_bufarr); - /* Copy values, the copy method depends on the arguments. * * Copy mode decision may depend on the validity of the underlying @@ -1681,7 +1656,7 @@ } duk_hbufobj_promote_plain(ctx, 0); - h_obj = duk_known_hobject(ctx, 0); + h_obj = duk_require_hobject(ctx, 0); /* XXX: V8 throws a TypeError for negative values. Would it * be more useful to interpret negative offsets here from the @@ -2071,7 +2046,7 @@ res_proto_bidx); DUK_ASSERT(h_bufobj != NULL); - h_bufobj->length = slice_length; + DUK_ASSERT(h_bufobj->length == 0); h_bufobj->shift = h_this->shift; /* inherit */ h_bufobj->elem_type = h_this->elem_type; /* inherit */ h_bufobj->is_typedarray = magic & 0x01; @@ -2102,12 +2077,14 @@ h_bufobj->buf = h_val; DUK_HBUFFER_INCREF(thr, h_val); + h_bufobj->length = slice_length; DUK_ASSERT(h_bufobj->offset == 0); duk_pop(ctx); /* reachable so pop OK */ } else { h_bufobj->buf = h_val; DUK_HBUFFER_INCREF(thr, h_val); + h_bufobj->length = slice_length; h_bufobj->offset = (duk_uint_t) (h_this->offset + start_offset); /* Copy the .buffer property, needed for TypedArray.prototype.subarray(). @@ -2878,30 +2855,63 @@ */ #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_LOCAL duk_hbufobj *duk__autospawn_arraybuffer(duk_context *ctx, duk_hbuffer *h_buf) { + duk_hbufobj *h_res; + + h_res = duk_push_bufobj_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFOBJ | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), + DUK_BIDX_ARRAYBUFFER_PROTOTYPE); + DUK_ASSERT(h_res != NULL); + DUK_UNREF(h_res); + + duk__set_bufobj_buffer(ctx, h_res, h_buf); + DUK_ASSERT_HBUFOBJ_VALID(h_res); + DUK_ASSERT(h_res->buf_prop == NULL); + return h_res; +} + DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_context *ctx) { duk_hbufobj *h_bufobj; h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(ctx, DUK__BUFOBJ_FLAG_THROW /*flags*/); DUK_ASSERT(h_bufobj != NULL); if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) { - duk_hbufobj *h_res; - duk_hbuffer *h_buf; - - h_buf = (duk_hbuffer *) h_bufobj; - h_res = duk_push_bufobj_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), - DUK_BIDX_ARRAYBUFFER_PROTOTYPE); - DUK_ASSERT(h_res != NULL); - DUK_UNREF(h_res); - - duk__set_bufobj_buffer(ctx, h_res, h_buf); - DUK_ASSERT_HBUFOBJ_VALID(h_res); - - DUK_DD(DUK_DDPRINT("autospawned .buffer ArrayBuffer: %!iT", duk_get_tval(ctx, -1))); + DUK_DD(DUK_DDPRINT("autospawn ArrayBuffer for plain buffer")); + (void) duk__autospawn_arraybuffer(ctx, (duk_hbuffer *) h_bufobj); return 1; } else { + if (h_bufobj->buf_prop == NULL && + DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_bufobj) != DUK_HOBJECT_CLASS_ARRAYBUFFER && + h_bufobj->buf != NULL) { + duk_hbufobj *h_arrbuf; + + DUK_DD(DUK_DDPRINT("autospawn ArrayBuffer for typed array or DataView")); + h_arrbuf = duk__autospawn_arraybuffer(ctx, h_bufobj->buf); + + if (h_bufobj->buf_prop == NULL) { + /* Must recheck buf_prop, in case ArrayBuffer + * alloc had a side effect which already filled + * it! + */ + + /* Set ArrayBuffer's .byteOffset and .byteLength based + * on the view so that Arraybuffer[view.byteOffset] + * matches view[0]. + */ + h_arrbuf->offset = 0; + DUK_ASSERT(h_bufobj->offset + h_bufobj->length >= h_bufobj->offset); /* Wrap check on creation. */ + h_arrbuf->length = h_bufobj->offset + h_bufobj->length; + DUK_ASSERT(h_arrbuf->buf_prop == NULL); + + DUK_ASSERT(h_bufobj->buf_prop == NULL); + h_bufobj->buf_prop = (duk_hobject *) h_arrbuf; + DUK_HBUFOBJ_INCREF(thr, h_arrbuf); /* Now reachable and accounted for. */ + } + + /* Left on stack; pushed for the second time below (OK). */ + } if (h_bufobj->buf_prop) { duk_push_hobject(ctx, h_bufobj->buf_prop); return 1; diff -Nru duktape-2.0.0/src-input/duk_bi_date.c duktape-2.1.1/src-input/duk_bi_date.c --- duktape-2.0.0/src-input/duk_bi_date.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_bi_date.c 2017-07-28 22:05:08.000000000 +0000 @@ -1421,6 +1421,7 @@ (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATE), DUK_BIDX_DATE_PROTOTYPE); diff -Nru duktape-2.0.0/src-input/duk_bi_date_unix.c duktape-2.1.1/src-input/duk_bi_date_unix.c --- duktape-2.0.0/src-input/duk_bi_date_unix.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_bi_date_unix.c 2017-07-28 22:05:08.000000000 +0000 @@ -171,7 +171,7 @@ * an mktime() error return is the cast above. See e.g.: * http://pubs.opengroup.org/onlinepubs/009695299/functions/mktime.html */ - goto error; + goto mktime_error; } DUK_DDD(DUK_DDDPRINT("t1=%ld (utc), t2=%ld (local)", (long) t1, (long) t2)); @@ -187,7 +187,7 @@ #endif return (duk_int_t) difftime(t2, t1); - error: + mktime_error: /* XXX: return something more useful, so that caller can throw? */ DUK_D(DUK_DPRINT("mktime() failed, d=%lf", (double) d)); return 0; diff -Nru duktape-2.0.0/src-input/duk_bi_date_windows.c duktape-2.1.1/src-input/duk_bi_date_windows.c --- duktape-2.0.0/src-input/duk_bi_date_windows.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_bi_date_windows.c 2017-07-28 22:05:08.000000000 +0000 @@ -96,3 +96,35 @@ return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000000LL); /* seconds */ } #endif /* DUK_USE_DATE_TZO_WINDOWS */ + +#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) { + 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; + FileTimeToLocalFileTime((const FILETIME *) &ft1, &ft2); + + FileTimeToSystemTime((const FILETIME *) &ft2, &st2); + duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2); + + return (duk_int_t) (((LONGLONG) tmp2.QuadPart - (LONGLONG) tmp1.QuadPart) / 10000000LL); /* seconds */ +} +#endif /* DUK_USE_DATE_TZO_WINDOWS_NO_DST */ diff -Nru duktape-2.0.0/src-input/duk_bi_duktape.c duktape-2.1.1/src-input/duk_bi_duktape.c --- duktape-2.0.0/src-input/duk_bi_duktape.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_bi_duktape.c 2017-07-28 22:05:08.000000000 +0000 @@ -29,15 +29,14 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_small_uint_t flags; - duk_bool_t rc; flags = (duk_small_uint_t) duk_get_uint(ctx, 0); - rc = duk_heap_mark_and_sweep(thr->heap, flags); + duk_heap_mark_and_sweep(thr->heap, flags); /* XXX: Not sure what the best return value would be in the API. - * Return a boolean for now. Note that rc == 0 is success (true). + * Return true for now. */ - duk_push_boolean(ctx, !rc); + duk_push_true(ctx); return 1; } @@ -49,15 +48,16 @@ * 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. + * be deleted. Must use duk_set_finalizer() to keep + * DUK_HOBJECT_FLAG_HAVE_FINALIZER in sync. */ duk_set_top(ctx, 2); - (void) duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_INT_FINALIZER); + duk_set_finalizer(ctx, 0); return 0; } else { /* Get. */ DUK_ASSERT(duk_get_top(ctx) == 1); - duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_INT_FINALIZER); + duk_get_finalizer(ctx, 0); return 1; } } diff -Nru duktape-2.0.0/src-input/duk_bi_encoding.c duktape-2.1.1/src-input/duk_bi_encoding.c --- duktape-2.0.0/src-input/duk_bi_encoding.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_bi_encoding.c 2017-07-28 22:05:08.000000000 +0000 @@ -143,6 +143,7 @@ } } +#if defined(DUK_USE_ENCODING_BUILTINS) DUK_LOCAL void duk__utf8_encode_char(void *udata, duk_codepoint_t codepoint) { duk__encode_context *enc_ctx; @@ -197,6 +198,7 @@ */ enc_ctx->out += duk_unicode_encode_xutf8(codepoint, enc_ctx->out); } +#endif /* DUK_USE_ENCODING_BUILTINS */ /* Shared helper for buffer-to-string using a TextDecoder() compatible UTF-8 * decoder. @@ -360,7 +362,6 @@ DUK_ASSERT_TOP(ctx, 1); if (duk_is_undefined(ctx, 0)) { len = 0; - final_len = len; } else { duk_hstring *h_input; @@ -418,6 +419,8 @@ final_len = (duk_size_t) (enc_ctx.out - output); duk_resize_buffer(ctx, -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 @@ -458,8 +461,8 @@ * initialized explicitly. */ dec_ctx = (duk__decode_context *) duk_push_fixed_buffer(ctx, sizeof(duk__decode_context)); - dec_ctx->fatal = fatal; - dec_ctx->ignore_bom = ignore_bom; + 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_string(ctx, -2, "\xff" "Context"); diff -Nru duktape-2.0.0/src-input/duk_bi_error.c duktape-2.1.1/src-input/duk_bi_error.c --- duktape-2.0.0/src-input/duk_bi_error.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_bi_error.c 2017-07-28 22:05:08.000000000 +0000 @@ -17,6 +17,7 @@ /* 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); DUK_UNREF(thr); diff -Nru duktape-2.0.0/src-input/duk_bi_function.c duktape-2.1.1/src-input/duk_bi_function.c --- duktape-2.0.0/src-input/duk_bi_function.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_bi_function.c 2017-07-28 22:05:08.000000000 +0000 @@ -61,7 +61,7 @@ DUK_ASSERT_TOP(ctx, 3); /* strictness is not inherited, intentional */ - comp_flags = DUK_JS_COMPILE_FLAG_FUNCEXPR; + comp_flags = DUK_COMPILE_FUNCEXPR; duk_push_hstring_stridx(ctx, DUK_STRIDX_COMPILE); /* XXX: copy from caller? */ /* XXX: ignored now */ h_sourcecode = duk_require_hstring(ctx, -2); /* no symbol check needed; -2 is concat'd code */ @@ -202,6 +202,7 @@ /* XXX: [[Construct]] newTarget currently unsupported */ DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx); } + duk_set_top(ctx, 2); /* chop off extra arguments: [ constructor argArray ] */ idx_args = 1; break; } @@ -332,6 +333,7 @@ /* create bound function object */ h_bound = duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_BOUNDFUNC | DUK_HOBJECT_FLAG_CONSTRUCTABLE | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION), diff -Nru duktape-2.0.0/src-input/duk_bi_global.c duktape-2.1.1/src-input/duk_bi_global.c --- duktape-2.0.0/src-input/duk_bi_global.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_bi_global.c 2017-07-28 22:05:08.000000000 +0000 @@ -431,7 +431,8 @@ DUK_ASSERT(duk_get_top(ctx) == 1 || duk_get_top(ctx) == 2); /* 2 when called by debugger */ DUK_ASSERT(thr->callstack_top >= 1); /* at least this function exists */ - DUK_ASSERT(((thr->callstack + thr->callstack_top - 1)->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0 || /* indirect eval */ + 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 */ /* @@ -461,8 +462,9 @@ /* [ source ] */ - comp_flags = DUK_JS_COMPILE_FLAG_EVAL; - act_eval = thr->callstack + thr->callstack_top - 1; /* this function */ + comp_flags = DUK_COMPILE_EVAL; + act_eval = thr->callstack_curr; /* this function */ + DUK_ASSERT(act_eval != NULL); if (thr->callstack_top >= (duk_size_t) -level) { /* Have a calling activation, check for direct eval (otherwise * assume indirect eval. @@ -473,7 +475,7 @@ /* Only direct eval inherits strictness from calling code * (E5.1 Section 10.1.1). */ - comp_flags |= DUK_JS_COMPILE_FLAG_STRICT; + comp_flags |= DUK_COMPILE_STRICT; } } else { DUK_ASSERT((act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0); @@ -493,7 +495,7 @@ /* E5 Section 10.4.2 */ DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; /* this function */ + act = thr->callstack_curr; /* this function */ if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) { DUK_ASSERT(thr->callstack_top >= 2); act = thr->callstack + thr->callstack_top + level; /* caller */ @@ -511,26 +513,29 @@ this_to_global = 0; if (DUK_HOBJECT_HAS_STRICT((duk_hobject *) func)) { - duk_hobject *new_env; + 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 = thr->callstack + thr->callstack_top + level; /* caller */ act_lex_env = act->lex_env; act = NULL; /* invalidated */ - new_env = duk_push_object_helper_proto(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), - act_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(ctx, (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 = new_env; - outer_var_env = new_env; + outer_lex_env = (duk_hobject *) new_env; + outer_var_env = (duk_hobject *) new_env; duk_insert(ctx, 0); /* stash to bottom of value stack to keep new_env reachable for duration of eval */ @@ -560,7 +565,7 @@ /* 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*/); - /* [ source template closure ] */ + /* [ env? source template closure ] */ if (this_to_global) { DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); @@ -579,11 +584,11 @@ (duk_heaphdr *) outer_var_env, duk_get_tval(ctx, -1))); - /* [ source template closure this ] */ + /* [ env? source template closure this ] */ duk_call_method(ctx, 0); - /* [ source template result ] */ + /* [ env? source template result ] */ return 1; } diff -Nru duktape-2.0.0/src-input/duk_bi_json.c duktape-2.1.1/src-input/duk_bi_json.c --- duktape-2.0.0/src-input/duk_bi_json.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_bi_json.c 2017-07-28 22:05:08.000000000 +0000 @@ -73,12 +73,15 @@ DUK_LOCAL_DECL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv); #endif #if defined(DUK_USE_JX) || defined(DUK_USE_JC) -DUK_LOCAL_DECL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h); +DUK_LOCAL_DECL void duk__enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h); DUK_LOCAL_DECL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr); #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) DUK_LOCAL_DECL void duk__enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj); #endif #endif +#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) +DUK_LOCAL_DECL void duk__enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h); +#endif DUK_LOCAL_DECL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth); /* @@ -1558,13 +1561,60 @@ DUK_BW_SET_PTR(thr, &js_ctx->bw, q); } -DUK_LOCAL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) { +DUK_LOCAL void duk__enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) { duk__enc_buffer_data(js_ctx, (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h), (duk_size_t) DUK_HBUFFER_GET_SIZE(h)); } #endif /* DUK_USE_JX || DUK_USE_JC */ +#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) +DUK_LOCAL void duk__enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) { + duk_size_t i, n; + const duk_uint8_t *buf; + duk_uint8_t *q; + + n = DUK_HBUFFER_GET_SIZE(h); + if (n == 0) { + DUK__EMIT_2(js_ctx, DUK_ASC_LCURLY, DUK_ASC_RCURLY); + return; + } + + DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY); + + /* Maximum encoded length with 32-bit index: 1 + 10 + 2 + 3 + 1 + 1 = 18, + * with 64-bit index: 1 + 20 + 2 + 3 + 1 + 1 = 28. 32 has some spare. + * + * Note that because the output buffer is reallocated from time to time, + * side effects (such as finalizers) affecting the buffer 'h' must be + * disabled. This is the case in the JSON.stringify() fast path. + */ + + buf = (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h); + if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { + for (i = 0; i < n; i++) { + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth + 1); + q = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, 32); + q += DUK_SPRINTF((char *) q, "\"%lu\": %u,", (unsigned long) i, (unsigned int) buf[i]); + DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, q); + } + } else { + q = DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw); + for (i = 0; i < n; i++) { + q = DUK_BW_ENSURE_RAW(js_ctx->thr, &js_ctx->bw, 32, q); + q += DUK_SPRINTF((char *) q, "\"%lu\":%u,", (unsigned long) i, (unsigned int) buf[i]); + } + DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, q); + } + DUK__UNEMIT_1(js_ctx); /* eat trailing comma */ + + if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth); + } + DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY); +} +#endif /* DUK_USE_JSON_STRINGIFY_FASTPATH */ + #if defined(DUK_USE_JX) || defined(DUK_USE_JC) DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) { char buf[64]; /* XXX: how to figure correct size? */ @@ -2114,7 +2164,7 @@ case DUK_TAG_STRING: { duk_hstring *h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { goto pop2_undef; } duk__enc_quote_string(js_ctx, h); @@ -2145,12 +2195,13 @@ case DUK_TAG_BUFFER: { #if defined(DUK_USE_JX) || defined(DUK_USE_JC) if (js_ctx->flag_ext_custom_or_compatible) { - duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv)); + duk__enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv)); break; } #endif - /* Could implement a fast path, but object coerce and - * serialize the result for now. + + /* Could implement a fastpath, but the fast path would need + * to handle realloc side effects correctly. */ duk_to_object(ctx, -1); duk__enc_object(js_ctx); @@ -2210,7 +2261,7 @@ duk_hstring *h; h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { return 0; } return 1; @@ -2279,7 +2330,7 @@ duk_hstring *h; h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { goto emit_undefined; } duk__enc_quote_string(js_ctx, h); @@ -2444,7 +2495,7 @@ DUK_DD(DUK_DDPRINT("property is an accessor, abort fast path")); goto abort_fastpath; } - if (DUK_HSTRING_HAS_SYMBOL(k)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(k))) { continue; } @@ -2638,13 +2689,16 @@ #if defined(DUK_USE_JX) || defined(DUK_USE_JC) if (js_ctx->flag_ext_custom_or_compatible) { - duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv)); + duk__enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv)); break; } #endif - /* Could implement a fast path, but abort fast path for now. */ - DUK_DD(DUK_DDPRINT("value is a plain buffer and serializing as plain JSON, abort fast path")); - goto abort_fastpath; + + /* Plain buffers mimic Uint8Arrays, and have enumerable index + * properties. + */ + duk__enc_buffer_json_fastpath(js_ctx, DUK_TVAL_GET_BUFFER(tv)); + break; } case DUK_TAG_POINTER: { #if defined(DUK_USE_JX) || defined(DUK_USE_JC) @@ -3041,8 +3095,11 @@ } if (js_ctx->h_gap != NULL) { - /* if gap is empty, behave as if not given at all */ - if (DUK_HSTRING_GET_CHARLEN(js_ctx->h_gap) == 0) { + /* If gap is empty, behave as if not given at all. Check + * against byte length because character length is more + * expensive. + */ + if (DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) == 0) { js_ctx->h_gap = NULL; } } @@ -3058,7 +3115,7 @@ if (js_ctx->h_replacer == NULL && /* replacer is a mutation risk */ js_ctx->idx_proplist == -1) { /* proplist is very rare */ duk_int_t pcall_rc; - duk_small_uint_t prev_mark_and_sweep_base_flags; + duk_small_uint_t prev_ms_base_flags; DUK_DD(DUK_DDPRINT("try JSON.stringify() fast path")); @@ -3080,14 +3137,17 @@ duk_dup(ctx, idx_value); /* Must prevent finalizers which may have arbitrary side effects. */ - prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags; - thr->heap->mark_and_sweep_base_flags |= - DUK_MS_FLAG_NO_FINALIZERS | /* avoid attempts to add/remove object keys */ - DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid attempt to compact any objects */ + prev_ms_base_flags = thr->heap->ms_base_flags; + thr->heap->ms_base_flags |= + DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* Avoid attempt to compact any objects. */ + thr->heap->pf_prevent_count++; /* Prevent finalizers. */ + DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */ pcall_rc = duk_safe_call(ctx, duk__json_stringify_fast, (void *) js_ctx /*udata*/, 1 /*nargs*/, 0 /*nret*/); - thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; + DUK_ASSERT(thr->heap->pf_prevent_count > 0); + thr->heap->pf_prevent_count--; + thr->heap->ms_base_flags = prev_ms_base_flags; if (pcall_rc == DUK_EXEC_SUCCESS) { DUK_DD(DUK_DDPRINT("fast path successful")); diff -Nru duktape-2.0.0/src-input/duk_bi_object.c duktape-2.1.1/src-input/duk_bi_object.c --- duktape-2.0.0/src-input/duk_bi_object.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_bi_object.c 2017-07-28 22:05:08.000000000 +0000 @@ -50,6 +50,7 @@ (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), DUK_BIDX_OBJECT_PROTOTYPE); return 1; @@ -112,6 +113,7 @@ (void) duk_push_object_helper_proto(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), proto); diff -Nru duktape-2.0.0/src-input/duk_bi_pointer.c duktape-2.1.1/src-input/duk_bi_pointer.c --- duktape-2.0.0/src-input/duk_bi_pointer.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_bi_pointer.c 2017-07-28 22:05:08.000000000 +0000 @@ -24,6 +24,7 @@ if (duk_is_constructor_call(ctx)) { (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER), DUK_BIDX_POINTER_PROTOTYPE); diff -Nru duktape-2.0.0/src-input/duk_bi_protos.h duktape-2.1.1/src-input/duk_bi_protos.h --- duktape-2.0.0/src-input/duk_bi_protos.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_bi_protos.h 2017-07-28 22:05:08.000000000 +0000 @@ -37,6 +37,9 @@ #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_context *ctx, const char *str); #endif diff -Nru duktape-2.0.0/src-input/duk_bi_proxy.c duktape-2.1.1/src-input/duk_bi_proxy.c --- duktape-2.0.0/src-input/duk_bi_proxy.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_bi_proxy.c 2017-07-28 22:05:08.000000000 +0000 @@ -46,7 +46,7 @@ goto skip_key; } } - if (DUK_HSTRING_HAS_SYMBOL(h)) { + 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(ctx, -1))); goto skip_key; @@ -123,6 +123,7 @@ */ (void) duk_push_object_helper_proto(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), NULL); diff -Nru duktape-2.0.0/src-input/duk_bi_string.c duktape-2.1.1/src-input/duk_bi_string.c --- duktape-2.0.0/src-input/duk_bi_string.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_bi_string.c 2017-07-28 22:05:08.000000000 +0000 @@ -20,6 +20,96 @@ #if defined(DUK_USE_STRING_BUILTIN) /* + * Helpers + */ + +DUK_LOCAL duk_hstring *duk__str_tostring_notregexp(duk_context *ctx, duk_idx_t idx) { + duk_hstring *h; + + if (duk_get_class_number(ctx, idx) == DUK_HOBJECT_CLASS_REGEXP) { + DUK_ERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx); + } + h = duk_to_hstring(ctx, idx); + DUK_ASSERT(h != NULL); + + return h; +} + +DUK_LOCAL duk_int_t duk__str_search_shared(duk_context *ctx, duk_hstring *h_this, duk_hstring *h_search, duk_int_t start_cpos, duk_bool_t backwards) { + duk_int_t cpos; + duk_int_t bpos; + const duk_uint8_t *p_start, *p_end, *p; + const duk_uint8_t *q_start; + duk_int_t q_blen; + duk_uint8_t firstbyte; + duk_uint8_t t; + + cpos = start_cpos; + + /* Empty searchstring always matches; cpos must be clamped here. + * (If q_blen were < 0 due to clamped coercion, it would also be + * caught here.) + */ + q_start = DUK_HSTRING_GET_DATA(h_search); + q_blen = (duk_int_t) DUK_HSTRING_GET_BYTELEN(h_search); + if (q_blen <= 0) { + return cpos; + } + DUK_ASSERT(q_blen > 0); + + bpos = (duk_int_t) duk_heap_strcache_offset_char2byte((duk_hthread *) ctx, h_this, (duk_uint32_t) cpos); + + p_start = DUK_HSTRING_GET_DATA(h_this); + p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_this); + p = p_start + bpos; + + /* This loop is optimized for size. For speed, there should be + * two separate loops, and we should ensure that memcmp() can be + * used without an extra "will searchstring fit" check. Doing + * the preconditioning for 'p' and 'p_end' is easy but cpos + * must be updated if 'p' is wound back (backward scanning). + */ + + firstbyte = q_start[0]; /* leading byte of match string */ + while (p <= p_end && p >= p_start) { + t = *p; + + /* For Ecmascript strings, this check can only match for + * initial UTF-8 bytes (not continuation bytes). For other + * strings all bets are off. + */ + + if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= (duk_size_t) q_blen)) { + DUK_ASSERT(q_blen > 0); /* no issues with memcmp() zero size, even if broken */ + if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { + return cpos; + } + } + + /* track cpos while scanning */ + if (backwards) { + /* when going backwards, we decrement cpos 'early'; + * 'p' may point to a continuation byte of the char + * at offset 'cpos', but that's OK because we'll + * backtrack all the way to the initial byte. + */ + if ((t & 0xc0) != 0x80) { + cpos--; + } + p--; + } else { + if ((t & 0xc0) != 0x80) { + cpos++; + } + p++; + } + } + + /* Not found. Empty string case is handled specially above. */ + return -1; +} + +/* * Constructor */ @@ -41,7 +131,7 @@ duk_push_hstring_empty(ctx); } else { h = duk_to_hstring_acceptsymbol(ctx, 0); - if (DUK_HSTRING_HAS_SYMBOL(h) && !duk_is_constructor_call(ctx)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h) && !duk_is_constructor_call(ctx))) { duk_push_symbol_descriptive_string(ctx, h); duk_replace(ctx, 0); } @@ -53,6 +143,7 @@ if (duk_is_constructor_call(ctx)) { /* String object internal value is immutable */ flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING); duk_push_object_helper(ctx, flags, DUK_BIDX_STRING_PROTOTYPE); @@ -202,7 +293,7 @@ pos = duk_to_int_clamped_raw(ctx, 0 /*index*/, 0 /*min(incl)*/, - DUK_HSTRING_GET_CHARLEN(h) - 1 /*max(incl)*/, + (duk_int_t) DUK_HSTRING_GET_CHARLEN(h) - 1 /*max(incl)*/, &clamped /*out_clamped*/); #if defined(DUK_USE_ES6) magic = duk_get_current_magic(ctx); @@ -364,17 +455,10 @@ */ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx) { - duk_hthread *thr = (duk_hthread *) ctx; duk_hstring *h_this; duk_hstring *h_search; duk_int_t clen_this; duk_int_t cpos; - duk_int_t bpos; - const duk_uint8_t *p_start, *p_end, *p; - const duk_uint8_t *q_start; - duk_int_t q_blen; - duk_uint8_t firstbyte; - duk_uint8_t t; duk_small_int_t is_lastindexof = duk_get_current_magic(ctx); /* 0=indexOf, 1=lastIndexOf */ h_this = duk_push_this_coercible_to_string(ctx); @@ -383,8 +467,6 @@ h_search = duk_to_hstring(ctx, 0); DUK_ASSERT(h_search != NULL); - q_start = DUK_HSTRING_GET_DATA(h_search); - q_blen = (duk_int_t) DUK_HSTRING_GET_BYTELEN(h_search); duk_to_number(ctx, 1); if (duk_is_nan(ctx, 1) && is_lastindexof) { @@ -397,67 +479,8 @@ cpos = duk_to_int_clamped(ctx, 1, 0, clen_this); } - /* Empty searchstring always matches; cpos must be clamped here. - * (If q_blen were < 0 due to clamped coercion, it would also be - * caught here.) - */ - if (q_blen <= 0) { - duk_push_int(ctx, cpos); - return 1; - } - DUK_ASSERT(q_blen > 0); - - bpos = (duk_int_t) duk_heap_strcache_offset_char2byte(thr, h_this, (duk_uint32_t) cpos); - - p_start = DUK_HSTRING_GET_DATA(h_this); - p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_this); - p = p_start + bpos; - - /* This loop is optimized for size. For speed, there should be - * two separate loops, and we should ensure that memcmp() can be - * used without an extra "will searchstring fit" check. Doing - * the preconditioning for 'p' and 'p_end' is easy but cpos - * must be updated if 'p' is wound back (backward scanning). - */ - - firstbyte = q_start[0]; /* leading byte of match string */ - while (p <= p_end && p >= p_start) { - t = *p; - - /* For Ecmascript strings, this check can only match for - * initial UTF-8 bytes (not continuation bytes). For other - * strings all bets are off. - */ - - if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= (duk_size_t) q_blen)) { - DUK_ASSERT(q_blen > 0); /* no issues with memcmp() zero size, even if broken */ - if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { - duk_push_int(ctx, cpos); - return 1; - } - } - - /* track cpos while scanning */ - if (is_lastindexof) { - /* when going backwards, we decrement cpos 'early'; - * 'p' may point to a continuation byte of the char - * at offset 'cpos', but that's OK because we'll - * backtrack all the way to the initial byte. - */ - if ((t & 0xc0) != 0x80) { - cpos--; - } - p--; - } else { - if ((t & 0xc0) != 0x80) { - cpos++; - } - p++; - } - } - - /* Not found. Empty string case is handled specially above. */ - duk_push_int(ctx, -1); + cpos = duk__str_search_shared(ctx, h_this, h_search, cpos, is_lastindexof /*backwards*/); + duk_push_int(ctx, cpos); return 1; } @@ -754,9 +777,10 @@ /* Use match charlen instead of bytelen, just in case the input and * match codepoint encodings would have different lengths. */ + /* XXX: charlen computed here, and also in char2byte helper. */ match_end_boff = duk_heap_strcache_offset_char2byte(thr, h_input, - match_start_coff + DUK_HSTRING_GET_CHARLEN(h_match)); + match_start_coff + (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h_match)); tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - match_end_boff); DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + match_end_boff, tmp_sz); @@ -1106,7 +1130,7 @@ DUK_DDD(DUK_DDDPRINT("split trailer; prev_end b=%ld,c=%ld", (long) prev_match_end_boff, (long) prev_match_end_coff)); - if (DUK_HSTRING_GET_CHARLEN(h_input) > 0 || !matched) { + if (DUK_HSTRING_GET_BYTELEN(h_input) > 0 || !matched) { /* Add trailer if: * a) non-empty input * b) empty input and no (zero size) match found (step 11) @@ -1366,10 +1390,10 @@ } else { DUK_MEMCPY((void *) p, (const void *) src, copy_size); p += copy_size; - copy_size *= 2; } src = (const duk_uint8_t *) buf; /* Use buf as source for larger copies. */ + copy_size = (duk_size_t) (p - buf); } #endif /* DUK_USE_PREFER_SIZE */ @@ -1448,4 +1472,91 @@ return 1; } +#if defined(DUK_USE_ES6) +DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_context *ctx) { + duk_int_t magic; + duk_hstring *h; + duk_hstring *h_search; + duk_size_t blen_search; + const duk_uint8_t *p_cmp_start; + duk_bool_t result; + + h = duk_push_this_coercible_to_string(ctx); + DUK_ASSERT(h != NULL); + + h_search = duk__str_tostring_notregexp(ctx, 0); + DUK_ASSERT(h_search != NULL); + + magic = duk_get_current_magic(ctx); + + p_cmp_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h); + blen_search = DUK_HSTRING_GET_BYTELEN(h_search); + + if (duk_is_undefined(ctx, 1)) { + if (magic) { + p_cmp_start += DUK_HSTRING_GET_BYTELEN(h) - blen_search; + } else { + /* p_cmp_start already OK */ + } + } else { + duk_int_t len; + duk_int_t pos; + + DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= DUK_INT_MAX); + len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h); + pos = duk_to_int_clamped(ctx, 1, 0, len); + DUK_ASSERT(pos >= 0 && pos <= len); + + if (magic) { + p_cmp_start -= blen_search; /* Conceptually subtracted last, but do already here. */ + } + DUK_ASSERT(pos >= 0 && pos <= len); + + p_cmp_start += duk_heap_strcache_offset_char2byte((duk_hthread *) ctx, h, pos); + } + + /* The main comparison can be done using a memcmp() rather than + * doing codepoint comparisons: for CESU-8 strings there is a + * canonical representation for every codepoint. But we do need + * to deal with the char/byte offset translation to find the + * comparison range. + */ + + result = 0; + if (p_cmp_start >= DUK_HSTRING_GET_DATA(h) && + p_cmp_start - (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h) + blen_search <= DUK_HSTRING_GET_BYTELEN(h)) { + if (DUK_MEMCMP((const void *) p_cmp_start, + (const void *) DUK_HSTRING_GET_DATA(h_search), + (size_t) blen_search) == 0) { + result = 1; + } + } + + duk_push_boolean(ctx, result); + return 1; +} +#endif /* DUK_USE_ES6 */ + +#if defined(DUK_USE_ES6) +DUK_INTERNAL duk_ret_t duk_bi_string_prototype_includes(duk_context *ctx) { + duk_hstring *h; + duk_hstring *h_search; + duk_int_t len; + duk_int_t pos; + + h = duk_push_this_coercible_to_string(ctx); + DUK_ASSERT(h != NULL); + + h_search = duk__str_tostring_notregexp(ctx, 0); + DUK_ASSERT(h_search != NULL); + + len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h); + pos = duk_to_int_clamped(ctx, 1, 0, len); + DUK_ASSERT(pos >= 0 && pos <= len); + + pos = duk__str_search_shared(ctx, h, h_search, pos, 0 /*backwards*/); + duk_push_boolean(ctx, pos >= 0); + return 1; +} +#endif /* DUK_USE_ES6 */ #endif /* DUK_USE_STRING_BUILTIN */ diff -Nru duktape-2.0.0/src-input/duk_bi_symbol.c duktape-2.1.1/src-input/duk_bi_symbol.c --- duktape-2.0.0/src-input/duk_bi_symbol.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_bi_symbol.c 2017-07-28 22:05:08.000000000 +0000 @@ -104,7 +104,8 @@ h_str = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h_str != NULL); - if (!DUK_HSTRING_HAS_SYMBOL(h_str)) { + /* Here symbol is more expected than not. */ + if (DUK_UNLIKELY(!DUK_HSTRING_HAS_SYMBOL(h_str))) { return NULL; } @@ -124,6 +125,7 @@ duk_push_symbol_descriptive_string(ctx, h_str); } else { /* .valueOf() */ + duk_push_hstring(ctx, h_str); } return 1; } diff -Nru duktape-2.0.0/src-input/duk_bi_thread.c duktape-2.1.1/src-input/duk_bi_thread.c --- duktape-2.0.0/src-input/duk_bi_thread.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_bi_thread.c 2017-07-28 22:05:08.000000000 +0000 @@ -79,11 +79,12 @@ DUK_DD(DUK_DDPRINT("resume state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.resume)")); goto state_error; } - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); /* us */ - DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL); /* caller */ + DUK_ASSERT(thr->callstack_curr != 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 - 1) != NULL); /* caller */ - caller_func = DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2); + caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr - 1); if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) { DUK_DD(DUK_DDPRINT("resume state invalid: caller must be Ecmascript code")); goto state_error; @@ -233,11 +234,12 @@ DUK_DD(DUK_DDPRINT("yield state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.yield)")); goto state_error; } - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); /* us */ - DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL); /* caller */ + DUK_ASSERT(thr->callstack_curr != 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 - 1) != NULL); /* caller */ - caller_func = DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2); + caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr - 1); if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) { DUK_DD(DUK_DDPRINT("yield state invalid: caller must be Ecmascript code")); goto state_error; diff -Nru duktape-2.0.0/src-input/duk_dblunion.h duktape-2.1.1/src-input/duk_dblunion.h --- duktape-2.0.0/src-input/duk_dblunion.h 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/src-input/duk_dblunion.h 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,423 @@ +/* + * 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/cross endian (e.g. ARM) DUK_USE_DOUBLE_ME + * + * ARM is a special case: ARM double values are in mixed/cross 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. + * + * 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] = 0x000000007ff80000ULL; \ + } while (0) +#define DUK__DBLUNION_IS_NAN_FULL(u) \ + ((((u)->ull[DUK_DBL_IDX_ULL0] & 0x000000007ff00000ULL) == 0x000000007ff00000ULL) && \ + ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0xffffffff000fffffULL) != 0)) +#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x000000007ff80000ULL) +#define DUK__DBLUNION_IS_ANYINF(u) \ + (((u)->ull[DUK_DBL_IDX_ULL0] & 0xffffffff7fffffffULL) == 0x000000007ff00000ULL) +#define DUK__DBLUNION_IS_POSINF(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x000000007ff00000ULL) +#define DUK__DBLUNION_IS_NEGINF(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x00000000fff00000ULL) +#define DUK__DBLUNION_IS_ANYZERO(u) \ + (((u)->ull[DUK_DBL_IDX_ULL0] & 0xffffffff7fffffffULL) == 0x0000000000000000ULL) +#define DUK__DBLUNION_IS_POSZERO(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000000000000ULL) +#define DUK__DBLUNION_IS_NEGZERO(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000080000000ULL) +#else +/* Macros for 64-bit ops + big/little endian doubles. */ +#define DUK__DBLUNION_SET_NAN_FULL(u) do { \ + (u)->ull[DUK_DBL_IDX_ULL0] = 0x7ff8000000000000ULL; \ + } while (0) +#define DUK__DBLUNION_IS_NAN_FULL(u) \ + ((((u)->ull[DUK_DBL_IDX_ULL0] & 0x7ff0000000000000ULL) == 0x7ff0000000000000UL) && \ + ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0x000fffffffffffffULL) != 0)) +#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x7ff8000000000000ULL) +#define DUK__DBLUNION_IS_ANYINF(u) \ + (((u)->ull[DUK_DBL_IDX_ULL0] & 0x7fffffffffffffffULL) == 0x7ff0000000000000ULL) +#define DUK__DBLUNION_IS_POSINF(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x7ff0000000000000ULL) +#define DUK__DBLUNION_IS_NEGINF(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0xfff0000000000000ULL) +#define DUK__DBLUNION_IS_ANYZERO(u) \ + (((u)->ull[DUK_DBL_IDX_ULL0] & 0x7fffffffffffffffULL) == 0x0000000000000000ULL) +#define DUK__DBLUNION_IS_POSZERO(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000000000000ULL) +#define DUK__DBLUNION_IS_NEGZERO(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x8000000000000000ULL) +#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] & 0x8000000000000000ULL) != 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 */ diff -Nru duktape-2.0.0/src-input/duk_dblunion.h.in duktape-2.1.1/src-input/duk_dblunion.h.in --- duktape-2.0.0/src-input/duk_dblunion.h.in 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_dblunion.h.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,423 +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/cross endian (e.g. ARM) DUK_USE_DOUBLE_ME - * - * ARM is a special case: ARM double values are in mixed/cross 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. - * - * 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] = 0x000000007ff80000ULL; \ - } while (0) -#define DUK__DBLUNION_IS_NAN_FULL(u) \ - ((((u)->ull[DUK_DBL_IDX_ULL0] & 0x000000007ff00000ULL) == 0x000000007ff00000ULL) && \ - ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0xffffffff000fffffULL) != 0)) -#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x000000007ff80000ULL) -#define DUK__DBLUNION_IS_ANYINF(u) \ - (((u)->ull[DUK_DBL_IDX_ULL0] & 0xffffffff7fffffffULL) == 0x000000007ff00000ULL) -#define DUK__DBLUNION_IS_POSINF(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x000000007ff00000ULL) -#define DUK__DBLUNION_IS_NEGINF(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x00000000fff00000ULL) -#define DUK__DBLUNION_IS_ANYZERO(u) \ - (((u)->ull[DUK_DBL_IDX_ULL0] & 0xffffffff7fffffffULL) == 0x0000000000000000ULL) -#define DUK__DBLUNION_IS_POSZERO(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000000000000ULL) -#define DUK__DBLUNION_IS_NEGZERO(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000080000000ULL) -#else -/* Macros for 64-bit ops + big/little endian doubles. */ -#define DUK__DBLUNION_SET_NAN_FULL(u) do { \ - (u)->ull[DUK_DBL_IDX_ULL0] = 0x7ff8000000000000ULL; \ - } while (0) -#define DUK__DBLUNION_IS_NAN_FULL(u) \ - ((((u)->ull[DUK_DBL_IDX_ULL0] & 0x7ff0000000000000ULL) == 0x7ff0000000000000UL) && \ - ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0x000fffffffffffffULL) != 0)) -#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x7ff8000000000000ULL) -#define DUK__DBLUNION_IS_ANYINF(u) \ - (((u)->ull[DUK_DBL_IDX_ULL0] & 0x7fffffffffffffffULL) == 0x7ff0000000000000ULL) -#define DUK__DBLUNION_IS_POSINF(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x7ff0000000000000ULL) -#define DUK__DBLUNION_IS_NEGINF(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0xfff0000000000000ULL) -#define DUK__DBLUNION_IS_ANYZERO(u) \ - (((u)->ull[DUK_DBL_IDX_ULL0] & 0x7fffffffffffffffULL) == 0x0000000000000000ULL) -#define DUK__DBLUNION_IS_POSZERO(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000000000000ULL) -#define DUK__DBLUNION_IS_NEGZERO(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x8000000000000000ULL) -#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] & 0x8000000000000000ULL) != 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 */ diff -Nru duktape-2.0.0/src-input/duk_debugger.c duktape-2.1.1/src-input/duk_debugger.c --- duktape-2.0.0/src-input/duk_debugger.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_debugger.c 2017-07-28 22:05:08.000000000 +0000 @@ -66,7 +66,6 @@ /* heap->dbg_detached_cb: keep */ /* heap->dbg_udata: keep */ /* heap->dbg_processing: keep on purpose to avoid debugger re-entry in detaching state */ - DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap); heap->dbg_state_dirty = 0; heap->dbg_force_restart = 0; heap->dbg_step_type = 0; @@ -74,6 +73,8 @@ heap->dbg_step_csindex = 0; heap->dbg_step_startline = 0; heap->dbg_have_next_byte = 0; + duk_debug_clear_paused(heap); /* XXX: some overlap with field inits above */ + heap->dbg_state_dirty = 0; /* XXX: clear_paused sets dirty; rework? */ /* Ensure there are no stale active breakpoint pointers. * Breakpoint list is currently kept - we could empty it @@ -92,7 +93,10 @@ duk_context *ctx; thr = heap->heap_thread; - DUK_ASSERT(thr != NULL); + if (thr == NULL) { + DUK_ASSERT(heap->dbg_detached_cb == NULL); + return; + } ctx = (duk_context *) thr; /* Safe to call multiple times. */ @@ -126,6 +130,9 @@ */ DUK_LOCAL void duk__debug_null_most_callbacks(duk_hthread *thr) { duk_heap *heap; + + DUK_ASSERT(thr != NULL); + heap = thr->heap; DUK_D(DUK_DPRINT("transport read/write error, NULL all callbacks expected detached")); heap->dbg_read_cb = NULL; @@ -973,7 +980,7 @@ duk_uint_fast32_t line; duk_uint_fast32_t pc; - act = duk_hthread_get_current_activation(thr); /* may be NULL */ + act = thr->callstack_curr; if (act == NULL) { return 0; } @@ -1004,13 +1011,13 @@ duk_debug_write_int(thr, (DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) ? 1 : 0)); DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* unsigned */ - if (thr->callstack_top == 0) { + act = thr->callstack_curr; + if (act == NULL) { duk_debug_write_undefined(thr); duk_debug_write_undefined(thr); duk_debug_write_int(thr, 0); duk_debug_write_int(thr, 0); } else { - act = thr->callstack + thr->callstack_top - 1; duk_push_tval(ctx, &act->tv_func); duk_get_prop_string(ctx, -1, "fileName"); duk__debug_write_hstring_safe_top(thr); @@ -1019,6 +1026,7 @@ duk_pop_3(ctx); /* Report next pc/line to be executed. */ duk_debug_write_uint(thr, (duk_uint32_t) duk_debug_curr_line(thr)); + act = thr->callstack_curr; duk_debug_write_uint(thr, (duk_uint32_t) duk_hthread_get_act_curr_pc(thr, act)); } @@ -1051,18 +1059,29 @@ duk__debug_write_hstring_safe_top(thr); duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_LINE_NUMBER); duk_debug_write_uint(thr, duk_get_uint(ctx, -1)); + duk_pop_2(ctx); } else { - /* For anything other than an Error instance, we calculate the error - * location directly from the current activation. + /* For anything other than an Error instance, we calculate the + * error location directly from the current activation if one + * exists. */ - act = thr->callstack + thr->callstack_top - 1; - duk_push_tval(ctx, &act->tv_func); - duk_get_prop_string(ctx, -1, "fileName"); - duk__debug_write_hstring_safe_top(thr); - pc = duk_hthread_get_act_prev_pc(thr, act); - duk_debug_write_uint(thr, (duk_uint32_t) duk_hobject_pc2line_query(ctx, -2, pc)); + act = thr->callstack_curr; + if (act != NULL) { + duk_push_tval(ctx, &act->tv_func); + duk_get_prop_string(ctx, -1, "fileName"); + duk__debug_write_hstring_safe_top(thr); + act = thr->callstack_curr; + pc = duk_hthread_get_act_prev_pc(thr, act); + duk_debug_write_uint(thr, (duk_uint32_t) duk_hobject_pc2line_query(ctx, -2, pc)); + duk_pop_2(ctx); + } else { + /* Can happen if duk_throw() is called on an empty + * callstack. + */ + duk_debug_write_cstring(thr, ""); + duk_debug_write_uint(thr, 0); + } } - duk_pop_2(ctx); /* shared pop */ duk_debug_write_eom(thr); } @@ -1202,7 +1221,11 @@ DUK_LOCAL void duk__debug_handle_pause(duk_hthread *thr, duk_heap *heap) { DUK_D(DUK_DPRINT("debug command Pause")); - DUK_HEAP_SET_PAUSED(heap); + if (duk_debug_is_paused(heap)) { + DUK_D(DUK_DPRINT("Pause requested when already paused, ignore")); + } else { + duk_debug_set_paused(heap); + } duk_debug_write_reply(thr); duk_debug_write_eom(thr); } @@ -1210,7 +1233,7 @@ DUK_LOCAL void duk__debug_handle_resume(duk_hthread *thr, duk_heap *heap) { DUK_D(DUK_DPRINT("debug command Resume")); - DUK_HEAP_CLEAR_PAUSED(heap); + duk_debug_clear_paused(heap); duk_debug_write_reply(thr); duk_debug_write_eom(thr); } @@ -1232,7 +1255,7 @@ line = duk_debug_curr_line(thr); if (line > 0) { - DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap); + duk_debug_clear_paused(heap); /* XXX: overlap with fields below; separate macro/helper? */ heap->dbg_step_type = step_type; heap->dbg_step_thread = thr; heap->dbg_step_csindex = thr->callstack_top - 1; @@ -1494,6 +1517,7 @@ /* Read callstack index, if non-null. */ if (duk_debug_peek_byte(thr) == DUK_DBG_IB_NULL) { direct_eval = 0; + level = -1; /* Not needed, but silences warning. */ (void) duk_debug_read_byte(thr); } else { direct_eval = 1; @@ -1736,82 +1760,29 @@ } } -#if defined(DUK_USE_STRTAB_CHAIN) -DUK_LOCAL void duk__debug_dump_strtab_chain(duk_hthread *thr, duk_heap *heap) { - duk_uint_fast32_t i, j; - duk_strtab_entry *e; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t *lst; -#else - duk_hstring **lst; -#endif - duk_hstring *h; - - for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { - e = heap->strtable + i; - if (e->listlen > 0) { -#if defined(DUK_USE_HEAPPTR16) - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); -#else - lst = e->u.strlist; -#endif - DUK_ASSERT(lst != NULL); - - for (j = 0; j < e->listlen; j++) { -#if defined(DUK_USE_HEAPPTR16) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[j]); -#else - h = lst[j]; -#endif - if (h != NULL) { - duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h); - } - } - } else { -#if defined(DUK_USE_HEAPPTR16) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16); -#else - h = e->u.str; -#endif - if (h != NULL) { - duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h); - } - } - } -} -#endif /* DUK_USE_STRTAB_CHAIN */ - -#if defined(DUK_USE_STRTAB_PROBE) -DUK_LOCAL void duk__debug_dump_strtab_probe(duk_hthread *thr, duk_heap *heap) { +DUK_LOCAL void duk__debug_dump_strtab(duk_hthread *thr, duk_heap *heap) { duk_uint32_t i; duk_hstring *h; for (i = 0; i < heap->st_size; i++) { -#if defined(DUK_USE_HEAPPTR16) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); +#if defined(DUK_USE_STRTAB_PTRCOMP) + h = DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, heap->strtable16[i]); #else h = heap->strtable[i]; #endif - if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) { - continue; + while (h != NULL) { + duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h); + h = h->hdr.h_next; } - - duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h); } } -#endif /* DUK_USE_STRTAB_PROBE */ DUK_LOCAL void duk__debug_handle_dump_heap(duk_hthread *thr, duk_heap *heap) { DUK_D(DUK_DPRINT("debug command DumpHeap")); duk_debug_write_reply(thr); duk__debug_dump_heap_allocated(thr, heap); -#if defined(DUK_USE_STRTAB_CHAIN) - duk__debug_dump_strtab_chain(thr, heap); -#endif -#if defined(DUK_USE_STRTAB_PROBE) - duk__debug_dump_strtab_probe(thr, heap); -#endif + duk__debug_dump_strtab(thr, heap); duk_debug_write_eom(thr); } #endif /* DUK_USE_DEBUGGER_DUMPHEAP */ @@ -1949,14 +1920,14 @@ "compfunc", "natfunc", "bufobj", - "thread", + "fastrefs", "array_part", "strict", "notail", "newenv", "namebinding", "createargs", - "envrecclosed", + "have_finalizer", "exotic_array", "exotic_stringobj", "exotic_arguments", @@ -1971,14 +1942,14 @@ DUK_HOBJECT_FLAG_COMPFUNC, DUK_HOBJECT_FLAG_NATFUNC, DUK_HOBJECT_FLAG_BUFOBJ, - DUK_HOBJECT_FLAG_THREAD, + DUK_HOBJECT_FLAG_FASTREFS, DUK_HOBJECT_FLAG_ARRAY_PART, DUK_HOBJECT_FLAG_STRICT, DUK_HOBJECT_FLAG_NOTAIL, DUK_HOBJECT_FLAG_NEWENV, DUK_HOBJECT_FLAG_NAMEBINDING, DUK_HOBJECT_FLAG_CREATEARGS, - DUK_HOBJECT_FLAG_ENVRECCLOSED, + DUK_HOBJECT_FLAG_HAVE_FINALIZER, DUK_HOBJECT_FLAG_EXOTIC_ARRAY, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS, @@ -2026,7 +1997,7 @@ for (;;) { mask = *masks++; - if (!mask) { + if (mask == 0) { break; } key = *keys++; @@ -2108,6 +2079,10 @@ DUK_D(DUK_DPRINT("debug command GetHeapObjInfo")); DUK_UNREF(heap); + DUK_ASSERT(sizeof(duk__debug_getinfo_hstring_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hstring_masks) / sizeof(duk_uint_t) - 1); + DUK_ASSERT(sizeof(duk__debug_getinfo_hobject_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hobject_masks) / sizeof(duk_uint_t) - 1); + DUK_ASSERT(sizeof(duk__debug_getinfo_hbuffer_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hbuffer_masks) / sizeof(duk_uint_t) - 1); + h = duk_debug_read_any_ptr(thr); if (!h) { duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid target"); @@ -2146,9 +2121,9 @@ duk__debug_getinfo_hstring_keys, duk__debug_getinfo_hstring_masks, DUK_HEAPHDR_GET_FLAGS_RAW(h)); - duk__debug_getinfo_prop_uint(thr, "bytelen", DUK_HSTRING_GET_BYTELEN(h_str)); - duk__debug_getinfo_prop_uint(thr, "charlen", DUK_HSTRING_GET_CHARLEN(h_str)); - duk__debug_getinfo_prop_uint(thr, "hash", DUK_HSTRING_GET_HASH(h_str)); + duk__debug_getinfo_prop_uint(thr, "bytelen", (duk_uint_t) DUK_HSTRING_GET_BYTELEN(h_str)); + duk__debug_getinfo_prop_uint(thr, "charlen", (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h_str)); + duk__debug_getinfo_prop_uint(thr, "hash", (duk_uint_t) DUK_HSTRING_GET_HASH(h_str)); duk__debug_getinfo_flags_key(thr, "data"); duk_debug_write_hstring(thr, h_str); break; @@ -2246,6 +2221,26 @@ DUK_UNREF(h_thr); } + if (DUK_HOBJECT_IS_DECENV(h_obj)) { + duk_hdecenv *h_env; + h_env = (duk_hdecenv *) h_obj; + + duk__debug_getinfo_flags_key(thr, "thread"); + duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->thread)); + duk__debug_getinfo_flags_key(thr, "varmap"); + duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->varmap)); + duk__debug_getinfo_prop_uint(thr, "regbase", (duk_uint_t) h_env->regbase); + } + + if (DUK_HOBJECT_IS_OBJENV(h_obj)) { + duk_hobjenv *h_env; + h_env = (duk_hobjenv *) h_obj; + + duk__debug_getinfo_flags_key(thr, "target"); + duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->target)); + duk__debug_getinfo_prop_bool(thr, "has_this", h_env->has_this); + } + #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) { duk_hbufobj *h_bufobj; @@ -2668,12 +2663,13 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)); + DUK_ASSERT(duk_debug_is_attached(thr->heap)); DUK_ASSERT(thr->heap->dbg_processing == 0); + DUK_ASSERT(!duk_debug_is_paused(thr->heap)); - DUK_HEAP_SET_PAUSED(thr->heap); + duk_debug_set_paused(thr->heap); - act = duk_hthread_get_current_activation(thr); + act = thr->callstack_curr; /* NOTE: act may be NULL if an error is thrown outside of any activation, * which may happen in the case of, e.g. syntax errors. @@ -2706,8 +2702,8 @@ thr->heap->dbg_state_dirty = 1; while (DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap)) { - DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)); - DUK_ASSERT(thr->heap->dbg_processing); + DUK_ASSERT(duk_debug_is_attached(thr->heap)); + DUK_ASSERT(thr->heap->dbg_processing == 0); duk_debug_process_messages(thr, 0 /*no_block*/); } @@ -2769,7 +2765,7 @@ DUK_ASSERT(thr != NULL); heap = thr->heap; DUK_ASSERT(heap != NULL); - DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)); + DUK_ASSERT(duk_debug_is_attached(thr->heap)); DUK_ASSERT_DISABLE(breakpoint_index >= 0); /* unsigned */ if (breakpoint_index >= heap->dbg_breakpoint_count) { @@ -2798,6 +2794,55 @@ return 1; } +/* + * Misc state management + */ + +DUK_INTERNAL duk_bool_t duk_debug_is_attached(duk_heap *heap) { + return (heap->dbg_read_cb != NULL); +} + +DUK_INTERNAL duk_bool_t duk_debug_is_paused(duk_heap *heap) { + return (DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) != 0); +} + +DUK_INTERNAL void duk_debug_set_paused(duk_heap *heap) { + if (duk_debug_is_paused(heap)) { + DUK_D(DUK_DPRINT("trying to set paused state when already paused, ignoring")); + } else { + DUK_HEAP_SET_DEBUGGER_PAUSED(heap); + heap->dbg_state_dirty = 1; + duk_debug_clear_step_state(heap); + DUK_ASSERT(heap->ms_running == 0); /* debugger can't be triggered within mark-and-sweep */ + heap->ms_running = 1; /* prevent mark-and-sweep, prevent refzero queueing */ + heap->ms_prevent_count++; + DUK_ASSERT(heap->ms_prevent_count != 0); /* Wrap. */ + DUK_ASSERT(heap->heap_thread != NULL); + } +} + +DUK_INTERNAL void duk_debug_clear_paused(duk_heap *heap) { + if (duk_debug_is_paused(heap)) { + DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap); + heap->dbg_state_dirty = 1; + duk_debug_clear_step_state(heap); + DUK_ASSERT(heap->ms_running == 1); + DUK_ASSERT(heap->ms_prevent_count > 0); + heap->ms_prevent_count--; + heap->ms_running = 0; + DUK_ASSERT(heap->heap_thread != NULL); + } else { + DUK_D(DUK_DPRINT("trying to clear paused state when not paused, ignoring")); + } +} + +DUK_INTERNAL void duk_debug_clear_step_state(duk_heap *heap) { + heap->dbg_step_type = DUK_STEP_TYPE_NONE; + heap->dbg_step_thread = NULL; + heap->dbg_step_csindex = 0; + heap->dbg_step_startline = 0; +} + #else /* DUK_USE_DEBUGGER_SUPPORT */ /* No debugger support. */ diff -Nru duktape-2.0.0/src-input/duk_debugger.h duktape-2.1.1/src-input/duk_debugger.h --- duktape-2.0.0/src-input/duk_debugger.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_debugger.h 2017-07-28 22:05:08.000000000 +0000 @@ -140,6 +140,12 @@ 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); -#endif + +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_step_state(duk_heap *heap); +#endif /* DUK_USE_DEBUGGER_SUPPORT */ #endif /* DUK_DEBUGGER_H_INCLUDED */ diff -Nru duktape-2.0.0/src-input/duk_debug_vsnprintf.c duktape-2.1.1/src-input/duk_debug_vsnprintf.c --- duktape-2.0.0/src-input/duk_debug_vsnprintf.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_debug_vsnprintf.c 2017-07-28 22:05:08.000000000 +0000 @@ -425,6 +425,9 @@ } } if (st->internal) { + if (DUK_HOBJECT_IS_ARRAY(h)) { + DUK__COMMA(); duk_fb_sprintf(fb, "__array:true"); + } if (DUK_HOBJECT_HAS_EXTENSIBLE(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__extensible:true"); } @@ -443,7 +446,7 @@ if (DUK_HOBJECT_HAS_BUFOBJ(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__bufobj:true"); } - if (DUK_HOBJECT_HAS_THREAD(h)) { + if (DUK_HOBJECT_IS_THREAD(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__thread:true"); } if (DUK_HOBJECT_HAS_ARRAY_PART(h)) { @@ -464,9 +467,6 @@ if (DUK_HOBJECT_HAS_CREATEARGS(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__createargs:true"); } - if (DUK_HOBJECT_HAS_ENVRECCLOSED(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__envrecclosed:true"); - } if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_array:true"); } @@ -511,6 +511,15 @@ duk_fb_put_funcptr(fb, (duk_uint8_t *) &f->func, sizeof(f->func)); DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld", (long) f->nargs); DUK__COMMA(); duk_fb_sprintf(fb, "__magic:%ld", (long) f->magic); + } else if (st->internal && DUK_HOBJECT_IS_DECENV(h)) { + duk_hdecenv *e = (duk_hdecenv *) h; + DUK__COMMA(); duk_fb_sprintf(fb, "__thread:"); duk__print_hobject(st, (duk_hobject *) e->thread); + DUK__COMMA(); duk_fb_sprintf(fb, "__varmap:"); duk__print_hobject(st, (duk_hobject *) e->varmap); + DUK__COMMA(); duk_fb_sprintf(fb, "__regbase:%ld", (long) e->regbase); + } else if (st->internal && DUK_HOBJECT_IS_OBJENV(h)) { + duk_hobjenv *e = (duk_hobjenv *) h; + DUK__COMMA(); duk_fb_sprintf(fb, "__target:"); duk__print_hobject(st, (duk_hobject *) e->target); + DUK__COMMA(); duk_fb_sprintf(fb, "__has_this:%ld", (long) e->has_this); #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) } else if (st->internal && DUK_HOBJECT_IS_BUFOBJ(h)) { duk_hbufobj *b = (duk_hbufobj *) h; @@ -744,6 +753,10 @@ } #if defined(DUK_USE_FASTINT) case DUK_TAG_FASTINT: + DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); + DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + duk_fb_sprintf(fb, "%.18gF", (double) DUK_TVAL_GET_NUMBER(tv)); + break; #endif default: { /* IEEE double is approximately 16 decimal digits; print a couple extra */ @@ -837,7 +850,7 @@ if (ch == DUK_ASC_STAR) { /* unsupported: would consume multiple args */ - goto error; + goto format_error; } else if (ch == DUK_ASC_PERCENT) { duk_fb_put_byte(&fb, (duk_uint8_t) DUK_ASC_PERCENT); break; @@ -889,7 +902,7 @@ fmtlen = (duk_size_t) (p - p_begfmt); if (fmtlen >= sizeof(fmtbuf)) { /* format is too large, abort */ - goto error; + goto format_error; } DUK_MEMZERO(fmtbuf, sizeof(fmtbuf)); DUK_MEMCPY(fmtbuf, p_begfmt, fmtlen); @@ -964,7 +977,7 @@ } goto done; - error: + format_error: duk_fb_put_cstring(&fb, "FMTERR"); /* fall through */ diff -Nru duktape-2.0.0/src-input/duk_error.h duktape-2.1.1/src-input/duk_error.h --- duktape-2.0.0/src-input/duk_error.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_error.h 2017-07-28 22:05:08.000000000 +0000 @@ -475,7 +475,10 @@ DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_fatal_handler(void *udata, const char *msg)); -DUK_INTERNAL_DECL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t lj_type); +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); diff -Nru duktape-2.0.0/src-input/duk_error_longjmp.c duktape-2.1.1/src-input/duk_error_longjmp.c --- duktape-2.0.0/src-input/duk_error_longjmp.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_error_longjmp.c 2017-07-28 22:05:08.000000000 +0000 @@ -38,18 +38,37 @@ 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)); - /* Perform a refzero check before throwing: this catches cases where - * some internal code uses no-refzero (NORZ) macro variants but an - * error occurs before it has the chance to DUK_REFZERO_CHECK_xxx() - * explicitly. Refzero'ed objects would otherwise remain pending - * until the next refzero (which is not a big issue but still). + /* 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_REFZERO_CHECK_SLOW(thr); + + 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 !defined(DUK_USE_CPP_EXCEPTIONS) /* If we don't have a jmpbuf_ptr, there is little we can do except diff -Nru duktape-2.0.0/src-input/duk_error_macros.c duktape-2.1.1/src-input/duk_error_macros.c --- duktape-2.0.0/src-input/duk_error_macros.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_error_macros.c 2017-07-28 22:05:08.000000000 +0000 @@ -8,7 +8,7 @@ #if defined(DUK_USE_VERBOSE_ERRORS) -DUK_INTERNAL void duk_err_handle_error_fmt(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *fmt, ...) { +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); @@ -18,13 +18,13 @@ va_end(ap); /* dead code, but ensures portability (see Linux man page notes) */ } -DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg) { +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 void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) { +DUK_INTERNAL DUK_COLD void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) { duk_err_create_and_throw(thr, code); } @@ -36,41 +36,41 @@ #if defined(DUK_USE_VERBOSE_ERRORS) #if defined(DUK_USE_PARANOID_ERRORS) -DUK_INTERNAL 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_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((duk_context *) thr, idx), (long) idx); } #else -DUK_INTERNAL 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_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((duk_context *) thr, idx), (long) idx); } #endif -DUK_INTERNAL void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 void duk_err_error_alloc_failed(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 void duk_err_error(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) { +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 void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *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 void duk_err_range_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx) { +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 void duk_err_range_push_beyond(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 void duk_err_type_invalid_args(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 void duk_err_type_invalid_state(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 void duk_err_type_invalid_trap_result(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 @@ -82,25 +82,25 @@ DUK_LOCAL void duk__err_shared(duk_hthread *thr, duk_uint_t code) { DUK_ERROR_RAW(thr, NULL, 0, code, NULL); } -DUK_INTERNAL void duk_err_error(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_error(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_ERROR); } -DUK_INTERNAL void duk_err_range(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_range(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_RANGE_ERROR); } -DUK_INTERNAL void duk_err_eval(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_eval(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_EVAL_ERROR); } -DUK_INTERNAL void duk_err_reference(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_reference(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_REFERENCE_ERROR); } -DUK_INTERNAL void duk_err_syntax(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_syntax(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_SYNTAX_ERROR); } -DUK_INTERNAL void duk_err_type(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_type(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_TYPE_ERROR); } -DUK_INTERNAL void duk_err_uri(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_uri(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_URI_ERROR); } #endif @@ -109,7 +109,7 @@ * Default fatal error handler */ -DUK_INTERNAL void duk_default_fatal_handler(void *udata, const char *msg) { +DUK_INTERNAL DUK_COLD void duk_default_fatal_handler(void *udata, const char *msg) { DUK_UNREF(udata); DUK_UNREF(msg); diff -Nru duktape-2.0.0/src-input/duk_error_misc.c duktape-2.1.1/src-input/duk_error_misc.c --- duktape-2.0.0/src-input/duk_error_misc.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_error_misc.c 2017-07-28 22:05:08.000000000 +0000 @@ -61,11 +61,16 @@ } /* - * Exposed helper for setting up heap longjmp state. + * Helper for debugger throw notify and pause-on-uncaught integration. */ -DUK_INTERNAL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t lj_type) { #if defined(DUK_USE_DEBUGGER_SUPPORT) +#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) +DUK_INTERNAL void duk_err_check_debugger_integration(duk_hthread *thr) { + duk_context *ctx = (duk_context *) thr; + duk_bool_t fatal; + 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 @@ -73,53 +78,100 @@ * 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 defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap) && - !thr->heap->dbg_processing && - lj_type == DUK_LJ_TYPE_THROW) { - duk_context *ctx = (duk_context *) thr; - duk_bool_t fatal; - duk_hobject *h_obj; - - /* 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. - */ - h_obj = duk_get_hobject(ctx, -1); - if (h_obj == thr->builtins[DUK_BIDX_DOUBLE_ERROR]) { - DUK_D(DUK_DPRINT("built-in DoubleError instance thrown, not intercepting")); - goto skip_throw_intercept; - } - DUK_D(DUK_DPRINT("throw with debugger attached, report to client")); + 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; + } + + fatal = !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(ctx, tv_obj); - fatal = !duk__have_active_catcher(thr); + /* 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_debug_send_throw(thr, fatal); + /* Report it to the debug client */ + DUK_D(DUK_DPRINT("throw with debugger attached, report to client")); + duk_debug_send_throw(thr, fatal); #endif #if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) - if (fatal) { - DUK_D(DUK_DPRINT("throw will be fatal, halt before longjmp")); - duk_debug_halt_execution(thr, 1 /*use_prev_pc*/); - } -#endif + if (fatal) { + DUK_D(DUK_DPRINT("throw will be fatal, halt before longjmp")); + duk_debug_halt_execution(thr, 1 /*use_prev_pc*/); } +#endif + + /* Restore longjmp state. */ + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + thr->heap->lj.type = DUK_LJ_TYPE_THROW; + tv_obj = DUK_GET_TVAL_NEGIDX(ctx, -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); - skip_throw_intercept: + duk_pop(ctx); +} +#else /* DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT */ +DUK_INTERNAL void duk_err_check_debugger_integration(duk_hthread *thr) { + DUK_UNREF(thr); +} #endif /* DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT */ #endif /* DUK_USE_DEBUGGER_SUPPORT */ - thr->heap->lj.type = lj_type; +/* + * 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); - DUK_ASSERT(thr->valstack_top > thr->valstack); - DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, thr->valstack_top - 1); /* side effects */ + heap->lj.type = lj_type; + DUK_TVAL_SET_TVAL(&heap->lj.value1, tv_val); + DUK_TVAL_INCREF(thr, tv_val); - duk_pop((duk_context *) thr); + DUK_ASSERT_LJSTATE_SET(heap); } diff -Nru duktape-2.0.0/src-input/duk_error_throw.c duktape-2.1.1/src-input/duk_error_throw.c --- duktape-2.0.0/src-input/duk_error_throw.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_error_throw.c 2017-07-28 22:05:08.000000000 +0000 @@ -16,7 +16,7 @@ * * 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->handling_error flag; the recursion + * "double fault" through the heap->creating_error flag; the recursion * then stops at the second level. */ @@ -26,7 +26,6 @@ DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code) { #endif duk_context *ctx = (duk_context *) thr; - duk_bool_t double_error = thr->heap->handling_error; #if defined(DUK_USE_VERBOSE_ERRORS) DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld, msg=%s, filename=%s, line=%ld", @@ -39,18 +38,11 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT(ctx != NULL); - thr->heap->handling_error = 1; - - if (!double_error) { - /* Allow headroom for calls during error handling (see GH-191). - * We allow space for 10 additional recursions, with one extra - * for, e.g. a print() call at the deepest level. - */ - DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX); - thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11; - } - - DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11); /* just making sure */ + /* 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 @@ -60,29 +52,50 @@ /* * 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. */ - /* XXX: if attempt to push beyond allocated valstack, this double fault - * handling fails miserably. We should really write the double error - * directly to thr->heap->lj.value1 and avoid valstack use entirely. - */ + if (thr->heap->creating_error) { + duk_tval tv_val; + duk_hobject *h_err; - if (double_error) { - if (thr->builtins[DUK_BIDX_DOUBLE_ERROR]) { - DUK_D(DUK_DPRINT("double fault detected -> push built-in fixed 'double error' instance")); - duk_push_hobject_bidx(ctx, DUK_BIDX_DOUBLE_ERROR); +#if 0 /* XXX: not always true because the second throw may come from a different coroutine */ + DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11); +#endif + thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX; + 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 " - "-> push the error code as a number")); - duk_push_int(ctx, (duk_int_t) code); + "-> 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 { - /* Error object is augmented at its creation here. */ + /* Allow headroom for calls during error handling (see GH-191). + * We allow space for 10 additional recursions, with one extra + * for, e.g. a print() call at the deepest level. + */ +#if 0 /* XXX: not always true, second throw may come from a different coroutine */ + DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX); +#endif + thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11; + thr->heap->creating_error = 1; + duk_require_stack(ctx, 1); - /* XXX: unnecessary '%s' formatting here, but cannot use - * 'msg' as a format string directly. + + /* 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(ctx, @@ -98,37 +111,38 @@ 0, NULL); #endif - } - - /* - * Augment error (throw time), unless double error - * - * 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 (double_error) { - DUK_D(DUK_DPRINT("double error: skip throw augmenting to avoid further trouble")); - } else { + /* 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(ctx, -1))); duk_err_augment_error_throw(thr); #endif + + duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(ctx, -1)); + thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX; + 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_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW); - - thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX; /* reset callstack limit */ - thr->heap->handling_error = 0; - DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT, %!iT (after throw augment)", (duk_tval *) &thr->heap->lj.value1, (duk_tval *) &thr->heap->lj.value2)); diff -Nru duktape-2.0.0/src-input/duk_forwdecl.h duktape-2.1.1/src-input/duk_forwdecl.h --- duktape-2.0.0/src-input/duk_forwdecl.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_forwdecl.h 2017-07-28 22:05:08.000000000 +0000 @@ -26,6 +26,8 @@ struct duk_hnatfunc; struct duk_hthread; struct duk_hbufobj; +struct duk_hdecenv; +struct duk_hobjenv; struct duk_hbuffer; struct duk_hbuffer_fixed; struct duk_hbuffer_dynamic; @@ -80,8 +82,10 @@ typedef struct duk_hobject duk_hobject; typedef struct duk_hcompfunc duk_hcompfunc; typedef struct duk_hnatfunc duk_hnatfunc; -typedef struct duk_hbufobj duk_hbufobj; 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_hbuffer duk_hbuffer; typedef struct duk_hbuffer_fixed duk_hbuffer_fixed; typedef struct duk_hbuffer_dynamic duk_hbuffer_dynamic; diff -Nru duktape-2.0.0/src-input/duk_hbuffer_alloc.c duktape-2.1.1/src-input/duk_hbuffer_alloc.c --- duktape-2.0.0/src-input/duk_hbuffer_alloc.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_hbuffer_alloc.c 2017-07-28 22:05:08.000000000 +0000 @@ -41,8 +41,8 @@ } res = (duk_hbuffer *) DUK_ALLOC(heap, alloc_size); - if (!res) { - goto error; + if (DUK_UNLIKELY(res == NULL)) { + goto alloc_error; } /* zero everything unless requested not to do so */ @@ -78,9 +78,9 @@ #else ptr = DUK_ALLOC(heap, size); #endif - if (!ptr) { + if (DUK_UNLIKELY(ptr == NULL)) { /* Because size > 0, NULL check is correct */ - goto error; + goto alloc_error; } *out_bufdata = ptr; @@ -116,7 +116,7 @@ DUK_DDD(DUK_DDDPRINT("allocated hbuffer: %p", (void *) res)); return res; - error: + alloc_error: DUK_DD(DUK_DDPRINT("hbuffer allocation failed")); DUK_FREE(heap, res); diff -Nru duktape-2.0.0/src-input/duk_hbuffer_ops.c duktape-2.1.1/src-input/duk_hbuffer_ops.c --- duktape-2.0.0/src-input/duk_hbuffer_ops.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_hbuffer_ops.c 2017-07-28 22:05:08.000000000 +0000 @@ -39,7 +39,7 @@ */ res = DUK_REALLOC_INDIRECT(thr->heap, duk_hbuffer_get_dynalloc_ptr, (void *) buf, new_size); - if (res != NULL || new_size == 0) { + 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", diff -Nru duktape-2.0.0/src-input/duk_heap_alloc.c duktape-2.1.1/src-input/duk_heap_alloc.c --- duktape-2.0.0/src-input/duk_heap_alloc.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_heap_alloc.c 2017-07-28 22:05:08.000000000 +0000 @@ -92,11 +92,9 @@ case DUK_HTYPE_OBJECT: duk_free_hobject(heap, (duk_hobject *) hdr); break; - case DUK_HTYPE_BUFFER: - duk_free_hbuffer(heap, (duk_hbuffer *) hdr); - break; default: - DUK_UNREACHABLE(); + DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) == DUK_HTYPE_BUFFER); + duk_free_hbuffer(heap, (duk_hbuffer *) hdr); } } @@ -132,23 +130,8 @@ } } -#if defined(DUK_USE_REFERENCE_COUNTING) -DUK_LOCAL void duk__free_refzero_list(duk_heap *heap) { - duk_heaphdr *curr; - duk_heaphdr *next; - - curr = heap->refzero_list; - while (curr) { - DUK_DDD(DUK_DDDPRINT("FINALFREE (refzero_list): %!iO", - (duk_heaphdr *) curr)); - next = DUK_HEAPHDR_GET_NEXT(heap, curr); - duk_heap_free_heaphdr_raw(heap, curr); - curr = next; - } -} -#endif - -DUK_LOCAL void duk__free_markandsweep_finalize_list(duk_heap *heap) { +#if defined(DUK_USE_FINALIZER_SUPPORT) +DUK_LOCAL void duk__free_finalize_list(duk_heap *heap) { duk_heaphdr *curr; duk_heaphdr *next; @@ -161,15 +144,15 @@ curr = next; } } +#endif /* DUK_USE_FINALIZER_SUPPORT */ DUK_LOCAL void duk__free_stringtable(duk_heap *heap) { /* strings are only tracked by stringtable */ - duk_heap_free_strtab(heap); + duk_heap_strtable_free(heap); } #if defined(DUK_USE_FINALIZER_SUPPORT) DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) { - duk_hthread *thr; duk_heaphdr *curr; duk_uint_t round_no; duk_size_t count_all; @@ -177,25 +160,31 @@ duk_size_t curr_limit; DUK_ASSERT(heap != NULL); - DUK_ASSERT(heap->heap_thread != NULL); #if defined(DUK_USE_REFERENCE_COUNTING) DUK_ASSERT(heap->refzero_list == NULL); /* refzero not running -> must be empty */ #endif - DUK_ASSERT(heap->finalize_list == NULL); /* mark-and-sweep not running -> must be empty */ + DUK_ASSERT(heap->finalize_list == NULL); /* mark-and-sweep last pass */ - /* XXX: here again finalizer thread is the heap_thread which needs - * to be coordinated with finalizer thread fixes. - */ - thr = heap->heap_thread; - DUK_ASSERT(thr != NULL); + if (heap->heap_thread == NULL) { + /* May happen when heap allocation fails right off. There + * cannot be any finalizable objects in this case. + */ + DUK_D(DUK_DPRINT("no heap_thread in heap destruct, assume no finalizable objects")); + return; + } - /* Prevent mark-and-sweep for the pending finalizers, also prevents - * refzero handling from moving objects away from the heap_allocated - * list. (The flag meaning is slightly abused here.) - */ - DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)); - DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap); + /* Prevent finalize_list processing and mark-and-sweep entirely. + * Setting ms_running = 1 also prevents refzero handling from moving + * objects away from the heap_allocated list (the flag name is a bit + * misleading here). + */ + DUK_ASSERT(heap->pf_prevent_count == 0); + heap->pf_prevent_count = 1; + DUK_ASSERT(heap->ms_running == 0); + heap->ms_running = 1; + DUK_ASSERT(heap->ms_prevent_count == 0); + heap->ms_prevent_count = 1; /* Bump, because mark-and-sweep assumes it's bumped when ms_running is set. */ curr_limit = 0; /* suppress warning, not used */ for (round_no = 0; ; round_no++) { @@ -204,18 +193,17 @@ count_finalized = 0; while (curr) { count_all++; - if (DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT) { + if (DUK_HEAPHDR_IS_OBJECT(curr)) { /* Only objects in heap_allocated may have finalizers. Check that * the object itself has a _Finalizer property (own or inherited) * so that we don't execute finalizers for e.g. Proxy objects. */ - DUK_ASSERT(thr != NULL); DUK_ASSERT(curr != NULL); - if (duk_hobject_hasprop_raw(thr, (duk_hobject *) curr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) { + if (DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) curr)) { if (!DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) curr)) { DUK_ASSERT(DUK_HEAP_HAS_FINALIZER_NORESCUE(heap)); /* maps to finalizer 2nd argument */ - duk_hobject_run_finalizer(thr, (duk_hobject *) curr); + duk_heap_run_finalizer(heap, (duk_hobject *) curr); count_finalized++; } } @@ -256,8 +244,10 @@ } } - DUK_ASSERT(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)); - DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap); + DUK_ASSERT(heap->ms_running == 1); + heap->ms_running = 0; + DUK_ASSERT(heap->pf_prevent_count == 1); + heap->pf_prevent_count = 0; } #endif /* DUK_USE_FINALIZER_SUPPORT */ @@ -265,7 +255,7 @@ DUK_D(DUK_DPRINT("free heap: %p", (void *) heap)); #if defined(DUK_USE_DEBUG) - duk_heap_dump_strtab(heap); + duk_heap_strtable_dump(heap); #endif #if defined(DUK_USE_DEBUGGER_SUPPORT) @@ -279,32 +269,47 @@ #endif /* Execute finalizers before freeing the heap, even for reachable - * objects, and regardless of whether or not mark-and-sweep is - * enabled. This gives finalizers the chance to free any native + * objects. This gives finalizers the chance to free any native * resources like file handles, allocations made outside Duktape, * etc. This is quite tricky to get right, so that all finalizer * guarantees are honored. * - * XXX: this perhaps requires an execution time limit. - */ - DUK_D(DUK_DPRINT("execute finalizers before freeing heap")); - /* Run mark-and-sweep a few times just in case (unreachable object + * Run mark-and-sweep a few times just in case (unreachable object * finalizers run already here). The last round must rescue objects * from the previous round without running any more finalizers. This * ensures rescued objects get their FINALIZED flag cleared so that * their finalizer is called once more in forced finalization to * satisfy finalizer guarantees. However, we don't want to run any - * more finalizer because that'd required one more loop, and so on. + * more finalizers because that'd required one more loop, and so on. + * + * XXX: this perhaps requires an execution time limit. */ + DUK_D(DUK_DPRINT("execute finalizers before freeing heap")); + DUK_ASSERT(heap->pf_skip_finalizers == 0); DUK_D(DUK_DPRINT("forced gc #1 in heap destruction")); duk_heap_mark_and_sweep(heap, 0); DUK_D(DUK_DPRINT("forced gc #2 in heap destruction")); duk_heap_mark_and_sweep(heap, 0); DUK_D(DUK_DPRINT("forced gc #3 in heap destruction (don't run finalizers)")); - duk_heap_mark_and_sweep(heap, DUK_MS_FLAG_SKIP_FINALIZERS); /* skip finalizers; queue finalizable objects to heap_allocated */ + heap->pf_skip_finalizers = 1; + duk_heap_mark_and_sweep(heap, 0); /* Skip finalizers; queue finalizable objects to heap_allocated. */ + /* There are never objects in refzero_list at this point, or at any + * point beyond a DECREF (even a DECREF_NORZ). Since Duktape 2.1 + * refzero_list processing is side effect free, so it is always + * processed to completion by a DECREF initially triggering a zero + * refcount. + */ +#if defined(DUK_USE_REFERENCE_COUNTING) + DUK_ASSERT(heap->refzero_list == NULL); /* Always processed to completion inline. */ +#endif #if defined(DUK_USE_FINALIZER_SUPPORT) - DUK_HEAP_SET_FINALIZER_NORESCUE(heap); /* rescue no longer supported */ + DUK_ASSERT(heap->finalize_list == NULL); /* Last mark-and-sweep with skip_finalizers. */ +#endif + +#if defined(DUK_USE_FINALIZER_SUPPORT) + DUK_D(DUK_DPRINT("run finalizers for remaining finalizable objects")); + DUK_HEAP_SET_FINALIZER_NORESCUE(heap); /* Rescue no longer supported. */ duk__free_run_finalizers(heap); #endif /* DUK_USE_FINALIZER_SUPPORT */ @@ -312,16 +317,17 @@ * are on the heap allocated list. */ - DUK_D(DUK_DPRINT("freeing heap objects of heap: %p", (void *) heap)); + DUK_D(DUK_DPRINT("freeing heap_allocated of heap: %p", (void *) heap)); duk__free_allocated(heap); #if defined(DUK_USE_REFERENCE_COUNTING) - DUK_D(DUK_DPRINT("freeing refzero list of heap: %p", (void *) heap)); - duk__free_refzero_list(heap); + DUK_ASSERT(heap->refzero_list == NULL); /* Always processed to completion inline. */ #endif - DUK_D(DUK_DPRINT("freeing mark-and-sweep finalize list of heap: %p", (void *) heap)); - duk__free_markandsweep_finalize_list(heap); +#if defined(DUK_USE_FINALIZER_SUPPORT) + DUK_D(DUK_DPRINT("freeing finalize_list of heap: %p", (void *) heap)); + duk__free_finalize_list(heap); +#endif DUK_D(DUK_DPRINT("freeing string table of heap: %p", (void *) heap)); duk__free_stringtable(heap); @@ -343,20 +349,26 @@ duk_small_uint_t i; #endif + DUK_UNREF(heap); + /* With ROM-based strings, heap->strs[] and thr->strs[] are omitted * so nothing to initialize for strs[]. */ #if defined(DUK_USE_ASSERTIONS) - for (i = 0; i < sizeof(duk_rom_strings) / sizeof(const duk_hstring *); i++) { - duk_uint32_t hash; + for (i = 0; i < sizeof(duk_rom_strings_lookup) / sizeof(const duk_hstring *); i++) { const duk_hstring *h; - h = duk_rom_strings[i]; - DUK_ASSERT(h != NULL); - hash = duk_heap_hashstring(heap, (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); - DUK_DD(DUK_DDPRINT("duk_rom_strings[%d] -> hash 0x%08lx, computed 0x%08lx", - (int) i, (unsigned long) DUK_HSTRING_GET_HASH(h), (unsigned long) hash)); - DUK_ASSERT(hash == (duk_uint32_t) DUK_HSTRING_GET_HASH(h)); + duk_uint32_t hash; + + h = duk_rom_strings_lookup[i]; + while (h != NULL) { + hash = duk_heap_hashstring(heap, (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); + DUK_DD(DUK_DDPRINT("duk_rom_strings_lookup[%d] -> hash 0x%08lx, computed 0x%08lx", + (int) i, (unsigned long) DUK_HSTRING_GET_HASH(h), (unsigned long) hash)); + DUK_ASSERT(hash == (duk_uint32_t) DUK_HSTRING_GET_HASH(h)); + + h = (const duk_hstring *) h->hdr.h_next; + } } #endif return 1; @@ -384,9 +396,9 @@ */ DUK_ASSERT(len <= 0xffffUL); DUK_DDD(DUK_DDDPRINT("intern built-in string %ld", (long) i)); - h = duk_heap_string_intern(heap, tmp, len); + h = duk_heap_strtable_intern(heap, tmp, len); if (!h) { - goto error; + goto failed; } DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)); @@ -421,7 +433,7 @@ return 1; - error: + failed: return 0; } #endif /* DUK_USE_ROM_STRINGS */ @@ -429,12 +441,11 @@ DUK_LOCAL duk_bool_t duk__init_heap_thread(duk_heap *heap) { duk_hthread *thr; - DUK_DD(DUK_DDPRINT("heap init: alloc heap thread")); - thr = duk_hthread_alloc(heap, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_THREAD | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD)); - if (!thr) { + DUK_D(DUK_DPRINT("heap init: alloc heap thread")); + thr = duk_hthread_alloc_unchecked(heap, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD)); + if (thr == NULL) { DUK_D(DUK_DPRINT("failed to alloc heap_thread")); return 0; } @@ -454,6 +465,7 @@ /* 'thr' is now reachable */ + DUK_D(DUK_DPRINT("heap init: init heap thread stacks")); if (!duk_hthread_init_stacks(heap, thr)) { return 0; } @@ -572,6 +584,8 @@ DUK__DUMPSZ(duk_harray); DUK__DUMPSZ(duk_hcompfunc); DUK__DUMPSZ(duk_hnatfunc); + DUK__DUMPSZ(duk_hdecenv); + DUK__DUMPSZ(duk_hobjenv); DUK__DUMPSZ(duk_hthread); #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) DUK__DUMPSZ(duk_hbufobj); @@ -584,9 +598,6 @@ DUK__DUMPSZ(duk_propvalue); DUK__DUMPSZ(duk_propdesc); DUK__DUMPSZ(duk_heap); -#if defined(DUK_USE_STRTAB_CHAIN) - DUK__DUMPSZ(duk_strtab_entry); -#endif DUK__DUMPSZ(duk_activation); DUK__DUMPSZ(duk_catcher); DUK__DUMPSZ(duk_strcache); @@ -695,10 +706,21 @@ void *heap_udata, duk_fatal_function fatal_func) { duk_heap *res = NULL; + duk_uint32_t st_initsize; DUK_D(DUK_DPRINT("allocate heap")); /* + * Random config sanity asserts + */ + + DUK_ASSERT(DUK_USE_STRTAB_MINSIZE >= 64); + + DUK_ASSERT((DUK_HTYPE_STRING & 0x01U) == 0); + DUK_ASSERT((DUK_HTYPE_BUFFER & 0x01U) == 0); + DUK_ASSERT((DUK_HTYPE_OBJECT & 0x01U) == 1); /* DUK_HEAPHDR_IS_OBJECT() relies ont his. */ + + /* * Debug dump type sizes */ @@ -713,9 +735,11 @@ */ #if defined(DUK_USE_SELF_TESTS) + DUK_D(DUK_DPRINT("run self tests")); if (duk_selftest_run_tests(alloc_func, realloc_func, free_func, heap_udata) > 0) { fatal_func(heap_udata, "self test(s) failed"); } + DUK_D(DUK_DPRINT("self tests passed")); #endif /* @@ -772,9 +796,13 @@ * Use a raw call, all macros expect the heap to be initialized */ +#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 1) + goto failed; +#endif + DUK_D(DUK_DPRINT("alloc duk_heap object")); res = (duk_heap *) alloc_func(heap_udata, sizeof(duk_heap)); if (!res) { - goto error; + goto failed; } /* @@ -782,6 +810,9 @@ */ DUK_MEMZERO(res, sizeof(*res)); +#if defined(DUK_USE_ASSERTIONS) + res->heap_initializing = 1; +#endif /* explicit NULL inits */ #if defined(DUK_USE_EXPLICIT_NULL_INIT) @@ -789,20 +820,20 @@ res->heap_allocated = NULL; #if defined(DUK_USE_REFERENCE_COUNTING) res->refzero_list = NULL; - res->refzero_list_tail = NULL; #endif +#if defined(DUK_USE_FINALIZER_SUPPORT) res->finalize_list = NULL; +#if defined(DUK_USE_ASSERTIONS) + res->currently_finalizing = NULL; +#endif +#endif res->heap_thread = NULL; res->curr_thread = NULL; res->heap_object = NULL; -#if defined(DUK_USE_STRTAB_CHAIN) - /* nothing to NULL */ -#elif defined(DUK_USE_STRTAB_PROBE) -#if defined(DUK_USE_HEAPPTR16) - res->strtable16 = (duk_uint16_t *) NULL; +#if defined(DUK_USE_STRTAB_PTRCOMP) + res->strtable16 = NULL; #else - res->strtable = (duk_hstring **) NULL; -#endif + res->strtable = NULL; #endif #if defined(DUK_USE_ROM_STRINGS) /* no res->strs[] */ @@ -836,13 +867,21 @@ res->heap_udata = heap_udata; res->fatal_func = fatal_func; -#if defined(DUK_USE_HEAPPTR16) - /* XXX: zero assumption */ - res->heapptr_null16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) NULL); - res->heapptr_deleted16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) DUK_STRTAB_DELETED_MARKER(res)); -#endif + /* XXX: for now there's a pointer packing zero assumption, i.e. + * NULL <=> compressed pointer 0. If this is removed, may need + * to precompute e.g. null16 here. + */ + + /* res->ms_trigger_counter == 0 -> now causes immediate GC; which is OK */ - /* res->mark_and_sweep_trigger_counter == 0 -> now causes immediate GC; which is OK */ + /* Prevent mark-and-sweep and finalizer execution until heap is completely + * initialized. + */ + DUK_ASSERT(res->ms_prevent_count == 0); + DUK_ASSERT(res->pf_prevent_count == 0); + res->ms_prevent_count = 1; + res->pf_prevent_count = 1; + DUK_ASSERT(res->ms_running == 0); res->call_recursion_depth = 0; res->call_recursion_limit = DUK_USE_NATIVE_CALL_RECLIMIT; @@ -870,71 +909,49 @@ res->lj.jmpbuf_ptr = NULL; #endif DUK_ASSERT(res->lj.type == DUK_LJ_TYPE_UNKNOWN); /* zero */ - + DUK_ASSERT(res->lj.iserror == 0); DUK_TVAL_SET_UNDEFINED(&res->lj.value1); DUK_TVAL_SET_UNDEFINED(&res->lj.value2); -#if (DUK_STRTAB_INITIAL_SIZE < DUK_UTIL_MIN_HASH_PRIME) -#error initial heap stringtable size is defined incorrectly -#endif + DUK_ASSERT_LJSTATE_UNSET(res); /* * Init stringtable: fixed variant */ -#if defined(DUK_USE_STRTAB_CHAIN) - DUK_MEMZERO(res->strtable, sizeof(duk_strtab_entry) * DUK_STRTAB_CHAIN_SIZE); -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - { - duk_small_uint_t i; - for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { -#if defined(DUK_USE_HEAPPTR16) - res->strtable[i].u.str16 = res->heapptr_null16; + st_initsize = DUK_USE_STRTAB_MINSIZE; +#if defined(DUK_USE_STRTAB_PTRCOMP) + res->strtable16 = (duk_uint16_t *) alloc_func(heap_udata, sizeof(duk_uint16_t) * st_initsize); + if (res->strtable16 == NULL) { + goto failed; + } #else - res->strtable[i].u.str = NULL; -#endif - } + res->strtable = (duk_hstring **) alloc_func(heap_udata, sizeof(duk_hstring *) * st_initsize); + if (res->strtable == NULL) { + goto failed; } -#endif /* DUK_USE_EXPLICIT_NULL_INIT */ -#endif /* DUK_USE_STRTAB_CHAIN */ - - /* - * Init stringtable: probe variant - */ +#endif + res->st_size = st_initsize; + res->st_mask = st_initsize - 1; +#if (DUK_USE_STRTAB_MINSIZE != DUK_USE_STRTAB_MAXSIZE) + DUK_ASSERT(res->st_count == 0); +#endif -#if defined(DUK_USE_STRTAB_PROBE) -#if defined(DUK_USE_HEAPPTR16) - res->strtable16 = (duk_uint16_t *) alloc_func(heap_udata, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE); - if (!res->strtable16) { - goto error; - } -#else /* DUK_USE_HEAPPTR16 */ - res->strtable = (duk_hstring **) alloc_func(heap_udata, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE); - if (!res->strtable) { - goto error; - } -#endif /* DUK_USE_HEAPPTR16 */ - res->st_size = DUK_STRTAB_INITIAL_SIZE; +#if defined(DUK_USE_STRTAB_PTRCOMP) + /* zero assumption */ + DUK_MEMZERO(res->strtable16, sizeof(duk_uint16_t) * st_initsize); +#else #if defined(DUK_USE_EXPLICIT_NULL_INIT) { duk_small_uint_t i; - DUK_ASSERT(res->st_size == DUK_STRTAB_INITIAL_SIZE); - for (i = 0; i < DUK_STRTAB_INITIAL_SIZE; i++) { -#if defined(DUK_USE_HEAPPTR16) - res->strtable16[i] = res->heapptr_null16; -#else + for (i = 0; i < st_initsize; i++) { res->strtable[i] = NULL; -#endif } } -#else /* DUK_USE_EXPLICIT_NULL_INIT */ -#if defined(DUK_USE_HEAPPTR16) - DUK_MEMZERO(res->strtable16, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE); #else - DUK_MEMZERO(res->strtable, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE); -#endif + DUK_MEMZERO(res->strtable, sizeof(duk_hstring *) * st_initsize); #endif /* DUK_USE_EXPLICIT_NULL_INIT */ -#endif /* DUK_USE_STRTAB_PROBE */ +#endif /* DUK_USE_STRTAB_PTRCOMP */ /* * Init stringcache @@ -959,30 +976,40 @@ * Init built-in strings */ - DUK_DD(DUK_DDPRINT("HEAP: INIT STRINGS")); +#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 2) + goto failed; +#endif + DUK_D(DUK_DPRINT("heap init: initialize heap strings")); if (!duk__init_heap_strings(res)) { - goto error; + goto failed; } /* * Init the heap thread */ - DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP THREAD")); +#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 3) + goto failed; +#endif + DUK_D(DUK_DPRINT("heap init: initialize heap thread")); if (!duk__init_heap_thread(res)) { - goto error; + goto failed; } /* * Init the heap object */ - DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP OBJECT")); +#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 4) + goto failed; +#endif + DUK_D(DUK_DPRINT("heap init: initialize heap object")); DUK_ASSERT(res->heap_thread != NULL); - res->heap_object = duk_hobject_alloc(res, DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT)); - if (!res->heap_object) { - goto error; + res->heap_object = duk_hobject_alloc_unchecked(res, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT)); + if (res->heap_object == NULL) { + goto failed; } DUK_HOBJECT_INCREF(res->heap_thread, res->heap_object); @@ -1029,23 +1056,49 @@ #endif /* - * All done + * Allow finalizer and mark-and-sweep processing. + */ + + DUK_D(DUK_DPRINT("heap init: allow finalizer/mark-and-sweep processing")); + DUK_ASSERT(res->ms_prevent_count == 1); + DUK_ASSERT(res->pf_prevent_count == 1); + res->ms_prevent_count = 0; + res->pf_prevent_count = 0; + DUK_ASSERT(res->ms_running == 0); +#if defined(DUK_USE_ASSERTIONS) + res->heap_initializing = 0; +#endif + + /* + * All done. */ DUK_D(DUK_DPRINT("allocated heap: %p", (void *) res)); return res; - error: + failed: DUK_D(DUK_DPRINT("heap allocation failed")); - if (res) { - /* assumes that allocated pointers and alloc funcs are valid - * if res exists + if (res != NULL) { + /* Assumes that allocated pointers and alloc funcs are valid + * if res exists. */ + DUK_ASSERT(res->ms_prevent_count == 1); + DUK_ASSERT(res->pf_prevent_count == 1); + DUK_ASSERT(res->ms_running == 0); + if (res->heap_thread != NULL) { + res->ms_prevent_count = 0; + res->pf_prevent_count = 0; + } +#if defined(DUK_USE_ASSERTIONS) + res->heap_initializing = 0; +#endif + DUK_ASSERT(res->alloc_func != NULL); DUK_ASSERT(res->realloc_func != NULL); DUK_ASSERT(res->free_func != NULL); duk_heap_free(res); } + return NULL; } diff -Nru duktape-2.0.0/src-input/duk_heap_finalize.c duktape-2.1.1/src-input/duk_heap_finalize.c --- duktape-2.0.0/src-input/duk_heap_finalize.c 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/src-input/duk_heap_finalize.c 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,449 @@ +/* + * Finalizer handling. + */ + +#include "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_context *ctx) { + DUK_DD(DUK_DDPRINT("fake global torture finalizer executed")); + + /* Require a lot of stack to force a value stack grow/shrink. */ + duk_require_stack(ctx, 100000); + + /* Force a reallocation with pointer change for value, call, and + * catch stacks to maximize side effects. + */ + duk_hthread_valstack_torture_realloc((duk_hthread *) ctx); + duk_hthread_callstack_torture_realloc((duk_hthread *) ctx); + duk_hthread_catchstack_torture_realloc((duk_hthread *) ctx); + + /* Inner function call, error throw. */ + duk_eval_string_noresult(ctx, + "(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 has been reached. + * Otherwise a callstack limit error will be created, then refzero'ed. + */ + if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit || + thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) { + DUK_D(DUK_DPRINT("skip global torture finalizer because of call recursion or call stack size limit")); + return; + } + + /* Run fake finalizer. Avoid creating unnecessary garbage. */ + duk_push_c_function((duk_context *) thr, duk__fake_global_finalizer, 0 /*nargs*/); + (void) duk_pcall((duk_context *) thr, 0 /*nargs*/); + duk_pop((duk_context *) 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); + DUK_ASSERT(heap->heap_thread->callstack != NULL); + DUK_ASSERT(heap->heap_thread->catchstack != 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_context *ctx, void *udata) { + duk_hthread *thr; + + DUK_ASSERT(ctx != NULL); + thr = (duk_hthread *) ctx; + 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(ctx, -1, DUK_STRIDX_INT_FINALIZER); /* -> [... obj finalizer] */ + duk_dup_m2(ctx); + duk_push_boolean(ctx, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap)); + DUK_DDD(DUK_DDDPRINT("calling finalizer")); + duk_call(ctx, 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_context *ctx; + 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); + ctx = (duk_context *) 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(ctx); +#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 (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(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; + } + + duk_push_hobject(ctx, obj); /* this also increases refcount by one */ + rc = duk_safe_call(ctx, duk__finalize_helper, NULL /*udata*/, 0 /*nargs*/, 1 /*nrets*/); /* -> [... obj retval/error] */ + DUK_ASSERT_TOP(ctx, 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(ctx, -1))); + } + duk_pop_2(ctx); /* -> [...] */ + + DUK_ASSERT_TOP(ctx, entry_top); +} + +#else /* DUK_USE_FINALIZER_SUPPORT */ + +/* nothing */ + +#endif /* DUK_USE_FINALIZER_SUPPORT */ diff -Nru duktape-2.0.0/src-input/duk_heap.h duktape-2.1.1/src-input/duk_heap.h --- duktape-2.0.0/src-input/duk_heap.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_heap.h 2017-07-28 22:05:08.000000000 +0000 @@ -14,13 +14,11 @@ * Heap flags */ -#define DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING (1 << 0) /* mark-and-sweep is currently running */ -#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1 << 1) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */ -#define DUK_HEAP_FLAG_REFZERO_FREE_RUNNING (1 << 2) /* refcount code is processing refzero list */ -#define DUK_HEAP_FLAG_ERRHANDLER_RUNNING (1 << 3) /* an error handler (user callback to augment/replace error) is running */ -#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1 << 4) /* executor interrupt running (used to avoid nested interrupts) */ -#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1 << 5) /* heap destruction ongoing, finalizer rescue no longer possible */ -#define DUK_HEAP_FLAG_DEBUGGER_PAUSED (1 << 6) /* debugger is paused: talk with debug client until step/resume */ +#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1 << 0) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */ +#define DUK_HEAP_FLAG_ERRHANDLER_RUNNING (1 << 1) /* an error handler (user callback to augment/replace error) is running */ +#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1 << 2) /* executor interrupt running (used to avoid nested interrupts) */ +#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1 << 3) /* heap destruction ongoing, finalizer rescue no longer possible */ +#define DUK_HEAP_FLAG_DEBUGGER_PAUSED (1 << 4) /* 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 { \ @@ -30,25 +28,19 @@ (heap)->flags &= ~(bits); \ } while (0) -#define DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) #define DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) -#define DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) #define DUK_HEAP_HAS_ERRHANDLER_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) #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_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) #define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) -#define DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) #define DUK_HEAP_SET_ERRHANDLER_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) #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_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) #define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) -#define DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) #define DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) #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) @@ -75,11 +67,25 @@ * field and the GC caller can impose further flags. */ -#define DUK_MS_FLAG_EMERGENCY (1 << 0) /* emergency mode: try extra hard */ -#define DUK_MS_FLAG_NO_STRINGTABLE_RESIZE (1 << 1) /* don't resize stringtable (but may sweep it); needed during stringtable resize */ -#define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1 << 2) /* don't compact objects; needed during object property allocation resize */ -#define DUK_MS_FLAG_NO_FINALIZERS (1 << 3) /* don't run finalizers; leave finalizable objects in finalize_list for next round */ -#define DUK_MS_FLAG_SKIP_FINALIZERS (1 << 4) /* don't run finalizers; queue finalizable objects back to heap_allocated */ +/* Emergency mark-and-sweep: try extra hard, even at the cost of + * performance. + */ +#define DUK_MS_FLAG_EMERGENCY (1 << 0) + +/* Voluntary mark-and-sweep: triggered periodically. */ +#define DUK_MS_FLAG_VOLUNTARY (1 << 1) + +/* 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 (1 << 2) + +/* 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 (1 << 2) /* * Thread switching @@ -121,39 +127,28 @@ #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 */ -/* helper to insert a (non-string) heap object into heap allocated list */ -#define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap,hdr) duk_heap_insert_into_heap_allocated((heap),(hdr)) - -/* - * Stringtable - */ - -/* initial stringtable size, must be prime and higher than DUK_UTIL_MIN_HASH_PRIME */ -#define DUK_STRTAB_INITIAL_SIZE 17 - -/* indicates a deleted string; any fixed non-NULL, non-hstring pointer works */ -#define DUK_STRTAB_DELETED_MARKER(heap) ((duk_hstring *) heap) - -/* resizing parameters */ -#define DUK_STRTAB_MIN_FREE_DIVISOR 4 /* load factor max 75% */ -#define DUK_STRTAB_MIN_USED_DIVISOR 4 /* load factor min 25% */ -#define DUK_STRTAB_GROW_ST_SIZE(n) ((n) + (n)) /* used entries + approx 100% -> reset load to 50% */ - -#define DUK_STRTAB_U32_MAX_STRLEN 10 /* 4'294'967'295 */ -#define DUK_STRTAB_HIGHEST_32BIT_PRIME 0xfffffffbUL - -/* probe sequence (open addressing) */ -#define DUK_STRTAB_HASH_INITIAL(hash,h_size) ((hash) % (h_size)) -#define DUK_STRTAB_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash)) - -/* fixed top level hashtable size (separate chaining) */ -#define DUK_STRTAB_CHAIN_SIZE DUK_USE_STRTAB_CHAIN_SIZE +/* 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 @@ -224,10 +219,17 @@ #define DUK_FREE(heap,ptr) duk_heap_mem_free((heap), (ptr)) /* + * Checked allocation, relative to a thread + */ + +#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)) + +/* * Memory constants */ -#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT 5 /* Retry allocation after mark-and-sweep for this +#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 @@ -268,27 +270,6 @@ duk_uint32_t line; }; -#if defined(DUK_USE_DEBUGGER_SUPPORT) -#define DUK_HEAP_IS_DEBUGGER_ATTACHED(heap) ((heap)->dbg_read_cb != NULL) -#define DUK_HEAP_CLEAR_STEP_STATE(heap) do { \ - (heap)->dbg_step_type = DUK_STEP_TYPE_NONE; \ - (heap)->dbg_step_thread = NULL; \ - (heap)->dbg_step_csindex = 0; \ - (heap)->dbg_step_startline = 0; \ - } while (0) -#define DUK_HEAP_SET_PAUSED(heap) do { \ - DUK_HEAP_SET_DEBUGGER_PAUSED(heap); \ - (heap)->dbg_state_dirty = 1; \ - DUK_HEAP_CLEAR_STEP_STATE((heap)); \ - } while (0) -#define DUK_HEAP_CLEAR_PAUSED(heap) do { \ - DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap); \ - (heap)->dbg_state_dirty = 1; \ - DUK_HEAP_CLEAR_STEP_STATE((heap)); \ - } while (0) -#define DUK_HEAP_IS_PAUSED(heap) (DUK_HEAP_HAS_DEBUGGER_PAUSED((heap))) -#endif /* DUK_USE_DEBUGGER_SUPPORT */ - /* * String cache should ideally be at duk_hthread level, but that would * cause string finalization to slow down relative to the number of @@ -317,28 +298,17 @@ duk_tval value2; /* 2nd related value (type specific) */ }; -/* - * Stringtable entry for fixed size stringtable - */ - -struct duk_strtab_entry { -#if defined(DUK_USE_HEAPPTR16) - /* A 16-bit listlen makes sense with 16-bit heap pointers: there - * won't be space for 64k strings anyway. - */ - duk_uint16_t listlen; /* if 0, 'str16' used, if > 0, 'strlist16' used */ - union { - duk_uint16_t strlist16; - duk_uint16_t str16; - } u; -#else - duk_size_t listlen; /* if 0, 'str' used, if > 0, 'strlist' used */ - union { - duk_hstring **strlist; - duk_hstring *str; - } u; -#endif -}; +#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) /* * Main heap structure @@ -357,12 +327,6 @@ */ void *heap_udata; - /* Precomputed pointers when using 16-bit heap pointer packing. */ -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t heapptr_null16; - duk_uint16_t heapptr_deleted16; -#endif - /* 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 @@ -370,53 +334,114 @@ */ duk_fatal_function fatal_func; - /* allocated heap objects */ + /* 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; - /* work list for objects whose refcounts are zero but which have not been - * "finalized"; avoids recursive C calls when refcounts go to zero in a - * chain of objects. + /* 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; - duk_heaphdr *refzero_list_tail; #endif - /* mark-and-sweep control */ +#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 + + /* 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 mark_and_sweep_trigger_counter; + duk_int_t ms_trigger_counter; #endif - duk_int_t mark_and_sweep_recursion_depth; - /* mark-and-sweep flags automatically active (used for critical sections) */ - duk_small_uint_t mark_and_sweep_base_flags; + /* 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; - /* work list for objects to be finalized (by mark-and-sweep) */ - duk_heaphdr *finalize_list; + /* Mark-and-sweep flags automatically active (used for critical sections). */ + duk_small_uint_t ms_base_flags; - /* longjmp state */ - duk_ljstate lj; + /* Mark-and-sweep running flag. Prevents re-entry, and also causes + * refzero events to be ignored (= objects won't be queued to refzero_list). + */ + 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 detecting internal "double faults", see duk_error_throw.c */ - duk_bool_t handling_error; + /* Longjmp state. */ + duk_ljstate lj; - /* heap thread, used internally and for finalization */ + /* Heap thread, used internally and for finalization. */ duk_hthread *heap_thread; - /* current thread */ - duk_hthread *curr_thread; /* currently running thread */ + /* Current running thread. */ + duk_hthread *curr_thread; - /* heap level "stash" object (e.g., various reachability roots) */ + /* 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 */ + /* Mix-in value for computing string hashes; should be reasonably unpredictable. */ duk_uint32_t hash_seed; - /* rnd_state for duk_util_tinyrandom.c */ + /* 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 */ @@ -425,7 +450,7 @@ #endif #endif - /* counter for unique local symbol creation */ + /* 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. @@ -441,10 +466,9 @@ duk_int_t inst_count_interrupt; #endif - /* debugger */ - + /* Debugger state. */ #if defined(DUK_USE_DEBUGGER_SUPPORT) - /* callbacks and udata; dbg_read_cb != NULL is used to indicate attached state */ + /* 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; @@ -454,7 +478,7 @@ duk_debug_detached_function dbg_detached_cb; void *dbg_udata; - /* debugger state, only relevant when attached */ + /* 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) */ @@ -478,30 +502,25 @@ duk_uint8_t dbg_next_byte; #endif - /* string intern table (weak refs) */ -#if defined(DUK_USE_STRTAB_PROBE) -#if defined(DUK_USE_HEAPPTR16) + /* String intern table (weak refs). */ +#if defined(DUK_USE_STRTAB_PTRCOMP) duk_uint16_t *strtable16; #else duk_hstring **strtable; #endif - duk_uint32_t st_size; /* alloc size in elements */ - duk_uint32_t st_used; /* used elements (includes DELETED) */ -#endif - - /* XXX: static alloc is OK until separate chaining stringtable - * resizing is implemented. - */ -#if defined(DUK_USE_STRTAB_CHAIN) - duk_strtab_entry strtable[DUK_STRTAB_CHAIN_SIZE]; + 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 + /* String access cache (codepoint offset -> byte offset) for fast string * character looping; 'weak' reference which needs special handling in GC. */ duk_strcache strcache[DUK_HEAP_STRCACHE_SIZE]; - /* built-in strings */ + /* Built-in strings. */ #if defined(DUK_USE_ROM_STRINGS) /* No field needed when strings are in ROM. */ #else @@ -530,32 +549,32 @@ 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_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING) -DUK_INTERNAL_DECL void duk_heap_remove_any_from_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 -#if 0 /*unused*/ -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen); -#endif -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen); -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t len); -#if 0 /*unused*/ -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val); -#endif -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val); -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val); +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); +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_string_remove(duk_heap *heap, duk_hstring *h); -#endif -#if defined(DUK_USE_MS_STRINGTABLE_RESIZE) -DUK_INTERNAL_DECL void duk_heap_force_strtab_resize(duk_heap *heap); +DUK_INTERNAL_DECL void duk_heap_strtable_unlink(duk_heap *heap, duk_hstring *h); #endif -DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap); +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_dump_strtab(duk_heap *heap); +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); @@ -569,41 +588,18 @@ 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); -#if defined(DUK_USE_REFERENCE_COUNTING) -DUK_INTERNAL_DECL void duk_refzero_free_pending(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr); -#if 0 /* Not needed: fast path handles inline; slow path uses duk_heaphdr_decref() which is needed anyway. */ -DUK_INTERNAL_DECL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h); -DUK_INTERNAL_DECL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h); -DUK_INTERNAL_DECL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h); -DUK_INTERNAL_DECL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h); -DUK_INTERNAL_DECL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h); -DUK_INTERNAL_DECL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h); -#endif -DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h); -DUK_INTERNAL_DECL void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h); -#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) -DUK_INTERNAL_DECL void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h); /* no 'norz' variant */ -DUK_INTERNAL_DECL void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h); /* no 'norz' variant */ -DUK_INTERNAL_DECL void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h); -DUK_INTERNAL_DECL void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h); -#else -DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv); -DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv); -DUK_INTERNAL_DECL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv); -DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h); -DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h); -DUK_INTERNAL_DECL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h); -#endif -#else /* DUK_USE_REFERENCE_COUNTING */ -/* no refcounting */ -#endif /* DUK_USE_REFERENCE_COUNTING */ +#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 duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags); +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); diff -Nru duktape-2.0.0/src-input/duk_heaphdr.h duktape-2.1.1/src-input/duk_heaphdr.h --- duktape-2.0.0/src-input/duk_heaphdr.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_heaphdr.h 2017-07-28 22:05:08.000000000 +0000 @@ -11,30 +11,45 @@ * * 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 are held in the - * heap-wide string table so they don't need link 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). This - * means essentially that the refcount field must be as wide as data pointers. - * On 64-bit platforms this means that the refcount needs to be 64 bits even - * if an 'int' is 32 bits. This is a bit unfortunate, and compromising on - * this might be reasonable in the future. + * 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_refcount16; + duk_uint16_t h_refcount; +#elif defined(DUK_USE_REFCOUNT32) + duk_uint32_t h_refcount; #else duk_size_t h_refcount; #endif -#endif +#endif /* DUK_USE_REFERENCE_COUNTING */ #if defined(DUK_USE_HEAPPTR16) duk_uint16_t h_next16; @@ -74,15 +89,26 @@ 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_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 +#endif /* DUK_USE_REFERENCE_COUNTING */ + + duk_hstring *h_next; + /* No 'h_prev' pointer for strings. */ }; #define DUK_HEAPHDR_FLAGS_TYPE_MASK 0x00000003UL @@ -138,21 +164,13 @@ #endif #if defined(DUK_USE_REFERENCE_COUNTING) -#if defined(DUK_USE_REFCOUNT16) -#define DUK_HEAPHDR_GET_REFCOUNT(h) ((h)->h_refcount16) -#define DUK_HEAPHDR_SET_REFCOUNT(h,val) do { \ - (h)->h_refcount16 = (val); \ - } while (0) -#define DUK_HEAPHDR_PREINC_REFCOUNT(h) (++(h)->h_refcount16) /* result: updated refcount */ -#define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount16) /* result: updated refcount */ -#else #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 */ -#endif #else /* refcount macros not defined without refcounting, caller must #if defined() now */ #endif /* DUK_USE_REFERENCE_COUNTING */ @@ -240,18 +258,23 @@ } while (0) #endif -#define DUK_HEAPHDR_STRING_INIT_NULLS(h) /* currently nop */ +#define DUK_HEAPHDR_STRING_INIT_NULLS(h) do { \ + (h)->h_next = NULL; \ + } while (0) /* * Type tests */ -#define DUK_HEAPHDR_IS_OBJECT(h) \ - (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_OBJECT) -#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) +/* 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 @@ -274,661 +297,9 @@ #define DUK_ASSERT_HEAPHDR_LINKS(heap,h) do {} while (0) #endif -/* - * Reference counting helper macros. The macros take a thread argument - * and must thus always be executed in a specific thread context. The - * thread argument is needed for features like finalization. Currently - * it is not required for INCREF, but it is included just in case. - * - * 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. - */ - -#if defined(DUK_USE_REFERENCE_COUNTING) - -#if defined(DUK_USE_ROM_OBJECTS) -/* With ROM objects "needs refcount update" is true when the value is - * heap allocated and is not a ROM object. - */ -/* XXX: double evaluation for 'tv' argument. */ -#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) \ - (DUK_TVAL_IS_HEAP_ALLOCATED((tv)) && !DUK_HEAPHDR_HAS_READONLY(DUK_TVAL_GET_HEAPHDR((tv)))) -#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) (!DUK_HEAPHDR_HAS_READONLY((h))) -#else /* DUK_USE_ROM_OBJECTS */ -/* Without ROM objects "needs refcount update" == is heap allocated. */ -#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) DUK_TVAL_IS_HEAP_ALLOCATED((tv)) -#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 1 -#endif /* DUK_USE_ROM_OBJECTS */ - -/* Fast variants, inline refcount operations except for refzero handling. - * Can be used explicitly when speed is always more important than size. - * For a good compiler and a single file build, these are basically the - * same as a forced inline. - */ -#define DUK_TVAL_INCREF_FAST(thr,tv) do { \ - duk_tval *duk__tv = (tv); \ - DUK_ASSERT(duk__tv != NULL); \ - if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \ - duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \ - DUK_ASSERT(duk__h != NULL); \ - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ - DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \ - } \ - } while (0) -#define DUK_TVAL_DECREF_FAST(thr,tv) do { \ - duk_tval *duk__tv = (tv); \ - DUK_ASSERT(duk__tv != NULL); \ - if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \ - duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \ - DUK_ASSERT(duk__h != NULL); \ - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \ - if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \ - duk_heaphdr_refzero((thr), duk__h); \ - } \ - } \ - } while (0) -#define DUK_TVAL_DECREF_NORZ_FAST(thr,tv) do { \ - duk_tval *duk__tv = (tv); \ - DUK_ASSERT(duk__tv != NULL); \ - if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \ - duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \ - DUK_ASSERT(duk__h != NULL); \ - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \ - if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \ - duk_heaphdr_refzero_norz((thr), duk__h); \ - } \ - } \ - } while (0) -#define DUK_HEAPHDR_INCREF_FAST(thr,h) do { \ - duk_heaphdr *duk__h = (duk_heaphdr *) (h); \ - DUK_ASSERT(duk__h != NULL); \ - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ - if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \ - DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \ - } \ - } while (0) -#define DUK_HEAPHDR_DECREF_FAST_RAW(thr,h,rzcall,rzcast) do { \ - duk_heaphdr *duk__h = (duk_heaphdr *) (h); \ - DUK_ASSERT(duk__h != NULL); \ - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \ - if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \ - if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \ - (rzcall)((thr), (rzcast) duk__h); \ - } \ - } \ - } while (0) -#define DUK_HEAPHDR_DECREF_FAST(thr,h) \ - DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *) -#define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) \ - DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *) - -/* Slow variants, call to a helper to reduce code size. - * Can be used explicitly when size is always more important than speed. - */ -#define DUK_TVAL_INCREF_SLOW(thr,tv) do { duk_tval_incref((tv)); } while (0) -#define DUK_TVAL_DECREF_SLOW(thr,tv) do { duk_tval_decref((thr), (tv)); } while (0) -#define DUK_TVAL_DECREF_NORZ_SLOW(thr,tv) do { duk_tval_decref_norz((thr), (tv)); } while (0) -#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) -#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) -#define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) -#define DUK_HSTRING_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) -#define DUK_HSTRING_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) -#define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) -#define DUK_HBUFFER_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) -#define DUK_HBUFFER_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) -#define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) -#define DUK_HOBJECT_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) -#define DUK_HOBJECT_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) -#define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) - -/* Default variants. Selection depends on speed/size preference. - * Concretely: with gcc 4.8.1 -Os x64 the difference in final binary - * is about +1kB for _FAST variants. - */ -#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) -/* XXX: It would be nice to specialize for specific duk_hobject subtypes - * but current refzero queue handling prevents that. - */ -#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_FAST((thr),(tv)) -#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_FAST((thr),(tv)) -#define DUK_TVAL_DECREF_NORZ(thr,tv) DUK_TVAL_DECREF_NORZ_FAST((thr),(tv)) -#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_FAST((thr),(h)) -#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *) -#define DUK_HEAPHDR_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *) -#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) -#define DUK_HSTRING_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *) -#define DUK_HSTRING_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *) /* no 'norz' variant */ -#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) -#define DUK_HOBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) -#define DUK_HOBJECT_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) -#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) -#define DUK_HBUFFER_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *) -#define DUK_HBUFFER_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *) /* no 'norz' variant */ -#define DUK_HCOMPFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HCOMPFUNC_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) -#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) -#define DUK_HNATFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HNATFUNC_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) -#define DUK_HNATFUNC_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) -#define DUK_HBUFOBJ_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HBUFOBJ_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) -#define DUK_HBUFOBJ_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) -#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HTHREAD_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) -#define DUK_HTHREAD_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) -#else -#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_SLOW((thr),(tv)) -#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_SLOW((thr),(tv)) -#define DUK_TVAL_DECREF_NORZ(thr,tv) DUK_TVAL_DECREF_NORZ_SLOW((thr),(tv)) -#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_SLOW((thr),(h)) -#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_SLOW((thr),(h)) -#define DUK_HEAPHDR_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_NORZ_SLOW((thr),(h)) -#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) -#define DUK_HSTRING_DECREF(thr,h) DUK_HSTRING_DECREF_SLOW((thr),(h)) -#define DUK_HSTRING_DECREF_NORZ(thr,h) DUK_HSTRING_DECREF_NORZ_SLOW((thr),(h)) -#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) -#define DUK_HOBJECT_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(h)) -#define DUK_HOBJECT_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(h)) -#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) -#define DUK_HBUFFER_DECREF(thr,h) DUK_HBUFFER_DECREF_SLOW((thr),(h)) -#define DUK_HBUFFER_DECREF_NORZ(thr,h) DUK_HBUFFER_DECREF_NORZ_SLOW((thr),(h)) -#define DUK_HCOMPFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HCOMPFUNC_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) -#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) -#define DUK_HNATFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HNATFUNC_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) -#define DUK_HNATFUNC_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) -#define DUK_HBUFOBJ_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HBUFOBJ_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) -#define DUK_HBUFOB_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) -#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HTHREAD_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) -#define DUK_HTHREAD_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) -#endif - -/* Convenience for some situations; the above macros don't allow NULLs - * for performance reasons. Macros cover only actually needed cases. - */ -#define DUK_HEAPHDR_INCREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HEAPHDR_INCREF((thr), (duk_heaphdr *) (h)); \ - } \ +#define DUK_ASSERT_HEAPHDR_VALID(h) do { \ + DUK_ASSERT((h) != NULL); \ + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID((h))); \ } while (0) -#define DUK_HEAPHDR_DECREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HEAPHDR_DECREF((thr), (duk_heaphdr *) (h)); \ - } \ - } while (0) -#define DUK_HEAPHDR_DECREF_NORZ_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HEAPHDR_DECREF_NORZ((thr), (duk_heaphdr *) (h)); \ - } \ - } while (0) -#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HOBJECT_INCREF((thr), (h)); \ - } \ - } while (0) -#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HOBJECT_DECREF((thr), (h)); \ - } \ - } while (0) -#define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HOBJECT_DECREF_NORZ((thr), (h)); \ - } \ - } while (0) -#define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HBUFFER_INCREF((thr), (h)); \ - } \ - } while (0) -#define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HBUFFER_DECREF((thr), (h)); \ - } \ - } while (0) -#define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HBUFFER_DECREF_NORZ((thr), (h)); \ - } \ - } while (0) -#define DUK_HTHREAD_INCREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HTHREAD_INCREF((thr), (h)); \ - } \ - } while (0) -#define DUK_HTHREAD_DECREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HTHREAD_DECREF((thr), (h)); \ - } \ - } while (0) -#define DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HTHREAD_DECREF_NORZ((thr), (h)); \ - } \ - } while (0) - -/* Free pending refzero entries; quick check to avoid call because often - * the queue is empty. - */ -#define DUK_REFZERO_CHECK_FAST(thr) do { \ - if ((thr)->heap->refzero_list != NULL) { \ - duk_refzero_free_pending((thr)); \ - } \ - } while (0) -#define DUK_REFZERO_CHECK_SLOW(thr) do { \ - duk_refzero_free_pending((thr)); \ - } while (0) - -/* - * Macros to set a duk_tval and update refcount of the target (decref the - * old value and incref the new value if necessary). This is both performance - * and footprint critical; any changes made should be measured for size/speed. - */ - -#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_UNDEFINED(tv__dst); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_UNDEFINED(tv__dst); \ - DUK_TVAL_DECREF_NORZ((thr), &tv__tmp); \ - } while (0) - -#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_UNUSED(tv__dst); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_NULL(tv__dst); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) -#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) -#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) -#define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_NAN(tv__dst); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) -#if defined(DUK_USE_FASTINT) -#define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_I48(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) -#define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_I32(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) -#define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_U32(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) -#else -#define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \ - DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval)) -#endif /* DUK_USE_FASTINT */ - -#define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_STRING(tv__dst, (newval)); \ - DUK_HSTRING_INCREF((thr), (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \ - DUK_HOBJECT_INCREF((thr), (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \ - DUK_HBUFFER_INCREF((thr), (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_POINTER(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -/* DUK_TVAL_SET_TVAL_UPDREF() is used a lot in executor, property lookups, - * etc, so it's very important for performance. Measure when changing. - * - * NOTE: the source and destination duk_tval pointers may be the same, and - * the macros MUST deal with that correctly. - */ - -/* Original idiom used, minimal code size. */ -#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \ - duk_tval *tv__dst, *tv__src; duk_tval tv__tmp; \ - tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ - DUK_TVAL_INCREF((thr), tv__src); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -/* Faster alternative: avoid making a temporary copy of tvptr_dst and use - * fast incref/decref macros. - */ -#define DUK_TVAL_SET_TVAL_UPDREF_ALT1(thr,tvptr_dst,tvptr_src) do { \ - duk_tval *tv__dst, *tv__src; duk_heaphdr *h__obj; \ - tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ - DUK_TVAL_INCREF_FAST((thr), tv__src); \ - if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv__dst)) { \ - h__obj = DUK_TVAL_GET_HEAPHDR(tv__dst); \ - DUK_ASSERT(h__obj != NULL); \ - DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ - DUK_HEAPHDR_DECREF_FAST((thr), h__obj); /* side effects */ \ - } else { \ - DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ - } \ - } while (0) - -/* XXX: no optimized variants yet */ -#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 -#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0 -#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0 -#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0 -#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0 -#define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0 -#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0 -#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0 -#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0 -#if defined(DUK_USE_FASTINT) -#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_I48_UPDREF_ALT0 -#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_I32_UPDREF_ALT0 -#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_U32_UPDREF_ALT0 -#else -#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast int-to-double */ -#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF -#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF -#endif /* DUK_USE_FASTINT */ -#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_I48_UPDREF /* convenience */ -#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0 -#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0 -#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0 -#define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0 -#define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0 - -#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) -/* Optimized for speed. */ -#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT1 -#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT1 -#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0 -#else -/* Optimized for size. */ -#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0 -#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0 -#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0 -#endif - -#else /* DUK_USE_REFERENCE_COUNTING */ - -#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) 0 -#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 0 - -#define DUK_TVAL_INCREF_FAST(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_DECREF_FAST(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_DECREF_NORZ_FAST(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_INCREF_SLOW(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_DECREF_SLOW(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_DECREF_NORZ_SLOW(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_INCREF(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_DECREF(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_DECREF_NORZ(thr,v) do {} while (0) /* nop */ -#define DUK_HEAPHDR_INCREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_DECREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_DECREF_NORZ(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_INCREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_DECREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_INCREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_DECREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_DECREF_NORZ(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_INCREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_INCREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF_NORZ(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_INCREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_INCREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF_NORZ(thr,h) do {} while (0) /* nop */ - -#define DUK_HCOMPFUNC_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HCOMPFUNC_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) do {} while (0) /* nop */ -#define DUK_HNATFUNC_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HNATFUNC_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HNATFUNC_DECREF_NORZ(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFOBJ_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFOBJ_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFOBJ_DECREF_NORZ(thr,h) do {} while (0) /* nop */ -#define DUK_HTHREAD_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HTHREAD_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HTHREAD_DECREF_NORZ(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do {} while (0) /* nop */ - -#define DUK_REFZERO_CHECK_FAST(thr) do {} while (0) /* nop */ -#define DUK_REFZERO_CHECK_SLOW(thr) do {} while (0) /* nop */ - -#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_UNDEFINED(tv__dst); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_UNUSED(tv__dst); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_NULL(tv__dst); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) -#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) -#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) -#define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_NAN(tv__dst); \ - DUK_UNREF((thr)); \ - } while (0) -#if defined(DUK_USE_FASTINT) -#define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_I48(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) -#define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_I32(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) -#define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_U32(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) -#else -#define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \ - DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval)) -#endif /* DUK_USE_FASTINT */ - -#define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_STRING(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_POINTER(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \ - duk_tval *tv__dst, *tv__src; \ - tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ - DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 -#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 -#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0 -#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0 -#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0 -#define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0 -#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0 -#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0 -#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0 -#if defined(DUK_USE_FASTINT) -#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_I48_UPDREF_ALT0 -#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_I32_UPDREF_ALT0 -#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_U32_UPDREF_ALT0 -#else -#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast-int-to-double */ -#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF -#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF -#endif /* DUK_USE_FASTINT */ -#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_I48_UPDREF /* convenience */ -#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0 -#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0 -#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0 -#define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0 -#define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0 - -#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0 -#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0 -#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0 - -#endif /* DUK_USE_REFERENCE_COUNTING */ #endif /* DUK_HEAPHDR_H_INCLUDED */ diff -Nru duktape-2.0.0/src-input/duk_heap_markandsweep.c duktape-2.1.1/src-input/duk_heap_markandsweep.c --- duktape-2.0.0/src-input/duk_heap_markandsweep.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_heap_markandsweep.c 2017-07-28 22:05:08.000000000 +0000 @@ -8,22 +8,7 @@ DUK_LOCAL_DECL void duk__mark_tval(duk_heap *heap, duk_tval *tv); /* - * Misc - */ - -/* Select a thread for mark-and-sweep use. - * - * XXX: This needs to change later. - */ -DUK_LOCAL duk_hthread *duk__get_temp_hthread(duk_heap *heap) { - if (heap->curr_thread) { - return heap->curr_thread; - } - return heap->heap_thread; /* may be NULL, too */ -} - -/* - * Marking functions for heap types: mark children recursively + * Marking functions for heap types: mark children recursively. */ DUK_LOCAL void duk__mark_hstring(duk_heap *heap, duk_hstring *h) { @@ -47,7 +32,7 @@ for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) { duk_hstring *key = DUK_HOBJECT_E_GET_KEY(heap, h, i); - if (!key) { + if (key == NULL) { continue; } duk__mark_heaphdr(heap, (duk_heaphdr *) key); @@ -63,15 +48,19 @@ duk__mark_tval(heap, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i)); } - /* hash part is a 'weak reference' and does not contribute */ + /* Hash part is a 'weak reference' and does not contribute. */ duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h)); - /* XXX: rearrange bits to allow a switch case to be used here? */ - /* XXX: add a fast path for objects (and arrays)? */ - /* DUK_HOBJECT_IS_ARRAY(h): needs no special handling now as there are - * no extra fields in need of marking. + /* Fast path for objects which don't have a subclass struct, or have a + * subclass struct but nothing that needs marking in the subclass struct. */ + if (DUK_HOBJECT_HAS_FASTREFS(h)) { + DUK_ASSERT(DUK_HOBJECT_ALLOWS_FASTREFS(h)); + return; + } + DUK_ASSERT(DUK_HOBJECT_PROHIBITS_FASTREFS(h)); + if (DUK_HOBJECT_IS_COMPFUNC(h)) { duk_hcompfunc *f = (duk_hcompfunc *) h; duk_tval *tv, *tv_end; @@ -103,16 +92,21 @@ /* May happen in some out-of-memory corner cases. */ DUK_D(DUK_DPRINT("duk_hcompfunc 'data' is NULL, skipping marking")); } - } else if (DUK_HOBJECT_IS_NATFUNC(h)) { - duk_hnatfunc *f = (duk_hnatfunc *) h; - DUK_UNREF(f); - /* nothing to mark */ #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) } else if (DUK_HOBJECT_IS_BUFOBJ(h)) { duk_hbufobj *b = (duk_hbufobj *) h; duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf); duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf_prop); #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + } else if (DUK_HOBJECT_IS_DECENV(h)) { + duk_hdecenv *e = (duk_hdecenv *) h; + DUK_ASSERT_HDECENV_VALID(e); + duk__mark_heaphdr(heap, (duk_heaphdr *) e->thread); + duk__mark_heaphdr(heap, (duk_heaphdr *) e->varmap); + } else if (DUK_HOBJECT_IS_OBJENV(h)) { + duk_hobjenv *e = (duk_hobjenv *) h; + DUK_ASSERT_HOBJENV_VALID(e); + duk__mark_heaphdr(heap, (duk_heaphdr *) e->target); } else if (DUK_HOBJECT_IS_THREAD(h)) { duk_hthread *t = (duk_hthread *) h; duk_tval *tv; @@ -141,19 +135,25 @@ duk__mark_heaphdr(heap, (duk_heaphdr *) t->resumer); - /* XXX: duk_small_uint_t would be enough for this loop */ for (i = 0; i < DUK_NUM_BUILTINS; i++) { duk__mark_heaphdr(heap, (duk_heaphdr *) t->builtins[i]); } + } 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); } } -/* recursion tracking happens here only */ +/* Mark any duk_heaphdr type. Recursion tracking happens only here. */ DUK_LOCAL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h) { DUK_DDD(DUK_DDDPRINT("duk__mark_heaphdr %p, type %ld", (void *) h, (h != NULL ? (long) DUK_HEAPHDR_GET_TYPE(h) : (long) -1))); - if (!h) { + if (h == NULL) { return; } #if defined(DUK_USE_ROM_OBJECTS) @@ -162,21 +162,24 @@ return; } #endif +#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) + h->h_assert_refcount++; /* Comparison refcount: bump even if already reachable. */ +#endif if (DUK_HEAPHDR_HAS_REACHABLE(h)) { DUK_DDD(DUK_DDDPRINT("already marked reachable, skip")); return; } DUK_HEAPHDR_SET_REACHABLE(h); - if (heap->mark_and_sweep_recursion_depth >= DUK_USE_MARK_AND_SWEEP_RECLIMIT) { - /* log this with a normal debug level because this should be relatively rare */ + if (heap->ms_recursion_depth >= DUK_USE_MARK_AND_SWEEP_RECLIMIT) { DUK_D(DUK_DPRINT("mark-and-sweep recursion limit reached, marking as temproot: %p", (void *) h)); DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap); DUK_HEAPHDR_SET_TEMPROOT(h); return; } - heap->mark_and_sweep_recursion_depth++; + heap->ms_recursion_depth++; + DUK_ASSERT(heap->ms_recursion_depth != 0); /* Wrap. */ switch (DUK_HEAPHDR_GET_TYPE(h)) { case DUK_HTYPE_STRING: @@ -193,12 +196,13 @@ DUK_UNREACHABLE(); } - heap->mark_and_sweep_recursion_depth--; + DUK_ASSERT(heap->ms_recursion_depth > 0); + heap->ms_recursion_depth--; } DUK_LOCAL void duk__mark_tval(duk_heap *heap, duk_tval *tv) { DUK_DDD(DUK_DDDPRINT("duk__mark_tval %p", (void *) tv)); - if (!tv) { + if (tv == NULL) { return; } if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { @@ -234,37 +238,12 @@ } /* - * Mark refzero_list objects. - * - * Objects on the refzero_list have no inbound references. They might have - * outbound references to objects that we might free, which would invalidate - * any references held by the refzero objects. A refzero object might also - * be rescued by refcount finalization. Refzero objects are treated as - * reachability roots to ensure they (or anything they point to) are not - * freed in mark-and-sweep. - */ - -#if defined(DUK_USE_REFERENCE_COUNTING) -DUK_LOCAL void duk__mark_refzero_list(duk_heap *heap) { - duk_heaphdr *hdr; - - DUK_DD(DUK_DDPRINT("duk__mark_refzero_list: %p", (void *) heap)); - - hdr = heap->refzero_list; - while (hdr) { - duk__mark_heaphdr(heap, hdr); - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -} -#endif - -/* * Mark unreachable, finalizable objects. * - * Such objects will be moved aside and their finalizers run later. They have - * to be treated as reachability roots for their properties etc to remain - * allocated. This marking is only done for unreachable values which would - * be swept later (refzero_list is thus excluded). + * Such objects will be moved aside and their finalizers run later. They + * have to be treated as reachability roots for their properties etc to + * remain allocated. This marking is only done for unreachable values which + * would be swept later. * * Objects are first marked FINALIZABLE and only then marked as reachability * roots; otherwise circular references might be handled inconsistently. @@ -272,32 +251,30 @@ #if defined(DUK_USE_FINALIZER_SUPPORT) DUK_LOCAL void duk__mark_finalizable(duk_heap *heap) { - duk_hthread *thr; duk_heaphdr *hdr; duk_size_t count_finalizable = 0; DUK_DD(DUK_DDPRINT("duk__mark_finalizable: %p", (void *) heap)); - thr = duk__get_temp_hthread(heap); - DUK_ASSERT(thr != NULL); + DUK_ASSERT(heap->heap_thread != NULL); hdr = heap->heap_allocated; - while (hdr) { - /* A finalizer is looked up from the object and up its prototype chain - * (which allows inherited finalizers). A prototype loop must not cause - * an error to be thrown here; duk_hobject_hasprop_raw() will ignore a - * prototype loop silently and indicate that the property doesn't exist. + while (hdr != NULL) { + /* A finalizer is looked up from the object and up its + * prototype chain (which allows inherited finalizers). + * The finalizer is checked for using a duk_hobject flag + * which is kept in sync with the presence and callability + * of a _Finalizer hidden symbol. */ if (!DUK_HEAPHDR_HAS_REACHABLE(hdr) && - DUK_HEAPHDR_GET_TYPE(hdr) == DUK_HTYPE_OBJECT && + DUK_HEAPHDR_IS_OBJECT(hdr) && !DUK_HEAPHDR_HAS_FINALIZED(hdr) && - duk_hobject_hasprop_raw(thr, (duk_hobject *) hdr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) { - + DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) hdr)) { /* heaphdr: * - is not reachable * - is an object - * - is not a finalized object + * - is not a finalized object waiting for rescue/keep decision * - has a finalizer */ @@ -307,7 +284,7 @@ (void *) hdr)); DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr)); DUK_HEAPHDR_SET_FINALIZABLE(hdr); - count_finalizable ++; + count_finalizable++; } hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); @@ -321,7 +298,7 @@ (long) count_finalizable)); hdr = heap->heap_allocated; - while (hdr) { + while (hdr != NULL) { if (DUK_HEAPHDR_HAS_FINALIZABLE(hdr)) { duk__mark_heaphdr(heap, hdr); } @@ -335,7 +312,6 @@ /* * Mark objects on finalize_list. - * */ #if defined(DUK_USE_FINALIZER_SUPPORT) @@ -348,7 +324,7 @@ DUK_DD(DUK_DDPRINT("duk__mark_finalize_list: %p", (void *) heap)); hdr = heap->finalize_list; - while (hdr) { + while (hdr != NULL) { duk__mark_heaphdr(heap, hdr); hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); #if defined(DUK_USE_DEBUG) @@ -368,15 +344,18 @@ /* * Fallback marking handler if recursion limit is reached. * - * Iterates 'temproots' until recursion limit is no longer hit. Note - * that temproots may reside either in heap allocated list or the - * refzero work list. This is a slow scan, but guarantees that we - * finish with a bounded C stack. + * Iterates 'temproots' until recursion limit is no longer hit. Temproots + * can be in heap_allocated or finalize_list; refzero_list is now always + * empty for mark-and-sweep. A temproot may occur in finalize_list now if + * there are objects on the finalize_list and user code creates a reference + * from an object in heap_allocated to the object in finalize_list (which is + * now allowed), and it happened to coincide with the recursion depth limit. + * + * This is a slow scan, but guarantees that we finish with a bounded C stack. * - * Note that nodes may have been marked as temproots before this - * scan begun, OR they may have been marked during the scan (as - * we process nodes recursively also during the scan). This is - * intended behavior. + * Note that nodes may have been marked as temproots before this scan begun, + * OR they may have been marked during the scan (as we process nodes + * recursively also during the scan). This is intended behavior. */ #if defined(DUK_USE_DEBUG) @@ -391,7 +370,10 @@ DUK_DDD(DUK_DDDPRINT("found a temp root: %p", (void *) hdr)); DUK_HEAPHDR_CLEAR_TEMPROOT(hdr); - DUK_HEAPHDR_CLEAR_REACHABLE(hdr); /* done so that duk__mark_heaphdr() works correctly */ + DUK_HEAPHDR_CLEAR_REACHABLE(hdr); /* Done so that duk__mark_heaphdr() works correctly. */ +#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) + hdr->h_assert_refcount--; /* Same node visited twice. */ +#endif duk__mark_heaphdr(heap, hdr); #if defined(DUK_USE_DEBUG) @@ -425,9 +407,8 @@ hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); } - /* must also check refzero_list */ -#if defined(DUK_USE_REFERENCE_COUNTING) - hdr = heap->refzero_list; +#if defined(DUK_USE_FINALIZER_SUPPORT) + hdr = heap->finalize_list; while (hdr) { #if defined(DUK_USE_DEBUG) duk__handle_temproot(heap, hdr, &count); @@ -436,7 +417,7 @@ #endif hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); } -#endif /* DUK_USE_REFERENCE_COUNTING */ +#endif #if defined(DUK_USE_DEBUG) DUK_DD(DUK_DDPRINT("temproot mark heap scan processed %ld temp roots", (long) count)); @@ -455,14 +436,11 @@ #if defined(DUK_USE_REFERENCE_COUNTING) DUK_LOCAL void duk__finalize_refcounts(duk_heap *heap) { - duk_hthread *thr; duk_heaphdr *hdr; - thr = duk__get_temp_hthread(heap); - DUK_ASSERT(thr != NULL); + DUK_ASSERT(heap->heap_thread != NULL); - DUK_DD(DUK_DDPRINT("duk__finalize_refcounts: heap=%p, hthread=%p", - (void *) heap, (void *) thr)); + DUK_DD(DUK_DDPRINT("duk__finalize_refcounts: heap=%p", (void *) heap)); hdr = heap->heap_allocated; while (hdr) { @@ -478,37 +456,21 @@ */ DUK_DDD(DUK_DDDPRINT("unreachable object, refcount finalize before sweeping: %p", (void *) hdr)); - duk_heaphdr_refcount_finalize(thr, hdr); - } - - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -} -#endif /* DUK_USE_REFERENCE_COUNTING */ -/* - * Clear (reachable) flags of refzero work list. - */ - -#if defined(DUK_USE_REFERENCE_COUNTING) -DUK_LOCAL void duk__clear_refzero_list_flags(duk_heap *heap) { - duk_heaphdr *hdr; - - DUK_DD(DUK_DDPRINT("duk__clear_refzero_list_flags: %p", (void *) heap)); + /* Finalize using heap->heap_thread; DECREF has a + * suppress check for mark-and-sweep which is based + * on heap->ms_running. + */ + duk_heaphdr_refcount_finalize_norz(heap, hdr); + } - hdr = heap->refzero_list; - while (hdr) { - DUK_HEAPHDR_CLEAR_REACHABLE(hdr); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr)); hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); } } #endif /* DUK_USE_REFERENCE_COUNTING */ /* - * Clear (reachable) flags of finalize_list + * Clear (reachable) flags of finalize_list. * * We could mostly do in the sweep phase when we move objects from the * heap into the finalize_list. However, if a finalizer run is skipped @@ -527,8 +489,11 @@ hdr = heap->finalize_list; while (hdr) { DUK_HEAPHDR_CLEAR_REACHABLE(hdr); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr)); +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(hdr) || \ + (heap->currently_finalizing == hdr)); +#endif + /* DUK_HEAPHDR_FLAG_FINALIZED may be set. */ DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr)); hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); } @@ -536,191 +501,85 @@ #endif /* DUK_USE_FINALIZER_SUPPORT */ /* - * Sweep stringtable + * Sweep stringtable. */ -#if defined(DUK_USE_STRTAB_CHAIN) - -/* XXX: skip count_free w/o debug? */ -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL void duk__sweep_string_chain16(duk_heap *heap, duk_uint16_t *slot, duk_size_t *count_keep, duk_size_t *count_free) { - duk_uint16_t h16 = *slot; +DUK_LOCAL void duk__sweep_stringtable(duk_heap *heap, duk_size_t *out_count_keep) { duk_hstring *h; - duk_uint16_t null16 = heap->heapptr_null16; - - if (h16 == null16) { - /* nop */ - return; - } - h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, h16); - DUK_ASSERT(h != NULL); - - if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) { - DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h); - (*count_keep)++; - } else { -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0); -#endif - /* deal with weak references first */ - duk_heap_strcache_string_remove(heap, (duk_hstring *) h); - *slot = null16; - - /* free inner references (these exist e.g. when external - * strings are enabled) - */ - duk_free_hstring(heap, h); - (*count_free)++; - } -} -#else /* DUK_USE_HEAPPTR16 */ -DUK_LOCAL void duk__sweep_string_chain(duk_heap *heap, duk_hstring **slot, duk_size_t *count_keep, duk_size_t *count_free) { - duk_hstring *h = *slot; - - if (h == NULL) { - /* nop */ - return; - } - - if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) { - DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h); - (*count_keep)++; - } else { -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0); -#endif - /* deal with weak references first */ - duk_heap_strcache_string_remove(heap, (duk_hstring *) h); - *slot = NULL; - - /* free inner references (these exist e.g. when external - * strings are enabled) - */ - duk_free_hstring(heap, h); - (*count_free)++; - } -} -#endif /* DUK_USE_HEAPPTR16 */ - -DUK_LOCAL void duk__sweep_stringtable_chain(duk_heap *heap, duk_size_t *out_count_keep) { - duk_strtab_entry *e; - duk_uint_fast32_t i; + duk_hstring *prev; + duk_uint32_t i; +#if defined(DUK_USE_DEBUG) duk_size_t count_free = 0; - duk_size_t count_keep = 0; - duk_size_t j, n; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t *lst; -#else - duk_hstring **lst; #endif + duk_size_t count_keep = 0; DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap)); - /* Non-zero refcounts should not happen for unreachable strings, - * because we refcount finalize all unreachable objects which - * should have decreased unreachable string refcounts to zero - * (even for cycles). - */ - - for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { - e = heap->strtable + i; - if (e->listlen == 0) { -#if defined(DUK_USE_HEAPPTR16) - duk__sweep_string_chain16(heap, &e->u.str16, &count_keep, &count_free); -#else - duk__sweep_string_chain(heap, &e->u.str, &count_keep, &count_free); -#endif - } else { -#if defined(DUK_USE_HEAPPTR16) - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); +#if defined(DUK_USE_STRTAB_PTRCOMP) + if (heap->strtable16 == NULL) { #else - lst = e->u.strlist; + if (heap->strtable == NULL) { #endif - for (j = 0, n = e->listlen; j < n; j++) { -#if defined(DUK_USE_HEAPPTR16) - duk__sweep_string_chain16(heap, lst + j, &count_keep, &count_free); -#else - duk__sweep_string_chain(heap, lst + j, &count_keep, &count_free); -#endif - } - } + goto done; } - DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept", - (long) count_free, (long) count_keep)); - *out_count_keep = count_keep; -} -#endif /* DUK_USE_STRTAB_CHAIN */ - -#if defined(DUK_USE_STRTAB_PROBE) -DUK_LOCAL void duk__sweep_stringtable_probe(duk_heap *heap, duk_size_t *out_count_keep) { - duk_hstring *h; - duk_uint_fast32_t i; -#if defined(DUK_USE_DEBUG) - duk_size_t count_free = 0; -#endif - duk_size_t count_keep = 0; - - DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap)); - for (i = 0; i < heap->st_size; i++) { -#if defined(DUK_USE_HEAPPTR16) - h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); +#if defined(DUK_USE_STRTAB_PTRCOMP) + h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); #else h = heap->strtable[i]; #endif - if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) { - continue; - } else if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) { - DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h); - count_keep++; - continue; - } - + prev = NULL; + while (h != NULL) { + duk_hstring *next; + next = h->hdr.h_next; + + if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) { + DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h); + count_keep++; + prev = h; + } else { #if defined(DUK_USE_DEBUG) - count_free++; + count_free++; #endif #if defined(DUK_USE_REFERENCE_COUNTING) - /* Non-zero refcounts should not happen for unreachable strings, - * because we refcount finalize all unreachable objects which - * should have decreased unreachable string refcounts to zero - * (even for cycles). - */ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0); + /* Non-zero refcounts should not happen for unreachable strings, + * because we refcount finalize all unreachable objects which + * should have decreased unreachable string refcounts to zero + * (even for cycles). + */ + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0); #endif - DUK_DDD(DUK_DDDPRINT("sweep string, not reachable: %p", (void *) h)); + /* Deal with weak references first. */ + duk_heap_strcache_string_remove(heap, (duk_hstring *) h); - /* deal with weak references first */ - duk_heap_strcache_string_remove(heap, (duk_hstring *) h); + /* Remove the string from the string table. */ + duk_heap_strtable_unlink_prev(heap, (duk_hstring *) h, (duk_hstring *) prev); - /* remove the string (mark DELETED), could also call - * duk_heap_string_remove() but that would be slow and - * pointless because we already know the slot. - */ -#if defined(DUK_USE_HEAPPTR16) - heap->strtable16[i] = heap->heapptr_deleted16; -#else - heap->strtable[i] = DUK_STRTAB_DELETED_MARKER(heap); -#endif + /* Free inner references (these exist e.g. when external + * strings are enabled) and the struct itself. + */ + duk_free_hstring(heap, (duk_hstring *) h); - /* free inner references (these exist e.g. when external - * strings are enabled) and the struct itself. - */ - duk_free_hstring(heap, (duk_hstring *) h); + /* Don't update 'prev'; it should be last string kept. */ + } + + h = next; + } } + done: #if defined(DUK_USE_DEBUG) DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept", (long) count_free, (long) count_keep)); #endif *out_count_keep = count_keep; } -#endif /* DUK_USE_STRTAB_PROBE */ /* - * Sweep heap + * Sweep heap. */ DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_count_keep) { @@ -749,65 +608,62 @@ if (DUK_HEAPHDR_HAS_REACHABLE(curr)) { /* - * Reachable object, keep + * Reachable object: + * - If FINALIZABLE -> actually unreachable (but marked + * artificially reachable), queue to finalize_list. + * - If !FINALIZABLE but FINALIZED -> rescued after + * finalizer execution. + * - Otherwise just a normal, reachable object. + * + * Objects which are kept are queued to heap_allocated + * tail (we're essentially filtering heap_allocated in + * practice). */ - DUK_DDD(DUK_DDDPRINT("sweep, reachable: %p", (void *) curr)); - - if (DUK_HEAPHDR_HAS_FINALIZABLE(curr)) { - /* - * If object has been marked finalizable, move it to the - * "to be finalized" work list. It will be collected on - * the next mark-and-sweep if it is still unreachable - * after running the finalizer. - */ - +#if defined(DUK_USE_FINALIZER_SUPPORT) + if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZABLE(curr))) { DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); - DUK_DDD(DUK_DDDPRINT("object has finalizer, move to finalization work list: %p", (void *) curr)); + DUK_DD(DUK_DDPRINT("sweep; reachable, finalizable --> move to finalize_list: %p", (void *) curr)); -#if defined(DUK_USE_DOUBLE_LINKED_HEAP) - if (heap->finalize_list) { - DUK_HEAPHDR_SET_PREV(heap, heap->finalize_list, curr); - } - DUK_HEAPHDR_SET_PREV(heap, curr, NULL); +#if defined(DUK_USE_REFERENCE_COUNTING) + DUK_HEAPHDR_PREINC_REFCOUNT(curr); /* Bump refcount so that refzero never occurs when pending a finalizer call. */ #endif - DUK_HEAPHDR_SET_NEXT(heap, curr, heap->finalize_list); - DUK_ASSERT_HEAPHDR_LINKS(heap, curr); - heap->finalize_list = curr; + DUK_HEAP_INSERT_INTO_FINALIZE_LIST(heap, curr); #if defined(DUK_USE_DEBUG) count_finalize++; #endif - } else { - /* - * Object will be kept; queue object back to heap_allocated (to tail) - */ - - if (DUK_HEAPHDR_HAS_FINALIZED(curr)) { - /* - * Object's finalizer was executed on last round, and - * object has been happily rescued. - */ - + } + else +#endif /* DUK_USE_FINALIZER_SUPPORT */ + { + if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZED(curr))) { DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); - DUK_DD(DUK_DDPRINT("object rescued during mark-and-sweep finalization: %p", (void *) curr)); + + if (flags & DUK_MS_FLAG_POSTPONE_RESCUE) { + DUK_DD(DUK_DDPRINT("sweep; reachable, finalized, but postponing rescue decisions --> keep object (with FINALIZED set): %!iO", curr)); + count_keep++; + } else { + DUK_DD(DUK_DDPRINT("sweep; reachable, finalized --> rescued after finalization: %p", (void *) curr)); +#if defined(DUK_USE_FINALIZER_SUPPORT) + DUK_HEAPHDR_CLEAR_FINALIZED(curr); +#endif #if defined(DUK_USE_DEBUG) - count_rescue++; + count_rescue++; #endif + } } else { - /* - * Plain, boring reachable object. - */ - DUK_DD(DUK_DDPRINT("keep object: %!iO", curr)); + DUK_DD(DUK_DDPRINT("sweep; reachable --> keep: %!iO", curr)); count_keep++; } - if (!heap->heap_allocated) { - heap->heap_allocated = curr; - } - if (prev) { + if (prev != NULL) { + DUK_ASSERT(heap->heap_allocated != NULL); DUK_HEAPHDR_SET_NEXT(heap, prev, curr); + } else { + DUK_ASSERT(heap->heap_allocated == NULL); + heap->heap_allocated = curr; } #if defined(DUK_USE_DOUBLE_LINKED_HEAP) DUK_HEAPHDR_SET_PREV(heap, curr, prev); @@ -818,21 +674,23 @@ } DUK_HEAPHDR_CLEAR_REACHABLE(curr); - DUK_HEAPHDR_CLEAR_FINALIZED(curr); - DUK_HEAPHDR_CLEAR_FINALIZABLE(curr); - + /* Keep FINALIZED if set, used if rescue decisions are postponed. */ + /* Keep FINALIZABLE for objects on finalize_list. */ DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); - - curr = next; } else { /* - * Unreachable object, free + * Unreachable object: + * - If FINALIZED, object was finalized but not + * rescued. This doesn't affect freeing. + * - Otherwise normal unreachable object. + * + * There's no guard preventing a FINALIZED object + * from being freed while finalizers execute: the + * artificial finalize_list reachability roots can't + * cause an incorrect free decision (but can cause + * an incorrect rescue decision). */ - DUK_DDD(DUK_DDDPRINT("sweep, not reachable: %p", (void *) curr)); - #if defined(DUK_USE_REFERENCE_COUNTING) /* Non-zero refcounts should not happen because we refcount * finalize all unreachable objects which should cancel out @@ -842,10 +700,15 @@ #endif DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); +#if defined(DUK_USE_DEBUG) if (DUK_HEAPHDR_HAS_FINALIZED(curr)) { - DUK_DDD(DUK_DDDPRINT("finalized object not rescued: %p", (void *) curr)); + DUK_DD(DUK_DDPRINT("sweep; unreachable, finalized --> finalized object not rescued: %p", (void *) curr)); + } else { + DUK_DD(DUK_DDPRINT("sweep; not reachable --> free: %p", (void *) curr)); } +#endif + /* Note: object cannot be a finalizable unreachable object, as * they have been marked temporarily reachable for this round, * and are handled above. @@ -855,17 +718,18 @@ count_free++; #endif - /* weak refs should be handled here, but no weak refs for + /* Weak refs should be handled here, but no weak refs for * any non-string objects exist right now. */ - /* free object and all auxiliary (non-heap) allocs */ + /* Free object and all auxiliary (non-heap) allocs. */ duk_heap_free_heaphdr_raw(heap, curr); - - curr = next; } + + curr = next; } - if (prev) { + + if (prev != NULL) { DUK_HEAPHDR_SET_NEXT(heap, prev, NULL); } DUK_ASSERT_HEAPHDR_LINKS(heap, prev); @@ -878,71 +742,6 @@ } /* - * Run (object) finalizers in the "to be finalized" work list. - */ - -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_LOCAL void duk__run_object_finalizers(duk_heap *heap, duk_small_uint_t flags) { - duk_heaphdr *curr; - duk_heaphdr *next; -#if defined(DUK_USE_DEBUG) - duk_size_t count = 0; -#endif - duk_hthread *thr; - - DUK_DD(DUK_DDPRINT("duk__run_object_finalizers: %p", (void *) heap)); - - thr = duk__get_temp_hthread(heap); - DUK_ASSERT(thr != NULL); - - curr = heap->finalize_list; - while (curr) { - DUK_DDD(DUK_DDDPRINT("mark-and-sweep finalize: %p", (void *) curr)); - - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* only objects have finalizers */ - DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr)); /* flags have been already cleared */ - DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr)); /* No finalizers for ROM objects */ - - if (DUK_LIKELY((flags & DUK_MS_FLAG_SKIP_FINALIZERS) == 0)) { - /* Run the finalizer, duk_hobject_run_finalizer() sets FINALIZED. - * Next mark-and-sweep will collect the object unless it has - * become reachable (i.e. rescued). FINALIZED prevents the - * finalizer from being executed again before that. - */ - duk_hobject_run_finalizer(thr, (duk_hobject *) curr); /* must never longjmp */ - DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(curr)); - } 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)); - } - - /* queue back to heap_allocated */ - next = DUK_HEAPHDR_GET_NEXT(heap, curr); - DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr); - - curr = next; -#if defined(DUK_USE_DEBUG) - count++; -#endif - } - - /* finalize_list will always be processed completely */ - heap->finalize_list = NULL; - -#if defined(DUK_USE_DEBUG) - DUK_D(DUK_DPRINT("mark-and-sweep finalize objects: %ld finalizers called", (long) count)); -#endif -} -#endif /* DUK_USE_FINALIZER_SUPPORT */ - -/* * Object compaction. * * Compaction is assumed to never throw an error. @@ -1017,26 +816,25 @@ duk_size_t count_compact = 0; duk_size_t count_bytes_saved = 0; #endif - duk_hthread *thr; DUK_DD(DUK_DDPRINT("duk__compact_objects: %p", (void *) heap)); - thr = duk__get_temp_hthread(heap); - DUK_ASSERT(thr != NULL); + DUK_ASSERT(heap->heap_thread != NULL); #if defined(DUK_USE_DEBUG) - duk__compact_object_list(heap, thr, heap->heap_allocated, &count_check, &count_compact, &count_bytes_saved); - duk__compact_object_list(heap, thr, heap->finalize_list, &count_check, &count_compact, &count_bytes_saved); -#if defined(DUK_USE_REFERENCE_COUNTING) - duk__compact_object_list(heap, thr, heap->refzero_list, &count_check, &count_compact, &count_bytes_saved); + duk__compact_object_list(heap, heap->heap_thread, heap->heap_allocated, &count_check, &count_compact, &count_bytes_saved); +#if defined(DUK_USE_FINALIZER_SUPPORT) + duk__compact_object_list(heap, heap->heap_thread, heap->finalize_list, &count_check, &count_compact, &count_bytes_saved); #endif #else - duk__compact_object_list(heap, thr, heap->heap_allocated); - duk__compact_object_list(heap, thr, heap->finalize_list); -#if defined(DUK_USE_REFERENCE_COUNTING) - duk__compact_object_list(heap, thr, heap->refzero_list); + duk__compact_object_list(heap, heap->heap_thread, heap->heap_allocated); +#if defined(DUK_USE_FINALIZER_SUPPORT) + duk__compact_object_list(heap, heap->heap_thread, heap->finalize_list); #endif #endif +#if defined(DUK_USE_REFERENCE_COUNTING) + DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ +#endif #if defined(DUK_USE_DEBUG) DUK_D(DUK_DPRINT("mark-and-sweep compact objects: %ld checked, %ld compaction attempts, %ld bytes saved by compaction", @@ -1062,166 +860,189 @@ } #if defined(DUK_USE_REFERENCE_COUNTING) - hdr = heap->refzero_list; - while (hdr) { - DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr)); - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -#endif /* DUK_USE_REFERENCE_COUNTING */ + DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ +#endif } #if defined(DUK_USE_REFERENCE_COUNTING) DUK_LOCAL void duk__assert_valid_refcounts(duk_heap *heap) { duk_heaphdr *hdr = heap->heap_allocated; while (hdr) { + /* Cannot really assert much w.r.t. refcounts now. */ + if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0 && DUK_HEAPHDR_HAS_FINALIZED(hdr)) { /* An object may be in heap_allocated list with a zero * refcount if it has just been finalized and is waiting * to be collected by the next cycle. + * (This doesn't currently happen however.) */ } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0) { /* An object may be in heap_allocated list with a zero - * refcount also if it is a temporary object created by - * a finalizer; because finalization now runs inside - * mark-and-sweep, such objects will not be queued to - * refzero_list and will thus appear here with refcount - * zero. + * refcount also if it is a temporary object created + * during debugger paused state. It will get collected + * by mark-and-sweep based on its reachability status + * (presumably not reachable because refcount is 0). */ -#if 0 /* this case can no longer occur because refcount is unsigned */ - } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) < 0) { - DUK_D(DUK_DPRINT("invalid refcount: %ld, %p -> %!O", - (hdr != NULL ? (long) DUK_HEAPHDR_GET_REFCOUNT(hdr) : (long) 0), - (void *) hdr, (duk_heaphdr *) hdr)); - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(hdr) > 0); -#endif } + DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(hdr) >= 0); /* Unsigned. */ hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); } } -#endif /* DUK_USE_REFERENCE_COUNTING */ -#endif /* DUK_USE_ASSERTIONS */ -/* - * Finalizer torture. Do one fake finalizer call which causes side effects - * similar to one or more finalizers on actual objects. - */ +DUK_LOCAL void duk__clear_assert_refcounts(duk_heap *heap) { + duk_heaphdr *curr; + duk_uint32_t i; + for (curr = heap->heap_allocated; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { + curr->h_assert_refcount = 0; + } #if defined(DUK_USE_FINALIZER_SUPPORT) -#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE) -DUK_LOCAL duk_ret_t duk__markandsweep_fake_finalizer(duk_context *ctx) { - DUK_D(DUK_DPRINT("fake mark-and-sweep torture finalizer executed")); - - /* Require a lot of stack to force a value stack grow/shrink. - * Recursive mark-and-sweep is prevented by allocation macros - * so this won't trigger another mark-and-sweep. - */ - duk_require_stack(ctx, 100000); + for (curr = heap->finalize_list; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { + curr->h_assert_refcount = 0; + } +#endif +#if defined(DUK_USE_REFERENCE_COUNTING) + for (curr = heap->refzero_list; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { + curr->h_assert_refcount = 0; + } +#endif - /* XXX: do something to force a callstack grow/shrink, perhaps - * just a manual forced resize or a forced relocating realloc? - */ + for (i = 0; i < heap->st_size; i++) { + duk_hstring *h; - return 0; +#if defined(DUK_USE_STRTAB_PTRCOMP) + h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); +#else + h = heap->strtable[i]; +#endif + while (h != NULL) { + ((duk_heaphdr *) h)->h_assert_refcount = 0; + h = h->hdr.h_next; + } + } } -DUK_LOCAL void duk__markandsweep_torture_finalizer(duk_hthread *thr) { - duk_context *ctx; - duk_int_t rc; +DUK_LOCAL void duk__check_refcount_heaphdr(duk_heaphdr *hdr) { + duk_bool_t count_ok; - DUK_ASSERT(thr != NULL); - ctx = (duk_context *) thr; + /* The refcount check only makes sense for reachable objects on + * heap_allocated or string table, after the sweep phase. Prior to + * sweep phase refcounts will include references that are not visible + * via reachability roots. + * + * Because we're called after the sweep phase, all heap objects on + * heap_allocated are reachable. REACHABLE flags have already been + * cleared so we can't check them. + */ - /* Avoid fake finalization when callstack limit has been reached. - * Otherwise a callstack limit error will be created, then refzero'ed. + /* ROM objects have intentionally incorrect refcount (1), but we won't + * check them. */ - if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit || - thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) { - DUK_D(DUK_DPRINT("call recursion depth reached, avoid fake mark-and-sweep torture finalizer")); - return; + DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr)); + + count_ok = ((duk_size_t) DUK_HEAPHDR_GET_REFCOUNT(hdr) == hdr->h_assert_refcount); + if (!count_ok) { + DUK_D(DUK_DPRINT("refcount mismatch for: %p: header=%ld counted=%ld --> %!iO", + (void *) hdr, (long) DUK_HEAPHDR_GET_REFCOUNT(hdr), + (long) hdr->h_assert_refcount, hdr)); + DUK_ASSERT(0); } +} + +DUK_LOCAL void duk__check_assert_refcounts(duk_heap *heap) { + duk_heaphdr *curr; + duk_uint32_t i; - /* Run fake finalizer. Avoid creating unnecessary garbage. */ - duk_push_c_function(ctx, duk__markandsweep_fake_finalizer, 0 /*nargs*/); - rc = duk_pcall(ctx, 0 /*nargs*/); - DUK_UNREF(rc); /* ignored */ - duk_pop(ctx); + for (curr = heap->heap_allocated; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { + duk__check_refcount_heaphdr(curr); + } +#if defined(DUK_USE_FINALIZER_SUPPORT) + for (curr = heap->finalize_list; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { + duk__check_refcount_heaphdr(curr); + } +#endif + + for (i = 0; i < heap->st_size; i++) { + duk_hstring *h; + +#if defined(DUK_USE_STRTAB_PTRCOMP) + h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); +#else + h = heap->strtable[i]; +#endif + while (h != NULL) { + duk__check_refcount_heaphdr((duk_heaphdr *) h); + h = h->hdr.h_next; + } + } } -#endif /* DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE */ -#endif /* DUK_USE_FINALIZER_SUPPORT */ +#endif /* DUK_USE_REFERENCE_COUNTING */ +#endif /* DUK_USE_ASSERTIONS */ /* * Main mark-and-sweep function. * * 'flags' represents the features requested by the caller. The current - * heap->mark_and_sweep_base_flags is ORed automatically into the flags; - * the base flags mask typically prevents certain mark-and-sweep operations - * to avoid trouble. + * heap->ms_base_flags is ORed automatically into the flags; the base flags + * mask typically prevents certain mark-and-sweep operation to avoid trouble. */ -DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags) { - duk_hthread *thr; +DUK_INTERNAL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags) { duk_size_t count_keep_obj; duk_size_t count_keep_str; #if defined(DUK_USE_VOLUNTARY_GC) duk_size_t tmp; #endif - /* XXX: thread selection for mark-and-sweep is currently a hack. - * If we don't have a thread, the entire mark-and-sweep is now - * skipped (although we could just skip finalizations). + /* If debugger is paused, garbage collection is disabled by default. + * This is achieved by bumping ms_prevent_count when becoming paused. */ + DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) || heap->ms_prevent_count > 0); - /* If thr != NULL, the thr may still be in the middle of - * initialization. - * XXX: Improve the thread viability test. + /* Prevention/recursion check as soon as possible because we may + * be called a number of times when voluntary mark-and-sweep is + * pending. */ - thr = duk__get_temp_hthread(heap); - if (thr == NULL) { - DUK_D(DUK_DPRINT("gc skipped because we don't have a temp thread")); - - /* reset voluntary gc trigger count */ -#if defined(DUK_USE_VOLUNTARY_GC) - heap->mark_and_sweep_trigger_counter = DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP; -#endif - return 0; /* OK */ + if (heap->ms_prevent_count != 0) { + DUK_DD(DUK_DDPRINT("reject recursive mark-and-sweep")); + return; } + DUK_ASSERT(heap->ms_running == 0); /* ms_prevent_count is bumped when ms_running is set */ - /* If debugger is paused, garbage collection is disabled by default. */ - /* XXX: will need a force flag if garbage collection is triggered - * explicitly during paused state. - */ -#if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_HEAP_IS_PAUSED(heap)) { - /* Checking this here rather that in memory alloc primitives - * reduces checking code there but means a failed allocation - * will go through a few retries before giving up. That's - * fine because this only happens during debugging. - */ - DUK_D(DUK_DPRINT("gc skipped because debugger is paused")); - return 0; - } -#endif + /* Heap_thread is used during mark-and-sweep for refcount finalization + * (it's also used for finalizer execution once mark-and-sweep is + * complete). Heap allocation code ensures heap_thread is set and + * properly initialized before setting ms_prevent_count to 0. + */ + DUK_ASSERT(heap->heap_thread != NULL); + DUK_ASSERT(heap->heap_thread->valstack != NULL); + DUK_ASSERT(heap->heap_thread->callstack != NULL); + DUK_ASSERT(heap->heap_thread->catchstack != NULL); DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) starting, requested flags: 0x%08lx, effective flags: 0x%08lx", - (unsigned long) flags, (unsigned long) (flags | heap->mark_and_sweep_base_flags))); + (unsigned long) flags, (unsigned long) (flags | heap->ms_base_flags))); - flags |= heap->mark_and_sweep_base_flags; + flags |= heap->ms_base_flags; +#if defined(DUK_USE_FINALIZER_SUPPORT) + if (heap->finalize_list != NULL) { + flags |= DUK_MS_FLAG_POSTPONE_RESCUE; + } +#endif /* * Assertions before */ #if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)); + DUK_ASSERT(heap->ms_prevent_count == 0); + DUK_ASSERT(heap->ms_running == 0); + DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(heap)); DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)); - DUK_ASSERT(heap->mark_and_sweep_recursion_depth == 0); + DUK_ASSERT(heap->ms_recursion_depth == 0); duk__assert_heaphdr_flags(heap); #if defined(DUK_USE_REFERENCE_COUNTING) - /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount + /* Note: heap->refzero_free_running may be true; a refcount * finalizer may trigger a mark-and-sweep. */ duk__assert_valid_refcounts(heap); @@ -1232,7 +1053,10 @@ * Begin */ - DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap); + DUK_ASSERT(heap->ms_prevent_count == 0); + DUK_ASSERT(heap->ms_running == 0); + heap->ms_prevent_count = 1; + heap->ms_running = 1; /* * Mark roots, hoping that recursion limit is not normally hit. @@ -1250,17 +1074,20 @@ * previous run had finalizer skip flag. */ - duk__mark_roots_heap(heap); /* main reachability roots */ +#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) + duk__clear_assert_refcounts(heap); +#endif + duk__mark_roots_heap(heap); /* Mark main reachability roots. */ #if defined(DUK_USE_REFERENCE_COUNTING) - duk__mark_refzero_list(heap); /* refzero_list treated as reachability roots */ + DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ #endif - duk__mark_temproots_by_heap_scan(heap); /* temproots */ + duk__mark_temproots_by_heap_scan(heap); /* Temproots. */ #if defined(DUK_USE_FINALIZER_SUPPORT) - duk__mark_finalizable(heap); /* mark finalizable as reachability roots */ - duk__mark_finalize_list(heap); /* mark finalizer work list as reachability roots */ + duk__mark_finalizable(heap); /* Mark finalizable as reachability roots. */ + duk__mark_finalize_list(heap); /* Mark finalizer work list as reachability roots. */ #endif - duk__mark_temproots_by_heap_scan(heap); /* temproots */ + duk__mark_temproots_by_heap_scan(heap); /* Temproots. */ /* * Sweep garbage and remove marking flags, and move objects with @@ -1282,15 +1109,12 @@ duk__finalize_refcounts(heap); #endif duk__sweep_heap(heap, flags, &count_keep_obj); -#if defined(DUK_USE_STRTAB_CHAIN) - duk__sweep_stringtable_chain(heap, &count_keep_str); -#elif defined(DUK_USE_STRTAB_PROBE) - duk__sweep_stringtable_probe(heap, &count_keep_str); -#else -#error internal error, invalid strtab options + duk__sweep_stringtable(heap, &count_keep_str); +#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) + duk__check_assert_refcounts(heap); #endif #if defined(DUK_USE_REFERENCE_COUNTING) - duk__clear_refzero_list_flags(heap); + DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ #endif #if defined(DUK_USE_FINALIZER_SUPPORT) duk__clear_finalize_list_flags(heap); @@ -1321,94 +1145,39 @@ /* * String table resize check. * - * Note: this may silently (and safely) fail if GC is caused by an - * allocation call in stringtable resize_hash(). Resize_hash() - * will prevent a recursive call to itself by setting the - * DUK_MS_FLAG_NO_STRINGTABLE_RESIZE in heap->mark_and_sweep_base_flags. - */ - - /* XXX: stringtable emergency compaction? */ - - /* XXX: remove this feature entirely? it would only matter for - * emergency GC. Disable for lowest memory builds. - */ -#if defined(DUK_USE_MS_STRINGTABLE_RESIZE) - if (!(flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE)) { - DUK_DD(DUK_DDPRINT("resize stringtable: %p", (void *) heap)); - duk_heap_force_strtab_resize(heap); - } else { - DUK_D(DUK_DPRINT("stringtable resize skipped because DUK_MS_FLAG_NO_STRINGTABLE_RESIZE is set")); - } -#endif - - /* - * Finalize objects in the finalization work list. Finalized - * objects are queued back to heap_allocated with FINALIZED set. - * - * Since finalizers may cause arbitrary side effects, they are - * prevented during string table and object property allocation - * resizing using the DUK_MS_FLAG_NO_FINALIZERS flag in - * heap->mark_and_sweep_base_flags. In this case the objects - * remain in the finalization work list after mark-and-sweep - * exits and they may be finalized on the next pass. - * - * Finalization currently happens inside "MARKANDSWEEP_RUNNING" - * protection (no mark-and-sweep may be triggered by the - * finalizers). As a side effect: - * - * 1) an out-of-memory error inside a finalizer will not - * cause a mark-and-sweep and may cause the finalizer - * to fail unnecessarily - * - * 2) any temporary objects whose refcount decreases to zero - * during finalization will not be put into refzero_list; - * they can only be collected by another mark-and-sweep - * - * This is not optimal, but since the sweep for this phase has - * already happened, this is probably good enough for now. - */ - -#if defined(DUK_USE_FINALIZER_SUPPORT) -#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE) - /* Cannot simulate individual finalizers because finalize_list only - * contains objects with actual finalizers. But simulate side effects - * from finalization by doing a bogus function call and resizing the - * stacks. + * This is mainly useful in emergency GC: if the string table load + * factor is really low for some reason, we can shrink the string + * table to a smaller size and free some memory in the process. + * Only execute in emergency GC. String table has internal flags + * to protect against recursive resizing if this mark-and-sweep pass + * was triggered by a string table resize. */ - if (flags & DUK_MS_FLAG_NO_FINALIZERS) { - DUK_D(DUK_DPRINT("skip mark-and-sweep torture finalizer, DUK_MS_FLAG_NO_FINALIZERS is set")); - } else if (!(thr->valstack != NULL && thr->callstack != NULL && thr->catchstack != NULL)) { - DUK_D(DUK_DPRINT("skip mark-and-sweep torture finalizer, thread not yet viable")); - } else { - DUK_D(DUK_DPRINT("run mark-and-sweep torture finalizer")); - duk__markandsweep_torture_finalizer(thr); - } -#endif /* DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE */ - if (flags & DUK_MS_FLAG_NO_FINALIZERS) { - DUK_D(DUK_DPRINT("finalizer run skipped because DUK_MS_FLAG_NO_FINALIZERS is set")); - } else { - duk__run_object_finalizers(heap, flags); + if (flags & DUK_MS_FLAG_EMERGENCY) { + DUK_D(DUK_DPRINT("stringtable resize check in emergency gc")); + duk_heap_strtable_force_resize(heap); } -#endif /* DUK_USE_FINALIZER_SUPPORT */ /* * Finish */ - DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap); + DUK_ASSERT(heap->ms_prevent_count == 1); + heap->ms_prevent_count = 0; + DUK_ASSERT(heap->ms_running == 1); + heap->ms_running = 0; /* * Assertions after */ #if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)); + DUK_ASSERT(heap->ms_prevent_count == 0); DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)); - DUK_ASSERT(heap->mark_and_sweep_recursion_depth == 0); + DUK_ASSERT(heap->ms_recursion_depth == 0); duk__assert_heaphdr_flags(heap); #if defined(DUK_USE_REFERENCE_COUNTING) - /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount + /* Note: heap->refzero_free_running may be true; a refcount * finalizer may trigger a mark-and-sweep. */ duk__assert_valid_refcounts(heap); @@ -1421,15 +1190,47 @@ #if defined(DUK_USE_VOLUNTARY_GC) tmp = (count_keep_obj + count_keep_str) / 256; - heap->mark_and_sweep_trigger_counter = (duk_int_t) ( + heap->ms_trigger_counter = (duk_int_t) ( (tmp * DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT) + DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD); DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, trigger reset to %ld", - (long) count_keep_obj, (long) count_keep_str, (long) heap->mark_and_sweep_trigger_counter)); + (long) count_keep_obj, (long) count_keep_str, (long) heap->ms_trigger_counter)); #else DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, no voluntary trigger", (long) count_keep_obj, (long) count_keep_str)); #endif - return 0; /* OK */ + /* + * Finalize objects in the finalization work list. Finalized + * objects are queued back to heap_allocated with FINALIZED set. + * + * Since finalizers may cause arbitrary side effects, they are + * prevented e.g. during string table and object property allocation + * resizing using heap->pf_prevent_count. In this case the objects + * remain in the finalization work list after mark-and-sweep exits + * and they may be finalized on the next pass or any DECREF checking + * for finalize_list. + * + * As of Duktape 2.1 finalization happens outside mark-and-sweep + * protection. Mark-and-sweep is allowed while the finalize_list + * is being processed, but no rescue decisions are done while the + * process is on-going. This avoids incorrect rescue decisions + * if an object is considered reachable (and thus rescued) because + * of a reference via finalize_list (which is considered a reachability + * root). When finalize_list is being processed, reachable objects + * with FINALIZED set will just keep their FINALIZED flag for later + * mark-and-sweep processing. + * + * This could also be handled (a bit better) by having a more refined + * notion of reachability for rescue/free decisions. + * + * XXX: avoid finalizer execution when doing emergency GC? + */ + +#if defined(DUK_USE_FINALIZER_SUPPORT) + /* Attempt to process finalize_list, pf_prevent_count check + * is inside the target. + */ + duk_heap_process_finalize_list(heap); +#endif /* DUK_USE_FINALIZER_SUPPORT */ } diff -Nru duktape-2.0.0/src-input/duk_heap_memory.c duktape-2.1.1/src-input/duk_heap_memory.c --- duktape-2.0.0/src-input/duk_heap_memory.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_heap_memory.c 2017-07-28 22:05:08.000000000 +0000 @@ -5,34 +5,28 @@ #include "duk_internal.h" /* - * Helpers - * - * The fast path checks are done within a macro to ensure "inlining" - * while the slow path actions use a helper (which won't typically be - * inlined in size optimized builds). + * Voluntary GC check */ #if defined(DUK_USE_VOLUNTARY_GC) -#define DUK__VOLUNTARY_PERIODIC_GC(heap) do { \ - (heap)->mark_and_sweep_trigger_counter--; \ - if ((heap)->mark_and_sweep_trigger_counter <= 0) { \ - duk__run_voluntary_gc(heap); \ - } \ - } while (0) - -DUK_LOCAL void duk__run_voluntary_gc(duk_heap *heap) { - if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { - DUK_DD(DUK_DDPRINT("mark-and-sweep in progress -> skip voluntary mark-and-sweep now")); - } else { - duk_small_uint_t flags; - duk_bool_t rc; +DUK_LOCAL DUK_INLINE void duk__check_voluntary_gc(duk_heap *heap) { + if (DUK_UNLIKELY(--(heap)->ms_trigger_counter < 0)) { +#if defined(DUK_USE_DEBUG) + if (heap->ms_prevent_count == 0) { + DUK_D(DUK_DPRINT("triggering voluntary mark-and-sweep")); + } else { + DUK_DD(DUK_DDPRINT("gc blocked -> skip voluntary mark-and-sweep now")); + } +#endif - DUK_D(DUK_DPRINT("triggering voluntary mark-and-sweep")); - flags = 0; - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); + /* Prevention checks in the call target handle cases where + * voluntary GC is not allowed. The voluntary GC trigger + * counter is only rewritten if mark-and-sweep actually runs. + */ + duk_heap_mark_and_sweep(heap, DUK_MS_FLAG_VOLUNTARY /*flags*/); } } +#define DUK__VOLUNTARY_PERIODIC_GC(heap) do { duk__check_voluntary_gc((heap)); } while (0) #else #define DUK__VOLUNTARY_PERIODIC_GC(heap) /* no voluntary gc */ #endif /* DUK_USE_VOLUNTARY_GC */ @@ -43,7 +37,6 @@ DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) { void *res; - duk_bool_t rc; duk_small_int_t i; DUK_ASSERT(heap != NULL); @@ -61,7 +54,7 @@ #if defined(DUK_USE_GC_TORTURE) /* simulate alloc failure on every alloc (except when mark-and-sweep is running) */ - if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + if (heap->ms_prevent_count == 0) { DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first alloc attempt fails")); res = NULL; DUK_UNREF(res); @@ -69,7 +62,7 @@ } #endif res = heap->alloc_func(heap->heap_udata, size); - if (res || size == 0) { + if (DUK_LIKELY(res || size == 0)) { /* for zero size allocations NULL is allowed */ return res; } @@ -79,16 +72,22 @@ DUK_D(DUK_DPRINT("first alloc attempt failed, attempt to gc and retry")); +#if 0 /* * Avoid a GC if GC is already running. This can happen at a late * stage in a GC when we try to e.g. resize the stringtable * or compact objects. + * + * NOTE: explicit handling isn't actually be needed: if the GC is + * not allowed, duk_heap_mark_and_sweep() will reject it for every + * attempt in the loop below, resulting in a NULL same as here. */ - if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + 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 @@ -104,8 +103,7 @@ flags |= DUK_MS_FLAG_EMERGENCY; } - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); + duk_heap_mark_and_sweep(heap, flags); res = heap->alloc_func(heap->heap_udata, size); if (res) { @@ -126,20 +124,43 @@ DUK_ASSERT_DISABLE(size >= 0); res = DUK_ALLOC(heap, size); - if (res) { + if (DUK_LIKELY(res != NULL)) { /* assume memset with zero size is OK */ DUK_MEMZERO(res, size); } return res; } +DUK_INTERNAL void *duk_heap_mem_alloc_checked(duk_hthread *thr, duk_size_t size) { + void *res; + + DUK_ASSERT(thr != NULL); + res = duk_heap_mem_alloc(thr->heap, size); + if (DUK_LIKELY(res != NULL || size == 0)) { + return res; + } + DUK_ERROR_ALLOC_FAILED(thr); + return NULL; +} + +DUK_INTERNAL void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, duk_size_t size) { + void *res; + + DUK_ASSERT(thr != NULL); + res = duk_heap_mem_alloc_zeroed(thr->heap, size); + if (DUK_LIKELY(res != NULL || size == 0)) { + return res; + } + DUK_ERROR_ALLOC_FAILED(thr); + return NULL; +} + /* * Reallocate memory with garbage collection */ DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize) { void *res; - duk_bool_t rc; duk_small_int_t i; DUK_ASSERT(heap != NULL); @@ -158,7 +179,7 @@ #if defined(DUK_USE_GC_TORTURE) /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */ - if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + if (heap->ms_prevent_count == 0) { DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first realloc attempt fails")); res = NULL; DUK_UNREF(res); @@ -166,7 +187,7 @@ } #endif res = heap->realloc_func(heap->heap_udata, ptr, newsize); - if (res || newsize == 0) { + if (DUK_LIKELY(res || newsize == 0)) { /* for zero size allocations NULL is allowed */ return res; } @@ -176,14 +197,16 @@ 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 (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + 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 @@ -199,8 +222,7 @@ flags |= DUK_MS_FLAG_EMERGENCY; } - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); + duk_heap_mark_and_sweep(heap, flags); res = heap->realloc_func(heap->heap_udata, ptr, newsize); if (res || newsize == 0) { @@ -222,7 +244,6 @@ DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize) { void *res; - duk_bool_t rc; duk_small_int_t i; DUK_ASSERT(heap != NULL); @@ -240,7 +261,7 @@ #if defined(DUK_USE_GC_TORTURE) /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */ - if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + 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); @@ -248,7 +269,7 @@ } #endif res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize); - if (res || newsize == 0) { + if (DUK_LIKELY(res || newsize == 0)) { /* for zero size allocations NULL is allowed */ return res; } @@ -258,14 +279,16 @@ 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 (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + 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 @@ -289,8 +312,7 @@ flags |= DUK_MS_FLAG_EMERGENCY; } - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); + duk_heap_mark_and_sweep(heap, flags); #if defined(DUK_USE_ASSERTIONS) ptr_post = cb(heap, ud); if (ptr_pre != ptr_post) { @@ -329,12 +351,8 @@ */ heap->free_func(heap->heap_udata, ptr); - /* Count free operations toward triggering a GC but never actually trigger - * a GC from a free. Otherwise code which frees internal structures would - * need to put in NULLs at every turn to ensure the object is always in - * consistent state for a mark-and-sweep. + /* 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. */ -#if defined(DUK_USE_VOLUNTARY_GC) - heap->mark_and_sweep_trigger_counter--; -#endif } diff -Nru duktape-2.0.0/src-input/duk_heap_misc.c duktape-2.1.1/src-input/duk_heap_misc.c --- duktape-2.0.0/src-input/duk_heap_misc.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_heap_misc.c 2017-07-28 22:05:08.000000000 +0000 @@ -4,44 +4,146 @@ #include "duk_internal.h" -#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING) -/* arbitrary remove only works with double linked heap, and is only required by - * reference counting so far. - */ -DUK_INTERNAL void duk_heap_remove_any_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) { +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_ASSERT_HEAPHDR_LINKS(heap, hdr); + DUK_ASSERT_HEAPHDR_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); - if (DUK_HEAPHDR_GET_PREV(heap, hdr)) { - DUK_HEAPHDR_SET_NEXT(heap, DUK_HEAPHDR_GET_PREV(heap, hdr), DUK_HEAPHDR_GET_NEXT(heap, hdr)); + /* 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 { - heap->heap_allocated = DUK_HEAPHDR_GET_NEXT(heap, hdr); + DUK_ASSERT(heap->heap_allocated == hdr); + heap->heap_allocated = next; } - if (DUK_HEAPHDR_GET_NEXT(heap, hdr)) { - DUK_HEAPHDR_SET_PREV(heap, DUK_HEAPHDR_GET_NEXT(heap, hdr), DUK_HEAPHDR_GET_PREV(heap, hdr)); + if (next != NULL) { + DUK_HEAPHDR_SET_PREV(heap, next, prev); } else { ; } - - /* The prev/next pointers of the removed duk_heaphdr are left as garbage. - * It's up to the caller to ensure they're written before inserting the - * object back. - */ } -#endif +#endif /* DUK_USE_REFERENCE_COUNTING */ -DUK_INTERNAL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) { - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING); +#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) - if (heap->heap_allocated) { - DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, heap->heap_allocated) == NULL); - DUK_HEAPHDR_SET_PREV(heap, heap->heap_allocated, hdr); - } 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, heap->heap_allocated); - heap->heap_allocated = hdr; + DUK_HEAPHDR_SET_NEXT(heap, hdr, root); + DUK_ASSERT_HEAPHDR_LINKS(heap, hdr); + DUK_ASSERT_HEAPHDR_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) { diff -Nru duktape-2.0.0/src-input/duk_heap_refcount.c duktape-2.1.1/src-input/duk_heap_refcount.c --- duktape-2.0.0/src-input/duk_heap_refcount.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_heap_refcount.c 2017-07-28 22:05:08.000000000 +0000 @@ -1,5 +1,9 @@ /* * 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 "duk_internal.h" @@ -11,36 +15,6 @@ #endif /* - * Misc - */ - -DUK_LOCAL void duk__queue_refzero(duk_heap *heap, duk_heaphdr *hdr) { - /* tail insert: don't disturb head in case refzero is running */ - - if (heap->refzero_list != NULL) { - duk_heaphdr *hdr_prev; - - hdr_prev = heap->refzero_list_tail; - DUK_ASSERT(hdr_prev != NULL); - DUK_ASSERT(DUK_HEAPHDR_GET_NEXT(heap, hdr_prev) == NULL); - - DUK_HEAPHDR_SET_NEXT(heap, hdr, NULL); - DUK_HEAPHDR_SET_PREV(heap, hdr, hdr_prev); - DUK_HEAPHDR_SET_NEXT(heap, hdr_prev, hdr); - DUK_ASSERT_HEAPHDR_LINKS(heap, hdr); - DUK_ASSERT_HEAPHDR_LINKS(heap, hdr_prev); - heap->refzero_list_tail = hdr; - } else { - DUK_ASSERT(heap->refzero_list_tail == NULL); - DUK_HEAPHDR_SET_NEXT(heap, hdr, NULL); - DUK_HEAPHDR_SET_PREV(heap, hdr, NULL); - DUK_ASSERT_HEAPHDR_LINKS(heap, hdr); - heap->refzero_list = hdr; - heap->refzero_list_tail = hdr; - } -} - -/* * Heap object refcount finalization. * * When an object is about to be freed, all other objects it refers to must @@ -48,41 +22,47 @@ * allocations (mark-and-sweep shares these helpers), it just manipulates * the refcounts. * - * Note that any of the decref's may cause a refcount to drop to zero, BUT - * it will not be processed inline. If refcount finalization is triggered - * by refzero processing, the objects will be just queued to the refzero - * list and processed later which eliminates C recursion. If refcount - * finalization is triggered by mark-and-sweep, any refzero situations are - * ignored because mark-and-sweep will deal with them. NORZ variants can - * be used here in both cases. + * 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__refcount_finalize_hobject(duk_hthread *thr, duk_hobject *h) { +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); - /* XXX: better to get base and walk forwards? */ + thr = heap->heap_thread; + DUK_ASSERT(thr != NULL); - p_key = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, h); - p_val = DUK_HOBJECT_E_GET_VALUE_BASE(thr->heap, h); - p_flag = DUK_HOBJECT_E_GET_FLAGS_BASE(thr->heap, h); + 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 (!key) { + if (DUK_UNLIKELY(key == NULL)) { continue; } DUK_HSTRING_DECREF_NORZ(thr, key); - if (p_flag[n] & DUK_PROPDESC_FLAG_ACCESSOR) { + 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)); @@ -97,7 +77,7 @@ } } - p_tv = DUK_HOBJECT_A_GET_BASE(thr->heap, h); + p_tv = DUK_HOBJECT_A_GET_BASE(heap, h); n = DUK_HOBJECT_GET_ASIZE(h); while (n-- > 0) { duk_tval *tv_val; @@ -105,39 +85,49 @@ DUK_TVAL_DECREF_NORZ(thr, tv_val); } - /* hash part is a 'weak reference' and does not contribute */ + /* Hash part is a 'weak reference' and doesn't contribute to refcounts. */ - { - duk_hobject *h_proto; - h_proto = (duk_hobject *) DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h); - DUK_ASSERT(h_proto == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_proto)); - DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_proto); + 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)); - /* XXX: rearrange bits to allow a switch case to be used here? */ - /* XXX: add a fast path for objects (and arrays)? */ + /* Slow path: special object, start bit checks from most likely. */ - /* DUK_HOBJECT_IS_ARRAY(h): needs no special handling now as there are - * no extra fields in need of decref. - */ if (DUK_HOBJECT_IS_COMPFUNC(h)) { duk_hcompfunc *f = (duk_hcompfunc *) h; duk_tval *tv, *tv_end; duk_hobject **funcs, **funcs_end; - if (DUK_HCOMPFUNC_GET_DATA(thr->heap, f) != NULL) { - tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, f); - tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, 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(thr->heap, f); - funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, f); + 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++; @@ -147,13 +137,19 @@ DUK_D(DUK_DPRINT("duk_hcompfunc 'data' is NULL, skipping decref")); } - DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_heaphdr *) DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f)); - DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_heaphdr *) DUK_HCOMPFUNC_GET_VARENV(thr->heap, f)); - DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(thr->heap, f)); - } else if (DUK_HOBJECT_IS_NATFUNC(h)) { - duk_hnatfunc *f = (duk_hnatfunc *) h; - DUK_UNREF(f); - /* nothing to finalize */ + 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_ASSERT_HDECENV_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_ASSERT_HOBJENV_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; @@ -191,264 +187,284 @@ } 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(duk_hthread *thr, duk_heaphdr *hdr) { - DUK_ASSERT(hdr); +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_GET_TYPE(hdr) == DUK_HTYPE_OBJECT) { - duk__refcount_finalize_hobject(thr, (duk_hobject *) hdr); + 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 */ } -#if defined(DUK_USE_FINALIZER_SUPPORT) -#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE) -DUK_LOCAL duk_ret_t duk__refcount_fake_finalizer(duk_context *ctx) { - DUK_UNREF(ctx); - DUK_D(DUK_DPRINT("fake refcount torture finalizer executed")); -#if 0 - DUK_DD(DUK_DDPRINT("fake torture finalizer for: %!T", duk_get_tval(ctx, 0))); -#endif - /* Require a lot of stack to force a value stack grow/shrink. */ - duk_require_stack(ctx, 100000); - - /* XXX: do something to force a callstack grow/shrink, perhaps - * just a manual forced resize? - */ - return 0; -} - -DUK_LOCAL void duk__refcount_run_torture_finalizer(duk_hthread *thr, duk_hobject *obj) { - duk_context *ctx; - duk_int_t rc; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(obj != NULL); - ctx = (duk_context *) thr; - - /* Avoid fake finalization for the duk__refcount_fake_finalizer function - * itself, otherwise we're in infinite recursion. - */ - if (DUK_HOBJECT_HAS_NATFUNC(obj)) { - if (((duk_hnatfunc *) obj)->func == duk__refcount_fake_finalizer) { - DUK_DD(DUK_DDPRINT("avoid fake torture finalizer for duk__refcount_fake_finalizer itself")); - return; - } - } - /* Avoid fake finalization when callstack limit has been reached. - * Otherwise a callstack limit error will be created, then refzero'ed, - * and we're in an infinite loop. - */ - if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit || - thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) { - DUK_D(DUK_DPRINT("call recursion depth reached, avoid fake torture finalizer")); - return; - } - - /* Run fake finalizer. Avoid creating new refzero queue entries - * so that we are not forced into a forever loop. - */ - duk_push_c_function(ctx, duk__refcount_fake_finalizer, 1 /*nargs*/); - duk_push_hobject(ctx, obj); - rc = duk_pcall(ctx, 1); - DUK_UNREF(rc); /* ignored */ - duk_pop(ctx); -} -#endif /* DUK_USE_REFZERO_FINALIZER_TORTURE */ -#endif /* DUK_USE_FINALIZER_SUPPORT */ - /* - * Refcount memory freeing loop. + * 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. * - * Frees objects in the refzero_pending list until the list becomes - * empty. When an object is freed, its references get decref'd and - * may cause further objects to be queued for freeing. + * - 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. + * 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_INTERNAL void duk_refzero_free_pending(duk_hthread *thr) { - duk_heaphdr *h1, *h2; - duk_heap *heap; +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(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - heap = thr->heap; DUK_ASSERT(heap != NULL); - /* - * Detect recursive invocation - */ + 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. */ - if (DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap)) { - DUK_DDD(DUK_DDDPRINT("refzero free running, skip run")); - return; - } + do { + duk_heaphdr *prev; - /* - * Churn refzero_list until empty - */ + DUK_DDD(DUK_DDDPRINT("refzero processing %p: %!O", (void *) curr, (duk_heaphdr *) curr)); - DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap); - while (heap->refzero_list) { - duk_hobject *obj; -#if defined(DUK_USE_FINALIZER_SUPPORT) - duk_bool_t rescued = 0; -#endif /* DUK_USE_FINALIZER_SUPPORT */ +#if defined(DUK_USE_DEBUG) + count++; +#endif - /* - * Pick an object from the head (don't remove yet). + 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); - h1 = heap->refzero_list; - obj = (duk_hobject *) h1; - DUK_DD(DUK_DDPRINT("refzero processing %p: %!O", (void *) h1, (duk_heaphdr *) h1)); - DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, h1) == NULL); - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(h1) == DUK_HTYPE_OBJECT); /* currently, always the case */ + 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. */ -#if defined(DUK_USE_FINALIZER_SUPPORT) -#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE) - /* Torture option to shake out finalizer side effect issues: - * make a bogus function call for every finalizable object, - * essentially simulating the case where everything has a - * finalizer. - */ - DUK_DD(DUK_DDPRINT("refzero torture enabled, fake finalizer")); - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h1) == 0); - DUK_HEAPHDR_PREINC_REFCOUNT(h1); /* bump refcount to prevent refzero during finalizer processing */ - duk__refcount_run_torture_finalizer(thr, obj); /* must never longjmp */ - DUK_HEAPHDR_PREDEC_REFCOUNT(h1); /* remove artificial bump */ - DUK_ASSERT_DISABLE(h1->h_refcount >= 0); /* refcount is unsigned, so always true */ -#endif /* DUK_USE_REFZERO_FINALIZER_TORTURE */ -#endif /* DUK_USE_FINALIZER_SUPPORT */ + duk_free_hobject(heap, (duk_hobject *) curr); /* Invalidates 'curr'. */ - /* - * Finalizer check. - * - * Note: running a finalizer may have arbitrary side effects, e.g. - * queue more objects on refzero_list (tail), or even trigger a - * mark-and-sweep. - * - * Note: quick reject check should match vast majority of - * objects and must be safe (not throw any errors, ever). - * - * An object may have FINALIZED here if it was finalized by mark-and-sweep - * on a previous run and refcount then decreased to zero. We won't run the - * finalizer again here. - * - * A finalizer is looked up from the object and up its prototype chain - * (which allows inherited finalizers). - */ + curr = prev; + } while (curr != NULL); -#if defined(DUK_USE_FINALIZER_SUPPORT) - if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) { - DUK_DDD(DUK_DDDPRINT("object has a finalizer, run it")); + heap->refzero_list = NULL; - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h1) == 0); - DUK_HEAPHDR_PREINC_REFCOUNT(h1); /* bump refcount to prevent refzero during finalizer processing */ + 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); - duk_hobject_run_finalizer(thr, obj); /* must never longjmp */ - DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1)); /* duk_hobject_run_finalizer() sets */ + hdr = (duk_heaphdr *) obj; - DUK_HEAPHDR_PREDEC_REFCOUNT(h1); /* remove artificial bump */ - DUK_ASSERT_DISABLE(h1->h_refcount >= 0); /* refcount is unsigned, so always true */ - - if (DUK_HEAPHDR_GET_REFCOUNT(h1) != 0) { - DUK_DDD(DUK_DDDPRINT("-> object refcount after finalization non-zero, object will be rescued")); - rescued = 1; - } else { - DUK_DDD(DUK_DDDPRINT("-> object refcount still zero after finalization, object will be freed")); + /* 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))) { + /* 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 */ - /* Refzero head is still the same. This is the case even if finalizer - * inserted more refzero objects; they are inserted to the tail. - */ - DUK_ASSERT(h1 == heap->refzero_list); + /* No need to finalize, free object via refzero_list. */ + + root = heap->refzero_list; - /* - * Remove the object from the refzero list. This cannot be done - * before a possible finalizer has been executed; the finalizer - * may trigger a mark-and-sweep, and mark-and-sweep must be able - * to traverse a complete 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); - h2 = DUK_HEAPHDR_GET_NEXT(heap, h1); - if (h2) { - DUK_HEAPHDR_SET_PREV(heap, h2, NULL); /* not strictly necessary */ - heap->refzero_list = h2; - } else { - heap->refzero_list = NULL; - heap->refzero_list_tail = 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); - /* - * Rescue or free. + /* 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) - if (rescued) { - /* yes -> move back to heap allocated */ - DUK_DD(DUK_DDPRINT("object rescued during refcount finalization: %p", (void *) h1)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(h1)); - DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1)); - DUK_HEAPHDR_CLEAR_FINALIZED(h1); - h2 = heap->heap_allocated; - DUK_HEAPHDR_SET_PREV(heap, h1, NULL); - if (h2) { - DUK_HEAPHDR_SET_PREV(heap, h2, h1); - } - DUK_HEAPHDR_SET_NEXT(heap, h1, h2); - DUK_ASSERT_HEAPHDR_LINKS(heap, h1); - DUK_ASSERT_HEAPHDR_LINKS(heap, h2); - heap->heap_allocated = h1; - } else -#endif /* DUK_USE_FINALIZER_SUPPORT */ - { - /* no -> decref members, then free */ - duk__refcount_finalize_hobject(thr, obj); - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(h1) == DUK_HTYPE_OBJECT); /* currently, always the case */ - duk_free_hobject(heap, (duk_hobject *) h1); - } +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. */ - count++; + if (DUK_UNLIKELY(thr->heap->finalize_list != NULL)) { + duk_heap_process_finalize_list(thr->heap); } - DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap); - - DUK_DDD(DUK_DDDPRINT("refzero processed %ld objects", (long) count)); +} - /* - * Once the whole refzero cascade has been freed, check for - * a voluntary mark-and-sweep. - */ +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 defined(DUK_USE_VOLUNTARY_GC) - /* 'count' is more or less comparable to normal trigger counter update - * which happens in memory block (re)allocation. - */ - heap->mark_and_sweep_trigger_counter -= count; - if (heap->mark_and_sweep_trigger_counter <= 0) { - duk_bool_t rc; - duk_small_uint_t flags = 0; /* not emergency */ - DUK_D(DUK_DPRINT("refcount triggering mark-and-sweep")); - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); - DUK_D(DUK_DPRINT("refcount triggered mark-and-sweep => rc %ld", (long) rc)); + if (DUK_UNLIKELY(thr->heap->finalize_list != NULL)) { + duk_heap_process_finalize_list(thr->heap); } -#endif /* DUK_USE_VOLUNTARY_GC */ +} +#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. + * 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, @@ -461,46 +477,67 @@ * mark-and-sweep also calls finalizers which would use the ordinary decref * macros anyway. * - * The DUK__RZ_SUPPRESS_CHECK() must be enabled also when mark-and-sweep - * support has been disabled: the flag is also used in heap destruction when - * running finalizers for remaining objects, and the flag prevents objects - * from being moved around in heap linked lists. + * 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. */ -/* The suppress condition is important to performance. The flags being tested - * are in the same duk_heap field so a single TEST instruction (on x86) tests - * for them. - */ +#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); \ + /* When mark-and-sweep runs, the 'thr' argument always matches heap_thread. \ + * This could be used to e.g. suppress check against 'thr' directly (and \ + * knowing it would be heap_thread); not really used now. \ + */ \ + DUK_ASSERT(thr->heap->ms_running == 0 || 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_COND() \ - (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) || DUK_HEAP_IS_PAUSED(heap)) +#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_COND() \ - (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) -#endif +#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 when mark-and-sweep running, object: %p", (void *) h)); \ + 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_heap_strcache_string_remove(thr->heap, (duk_hstring *) h); \ - duk_heap_string_remove(heap, (duk_hstring *) h); \ - duk_free_hstring(heap, (duk_hstring *) h); \ + duk__refcount_refzero_hstring(heap, (duk_hstring *) h); \ } while (0) #define DUK__RZ_BUFFER() do { \ - duk_heap_remove_any_from_heap_allocated(heap, (duk_heaphdr *) h); \ - duk_free_hbuffer(heap, (duk_hbuffer *) h); \ + duk__refcount_refzero_hbuffer(heap, (duk_hbuffer *) h); \ } while (0) #define DUK__RZ_OBJECT() do { \ - duk_heap_remove_any_from_heap_allocated(heap, (duk_heaphdr *) h); \ - duk__queue_refzero(heap, (duk_heaphdr *) h); \ - if (!skip_free_pending) { \ - duk_refzero_free_pending(thr); \ - } \ + 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 @@ -570,42 +607,39 @@ DUK__RZ_OBJECT(); break; - case DUK_HTYPE_BUFFER: + 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; - - default: - DUK_D(DUK_DPRINT("invalid heap type in decref: %ld", (long) DUK_HEAPHDR_GET_TYPE(h))); - DUK_UNREACHABLE(); } } -DUK_INTERNAL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h) { +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 void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h) { +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 void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h) { +DUK_INTERNAL DUK_NOINLINE void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h) { duk__hstring_refzero_helper(thr, h); } -DUK_INTERNAL void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h) { +DUK_INTERNAL DUK_NOINLINE void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h) { duk__hbuffer_refzero_helper(thr, h); } -DUK_INTERNAL void duk_hobject_refzero(duk_hthread *thr, duk_hobject *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 void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h) { +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*/); } @@ -619,6 +653,7 @@ 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. */ } } @@ -657,7 +692,7 @@ } duk_heaphdr_refzero_norz(thr, h); #else - duk_heaphdr_decref(thr, h); + duk_heaphdr_decref_norz(thr, h); #endif } } @@ -671,6 +706,13 @@ 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; \ @@ -680,6 +722,10 @@ } \ } 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; \ @@ -696,13 +742,18 @@ DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0); - DUK_HEAPHDR_PREINC_REFCOUNT(h); + 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(); diff -Nru duktape-2.0.0/src-input/duk_heap_stringcache.c duktape-2.1.1/src-input/duk_heap_stringcache.c --- duktape-2.0.0/src-input/duk_heap_stringcache.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_heap_stringcache.c 2017-07-28 22:05:08.000000000 +0000 @@ -84,6 +84,10 @@ * * 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) { @@ -93,20 +97,27 @@ duk_small_int_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; - if (char_offset > DUK_HSTRING_GET_CHARLEN(h)) { - goto error; - } - /* * For ASCII strings, the answer is simple. */ - if (DUK_HSTRING_IS_ASCII(h)) { - /* clen == blen -> pure ascii */ + 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; } @@ -128,7 +139,7 @@ heap = thr->heap; sce = NULL; - use_cache = (DUK_HSTRING_GET_CHARLEN(h) > DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT); + use_cache = (char_length > DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT); if (use_cache) { #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) @@ -159,7 +170,7 @@ DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h) >= char_offset); dist_start = char_offset; - dist_end = DUK_HSTRING_GET_CHARLEN(h) - 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); @@ -232,12 +243,12 @@ scan_done: - if (!p_found) { + 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 error; + goto scan_error; } DUK_ASSERT(p_found >= p_start); @@ -292,7 +303,7 @@ return byte_offset; - error: + scan_error: DUK_ERROR_INTERNAL(thr); return 0; } diff -Nru duktape-2.0.0/src-input/duk_heap_stringtable.c duktape-2.1.1/src-input/duk_heap_stringtable.c --- duktape-2.0.0/src-input/duk_heap_stringtable.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_heap_stringtable.c 2017-07-28 22:05:08.000000000 +0000 @@ -1,57 +1,169 @@ /* - * Heap stringtable handling, string interning. + * Heap string table handling, string interning. */ #include "duk_internal.h" -#if defined(DUK_USE_STRTAB_PROBE) -#define DUK__HASH_INITIAL(hash,h_size) DUK_STRTAB_HASH_INITIAL((hash),(h_size)) -#define DUK__HASH_PROBE_STEP(hash) DUK_STRTAB_HASH_PROBE_STEP((hash)) -#define DUK__DELETED_MARKER(heap) DUK_STRTAB_DELETED_MARKER((heap)) +/* Resize checks not needed if minsize == maxsize, typical for low memory + * targets. + */ +#define DUK__STRTAB_RESIZE_CHECK +#if (DUK_USE_STRTAB_MINSIZE == DUK_USE_STRTAB_MAXSIZE) +#undef DUK__STRTAB_RESIZE_CHECK +#endif + +#if defined(DUK_USE_STRTAB_PTRCOMP) +#define DUK__HEAPPTR_ENC16(heap,ptr) DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (ptr)) +#define DUK__HEAPPTR_DEC16(heap,val) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (val)) +#define DUK__GET_STRTABLE(heap) ((heap)->strtable16) +#else +#define DUK__HEAPPTR_ENC16(heap,ptr) (ptr) +#define DUK__HEAPPTR_DEC16(heap,val) (val) +#define DUK__GET_STRTABLE(heap) ((heap)->strtable) #endif -#define DUK__PREVENT_MS_SIDE_EFFECTS(heap) do { \ - (heap)->mark_and_sweep_base_flags |= \ - DUK_MS_FLAG_NO_STRINGTABLE_RESIZE | /* avoid recursive string table call */ \ - DUK_MS_FLAG_NO_FINALIZERS | /* avoid pressure to add/remove strings, invalidation of call data argument, etc. */ \ - DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid array abandoning which interns strings */ \ - } while (0) +#define DUK__STRTAB_U32_MAX_STRLEN 10 /* 4'294'967'295 */ /* - * Create a hstring and insert into the heap. The created object - * is directly garbage collectable with reference count zero. + * Debug dump stringtable. + */ + +#if defined(DUK_USE_DEBUG) +DUK_INTERNAL void duk_heap_strtable_dump(duk_heap *heap) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *strtable; +#else + duk_hstring **strtable; +#endif + duk_uint32_t i; + duk_hstring *h; + duk_size_t count_total = 0; + duk_size_t count_chain; + duk_size_t count_chain_min = DUK_SIZE_MAX; + duk_size_t count_chain_max = 0; + duk_size_t count_len[8]; /* chain lengths from 0 to 7 */ + + if (heap == NULL) { + DUK_D(DUK_DPRINT("string table, heap=NULL")); + return; + } + + strtable = DUK__GET_STRTABLE(heap); + if (strtable == NULL) { + DUK_D(DUK_DPRINT("string table, strtab=NULL")); + return; + } + + DUK_MEMZERO((void *) count_len, sizeof(count_len)); + for (i = 0; i < heap->st_size; i++) { + h = DUK__HEAPPTR_DEC16(heap, strtable[i]); + count_chain = 0; + while (h != NULL) { + count_chain++; + h = h->hdr.h_next; + } + if (count_chain < sizeof(count_len) / sizeof(duk_size_t)) { + count_len[count_chain]++; + } + count_chain_max = (count_chain > count_chain_max ? count_chain : count_chain_max); + count_chain_min = (count_chain < count_chain_min ? count_chain : count_chain_min); + count_total += count_chain; + } + + DUK_D(DUK_DPRINT("string table, strtab=%p, count=%lu, chain min=%lu max=%lu avg=%lf: " + "counts: %lu %lu %lu %lu %lu %lu %lu %lu ...", + (void *) heap->strtable, (unsigned long) count_total, + (unsigned long) count_chain_min, (unsigned long) count_chain_max, + (double) count_total / (double) heap->st_size, + (unsigned long) count_len[0], (unsigned long) count_len[1], + (unsigned long) count_len[2], (unsigned long) count_len[3], + (unsigned long) count_len[4], (unsigned long) count_len[5], + (unsigned long) count_len[6], (unsigned long) count_len[7])); +} +#endif /* DUK_USE_DEBUG */ + +/* + * Assertion helper to ensure strtable is populated correctly. + */ + +#if defined(DUK_USE_ASSERTIONS) +DUK_LOCAL void duk__strtable_assert_checks(duk_heap *heap) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *strtable; +#else + duk_hstring **strtable; +#endif + duk_uint32_t i; + duk_hstring *h; + duk_size_t count = 0; + + DUK_ASSERT(heap != NULL); + + strtable = DUK__GET_STRTABLE(heap); + if (strtable != NULL) { + DUK_ASSERT(heap->st_size != 0); + DUK_ASSERT(heap->st_mask == heap->st_size - 1); + + for (i = 0; i < heap->st_size; i++) { + h = DUK__HEAPPTR_DEC16(heap, strtable[i]); + while (h != NULL) { + DUK_ASSERT((DUK_HSTRING_GET_HASH(h) & heap->st_mask) == i); + count++; + h = h->hdr.h_next; + } + } + } else { + DUK_ASSERT(heap->st_size == 0); + DUK_ASSERT(heap->st_mask == 0); + } + +#if defined(DUK__STRTAB_RESIZE_CHECK) + DUK_ASSERT(count == (duk_size_t) heap->st_count); +#endif +} +#endif /* DUK_USE_ASSERTIONS */ + +/* + * Allocate and initialize a duk_hstring. + * + * Returns a NULL if allocation or initialization fails for some reason. * - * The caller must place the interned string into the stringtable - * immediately (without chance of a longjmp); otherwise the string - * is lost. + * The string won't be inserted into the string table and isn't tracked in + * any way (link pointers will be NULL). The caller must place the string + * into the string table without any risk of a longjmp, otherwise the string + * is leaked. */ -DUK_LOCAL -duk_hstring *duk__alloc_init_hstring(duk_heap *heap, - const duk_uint8_t *str, - duk_uint32_t blen, - duk_uint32_t strhash, - const duk_uint8_t *extdata) { - duk_hstring *res = NULL; - duk_uint8_t *data; - duk_size_t alloc_size; +DUK_LOCAL duk_hstring *duk__strtable_alloc_hstring(duk_heap *heap, + const duk_uint8_t *str, + duk_uint32_t blen, + duk_uint32_t strhash, + const duk_uint8_t *extdata) { + duk_hstring *res; + const duk_uint8_t *data; #if !defined(DUK_USE_HSTRING_ARRIDX) duk_uarridx_t dummy; #endif - duk_uint32_t clen; + + DUK_ASSERT(heap != NULL); + DUK_UNREF(extdata); #if defined(DUK_USE_STRLEN16) /* If blen <= 0xffffUL, clen is also guaranteed to be <= 0xffffUL. */ if (blen > 0xffffUL) { DUK_D(DUK_DPRINT("16-bit string blen/clen active and blen over 16 bits, reject intern")); - return NULL; + goto alloc_error; } #endif + /* XXX: Memzeroing the allocated structure is not really necessary + * because we could just initialize all fields explicitly (almost + * all fields are initialized explicitly anyway). + */ +#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) if (extdata) { - alloc_size = (duk_size_t) sizeof(duk_hstring_external); - res = (duk_hstring *) DUK_ALLOC(heap, alloc_size); - if (!res) { + res = (duk_hstring *) DUK_ALLOC(heap, sizeof(duk_hstring_external)); + if (DUK_UNLIKELY(res == NULL)) { goto alloc_error; } DUK_MEMZERO(res, sizeof(duk_hstring_external)); @@ -60,12 +172,18 @@ #endif DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, DUK_HSTRING_FLAG_EXTDATA); + DUK_ASSERT(extdata[blen] == 0); /* Application responsibility. */ + data = extdata; ((duk_hstring_external *) res)->extdata = extdata; - } else { + } else +#endif /* DUK_USE_HSTRING_EXTDATA && DUK_USE_EXTSTR_INTERN_CHECK */ + { + duk_uint8_t *data_tmp; + /* NUL terminate for convenient C access */ - alloc_size = (duk_size_t) (sizeof(duk_hstring) + blen + 1); - res = (duk_hstring *) DUK_ALLOC(heap, alloc_size); - if (!res) { + DUK_ASSERT(sizeof(duk_hstring) + blen + 1 > blen); /* No wrap, limits ensure. */ + res = (duk_hstring *) DUK_ALLOC(heap, sizeof(duk_hstring) + blen + 1); + if (DUK_UNLIKELY(res == NULL)) { goto alloc_error; } DUK_MEMZERO(res, sizeof(duk_hstring)); @@ -74,1081 +192,778 @@ #endif DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, 0); - data = (duk_uint8_t *) (res + 1); - DUK_MEMCPY(data, str, blen); - data[blen] = (duk_uint8_t) 0; + data_tmp = (duk_uint8_t *) (res + 1); + DUK_MEMCPY(data_tmp, str, blen); + data_tmp[blen] = (duk_uint8_t) 0; + data = (const duk_uint8_t *) data_tmp; } + DUK_HSTRING_SET_BYTELEN(res, blen); + DUK_HSTRING_SET_HASH(res, strhash); + DUK_ASSERT(!DUK_HSTRING_HAS_ARRIDX(res)); #if defined(DUK_USE_HSTRING_ARRIDX) - if (duk_js_to_arrayindex_raw_string(str, blen, &res->arridx)) { + res->arridx = duk_js_to_arrayindex_string(data, blen); + if (res->arridx != DUK_HSTRING_NO_ARRAY_INDEX) { #else - if (duk_js_to_arrayindex_raw_string(str, blen, &dummy)) { + dummy = duk_js_to_arrayindex_string(data, blen); + if (dummy != DUK_HSTRING_NO_ARRAY_INDEX) { #endif + /* Array index strings cannot be symbol strings, + * and they're always pure ASCII so blen == clen. + */ DUK_HSTRING_SET_ARRIDX(res); - } - - /* All strings beginning with specific (invalid UTF-8) byte prefixes - * are treated as symbols. - */ - DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(res)); - DUK_ASSERT(!DUK_HSTRING_HAS_HIDDEN(res)); - if (blen > 0) { - if (str[0] == 0xffU) { - DUK_HSTRING_SET_SYMBOL(res); - DUK_HSTRING_SET_HIDDEN(res); - } else if ((str[0] & 0xc0U) == 0x80U) { - DUK_HSTRING_SET_SYMBOL(res); + DUK_HSTRING_SET_ASCII(res); + DUK_ASSERT(duk_unicode_unvalidated_utf8_length(data, (duk_size_t) blen) == blen); + } else { + /* Because 'data' is NUL-terminated, we don't need a + * blen > 0 check here. For NUL (0x00) the symbol + * checks will be false. + */ + if (DUK_UNLIKELY(data[0] >= 0x80U)) { + if (data[0] == 0xffU) { + DUK_HSTRING_SET_SYMBOL(res); + DUK_HSTRING_SET_HIDDEN(res); + } else if (data[0] <= 0xbf) { + /* Check equivalent to: (data[0] & 0xc0U) == 0x80U. */ + DUK_HSTRING_SET_SYMBOL(res); + } } - } - - DUK_HSTRING_SET_HASH(res, strhash); - DUK_HSTRING_SET_BYTELEN(res, blen); - - clen = (duk_uint32_t) duk_unicode_unvalidated_utf8_length(str, (duk_size_t) blen); - DUK_ASSERT(clen <= blen); -#if defined(DUK_USE_HSTRING_CLEN) - DUK_HSTRING_SET_CHARLEN(res, clen); -#endif - /* Using an explicit 'ASCII' flag has larger footprint (one call site - * only) but is quite useful for the case when there's no explicit - * 'clen' in duk_hstring. - */ - DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(res)); - if (clen == blen) { - DUK_HSTRING_SET_ASCII(res); + /* Using an explicit 'ASCII' flag has larger footprint (one call site + * only) but is quite useful for the case when there's no explicit + * 'clen' in duk_hstring. + * + * The flag is set lazily for RAM strings. + */ + DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(res)); } - DUK_DDD(DUK_DDDPRINT("interned string, hash=0x%08lx, blen=%ld, clen=%ld, has_arridx=%ld, has_extdata=%ld", + DUK_DDD(DUK_DDDPRINT("interned string, hash=0x%08lx, blen=%ld, has_arridx=%ld, has_extdata=%ld", (unsigned long) DUK_HSTRING_GET_HASH(res), (long) DUK_HSTRING_GET_BYTELEN(res), - (long) DUK_HSTRING_GET_CHARLEN(res), (long) (DUK_HSTRING_HAS_ARRIDX(res) ? 1 : 0), (long) (DUK_HSTRING_HAS_EXTDATA(res) ? 1 : 0))); + DUK_ASSERT(res != NULL); return res; alloc_error: - DUK_FREE(heap, res); return NULL; } /* - * String table algorithm: fixed size string table with array chaining - * - * The top level string table has a fixed size, with each slot holding - * either NULL, string pointer, or pointer to a separately allocated - * string pointer list. - * - * This is good for low memory environments using a pool allocator: the - * top level allocation has a fixed size and the pointer lists have quite - * small allocation size, which further matches the typical pool sizes - * needed by objects, strings, property tables, etc. + * Grow strtable allocation in-place. */ -#if defined(DUK_USE_STRTAB_CHAIN) +#if defined(DUK__STRTAB_RESIZE_CHECK) +DUK_LOCAL void duk__strtable_grow_inplace(duk_heap *heap) { + duk_uint32_t new_st_size; + duk_uint32_t old_st_size; + duk_uint32_t i; + duk_hstring *h; + duk_hstring *next; + duk_hstring *prev; +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *new_ptr; + duk_uint16_t *new_ptr_high; +#else + duk_hstring **new_ptr; + duk_hstring **new_ptr_high; +#endif -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL duk_bool_t duk__insert_hstring_chain(duk_heap *heap, duk_hstring *h) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_uint16_t *lst; - duk_uint16_t *new_lst; - duk_size_t i, n; - duk_uint16_t null16 = heap->heapptr_null16; - duk_uint16_t h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h); + DUK_DD(DUK_DDPRINT("grow in-place: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size * 2)); DUK_ASSERT(heap != NULL); - DUK_ASSERT(h != NULL); - - slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); - - e = heap->strtable + slotidx; - if (e->listlen == 0) { - if (e->u.str16 == null16) { - e->u.str16 = h16; - } else { - /* Now two entries in the same slot, alloc list */ - lst = (duk_uint16_t *) DUK_ALLOC(heap, sizeof(duk_uint16_t) * 2); - if (lst == NULL) { - return 1; /* fail */ - } - lst[0] = e->u.str16; - lst[1] = h16; - e->u.strlist16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) lst); - e->listlen = 2; - } - } else { - DUK_ASSERT(e->u.strlist16 != null16); - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); - DUK_ASSERT(lst != NULL); - for (i = 0, n = e->listlen; i < n; i++) { - if (lst[i] == null16) { - lst[i] = h16; - return 0; - } - } - - if (e->listlen + 1 == 0) { - /* Overflow, relevant mainly when listlen is 16 bits. */ - return 1; /* fail */ - } + DUK_ASSERT(heap->st_resizing == 1); + DUK_ASSERT(heap->st_size >= 2); + DUK_ASSERT((heap->st_size & (heap->st_size - 1)) == 0); /* 2^N */ + DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL); + + new_st_size = heap->st_size << 1U; + DUK_ASSERT(new_st_size > heap->st_size); /* No overflow. */ + + /* Reallocate the strtable first and then work in-place to rehash + * strings. We don't need an indirect allocation here: even if GC + * is triggered to satisfy the allocation, recursive strtable resize + * is prevented by flags. This is also why we don't need to use + * DUK_REALLOC_INDIRECT(). + */ - new_lst = (duk_uint16_t *) DUK_REALLOC(heap, lst, sizeof(duk_uint16_t) * (e->listlen + 1)); - if (new_lst == NULL) { - return 1; /* fail */ - } - new_lst[e->listlen++] = h16; - e->u.strlist16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) new_lst); +#if defined(DUK_USE_STRTAB_PTRCOMP) + new_ptr = (duk_uint16_t *) DUK_REALLOC(heap, heap->strtable16, sizeof(duk_uint16_t) * new_st_size); +#else + new_ptr = (duk_hstring **) DUK_REALLOC(heap, heap->strtable, sizeof(duk_hstring *) * new_st_size); +#endif + if (DUK_UNLIKELY(new_ptr == NULL)) { + /* If realloc fails we can continue normally: the string table + * won't "fill up" although chains will gradually get longer. + * When string insertions continue, we'll quite soon try again + * with no special handling. + */ + DUK_D(DUK_DPRINT("string table grow failed, ignoring")); + return; } - return 0; -} -#else /* DUK_USE_HEAPPTR16 */ -DUK_LOCAL duk_bool_t duk__insert_hstring_chain(duk_heap *heap, duk_hstring *h) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_hstring **lst; - duk_hstring **new_lst; - duk_size_t i, n; +#if defined(DUK_USE_STRTAB_PTRCOMP) + heap->strtable16 = new_ptr; +#else + heap->strtable = new_ptr; +#endif - DUK_ASSERT(heap != NULL); - DUK_ASSERT(h != NULL); + /* Rehash a single bucket into two separate ones. When we grow + * by x2 the highest 'new' bit determines whether a string remains + * in its old position (bit is 0) or goes to a new one (bit is 1). + */ - slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); + old_st_size = heap->st_size; + new_ptr_high = new_ptr + old_st_size; + for (i = 0; i < old_st_size; i++) { + duk_hstring *new_root; + duk_hstring *new_root_high; + + h = DUK__HEAPPTR_DEC16(heap, new_ptr[i]); + new_root = h; + new_root_high = NULL; + + prev = NULL; + while (h != NULL) { + duk_uint32_t mask; + + DUK_ASSERT((DUK_HSTRING_GET_HASH(h) & heap->st_mask) == i); + next = h->hdr.h_next; + + /* Example: if previous size was 256, previous mask is 0xFF + * and size is 0x100 which corresponds to the new bit that + * comes into play. + */ + DUK_ASSERT(heap->st_mask == old_st_size - 1); + mask = old_st_size; + if (DUK_HSTRING_GET_HASH(h) & mask) { + if (prev != NULL) { + prev->hdr.h_next = h->hdr.h_next; + } else { + DUK_ASSERT(h == new_root); + new_root = h->hdr.h_next; + } - e = heap->strtable + slotidx; - if (e->listlen == 0) { - if (e->u.str == NULL) { - e->u.str = h; - } else { - /* Now two entries in the same slot, alloc list */ - lst = (duk_hstring **) DUK_ALLOC(heap, sizeof(duk_hstring *) * 2); - if (lst == NULL) { - return 1; /* fail */ - } - lst[0] = e->u.str; - lst[1] = h; - e->u.strlist = lst; - e->listlen = 2; - } - } else { - DUK_ASSERT(e->u.strlist != NULL); - lst = e->u.strlist; - for (i = 0, n = e->listlen; i < n; i++) { - if (lst[i] == NULL) { - lst[i] = h; - return 0; + h->hdr.h_next = new_root_high; + new_root_high = h; + } else { + prev = h; } + h = next; } - if (e->listlen + 1 == 0) { - /* Overflow, relevant mainly when listlen is 16 bits. */ - return 1; /* fail */ - } - - new_lst = (duk_hstring **) DUK_REALLOC(heap, e->u.strlist, sizeof(duk_hstring *) * (e->listlen + 1)); - if (new_lst == NULL) { - return 1; /* fail */ - } - new_lst[e->listlen++] = h; - e->u.strlist = new_lst; + new_ptr[i] = DUK__HEAPPTR_ENC16(heap, new_root); + new_ptr_high[i] = DUK__HEAPPTR_ENC16(heap, new_root_high); } - return 0; -} -#endif /* DUK_USE_HEAPPTR16 */ -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_uint16_t *lst; - duk_size_t i, n; - duk_uint16_t null16 = heap->heapptr_null16; - - DUK_ASSERT(heap != NULL); - - slotidx = strhash % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); - - e = heap->strtable + slotidx; - if (e->listlen == 0) { - if (e->u.str16 != null16) { - duk_hstring *h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16); - DUK_ASSERT(h != NULL); - if (DUK_HSTRING_GET_BYTELEN(h) == blen && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) { - return h; - } - } - } else { - DUK_ASSERT(e->u.strlist16 != null16); - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); - DUK_ASSERT(lst != NULL); - for (i = 0, n = e->listlen; i < n; i++) { - if (lst[i] != null16) { - duk_hstring *h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[i]); - DUK_ASSERT(h != NULL); - if (DUK_HSTRING_GET_BYTELEN(h) == blen && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) { - return h; - } - } - } - } + heap->st_size = new_st_size; + heap->st_mask = new_st_size - 1; - return NULL; +#if defined(DUK_USE_ASSERTIONS) + duk__strtable_assert_checks(heap); +#endif } -#else /* DUK_USE_HEAPPTR16 */ -DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_hstring **lst; - duk_size_t i, n; - - DUK_ASSERT(heap != NULL); +#endif /* DUK__STRTAB_RESIZE_CHECK */ - slotidx = strhash % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); - - e = heap->strtable + slotidx; - if (e->listlen == 0) { - if (e->u.str != NULL && - DUK_HSTRING_GET_BYTELEN(e->u.str) == blen && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(e->u.str), (size_t) blen) == 0) { - return e->u.str; - } - } else { - DUK_ASSERT(e->u.strlist != NULL); - lst = e->u.strlist; - for (i = 0, n = e->listlen; i < n; i++) { - if (lst[i] != NULL && - DUK_HSTRING_GET_BYTELEN(lst[i]) == blen && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(lst[i]), (size_t) blen) == 0) { - return lst[i]; - } - } - } +/* + * Shrink strtable allocation in-place. + */ - return NULL; -} -#endif /* DUK_USE_HEAPPTR16 */ +#if defined(DUK__STRTAB_RESIZE_CHECK) +DUK_LOCAL void duk__strtable_shrink_inplace(duk_heap *heap) { + duk_uint32_t new_st_size; + duk_uint32_t i; + duk_hstring *h; + duk_hstring *other; + duk_hstring *root; +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *old_ptr; + duk_uint16_t *old_ptr_high; + duk_uint16_t *new_ptr; +#else + duk_hstring **old_ptr; + duk_hstring **old_ptr_high; + duk_hstring **new_ptr; +#endif -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL void duk__remove_matching_hstring_chain(duk_heap *heap, duk_hstring *h) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_uint16_t *lst; - duk_size_t i, n; - duk_uint16_t h16; - duk_uint16_t null16 = heap->heapptr_null16; + DUK_DD(DUK_DDPRINT("shrink in-place: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size / 2)); DUK_ASSERT(heap != NULL); - DUK_ASSERT(h != NULL); - - slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); + DUK_ASSERT(heap->st_resizing == 1); + DUK_ASSERT(heap->st_size >= 2); + DUK_ASSERT((heap->st_size & (heap->st_size - 1)) == 0); /* 2^N */ + DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL); - DUK_ASSERT(h != NULL); - h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h); + new_st_size = heap->st_size >> 1U; - e = heap->strtable + slotidx; - if (e->listlen == 0) { - if (e->u.str16 == h16) { - e->u.str16 = null16; - return; - } - } else { - DUK_ASSERT(e->u.strlist16 != null16); - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); - DUK_ASSERT(lst != NULL); - for (i = 0, n = e->listlen; i < n; i++) { - if (lst[i] == h16) { - lst[i] = null16; - return; + /* Combine two buckets into a single one. When we shrink, one hash + * bit (highest) disappears. + */ + old_ptr = DUK__GET_STRTABLE(heap); + old_ptr_high = old_ptr + new_st_size; + for (i = 0; i < new_st_size; i++) { + h = DUK__HEAPPTR_DEC16(heap, old_ptr[i]); + other = DUK__HEAPPTR_DEC16(heap, old_ptr_high[i]); + + if (h == NULL) { + /* First chain is empty, so use second one as is. */ + root = other; + } else { + /* Find end of first chain, and link in the second. */ + root = h; + while (h->hdr.h_next != NULL) { + h = h->hdr.h_next; } + h->hdr.h_next = other; } - } - - DUK_D(DUK_DPRINT("failed to find string that should be in stringtable")); - DUK_UNREACHABLE(); - return; -} -#else /* DUK_USE_HEAPPTR16 */ -DUK_LOCAL void duk__remove_matching_hstring_chain(duk_heap *heap, duk_hstring *h) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_hstring **lst; - duk_size_t i, n; - - DUK_ASSERT(heap != NULL); - DUK_ASSERT(h != NULL); - slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); - - e = heap->strtable + slotidx; - if (e->listlen == 0) { - DUK_ASSERT(h != NULL); - if (e->u.str == h) { - e->u.str = NULL; - return; - } - } else { - DUK_ASSERT(e->u.strlist != NULL); - lst = e->u.strlist; - for (i = 0, n = e->listlen; i < n; i++) { - DUK_ASSERT(h != NULL); - if (lst[i] == h) { - lst[i] = NULL; - return; - } - } + old_ptr[i] = DUK__HEAPPTR_ENC16(heap, root); } - DUK_D(DUK_DPRINT("failed to find string that should be in stringtable")); - DUK_UNREACHABLE(); - return; -} -#endif /* DUK_USE_HEAPPTR16 */ + heap->st_size = new_st_size; + heap->st_mask = new_st_size - 1; -#if defined(DUK_USE_DEBUG) -DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap) { - duk_strtab_entry *e; - duk_small_uint_t i; - duk_size_t j, n, used; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t *lst; - duk_uint16_t null16 = heap->heapptr_null16; + /* The strtable is now consistent and we can realloc safely. Even + * if side effects cause string interning or removal the strtable + * updates are safe. Recursive resize has been prevented by caller. + * This is also why we don't need to use DUK_REALLOC_INDIRECT(). + * + * We assume a realloc() to a smaller size is guaranteed to succeed. + * It would be relatively straightforward to handle the error by + * essentially performing a "grow" step to recover. + */ + +#if defined(DUK_USE_STRTAB_PTRCOMP) + new_ptr = (duk_uint16_t *) DUK_REALLOC(heap, heap->strtable16, sizeof(duk_uint16_t) * new_st_size); + DUK_ASSERT(new_ptr != NULL); + heap->strtable16 = new_ptr; #else - duk_hstring **lst; + new_ptr = (duk_hstring **) DUK_REALLOC(heap, heap->strtable, sizeof(duk_hstring *) * new_st_size); + DUK_ASSERT(new_ptr != NULL); + heap->strtable = new_ptr; #endif - DUK_ASSERT(heap != NULL); +#if defined(DUK_USE_ASSERTIONS) + duk__strtable_assert_checks(heap); +#endif +} +#endif /* DUK__STRTAB_RESIZE_CHECK */ - for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { - e = heap->strtable + i; +/* + * Grow/shrink check. + */ + +#if defined(DUK__STRTAB_RESIZE_CHECK) +DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__strtable_resize_check(duk_heap *heap) { + duk_uint32_t load_factor; /* fixed point */ - if (e->listlen == 0) { -#if defined(DUK_USE_HEAPPTR16) - DUK_DD(DUK_DDPRINT("[%03d] -> plain %d", (int) i, (int) (e->u.str16 != null16 ? 1 : 0))); + DUK_ASSERT(heap != NULL); +#if defined(DUK_USE_STRTAB_PTRCOMP) + DUK_ASSERT(heap->strtable16 != NULL); #else - DUK_DD(DUK_DDPRINT("[%03d] -> plain %d", (int) i, (int) (e->u.str ? 1 : 0))); + DUK_ASSERT(heap->strtable != NULL); #endif + + /* Prevent recursive resizing. */ + if (DUK_UNLIKELY(heap->st_resizing)) { + DUK_D(DUK_DPRINT("prevent recursive strtable resize")); + return; + } + + heap->st_resizing = 1; + + DUK_ASSERT(heap->st_size >= 16U); + DUK_ASSERT((heap->st_size >> 4U) >= 1); + load_factor = heap->st_count / (heap->st_size >> 4U); + + DUK_DD(DUK_DDPRINT("resize check string table: size=%lu, count=%lu, load_factor=%lu (fixed point .4; float %lf)", + (unsigned long) heap->st_size, (unsigned long) heap->st_count, + (unsigned long) load_factor, + (double) heap->st_count / (double) heap->st_size)); + + if (load_factor >= DUK_USE_STRTAB_GROW_LIMIT) { + if (heap->st_size >= DUK_USE_STRTAB_MAXSIZE) { + DUK_DD(DUK_DDPRINT("want to grow strtable (based on load factor) but already maximum size")); } else { - used = 0; -#if defined(DUK_USE_HEAPPTR16) - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); -#else - lst = e->u.strlist; + DUK_D(DUK_DPRINT("grow string table: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size * 2)); +#if defined(DUK_USE_DEBUG) + duk_heap_strtable_dump(heap); #endif - DUK_ASSERT(lst != NULL); - for (j = 0, n = e->listlen; j < n; j++) { -#if defined(DUK_USE_HEAPPTR16) - if (lst[j] != null16) { -#else - if (lst[j] != NULL) { + duk__strtable_grow_inplace(heap); + } + } else if (load_factor <= DUK_USE_STRTAB_SHRINK_LIMIT) { + if (heap->st_size <= DUK_USE_STRTAB_MINSIZE) { + DUK_DD(DUK_DDPRINT("want to shrink strtable (based on load factor) but already minimum size")); + } else { + DUK_D(DUK_DPRINT("shrink string table: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size / 2)); +#if defined(DUK_USE_DEBUG) + duk_heap_strtable_dump(heap); #endif - used++; - } - } - DUK_DD(DUK_DDPRINT("[%03d] -> array %d/%d", (int) i, (int) used, (int) e->listlen)); + duk__strtable_shrink_inplace(heap); } + } else { + DUK_DD(DUK_DDPRINT("no need for strtable resize")); } -} -#endif /* DUK_USE_DEBUG */ -#endif /* DUK_USE_STRTAB_CHAIN */ + heap->st_resizing = 0; +} +#endif /* DUK__STRTAB_RESIZE_CHECK */ /* - * String table algorithm: closed hashing with a probe sequence - * - * This is the default algorithm and works fine for environments with - * minimal memory constraints. + * Torture grow/shrink: unconditionally grow and shrink back. */ -#if defined(DUK_USE_STRTAB_PROBE) +#if defined(DUK_USE_STRTAB_TORTURE) && defined(DUK__STRTAB_RESIZE_CHECK) +DUK_LOCAL void duk__strtable_resize_torture(duk_heap *heap) { + duk_uint32_t old_st_size; -/* Count actually used (non-NULL, non-DELETED) entries. */ -DUK_LOCAL duk_int_t duk__count_used_probe(duk_heap *heap) { - duk_int_t res = 0; - duk_uint_fast32_t i, n; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t null16 = heap->heapptr_null16; - duk_uint16_t deleted16 = heap->heapptr_deleted16; -#endif + DUK_ASSERT(heap != NULL); - n = (duk_uint_fast32_t) heap->st_size; - for (i = 0; i < n; i++) { -#if defined(DUK_USE_HEAPPTR16) - if (heap->strtable16[i] != null16 && heap->strtable16[i] != deleted16) { -#else - if (heap->strtable[i] != NULL && heap->strtable[i] != DUK__DELETED_MARKER(heap)) { -#endif - res++; - } + old_st_size = heap->st_size; + if (old_st_size >= DUK_USE_STRTAB_MAXSIZE) { + return; } - return res; -} - -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL void duk__insert_hstring_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, duk_uint32_t *p_used, duk_hstring *h) { -#else -DUK_LOCAL void duk__insert_hstring_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, duk_uint32_t *p_used, duk_hstring *h) { -#endif - duk_uint32_t i; - duk_uint32_t step; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t null16 = heap->heapptr_null16; - duk_uint16_t deleted16 = heap->heapptr_deleted16; -#endif - - DUK_ASSERT(size > 0); - - i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(h), size); - step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(h)); - for (;;) { -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t e16 = entries16[i]; -#else - duk_hstring *e = entries[i]; -#endif - -#if defined(DUK_USE_HEAPPTR16) - /* XXX: could check for e16 == 0 because NULL is guaranteed to - * encode to zero. - */ - if (e16 == null16) { -#else - if (e == NULL) { -#endif - DUK_DDD(DUK_DDDPRINT("insert hit (null): %ld", (long) i)); -#if defined(DUK_USE_HEAPPTR16) - entries16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h); -#else - entries[i] = h; -#endif - (*p_used)++; - break; -#if defined(DUK_USE_HEAPPTR16) - } else if (e16 == deleted16) { -#else - } else if (e == DUK__DELETED_MARKER(heap)) { -#endif - /* st_used remains the same, DELETED is counted as used */ - DUK_DDD(DUK_DDDPRINT("insert hit (deleted): %ld", (long) i)); -#if defined(DUK_USE_HEAPPTR16) - entries16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h); -#else - entries[i] = h; -#endif - break; - } - DUK_DDD(DUK_DDDPRINT("insert miss: %ld", (long) i)); - i = (i + step) % size; - /* looping should never happen */ - DUK_ASSERT(i != DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(h), size)); + heap->st_resizing = 1; + duk__strtable_grow_inplace(heap); + if (heap->st_size > old_st_size) { + duk__strtable_shrink_inplace(heap); } + heap->st_resizing = 0; } +#endif /* DUK_USE_STRTAB_TORTURE && DUK__STRTAB_RESIZE_CHECK */ -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL duk_hstring *duk__find_matching_string_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { -#else -DUK_LOCAL duk_hstring *duk__find_matching_string_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { -#endif - duk_uint32_t i; - duk_uint32_t step; - - DUK_ASSERT(size > 0); +/* + * Raw intern; string already checked not to be present. + */ - i = DUK__HASH_INITIAL(strhash, size); - step = DUK__HASH_PROBE_STEP(strhash); - for (;;) { - duk_hstring *e; -#if defined(DUK_USE_HEAPPTR16) - e = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, entries16[i]); +DUK_LOCAL duk_hstring *duk__strtable_do_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { + duk_hstring *res; + const duk_uint8_t *extdata; +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *slot; #else - e = entries[i]; + duk_hstring **slot; #endif - if (!e) { - return NULL; - } - if (e != DUK__DELETED_MARKER(heap) && DUK_HSTRING_GET_BYTELEN(e) == blen) { - if (DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(e), (size_t) blen) == 0) { - DUK_DDD(DUK_DDDPRINT("find matching hit: %ld (step %ld, size %ld)", - (long) i, (long) step, (long) size)); - return e; - } - } - DUK_DDD(DUK_DDDPRINT("find matching miss: %ld (step %ld, size %ld)", - (long) i, (long) step, (long) size)); - i = (i + step) % size; + DUK_DDD(DUK_DDDPRINT("do_intern: heap=%p, str=%p, blen=%lu, strhash=%lx, st_size=%lu, st_count=%lu, load=%lf", + (void *) heap, (const void *) str, (unsigned long) blen, (unsigned long) strhash, + (unsigned long) heap->st_size, (unsigned long) heap->st_count, + (double) heap->st_count / (double) heap->st_size)); - /* looping should never happen */ - DUK_ASSERT(i != DUK__HASH_INITIAL(strhash, size)); - } - DUK_UNREACHABLE(); -} + DUK_ASSERT(heap != NULL); -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL void duk__remove_matching_hstring_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, duk_hstring *h) { -#else -DUK_LOCAL void duk__remove_matching_hstring_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, duk_hstring *h) { -#endif - duk_uint32_t i; - duk_uint32_t step; - duk_uint32_t hash; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t null16 = heap->heapptr_null16; - duk_uint16_t h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h); -#endif + /* Prevent any side effects on the string table and the caller provided + * str/blen arguments while interning is in progress. For example, if + * the caller provided str/blen from a dynamic buffer, a finalizer + * might resize or modify that dynamic buffer, invalidating the call + * arguments. + * + * While finalizers must be prevented, mark-and-sweep itself is fine. + * Recursive string table resize is prevented explicitly here. + */ - DUK_ASSERT(size > 0); - - hash = DUK_HSTRING_GET_HASH(h); - i = DUK__HASH_INITIAL(hash, size); - step = DUK__HASH_PROBE_STEP(hash); - for (;;) { -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t e16 = entries16[i]; -#else - duk_hstring *e = entries[i]; -#endif + heap->pf_prevent_count++; + DUK_ASSERT(heap->pf_prevent_count != 0); /* Wrap. */ -#if defined(DUK_USE_HEAPPTR16) - if (e16 == null16) { -#else - if (!e) { -#endif - DUK_UNREACHABLE(); - break; - } -#if defined(DUK_USE_HEAPPTR16) - if (e16 == h16) { -#else - if (e == h) { -#endif - /* st_used remains the same, DELETED is counted as used */ - DUK_DDD(DUK_DDDPRINT("free matching hit: %ld", (long) i)); -#if defined(DUK_USE_HEAPPTR16) - entries16[i] = heap->heapptr_deleted16; -#else - entries[i] = DUK__DELETED_MARKER(heap); +#if defined(DUK_USE_STRTAB_TORTURE) && defined(DUK__STRTAB_RESIZE_CHECK) + duk__strtable_resize_torture(heap); #endif - break; - } - DUK_DDD(DUK_DDDPRINT("free matching miss: %ld", (long) i)); - i = (i + step) % size; + /* String table grow/shrink check. Because of chaining (and no + * accumulation issues as with hash probe chains and DELETED + * markers) there's never a mandatory need to resize right now. + * Check for the resize only periodically, based on st_count + * bit pattern. Because string table removal doesn't do a shrink + * check, we do that also here. + * + * Do the resize and possible grow/shrink before the new duk_hstring + * has been allocated. Otherwise we may trigger a GC when the result + * duk_hstring is not yet strongly referenced. + */ - /* looping should never happen */ - DUK_ASSERT(i != DUK__HASH_INITIAL(hash, size)); +#if defined(DUK__STRTAB_RESIZE_CHECK) + if (DUK_UNLIKELY((heap->st_count & DUK_USE_STRTAB_RESIZE_CHECK_MASK) == 0)) { + duk__strtable_resize_check(heap); } -} - -DUK_LOCAL duk_bool_t duk__resize_strtab_raw_probe(duk_heap *heap, duk_uint32_t new_size) { -#if defined(DUK_USE_DEBUG) - duk_uint32_t old_used = heap->st_used; -#endif - duk_uint32_t old_size = heap->st_size; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t *old_entries = heap->strtable16; - duk_uint16_t *new_entries = NULL; -#else - duk_hstring **old_entries = heap->strtable; - duk_hstring **new_entries = NULL; #endif - duk_uint32_t new_used = 0; - duk_uint32_t i; -#if defined(DUK_USE_DEBUG) - DUK_UNREF(old_used); /* unused with some debug level combinations */ -#endif + /* External string check (low memory optimization). */ -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) - DUK_DDD(DUK_DDDPRINT("attempt to resize stringtable: %ld entries, %ld bytes, %ld used, %ld%% load -> %ld entries, %ld bytes, %ld used, %ld%% load", - (long) old_size, (long) (sizeof(duk_hstring *) * old_size), (long) old_used, - (long) (((double) old_used) / ((double) old_size) * 100.0), - (long) new_size, (long) (sizeof(duk_hstring *) * new_size), (long) duk__count_used_probe(heap), - (long) (((double) duk__count_used_probe(heap)) / ((double) new_size) * 100.0))); +#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) + extdata = (const duk_uint8_t *) DUK_USE_EXTSTR_INTERN_CHECK(heap->heap_udata, (void *) DUK_LOSE_CONST(str), (duk_size_t) blen); +#else + extdata = (const duk_uint8_t *) NULL; #endif - DUK_ASSERT(new_size > (duk_uint32_t) duk__count_used_probe(heap)); /* required for rehash to succeed, equality not that useful */ - DUK_ASSERT(old_entries); - - /* - * The attempt to allocate may cause a GC. Such a GC must not attempt to resize - * the stringtable (though it can be swept); finalizer execution and object - * compaction must also be postponed to avoid the pressure to add strings to the - * string table. Call site must prevent these. + /* Allocate and initialize string, not yet linked. This may cause a + * GC which may cause other strings to be interned and inserted into + * the string table before we insert our string. Finalizer execution + * is disabled intentionally to avoid a finalizer from e.g. resizing + * a buffer used as a data area for 'str'. */ - DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE); - DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_FINALIZERS); - DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_OBJECT_COMPACTION); + res = duk__strtable_alloc_hstring(heap, str, blen, strhash, extdata); -#if defined(DUK_USE_HEAPPTR16) - new_entries = (duk_uint16_t *) DUK_ALLOC(heap, sizeof(duk_uint16_t) * new_size); -#else - new_entries = (duk_hstring **) DUK_ALLOC(heap, sizeof(duk_hstring *) * new_size); -#endif + /* Allow side effects again: GC must be avoided until duk_hstring + * result (if successful) has been INCREF'd. + */ + DUK_ASSERT(heap->pf_prevent_count > 0); + heap->pf_prevent_count--; - if (!new_entries) { - goto resize_error; - } + /* Alloc error handling. */ -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - for (i = 0; i < new_size; i++) { -#if defined(DUK_USE_HEAPPTR16) - new_entries[i] = heap->heapptr_null16; -#else - new_entries[i] = NULL; + if (DUK_UNLIKELY(res == NULL)) { +#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) + if (extdata != NULL) { + DUK_USE_EXTSTR_FREE(heap->heap_udata, (const void *) extdata); + } #endif + return NULL; } -#else -#if defined(DUK_USE_HEAPPTR16) - /* Relies on NULL encoding to zero. */ - DUK_MEMZERO(new_entries, sizeof(duk_uint16_t) * new_size); -#else - DUK_MEMZERO(new_entries, sizeof(duk_hstring *) * new_size); -#endif -#endif - /* Because new_size > duk__count_used_probe(heap), guaranteed to work */ - for (i = 0; i < old_size; i++) { - duk_hstring *e; + /* Insert into string table. */ -#if defined(DUK_USE_HEAPPTR16) - e = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, old_entries[i]); +#if defined(DUK_USE_STRTAB_PTRCOMP) + slot = heap->strtable16 + (strhash & heap->st_mask); #else - e = old_entries[i]; + slot = heap->strtable + (strhash & heap->st_mask); #endif - if (e == NULL || e == DUK__DELETED_MARKER(heap)) { - continue; - } - /* checking for DUK__DELETED_MARKER is not necessary here, but helper does it now */ - duk__insert_hstring_probe(heap, new_entries, new_size, &new_used, e); - } + DUK_ASSERT(res->hdr.h_next == NULL); /* This is the case now, but unnecessary zeroing/NULLing. */ + res->hdr.h_next = DUK__HEAPPTR_DEC16(heap, *slot); + *slot = DUK__HEAPPTR_ENC16(heap, res); -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1) - DUK_DD(DUK_DDPRINT("resized stringtable: %ld entries, %ld bytes, %ld used, %ld%% load -> %ld entries, %ld bytes, %ld used, %ld%% load", - (long) old_size, (long) (sizeof(duk_hstring *) * old_size), (long) old_used, - (long) (((double) old_used) / ((double) old_size) * 100.0), - (long) new_size, (long) (sizeof(duk_hstring *) * new_size), (long) new_used, - (long) (((double) new_used) / ((double) new_size) * 100.0))); -#endif + /* Update string count only for successful inserts. */ -#if defined(DUK_USE_HEAPPTR16) - DUK_FREE(heap, heap->strtable16); - heap->strtable16 = new_entries; -#else - DUK_FREE(heap, heap->strtable); - heap->strtable = new_entries; +#if defined(DUK__STRTAB_RESIZE_CHECK) + heap->st_count++; #endif - heap->st_size = new_size; - heap->st_used = new_used; /* may be less, since DELETED entries are NULLed by rehash */ - return 0; /* OK */ + /* The duk_hstring is in the string table but is not yet strongly + * reachable. Calling code MUST NOT make any allocations or other + * side effects before the duk_hstring has been INCREF'd and made + * reachable. + */ - resize_error: - DUK_FREE(heap, new_entries); - return 1; /* FAIL */ + return res; } -DUK_LOCAL duk_bool_t duk__resize_strtab_probe(duk_heap *heap) { - duk_uint32_t new_size; - duk_bool_t ret; - - new_size = (duk_uint32_t) duk__count_used_probe(heap); - if (new_size >= 0x80000000UL) { - new_size = DUK_STRTAB_HIGHEST_32BIT_PRIME; - } else { - new_size = duk_util_get_hash_prime(DUK_STRTAB_GROW_ST_SIZE(new_size)); - new_size = duk_util_get_hash_prime(new_size); - } - DUK_ASSERT(new_size > 0); +/* + * Intern a string from str/blen, returning either an existing duk_hstring + * or adding a new one into the string table. The input string does -not- + * need to be NUL terminated. + * + * The input 'str' argument may point to a Duktape managed data area such as + * the data area of a dynamic buffer. It's crucial to avoid any side effects + * that might affect the data area (e.g. resize the dynamic buffer, or write + * to the buffer) before the string is fully interned. + */ - /* rehash even if old and new sizes are the same to get rid of - * DELETED entries. - */ +#if defined(DUK_USE_ROM_STRINGS) +DUK_LOCAL duk_hstring *duk__strtab_romstring_lookup(duk_heap *heap, const duk_uint8_t *str, duk_size_t blen, duk_uint32_t strhash) { + duk_size_t lookup_hash; + duk_hstring *curr; - ret = duk__resize_strtab_raw_probe(heap, new_size); + DUK_ASSERT(heap != NULL); + DUK_UNREF(heap); - return ret; -} + lookup_hash = (blen << 4); + if (blen > 0) { + lookup_hash += str[0]; + } + lookup_hash &= 0xff; -DUK_LOCAL duk_bool_t duk__recheck_strtab_size_probe(duk_heap *heap, duk_uint32_t new_used) { - duk_uint32_t new_free; - duk_uint32_t tmp1; - duk_uint32_t tmp2; - - DUK_ASSERT(new_used <= heap->st_size); /* grow by at most one */ - new_free = heap->st_size - new_used; /* unsigned intentionally */ - - /* new_free / size <= 1 / DIV <=> new_free <= size / DIV */ - /* new_used / size <= 1 / DIV <=> new_used <= size / DIV */ - - tmp1 = heap->st_size / DUK_STRTAB_MIN_FREE_DIVISOR; - tmp2 = heap->st_size / DUK_STRTAB_MIN_USED_DIVISOR; - - if (new_free <= tmp1 || new_used <= tmp2) { - /* load factor too low or high, count actually used entries and resize */ - return duk__resize_strtab_probe(heap); - } else { - return 0; /* OK */ + curr = DUK_LOSE_CONST(duk_rom_strings_lookup[lookup_hash]); + while (curr != NULL) { + if (strhash == DUK_HSTRING_GET_HASH(curr) && + blen == DUK_HSTRING_GET_BYTELEN(curr) && + DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(curr), blen) == 0) { + DUK_DDD(DUK_DDDPRINT("intern check: rom string: %!O, computed hash 0x%08lx, rom hash 0x%08lx", + curr, (unsigned long) strhash, (unsigned long) DUK_HSTRING_GET_HASH(curr))); + return curr; + } + curr = curr->hdr.h_next; } + + return NULL; } +#endif /* DUK_USE_ROM_STRINGS */ -#if defined(DUK_USE_DEBUG) -DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap) { - duk_uint32_t i; +DUK_INTERNAL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) { + duk_uint32_t strhash; duk_hstring *h; + DUK_DDD(DUK_DDDPRINT("intern check: heap=%p, str=%p, blen=%lu", (void *) heap, (const void *) str, (unsigned long) blen)); + + /* Preliminaries. */ + DUK_ASSERT(heap != NULL); -#if defined(DUK_USE_HEAPPTR16) - DUK_ASSERT(heap->strtable16 != NULL); -#else - DUK_ASSERT(heap->strtable != NULL); -#endif - DUK_UNREF(h); + DUK_ASSERT(blen == 0 || str != NULL); + DUK_ASSERT(blen <= DUK_HSTRING_MAX_BYTELEN); /* Caller is responsible for ensuring this. */ + strhash = duk_heap_hashstring(heap, str, (duk_size_t) blen); - for (i = 0; i < heap->st_size; i++) { -#if defined(DUK_USE_HEAPPTR16) - h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->strtable16[i]); + /* String table lookup. */ + + DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL); + DUK_ASSERT(heap->st_size > 0); + DUK_ASSERT(heap->st_size == heap->st_mask + 1); +#if defined(DUK_USE_STRTAB_PTRCOMP) + h = DUK__HEAPPTR_DEC16(heap, heap->strtable16[strhash & heap->st_mask]); #else - h = heap->strtable[i]; + h = heap->strtable[strhash & heap->st_mask]; #endif - - DUK_DD(DUK_DDPRINT("[%03d] -> %p", (int) i, (void *) h)); + while (h != NULL) { + if (DUK_HSTRING_GET_HASH(h) == strhash && + DUK_HSTRING_GET_BYTELEN(h) == blen && + DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) { + /* Found existing entry. */ + return h; + } + h = h->hdr.h_next; } -} -#endif /* DUK_USE_DEBUG */ -#endif /* DUK_USE_STRTAB_PROBE */ - -/* - * Raw intern and lookup - */ - -DUK_LOCAL duk_hstring *duk__do_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { - duk_hstring *res; - const duk_uint8_t *extdata; - duk_small_uint_t prev_mark_and_sweep_base_flags; - - /* Prevent any side effects on the string table and the caller provided - * str/blen arguments while interning is in progress. For example, if - * the caller provided str/blen from a dynamic buffer, a finalizer might - * resize that dynamic buffer, invalidating the call arguments. + /* ROM table lookup. Because this lookup is slower, do it only after + * RAM lookup. This works because no ROM string is ever interned into + * the RAM string table. */ - DUK_ASSERT((heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE) == 0); - prev_mark_and_sweep_base_flags = heap->mark_and_sweep_base_flags; - DUK__PREVENT_MS_SIDE_EFFECTS(heap); - -#if defined(DUK_USE_STRTAB_PROBE) - if (duk__recheck_strtab_size_probe(heap, heap->st_used + 1)) { - goto failed; - } -#endif -#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) - extdata = (const duk_uint8_t *) DUK_USE_EXTSTR_INTERN_CHECK(heap->heap_udata, (void *) DUK_LOSE_CONST(str), (duk_size_t) blen); -#else - extdata = (const duk_uint8_t *) NULL; -#endif - res = duk__alloc_init_hstring(heap, str, blen, strhash, extdata); - if (!res) { - goto failed; - } - -#if defined(DUK_USE_STRTAB_CHAIN) - if (duk__insert_hstring_chain(heap, res)) { - /* failed */ - DUK_FREE(heap, res); - goto failed; - } -#elif defined(DUK_USE_STRTAB_PROBE) - /* guaranteed to succeed */ - duk__insert_hstring_probe(heap, -#if defined(DUK_USE_HEAPPTR16) - heap->strtable16, -#else - heap->strtable, -#endif - heap->st_size, - &heap->st_used, - res); -#else -#error internal error, invalid strtab options +#if defined(DUK_USE_ROM_STRINGS) + h = duk__strtab_romstring_lookup(heap, str, blen, strhash); + if (h != NULL) { + return h; + } #endif - /* Note: hstring is in heap but has refcount zero and is not strongly reachable. - * Caller should increase refcount and make the hstring reachable before any - * operations which require allocation (and possible gc). - */ - - done: - heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; - return res; + /* Not found in string table; insert. */ - failed: - res = NULL; - goto done; + h = duk__strtable_do_intern(heap, str, blen, strhash); + return h; /* may be NULL */ } -DUK_LOCAL duk_hstring *duk__do_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t *out_strhash) { - duk_hstring *res; +/* + * Intern a string from u32. + */ - DUK_ASSERT(out_strhash); +/* XXX: Could arrange some special handling because we know that the result + * will have an arridx flag and an ASCII flag, won't need a clen check, etc. + */ - *out_strhash = duk_heap_hashstring(heap, str, (duk_size_t) blen); +DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32(duk_heap *heap, duk_uint32_t val) { + char buf[DUK__STRTAB_U32_MAX_STRLEN]; + char *p; -#if defined(DUK_USE_ROM_STRINGS) - { - duk_small_uint_t i; - /* XXX: This is VERY inefficient now, and should be e.g. a - * binary search or perfect hash, to be fixed. - */ - for (i = 0; i < (duk_small_uint_t) (sizeof(duk_rom_strings) / sizeof(duk_hstring *)); i++) { - duk_hstring *romstr; - romstr = (duk_hstring *) DUK_LOSE_CONST(duk_rom_strings[i]); - if (blen == DUK_HSTRING_GET_BYTELEN(romstr) && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(romstr), blen) == 0) { - DUK_DD(DUK_DDPRINT("intern check: rom string: %!O, computed hash 0x%08lx, rom hash 0x%08lx", - romstr, (unsigned long) *out_strhash, (unsigned long) DUK_HSTRING_GET_HASH(romstr))); - DUK_ASSERT(*out_strhash == DUK_HSTRING_GET_HASH(romstr)); - *out_strhash = DUK_HSTRING_GET_HASH(romstr); - return romstr; - } - } - } -#endif /* DUK_USE_ROM_STRINGS */ + DUK_ASSERT(heap != NULL); -#if defined(DUK_USE_STRTAB_CHAIN) - res = duk__find_matching_string_chain(heap, str, blen, *out_strhash); -#elif defined(DUK_USE_STRTAB_PROBE) - res = duk__find_matching_string_probe(heap, -#if defined(DUK_USE_HEAPPTR16) - heap->strtable16, -#else - heap->strtable, -#endif - heap->st_size, - str, - blen, - *out_strhash); -#else -#error internal error, invalid strtab options -#endif + /* This is smaller and faster than a %lu sprintf. */ + p = buf + sizeof(buf); + do { + p--; + *p = duk_lc_digits[val % 10]; + val = val / 10; + } while (val != 0); /* For val == 0, emit exactly one '0'. */ + DUK_ASSERT(p >= buf); - return res; + return duk_heap_strtable_intern(heap, (const duk_uint8_t *) p, (duk_uint32_t) ((buf + sizeof(buf)) - p)); } /* - * Exposed calls + * Checked convenience variants. + * + * XXX: Because the main use case is for the checked variants, make them the + * main functionality and provide a safe variant separately (it is only needed + * during heap init). The problem with that is that longjmp state and error + * creation must already be possible to throw. */ -#if 0 /*unused*/ -DUK_INTERNAL duk_hstring *duk_heap_string_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) { - duk_uint32_t strhash; /* dummy */ - return duk__do_lookup(heap, str, blen, &strhash); -} -#endif - -DUK_INTERNAL duk_hstring *duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) { +DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) { duk_hstring *res; - duk_uint32_t strhash; - /* caller is responsible for ensuring this */ - DUK_ASSERT(blen <= DUK_HSTRING_MAX_BYTELEN); + DUK_ASSERT(thr != NULL); + DUK_ASSERT(thr->heap != NULL); + DUK_ASSERT(blen == 0 || str != NULL); - res = duk__do_lookup(heap, str, blen, &strhash); - if (res) { - return res; - } - - res = duk__do_intern(heap, str, blen, strhash); - return res; /* may be NULL */ -} - -DUK_INTERNAL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) { - duk_hstring *res = duk_heap_string_intern(thr->heap, str, blen); - if (!res) { + res = duk_heap_strtable_intern(thr->heap, str, blen); + if (DUK_UNLIKELY(res == NULL)) { DUK_ERROR_ALLOC_FAILED(thr); } return res; } -#if 0 /*unused*/ -DUK_INTERNAL duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val) { - char buf[DUK_STRTAB_U32_MAX_STRLEN+1]; - DUK_SNPRINTF(buf, sizeof(buf), "%lu", (unsigned long) val); - buf[sizeof(buf) - 1] = (char) 0; - DUK_ASSERT(DUK_STRLEN(buf) <= DUK_UINT32_MAX); /* formatted result limited */ - return duk_heap_string_lookup(heap, (const duk_uint8_t *) buf, (duk_uint32_t) DUK_STRLEN(buf)); -} -#endif +DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32_checked(duk_hthread *thr, duk_uint32_t val) { + duk_hstring *res; -DUK_INTERNAL duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val) { - char buf[DUK_STRTAB_U32_MAX_STRLEN+1]; - DUK_SNPRINTF(buf, sizeof(buf), "%lu", (unsigned long) val); - buf[sizeof(buf) - 1] = (char) 0; - DUK_ASSERT(DUK_STRLEN(buf) <= DUK_UINT32_MAX); /* formatted result limited */ - return duk_heap_string_intern(heap, (const duk_uint8_t *) buf, (duk_uint32_t) DUK_STRLEN(buf)); -} + DUK_ASSERT(thr != NULL); + DUK_ASSERT(thr->heap != NULL); -DUK_INTERNAL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val) { - duk_hstring *res = duk_heap_string_intern_u32(thr->heap, val); - if (!res) { + res = duk_heap_strtable_intern_u32(thr->heap, val); + if (DUK_UNLIKELY(res == NULL)) { DUK_ERROR_ALLOC_FAILED(thr); } return res; } -/* find and remove string from stringtable; caller must free the string itself */ +/* + * Remove (unlink) a string from the string table. + * + * Just unlinks the duk_hstring, leaving link pointers as garbage. + * Caller must free the string itself. + */ + #if defined(DUK_USE_REFERENCE_COUNTING) -DUK_INTERNAL void duk_heap_string_remove(duk_heap *heap, duk_hstring *h) { - DUK_DDD(DUK_DDDPRINT("remove string from stringtable: %!O", (duk_heaphdr *) h)); +/* Unlink without a 'prev' pointer. */ +DUK_INTERNAL void duk_heap_strtable_unlink(duk_heap *heap, duk_hstring *h) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *slot; +#else + duk_hstring **slot; +#endif + duk_hstring *other; + duk_hstring *prev; + + DUK_DDD(DUK_DDDPRINT("remove: heap=%p, h=%p, blen=%lu, strhash=%lx", + (void *) heap, (void *) h, + (unsigned long) (h != NULL ? DUK_HSTRING_GET_BYTELEN(h) : 0), + (unsigned long) (h != NULL ? DUK_HSTRING_GET_HASH(h) : 0))); -#if defined(DUK_USE_STRTAB_CHAIN) - duk__remove_matching_hstring_chain(heap, h); -#elif defined(DUK_USE_STRTAB_PROBE) - duk__remove_matching_hstring_probe(heap, -#if defined(DUK_USE_HEAPPTR16) - heap->strtable16, -#else - heap->strtable, + DUK_ASSERT(heap != NULL); + DUK_ASSERT(h != NULL); + +#if defined(DUK__STRTAB_RESIZE_CHECK) + DUK_ASSERT(heap->st_count > 0); + heap->st_count--; #endif - heap->st_size, - h); + +#if defined(DUK_USE_STRTAB_PTRCOMP) + slot = heap->strtable16 + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); #else -#error internal error, invalid strtab options + slot = heap->strtable + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); #endif + other = DUK__HEAPPTR_DEC16(heap, *slot); + DUK_ASSERT(other != NULL); /* At least argument string is in the chain. */ + + prev = NULL; + while (other != h) { + prev = other; + other = other->hdr.h_next; + DUK_ASSERT(other != NULL); /* We'll eventually find 'h'. */ + } + if (prev != NULL) { + /* Middle of list. */ + prev->hdr.h_next = h->hdr.h_next; + } else { + /* Head of list. */ + *slot = DUK__HEAPPTR_ENC16(heap, h->hdr.h_next); + } + + /* There's no resize check on a string free. The next string + * intern will do one. + */ } +#endif /* DUK_USE_REFERENCE_COUNTING */ + +/* Unlink with a 'prev' pointer. */ +DUK_INTERNAL void duk_heap_strtable_unlink_prev(duk_heap *heap, duk_hstring *h, duk_hstring *prev) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *slot; +#else + duk_hstring **slot; #endif -#if defined(DUK_USE_MS_STRINGTABLE_RESIZE) -DUK_INTERNAL void duk_heap_force_strtab_resize(duk_heap *heap) { - duk_small_uint_t prev_mark_and_sweep_base_flags; - /* Force a resize so that DELETED entries are eliminated. - * Another option would be duk__recheck_strtab_size_probe(); - * but since that happens on every intern anyway, this whole - * check can now be disabled. - */ + DUK_DDD(DUK_DDDPRINT("remove: heap=%p, prev=%p, h=%p, blen=%lu, strhash=%lx", + (void *) heap, (void *) prev, (void *) h, + (unsigned long) (h != NULL ? DUK_HSTRING_GET_BYTELEN(h) : 0), + (unsigned long) (h != NULL ? DUK_HSTRING_GET_HASH(h) : 0))); - DUK_ASSERT((heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE) == 0); - prev_mark_and_sweep_base_flags = heap->mark_and_sweep_base_flags; - DUK__PREVENT_MS_SIDE_EFFECTS(heap); + DUK_ASSERT(heap != NULL); + DUK_ASSERT(h != NULL); + DUK_ASSERT(prev == NULL || prev->hdr.h_next == h); -#if defined(DUK_USE_STRTAB_CHAIN) - DUK_UNREF(heap); -#elif defined(DUK_USE_STRTAB_PROBE) - (void) duk__resize_strtab_probe(heap); +#if defined(DUK__STRTAB_RESIZE_CHECK) + DUK_ASSERT(heap->st_count > 0); + heap->st_count--; #endif - heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; -} + if (prev != NULL) { + /* Middle of list. */ + prev->hdr.h_next = h->hdr.h_next; + } else { + /* Head of list. */ +#if defined(DUK_USE_STRTAB_PTRCOMP) + slot = heap->strtable16 + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); +#else + slot = heap->strtable + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); #endif + DUK_ASSERT(DUK__HEAPPTR_DEC16(heap, *slot) == h); + *slot = DUK__HEAPPTR_ENC16(heap, h->hdr.h_next); + } +} -#if defined(DUK_USE_STRTAB_CHAIN) -DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap) { - /* Free strings in the stringtable and any allocations needed - * by the stringtable itself. +/* + * Force string table resize check in mark-and-sweep. + */ + +DUK_INTERNAL void duk_heap_strtable_force_resize(duk_heap *heap) { + /* Does only one grow/shrink step if needed. The heap->st_resizing + * flag protects against recursive resizing. */ - duk_uint_fast32_t i, j; - duk_strtab_entry *e; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t *lst; - duk_uint16_t null16 = heap->heapptr_null16; -#else - duk_hstring **lst; -#endif - duk_hstring *h; - for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { - e = heap->strtable + i; - if (e->listlen > 0) { -#if defined(DUK_USE_HEAPPTR16) - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); -#else - lst = e->u.strlist; -#endif - DUK_ASSERT(lst != NULL); + DUK_ASSERT(heap != NULL); + DUK_UNREF(heap); - for (j = 0; j < e->listlen; j++) { -#if defined(DUK_USE_HEAPPTR16) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[j]); - lst[j] = null16; -#else - h = lst[j]; - lst[j] = NULL; -#endif - /* strings may have inner refs (extdata) in some cases */ - if (h != NULL) { - duk_free_hstring(heap, h); - } - } -#if defined(DUK_USE_HEAPPTR16) - e->u.strlist16 = null16; +#if defined(DUK__STRTAB_RESIZE_CHECK) +#if defined(DUK_USE_STRTAB_PTRCOMP) + if (heap->strtable16 != NULL) { #else - e->u.strlist = NULL; + if (heap->strtable != NULL) { #endif - DUK_FREE(heap, lst); - } else { -#if defined(DUK_USE_HEAPPTR16) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16); - e->u.str16 = null16; -#else - h = e->u.str; - e->u.str = NULL; -#endif - if (h != NULL) { - duk_free_hstring(heap, h); - } - } - e->listlen = 0; + duk__strtable_resize_check(heap); } +#endif } -#endif /* DUK_USE_STRTAB_CHAIN */ -#if defined(DUK_USE_STRTAB_PROBE) -DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap) { - duk_uint_fast32_t i; - duk_hstring *h; +/* + * Free strings in the string table and the string table itself. + */ -#if defined(DUK_USE_HEAPPTR16) - if (heap->strtable16) { +DUK_INTERNAL void duk_heap_strtable_free(duk_heap *heap) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *strtable; + duk_uint16_t *st; #else - if (heap->strtable) { + duk_hstring **strtable; + duk_hstring **st; #endif - for (i = 0; i < (duk_uint_fast32_t) heap->st_size; i++) { -#if defined(DUK_USE_HEAPPTR16) - h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); -#else - h = heap->strtable[i]; + duk_hstring *h; + + DUK_ASSERT(heap != NULL); + +#if defined(DUK_USE_ASSERTIONS) + duk__strtable_assert_checks(heap); #endif - if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) { - continue; - } - DUK_ASSERT(h != NULL); - /* strings may have inner refs (extdata) in some cases */ + /* Strtable can be NULL if heap init fails. However, in that case + * heap->st_size is 0, so strtable == strtable_end and we skip the + * loop without a special check. + */ + strtable = DUK__GET_STRTABLE(heap); + st = strtable + heap->st_size; + DUK_ASSERT(strtable != NULL || heap->st_size == 0); + + while (strtable != st) { + --st; + h = DUK__HEAPPTR_DEC16(heap, *st); + while (h) { + duk_hstring *h_next; + h_next = h->hdr.h_next; + + /* Strings may have inner refs (extdata) in some cases. */ duk_free_hstring(heap, h); -#if 0 /* not strictly necessary */ - heap->strtable[i] = NULL; -#endif + + h = h_next; } -#if defined(DUK_USE_HEAPPTR16) - DUK_FREE(heap, heap->strtable16); -#else - DUK_FREE(heap, heap->strtable); -#endif -#if 0 /* not strictly necessary */ - heap->strtable = NULL; -#endif } + + DUK_FREE(heap, strtable); } -#endif /* DUK_USE_STRTAB_PROBE */ diff -Nru duktape-2.0.0/src-input/duk_henv.h duktape-2.1.1/src-input/duk_henv.h --- duktape-2.0.0/src-input/duk_henv.h 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/src-input/duk_henv.h 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,48 @@ +/* + * Environment object representation. + */ + +#if !defined(DUK_HENV_H_INCLUDED) +#define DUK_HENV_H_INCLUDED + +#define DUK_ASSERT_HDECENV_VALID(h) do { \ + DUK_ASSERT((h) != NULL); \ + DUK_ASSERT(DUK_HOBJECT_IS_DECENV((duk_hobject *) (h))); \ + DUK_ASSERT((h)->thread == NULL || (h)->varmap != NULL); \ + } while (0) + +#define DUK_ASSERT_HOBJENV_VALID(h) do { \ + 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); \ + } while (0) + +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; +}; + +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 */ diff -Nru duktape-2.0.0/src-input/duk_hobject_alloc.c duktape-2.1.1/src-input/duk_hobject_alloc.c --- duktape-2.0.0/src-input/duk_hobject_alloc.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_hobject_alloc.c 2017-07-28 22:05:08.000000000 +0000 @@ -6,19 +6,29 @@ * 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 "duk_internal.h" -DUK_LOCAL void duk__init_object_parts(duk_heap *heap, duk_hobject *obj, duk_uint_t hobject_flags) { +/* + * 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 - - /* XXX: macro? sets both heaphdr and object flags */ - obj->hdr.h_flags = hobject_flags; - DUK_HEAPHDR_SET_TYPE(&obj->hdr, DUK_HTYPE_OBJECT); /* also goes into flags */ - #if defined(DUK_USE_HEAPPTR16) - /* Zero encoded pointer is required to match NULL */ + /* 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); @@ -27,14 +37,22 @@ DUK_ASSERT_HEAPHDR_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. + /* 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. * @@ -46,7 +64,7 @@ * count before invoking any operation that might require memory allocation. */ -DUK_INTERNAL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags) { +DUK_INTERNAL duk_hobject *duk_hobject_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags) { duk_hobject *res; DUK_ASSERT(heap != NULL); @@ -54,30 +72,30 @@ /* 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_THREAD) == 0); - res = (duk_hobject *) DUK_ALLOC(heap, sizeof(duk_hobject)); - if (!res) { + res = (duk_hobject *) DUK_ALLOC_ZEROED(heap, sizeof(duk_hobject)); + if (DUK_UNLIKELY(res == NULL)) { return NULL; } - DUK_MEMZERO(res, sizeof(duk_hobject)); + DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(res)); - duk__init_object_parts(heap, res, hobject_flags); + duk__init_object_parts(heap, hobject_flags, res); + DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(res)); return res; } -DUK_INTERNAL duk_hcompfunc *duk_hcompfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags) { - duk_hcompfunc *res; +DUK_INTERNAL duk_hobject *duk_hobject_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { + duk_hobject *res; - res = (duk_hcompfunc *) DUK_ALLOC(heap, sizeof(duk_hcompfunc)); - if (!res) { - return NULL; - } - DUK_MEMZERO(res, sizeof(duk_hcompfunc)); + res = (duk_hobject *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hobject)); + return res; +} - duk__init_object_parts(heap, &res->obj, hobject_flags); +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. */ @@ -93,17 +111,10 @@ return res; } -DUK_INTERNAL duk_hnatfunc *duk_hnatfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags) { +DUK_INTERNAL duk_hnatfunc *duk_hnatfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { duk_hnatfunc *res; - res = (duk_hnatfunc *) DUK_ALLOC(heap, sizeof(duk_hnatfunc)); - if (!res) { - return NULL; - } - DUK_MEMZERO(res, sizeof(duk_hnatfunc)); - - duk__init_object_parts(heap, &res->obj, hobject_flags); - + res = (duk_hnatfunc *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hnatfunc)); #if defined(DUK_USE_EXPLICIT_NULL_INIT) res->func = NULL; #endif @@ -112,17 +123,10 @@ } #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_hbufobj *duk_hbufobj_alloc(duk_heap *heap, duk_uint_t hobject_flags) { +DUK_INTERNAL duk_hbufobj *duk_hbufobj_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { duk_hbufobj *res; - res = (duk_hbufobj *) DUK_ALLOC(heap, sizeof(duk_hbufobj)); - if (!res) { - return NULL; - } - DUK_MEMZERO(res, sizeof(duk_hbufobj)); - - duk__init_object_parts(heap, &res->obj, hobject_flags); - + 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; @@ -133,24 +137,22 @@ } #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ -/* - * Allocate a new thread. +/* 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. + * 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(duk_heap *heap, duk_uint_t hobject_flags) { +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 (!res) { + if (DUK_UNLIKELY(res == NULL)) { return NULL; } DUK_MEMZERO(res, sizeof(duk_hthread)); - duk__init_object_parts(heap, &res->obj, hobject_flags); + duk__init_object_parts(heap, hobject_flags, &res->obj); #if defined(DUK_USE_EXPLICIT_NULL_INIT) res->ptr_curr_pc = NULL; @@ -160,6 +162,7 @@ res->valstack_bottom = NULL; res->valstack_top = NULL; res->callstack = NULL; + res->callstack_curr = NULL; res->catchstack = NULL; res->resumer = NULL; res->compile_ctx = NULL, @@ -169,7 +172,7 @@ res->strs = NULL; #endif { - int i; + duk_small_uint_t i; for (i = 0; i < DUK_NUM_BUILTINS; i++) { res->builtins[i] = NULL; } @@ -186,32 +189,51 @@ return res; } -#if 0 /* unused now */ -DUK_INTERNAL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags) { - duk_hobject *res = duk_hobject_alloc(thr->heap, hobject_flags); - if (!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); } 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 -/* - * Allocate a new array. - */ + DUK_ASSERT(res->thread == NULL); + DUK_ASSERT(res->varmap == NULL); + DUK_ASSERT(res->regbase == 0); -DUK_INTERNAL duk_harray *duk_harray_alloc(duk_heap *heap, duk_uint_t hobject_flags) { - duk_harray *res; + return res; +} - res = (duk_harray *) DUK_ALLOC(heap, sizeof(duk_harray)); - if (!res) { - return NULL; - } - DUK_MEMZERO(res, sizeof(duk_harray)); +DUK_INTERNAL duk_hobjenv *duk_hobjenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { + duk_hobjenv *res; - duk__init_object_parts(heap, &res->obj, hobject_flags); + 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->length == 0); + DUK_ASSERT(res->target == NULL); return res; } diff -Nru duktape-2.0.0/src-input/duk_hobject_enum.c duktape-2.1.1/src-input/duk_hobject_enum.c --- duktape-2.0.0/src-input/duk_hobject_enum.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_hobject_enum.c 2017-07-28 22:05:08.000000000 +0000 @@ -242,6 +242,9 @@ */ DUK_LOCAL void duk__add_enum_key(duk_context *ctx, duk_hstring *k) { + /* 'k' may be unreachable on entry so must push without any + * potential for GC. + */ duk_push_hstring(ctx, k); duk_push_true(ctx); duk_put_prop(ctx, -3); @@ -442,7 +445,7 @@ /* This is a bit fragile: the string is not * reachable until it is pushed by the helper. */ - k = duk_heap_string_intern_u32_checked(thr, i); + k = duk_heap_strtable_intern_u32_checked(thr, i); DUK_ASSERT(k); duk__add_enum_key(ctx, k); @@ -476,7 +479,7 @@ if (DUK_TVAL_IS_UNUSED(tv)) { continue; } - k = duk_heap_string_intern_u32_checked(thr, i); /* Fragile reachability. */ + k = duk_heap_strtable_intern_u32_checked(thr, i); /* Fragile reachability. */ DUK_ASSERT(k); duk__add_enum_key(ctx, k); @@ -506,7 +509,7 @@ !DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(thr->heap, curr, i)) { continue; } - if (DUK_HSTRING_HAS_SYMBOL(k)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(k))) { if (!(enum_flags & DUK_ENUM_INCLUDE_HIDDEN) && DUK_HSTRING_HAS_HIDDEN(k)) { continue; diff -Nru duktape-2.0.0/src-input/duk_hobject_finalizer.c duktape-2.1.1/src-input/duk_hobject_finalizer.c --- duktape-2.0.0/src-input/duk_hobject_finalizer.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_hobject_finalizer.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,113 +0,0 @@ -/* - * Run an duk_hobject finalizer. Used for both reference counting - * and mark-and-sweep algorithms. Must never throw an error. - * - * There is no return value. Any return value or error thrown by - * the finalizer is ignored (although errors are debug logged). - * - * Notes: - * - * - The thread used for calling the finalizer is the same as the - * 'thr' argument. This may need to change later. - * - * - 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). - */ - -#include "duk_internal.h" - -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_LOCAL duk_ret_t duk__finalize_helper(duk_context *ctx, void *udata) { - duk_hthread *thr; - - DUK_ASSERT(ctx != NULL); - thr = (duk_hthread *) ctx; - DUK_UNREF(udata); - - DUK_DDD(DUK_DDDPRINT("protected finalization helper running")); - - /* [... obj] */ - - /* 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(ctx, -1, DUK_STRIDX_INT_FINALIZER); /* -> [... obj finalizer] */ - if (!duk_is_callable(ctx, -1)) { - DUK_DDD(DUK_DDDPRINT("-> no finalizer or finalizer not callable")); - return 0; - } - duk_dup_m2(ctx); - duk_push_boolean(ctx, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap)); - DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling finalizer")); - duk_call(ctx, 2); /* [ ... obj finalizer obj heapDestruct ] -> [ ... obj retval ] */ - DUK_DDD(DUK_DDDPRINT("finalizer finished 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_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj) { - duk_context *ctx = (duk_context *) thr; - duk_ret_t rc; -#if defined(DUK_USE_ASSERTIONS) - duk_idx_t entry_top; -#endif - - DUK_DDD(DUK_DDDPRINT("running object finalizer for object: %p", (void *) obj)); - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(ctx != NULL); - DUK_ASSERT(obj != NULL); - DUK_ASSERT_VALSTACK_SPACE(thr, 1); - -#if defined(DUK_USE_ASSERTIONS) - entry_top = duk_get_top(ctx); -#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). - */ - - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); - if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj)) { - DUK_D(DUK_DPRINT("object already finalized, avoid running finalizer twice: %!O", obj)); - return; - } - DUK_HEAPHDR_SET_FINALIZED((duk_heaphdr *) obj); /* ensure never re-entered until rescue cycle complete */ - if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj)) { - /* This shouldn't happen; call sites should avoid looking up - * _Finalizer "through" a Proxy, but ignore if we come here - * with a Proxy to avoid finalizer re-entry. - */ - DUK_D(DUK_DPRINT("object is a proxy, skip finalizer call")); - return; - } - - /* XXX: use a NULL error handler for the finalizer call? */ - - DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling wrapped finalize helper")); - duk_push_hobject(ctx, obj); /* this also increases refcount by one */ - rc = duk_safe_call(ctx, duk__finalize_helper, NULL /*udata*/, 0 /*nargs*/, 1 /*nrets*/); /* -> [... obj retval/error] */ - DUK_ASSERT_TOP(ctx, 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(ctx, -1))); - } - duk_pop_2(ctx); /* -> [...] */ - - DUK_ASSERT_TOP(ctx, entry_top); -} -#endif /* DUK_USE_FINALIZER_SUPPORT */ diff -Nru duktape-2.0.0/src-input/duk_hobject.h duktape-2.1.1/src-input/duk_hobject.h --- duktape-2.0.0/src-input/duk_hobject.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_hobject.h 2017-07-28 22:05:08.000000000 +0000 @@ -32,8 +32,8 @@ #if !defined(DUK_HOBJECT_H_INCLUDED) #define DUK_HOBJECT_H_INCLUDED -/* Object flag. There are currently 25 flag bits available. Make sure - * this stays in sync with debugger object inspection code. +/* 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 @@ -45,14 +45,14 @@ #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_THREAD DUK_HEAPHDR_USER_FLAG(7) /* object is a thread (duk_hthread) */ +#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_ENVRECCLOSED DUK_HEAPHDR_USER_FLAG(14) /* envrec: (declarative) record is closed */ +#define DUK_HOBJECT_FLAG_HAVE_FINALIZER DUK_HEAPHDR_USER_FLAG(14) /* object has a callable 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) */ @@ -132,7 +132,6 @@ #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_THREAD (1UL << DUK_HOBJECT_CLASS_THREAD) #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) @@ -166,7 +165,7 @@ #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) #define DUK_HOBJECT_IS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) -#define DUK_HOBJECT_IS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) +#define DUK_HOBJECT_IS_THREAD(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_THREAD) #define DUK_HOBJECT_IS_NONBOUND_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \ DUK_HOBJECT_FLAG_COMPFUNC | \ @@ -204,14 +203,14 @@ #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) #define DUK_HOBJECT_HAS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) -#define DUK_HOBJECT_HAS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) +#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_ENVRECCLOSED(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED) +#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) @@ -224,14 +223,14 @@ #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) #define DUK_HOBJECT_SET_BUFOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) -#define DUK_HOBJECT_SET_THREAD(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) +#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_ENVRECCLOSED(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED) +#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) @@ -244,20 +243,28 @@ #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) #define DUK_HOBJECT_CLEAR_BUFOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) -#define DUK_HOBJECT_CLEAR_THREAD(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) +#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_ENVRECCLOSED(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED) +#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) #define DUK_HOBJECT_CLEAR_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC) #define DUK_HOBJECT_CLEAR_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ) +/* Object can/cannot use FASTREFS, i.e. has no strong reference fields beyond + * duk_hobject base header. + */ +#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))) +#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. */ @@ -639,6 +646,16 @@ #define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr,h,p) duk_hobject_set_prototype_updref((thr), (h), (p)) /* + * 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 */ @@ -651,22 +668,9 @@ #if defined(DUK_USE_OBJSIZES16) #define DUK_HOBJECT_MAX_PROPERTIES 0x0000ffffUL #else -#define DUK_HOBJECT_MAX_PROPERTIES 0x7fffffffUL /* 2**31-1 ~= 2G properties */ +#define DUK_HOBJECT_MAX_PROPERTIES 0x3fffffffUL /* 2**30-1 ~= 1G properties */ #endif -/* higher value conserves memory; also note that linear scan is cache friendly */ -#define DUK_HOBJECT_E_USE_HASH_LIMIT 32 - -/* hash size relative to entries size: for value X, approx. hash_prime(e_size + e_size / X) */ -#define DUK_HOBJECT_H_SIZE_DIVISOR 4 /* hash size approx. 1.25 times entries size */ - -/* if new_size < L * old_size, resize without abandon check; L = 3-bit fixed point, e.g. 9 -> 9/8 = 112.5% */ -#define DUK_HOBJECT_A_FAST_RESIZE_LIMIT 9 /* 112.5%, i.e. new size less than 12.5% higher -> fast resize */ - -/* if density < L, abandon array part, L = 3-bit fixed point, e.g. 2 -> 2/8 = 25% */ -/* limit is quite low: one array entry is 8 bytes, one normal entry is 4+1+8+4 = 17 bytes (with hash entry) */ -#define DUK_HOBJECT_A_ABANDON_LIMIT 2 /* 25%, i.e. less than 25% used -> abandon */ - /* 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 @@ -678,18 +682,6 @@ #error invalid DUK_USE_ALIGN_BY #endif -/* controls for minimum entry part growth */ -#define DUK_HOBJECT_E_MIN_GROW_ADD 16 -#define DUK_HOBJECT_E_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */ - -/* controls for minimum array part growth */ -#define DUK_HOBJECT_A_MIN_GROW_ADD 16 -#define DUK_HOBJECT_A_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */ - -/* probe sequence */ -#define DUK_HOBJECT_HASH_INITIAL(hash,h_size) ((hash) % (h_size)) -#define DUK_HOBJECT_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash)) - /* * PC-to-line constants */ @@ -719,7 +711,7 @@ struct duk_propdesc { /* read-only values 'lifted' for ease of use */ - duk_small_int_t flags; + duk_small_uint_t flags; duk_hobject *get; duk_hobject *set; @@ -843,17 +835,18 @@ */ /* alloc and init */ -DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags); -#if 0 /* unused */ -DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags); -#endif -DUK_INTERNAL_DECL duk_harray *duk_harray_alloc(duk_heap *heap, duk_uint_t hobject_flags); -DUK_INTERNAL_DECL duk_hcompfunc *duk_hcompfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags); -DUK_INTERNAL_DECL duk_hnatfunc *duk_hnatfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags); +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); #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL_DECL duk_hbufobj *duk_hbufobj_alloc(duk_heap *heap, duk_uint_t hobject_flags); +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(duk_heap *heap, duk_uint_t hobject_flags); +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); /* resize */ DUK_INTERNAL_DECL void duk_hobject_realloc_props(duk_hthread *thr, @@ -890,6 +883,11 @@ 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 @@ -936,11 +934,6 @@ /* macros */ DUK_INTERNAL_DECL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p); -/* finalization */ -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_INTERNAL_DECL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj); -#endif - /* 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); diff -Nru duktape-2.0.0/src-input/duk_hobject_pc2line.c duktape-2.1.1/src-input/duk_hobject_pc2line.c --- duktape-2.0.0/src-input/duk_hobject_pc2line.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_hobject_pc2line.c 2017-07-28 22:05:08.000000000 +0000 @@ -150,7 +150,7 @@ 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 error; + goto pc2line_error; } hdr = (duk_uint32_t *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, buf); @@ -159,7 +159,7 @@ /* 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 error; + goto pc2line_error; } curr_line = hdr[1 + hdr_index * 2]; @@ -167,7 +167,7 @@ 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 error; + goto pc2line_error; } /* @@ -218,7 +218,7 @@ DUK_DDD(DUK_DDDPRINT("pc2line lookup result: pc %ld -> line %ld", (long) pc, (long) curr_line)); return curr_line; - error: + pc2line_error: DUK_D(DUK_DPRINT("pc2line conversion failed for pc=%ld", (long) pc)); return 0; } diff -Nru duktape-2.0.0/src-input/duk_hobject_props.c duktape-2.1.1/src-input/duk_hobject_props.c --- duktape-2.0.0/src-input/duk_hobject_props.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_hobject_props.c 2017-07-28 22:05:08.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Hobject property set/get functionality. + * duk_hobject property access functionality. * * This is very central functionality for size, performance, and compliance. * It is also rather intricate; see hobject-algorithms.rst for discussion on @@ -40,10 +40,6 @@ * might be more appropriate. */ -/* - * XXX: duk_uint_fast32_t should probably be used in many places here. - */ - #include "duk_internal.h" /* @@ -52,10 +48,6 @@ #define DUK__NO_ARRAY_INDEX DUK_HSTRING_NO_ARRAY_INDEX -/* hash probe sequence */ -#define DUK__HASH_INITIAL(hash,h_size) DUK_HOBJECT_HASH_INITIAL((hash),(h_size)) -#define DUK__HASH_PROBE_STEP(hash) DUK_HOBJECT_HASH_PROBE_STEP((hash)) - /* marker values for hash part */ #define DUK__HASH_UNUSED DUK_HOBJECT_HASHIDX_UNUSED #define DUK__HASH_DELETED DUK_HOBJECT_HASHIDX_DELETED @@ -218,14 +210,26 @@ DUK_LOCAL duk_uint32_t duk__get_default_h_size(duk_uint32_t e_size) { DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES); - if (e_size >= DUK_HOBJECT_E_USE_HASH_LIMIT) { + if (e_size >= DUK_USE_HOBJECT_HASH_PROP_LIMIT) { duk_uint32_t res; + duk_uint32_t tmp; - /* result: hash_prime(floor(1.2 * e_size)) */ - res = duk_util_get_hash_prime(e_size + e_size / DUK_HOBJECT_H_SIZE_DIVISOR); - - /* if fails, e_size will be zero = not an issue, except performance-wise */ - DUK_ASSERT(res == 0 || res > e_size); + /* Hash size should be 2^N where N is chosen so that 2^N is + * larger than e_size. Extra shifting is used to ensure hash + * is relatively sparse. + */ + tmp = e_size; + res = 2; /* Result will be 2 ** (N + 1). */ + while (tmp >= 0x40) { + tmp >>= 6; + res <<= 6; + } + while (tmp != 0) { + tmp >>= 1; + res <<= 1; + } + DUK_ASSERT((DUK_HOBJECT_MAX_PROPERTIES << 2U) > DUK_HOBJECT_MAX_PROPERTIES); /* Won't wrap, even shifted by 2. */ + DUK_ASSERT(res > e_size); return res; } else { return 0; @@ -239,7 +243,7 @@ DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES); - res = (e_size + DUK_HOBJECT_E_MIN_GROW_ADD) / DUK_HOBJECT_E_MIN_GROW_DIVISOR; + res = (e_size + DUK_USE_HOBJECT_ENTRY_MINGROW_ADD) / DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR; DUK_ASSERT(res >= 1); /* important for callers */ return res; } @@ -250,7 +254,7 @@ DUK_ASSERT((duk_size_t) a_size <= DUK_HOBJECT_MAX_PROPERTIES); - res = (a_size + DUK_HOBJECT_A_MIN_GROW_ADD) / DUK_HOBJECT_A_MIN_GROW_DIVISOR; + res = (a_size + DUK_USE_HOBJECT_ARRAY_MINGROW_ADD) / DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR; DUK_ASSERT(res >= 1); /* important for callers */ return res; } @@ -325,7 +329,7 @@ * of the check, but may confuse debugging. */ - return (a_used < DUK_HOBJECT_A_ABANDON_LIMIT * (a_size >> 3)); + return (a_used < DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT * (a_size >> 3)); } /* Fast check for extending array: check whether or not a slow density check is required. */ @@ -351,7 +355,7 @@ * arr_idx > limit'' * ((old_size + 7) / 8) */ - return (arr_idx > DUK_HOBJECT_A_FAST_RESIZE_LIMIT * ((old_size + 7) >> 3)); + return (arr_idx > DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT * ((old_size + 7) >> 3)); } /* @@ -503,29 +507,26 @@ /* * Reallocate property allocation, moving properties to the new allocation. * - * Includes key compaction, rehashing, and can also optionally abandoning + * Includes key compaction, rehashing, and can also optionally abandon * the array part, 'migrating' array entries into the beginning of the - * new entry part. Arguments are not validated here, so e.g. new_h_size - * MUST be a valid prime. + * new entry part. * * There is no support for in-place reallocation or just compacting keys * without resizing the property allocation. This is intentional to keep - * code size minimal. + * code size minimal, but would be useful future work. * * The implementation is relatively straightforward, except for the array * abandonment process. Array abandonment requires that new string keys * are interned, which may trigger GC. All keys interned so far must be - * reachable for GC at all times; valstack is used for that now. + * reachable for GC at all times and correctly refcounted for; valstack is + * used for that now. * * Also, a GC triggered during this reallocation process must not interfere - * with the object being resized. This is currently controlled by using - * heap->mark_and_sweep_base_flags to indicate that no finalizers will be - * executed (as they can affect ANY object) and no objects are compacted - * (it would suffice to protect this particular object only, though). - * - * Note: a non-checked variant would be nice but is a bit tricky to - * implement for the array abandonment process. It's easy for - * everything else. + * with the object being resized. This is currently controlled by preventing + * finalizers (as they may affect ANY object) and object compaction in + * mark-and-sweep. It would suffice to protect only this particular object + * from compaction, however. DECREF refzero cascades are side effect free + * and OK. * * Note: because we need to potentially resize the valstack (as part * of abandoning the array part), any tval pointers to the valstack @@ -539,7 +540,7 @@ duk_uint32_t new_h_size, duk_bool_t abandon_array) { duk_context *ctx = (duk_context *) thr; - duk_small_uint_t prev_mark_and_sweep_base_flags; + duk_small_uint_t prev_ms_base_flags; duk_uint32_t new_alloc_size; duk_uint32_t new_e_size_adjusted; duk_uint8_t *new_p; @@ -550,6 +551,10 @@ duk_uint32_t *new_h; duk_uint32_t new_e_next; duk_uint_fast32_t i; + duk_size_t array_copy_size; +#if defined(DUK_USE_ASSERTIONS) + duk_bool_t prev_error_not_allowed; +#endif DUK_ASSERT(thr != NULL); DUK_ASSERT(ctx != NULL); @@ -619,9 +624,8 @@ /* * Property count check. This is the only point where we ensure that * we don't get more (allocated) property space that we can handle. - * There aren't hard limits as such, but some algorithms fail (e.g. - * finding next higher prime, selecting hash part size) if we get too - * close to the 4G property limit. + * There aren't hard limits as such, but some algorithms may fail + * if we get too close to the 4G property limit. * * Since this works based on allocation size (not actually used size), * the limit is a bit approximate but good enough in practice. @@ -634,43 +638,46 @@ /* * Compute new alloc size and alloc new area. * - * The new area is allocated as a dynamic buffer and placed into the - * valstack for reachability. The actual buffer is then detached at - * the end. - * - * Note: heap_mark_and_sweep_base_flags are altered here to ensure - * no-one touches this object while we're resizing and rehashing it. - * The flags must be reset on every exit path after it. Finalizers - * and compaction is prevented currently for all objects while it - * would be enough to restrict it only for the current object. + * The new area is not tracked in the heap at all, so it's critical + * we get to free/keep it in a controlled manner. */ - prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags; - thr->heap->mark_and_sweep_base_flags |= - DUK_MS_FLAG_NO_FINALIZERS | /* avoid attempts to add/remove object keys */ - DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid attempt to compact the current object */ +#if defined(DUK_USE_ASSERTIONS) + /* Whole path must be error throw free, but we may be called from + * within error handling so can't assert for error_not_allowed == 0. + */ + prev_error_not_allowed = thr->heap->error_not_allowed; + thr->heap->error_not_allowed = 1; +#endif + prev_ms_base_flags = thr->heap->ms_base_flags; + thr->heap->ms_base_flags |= + DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* Avoid attempt to compact the current object (all objects really). */ + thr->heap->pf_prevent_count++; /* Avoid finalizers. */ + DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */ new_alloc_size = DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size); DUK_DDD(DUK_DDDPRINT("new hobject allocation size is %ld", (long) new_alloc_size)); if (new_alloc_size == 0) { - /* for zero size, don't push anything on valstack */ DUK_ASSERT(new_e_size_adjusted == 0); DUK_ASSERT(new_a_size == 0); DUK_ASSERT(new_h_size == 0); new_p = NULL; } else { - /* This may trigger mark-and-sweep with arbitrary side effects, - * including an attempted resize of the object we're resizing, - * executing a finalizer which may add or remove properties of - * the object we're resizing etc. - */ - - /* Note: buffer is dynamic so that we can 'steal' the actual - * allocation later. + /* Alloc may trigger mark-and-sweep but no compaction, and + * cannot throw. */ - - new_p = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, new_alloc_size); /* errors out if out of memory */ - DUK_ASSERT(new_p != NULL); /* since new_alloc_size > 0 */ +#if 0 /* XXX: inject test */ + if (1) { + goto alloc_failed; + } +#endif + new_p = (duk_uint8_t *) DUK_ALLOC(thr->heap, new_alloc_size); + if (new_p == NULL) { + /* NULL always indicates alloc failure because + * new_alloc_size > 0. + */ + goto alloc_failed; + } } /* Set up pointers to the new property area: this is hidden behind a macro @@ -691,27 +698,27 @@ (void *) new_a, (void *) new_h)); /* - * Migrate array to start of entries if requested. + * Migrate array part to start of entries if requested. * * Note: from an enumeration perspective the order of entry keys matters. * Array keys should appear wherever they appeared before the array abandon - * operation. + * operation. (This no longer matters much because keys are ES2015 sorted.) */ if (abandon_array) { - /* - * Note: assuming new_a_size == 0, and that entry part contains - * no conflicting keys, refcounts do not need to be adjusted for - * the values, as they remain exactly the same. + /* Assuming new_a_size == 0, and that entry part contains + * no conflicting keys, refcounts do not need to be adjusted for + * the values, as they remain exactly the same. * - * The keys, however, need to be interned, incref'd, and be - * reachable for GC. Any intern attempt may trigger a GC and - * claim any non-reachable strings, so every key must be reachable - * at all times. + * The keys, however, need to be interned, incref'd, and be + * reachable for GC. Any intern attempt may trigger a GC and + * claim any non-reachable strings, so every key must be reachable + * at all times. Refcounts must be correct to satisfy refcount + * assertions. * - * A longjmp must not occur here, as the new_p allocation would - * be freed without these keys being decref'd, hence the messy - * decref handling if intern fails. + * A longjmp must not occur here, as the new_p allocation would + * leak. Refcounts would come out correctly as the interned + * strings are valstack tracked. */ DUK_ASSERT(new_a_size == 0); @@ -740,20 +747,29 @@ * must be careful. */ - /* never shrinks; auto-adds DUK_VALSTACK_INTERNAL_EXTRA, which is generous */ +#if 0 /* XXX: inject test */ + if (1) { + goto abandon_error; + } +#endif + /* Never shrinks; auto-adds DUK_VALSTACK_INTERNAL_EXTRA, which + * is generous. + */ if (!duk_check_stack(ctx, 1)) { goto abandon_error; } DUK_ASSERT_VALSTACK_SPACE(thr, 1); - key = duk_heap_string_intern_u32(thr->heap, i); - if (!key) { + key = duk_heap_strtable_intern_u32(thr->heap, i); + if (key == NULL) { goto abandon_error; } duk_push_hstring(ctx, key); /* keep key reachable for GC etc; guaranteed not to fail */ - /* key is now reachable in the valstack */ + /* Key is now reachable in the valstack, don't INCREF + * the new allocation yet (we'll steal the refcounts + * from the value stack once all keys are done). + */ - DUK_HSTRING_INCREF(thr, key); /* second incref for the entry reference */ new_e_k[new_e_next] = key; tv2 = &new_e_pv[new_e_next].v; /* array entries are all plain values */ DUK_TVAL_SET_TVAL(tv2, tv1); @@ -767,8 +783,9 @@ */ } + /* Steal refcounts from value stack. */ DUK_DDD(DUK_DDDPRINT("abandon array: pop %ld key temps from valstack", (long) new_e_next)); - duk_pop_n(ctx, new_e_next); + duk_pop_n_nodecref_unsafe(ctx, new_e_next); } /* @@ -781,7 +798,7 @@ DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL); key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i); - if (!key) { + if (key == NULL) { continue; } @@ -796,53 +813,46 @@ /* the entries [new_e_next, new_e_size_adjusted[ are left uninitialized on purpose (ok, not gc reachable) */ /* - * Copy array elements to new array part. + * Copy array elements to new array part. If the new array part is + * larger, initialize the unused entries as UNUSED because they are + * GC reachable. */ - if (new_a_size > DUK_HOBJECT_GET_ASIZE(obj)) { - /* copy existing entries as is */ - DUK_ASSERT(new_p != NULL && new_a != NULL); - if (DUK_HOBJECT_GET_ASIZE(obj) > 0) { - /* Avoid zero copy with an invalid pointer. If obj->p is NULL, - * the 'new_a' pointer will be invalid which is not allowed even - * when copy size is zero. - */ - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL); - DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0); - DUK_MEMCPY((void *) new_a, (void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), sizeof(duk_tval) * DUK_HOBJECT_GET_ASIZE(obj)); - } - - /* fill new entries with -unused- (required, gc reachable) */ - for (i = DUK_HOBJECT_GET_ASIZE(obj); i < new_a_size; i++) { - duk_tval *tv = &new_a[i]; - DUK_TVAL_SET_UNUSED(tv); - } - } else { #if defined(DUK_USE_ASSERTIONS) - /* caller must have decref'd values above new_a_size (if that is necessary) */ - if (!abandon_array) { - for (i = new_a_size; i < DUK_HOBJECT_GET_ASIZE(obj); i++) { - duk_tval *tv; - tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i); - - /* current assertion is quite strong: decref's and set to unused */ - DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv)); - } + /* Caller must have decref'd values above new_a_size (if that is necessary). */ + if (!abandon_array) { + for (i = new_a_size; i < DUK_HOBJECT_GET_ASIZE(obj); i++) { + duk_tval *tv; + tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i); + DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv)); } + } #endif - if (new_a_size > 0) { - /* Avoid zero copy with an invalid pointer. If obj->p is NULL, - * the 'new_a' pointer will be invalid which is not allowed even - * when copy size is zero. - */ - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL); - DUK_ASSERT(new_a_size > 0); - DUK_MEMCPY((void *) new_a, (void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), sizeof(duk_tval) * new_a_size); - } + if (new_a_size > DUK_HOBJECT_GET_ASIZE(obj)) { + array_copy_size = sizeof(duk_tval) * DUK_HOBJECT_GET_ASIZE(obj); + } else { + array_copy_size = sizeof(duk_tval) * new_a_size; + } + if (array_copy_size > 0) { + /* Avoid zero copy with an invalid pointer. If obj->p is NULL, + * the 'new_a' pointer will be invalid which is not allowed even + * when copy size is zero. + */ + DUK_ASSERT(new_a != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0); + DUK_MEMCPY((void *) new_a, + (const void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), + array_copy_size); + } + for (i = DUK_HOBJECT_GET_ASIZE(obj); i < new_a_size; i++) { + duk_tval *tv = &new_a[i]; + DUK_TVAL_SET_UNUSED(tv); } /* - * Rebuild the hash part always from scratch (guaranteed to finish). + * Rebuild the hash part always from scratch (guaranteed to finish + * as long as caller gave consistent parameters). * * Any resize of hash part requires rehashing. In addition, by rehashing * get rid of any elements marked deleted (DUK__HASH_DELETED) which is critical @@ -850,7 +860,11 @@ */ #if defined(DUK_USE_HOBJECT_HASH_PART) - if (DUK_UNLIKELY(new_h_size > 0)) { + if (new_h_size == 0) { + DUK_DDD(DUK_DDDPRINT("no hash part, no rehash")); + } else { + duk_uint32_t mask; + DUK_ASSERT(new_h != NULL); /* fill new_h with u32 0xff = UNUSED */ @@ -859,13 +873,15 @@ DUK_MEMSET(new_h, 0xff, sizeof(duk_uint32_t) * new_h_size); DUK_ASSERT(new_e_next <= new_h_size); /* equality not actually possible */ + + mask = new_h_size - 1; for (i = 0; i < new_e_next; i++) { duk_hstring *key = new_e_k[i]; duk_uint32_t j, step; DUK_ASSERT(key != NULL); - j = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), new_h_size); - step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key)); + j = DUK_HSTRING_GET_HASH(key) & mask; + step = 1; /* Cache friendly but clustering prone. */ for (;;) { DUK_ASSERT(new_h[j] != DUK__HASH_DELETED); /* should never happen */ @@ -875,14 +891,11 @@ break; } DUK_DDD(DUK_DDDPRINT("rebuild miss %ld, step %ld", (long) j, (long) step)); - j = (j + step) % new_h_size; + j = (j + step) & mask; - /* guaranteed to finish */ - DUK_ASSERT(j != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), new_h_size)); + /* Guaranteed to finish (hash is larger than #props). */ } } - } else { - DUK_DDD(DUK_DDDPRINT("no hash part, no rehash")); } #endif /* DUK_USE_HOBJECT_HASH_PART */ @@ -921,30 +934,20 @@ DUK_HOBJECT_SET_ASIZE(obj, new_a_size); DUK_HOBJECT_SET_HSIZE(obj, new_h_size); - if (new_p) { - /* - * Detach actual buffer from dynamic buffer in valstack, and - * pop it from the stack. - * - * XXX: the buffer object is certainly not reachable at this point, - * so it would be nice to free it forcibly even with only - * mark-and-sweep enabled. Not a big issue though. - */ - (void) duk_steal_buffer(ctx, -1, NULL); - duk_pop(ctx); - } else { - DUK_ASSERT(new_alloc_size == 0); - /* no need to pop, nothing was pushed */ - } - - /* clear array part flag only after switching */ + /* Clear array part flag only after switching. */ if (abandon_array) { DUK_HOBJECT_CLEAR_ARRAY_PART(obj); } DUK_DDD(DUK_DDDPRINT("resize result: %!O", (duk_heaphdr *) obj)); - thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; + DUK_ASSERT(thr->heap->pf_prevent_count > 0); + thr->heap->pf_prevent_count--; + thr->heap->ms_base_flags = prev_ms_base_flags; +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(thr->heap->error_not_allowed == 1); + thr->heap->error_not_allowed = prev_error_not_allowed; +#endif /* * Post resize assertions. @@ -956,21 +959,25 @@ return; /* - * Abandon array failed, need to decref keys already inserted - * into the beginning of new_e_k before unwinding valstack. + * Abandon array failed. We don't need to DECREF anything + * because the references in the new allocation are not + * INCREF'd until abandon is complete. The string interned + * keys are on the value stack and are handled normally by + * unwind. */ abandon_error: - DUK_D(DUK_DPRINT("hobject resize failed during abandon array, decref keys")); - i = new_e_next; - while (i > 0) { - i--; - DUK_ASSERT(new_e_k != NULL); - DUK_ASSERT(new_e_k[i] != NULL); - DUK_HSTRING_DECREF(thr, new_e_k[i]); /* side effects */ - } + alloc_failed: + DUK_D(DUK_DPRINT("object property table resize failed")); - thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; + DUK_FREE(thr->heap, new_p); /* OK for NULL. */ + + thr->heap->pf_prevent_count--; + thr->heap->ms_base_flags = prev_ms_base_flags; +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(thr->heap->error_not_allowed == 1); + thr->heap->error_not_allowed = prev_error_not_allowed; +#endif DUK_ERROR_ALLOC_FAILED(thr); } @@ -1122,7 +1129,7 @@ } #if defined(DUK_USE_HOBJECT_HASH_PART) - if (e_size >= DUK_HOBJECT_E_USE_HASH_LIMIT) { + if (e_size >= DUK_USE_HOBJECT_HASH_PROP_LIMIT) { h_size = duk__get_default_h_size(e_size); } else { h_size = 0; @@ -1183,13 +1190,15 @@ duk_uint32_t n; duk_uint32_t i, step; duk_uint32_t *h_base; + duk_uint32_t mask; DUK_DDD(DUK_DDDPRINT("duk_hobject_find_existing_entry() using hash part for lookup")); h_base = DUK_HOBJECT_H_GET_BASE(heap, obj); n = DUK_HOBJECT_GET_HSIZE(obj); - i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n); - step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key)); + mask = n - 1; + i = DUK_HSTRING_GET_HASH(key) & mask; + step = 1; /* Cache friendly but clustering prone. */ for (;;) { duk_uint32_t t; @@ -1217,10 +1226,9 @@ DUK_DDD(DUK_DDDPRINT("lookup miss i=%ld, t=%ld", (long) i, (long) t)); } - i = (i + step) % n; + i = (i + step) & mask; - /* guaranteed to finish, as hash is never full */ - DUK_ASSERT(i != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n)); + /* Guaranteed to finish (hash is larger than #props). */ } } #endif /* DUK_USE_HOBJECT_HASH_PART */ @@ -1325,13 +1333,14 @@ #if defined(DUK_USE_HOBJECT_HASH_PART) if (DUK_UNLIKELY(DUK_HOBJECT_GET_HSIZE(obj) > 0)) { - duk_uint32_t n; + duk_uint32_t n, mask; duk_uint32_t i, step; duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(thr->heap, obj); n = DUK_HOBJECT_GET_HSIZE(obj); - i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n); - step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key)); + mask = n - 1; + i = DUK_HSTRING_GET_HASH(key) & mask; + step = 1; /* Cache friendly but clustering prone. */ for (;;) { duk_uint32_t t = h_base[i]; @@ -1346,10 +1355,9 @@ break; } DUK_DDD(DUK_DDDPRINT("duk__alloc_entry_checked() miss %ld", (long) i)); - i = (i + step) % n; + i = (i + step) & mask; - /* guaranteed to find an empty slot */ - DUK_ASSERT(i != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), DUK_HOBJECT_GET_HSIZE(obj))); + /* Guaranteed to finish (hash is larger than #props). */ } } #endif /* DUK_USE_HOBJECT_HASH_PART */ @@ -1749,6 +1757,8 @@ DUK_DDD(DUK_DDDPRINT("string object exotic property get for key: %!O, arr_idx: %ld", (duk_heaphdr *) key, (long) arr_idx)); + /* XXX: charlen; avoid multiple lookups? */ + if (arr_idx != DUK__NO_ARRAY_INDEX) { duk_hstring *h_val; @@ -1989,7 +1999,7 @@ } /* not found in 'curr', next in prototype chain; impose max depth */ - if (sanity-- == 0) { + if (DUK_UNLIKELY(sanity-- == 0)) { if (flags & DUK_GETDESC_FLAG_IGNORE_PROTOLOOP) { /* treat like property not found */ break; @@ -1998,7 +2008,7 @@ } } curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); - } while (curr); + } while (curr != NULL); /* out_desc is left untouched (possibly garbage), caller must use return * value to determine whether out_desc can be looked up @@ -2348,7 +2358,7 @@ duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj); duk_int_t pop_count; - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { /* Symbols (ES2015 or hidden) don't have virtual properties. */ DUK_DDD(DUK_DDDPRINT("base object is a symbol, start lookup from symbol prototype")); curr = thr->builtins[DUK_BIDX_SYMBOL_PROTOTYPE]; @@ -2689,11 +2699,11 @@ /* XXX: option to pretend property doesn't exist if sanity limit is * hit might be useful. */ - if (sanity-- == 0) { + if (DUK_UNLIKELY(sanity-- == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); } curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); - } while (curr); + } while (curr != NULL); /* * Not found @@ -3373,7 +3383,7 @@ arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key); DUK_ASSERT(key != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { /* Symbols (ES2015 or hidden) don't have virtual properties. */ curr = thr->builtins[DUK_BIDX_SYMBOL_PROTOTYPE]; goto lookup; @@ -3789,11 +3799,11 @@ /* XXX: option to pretend property doesn't exist if sanity limit is * hit might be useful. */ - if (sanity-- == 0) { + if (DUK_UNLIKELY(sanity-- == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); } curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); - } while (curr); + } while (curr != NULL); /* * Property not found in prototype chain. @@ -4420,10 +4430,10 @@ /* Note: proxy handling must happen before key is string coerced. */ if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_DELETE_PROPERTY, tv_key, &h_target)) { - /* -> [ ... trap handler ] */ + /* -> [ ... obj key trap handler ] */ DUK_DDD(DUK_DDDPRINT("-> proxy object 'deleteProperty' for key %!T", (duk_tval *) tv_key)); duk_push_hobject(ctx, h_target); /* target */ - duk_push_tval(ctx, tv_key); /* P */ + duk_dup_m4(ctx); /* P */ duk_call_method(ctx, 2 /*nargs*/); tmp_bool = duk_to_boolean(ctx, -1); duk_pop(ctx); @@ -4434,6 +4444,7 @@ /* Target object must be checked for a conflicting * non-configurable property. */ + tv_key = DUK_GET_TVAL_NEGIDX(ctx, -1); arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key); DUK_ASSERT(key != NULL); @@ -4781,6 +4792,41 @@ return 0; } +/* + * Fast finalizer check for an object. Walks the prototype chain, checking + * for finalizer presence using DUK_HOBJECT_FLAG_HAVE_FINALIZER which is kept + * in sync with the actual property when setting/removing the finalizer. + */ + +#if defined(DUK_USE_HEAPPTR16) +DUK_INTERNAL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_heap *heap, duk_hobject *obj) { +#else +DUK_INTERNAL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_hobject *obj) { +#endif + duk_uint_t sanity; + + DUK_ASSERT(obj != NULL); + + sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; + do { + if (DUK_UNLIKELY(DUK_HOBJECT_HAS_HAVE_FINALIZER(obj))) { + return 1; + } + if (DUK_UNLIKELY(sanity-- == 0)) { + DUK_D(DUK_DPRINT("prototype loop when checking for finalizer existence; returning false")); + return 0; + } +#if defined(DUK_USE_HEAPPTR16) + DUK_ASSERT(heap != NULL); + obj = DUK_HOBJECT_GET_PROTOTYPE(heap, obj); +#else + obj = DUK_HOBJECT_GET_PROTOTYPE(NULL, obj); /* 'heap' arg ignored */ +#endif + } while (obj != NULL); + + return 0; +} + /* * Object.getOwnPropertyDescriptor() (E5 Sections 15.2.3.3, 8.10.4) * diff -Nru duktape-2.0.0/src-input/duk_hstring.h duktape-2.1.1/src-input/duk_hstring.h --- duktape-2.0.0/src-input/duk_hstring.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_hstring.h 2017-07-28 22:05:08.000000000 +0000 @@ -79,7 +79,7 @@ */ #define DUK_HSTRING_IS_ASCII(x) (DUK_HSTRING_GET_BYTELEN((x)) == DUK_HSTRING_GET_CHARLEN((x))) #endif -#define DUK_HSTRING_IS_ASCII(x) DUK_HSTRING_HAS_ASCII((x)) +#define DUK_HSTRING_IS_ASCII(x) DUK_HSTRING_HAS_ASCII((x)) /* lazily set! */ #define DUK_HSTRING_IS_EMPTY(x) (DUK_HSTRING_GET_BYTELEN((x)) == 0) #if defined(DUK_USE_STRHASH16) @@ -100,7 +100,7 @@ (x)->hdr.h_strextra16 = (v); \ } while (0) #if defined(DUK_USE_HSTRING_CLEN) -#define DUK_HSTRING_GET_CHARLEN(x) ((x)->clen16) +#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x)) #define DUK_HSTRING_SET_CHARLEN(x,v) do { \ (x)->clen16 = (v); \ } while (0) @@ -115,7 +115,7 @@ #define DUK_HSTRING_SET_BYTELEN(x,v) do { \ (x)->blen = (v); \ } while (0) -#define DUK_HSTRING_GET_CHARLEN(x) ((x)->clen) +#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x)) #define DUK_HSTRING_SET_CHARLEN(x,v) do { \ (x)->clen = (v); \ } while (0) @@ -146,11 +146,11 @@ * avoids helper call if string has no array index value. */ #define DUK_HSTRING_GET_ARRIDX_FAST(h) \ - (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_string_helper((h)) : DUK_HSTRING_NO_ARRAY_INDEX) + (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_hstring_fast_known((h)) : DUK_HSTRING_NO_ARRAY_INDEX) /* Slower but more compact variant. */ #define DUK_HSTRING_GET_ARRIDX_SLOW(h) \ - (duk_js_to_arrayindex_string_helper((h))) + (duk_js_to_arrayindex_hstring_fast((h))) #endif /* @@ -165,30 +165,26 @@ */ duk_heaphdr_string hdr; - /* Note: we could try to stuff a partial hash (e.g. 16 bits) into the - * shared heap header. Good hashing needs more hash bits though. - */ - - /* string hash */ + /* String hash. */ #if defined(DUK_USE_STRHASH16) /* If 16-bit hash is in use, stuff it into duk_heaphdr_string flags. */ #else duk_uint32_t hash; #endif - /* precomputed array index (or DUK_HSTRING_NO_ARRAY_INDEX) */ + /* Precomputed array index (or DUK_HSTRING_NO_ARRAY_INDEX). */ #if defined(DUK_USE_HSTRING_ARRIDX) duk_uarridx_t arridx; #endif - /* length in bytes (not counting NUL term) */ + /* Length in bytes (not counting NUL term). */ #if defined(DUK_USE_STRLEN16) /* placed in duk_heaphdr_string */ #else duk_uint32_t blen; #endif - /* length in codepoints (must be E5 compatible) */ + /* Length in codepoints (must be E5 compatible). */ #if defined(DUK_USE_STRLEN16) #if defined(DUK_USE_HSTRING_CLEN) duk_uint16_t clen16; @@ -200,7 +196,7 @@ #endif /* - * String value of 'blen+1' bytes follows (+1 for NUL termination + * String data of 'blen+1' bytes follows (+1 for NUL termination * convenience for C API). No alignment needs to be guaranteed * for strings, but fields above should guarantee alignment-by-4 * (but not alignment-by-8). @@ -225,9 +221,6 @@ */ DUK_INTERNAL_DECL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos, duk_bool_t surrogate_aware); - -#if !defined(DUK_USE_HSTRING_CLEN) DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h); -#endif #endif /* DUK_HSTRING_H_INCLUDED */ diff -Nru duktape-2.0.0/src-input/duk_hstring_misc.c duktape-2.1.1/src-input/duk_hstring_misc.c --- duktape-2.0.0/src-input/duk_hstring_misc.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_hstring_misc.c 2017-07-28 22:05:08.000000000 +0000 @@ -4,6 +4,10 @@ #include "duk_internal.h" +/* + * duk_hstring charCodeAt, with and without surrogate awareness + */ + DUK_INTERNAL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos, duk_bool_t surrogate_aware) { duk_uint32_t boff; const duk_uint8_t *p, *p_start, *p_end; @@ -51,13 +55,84 @@ return cp1; } -#if !defined(DUK_USE_HSTRING_CLEN) -DUK_INTERNAL duk_size_t duk_hstring_get_charlen(duk_hstring *h) { - if (DUK_HSTRING_HAS_ASCII(h)) { +/* + * duk_hstring charlen access + */ + +#if defined(DUK_USE_HSTRING_CLEN) +DUK_LOCAL DUK_COLD duk_size_t duk__hstring_get_charlen_slowpath(duk_hstring *h) { + duk_size_t res; + + DUK_ASSERT(h->clen == 0); /* Checked by caller. */ + +#if defined(DUK_USE_ROM_STRINGS) + /* ROM strings have precomputed clen, but if the computed clen is zero + * we can still come here and can't write anything. + */ + if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { + return 0; + } +#endif + + res = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); +#if defined(DUK_USE_STRLEN16) + DUK_ASSERT(res <= 0xffffUL); /* Bytelength checked during interning. */ + h->clen16 = (duk_uint16_t) res; +#else + h->clen = (duk_uint32_t) res; +#endif + if (DUK_LIKELY(res == DUK_HSTRING_GET_BYTELEN(h))) { + DUK_HSTRING_SET_ASCII(h); + } + return res; +} +#else /* DUK_USE_HSTRING_CLEN */ +DUK_LOCAL duk_size_t duk__hstring_get_charlen_slowpath(duk_hstring *h) { + if (DUK_LIKELY(DUK_HSTRING_HAS_ASCII(h))) { /* Most practical strings will go here. */ return DUK_HSTRING_GET_BYTELEN(h); } else { - return duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); + /* ASCII flag is lazy, so set it here. */ + duk_size_t res; + + /* XXX: here we could use the strcache to speed up the + * computation (matters for 'i < str.length' loops). + */ + + res = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); + +#if defined(DUK_USE_ROM_STRINGS) + if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { + /* For ROM strings, can't write anything; ASCII flag + * is preset so we don't need to update it. + */ + return res; + } +#endif + if (DUK_LIKELY(res == DUK_HSTRING_GET_BYTELEN(h))) { + DUK_HSTRING_SET_ASCII(h); + } + return res; } } -#endif /* !DUK_USE_HSTRING_CLEN */ +#endif /* DUK_USE_HSTRING_CLEN */ + +#if defined(DUK_USE_HSTRING_CLEN) +DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) { +#if defined(DUK_USE_STRLEN16) + if (DUK_LIKELY(h->clen16 != 0)) { + return h->clen16; + } +#else + if (DUK_LIKELY(h->clen != 0)) { + return h->clen; + } +#endif + return duk__hstring_get_charlen_slowpath(h); +} +#else /* DUK_USE_HSTRING_CLEN */ +DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) { + /* Always use slow path. */ + return duk__hstring_get_charlen_slowpath(h); +} +#endif /* DUK_USE_HSTRING_CLEN */ diff -Nru duktape-2.0.0/src-input/duk_hthread_alloc.c duktape-2.1.1/src-input/duk_hthread_alloc.c --- duktape-2.0.0/src-input/duk_hthread_alloc.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_hthread_alloc.c 2017-07-28 22:05:08.000000000 +0000 @@ -21,6 +21,7 @@ DUK_ASSERT(thr->valstack_bottom == NULL); DUK_ASSERT(thr->valstack_top == NULL); DUK_ASSERT(thr->callstack == NULL); + DUK_ASSERT(thr->callstack_curr == NULL); DUK_ASSERT(thr->catchstack == NULL); /* valstack */ @@ -50,6 +51,7 @@ DUK_MEMZERO(thr->callstack, alloc_size); thr->callstack_size = DUK_CALLSTACK_INITIAL_SIZE; DUK_ASSERT(thr->callstack_top == 0); + DUK_ASSERT(thr->callstack_curr == NULL); /* catchstack */ alloc_size = sizeof(duk_catcher) * DUK_CATCHSTACK_INITIAL_SIZE; diff -Nru duktape-2.0.0/src-input/duk_hthread_builtins.c duktape-2.1.1/src-input/duk_hthread_builtins.c --- duktape-2.0.0/src-input/duk_hthread_builtins.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_hthread_builtins.c 2017-07-28 22:05:08.000000000 +0000 @@ -35,12 +35,13 @@ #if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT) DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) { duk_context *ctx; - duk_hobject *h1; + duk_hobject *h_global; #if defined(DUK_USE_ROM_GLOBAL_CLONE) - duk_hobject *h2; + duk_hobject *h_oldglobal; duk_uint8_t *props; duk_size_t alloc_size; #endif + duk_hobject *h_objenv; ctx = (duk_context *) thr; @@ -48,83 +49,84 @@ #if defined(DUK_USE_ROM_GLOBAL_INHERIT) /* Inherit from ROM-based global object: less RAM usage, less transparent. */ - h1 = duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL), - DUK_BIDX_GLOBAL); - DUK_ASSERT(h1 != NULL); + h_global = duk_push_object_helper(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL), + DUK_BIDX_GLOBAL); + DUK_ASSERT(h_global != NULL); #elif defined(DUK_USE_ROM_GLOBAL_CLONE) /* Clone the properties of the ROM-based global object to create a * fully RAM-based global object. Uses more memory than the inherit * model but more compliant. */ - h1 = duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL), - DUK_BIDX_OBJECT_PROTOTYPE); - DUK_ASSERT(h1 != NULL); - h2 = thr->builtins[DUK_BIDX_GLOBAL]; - DUK_ASSERT(h2 != NULL); + h_global = duk_push_object_helper(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL), + DUK_BIDX_OBJECT_PROTOTYPE); + DUK_ASSERT(h_global != NULL); + h_oldglobal = thr->builtins[DUK_BIDX_GLOBAL]; + DUK_ASSERT(h_oldglobal != NULL); /* Copy the property table verbatim; this handles attributes etc. * For ROM objects it's not necessary (or possible) to update * refcounts so leave them as is. */ - alloc_size = DUK_HOBJECT_P_ALLOC_SIZE(h2); + alloc_size = DUK_HOBJECT_P_ALLOC_SIZE(h_oldglobal); DUK_ASSERT(alloc_size > 0); - props = DUK_ALLOC(thr->heap, alloc_size); - if (!props) { - DUK_ERROR_ALLOC_FAILED(thr); - return; - } - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h2) != NULL); - DUK_MEMCPY((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h2), alloc_size); + props = DUK_ALLOC_CHECKED(thr, alloc_size); + DUK_ASSERT(props != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal) != NULL); + DUK_MEMCPY((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal), alloc_size); /* XXX: keep property attributes or tweak them here? * Properties will now be non-configurable even when they're * normally configurable for the global object. */ - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h1) == NULL); - DUK_HOBJECT_SET_PROPS(thr->heap, h1, props); - DUK_HOBJECT_SET_ESIZE(h1, DUK_HOBJECT_GET_ESIZE(h2)); - DUK_HOBJECT_SET_ENEXT(h1, DUK_HOBJECT_GET_ENEXT(h2)); - DUK_HOBJECT_SET_ASIZE(h1, DUK_HOBJECT_GET_ASIZE(h2)); - DUK_HOBJECT_SET_HSIZE(h1, DUK_HOBJECT_GET_HSIZE(h2)); + DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h_global) == NULL); + DUK_HOBJECT_SET_PROPS(thr->heap, h_global, props); + DUK_HOBJECT_SET_ESIZE(h_global, DUK_HOBJECT_GET_ESIZE(h_oldglobal)); + DUK_HOBJECT_SET_ENEXT(h_global, DUK_HOBJECT_GET_ENEXT(h_oldglobal)); + DUK_HOBJECT_SET_ASIZE(h_global, DUK_HOBJECT_GET_ASIZE(h_oldglobal)); + DUK_HOBJECT_SET_HSIZE(h_global, DUK_HOBJECT_GET_HSIZE(h_oldglobal)); #else -#error internal error in defines +#error internal error in config defines #endif - duk_hobject_compact_props(thr, h1); + duk_hobject_compact_props(thr, h_global); DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); - DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL])); /* no need to decref */ - thr->builtins[DUK_BIDX_GLOBAL] = h1; - DUK_HOBJECT_INCREF(thr, h1); - DUK_D(DUK_DPRINT("duplicated global object: %!O", h1)); - + DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL])); /* no need to decref: ROM object */ + thr->builtins[DUK_BIDX_GLOBAL] = h_global; + DUK_HOBJECT_INCREF(thr, h_global); + DUK_D(DUK_DPRINT("duplicated global object: %!O", h_global)); /* Create a fresh object environment for the global scope. This is * needed so that the global scope points to the newly created RAM-based * global object. */ - h1 = duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV), - -1); /* no prototype */ - DUK_ASSERT(h1 != NULL); - duk_dup_m2(ctx); - duk_dup_top(ctx); /* -> [ ... new_global new_globalenv new_global new_global ] */ - duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); /* always provideThis=true */ + h_objenv = (duk_hobject *) duk_hobjenv_alloc(thr, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV)); + DUK_ASSERT(h_objenv != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_objenv) == NULL); + duk_push_hobject(ctx, h_objenv); + + DUK_ASSERT(h_global != NULL); + ((duk_hobjenv *) h_objenv)->target = h_global; + DUK_HOBJECT_INCREF(thr, h_global); + DUK_ASSERT(((duk_hobjenv *) h_objenv)->has_this == 0); - duk_hobject_compact_props(thr, h1); DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL); - DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL_ENV])); /* no need to decref */ - thr->builtins[DUK_BIDX_GLOBAL_ENV] = h1; - DUK_HOBJECT_INCREF(thr, h1); - DUK_D(DUK_DPRINT("duplicated global env: %!O", h1)); + DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL_ENV])); /* no need to decref: ROM object */ + thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_objenv; + DUK_HOBJECT_INCREF(thr, h_objenv); + DUK_D(DUK_DPRINT("duplicated global env: %!O", h_objenv)); - duk_pop_2(ctx); + DUK_ASSERT_HOBJENV_VALID((duk_hobjenv *) h_objenv); + + duk_pop_2(ctx); /* Pop global object and global env. */ } #endif /* DUK_USE_ROM_GLOBAL_CLONE || DUK_USE_ROM_GLOBAL_INHERIT */ @@ -230,11 +232,11 @@ duk_small_int_t len = -1; /* must be signed */ class_num = (duk_small_uint_t) duk_bd_decode_varuint(bd); - len = (duk_small_int_t) duk_bd_decode_flagged(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/); + len = (duk_small_int_t) duk_bd_decode_flagged_signed(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/); if (class_num == DUK_HOBJECT_CLASS_FUNCTION) { duk_small_uint_t natidx; - duk_int_t c_nargs; /* must hold DUK_VARARGS */ + duk_small_int_t c_nargs; /* must hold DUK_VARARGS */ duk_c_function c_func; duk_int16_t magic; @@ -246,7 +248,7 @@ c_func = duk_bi_native_functions[natidx]; DUK_ASSERT(c_func != NULL); - c_nargs = (duk_small_uint_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, len /*def_value*/); + c_nargs = (duk_small_int_t) duk_bd_decode_flagged_signed(bd, DUK__NARGS_BITS, len /*def_value*/); if (c_nargs == DUK__NARGS_VARARGS_MARKER) { c_nargs = DUK_VARARGS; } @@ -289,8 +291,31 @@ ((duk_hnatfunc *) h)->magic = magic; } else if (class_num == DUK_HOBJECT_CLASS_ARRAY) { duk_push_array(ctx); + } else if (class_num == DUK_HOBJECT_CLASS_OBJENV) { + duk_hobjenv *env; + duk_hobject *global; + + DUK_ASSERT(i == DUK_BIDX_GLOBAL_ENV); + DUK_ASSERT(DUK_BIDX_GLOBAL_ENV > DUK_BIDX_GLOBAL); + + env = duk_hobjenv_alloc(thr, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV)); + DUK_ASSERT(env->target == NULL); + duk_push_hobject(ctx, (duk_hobject *) env); + + global = duk_known_hobject(ctx, DUK_BIDX_GLOBAL); + DUK_ASSERT(global != NULL); + env->target = global; + DUK_HOBJECT_INCREF(thr, global); + DUK_ASSERT(env->has_this == 0); + + DUK_ASSERT_HOBJENV_VALID(env); } else { + DUK_ASSERT(class_num != DUK_HOBJECT_CLASS_DECENV); + (void) duk_push_object_helper(ctx, + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_EXTENSIBLE, -1); /* no prototype or class yet */ @@ -339,14 +364,13 @@ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_COMPFUNC(h)); /* DUK_HOBJECT_FLAG_NATFUNC varies */ - DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(h)); + DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(h) || class_num == DUK_HOBJECT_CLASS_ARRAY); /* DUK_HOBJECT_FLAG_STRICT varies */ DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(h) || /* all native functions have NEWENV */ DUK_HOBJECT_HAS_NEWENV(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(h)); - DUK_ASSERT(!DUK_HOBJECT_HAS_ENVRECCLOSED(h)); /* DUK_HOBJECT_FLAG_EXOTIC_ARRAY varies */ /* DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ varies */ DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h)); @@ -695,12 +719,8 @@ #endif " " /* Low memory options */ -#if defined(DUK_USE_STRTAB_CHAIN) - "c" /* chain */ -#elif defined(DUK_USE_STRTAB_PROBE) - "p" /* probe */ -#else - "?" +#if defined(DUK_USE_STRTAB_PTRCOMP) + "s" #endif #if !defined(DUK_USE_HEAPPTR16) && !defined(DUK_DATAPTR16) && !defined(DUK_FUNCPTR16) "n" diff -Nru duktape-2.0.0/src-input/duk_hthread.h duktape-2.1.1/src-input/duk_hthread.h --- duktape-2.0.0/src-input/duk_hthread.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_hthread.h 2017-07-28 22:05:08.000000000 +0000 @@ -134,8 +134,6 @@ #endif #endif /* DUK_USE_ROM_STRINGS */ -#define DUK_HTHREAD_GET_CURRENT_ACTIVATION(thr) (&(thr)->callstack[(thr)->callstack_top - 1]) - /* values for the state field */ #define DUK_HTHREAD_STATE_INACTIVE 1 /* thread not currently running */ #define DUK_HTHREAD_STATE_RUNNING 2 /* thread currently running (only one at a time) */ @@ -317,8 +315,9 @@ /* Call stack. [0,callstack_top[ is GC reachable. */ duk_activation *callstack; + duk_activation *callstack_curr; /* current activation (or NULL if none) */ duk_size_t callstack_size; /* allocation size */ - duk_size_t callstack_top; /* next to use, highest used is top - 1 */ + duk_size_t callstack_top; /* next to use, highest used is top - 1 (or none if top == 0) */ duk_size_t callstack_preventcount; /* number of activation records in callstack preventing a yield */ /* Catch stack. [0,catchstack_top[ is GC reachable. */ @@ -380,12 +379,19 @@ DUK_INTERNAL_DECL void duk_hthread_callstack_grow(duk_hthread *thr); DUK_INTERNAL_DECL void duk_hthread_callstack_shrink_check(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_hthread_callstack_unwind_norz(duk_hthread *thr, duk_size_t new_top); DUK_INTERNAL_DECL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top); DUK_INTERNAL_DECL void duk_hthread_catchstack_grow(duk_hthread *thr); DUK_INTERNAL_DECL void duk_hthread_catchstack_shrink_check(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_hthread_catchstack_unwind_norz(duk_hthread *thr, duk_size_t new_top); DUK_INTERNAL_DECL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top); -DUK_INTERNAL_DECL duk_activation *duk_hthread_get_current_activation(duk_hthread *thr); +#if defined(DUK_USE_FINALIZER_TORTURE) +DUK_INTERNAL_DECL void duk_hthread_valstack_torture_realloc(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_hthread_callstack_torture_realloc(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_hthread_catchstack_torture_realloc(duk_hthread *thr); +#endif + DUK_INTERNAL_DECL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */ DUK_INTERNAL_DECL void *duk_hthread_get_callstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */ DUK_INTERNAL_DECL void *duk_hthread_get_catchstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */ diff -Nru duktape-2.0.0/src-input/duk_hthread_misc.c duktape-2.1.1/src-input/duk_hthread_misc.c --- duktape-2.0.0/src-input/duk_hthread_misc.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_hthread_misc.c 2017-07-28 22:05:08.000000000 +0000 @@ -10,7 +10,6 @@ /* Order of unwinding is important */ duk_hthread_catchstack_unwind(thr, 0); - duk_hthread_callstack_unwind(thr, 0); /* side effects, possibly errors */ thr->valstack_bottom = thr->valstack; @@ -33,16 +32,6 @@ */ } -DUK_INTERNAL duk_activation *duk_hthread_get_current_activation(duk_hthread *thr) { - DUK_ASSERT(thr != NULL); - - if (thr->callstack_top > 0) { - return thr->callstack + thr->callstack_top - 1; - } else { - return NULL; - } -} - #if defined(DUK_USE_DEBUGGER_SUPPORT) DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act) { duk_instr_t *bcode; @@ -88,7 +77,9 @@ if (thr->ptr_curr_pc != NULL) { /* ptr_curr_pc != NULL only when bytecode executor is active. */ DUK_ASSERT(thr->callstack_top > 0); - act = thr->callstack + thr->callstack_top - 1; + DUK_ASSERT(thr->callstack_curr != NULL); + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); act->curr_pc = *thr->ptr_curr_pc; } } @@ -101,7 +92,9 @@ if (thr->ptr_curr_pc != NULL) { /* ptr_curr_pc != NULL only when bytecode executor is active. */ DUK_ASSERT(thr->callstack_top > 0); - act = thr->callstack + thr->callstack_top - 1; + DUK_ASSERT(thr->callstack_curr != NULL); + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); act->curr_pc = *thr->ptr_curr_pc; thr->ptr_curr_pc = NULL; } diff -Nru duktape-2.0.0/src-input/duk_hthread_stacks.c duktape-2.1.1/src-input/duk_hthread_stacks.c --- duktape-2.0.0/src-input/duk_hthread_stacks.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_hthread_stacks.c 2017-07-28 22:05:08.000000000 +0000 @@ -22,8 +22,7 @@ #include "duk_internal.h" -/* check that there is space for at least one new entry */ -DUK_INTERNAL void duk_hthread_callstack_grow(duk_hthread *thr) { +DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__hthread_do_callstack_grow(duk_hthread *thr) { duk_activation *new_ptr; duk_size_t old_size; duk_size_t new_size; @@ -32,10 +31,6 @@ DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */ DUK_ASSERT(thr->callstack_size >= thr->callstack_top); - if (thr->callstack_top < thr->callstack_size) { - return; - } - old_size = thr->callstack_size; new_size = old_size + DUK_CALLSTACK_GROW_STEP; @@ -60,10 +55,28 @@ thr->callstack = new_ptr; thr->callstack_size = new_size; + if (thr->callstack_top > 0) { + thr->callstack_curr = thr->callstack + thr->callstack_top - 1; + } else { + thr->callstack_curr = NULL; + } + /* note: any entries above the callstack top are garbage and not zeroed */ } -DUK_INTERNAL void duk_hthread_callstack_shrink_check(duk_hthread *thr) { +/* check that there is space for at least one new entry */ +DUK_INTERNAL void duk_hthread_callstack_grow(duk_hthread *thr) { + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */ + DUK_ASSERT(thr->callstack_size >= thr->callstack_top); + + if (DUK_LIKELY(thr->callstack_top < thr->callstack_size)) { + return; + } + duk__hthread_do_callstack_grow(thr); +} + +DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__hthread_do_callstack_shrink(duk_hthread *thr) { duk_size_t new_size; duk_activation *p; @@ -71,10 +84,6 @@ DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */ DUK_ASSERT(thr->callstack_size >= thr->callstack_top); - if (thr->callstack_size - thr->callstack_top < DUK_CALLSTACK_SHRINK_THRESHOLD) { - return; - } - new_size = thr->callstack_top + DUK_CALLSTACK_SHRINK_SPARE; DUK_ASSERT(new_size >= thr->callstack_top); @@ -90,6 +99,12 @@ if (p) { thr->callstack = p; thr->callstack_size = new_size; + + if (thr->callstack_top > 0) { + thr->callstack_curr = thr->callstack + thr->callstack_top - 1; + } else { + thr->callstack_curr = NULL; + } } else { /* Because new_size != 0, if condition doesn't need to be * (p != NULL || new_size == 0). @@ -101,7 +116,19 @@ /* note: any entries above the callstack top are garbage and not zeroed */ } -DUK_INTERNAL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top) { +DUK_INTERNAL void duk_hthread_callstack_shrink_check(duk_hthread *thr) { + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */ + DUK_ASSERT(thr->callstack_size >= thr->callstack_top); + + if (DUK_LIKELY(thr->callstack_size - thr->callstack_top < DUK_CALLSTACK_SHRINK_THRESHOLD)) { + return; + } + + duk__hthread_do_callstack_shrink(thr); +} + +DUK_INTERNAL void duk_hthread_callstack_unwind_norz(duk_hthread *thr, duk_size_t new_top) { duk_size_t idx; DUK_DDD(DUK_DDDPRINT("unwind callstack top of thread %p from %ld to %ld", @@ -130,9 +157,7 @@ while (idx > new_top) { duk_activation *act; duk_hobject *func; -#if defined(DUK_USE_REFERENCE_COUNTING) duk_hobject *tmp; -#endif #if defined(DUK_USE_DEBUGGER_SUPPORT) duk_heap *heap; #endif @@ -174,12 +199,12 @@ DUK_TVAL_SET_NULL(tv_caller); /* no incref needed */ DUK_ASSERT(act->prev_caller == NULL); } - DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */ + DUK_TVAL_DECREF_NORZ(thr, &tv_tmp); } else { h_tmp = act->prev_caller; if (h_tmp) { act->prev_caller = NULL; - DUK_HOBJECT_DECREF(thr, h_tmp); /* side effects */ + DUK_HOBJECT_DECREF_NORZ(thr, h_tmp); } } act = thr->callstack + idx; /* avoid side effects */ @@ -199,8 +224,12 @@ /* Pause for all step types: step into, step over, step out. * This is the only place explicitly handling a step out. */ - DUK_HEAP_SET_PAUSED(heap); - DUK_ASSERT(heap->dbg_step_thread == NULL); + if (duk_debug_is_paused(heap)) { + DUK_D(DUK_DPRINT("step pause trigger but already paused, ignoring")); + } else { + duk_debug_set_paused(heap); + DUK_ASSERT(heap->dbg_step_thread == NULL); + } } #endif @@ -221,42 +250,19 @@ } /* func is NULL for lightfunc */ + /* Catch sites are required to clean up their environments + * in FINALLY part before propagating, so this should + * always hold here. + */ DUK_ASSERT(act->lex_env == act->var_env); + if (act->var_env != NULL) { DUK_DDD(DUK_DDDPRINT("closing var_env record %p -> %!O", (void *) act->var_env, (duk_heaphdr *) act->var_env)); - duk_js_close_environment_record(thr, act->var_env, func, act->idx_bottom); + duk_js_close_environment_record(thr, act->var_env); act = thr->callstack + idx; /* avoid side effect issues */ } -#if 0 - if (act->lex_env != NULL) { - if (act->lex_env == act->var_env) { - /* common case, already closed, so skip */ - DUK_DD(DUK_DDPRINT("lex_env and var_env are the same and lex_env " - "already closed -> skip closing lex_env")); - ; - } else { - DUK_DD(DUK_DDPRINT("closing lex_env record %p -> %!O", - (void *) act->lex_env, (duk_heaphdr *) act->lex_env)); - duk_js_close_environment_record(thr, act->lex_env, DUK_ACT_GET_FUNC(act), act->idx_bottom); - act = thr->callstack + idx; /* avoid side effect issues */ - } - } -#endif - - DUK_ASSERT((act->lex_env == NULL) || - ((duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_VARMAP(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL))); - - DUK_ASSERT((act->var_env == NULL) || - ((duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_VARMAP(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL))); - skip_env_close: /* @@ -269,55 +275,38 @@ } /* - * Reference count updates - * - * Note: careful manipulation of refcounts. The top is - * not updated yet, so all the activations are reachable - * for mark-and-sweep (which may be triggered by decref). - * However, the pointers are NULL so this is not an issue. + * Reference count updates, using NORZ macros so we don't + * need to handle side effects. */ -#if defined(DUK_USE_REFERENCE_COUNTING) - tmp = act->var_env; -#endif + DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, act->var_env); act->var_env = NULL; -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); - act = thr->callstack + idx; /* avoid side effect issues */ -#endif - -#if defined(DUK_USE_REFERENCE_COUNTING) - tmp = act->lex_env; -#endif + DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, act->lex_env); act->lex_env = NULL; -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); - act = thr->callstack + idx; /* avoid side effect issues */ -#endif /* Note: this may cause a corner case situation where a finalizer * may see a currently reachable activation whose 'func' is NULL. */ -#if defined(DUK_USE_REFERENCE_COUNTING) tmp = DUK_ACT_GET_FUNC(act); -#endif + DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp); + DUK_UNREF(tmp); act->func = NULL; -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); - act = thr->callstack + idx; /* avoid side effect issues */ - DUK_UNREF(act); -#endif } thr->callstack_top = new_top; + if (new_top > 0) { + thr->callstack_curr = thr->callstack + new_top - 1; + } else { + thr->callstack_curr = NULL; + } /* * We could clear the book-keeping variables for the topmost activation, * but don't do so now. */ #if 0 - if (thr->callstack_top > 0) { - duk_activation *act = thr->callstack + thr->callstack_top - 1; + if (thr->callstack_curr != NULL) { + duk_activation *act = thr->callstack_curr; act->idx_retval = 0; } #endif @@ -328,7 +317,12 @@ */ } -DUK_INTERNAL void duk_hthread_catchstack_grow(duk_hthread *thr) { +DUK_INTERNAL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top) { + duk_hthread_callstack_unwind_norz(thr, new_top); + DUK_REFZERO_CHECK_FAST(thr); +} + +DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__hthread_do_catchstack_grow(duk_hthread *thr) { duk_catcher *new_ptr; duk_size_t old_size; duk_size_t new_size; @@ -337,10 +331,6 @@ DUK_ASSERT_DISABLE(thr->catchstack_top); /* avoid warning (unsigned) */ DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top); - if (thr->catchstack_top < thr->catchstack_size) { - return; - } - old_size = thr->catchstack_size; new_size = old_size + DUK_CATCHSTACK_GROW_STEP; @@ -368,7 +358,19 @@ /* note: any entries above the catchstack top are garbage and not zeroed */ } -DUK_INTERNAL void duk_hthread_catchstack_shrink_check(duk_hthread *thr) { +DUK_INTERNAL void duk_hthread_catchstack_grow(duk_hthread *thr) { + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->catchstack_top); /* avoid warning (unsigned) */ + DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top); + + if (DUK_LIKELY(thr->catchstack_top < thr->catchstack_size)) { + return; + } + + duk__hthread_do_catchstack_grow(thr); +} + +DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__hthread_do_catchstack_shrink(duk_hthread *thr) { duk_size_t new_size; duk_catcher *p; @@ -376,10 +378,6 @@ DUK_ASSERT_DISABLE(thr->catchstack_top >= 0); /* avoid warning (unsigned) */ DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top); - if (thr->catchstack_size - thr->catchstack_top < DUK_CATCHSTACK_SHRINK_THRESHOLD) { - return; - } - new_size = thr->catchstack_top + DUK_CATCHSTACK_SHRINK_SPARE; DUK_ASSERT(new_size >= thr->catchstack_top); @@ -406,7 +404,19 @@ /* note: any entries above the catchstack top are garbage and not zeroed */ } -DUK_INTERNAL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top) { +DUK_INTERNAL void duk_hthread_catchstack_shrink_check(duk_hthread *thr) { + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->catchstack_top >= 0); /* avoid warning (unsigned) */ + DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top); + + if (DUK_LIKELY(thr->catchstack_size - thr->catchstack_top < DUK_CATCHSTACK_SHRINK_THRESHOLD)) { + return; + } + + duk__hthread_do_catchstack_shrink(thr); +} + +DUK_INTERNAL void duk_hthread_catchstack_unwind_norz(duk_hthread *thr, duk_size_t new_top) { duk_size_t idx; DUK_DDD(DUK_DDDPRINT("unwind catchstack top of thread %p from %ld to %ld", @@ -462,7 +472,8 @@ env = act->lex_env; /* current lex_env of the activation (created for catcher) */ DUK_ASSERT(env != NULL); /* must be, since env was created when catcher was created */ act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env); /* prototype is lex_env before catcher created */ - DUK_HOBJECT_DECREF(thr, env); + DUK_HOBJECT_INCREF(thr, act->lex_env); + DUK_HOBJECT_DECREF_NORZ(thr, env); /* There is no need to decref anything else than 'env': if 'env' * becomes unreachable, refzero will handle decref'ing its prototype. @@ -474,3 +485,97 @@ /* note: any entries above the catchstack top are garbage and not zeroed */ } + +DUK_INTERNAL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top) { + duk_hthread_catchstack_unwind_norz(thr, new_top); + DUK_REFZERO_CHECK_FAST(thr); +} + +#if defined(DUK_USE_FINALIZER_TORTURE) +DUK_INTERNAL void duk_hthread_valstack_torture_realloc(duk_hthread *thr) { + duk_size_t alloc_size; + duk_tval *new_ptr; + duk_ptrdiff_t end_off; + duk_ptrdiff_t bottom_off; + duk_ptrdiff_t top_off; + + if (thr->valstack == NULL) { + return; + } + + end_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack); + bottom_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack); + top_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack); + alloc_size = (duk_size_t) end_off; + if (alloc_size == 0) { + return; + } + + new_ptr = (duk_tval *) DUK_ALLOC(thr->heap, alloc_size); + if (new_ptr != NULL) { + DUK_MEMCPY((void *) new_ptr, (const void *) thr->valstack, alloc_size); + DUK_MEMSET((void *) thr->valstack, 0x55, alloc_size); + DUK_FREE(thr->heap, (void *) thr->valstack); + thr->valstack = new_ptr; + thr->valstack_end = (duk_tval *) ((duk_uint8_t *) new_ptr + end_off); + thr->valstack_bottom = (duk_tval *) ((duk_uint8_t *) new_ptr + bottom_off); + thr->valstack_top = (duk_tval *) ((duk_uint8_t *) new_ptr + top_off); + /* No change in size. */ + } else { + DUK_D(DUK_DPRINT("failed to realloc valstack for torture, ignore")); + } +} + +DUK_INTERNAL void duk_hthread_callstack_torture_realloc(duk_hthread *thr) { + duk_size_t alloc_size; + duk_activation *new_ptr; + duk_ptrdiff_t curr_off; + + if (thr->callstack == NULL) { + return; + } + + curr_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->callstack_curr - (duk_uint8_t *) thr->callstack); + alloc_size = sizeof(duk_activation) * thr->callstack_size; + if (alloc_size == 0) { + return; + } + + new_ptr = (duk_activation *) DUK_ALLOC(thr->heap, alloc_size); + if (new_ptr != NULL) { + DUK_MEMCPY((void *) new_ptr, (const void *) thr->callstack, alloc_size); + DUK_MEMSET((void *) thr->callstack, 0x55, alloc_size); + DUK_FREE(thr->heap, (void *) thr->callstack); + thr->callstack = new_ptr; + thr->callstack_curr = (duk_activation *) ((duk_uint8_t *) new_ptr + curr_off); + /* No change in size. */ + } else { + DUK_D(DUK_DPRINT("failed to realloc callstack for torture, ignore")); + } +} + +DUK_INTERNAL void duk_hthread_catchstack_torture_realloc(duk_hthread *thr) { + duk_size_t alloc_size; + duk_catcher *new_ptr; + + if (thr->catchstack == NULL) { + return; + } + + alloc_size = sizeof(duk_catcher) * thr->catchstack_size; + if (alloc_size == 0) { + return; + } + + new_ptr = (duk_catcher *) DUK_ALLOC(thr->heap, alloc_size); + if (new_ptr != NULL) { + DUK_MEMCPY((void *) new_ptr, (const void *) thr->catchstack, alloc_size); + DUK_MEMSET((void *) thr->catchstack, 0x55, alloc_size); + DUK_FREE(thr->heap, (void *) thr->catchstack); + thr->catchstack = new_ptr; + /* No change in size. */ + } else { + DUK_D(DUK_DPRINT("failed to realloc catchstack for torture, ignore")); + } +} +#endif /* DUK_USE_FINALIZER_TORTURE */ diff -Nru duktape-2.0.0/src-input/duk_internal.h duktape-2.1.1/src-input/duk_internal.h --- duktape-2.0.0/src-input/duk_internal.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_internal.h 2017-07-28 22:05:08.000000000 +0000 @@ -41,6 +41,7 @@ * dependencies. */ +#include "duk_dblunion.h" #include "duk_replacements.h" #include "duk_jmpbuf.h" #include "duk_exception.h" @@ -55,6 +56,7 @@ #include "duk_js_compiler.h" #include "duk_regexp.h" #include "duk_heaphdr.h" +#include "duk_refcount.h" #include "duk_api_internal.h" #include "duk_hstring.h" #include "duk_hobject.h" @@ -63,6 +65,7 @@ #include "duk_hbufobj.h" #include "duk_hthread.h" #include "duk_harray.h" +#include "duk_henv.h" #include "duk_hbuffer.h" #include "duk_heap.h" #include "duk_debugger.h" diff -Nru duktape-2.0.0/src-input/duk_js_bytecode.h duktape-2.1.1/src-input/duk_js_bytecode.h --- duktape-2.0.0/src-input/duk_js_bytecode.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_js_bytecode.h 2017-07-28 22:05:08.000000000 +0000 @@ -461,8 +461,7 @@ #define DUK_BC_TRYCATCH_FLAG_WITH_BINDING (1 << 3) /* DUK_OP_DECLVAR flags in A; bottom bits are reserved for propdesc flags (DUK_PROPDESC_FLAG_XXX) */ -#define DUK_BC_DECLVAR_FLAG_UNDEF_VALUE (1 << 4) /* use 'undefined' for value automatically */ -#define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1 << 5) /* function declaration */ +#define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1 << 4) /* function declaration */ /* Misc constants and helper macros. */ #define DUK_BC_LDINT_BIAS (1L << 15) diff -Nru duktape-2.0.0/src-input/duk_js_call.c duktape-2.1.1/src-input/duk_js_call.c --- duktape-2.0.0/src-input/duk_js_call.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_js_call.c 2017-07-28 22:05:08.000000000 +0000 @@ -21,6 +21,8 @@ #include "duk_internal.h" +/* XXX: heap->error_not_allowed for success path too? */ + /* * Forward declarations. */ @@ -176,16 +178,19 @@ arg = duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_ARRAY_PART | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARGUMENTS), DUK_BIDX_OBJECT_PROTOTYPE); DUK_ASSERT(arg != NULL); (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), -1); /* no prototype */ (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), -1); /* no prototype */ i_arg = duk_get_top(ctx) - 3; @@ -473,6 +478,8 @@ duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_LENGTH); /* -> [ ... func this arg1 ... argN _Args length ] */ len = (duk_idx_t) duk_require_int(ctx, -1); duk_pop(ctx); + + duk_require_stack(ctx, len); for (i = 0; i < len; i++) { /* XXX: very slow - better to bulk allocate a gap, and copy * from args_array directly (we know it has a compact array @@ -495,7 +502,7 @@ (long) num_stack_args, (long) idx_func, duk_get_tval(ctx, idx_func))); } while (--sanity > 0); - if (sanity == 0) { + if (DUK_UNLIKELY(sanity == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_BOUND_CHAIN_LIMIT); } @@ -569,7 +576,9 @@ return; } - act_callee = thr->callstack + thr->callstack_top - 1; + DUK_ASSERT(thr->callstack_top > 0); + act_callee = thr->callstack_curr; + DUK_ASSERT(act_callee != NULL); act_caller = (thr->callstack_top >= 2 ? act_callee - 1 : NULL); /* XXX: check .caller writability? */ @@ -1050,16 +1059,6 @@ */ duk__handle_call_inner(thr, num_stack_args, call_flags, idx_func); - /* Success path handles */ - DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth); - DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc); - - /* Longjmp state is kept clean in success path */ - DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN); - DUK_ASSERT(thr->heap->lj.iserror == 0); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1)); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); - thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr; return DUK_EXEC_SUCCESS; @@ -1086,11 +1085,6 @@ idx_func, old_jmpbuf_ptr); - /* Longjmp state is cleaned up by error handling */ - DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN); - DUK_ASSERT(thr->heap->lj.iserror == 0); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1)); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); return DUK_EXEC_ERROR; } #if defined(DUK_USE_CPP_EXCEPTIONS) @@ -1116,6 +1110,7 @@ entry_ptr_curr_pc, idx_func, old_jmpbuf_ptr); + return DUK_EXEC_ERROR; } } catch (...) { @@ -1136,6 +1131,7 @@ entry_ptr_curr_pc, idx_func, old_jmpbuf_ptr); + return DUK_EXEC_ERROR; } } @@ -1326,7 +1322,8 @@ duk_hthread_callstack_grow(thr); - if (thr->callstack_top > 0) { + act = thr->callstack_curr; + if (act != NULL) { /* * Update idx_retval of current activation. * @@ -1337,12 +1334,13 @@ * the Ecmascript call's idx_retval must be set for things to work. */ - (thr->callstack + thr->callstack_top - 1)->idx_retval = entry_valstack_bottom_index + idx_func; + act->idx_retval = entry_valstack_bottom_index + idx_func; } DUK_ASSERT(thr->callstack_top < thr->callstack_size); act = thr->callstack + thr->callstack_top; thr->callstack_top++; + thr->callstack_curr = act; DUK_ASSERT(thr->callstack_top <= thr->callstack_size); DUK_ASSERT(thr->valstack_top > thr->valstack_bottom); /* at least effective 'this' */ DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func)); @@ -1433,8 +1431,8 @@ #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) if (func) { duk__update_func_caller_prop(thr, func); + act = thr->callstack_curr; } - act = thr->callstack + thr->callstack_top - 1; #endif /* [ ... func this arg1 ... argN ] */ @@ -1479,7 +1477,7 @@ /* [ ... func this arg1 ... argN envobj ] */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; act->lex_env = env; act->var_env = env; DUK_HOBJECT_INCREF(thr, env); @@ -1494,6 +1492,7 @@ DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func)); duk__handle_oldenv_for_call(thr, func, act); + /* No need to re-lookup 'act' at present: no side effects. */ DUK_ASSERT(act->lex_env != NULL); DUK_ASSERT(act->var_env != NULL); @@ -1530,6 +1529,7 @@ * new value stack bottom, and call the target. */ + act = thr->callstack_curr; if (func != NULL && DUK_HOBJECT_IS_COMPFUNC(func)) { /* * Ecmascript call @@ -1572,10 +1572,9 @@ DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); /* may need unwind */ DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1); - DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1); - duk_hthread_catchstack_unwind(thr, entry_catchstack_top); + duk_hthread_catchstack_unwind_norz(thr, entry_catchstack_top); duk_hthread_catchstack_shrink_check(thr); - duk_hthread_callstack_unwind(thr, entry_callstack_top); + duk_hthread_callstack_unwind_norz(thr, entry_callstack_top); /* XXX: may now fail */ duk_hthread_callstack_shrink_check(thr); thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index; @@ -1637,7 +1636,7 @@ DUK_ASSERT(thr->catchstack_top == entry_catchstack_top); /* no need to unwind */ DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1); - duk_hthread_callstack_unwind(thr, entry_callstack_top); + duk_hthread_callstack_unwind_norz(thr, entry_callstack_top); duk_hthread_callstack_shrink_check(thr); thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index; @@ -1692,9 +1691,12 @@ DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */ thr->state = (duk_uint8_t) entry_thread_state; + /* Disabled assert: triggered with some torture tests. */ +#if 0 DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */ (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */ (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */ +#endif thr->heap->call_recursion_depth = entry_call_recursion_depth; @@ -1707,7 +1709,7 @@ * on every return should have no ill effect. */ #if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + if (duk_debug_is_attached(thr->heap)) { DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt")); DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init); thr->interrupt_init -= thr->interrupt_counter; @@ -1720,6 +1722,14 @@ duk__interrupt_fixup(thr, entry_curr_thread); #endif + /* Restored by success path. */ + DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth); + DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc); + + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + + DUK_REFZERO_CHECK_FAST(thr); + return; thread_state_error: @@ -1751,6 +1761,7 @@ * the error here. */ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW); + DUK_ASSERT_LJSTATE_SET(thr->heap); DUK_ASSERT(thr->callstack_top >= entry_callstack_top); DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); @@ -1772,9 +1783,9 @@ * scopes; this is a sandboxing issue, described in: * https://github.com/svaarala/duktape/issues/476 */ - duk_hthread_catchstack_unwind(thr, entry_catchstack_top); + duk_hthread_catchstack_unwind_norz(thr, entry_catchstack_top); duk_hthread_catchstack_shrink_check(thr); - duk_hthread_callstack_unwind(thr, entry_callstack_top); + duk_hthread_callstack_unwind_norz(thr, entry_callstack_top); duk_hthread_callstack_shrink_check(thr); thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index; @@ -1825,9 +1836,12 @@ DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */ thr->state = (duk_uint8_t) entry_thread_state; + /* Disabled assert: triggered with some torture tests. */ +#if 0 DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */ (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */ (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */ +#endif thr->heap->call_recursion_depth = entry_call_recursion_depth; @@ -1840,7 +1854,7 @@ * on every return should have no ill effect. */ #if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + if (duk_debug_is_attached(thr->heap)) { DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt")); DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init); thr->interrupt_init -= thr->interrupt_counter; @@ -1852,6 +1866,21 @@ #if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG) duk__interrupt_fixup(thr, entry_curr_thread); #endif + + /* Error handling complete, remove side effect protections and + * process pending finalizers. + */ +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(thr->heap->error_not_allowed == 1); + thr->heap->error_not_allowed = 0; +#endif + DUK_ASSERT(thr->heap->pf_prevent_count > 0); + thr->heap->pf_prevent_count--; + DUK_DD(DUK_DDPRINT("call error handled, pf_prevent_count updated to %ld", (long) thr->heap->pf_prevent_count)); + + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + + DUK_REFZERO_CHECK_SLOW(thr); } /* @@ -1949,12 +1978,6 @@ entry_callstack_top, entry_catchstack_top); - /* Longjmp state is kept clean in success path */ - DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN); - DUK_ASSERT(thr->heap->lj.iserror == 0); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1)); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); - /* Note: either pointer may be NULL (at entry), so don't assert */ thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr; @@ -1974,12 +1997,6 @@ entry_catchstack_top, old_jmpbuf_ptr); - /* Longjmp state is cleaned up by error handling */ - DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN); - DUK_ASSERT(thr->heap->lj.iserror == 0); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1)); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); - retval = DUK_EXEC_ERROR; } #if defined(DUK_USE_CPP_EXCEPTIONS) @@ -2024,6 +2041,8 @@ DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == old_jmpbuf_ptr); /* success/error path both do this */ + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + duk__handle_safe_call_shared(thr, idx_retbase, num_stack_rets, @@ -2138,6 +2157,10 @@ DUK_ASSERT(thr->callstack_top == entry_callstack_top); duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, rc); + + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + + DUK_REFZERO_CHECK_FAST(thr); return; thread_state_error: @@ -2172,6 +2195,7 @@ * the error here. */ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW); + DUK_ASSERT_LJSTATE_SET(thr->heap); DUK_ASSERT(thr->callstack_top >= entry_callstack_top); DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); @@ -2180,9 +2204,9 @@ DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); DUK_ASSERT(thr->callstack_top >= entry_callstack_top); - duk_hthread_catchstack_unwind(thr, entry_catchstack_top); + duk_hthread_catchstack_unwind_norz(thr, entry_catchstack_top); duk_hthread_catchstack_shrink_check(thr); - duk_hthread_callstack_unwind(thr, entry_callstack_top); + duk_hthread_callstack_unwind_norz(thr, entry_callstack_top); duk_hthread_callstack_shrink_check(thr); thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index; @@ -2214,6 +2238,21 @@ thr->heap->lj.iserror = 0; DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */ + + /* Error handling complete, remove side effect protections and + * process pending finalizers. + */ +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(thr->heap->error_not_allowed == 1); + thr->heap->error_not_allowed = 0; +#endif + DUK_ASSERT(thr->heap->pf_prevent_count > 0); + thr->heap->pf_prevent_count--; + DUK_DD(DUK_DDPRINT("safe call error handled, pf_prevent_count updated to %ld", (long) thr->heap->pf_prevent_count)); + + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + + DUK_REFZERO_CHECK_SLOW(thr); } DUK_LOCAL void duk__handle_safe_call_shared(duk_hthread *thr, @@ -2260,6 +2299,8 @@ #if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG) duk__interrupt_fixup(thr, entry_curr_thread); #endif + + DUK_ASSERT_LJSTATE_UNSET(thr->heap); } /* @@ -2447,7 +2488,8 @@ DUK_ASSERT(thr->callstack_top >= 1); DUK_ASSERT((call_flags & DUK_CALL_FLAG_IS_RESUME) == 0); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) { /* See: test-bug-tailcall-preventyield-assert.c. */ DUK_DDD(DUK_DDDPRINT("tail call prevented by current activation having DUK_ACT_FLAG_PREVENTYIELD")); @@ -2494,16 +2536,17 @@ break; } } - duk_hthread_catchstack_unwind(thr, i_stk + 1); + duk_hthread_catchstack_unwind_norz(thr, i_stk + 1); /* Unwind the topmost callstack entry before reusing it */ DUK_ASSERT(thr->callstack_top > 0); - duk_hthread_callstack_unwind(thr, thr->callstack_top - 1); + duk_hthread_callstack_unwind_norz(thr, thr->callstack_top - 1); /* Then reuse the unwound activation; callstack was not shrunk so there is always space */ + DUK_ASSERT(thr->callstack_top < thr->callstack_size); + act = thr->callstack + thr->callstack_top; thr->callstack_top++; - DUK_ASSERT(thr->callstack_top <= thr->callstack_size); - act = thr->callstack + thr->callstack_top - 1; + thr->callstack_curr = act; /* Start filling in the activation */ act->func = func; /* don't want an intermediate exposed state with func == NULL */ @@ -2520,7 +2563,7 @@ DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */ #if defined(DUK_USE_REFERENCE_COUNTING) DUK_HOBJECT_INCREF(thr, func); - act = thr->callstack + thr->callstack_top - 1; /* side effects (currently none though) */ + act = thr->callstack_curr; /* side effects (currently none though) */ #endif #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) @@ -2532,7 +2575,7 @@ * is in use. */ duk__update_func_caller_prop(thr, func); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; #endif act->flags = (DUK_HOBJECT_HAS_STRICT(func) ? @@ -2589,7 +2632,7 @@ DUK_DDD(DUK_DDDPRINT("update to current activation idx_retval")); DUK_ASSERT(thr->callstack_top < thr->callstack_size); DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL); DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act))); act->idx_retval = entry_valstack_bottom_index + idx_func; @@ -2598,6 +2641,7 @@ DUK_ASSERT(thr->callstack_top < thr->callstack_size); act = thr->callstack + thr->callstack_top; thr->callstack_top++; + thr->callstack_curr = act; DUK_ASSERT(thr->callstack_top <= thr->callstack_size); DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); @@ -2630,7 +2674,7 @@ #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) duk__update_func_caller_prop(thr, func); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; #endif } @@ -2659,6 +2703,7 @@ */ duk__handle_oldenv_for_call(thr, func, act); + /* No need to re-lookup 'act' at present: no side effects. */ DUK_ASSERT(act->lex_env != NULL); DUK_ASSERT(act->var_env != NULL); @@ -2688,7 +2733,7 @@ /* [ ... arg1 ... argN envobj ] */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; act->lex_env = env; act->var_env = env; DUK_HOBJECT_INCREF(thr, act->lex_env); @@ -2724,5 +2769,6 @@ * the topmost activation. */ + DUK_REFZERO_CHECK_FAST(thr); return 1; } diff -Nru duktape-2.0.0/src-input/duk_js_compiler.c duktape-2.1.1/src-input/duk_js_compiler.c --- duktape-2.0.0/src-input/duk_js_compiler.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_js_compiler.c 2017-07-28 22:05:08.000000000 +0000 @@ -1998,6 +1998,8 @@ duk_pop(ctx); return ret; #else + DUK_UNREF(comp_ctx); + DUK_UNREF(rc); DUK_ASSERT((rc & DUK__CONST_MARKER) == 0); /* caller removes const marker */ return 0; #endif @@ -2249,15 +2251,31 @@ DUK_DDD(DUK_DDDPRINT("arith inline check: d1=%lf, d2=%lf, op=%ld", (double) d1, (double) d2, (long) x->op)); switch (x->op) { - case DUK_OP_ADD: d3 = d1 + d2; break; - case DUK_OP_SUB: d3 = d1 - d2; break; - case DUK_OP_MUL: d3 = d1 * d2; break; - case DUK_OP_DIV: d3 = d1 / d2; break; + case DUK_OP_ADD: { + d3 = d1 + d2; + break; + } + case DUK_OP_SUB: { + d3 = d1 - d2; + break; + } + case DUK_OP_MUL: { + d3 = d1 * d2; + break; + } + case DUK_OP_DIV: { + d3 = d1 / d2; + break; + } case DUK_OP_EXP: { d3 = (duk_double_t) duk_js_arith_pow((double) d1, (double) d2); break; } - default: accept_fold = 0; break; + default: { + d3 = 0.0; /* Won't be used, but silence MSVC /W4 warning. */ + accept_fold = 0; + break; + } } if (accept_fold) { @@ -6171,6 +6189,7 @@ duk_small_uint_t stmt_flags = 0; duk_int_t label_id = -1; duk_small_uint_t tok; + duk_bool_t test_func_decl; DUK__RECURSION_INCREASE(comp_ctx, thr); @@ -6236,17 +6255,15 @@ * for function statements are modelled after V8, see * test-dev-func-decl-outside-top.js. */ - + test_func_decl = allow_source_elem; #if defined(DUK_USE_NONSTD_FUNC_STMT) /* Lenient: allow function declarations outside top level in * non-strict mode but reject them in strict mode. */ - if (allow_source_elem || !comp_ctx->curr_func.is_strict) -#else /* DUK_USE_NONSTD_FUNC_STMT */ - /* Strict: never allow function declarations outside top level. */ - if (allow_source_elem) + test_func_decl = test_func_decl || !comp_ctx->curr_func.is_strict; #endif /* DUK_USE_NONSTD_FUNC_STMT */ - { + /* Strict: never allow function declarations outside top level. */ + if (test_func_decl) { /* FunctionDeclaration: not strictly a statement but handled as such. * * O(depth^2) parse count for inner functions is handled by recording a @@ -6958,6 +6975,9 @@ (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1))); +#if defined(DUK_USE_FASTINT) + DUK_ASSERT(DUK_TVAL_IS_NULL(duk_get_tval(ctx, -1)) || DUK_TVAL_IS_FASTINT(duk_get_tval(ctx, -1))); +#endif duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */ } @@ -7023,8 +7043,7 @@ duk_push_null(ctx); declvar_flags = DUK_PROPDESC_FLAG_WRITABLE | - DUK_PROPDESC_FLAG_ENUMERABLE | - DUK_BC_DECLVAR_FLAG_UNDEF_VALUE; + DUK_PROPDESC_FLAG_ENUMERABLE; if (configurable_bindings) { declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE; } @@ -7701,9 +7720,9 @@ DUK_ASSERT(lex_pt != NULL); flags = comp_stk->flags; - is_eval = (flags & DUK_JS_COMPILE_FLAG_EVAL ? 1 : 0); - is_strict = (flags & DUK_JS_COMPILE_FLAG_STRICT ? 1 : 0); - is_funcexpr = (flags & DUK_JS_COMPILE_FLAG_FUNCEXPR ? 1 : 0); + is_eval = (flags & DUK_COMPILE_EVAL ? 1 : 0); + is_strict = (flags & DUK_COMPILE_STRICT ? 1 : 0); + is_funcexpr = (flags & DUK_COMPILE_FUNCEXPR ? 1 : 0); h_filename = duk_get_hstring(ctx, -1); /* may be undefined */ @@ -7779,7 +7798,7 @@ */ DUK_ASSERT(func->is_setget == 0); - func->is_strict = is_strict; + func->is_strict = (duk_uint8_t) is_strict; DUK_ASSERT(func->is_notail == 0); if (is_funcexpr) { @@ -7794,8 +7813,9 @@ (void) duk__parse_func_like_raw(comp_ctx, 0 /*flags*/); } else { DUK_ASSERT(func->is_function == 0); - func->is_eval = is_eval; - func->is_global = !is_eval; + DUK_ASSERT(is_eval == 0 || is_eval == 1); + func->is_eval = (duk_uint8_t) is_eval; + func->is_global = (duk_uint8_t) !is_eval; DUK_ASSERT(func->is_namebinding == 0); DUK_ASSERT(func->is_constructable == 0); @@ -7835,6 +7855,7 @@ DUK_LEXER_INITCTX(&comp_stk.comp_ctx_alloc.lex); comp_stk.comp_ctx_alloc.lex.input = src_buffer; comp_stk.comp_ctx_alloc.lex.input_length = src_length; + comp_stk.comp_ctx_alloc.lex.flags = flags; /* Forward flags directly for now. */ /* [ ... filename ] */ diff -Nru duktape-2.0.0/src-input/duk_js_compiler.h duktape-2.1.1/src-input/duk_js_compiler.h --- duktape-2.0.0/src-input/duk_js_compiler.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_js_compiler.h 2017-07-28 22:05:08.000000000 +0000 @@ -222,10 +222,6 @@ * Prototypes */ -#define DUK_JS_COMPILE_FLAG_EVAL (1 << 0) /* source is eval code (not global) */ -#define DUK_JS_COMPILE_FLAG_STRICT (1 << 1) /* strict outer context */ -#define DUK_JS_COMPILE_FLAG_FUNCEXPR (1 << 2) /* source is a function expression (used for Function constructor) */ - DUK_INTERNAL_DECL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer, duk_size_t src_length, duk_small_uint_t flags); #endif /* DUK_JS_COMPILER_H_INCLUDED */ diff -Nru duktape-2.0.0/src-input/duk_js_executor.c duktape-2.1.1/src-input/duk_js_executor.c --- duktape-2.0.0/src-input/duk_js_executor.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_js_executor.c 2017-07-28 22:05:08.000000000 +0000 @@ -276,7 +276,7 @@ break; } default: { - DUK_UNREACHABLE(); + /* Possible with DUK_OP_EXP. */ goto skip_fastint; } } @@ -533,8 +533,7 @@ if (DUK_TVAL_IS_NUMBER(tv)) { d1 = DUK_TVAL_GET_NUMBER(tv); } else { - d1 = duk_to_number(ctx, idx_src); /* side effects, perform in-place */ - DUK_ASSERT(DUK_TVAL_IS_NUMBER(DUK_GET_TVAL_POSIDX(ctx, idx_src))); + d1 = duk_to_number_tval(ctx, tv); /* side effects */ } if (opcode == DUK_OP_UNP) { @@ -586,7 +585,9 @@ else #endif /* DUK_USE_FASTINT */ { - i1 = duk_to_int32(ctx, idx_src); /* side effects */ + duk_push_tval(ctx, tv); + i1 = duk_to_int32(ctx, -1); /* side effects */ + duk_pop_unsafe(ctx); } /* Result is always fastint compatible. */ @@ -729,7 +730,7 @@ DUK_ASSERT(DUK_TVAL_IS_STRING(tv_id)); name = DUK_TVAL_GET_STRING(tv_id); DUK_ASSERT(name != NULL); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [ ... val this ] */ /* XXX: Fastint fast path would be useful here. Also fastints @@ -748,11 +749,13 @@ if (op & 0x02) { duk_push_number(ctx, y); /* -> [ ... x this y ] */ + act = thr->callstack_curr; duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(ctx, -1), is_strict); duk_pop_2(ctx); /* -> [ ... x ] */ } else { duk_pop_2(ctx); /* -> [ ... ] */ duk_push_number(ctx, y); /* -> [ ... y ] */ + act = thr->callstack_curr; duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(ctx, -1), is_strict); } @@ -882,17 +885,19 @@ duk__set_catcher_regs(thr, cat_idx, tv_val_unstable, lj_type); - duk_hthread_catchstack_unwind(thr, cat_idx + 1); - duk_hthread_callstack_unwind(thr, thr->catchstack[cat_idx].callstack_index + 1); + duk_hthread_catchstack_unwind_norz(thr, cat_idx + 1); + duk_hthread_callstack_unwind_norz(thr, thr->catchstack[cat_idx].callstack_index + 1); DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))); + DUK_ASSERT(thr->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); duk__reconfig_valstack_ecma_catcher(thr, thr->callstack_top - 1, cat_idx); DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); act->curr_pc = thr->catchstack[cat_idx].pc_base + 0; /* +0 = catch */ act = NULL; @@ -907,8 +912,7 @@ */ if (DUK_CAT_HAS_CATCH_BINDING_ENABLED(&thr->catchstack[cat_idx])) { - duk_hobject *new_env; - duk_hobject *act_lex_env; + duk_hdecenv *new_env; DUK_DDD(DUK_DDDPRINT("catcher has an automatic catch binding")); @@ -916,7 +920,8 @@ * points, so we re-lookup it multiple times. */ DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); if (act->lex_env == NULL) { DUK_ASSERT(act->var_env == NULL); @@ -924,22 +929,26 @@ /* this may have side effects, so re-lookup act */ duk_js_init_activation_environment_records_delayed(thr, act); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); } DUK_ASSERT(act->lex_env != NULL); DUK_ASSERT(act->var_env != NULL); DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL); DUK_UNREF(act); /* unreferenced without assertions */ - act = thr->callstack + thr->callstack_top - 1; - act_lex_env = act->lex_env; - act = NULL; /* invalidated */ - - new_env = duk_push_object_helper_proto(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), - act_lex_env); + /* XXX: If an out-of-memory happens here, longjmp state asserts + * will be triggered at present and a try-catch fails to catch. + * That's not sandboxing fatal (C API protected calls are what + * matters), and script catch code can immediately throw anyway + * for almost any operation. + */ + 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(ctx, (duk_hobject *) new_env); + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL); DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", (duk_heaphdr *) new_env)); /* Note: currently the catch binding is handled without a register @@ -948,14 +957,20 @@ * record regbases etc. */ + /* XXX: duk_xdef_prop() may cause an out-of-memory, see above. */ DUK_ASSERT(thr->catchstack[cat_idx].h_varname != NULL); duk_push_hstring(ctx, thr->catchstack[cat_idx].h_varname); duk_push_tval(ctx, thr->valstack + thr->catchstack[cat_idx].idx_base); duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_W); /* writable, not configurable */ - act = thr->callstack + thr->callstack_top - 1; - act->lex_env = new_env; - DUK_HOBJECT_INCREF(thr, new_env); /* reachable through activation */ + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); + DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, act->lex_env); + act->lex_env = (duk_hobject *) new_env; + DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env); /* reachable through activation */ + /* Net refcount change to act->lex_env is 0: incref for new_env's + * prototype, decref for act->lex_env overwrite. + */ DUK_CAT_SET_LEXENV_ACTIVE(&thr->catchstack[cat_idx]); @@ -975,17 +990,19 @@ duk__set_catcher_regs(thr, cat_idx, tv_val_unstable, lj_type); - duk_hthread_catchstack_unwind(thr, cat_idx + 1); /* cat_idx catcher is kept, even for finally */ - duk_hthread_callstack_unwind(thr, thr->catchstack[cat_idx].callstack_index + 1); + duk_hthread_catchstack_unwind_norz(thr, cat_idx + 1); /* cat_idx catcher is kept, even for finally */ + duk_hthread_callstack_unwind_norz(thr, thr->catchstack[cat_idx].callstack_index + 1); DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))); + DUK_ASSERT(thr->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); duk__reconfig_valstack_ecma_catcher(thr, thr->callstack_top - 1, cat_idx); DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); act->curr_pc = thr->catchstack[cat_idx].pc_base + 1; /* +1 = finally */ act = NULL; @@ -998,7 +1015,8 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL); DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(DUK_ACT_GET_FUNC(act))); @@ -1007,13 +1025,14 @@ act->curr_pc = thr->catchstack[cat_idx].pc_base + (lj_type == DUK_LJ_TYPE_CONTINUE ? 1 : 0); act = NULL; /* invalidated */ - duk_hthread_catchstack_unwind(thr, cat_idx + 1); /* keep label catcher */ + duk_hthread_catchstack_unwind_norz(thr, cat_idx + 1); /* keep label catcher */ /* no need to unwind callstack */ /* valstack should not need changes */ #if defined(DUK_USE_ASSERTIONS) DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) == (duk_size_t) ((duk_hcompfunc *) DUK_ACT_GET_FUNC(act))->nregs); #endif @@ -1035,7 +1054,7 @@ tv1 = resumer->valstack + resumer->callstack[act_idx].idx_retval; /* return value from Duktape.Thread.resume() */ DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable); /* side effects */ - duk_hthread_callstack_unwind(resumer, act_idx + 1); /* unwind to 'resume' caller */ + duk_hthread_callstack_unwind_norz(resumer, act_idx + 1); /* unwind to 'resume' caller */ /* no need to unwind catchstack */ duk__reconfig_valstack_ecma_return(resumer, act_idx); @@ -1098,10 +1117,11 @@ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged by Duktape.Thread.resume() */ DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))->func == duk_bi_thread_resume); - DUK_ASSERT_DISABLE((thr->callstack + thr->callstack_top - 2)->idx_retval >= 0); /* unsigned */ + DUK_ASSERT(thr->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack_curr))->func == duk_bi_thread_resume); + DUK_ASSERT_DISABLE((thr->callstack_curr - 1)->idx_retval >= 0); /* unsigned */ tv = &thr->heap->lj.value2; /* resumee */ DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); @@ -1116,11 +1136,11 @@ DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED || resumee->callstack_top >= 2); /* YIELDED: Ecmascript activation + Duktape.Thread.yield() activation */ DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED || - (DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1))->func == duk_bi_thread_yield)); + (DUK_ACT_GET_FUNC(resumee->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumee->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumee->callstack_curr))->func == duk_bi_thread_yield)); DUK_ASSERT_DISABLE(resumee->state != DUK_HTHREAD_STATE_YIELDED || - (resumee->callstack + resumee->callstack_top - 2)->idx_retval >= 0); /* idx_retval unsigned */ + (resumee->callstack_curr - 1)->idx_retval >= 0); /* idx_retval unsigned */ DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_INACTIVE || resumee->callstack_top == 0); /* INACTIVE: no activation, single function value on valstack */ @@ -1135,7 +1155,9 @@ * which we simply ignore. */ + DUK_ASSERT(resumee->resumer == NULL); resumee->resumer = thr; + DUK_HTHREAD_INCREF(thr, thr); resumee->state = DUK_HTHREAD_STATE_RUNNING; thr->state = DUK_HTHREAD_STATE_RESUMED; DUK_HEAP_SWITCH_THREAD(thr->heap, resumee); @@ -1159,13 +1181,15 @@ tv2 = &thr->heap->lj.value1; DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv2); /* side effects */ - duk_hthread_callstack_unwind(resumee, act_idx + 1); /* unwind to 'yield' caller */ + duk_hthread_callstack_unwind_norz(resumee, act_idx + 1); /* unwind to 'yield' caller */ /* no need to unwind catchstack */ duk__reconfig_valstack_ecma_return(resumee, act_idx); + DUK_ASSERT(resumee->resumer == NULL); resumee->resumer = thr; + DUK_HTHREAD_INCREF(thr, thr); resumee->state = DUK_HTHREAD_STATE_RUNNING; thr->state = DUK_HTHREAD_STATE_RESUMED; DUK_HEAP_SWITCH_THREAD(thr->heap, resumee); @@ -1201,7 +1225,9 @@ DUK_ERROR_INTERNAL(thr); } + DUK_ASSERT(resumee->resumer == NULL); resumee->resumer = thr; + DUK_HTHREAD_INCREF(thr, thr); resumee->state = DUK_HTHREAD_STATE_RUNNING; thr->state = DUK_HTHREAD_STATE_RESUMED; DUK_HEAP_SWITCH_THREAD(thr->heap, resumee); @@ -1234,28 +1260,31 @@ DUK_ASSERT(thr != entry_thread); /* Duktape.Thread.yield() should prevent */ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged from Duktape.Thread.yield() */ DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.yield() activation */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))->func == duk_bi_thread_yield); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2))); /* an Ecmascript function */ - DUK_ASSERT_DISABLE((thr->callstack + thr->callstack_top - 2)->idx_retval >= 0); /* unsigned */ + DUK_ASSERT(thr->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack_curr))->func == duk_bi_thread_yield); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr - 1) != NULL && + DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr - 1))); /* an Ecmascript function */ + DUK_ASSERT_DISABLE((thr->callstack_curr - 1)->idx_retval >= 0); /* unsigned */ resumer = thr->resumer; DUK_ASSERT(resumer != NULL); DUK_ASSERT(resumer->state == DUK_HTHREAD_STATE_RESUMED); /* written by a previous RESUME handling */ DUK_ASSERT(resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ - DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1))->func == duk_bi_thread_resume); - DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 2) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 2))); /* an Ecmascript function */ - DUK_ASSERT_DISABLE((resumer->callstack + resumer->callstack_top - 2)->idx_retval >= 0); /* unsigned */ + DUK_ASSERT(resumer->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumer->callstack_curr))->func == duk_bi_thread_resume); + DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr - 1) != NULL && + DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr - 1))); /* an Ecmascript function */ + DUK_ASSERT_DISABLE((resumer->callstack_curr - 1)->idx_retval >= 0); /* unsigned */ if (thr->heap->lj.iserror) { thr->state = DUK_HTHREAD_STATE_YIELDED; thr->resumer = NULL; + DUK_HTHREAD_DECREF_NORZ(thr, resumer); resumer->state = DUK_HTHREAD_STATE_RUNNING; DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); thr = resumer; @@ -1271,6 +1300,7 @@ thr->state = DUK_HTHREAD_STATE_YIELDED; thr->resumer = NULL; + DUK_HTHREAD_DECREF_NORZ(thr, resumer); resumer->state = DUK_HTHREAD_STATE_RUNNING; DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); #if 0 @@ -1351,9 +1381,9 @@ * final catcher unwind everything */ #if 0 - duk_hthread_catchstack_unwind(thr, (cat - thr->catchstack) + 1); /* leave 'cat' as top catcher (also works if catchstack exhausted) */ - duk_hthread_callstack_unwind(thr, entry_callstack_index + 1); - + duk_hthread_catchstack_unwind_norz(thr, (cat - thr->catchstack) + 1); /* leave 'cat' as top catcher (also works if catchstack exhausted) */ + duk_hthread_callstack_unwind_norz(thr, entry_callstack_index + 1); + DUK_REFZERO_CHECK_SLOW(thr); #endif DUK_D(DUK_DPRINT("-> throw propagated up to entry level, rethrow and exit bytecode executor")); retval = DUK__LONGJMP_RETHROW; @@ -1370,11 +1400,12 @@ DUK_ASSERT(thr->resumer != NULL); DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2))); /* an Ecmascript function */ + DUK_ASSERT(thr->resumer->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack_curr))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */ + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr - 1) != NULL && + DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr - 1))); /* an Ecmascript function */ resumer = thr->resumer; @@ -1387,6 +1418,7 @@ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED); thr->resumer = NULL; + DUK_HTHREAD_DECREF_NORZ(thr, resumer); resumer->state = DUK_HTHREAD_STATE_RUNNING; DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); thr = resumer; @@ -1415,6 +1447,8 @@ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */ + DUK_GC_TORTURE(thr->heap); + just_return: return retval; @@ -1555,6 +1589,7 @@ cat = thr->catchstack + thr->catchstack_top - 1; /* may be < thr->catchstack initially */ DUK_ASSERT(thr->callstack_top > 0); /* ensures callstack_top - 1 >= 0 */ + DUK_ASSERT(thr->callstack_curr != NULL); orig_callstack_index = thr->callstack_top - 1; while (cat >= thr->catchstack) { @@ -1602,22 +1637,22 @@ */ DUK_DDD(DUK_DDDPRINT("return to Ecmascript caller, idx_retval=%ld, lj_value1=%!T", - (long) (thr->callstack + thr->callstack_top - 2)->idx_retval, + (long) (thr->callstack_curr - 1)->idx_retval, (duk_tval *) &thr->heap->lj.value1)); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2))); /* must be ecmascript */ + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr - 1))); /* must be ecmascript */ - tv1 = thr->valstack + (thr->callstack + thr->callstack_top - 2)->idx_retval; + tv1 = thr->valstack + (thr->callstack_curr - 1)->idx_retval; DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom); tv2 = thr->valstack_top - 1; DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */ DUK_DDD(DUK_DDDPRINT("return value at idx_retval=%ld is %!T", - (long) (thr->callstack + thr->callstack_top - 2)->idx_retval, - (duk_tval *) (thr->valstack + (thr->callstack + thr->callstack_top - 2)->idx_retval))); + (long) (thr->callstack_curr - 1)->idx_retval, + (duk_tval *) (thr->valstack + (thr->callstack_curr - 1)->idx_retval))); - duk_hthread_catchstack_unwind(thr, new_cat_top); /* leave 'cat' as top catcher (also works if catchstack exhausted) */ - duk_hthread_callstack_unwind(thr, thr->callstack_top - 1); + duk_hthread_catchstack_unwind_norz(thr, new_cat_top); /* leave 'cat' as top catcher (also works if catchstack exhausted) */ + duk_hthread_callstack_unwind_norz(thr, thr->callstack_top - 1); duk__reconfig_valstack_ecma_return(thr, thr->callstack_top - 1); DUK_DD(DUK_DDPRINT("-> return not intercepted, restart execution in caller")); @@ -1629,12 +1664,13 @@ DUK_ASSERT(thr->resumer != NULL); DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2))); /* an Ecmascript function */ - DUK_ASSERT_DISABLE((thr->resumer->callstack + thr->resumer->callstack_top - 2)->idx_retval >= 0); /* unsigned */ + DUK_ASSERT(thr->resumer->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack_curr))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */ + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr - 1) != NULL && + DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr - 1))); /* an Ecmascript function */ + DUK_ASSERT_DISABLE((thr->resumer->callstack_curr - 1)->idx_retval >= 0); /* unsigned */ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED); @@ -1648,6 +1684,7 @@ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED); thr->resumer = NULL; + DUK_HTHREAD_DECREF(thr, resumer); resumer->state = DUK_HTHREAD_STATE_RUNNING; DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); #if 0 @@ -1706,7 +1743,8 @@ DUK_ASSERT(thr->heap->dbg_processing == 0); /* don't re-enter e.g. during Eval */ ctx = (duk_context *) thr; - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); /* It might seem that replacing 'thr->heap' with just 'heap' below * might be a good idea, but it increases code size slightly @@ -1731,8 +1769,7 @@ (line != thr->heap->dbg_step_startline)) { DUK_D(DUK_DPRINT("STEP STATE TRIGGERED PAUSE at line %ld", (long) line)); - - DUK_HEAP_SET_PAUSED(thr->heap); + duk_debug_set_paused(thr->heap); } /* Check for breakpoints only on line transition. @@ -1758,8 +1795,7 @@ if (act->prev_line != bp->line && line == bp->line) { DUK_D(DUK_DPRINT("BREAKPOINT TRIGGERED at %!O:%ld", (duk_heaphdr *) bp->filename, (long) bp->line)); - - DUK_HEAP_SET_PAUSED(thr->heap); + duk_debug_set_paused(thr->heap); } } } else { @@ -1846,8 +1882,9 @@ * above, so we must recheck attach status. */ - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { - act = thr->callstack + thr->callstack_top - 1; /* relookup, may have changed */ + if (duk_debug_is_attached(thr->heap)) { + act = thr->callstack_curr; /* relookup, may have changed */ + DUK_ASSERT(act != NULL); if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE || ((thr->heap->dbg_step_type == DUK_STEP_TYPE_INTO || thr->heap->dbg_step_type == DUK_STEP_TYPE_OVER) && @@ -1870,7 +1907,7 @@ } #endif /* DUK_USE_DEBUGGER_SUPPORT */ -DUK_LOCAL duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) { +DUK_LOCAL DUK_NOINLINE DUK_COLD duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) { duk_int_t ctr; duk_activation *act; duk_hcompfunc *fun; @@ -1920,7 +1957,8 @@ } DUK_HEAP_SET_INTERRUPT_RUNNING(thr->heap); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC((duk_hobject *) fun)); @@ -1956,7 +1994,7 @@ * detaching (to finish off the pending detach). */ duk__interrupt_handle_debugger(thr, &immediate, &retval); - act = thr->callstack + thr->callstack_top - 1; /* relookup if changed */ + act = thr->callstack_curr; /* relookup if changed */ DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */ } #endif /* DUK_USE_DEBUGGER_SUPPORT */ @@ -2098,7 +2136,7 @@ (thr->heap->dbg_step_thread != thr || thr->heap->dbg_step_csindex != thr->callstack_top - 1)) { DUK_D(DUK_DPRINT("STEP INTO ACTIVE, FORCE PAUSED")); - DUK_HEAP_SET_PAUSED(thr->heap); + duk_debug_set_paused(thr->heap); } /* Force interrupt right away if we're paused or in "checked mode". @@ -2153,7 +2191,7 @@ #if defined(DUK_USE_EXEC_FUN_LOCAL) #define DUK__FUN() fun #else -#define DUK__FUN() ((duk_hcompfunc *) DUK_ACT_GET_FUNC((thr)->callstack + (thr)->callstack_top - 1)) +#define DUK__FUN() ((duk_hcompfunc *) DUK_ACT_GET_FUNC((thr)->callstack_curr)) #endif #define DUK__STRICT() (DUK_HOBJECT_HAS_STRICT((duk_hobject *) DUK__FUN())) @@ -2230,12 +2268,12 @@ #define DUK__SYNC_CURR_PC() do { \ duk_activation *act; \ - act = thr->callstack + thr->callstack_top - 1; \ + act = thr->callstack_curr; \ act->curr_pc = curr_pc; \ } while (0) #define DUK__SYNC_AND_NULL_CURR_PC() do { \ duk_activation *act; \ - act = thr->callstack + thr->callstack_top - 1; \ + act = thr->callstack_curr; \ act->curr_pc = curr_pc; \ thr->ptr_curr_pc = NULL; \ } while (0) @@ -2287,15 +2325,27 @@ lj_ret = duk__handle_longjmp(heap->curr_thread, entry_thread, entry_callstack_top); + /* Error handling complete, remove side effect protections. + */ +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(heap->error_not_allowed == 1); + heap->error_not_allowed = 0; +#endif + DUK_ASSERT(heap->pf_prevent_count > 0); + heap->pf_prevent_count--; + DUK_DD(DUK_DDPRINT("executor error handled, pf_prevent_count updated to %ld", (long) heap->pf_prevent_count)); + if (lj_ret == DUK__LONGJMP_RESTART) { /* Restart bytecode execution, possibly with a changed thread. */ - ; + DUK_REFZERO_CHECK_SLOW(heap->curr_thread); } else { - /* Rethrow error to calling state. */ - DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW); + /* If an error is propagated, don't run refzero checks here. + * The next catcher will deal with that. Pf_prevent_count + * will be re-bumped by the longjmp. + */ - /* Longjmp handling has restored jmpbuf_ptr. */ - DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr); + DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW); /* Rethrow error to calling state. */ + DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr); /* Longjmp handling has restored jmpbuf_ptr. */ /* Thread may have changed, e.g. YIELD converted to THROW. */ duk_err_longjmp(heap->curr_thread); @@ -2318,8 +2368,10 @@ DUK_ASSERT(exec_thr->heap->curr_thread != NULL); DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR((duk_heaphdr *) exec_thr); DUK_ASSERT(exec_thr->callstack_top >= 1); /* at least one activation, ours */ - DUK_ASSERT(DUK_ACT_GET_FUNC(exec_thr->callstack + exec_thr->callstack_top - 1) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(exec_thr->callstack + exec_thr->callstack_top - 1))); + DUK_ASSERT(DUK_ACT_GET_FUNC(exec_thr->callstack_curr) != NULL); + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(exec_thr->callstack_curr))); + + DUK_GC_TORTURE(exec_thr->heap); entry_thread = exec_thr; heap = entry_thread->heap; @@ -2410,7 +2462,7 @@ } /* Inner executor, performance critical. */ -DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_size_t entry_callstack_top) { +DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_size_t entry_callstack_top) { /* Current PC, accessed by other functions through thr->ptr_to_curr_pc. * Critical for performance. It would be safest to make this volatile, * but that eliminates performance benefits; aliasing guarantees @@ -2451,6 +2503,8 @@ #endif #endif + DUK_GC_TORTURE(entry_thread->heap); + /* * Restart execution by reloading thread state. * @@ -2500,8 +2554,11 @@ thr = entry_thread->heap->curr_thread; DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))); + DUK_ASSERT(thr->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); + + DUK_GC_TORTURE(thr->heap); thr->ptr_curr_pc = &curr_pc; @@ -2515,7 +2572,8 @@ /* Assume interrupt init/counter are properly initialized here. */ /* Assume that thr->valstack_bottom has been set-up before getting here. */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); DUK_ASSERT(fun != NULL); DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == fun->nregs); @@ -2523,9 +2581,10 @@ DUK_ASSERT(consts != NULL); #if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap) && !thr->heap->dbg_processing) { + if (duk_debug_is_attached(thr->heap) && !thr->heap->dbg_processing) { duk__executor_recheck_debugger(thr, act, fun); - act = thr->callstack + thr->callstack_top - 1; /* relookup after side effects (no side effects currently however) */ + act = thr->callstack_curr; /* relookup after side effects (no side effects currently however) */ + DUK_ASSERT(act != NULL); } #endif /* DUK_USE_DEBUGGER_SUPPORT */ @@ -2575,10 +2634,11 @@ duk_small_uint_t exec_int_ret; /* Write curr_pc back for the debugger. */ - DUK_ASSERT(thr->callstack_top > 0); { duk_activation *act; - act = thr->callstack + thr->callstack_top - 1; + DUK_ASSERT(thr->callstack_top > 0); + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); act->curr_pc = (duk_instr_t *) curr_pc; } @@ -2612,7 +2672,7 @@ #if defined(DUK_USE_ASSERTIONS) || defined(DUK_USE_DEBUG) { duk_activation *act; - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; DUK_ASSERT(curr_pc >= DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, DUK__FUN())); DUK_ASSERT(curr_pc < DUK_HCOMPFUNC_GET_CODE_END(thr->heap, DUK__FUN())); DUK_UNREF(act); /* if debugging disabled */ @@ -2904,7 +2964,7 @@ DUK_ASSERT(DUK_TVAL_IS_STRING(tv)); name = DUK_TVAL_GET_STRING(tv); tv = NULL; /* lookup has side effects */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; if (duk_js_getvar_activation(thr, act, name, 0 /*throw*/)) { /* -> [... val this] */ tv = DUK_GET_TVAL_NEGIDX(ctx, -2); @@ -3632,14 +3692,12 @@ duk_hstring *name; duk_small_uint_t prop_flags; duk_bool_t is_func_decl; - duk_bool_t is_undef_value; tv1 = DUK__REGCONSTP_B(ins); DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); name = DUK_TVAL_GET_STRING(tv1); DUK_ASSERT(name != NULL); - is_undef_value = ((a & DUK_BC_DECLVAR_FLAG_UNDEF_VALUE) != 0); is_func_decl = ((a & DUK_BC_DECLVAR_FLAG_FUNC_DECL) != 0); /* XXX: declvar takes an duk_tval pointer, which is awkward and @@ -3651,19 +3709,25 @@ */ prop_flags = a & DUK_PROPDESC_FLAGS_MASK; - if (is_undef_value) { + if (is_func_decl) { + duk_push_tval(ctx, DUK__REGCONSTP_C(ins)); + } else { DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */ thr->valstack_top++; - } else { - duk_push_tval(ctx, DUK__REGCONSTP_C(ins)); } tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; if (duk_js_declvar_activation(thr, act, name, tv1, prop_flags, is_func_decl)) { - /* already declared, must update binding value */ - tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1); - duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT()); + if (is_func_decl) { + /* Already declared, update value. */ + tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1); + duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT()); + } else { + /* Already declared but no initializer value + * (e.g. 'var xyz;'), no-op. + */ + } } duk_pop(ctx); @@ -3717,7 +3781,7 @@ DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); name = DUK_TVAL_GET_STRING(tv1); DUK_ASSERT(name != NULL); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */ idx = (duk_uint_fast_t) DUK_DEC_A(ins); @@ -3744,7 +3808,7 @@ DUK_ASSERT_DISABLE(bc >= 0); /* unsigned */ DUK_ASSERT((duk_uint_t) bc < (duk_uint_t) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, DUK__FUN())); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; fun_act = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); fun_temp = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, fun_act)[bc]; DUK_ASSERT(fun_temp != NULL); @@ -3756,6 +3820,7 @@ if (act->lex_env == NULL) { DUK_ASSERT(act->var_env == NULL); duk_js_init_activation_environment_records_delayed(thr, act); + act = thr->callstack_curr; } DUK_ASSERT(act->lex_env != NULL); DUK_ASSERT(act->var_env != NULL); @@ -3782,7 +3847,7 @@ DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); name = DUK_TVAL_GET_STRING(tv1); DUK_ASSERT(name != NULL); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */ duk_pop(ctx); /* 'this' binding is not needed here */ DUK__REPLACE_TOP_A_BREAK(); @@ -3803,7 +3868,7 @@ */ tv1 = DUK__REGP_A(ins); /* val */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT()); break; } @@ -3818,7 +3883,7 @@ DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); name = DUK_TVAL_GET_STRING(tv1); DUK_ASSERT(name != NULL); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; rc = duk_js_delvar_activation(thr, act, name); DUK__REPLACE_BOOL_A_BREAK(rc); } @@ -3879,6 +3944,7 @@ thr->valstack_top++; DUK__RETURN_SHARED(); } + /* This will be unused without refcounting. */ case DUK_OP_RETCONST: { duk_tval *tv; @@ -3895,7 +3961,10 @@ DUK__SYNC_AND_NULL_CURR_PC(); tv = DUK__CONSTP_BC(ins); DUK_TVAL_SET_TVAL(thr->valstack_top, tv); +#if defined(DUK_USE_REFERENCE_COUNTING) + /* Without refcounting only RETCONSTN is used. */ DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv)); /* no INCREF for this constant */ +#endif thr->valstack_top++; DUK__RETURN_SHARED(); } @@ -4019,57 +4088,44 @@ a = DUK_DEC_A(ins); bc = DUK_DEC_BC(ins); - act = thr->callstack + thr->callstack_top - 1; - DUK_ASSERT(thr->callstack_top >= 1); - - /* 'with' target must be created first, in case we run out of memory */ - /* XXX: refactor out? */ - - if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) { - DUK_DDD(DUK_DDDPRINT("need to initialize a with binding object")); - - if (act->lex_env == NULL) { - DUK_ASSERT(act->var_env == NULL); - DUK_DDD(DUK_DDDPRINT("delayed environment initialization")); - - /* must relookup act in case of side effects */ - duk_js_init_activation_environment_records_delayed(thr, act); - act = thr->callstack + thr->callstack_top - 1; - DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */ - } - DUK_ASSERT(act->lex_env != NULL); - DUK_ASSERT(act->var_env != NULL); - - (void) duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV), - -1); /* no prototype, updated below */ - - duk_push_tval(ctx, DUK__REGP(bc)); - duk_to_object(ctx, -1); - duk_dup_top(ctx); - - /* [ ... env target ] */ - /* [ ... env target target ] */ - - duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); /* always provideThis=true */ - - /* [ ... env ] */ + /* Registers 'bc' and 'bc + 1' are written in longjmp handling + * and if their previous values (which are temporaries) become + * unreachable -and- have a finalizer, there'll be a function + * call during error handling which is not supported now (GH-287). + * Ensure that both 'bc' and 'bc + 1' have primitive values to + * guarantee no finalizer calls in error handling. Scrubbing also + * ensures finalizers for the previous values run here rather than + * later. Error handling related values are also written to 'bc' + * and 'bc + 1' but those values never become unreachable during + * error handling, so there's no side effect problem even if the + * error value has a finalizer. + */ + duk_dup(ctx, bc); /* Stabilize value. */ + duk_to_undefined(ctx, bc); + duk_to_undefined(ctx, bc + 1); - DUK_DDD(DUK_DDDPRINT("environment for with binding: %!iT", - (duk_tval *) duk_get_tval(ctx, -1))); - } + /* Ensure a catchstack entry is available. One entry + * is guaranteed even if side effects cause function + * calls and the catchstack is shrunk because some + * spare room is left behind by a shrink operation. + */ + duk_hthread_catchstack_grow(thr); - /* allocate catcher and populate it (should be atomic) */ + /* Allocate catcher and populate it. Doesn't have to + * be fully atomic, but the catcher must be in a + * consistent state if side effects (such as finalizer + * calls) occur. + */ - duk_hthread_catchstack_grow(thr); - cat = thr->catchstack + thr->catchstack_top; DUK_ASSERT(thr->catchstack_top + 1 <= thr->catchstack_size); + cat = thr->catchstack + thr->catchstack_top; thr->catchstack_top++; cat->flags = DUK_CAT_TYPE_TCF; cat->h_varname = NULL; + cat->callstack_index = thr->callstack_top - 1; + cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */ + cat->idx_base = (duk_size_t) (thr->valstack_bottom - thr->valstack) + bc; if (a & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) { cat->flags |= DUK_CAT_FLAG_CATCH_ENABLED; @@ -4080,7 +4136,7 @@ if (a & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING) { DUK_DDD(DUK_DDDPRINT("catch binding flag set to catcher")); cat->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED; - tv1 = DUK__REGP(bc); + tv1 = DUK_GET_TVAL_NEGIDX(thr, -1); DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); /* borrowed reference; although 'tv1' comes from a register, @@ -4089,54 +4145,69 @@ */ cat->h_varname = DUK_TVAL_GET_STRING(tv1); } else if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) { - /* env created above to stack top */ - duk_hobject *new_env; + duk_hobjenv *env; + duk_hobject *target; - DUK_DDD(DUK_DDDPRINT("lexenv active flag set to catcher")); - cat->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE; + /* Delayed env initialization for activation (if needed). */ + DUK_ASSERT(thr->callstack_top >= 1); + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); + if (act->lex_env == NULL) { + DUK_DDD(DUK_DDDPRINT("delayed environment initialization")); + DUK_ASSERT(act->var_env == NULL); - DUK_DDD(DUK_DDDPRINT("activating object env: %!iT", - (duk_tval *) duk_get_tval(ctx, -1))); + duk_js_init_activation_environment_records_delayed(thr, act); + act = thr->callstack_curr; /* relookup, side effects */ + DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */ + } DUK_ASSERT(act->lex_env != NULL); - new_env = DUK_GET_HOBJECT_NEGIDX(ctx, -1); - DUK_ASSERT(new_env != NULL); + DUK_ASSERT(act->var_env != NULL); - act = thr->callstack + thr->callstack_top - 1; /* relookup (side effects) */ - DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, new_env, act->lex_env); /* side effects */ + /* Coerce 'with' target. */ + target = duk_to_hobject(ctx, -1); + DUK_ASSERT(target != NULL); + + /* Create an object environment; it is not pushed + * so avoid side effects very carefully until it is + * referenced. + */ + env = duk_hobjenv_alloc(thr, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV)); + DUK_ASSERT(env != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL); + env->target = target; /* always provideThis=true */ + DUK_HOBJECT_INCREF(thr, target); + env->has_this = 1; + DUK_ASSERT_HOBJENV_VALID(env); + DUK_DDD(DUK_DDDPRINT("environment for with binding: %!iO", env)); - act = thr->callstack + thr->callstack_top - 1; /* relookup (side effects) */ - act->lex_env = new_env; - DUK_HOBJECT_INCREF(thr, new_env); - duk_pop(ctx); + act = thr->callstack_curr; /* relookup (side effects) */ + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL); + DUK_ASSERT(act->lex_env != NULL); + DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) env, act->lex_env); + act->lex_env = (duk_hobject *) env; /* Now reachable. */ + DUK_HOBJECT_INCREF(thr, (duk_hobject *) env); + /* Net refcount change to act->lex_env is 0: incref for env's + * prototype, decref for act->lex_env overwrite. + */ + + /* Set catcher lex_env active (affects unwind) + * only when the whole setup is complete. + */ + cat = thr->catchstack + thr->catchstack_top - 1; + cat->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE; } else { ; } - /* Registers 'bc' and 'bc + 1' are written in longjmp handling - * and if their previous values (which are temporaries) become - * unreachable -and- have a finalizer, there'll be a function - * call during error handling which is not supported now (GH-287). - * Ensure that both 'bc' and 'bc + 1' have primitive values to - * guarantee no finalizer calls in error handling. Scrubbing also - * ensures finalizers for the previous values run here rather than - * later. Error handling related values are also written to 'bc' - * and 'bc + 1' but those values never become unreachable during - * error handling, so there's no side effect problem even if the - * error value has a finalizer. - */ - duk_to_undefined(ctx, bc); - duk_to_undefined(ctx, bc + 1); - - cat = thr->catchstack + thr->catchstack_top - 1; /* relookup (side effects) */ - cat->callstack_index = thr->callstack_top - 1; - cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */ - cat->idx_base = (duk_size_t) (thr->valstack_bottom - thr->valstack) + bc; - DUK_DDD(DUK_DDDPRINT("TRYCATCH catcher: flags=0x%08lx, callstack_index=%ld, pc_base=%ld, " "idx_base=%ld, h_varname=%!O", (unsigned long) cat->flags, (long) cat->callstack_index, (long) cat->pc_base, (long) cat->idx_base, (duk_heaphdr *) cat->h_varname)); + duk_pop(ctx); + curr_pc += 2; /* skip jump slots */ break; } @@ -4190,7 +4261,8 @@ cat = thr->catchstack + thr->catchstack_top - 1; DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat)); /* cleared before entering catch part */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) { duk_hobject *prev_env; @@ -4205,6 +4277,7 @@ DUK_ASSERT(prev_env != NULL); act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, prev_env); DUK_CAT_CLEAR_LEXENV_ACTIVE(cat); + DUK_HOBJECT_INCREF(thr, act->lex_env); DUK_HOBJECT_DECREF(thr, prev_env); /* side effects */ } @@ -4329,7 +4402,8 @@ duk_push_tval(ctx, thr->valstack + cat->idx_base); - duk_err_setup_heap_ljstate(thr, (duk_small_int_t) cont_type); + duk_err_setup_ljstate1(thr, (duk_small_int_t) cont_type, thr->valstack + cat->idx_base); + /* No debugger Throw notify check on purpose (rethrow). */ DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */ duk_err_longjmp(thr); @@ -4366,7 +4440,10 @@ (duk_tval *) duk_get_tval(ctx, -1))); #endif - duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW); + duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(ctx, -1)); +#if defined(DUK_USE_DEBUGGER_SUPPORT) + duk_err_check_debugger_integration(thr); +#endif DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */ duk_err_longjmp(thr); @@ -4903,7 +4980,7 @@ * from precompiled bytecode. */ #if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + if (duk_debug_is_attached(thr->heap)) { DUK_D(DUK_DPRINT("DEBUGGER statement encountered, halt execution")); DUK__SYNC_AND_NULL_CURR_PC(); duk_debug_halt_execution(thr, 1 /*use_prev_pc*/); @@ -4996,22 +5073,18 @@ case DUK_OP_UNUSED252: case DUK_OP_UNUSED253: case DUK_OP_UNUSED254: - case DUK_OP_UNUSED255: { - /* Force all case clauses to map to an actual handler - * so that the compiler can emit a jump without a bounds - * check: the switch argument is a duk_uint8_t so that - * the compiler may be able to figure it out. This is - * a small detail and obviously compiler dependent. - */ - volatile duk_small_int_t dummy_volatile; - dummy_volatile = 0; - DUK_UNREF(dummy_volatile); - DUK_D(DUK_DPRINT("invalid opcode: %ld - %!I", (long) op, ins)); - DUK__INTERNAL_ERROR("invalid opcode"); - break; - } + case DUK_OP_UNUSED255: + /* Force all case clauses to map to an actual handler + * so that the compiler can emit a jump without a bounds + * check: the switch argument is a duk_uint8_t so that + * the compiler may be able to figure it out. This is + * a small detail and obviously compiler dependent. + */ + /* default: clause omitted on purpose */ +#else + default: #endif /* DUK_USE_EXEC_PREFER_SIZE */ - default: { + { /* Default case catches invalid/unsupported opcodes. */ DUK_D(DUK_DPRINT("invalid opcode: %ld - %!I", (long) op, ins)); DUK__INTERNAL_ERROR("invalid opcode"); diff -Nru duktape-2.0.0/src-input/duk_js.h duktape-2.1.1/src-input/duk_js.h --- duktape-2.0.0/src-input/duk_js.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_js.h 2017-07-28 22:05:08.000000000 +0000 @@ -28,8 +28,11 @@ DUK_INTERNAL_DECL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv); DUK_INTERNAL_DECL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv); DUK_INTERNAL_DECL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv); -DUK_INTERNAL_DECL duk_small_int_t duk_js_to_arrayindex_raw_string(const duk_uint8_t *str, duk_uint32_t blen, duk_uarridx_t *out_idx); -DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h); +DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string(const duk_uint8_t *str, duk_uint32_t blen); +#if !defined(DUK_USE_HSTRING_ARRIDX) +DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_hstring_fast_known(duk_hstring *h); +DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_hstring_fast(duk_hstring *h); +#endif DUK_INTERNAL_DECL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags); DUK_INTERNAL_DECL duk_small_int_t duk_js_data_compare(const duk_uint8_t *buf1, const duk_uint8_t *buf2, duk_size_t len1, duk_size_t len2); DUK_INTERNAL_DECL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2); @@ -82,7 +85,7 @@ DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name); DUK_INTERNAL_DECL duk_bool_t duk_js_declvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_small_int_t prop_flags, duk_bool_t is_func_decl); DUK_INTERNAL_DECL void duk_js_init_activation_environment_records_delayed(duk_hthread *thr, duk_activation *act); -DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env, duk_hobject *func, duk_size_t regbase); +DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env); DUK_INTERNAL_DECL duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_size_t idx_bottom); DUK_INTERNAL_DECL void duk_js_push_closure(duk_hthread *thr, diff -Nru duktape-2.0.0/src-input/duk_js_ops.c duktape-2.1.1/src-input/duk_js_ops.c --- duktape-2.0.0/src-input/duk_js_ops.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_js_ops.c 2017-07-28 22:05:08.000000000 +0000 @@ -218,7 +218,7 @@ case DUK_TAG_STRING: { /* For Symbols ToNumber() is always a TypeError. */ duk_hstring *h = DUK_TVAL_GET_STRING(tv); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { DUK_ERROR_TYPE(thr, DUK_STR_CANNOT_NUMBER_COERCE_SYMBOL); } duk_push_hstring(ctx, h); @@ -950,7 +950,7 @@ DUK_ASSERT(h1 != NULL); DUK_ASSERT(h2 != NULL); - if (!DUK_HSTRING_HAS_SYMBOL(h1) && !DUK_HSTRING_HAS_SYMBOL(h2)) { + if (DUK_LIKELY(!DUK_HSTRING_HAS_SYMBOL(h1) && !DUK_HSTRING_HAS_SYMBOL(h2))) { rc = duk_js_string_compare(h1, h2); duk_pop_2(ctx); if (rc < 0) { @@ -1080,7 +1080,7 @@ /* func support for [[HasInstance]] checked in the beginning of the loop */ } while (--sanity > 0); - if (sanity == 0) { + if (DUK_UNLIKELY(sanity == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_BOUND_CHAIN_LIMIT); } @@ -1166,7 +1166,7 @@ val = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, val); } while (--sanity > 0); - if (sanity == 0) { + if (DUK_UNLIKELY(sanity == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); } DUK_UNREACHABLE(); @@ -1267,7 +1267,7 @@ /* All internal keys are identified as Symbols. */ str = DUK_TVAL_GET_STRING(tv_x); DUK_ASSERT(str != NULL); - if (DUK_HSTRING_HAS_SYMBOL(str)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(str))) { stridx = DUK_STRIDX_LC_SYMBOL; } else { stridx = DUK_STRIDX_LC_STRING; @@ -1317,64 +1317,109 @@ * * Array index: E5 Section 15.4 * Array length: E5 Section 15.4.5.1 steps 3.c - 3.d (array length write) - * - * duk_js_to_arrayindex_string_helper() computes the array index from - * string contents alone. Depending on options it's only called during - * string intern (and value stored to duk_hstring) or it's called also - * at runtime. */ -DUK_INTERNAL duk_small_int_t duk_js_to_arrayindex_raw_string(const duk_uint8_t *str, duk_uint32_t blen, duk_uarridx_t *out_idx) { - duk_uarridx_t res, new_res; - - if (blen == 0 || blen > 10) { - goto parse_fail; - } - if (str[0] == (duk_uint8_t) '0' && blen > 1) { - goto parse_fail; - } +/* Compure array index from string context, or return a "not array index" + * indicator. + */ +DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_string(const duk_uint8_t *str, duk_uint32_t blen) { + duk_uarridx_t res; - /* Accept 32-bit decimal integers, no leading zeroes, signs, etc. - * Leading zeroes are not accepted (zero index "0" is an exception - * handled above). + /* Only strings with byte length 1-10 can be 32-bit array indices. + * Leading zeroes (except '0' alone), plus/minus signs are not allowed. + * We could do a lot of prechecks here, but since most strings won't + * start with any digits, it's simpler to just parse the number and + * fail quickly. */ res = 0; - while (blen-- > 0) { - duk_uint8_t c = *str++; - if (c >= (duk_uint8_t) '0' && c <= (duk_uint8_t) '9') { - new_res = res * 10 + (duk_uint32_t) (c - (duk_uint8_t) '0'); - if (new_res < res) { - /* overflow, more than 32 bits -> not an array index */ - goto parse_fail; + if (blen == 0) { + goto parse_fail; + } + do { + duk_uarridx_t dig; + dig = (duk_uarridx_t) (*str++) - DUK_ASC_0; + + if (dig <= 9U) { + /* Careful overflow handling. When multiplying by 10: + * - 0x19999998 x 10 = 0xfffffff0: no overflow, and adding + * 0...9 is safe. + * - 0x19999999 x 10 = 0xfffffffa: no overflow, adding + * 0...5 is safe, 6...9 overflows. + * - 0x1999999a x 10 = 0x100000004: always overflow. + */ + if (DUK_UNLIKELY(res >= 0x19999999UL)) { + if (res >= 0x1999999aUL) { + /* Always overflow. */ + goto parse_fail; + } + DUK_ASSERT(res == 0x19999999UL); + if (dig >= 6U) { + goto parse_fail; + } + res = 0xfffffffaUL + dig; + DUK_ASSERT(res >= 0xfffffffaUL); + DUK_ASSERT_DISABLE(res <= 0xffffffffUL); /* range */ + } else { + res = res * 10U + dig; + if (DUK_UNLIKELY(res == 0)) { + /* If 'res' is 0, previous 'res' must + * have been 0 and we scanned in a zero. + * This is only allowed if blen == 1, + * i.e. the exact string '0'. + */ + if (blen == (duk_uint32_t) 1) { + return 0; + } + goto parse_fail; + } } - res = new_res; } else { + /* Because 'dig' is unsigned, catches both values + * above '9' and below '0'. + */ goto parse_fail; } - } + } while (--blen > 0); - *out_idx = res; - return 1; + return res; parse_fail: - *out_idx = DUK_HSTRING_NO_ARRAY_INDEX; - return 0; + return DUK_HSTRING_NO_ARRAY_INDEX; } -/* Called by duk_hstring.h macros */ -DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h) { +#if !defined(DUK_USE_HSTRING_ARRIDX) +/* Get array index for a string which is known to be an array index. This helper + * is needed when duk_hstring doesn't concretely store the array index, but strings + * are flagged as array indices at intern time. + */ +DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_hstring_fast_known(duk_hstring *h) { + const duk_uint8_t *p; duk_uarridx_t res; - duk_small_int_t rc; + duk_uint8_t t; + + DUK_ASSERT(h != NULL); + DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(h)); + p = DUK_HSTRING_GET_DATA(h); + res = 0; + for (;;) { + t = *p++; + if (DUK_UNLIKELY(t == 0)) { + /* Scanning to NUL is always safe for interned strings. */ + break; + } + DUK_ASSERT(t >= DUK_ASC_0 && t <= DUK_ASC_9); + res = res * 10U + (t - DUK_ASC_0); + } + return res; +} + +DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_hstring_fast(duk_hstring *h) { + DUK_ASSERT(h != NULL); if (!DUK_HSTRING_HAS_ARRIDX(h)) { return DUK_HSTRING_NO_ARRAY_INDEX; } - - rc = duk_js_to_arrayindex_raw_string(DUK_HSTRING_GET_DATA(h), - DUK_HSTRING_GET_BYTELEN(h), - &res); - DUK_UNREF(rc); - DUK_ASSERT(rc != 0); - return res; + return duk_js_to_arrayindex_hstring_fast_known(h); } +#endif /* DUK_USE_HSTRING_ARRIDX */ diff -Nru duktape-2.0.0/src-input/duk_js_var.c duktape-2.1.1/src-input/duk_js_var.c --- duktape-2.0.0/src-input/duk_js_var.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_js_var.c 2017-07-28 22:05:08.000000000 +0000 @@ -37,11 +37,11 @@ */ typedef struct { + duk_hobject *env; duk_hobject *holder; /* for object-bound identifiers */ duk_tval *value; /* for register-bound and declarative env identifiers */ duk_int_t attrs; /* property attributes for identifier (relevant if value != NULL) */ - duk_tval *this_binding; - duk_hobject *env; + duk_bool_t has_this; /* for object-bound identifiers: provide 'this' binding */ } duk__id_lookup_result; /* @@ -194,7 +194,7 @@ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&fun_clos->obj)); DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(&fun_clos->obj)); DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(&fun_clos->obj)); - DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(&fun_clos->obj)); + DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(&fun_clos->obj)); /* DUK_HOBJECT_FLAG_ARRAY_PART: don't care */ /* DUK_HOBJECT_FLAG_NEWENV: handled below */ DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&fun_clos->obj)); @@ -229,7 +229,7 @@ #if defined(DUK_USE_FUNC_NAME_PROPERTY) if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_clos->obj)) { duk_hobject *proto; - duk_hobject *new_env; + duk_hdecenv *new_env; /* * Named function expression, name needs to be bound @@ -247,11 +247,18 @@ } /* -> [ ... closure template env ] */ - new_env = duk_push_object_helper_proto(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), - proto); + 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(ctx, (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, proto); + DUK_HOBJECT_INCREF_ALLOWNULL(thr, proto); + + DUK_ASSERT(new_env->thread == NULL); /* Closed. */ + DUK_ASSERT(new_env->varmap == NULL); /* It's important that duk_xdef_prop() is a 'raw define' so that any * properties in an ancestor are never an issue (they should never be @@ -270,10 +277,10 @@ /* [ ... closure template env ] */ - DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, new_env); - DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, new_env); - DUK_HOBJECT_INCREF(thr, new_env); - DUK_HOBJECT_INCREF(thr, new_env); + DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, (duk_hobject *) new_env); + DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, (duk_hobject *) new_env); + DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env); + DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env); duk_pop(ctx); /* [ ... closure template ] */ @@ -495,10 +502,11 @@ duk_hobject *func, duk_size_t idx_bottom) { duk_context *ctx = (duk_context *) thr; - duk_hobject *env; + duk_hdecenv *env; duk_hobject *parent; duk_hcompfunc *f; + DUK_ASSERT(ctx != NULL); DUK_ASSERT(thr != NULL); DUK_ASSERT(func != NULL); @@ -508,25 +516,44 @@ parent = thr->builtins[DUK_BIDX_GLOBAL_ENV]; } - (void) duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), - -1); /* no prototype, updated below */ - env = duk_known_hobject(ctx, -1); - DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, env, parent); /* parent env is the prototype */ + env = duk_hdecenv_alloc(thr, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV)); + DUK_ASSERT(env != NULL); + duk_push_hobject(ctx, (duk_hobject *) env); + + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL); + DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) env, parent); + DUK_HOBJECT_INCREF_ALLOWNULL(thr, parent); /* parent env is the prototype */ /* open scope information, for compiled functions only */ + DUK_ASSERT(env->thread == NULL); + DUK_ASSERT(env->varmap == NULL); + DUK_ASSERT(env->regbase == 0); if (DUK_HOBJECT_IS_COMPFUNC(func)) { - duk_push_hthread(ctx, thr); - duk_xdef_prop_stridx_short_wec(ctx, -2, DUK_STRIDX_INT_THREAD); - duk_push_hobject(ctx, func); - duk_xdef_prop_stridx_short_wec(ctx, -2, DUK_STRIDX_INT_CALLEE); - duk_push_size_t(ctx, idx_bottom); - duk_xdef_prop_stridx_short_wec(ctx, -2, DUK_STRIDX_INT_REGBASE); + duk_hobject *varmap; + duk_tval *tv; + + tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARMAP(thr)); + if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) { + DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); + varmap = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(varmap != NULL); + env->varmap = varmap; + DUK_HOBJECT_INCREF(thr, varmap); + env->thread = thr; + DUK_HTHREAD_INCREF(thr, thr); + env->regbase = idx_bottom; + } else { + /* If function has no _Varmap, leave the environment closed. */ + DUK_ASSERT(env->thread == NULL); + DUK_ASSERT(env->varmap == NULL); + DUK_ASSERT(env->regbase == 0); + } } - return env; + return (duk_hobject *) env; } DUK_INTERNAL @@ -535,7 +562,10 @@ duk_context *ctx = (duk_context *) thr; duk_hobject *func; duk_hobject *env; + duk_size_t act_off; + DUK_ASSERT(act != NULL); + act_off = (duk_size_t) ((duk_uint8_t *) act - (duk_uint8_t *) thr->callstack); func = DUK_ACT_GET_FUNC(act); DUK_ASSERT(func != NULL); DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound functions are never in act 'func' */ @@ -550,6 +580,7 @@ env = duk_create_activation_environment_record(thr, func, act->idx_bottom); DUK_ASSERT(env != NULL); + act = (duk_activation *) (void *) ((duk_uint8_t *) thr->callstack + act_off); DUK_DDD(DUK_DDDPRINT("created delayed fresh env: %!ipO", (duk_heaphdr *) env)); #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) @@ -574,156 +605,103 @@ * Closing environment records. * * The environment record MUST be closed with the thread where its activation - * is. In other words (if 'env' is open): - * - * - 'thr' must match _env.thread - * - 'func' must match _env.callee - * - 'regbase' must match _env.regbase - * - * These are not looked up from the env to minimize code size. - * - * XXX: should access the own properties directly instead of using the API + * is; i.e. if 'env' is open, 'thr' must match env->thread, and the regbase + * and varmap must still be valid. On entry, 'env' must be reachable. */ -DUK_INTERNAL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env, duk_hobject *func, duk_size_t regbase) { +DUK_INTERNAL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env) { duk_context *ctx = (duk_context *) thr; duk_uint_fast32_t i; + duk_hobject *varmap; + duk_hstring *key; + duk_tval *tv; + duk_uint_t regnum; DUK_ASSERT(thr != NULL); DUK_ASSERT(env != NULL); - /* func is NULL for lightfuncs */ - if (!DUK_HOBJECT_IS_DECENV(env) || DUK_HOBJECT_HAS_ENVRECCLOSED(env)) { - DUK_DDD(DUK_DDDPRINT("environment record not a declarative record, " - "or already closed: %!iO", - (duk_heaphdr *) env)); + if (DUK_UNLIKELY(!DUK_HOBJECT_IS_DECENV(env))) { + DUK_DDD(DUK_DDDPRINT("env not a declarative record: %!iO", (duk_heaphdr *) env)); return; } - DUK_DDD(DUK_DDDPRINT("closing environment record: %!iO, func: %!iO, regbase: %ld", - (duk_heaphdr *) env, (duk_heaphdr *) func, (long) regbase)); - - duk_push_hobject(ctx, env); + varmap = ((duk_hdecenv *) env)->varmap; + if (varmap == NULL) { + DUK_DDD(DUK_DDDPRINT("env already closed: %!iO", (duk_heaphdr *) env)); - /* assertions: env must be closed in the same thread as where it runs */ -#if defined(DUK_USE_ASSERTIONS) - { - /* [... env] */ - - if (duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_CALLEE)) { - DUK_ASSERT(duk_is_object(ctx, -1)); - DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) func); - } - duk_pop(ctx); - - if (duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_THREAD)) { - DUK_ASSERT(duk_is_object(ctx, -1)); - DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) thr); - } - duk_pop(ctx); - - if (duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_REGBASE)) { - DUK_ASSERT(duk_is_number(ctx, -1)); - DUK_ASSERT(duk_get_number(ctx, -1) == (double) regbase); - } - duk_pop(ctx); - - /* [... env] */ + return; } -#endif + DUK_ASSERT(((duk_hdecenv *) env)->thread != NULL); + DUK_ASSERT_HDECENV_VALID((duk_hdecenv *) env); - if (func != NULL && DUK_HOBJECT_IS_COMPFUNC(func)) { - duk_hobject *varmap; - duk_hstring *key; - duk_tval *tv; - duk_uint_t regnum; - - /* XXX: additional conditions when to close variables? we don't want to do it - * unless the environment may have "escaped" (referenced in a function closure). - * With delayed environments, the existence is probably good enough of a check. - */ + DUK_DDD(DUK_DDDPRINT("closing env: %!iO", (duk_heaphdr *) env)); + DUK_DDD(DUK_DDDPRINT("varmap: %!O", (duk_heaphdr *) varmap)); - /* XXX: any way to detect faster whether something needs to be closed? - * We now look up _Callee and then skip the rest. - */ + /* Env must be closed in the same thread as where it runs. */ + DUK_ASSERT(((duk_hdecenv *) env)->thread == thr); - /* Note: we rely on the _Varmap having a bunch of nice properties, like: - * - being compacted and unmodified during this process - * - not containing an array part - * - having correct value types - */ - - /* [... env] */ - - if (!duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_CALLEE)) { - DUK_DDD(DUK_DDDPRINT("env has no callee property, nothing to close; re-delete the control properties just in case")); - duk_pop(ctx); - goto skip_varmap; - } - - /* [... env callee] */ - - if (!duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VARMAP)) { - DUK_DDD(DUK_DDDPRINT("callee has no varmap property, nothing to close; delete the control properties")); - duk_pop_2(ctx); - goto skip_varmap; - } - varmap = duk_require_hobject(ctx, -1); - DUK_ASSERT(varmap != NULL); - - DUK_DDD(DUK_DDDPRINT("varmap: %!O", (duk_heaphdr *) varmap)); - - /* [... env callee varmap] */ - - DUK_DDD(DUK_DDDPRINT("copying bound register values, %ld bound regs", (long) DUK_HOBJECT_GET_ENEXT(varmap))); - - for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) { - key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i); - DUK_ASSERT(key != NULL); /* assume keys are compacted */ + /* XXX: additional conditions when to close variables? we don't want to do it + * unless the environment may have "escaped" (referenced in a function closure). + * With delayed environments, the existence is probably good enough of a check. + */ - DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, varmap, i)); /* assume plain values */ + /* Note: we rely on the _Varmap having a bunch of nice properties, like: + * - being compacted and unmodified during this process + * - not containing an array part + * - having correct value types + */ - tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, varmap, i); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); /* assume value is a number */ - regnum = (duk_uint_t) DUK_TVAL_GET_NUMBER(tv); - DUK_ASSERT_DISABLE(regnum >= 0); /* unsigned */ - DUK_ASSERT(regnum < ((duk_hcompfunc *) func)->nregs); /* regnum is sane */ - DUK_ASSERT(thr->valstack + regbase + regnum >= thr->valstack); - DUK_ASSERT(thr->valstack + regbase + regnum < thr->valstack_top); + DUK_DDD(DUK_DDDPRINT("copying bound register values, %ld bound regs", (long) DUK_HOBJECT_GET_ENEXT(varmap))); - /* XXX: slightly awkward */ - duk_push_hstring(ctx, key); - duk_push_tval(ctx, thr->valstack + regbase + regnum); - DUK_DDD(DUK_DDDPRINT("closing identifier '%s' -> reg %ld, value %!T", - (const char *) duk_require_string(ctx, -2), - (long) regnum, - (duk_tval *) duk_get_tval(ctx, -1))); + /* Copy over current variable values from value stack to the + * environment record. The scope object is empty but may + * inherit from another scope which has conflicting names. + */ - /* [... env callee varmap key val] */ + /* XXX: Do this using a once allocated entry area, no side effects. + * Hash part would need special treatment however (maybe copy, and + * then realloc with hash part if large enough). + */ + for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) { + duk_size_t regbase; - /* if property already exists, overwrites silently */ - duk_xdef_prop(ctx, -5, DUK_PROPDESC_FLAGS_WE); /* writable but not deletable */ - } + key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i); + DUK_ASSERT(key != NULL); /* assume keys are compact in _Varmap */ + DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, varmap, i)); /* assume plain values */ - duk_pop_2(ctx); + tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, varmap, i); + DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (duk_double_t) DUK_UINT32_MAX); /* limits */ +#if defined(DUK_USE_FASTINT) + DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv)); + regnum = (duk_uint_t) DUK_TVAL_GET_FASTINT_U32(tv); +#else + regnum = (duk_uint_t) DUK_TVAL_GET_NUMBER(tv); +#endif - /* [... env] */ + regbase = ((duk_hdecenv *) env)->regbase; + DUK_ASSERT(thr->valstack + regbase + regnum >= thr->valstack); + DUK_ASSERT(thr->valstack + regbase + regnum < thr->valstack_top); + + /* If property already exists, overwrites silently. + * Property is writable, but not deletable (not configurable + * in terms of property attributes). + */ + duk_push_tval(ctx, thr->valstack + regbase + regnum); + DUK_DDD(DUK_DDDPRINT("closing identifier %!O -> reg %ld, value %!T", + (duk_heaphdr *) key, + (long) regnum, + (duk_tval *) duk_get_tval(ctx, -1))); + duk_hobject_define_property_internal(thr, env, key, DUK_PROPDESC_FLAGS_WE); } - skip_varmap: + /* NULL atomically to avoid inconsistent state + side effects. */ + DUK_HOBJECT_DECREF_NORZ(thr, ((duk_hdecenv *) env)->thread); + DUK_HOBJECT_DECREF_NORZ(thr, ((duk_hdecenv *) env)->varmap); + ((duk_hdecenv *) env)->thread = NULL; + ((duk_hdecenv *) env)->varmap = NULL; - /* [... env] */ - - duk_del_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_CALLEE); - duk_del_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_THREAD); - duk_del_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_REGBASE); - - duk_pop(ctx); - - DUK_HOBJECT_SET_ENVRECCLOSED(env); - - DUK_DDD(DUK_DDDPRINT("environment record after being closed: %!O", - (duk_heaphdr *) env)); + DUK_DDD(DUK_DDDPRINT("env after closing: %!O", (duk_heaphdr *) env)); } /* @@ -753,12 +731,8 @@ DUK_LOCAL duk_bool_t duk__getid_open_decl_env_regs(duk_hthread *thr, duk_hstring *name, - duk_hobject *env, + duk_hdecenv *env, duk__id_lookup_result *out) { - duk_hthread *env_thr; - duk_hobject *env_func; - duk_size_t env_regbase; - duk_hobject *varmap; duk_tval *tv; duk_size_t reg_rel; duk_size_t idx; @@ -768,69 +742,39 @@ DUK_ASSERT(env != NULL); DUK_ASSERT(out != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_DECENV(env)); + DUK_ASSERT(DUK_HOBJECT_IS_DECENV((duk_hobject *) env)); + DUK_ASSERT_HDECENV_VALID(env); - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_CALLEE(thr)); - if (!tv) { - /* env is closed, should be missing _Callee, _Thread, _Regbase */ - DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL); - DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL); - DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL); + if (env->thread == NULL) { + /* already closed */ return 0; } + DUK_ASSERT(env->varmap != NULL); - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); - DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_TVAL_GET_OBJECT(tv))); - env_func = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(env_func != NULL); - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env_func, DUK_HTHREAD_STRING_INT_VARMAP(thr)); - if (!tv) { + tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env->varmap, name); + if (DUK_UNLIKELY(tv == NULL)) { return 0; } - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); - varmap = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(varmap != NULL); - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, varmap, name); - if (!tv) { - return 0; - } DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (duk_double_t) DUK_UINT32_MAX); /* limits */ +#if defined(DUK_USE_FASTINT) + DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv)); + reg_rel = (duk_size_t) DUK_TVAL_GET_FASTINT_U32(tv); +#else reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv); +#endif DUK_ASSERT_DISABLE(reg_rel >= 0); /* unsigned */ - DUK_ASSERT(reg_rel < ((duk_hcompfunc *) env_func)->nregs); - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THREAD(thr)); - DUK_ASSERT(tv != NULL); - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); - DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_THREAD(DUK_TVAL_GET_OBJECT(tv))); - env_thr = (duk_hthread *) DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(env_thr != NULL); - /* Note: env_thr != thr is quite possible and normal, so careful - * with what thread is used for valstack lookup. - */ - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_REGBASE(thr)); - DUK_ASSERT(tv != NULL); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); - env_regbase = (duk_size_t) DUK_TVAL_GET_NUMBER(tv); - - idx = env_regbase + reg_rel; - tv = env_thr->valstack + idx; - DUK_ASSERT(tv >= env_thr->valstack && tv < env_thr->valstack_end); /* XXX: more accurate? */ + idx = env->regbase + reg_rel; + tv = env->thread->valstack + idx; + DUK_ASSERT(tv >= env->thread->valstack && tv < env->thread->valstack_end); /* XXX: more accurate? */ out->value = tv; out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */ - out->this_binding = NULL; /* implicit this value always undefined for - * declarative environment records. - */ - out->env = env; + out->env = (duk_hobject *) env; out->holder = NULL; - + out->has_this = 0; return 1; } @@ -859,6 +803,7 @@ return 0; } + /* XXX: move varmap to duk_hcompfunc struct field. */ tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARMAP(thr)); if (!tv) { return 0; @@ -882,12 +827,9 @@ out->value = tv; out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */ - out->this_binding = NULL; /* implicit this value always undefined for - * declarative environment records. - */ out->env = NULL; out->holder = NULL; - + out->has_this = 0; return 1; } @@ -899,7 +841,6 @@ duk_bool_t parents, duk__id_lookup_result *out) { duk_tval *tv; - duk_tval *tv_target; duk_tval tv_name; duk_uint_t sanity; @@ -940,10 +881,10 @@ if (duk__getid_activation_regs(thr, name, act, out)) { DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " - "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O " + "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " "(found from register bindings when env=NULL)", (duk_heaphdr *) name, (duk_tval *) out->value, - (long) out->attrs, (duk_tval *) out->this_binding, + (long) out->attrs, (long) out->has_this, (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); return 1; } @@ -1020,37 +961,30 @@ * register-bound variables. */ - if (DUK_HOBJECT_HAS_ENVRECCLOSED(env)) { - /* already closed */ - goto skip_regs; - } - - if (duk__getid_open_decl_env_regs(thr, name, env, out)) { + DUK_ASSERT_HDECENV_VALID((duk_hdecenv *) env); + if (duk__getid_open_decl_env_regs(thr, name, (duk_hdecenv *) env, out)) { DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " - "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O " + "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " "(declarative environment record, scope open, found in regs)", (duk_heaphdr *) name, (duk_tval *) out->value, - (long) out->attrs, (duk_tval *) out->this_binding, + (long) out->attrs, (long) out->has_this, (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); return 1; } - skip_regs: tv = duk_hobject_find_existing_entry_tval_ptr_and_attrs(thr->heap, env, name, &attrs); if (tv) { out->value = tv; out->attrs = attrs; - out->this_binding = NULL; /* implicit this value always undefined for - * declarative environment records. - */ out->env = env; out->holder = env; + out->has_this = 0; DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " - "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O " + "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " "(declarative environment record, found in properties)", (duk_heaphdr *) name, (duk_tval *) out->value, - (long) out->attrs, (duk_tval *) out->this_binding, + (long) out->attrs, (long) out->has_this, (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); return 1; } @@ -1073,11 +1007,9 @@ duk_bool_t found; DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV); + DUK_ASSERT_HOBJENV_VALID((duk_hobjenv *) env); - tv_target = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_TARGET(thr)); - DUK_ASSERT(tv_target != NULL); - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_target)); - target = DUK_TVAL_GET_OBJECT(tv_target); + target = ((duk_hobjenv *) env)->target; DUK_ASSERT(target != NULL); /* Target may be a Proxy or property may be an accessor, so we must @@ -1088,10 +1020,13 @@ */ if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(target)) { + duk_tval tv_target_tmp; + DUK_ASSERT(name != NULL); DUK_TVAL_SET_STRING(&tv_name, name); + DUK_TVAL_SET_OBJECT(&tv_target_tmp, target); - found = duk_hobject_hasprop(thr, tv_target, &tv_name); + found = duk_hobject_hasprop(thr, &tv_target_tmp, &tv_name); } else { /* XXX: duk_hobject_hasprop() would be correct for * non-Proxy objects too, but it is about ~20-25% @@ -1104,16 +1039,15 @@ if (found) { out->value = NULL; /* can't get value, may be accessor */ out->attrs = 0; /* irrelevant when out->value == NULL */ - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THIS(thr)); - out->this_binding = tv; /* may be NULL */ out->env = env; out->holder = target; + out->has_this = ((duk_hobjenv *) env)->has_this; DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " - "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O " + "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " "(object environment record)", (duk_heaphdr *) name, (duk_tval *) out->value, - (long) out->attrs, (duk_tval *) out->this_binding, + (long) out->attrs, (long) out->has_this, (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); return 1; } @@ -1125,11 +1059,11 @@ goto fail_not_found; } - if (sanity-- == 0) { + if (DUK_UNLIKELY(sanity-- == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); } env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env); - }; + } /* * Not found (even in global object) @@ -1236,29 +1170,27 @@ parents = 1; /* follow parent chain */ if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) { if (ref.value) { - DUK_ASSERT(ref.this_binding == NULL); /* always for register bindings */ duk_push_tval(ctx, ref.value); duk_push_undefined(ctx); } else { DUK_ASSERT(ref.holder != NULL); - /* Note: getprop may invoke any getter and invalidate any - * duk_tval pointers, so this must be done first. + /* ref.holder is safe across the getprop call (even + * with side effects) because 'env' is reachable and + * ref.holder is a direct heap pointer. */ - if (ref.this_binding) { - duk_push_tval(ctx, ref.this_binding); - } else { - duk_push_undefined(ctx); - } - DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder); DUK_TVAL_SET_STRING(&tv_tmp_key, name); - (void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key); /* [this value] */ + (void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key); /* [value] */ - /* ref.value, ref.this.binding invalidated here by getprop call */ + if (ref.has_this) { + duk_push_hobject(ctx, ref.holder); + } else { + duk_push_undefined(ctx); + } - duk_insert(ctx, -2); /* [this value] -> [value this] */ + /* [value this] */ } return 1; @@ -1361,13 +1293,11 @@ */ duk_tval *tv_val; - DUK_ASSERT(ref.this_binding == NULL); /* always for register bindings */ - tv_val = ref.value; DUK_ASSERT(tv_val != NULL); DUK_TVAL_SET_TVAL_UPDREF(thr, tv_val, val); /* side effects */ - /* ref.value and ref.this_binding invalidated here */ + /* ref.value invalidated here */ } else { DUK_ASSERT(ref.holder != NULL); @@ -1375,7 +1305,7 @@ DUK_TVAL_SET_STRING(&tv_tmp_key, name); (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, strict); - /* ref.value and ref.this_binding invalidated here */ + /* ref.value invalidated here */ } return; @@ -1748,14 +1678,11 @@ */ if (DUK_HOBJECT_IS_DECENV(env)) { + DUK_ASSERT_HDECENV_VALID((duk_hdecenv *) env); holder = env; } else { - DUK_ASSERT(DUK_HOBJECT_IS_OBJENV(env)); - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_TARGET(thr)); - DUK_ASSERT(tv != NULL); - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); - holder = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT_HOBJENV_VALID((duk_hobjenv *) env); + holder = ((duk_hobjenv *) env)->target; DUK_ASSERT(holder != NULL); } @@ -1797,6 +1724,10 @@ duk_bool_t is_func_decl) { duk_hobject *env; duk_tval tv_val_copy; + duk_size_t act_off; + + DUK_ASSERT(act != NULL); + act_off = (duk_size_t) ((duk_uint8_t *) act - (duk_uint8_t *) thr->callstack); /* * Make a value copy of the input val. This ensures that @@ -1813,6 +1744,7 @@ if (!act->var_env) { DUK_ASSERT(act->lex_env == NULL); duk_js_init_activation_environment_records_delayed(thr, act); + act = (duk_activation *) (void *) ((duk_uint8_t *) thr->callstack + act_off); } DUK_ASSERT(act->lex_env != NULL); DUK_ASSERT(act->var_env != NULL); diff -Nru duktape-2.0.0/src-input/duk_lexer.c duktape-2.1.1/src-input/duk_lexer.c --- duktape-2.0.0/src-input/duk_lexer.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_lexer.c 2017-07-28 22:05:08.000000000 +0000 @@ -744,6 +744,68 @@ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE); } +/* Parse legacy octal escape of the form \N{1,3}, e.g. \0, \5, \0377. Maximum + * allowed value is \0377 (U+00FF), longest match is used. Used for both string + * RegExp octal escape parsing. Window[0] must be the slash '\' and the first + * digit must already be validated to be in [0-9] by the caller. + */ +DUK_LOCAL duk_codepoint_t duk__lexer_parse_legacy_octal(duk_lexer_ctx *lex_ctx, duk_small_int_t *out_adv, duk_bool_t reject_annex_b) { + duk_codepoint_t cp; + duk_small_uint_t lookup_idx; + duk_small_int_t adv; + duk_codepoint_t tmp; + + DUK_ASSERT(out_adv != NULL); + DUK_ASSERT(DUK__LOOKUP(lex_ctx, 0) == DUK_ASC_BACKSLASH); + DUK_ASSERT(DUK__LOOKUP(lex_ctx, 1) >= DUK_ASC_0 && DUK__LOOKUP(lex_ctx, 1) <= DUK_ASC_9); + + cp = 0; + for (lookup_idx = 1; lookup_idx <= 3; lookup_idx++) { + DUK_DDD(DUK_DDDPRINT("lookup_idx=%ld, cp=%ld", (long) lookup_idx, (long) cp)); + tmp = DUK__LOOKUP(lex_ctx, lookup_idx); + if (tmp < DUK_ASC_0 || tmp > DUK_ASC_7) { + /* No more valid digits. */ + break; + } + tmp = (cp << 3) + (tmp - DUK_ASC_0); + if (tmp > 0xff) { + /* Three digit octal escapes above \377 (= 0xff) + * are not allowed. + */ + break; + } + cp = tmp; + } + DUK_DDD(DUK_DDDPRINT("final lookup_idx=%ld, cp=%ld", (long) lookup_idx, (long) cp)); + + adv = lookup_idx; + if (lookup_idx == 1) { + DUK_DDD(DUK_DDDPRINT("\\8 or \\9 -> treat as literal, accept in strict mode too")); + DUK_ASSERT(tmp == DUK_ASC_8 || tmp == DUK_ASC_9); + cp = tmp; + adv++; /* correction to above, eat offending character */ + } else if (lookup_idx == 2 && cp == 0) { + /* Note: 'foo\0bar' is OK in strict mode, but 'foo\00bar' is not. + * It won't be interpreted as 'foo\u{0}0bar' but as a SyntaxError. + */ + DUK_DDD(DUK_DDDPRINT("\\0 -> accept in strict mode too")); + } else { + /* This clause also handles non-shortest zero, e.g. \00. */ + if (reject_annex_b) { + DUK_DDD(DUK_DDDPRINT("non-zero octal literal %ld -> reject in strict-mode", (long) cp)); + cp = -1; + } else { + DUK_DDD(DUK_DDDPRINT("non-zero octal literal %ld -> accepted", (long) cp)); + DUK_ASSERT(cp >= 0 && cp <= 0xff); + } + } + + *out_adv = adv; + + DUK_ASSERT((cp >= 0 && cp <= 0xff) || (cp == -1 && reject_annex_b)); + return cp; +} + /* XXX: move strict mode to lex_ctx? */ DUK_LOCAL void duk__lexer_parse_string_literal(duk_lexer_ctx *lex_ctx, duk_token *out_token, duk_small_int_t quote, duk_bool_t strict_mode) { duk_small_int_t adv; @@ -829,46 +891,9 @@ * Parse octal (up to 3 digits) from the lookup window. */ - duk_codepoint_t tmp; - duk_small_uint_t lookup_idx; - - emitcp = 0; - for (lookup_idx = 1; lookup_idx <= 3; lookup_idx++) { - DUK_DDD(DUK_DDDPRINT("lookup_idx=%ld, emitcp=%ld", (long) lookup_idx, (long) emitcp)); - tmp = DUK__LOOKUP(lex_ctx, lookup_idx); - if (tmp < DUK_ASC_0 || tmp > DUK_ASC_7) { - /* No more valid digits. */ - break; - } - tmp = (emitcp << 3) + (tmp - DUK_ASC_0); - if (tmp > 0xff) { - /* Three digit octal escapes above \377 (= 0xff) - * are not allowed. - */ - break; - } - emitcp = tmp; - } - DUK_DDD(DUK_DDDPRINT("final lookup_idx=%ld, emitcp=%ld", (long) lookup_idx, (long) emitcp)); - - adv = lookup_idx; - if (lookup_idx == 1) { - /* \8 or \9 -> treat as literal, accept also - * in strict mode. - */ - DUK_DDD(DUK_DDDPRINT("\\8 or \\9 -> treat as literal, accept in strict mode too")); - emitcp = x; - adv++; /* correction to above, eat offending character */ - } else if (lookup_idx == 2 && emitcp == 0) { - /* Zero escape, also allowed in non-strict mode. */ - DUK_DDD(DUK_DDDPRINT("\\0 -> accept in strict mode too")); - } else { - /* Valid octal, only accept in non-strict mode. */ - DUK_DDD(DUK_DDDPRINT("octal literal %ld -> accept only in non-strict-mode", (long) emitcp)); - DUK_ASSERT(emitcp >= 0 && emitcp <= 0xff); - if (strict_mode) { - goto fail_escape; - } + emitcp = duk__lexer_parse_legacy_octal(lex_ctx, &adv, strict_mode /*reject_annex_b*/); + if (emitcp < 0) { + goto fail_escape; } } else if (x < 0) { goto fail_unterminated; @@ -919,6 +944,19 @@ return; } +/* Skip to end-of-line (or end-of-file), used for single line comments. */ +DUK_LOCAL void duk__lexer_skip_to_endofline(duk_lexer_ctx *lex_ctx) { + for (;;) { + duk_codepoint_t x; + + x = DUK__L0(); + if (x < 0 || duk_unicode_is_line_terminator(x)) { + break; + } + DUK__ADVANCECHARS(lex_ctx, 1); + } +} + /* * Parse Ecmascript source InputElementDiv or InputElementRegExp * (E5 Section 7), skipping whitespace, comments, and line terminators. @@ -1057,6 +1095,17 @@ DUK__ADVANCECHARS(lex_ctx, 1); got_lineterm = 1; goto restart_lineupdate; +#if defined(DUK_USE_SHEBANG_COMMENTS) + case DUK_ASC_HASH: /* '#' */ + if (DUK__L1() == DUK_ASC_EXCLAMATION && lex_ctx->window[0].offset == 0 && + (lex_ctx->flags & DUK_COMPILE_SHEBANG)) { + /* "Shebang" comment ('#! ...') on first line. */ + /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but not necessary */ + duk__lexer_skip_to_endofline(lex_ctx); + goto restart; /* line terminator will be handled on next round */ + } + goto fail_token; +#endif /* DUK_USE_SHEBANG_COMMENTS */ case DUK_ASC_SLASH: /* '/' */ if (DUK__L1() == DUK_ASC_SLASH) { /* @@ -1064,14 +1113,8 @@ * code point). */ - /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but it unnecessary */ - for (;;) { - x = DUK__L0(); - if (x < 0 || duk_unicode_is_line_terminator(x)) { - break; - } - DUK__ADVANCECHARS(lex_ctx, 1); - } + /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but not necessary */ + duk__lexer_skip_to_endofline(lex_ctx); goto restart; /* line terminator will be handled on next round */ } else if (DUK__L1() == DUK_ASC_STAR) { /* @@ -1256,6 +1299,18 @@ advtok = DUK__ADVTOK(1, DUK_TOK_COMMA); break; case DUK_ASC_LANGLE: /* '<' */ +#if defined(DUK_USE_HTML_COMMENTS) + if (DUK__L1() == DUK_ASC_EXCLAMATION && DUK__L2() == DUK_ASC_MINUS && DUK__L3() == DUK_ASC_MINUS) { + /* + * ES6: B.1.3, handle "" SingleLineHTMLCloseComment + * Only allowed: + * - on new line + * - preceded only by whitespace + * - preceded by end of multiline comment and optional whitespace + * + * Since whitespace generates no tokens, and multiline comments + * are treated as a line ending, consulting `got_lineterm` is + * sufficient to test for these three options. + */ + + /* DUK__ADVANCECHARS(lex_ctx, 3) would be correct here, but not necessary */ + duk__lexer_skip_to_endofline(lex_ctx); + goto restart; /* line terminator will be handled on next round */ + } else +#endif /* DUK_USE_HTML_COMMENTS */ if (DUK__L1() == DUK_ASC_MINUS) { advtok = DUK__ADVTOK(2, DUK_TOK_DECREMENT); } else if (DUK__L1() == DUK_ASC_EQUALS) { @@ -2020,6 +2094,8 @@ } else if (DUK__L2() == DUK_ASC_COLON) { /* (?: */ advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_START_NONCAPTURE_GROUP); + } else { + goto fail_group; } } else { /* ( */ @@ -2087,6 +2163,10 @@ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_ESCAPE); return; + fail_group: + DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_GROUP); + return; + #if !defined(DUK_USE_ES6_REGEXP_SYNTAX) fail_invalid_char: DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_CHARACTER); @@ -2163,7 +2243,7 @@ DUK__ADVANCECHARS(lex_ctx, 1); /* eat ']' before finishing */ break; } else if (x == DUK_ASC_MINUS) { - if (start >= 0 && !dash && DUK__L0() != DUK_ASC_RBRACKET) { + if (start >= 0 && !dash && DUK__L1() != DUK_ASC_RBRACKET) { /* '-' as a range indicator */ dash = 1; continue; @@ -2260,12 +2340,24 @@ sizeof(duk_unicode_re_ranges_not_wordchar) / sizeof(duk_uint16_t)); ch = -1; } else if (DUK__ISDIGIT(x)) { - /* DecimalEscape, only \0 is allowed, no leading zeroes are allowed */ + /* DecimalEscape, only \0 is allowed, no leading + * zeroes are allowed. + * + * ES2015 Annex B also allows (maximal match) legacy + * octal escapes up to \377 and \8 and \9 are + * accepted as literal '8' and '9', also in strict mode. + */ + +#if defined(DUK_USE_ES6_REGEXP_SYNTAX) + ch = duk__lexer_parse_legacy_octal(lex_ctx, &adv, 0 /*reject_annex_b*/); + DUK_ASSERT(ch >= 0); /* no rejections */ +#else if (x == DUK_ASC_0 && !DUK__ISDIGIT(DUK__L2())) { ch = 0x0000; } else { goto fail_escape; } +#endif #if defined(DUK_USE_ES6_REGEXP_SYNTAX) } else if (x >= 0) { /* IdentityEscape: ES2015 Annex B allows almost all diff -Nru duktape-2.0.0/src-input/duk_lexer.h duktape-2.1.1/src-input/duk_lexer.h --- duktape-2.0.0/src-input/duk_lexer.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_lexer.h 2017-07-28 22:05:08.000000000 +0000 @@ -32,7 +32,7 @@ #define DUK_LEXER_GETPOINT(ctx,pt) duk_lexer_getpoint((ctx), (pt)) -/* currently 6 characters of lookup are actually needed (duk_lexer.c) */ +/* Currently 6 characters of lookup are actually needed (duk_lexer.c). */ #define DUK_LEXER_WINDOW_SIZE 6 #if defined(DUK_USE_LEXER_SLIDING_WINDOW) #define DUK_LEXER_BUFFER_SIZE 64 @@ -410,6 +410,8 @@ duk_int_t token_count; /* number of tokens parsed */ duk_int_t token_limit; /* maximum token count before error (sanity backstop) */ + + duk_small_uint_t flags; /* lexer flags, use compiler flag defines for now */ }; /* diff -Nru duktape-2.0.0/src-input/duk_refcount.h duktape-2.1.1/src-input/duk_refcount.h --- duktape-2.0.0/src-input/duk_refcount.h 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/src-input/duk_refcount.h 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,698 @@ +/* + * Reference counting helper macros. The macros take a thread argument + * and must thus always be executed in a specific thread context. The + * thread argument is not really needed anymore: DECREF can operate with + * a heap pointer only, and INCREF needs neither. + */ + +#if !defined(DUK_REFCOUNT_H_INCLUDED) +#define DUK_REFCOUNT_H_INCLUDED + +#if defined(DUK_USE_REFERENCE_COUNTING) + +#if defined(DUK_USE_ROM_OBJECTS) +/* With ROM objects "needs refcount update" is true when the value is + * heap allocated and is not a ROM object. + */ +/* XXX: double evaluation for 'tv' argument. */ +#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) \ + (DUK_TVAL_IS_HEAP_ALLOCATED((tv)) && !DUK_HEAPHDR_HAS_READONLY(DUK_TVAL_GET_HEAPHDR((tv)))) +#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) (!DUK_HEAPHDR_HAS_READONLY((h))) +#else /* DUK_USE_ROM_OBJECTS */ +/* Without ROM objects "needs refcount update" == is heap allocated. */ +#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) DUK_TVAL_IS_HEAP_ALLOCATED((tv)) +#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 1 +#endif /* DUK_USE_ROM_OBJECTS */ + +/* Fast variants, inline refcount operations except for refzero handling. + * Can be used explicitly when speed is always more important than size. + * For a good compiler and a single file build, these are basically the + * same as a forced inline. + */ +#define DUK_TVAL_INCREF_FAST(thr,tv) do { \ + duk_tval *duk__tv = (tv); \ + DUK_ASSERT(duk__tv != NULL); \ + if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \ + duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \ + DUK_ASSERT(duk__h != NULL); \ + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ + DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \ + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) != 0); /* No wrapping. */ \ + } \ + } while (0) +#define DUK_TVAL_DECREF_FAST(thr,tv) do { \ + duk_tval *duk__tv = (tv); \ + DUK_ASSERT(duk__tv != NULL); \ + if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \ + duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \ + DUK_ASSERT(duk__h != NULL); \ + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \ + if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \ + duk_heaphdr_refzero((thr), duk__h); \ + } \ + } \ + } while (0) +#define DUK_TVAL_DECREF_NORZ_FAST(thr,tv) do { \ + duk_tval *duk__tv = (tv); \ + DUK_ASSERT(duk__tv != NULL); \ + if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \ + duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \ + DUK_ASSERT(duk__h != NULL); \ + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \ + if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \ + duk_heaphdr_refzero_norz((thr), duk__h); \ + } \ + } \ + } while (0) +#define DUK_HEAPHDR_INCREF_FAST(thr,h) do { \ + duk_heaphdr *duk__h = (duk_heaphdr *) (h); \ + DUK_ASSERT(duk__h != NULL); \ + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ + if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \ + DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \ + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) != 0); /* No wrapping. */ \ + } \ + } while (0) +#define DUK_HEAPHDR_DECREF_FAST_RAW(thr,h,rzcall,rzcast) do { \ + duk_heaphdr *duk__h = (duk_heaphdr *) (h); \ + DUK_ASSERT(duk__h != NULL); \ + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \ + if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \ + if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \ + (rzcall)((thr), (rzcast) duk__h); \ + } \ + } \ + } while (0) +#define DUK_HEAPHDR_DECREF_FAST(thr,h) \ + DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *) +#define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) \ + DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *) + +/* Slow variants, call to a helper to reduce code size. + * Can be used explicitly when size is always more important than speed. + */ +#define DUK_TVAL_INCREF_SLOW(thr,tv) do { duk_tval_incref((tv)); } while (0) +#define DUK_TVAL_DECREF_SLOW(thr,tv) do { duk_tval_decref((thr), (tv)); } while (0) +#define DUK_TVAL_DECREF_NORZ_SLOW(thr,tv) do { duk_tval_decref_norz((thr), (tv)); } while (0) +#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) +#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) +#define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) +#define DUK_HSTRING_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) +#define DUK_HSTRING_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) +#define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) +#define DUK_HBUFFER_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) +#define DUK_HBUFFER_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) +#define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) +#define DUK_HOBJECT_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) +#define DUK_HOBJECT_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) +#define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) + +/* Default variants. Selection depends on speed/size preference. + * Concretely: with gcc 4.8.1 -Os x64 the difference in final binary + * is about +1kB for _FAST variants. + */ +#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) +/* XXX: It would be nice to specialize for specific duk_hobject subtypes + * but current refzero queue handling prevents that. + */ +#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_FAST((thr),(tv)) +#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_FAST((thr),(tv)) +#define DUK_TVAL_DECREF_NORZ(thr,tv) DUK_TVAL_DECREF_NORZ_FAST((thr),(tv)) +#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_FAST((thr),(h)) +#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *) +#define DUK_HEAPHDR_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *) +#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) +#define DUK_HSTRING_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *) +#define DUK_HSTRING_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *) /* no 'norz' variant */ +#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) +#define DUK_HOBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) +#define DUK_HOBJECT_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) +#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) +#define DUK_HBUFFER_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *) +#define DUK_HBUFFER_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *) /* no 'norz' variant */ +#define DUK_HCOMPFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HCOMPFUNC_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) +#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) +#define DUK_HNATFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HNATFUNC_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) +#define DUK_HNATFUNC_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) +#define DUK_HBUFOBJ_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HBUFOBJ_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) +#define DUK_HBUFOBJ_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) +#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HTHREAD_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) +#define DUK_HTHREAD_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) +#else +#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_SLOW((thr),(tv)) +#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_SLOW((thr),(tv)) +#define DUK_TVAL_DECREF_NORZ(thr,tv) DUK_TVAL_DECREF_NORZ_SLOW((thr),(tv)) +#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_SLOW((thr),(h)) +#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_SLOW((thr),(h)) +#define DUK_HEAPHDR_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_NORZ_SLOW((thr),(h)) +#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) +#define DUK_HSTRING_DECREF(thr,h) DUK_HSTRING_DECREF_SLOW((thr),(h)) +#define DUK_HSTRING_DECREF_NORZ(thr,h) DUK_HSTRING_DECREF_NORZ_SLOW((thr),(h)) +#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) +#define DUK_HOBJECT_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(h)) +#define DUK_HOBJECT_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(h)) +#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) +#define DUK_HBUFFER_DECREF(thr,h) DUK_HBUFFER_DECREF_SLOW((thr),(h)) +#define DUK_HBUFFER_DECREF_NORZ(thr,h) DUK_HBUFFER_DECREF_NORZ_SLOW((thr),(h)) +#define DUK_HCOMPFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HCOMPFUNC_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) +#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) +#define DUK_HNATFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HNATFUNC_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) +#define DUK_HNATFUNC_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) +#define DUK_HBUFOBJ_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HBUFOBJ_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) +#define DUK_HBUFOB_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) +#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HTHREAD_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) +#define DUK_HTHREAD_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) +#endif + +/* Convenience for some situations; the above macros don't allow NULLs + * for performance reasons. Macros cover only actually needed cases. + */ +#define DUK_HEAPHDR_INCREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HEAPHDR_INCREF((thr), (duk_heaphdr *) (h)); \ + } \ + } while (0) +#define DUK_HEAPHDR_DECREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HEAPHDR_DECREF((thr), (duk_heaphdr *) (h)); \ + } \ + } while (0) +#define DUK_HEAPHDR_DECREF_NORZ_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HEAPHDR_DECREF_NORZ((thr), (duk_heaphdr *) (h)); \ + } \ + } while (0) +#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HOBJECT_INCREF((thr), (h)); \ + } \ + } while (0) +#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HOBJECT_DECREF((thr), (h)); \ + } \ + } while (0) +#define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HOBJECT_DECREF_NORZ((thr), (h)); \ + } \ + } while (0) +#define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HBUFFER_INCREF((thr), (h)); \ + } \ + } while (0) +#define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HBUFFER_DECREF((thr), (h)); \ + } \ + } while (0) +#define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HBUFFER_DECREF_NORZ((thr), (h)); \ + } \ + } while (0) +#define DUK_HTHREAD_INCREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HTHREAD_INCREF((thr), (h)); \ + } \ + } while (0) +#define DUK_HTHREAD_DECREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HTHREAD_DECREF((thr), (h)); \ + } \ + } while (0) +#define DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HTHREAD_DECREF_NORZ((thr), (h)); \ + } \ + } while (0) + +/* Called after one or more DECREF NORZ calls to handle pending side effects. + * At present DECREF NORZ does freeing inline but doesn't execute finalizers, + * so these macros check for pending finalizers and execute them. The FAST + * variant is performance critical. + */ +#if defined(DUK_USE_FINALIZER_SUPPORT) +#define DUK_REFZERO_CHECK_FAST(thr) do { \ + duk_refzero_check_fast((thr)); \ + } while (0) +#define DUK_REFZERO_CHECK_SLOW(thr) do { \ + duk_refzero_check_slow((thr)); \ + } while (0) +#else /* DUK_USE_FINALIZER_SUPPORT */ +#define DUK_REFZERO_CHECK_FAST(thr) do { } while (0) +#define DUK_REFZERO_CHECK_SLOW(thr) do { } while (0) +#endif /* DUK_USE_FINALIZER_SUPPORT */ + +/* + * Macros to set a duk_tval and update refcount of the target (decref the + * old value and incref the new value if necessary). This is both performance + * and footprint critical; any changes made should be measured for size/speed. + */ + +#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_UNDEFINED(tv__dst); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_UNDEFINED(tv__dst); \ + DUK_TVAL_DECREF_NORZ((thr), &tv__tmp); \ + } while (0) + +#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_UNUSED(tv__dst); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_NULL(tv__dst); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) +#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) +#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) +#define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_NAN(tv__dst); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) +#if defined(DUK_USE_FASTINT) +#define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_I48(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) +#define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_I32(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) +#define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_U32(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) +#else +#define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \ + DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval)) +#endif /* DUK_USE_FASTINT */ + +#define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_STRING(tv__dst, (newval)); \ + DUK_HSTRING_INCREF((thr), (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \ + DUK_HOBJECT_INCREF((thr), (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \ + DUK_HBUFFER_INCREF((thr), (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_POINTER(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +/* DUK_TVAL_SET_TVAL_UPDREF() is used a lot in executor, property lookups, + * etc, so it's very important for performance. Measure when changing. + * + * NOTE: the source and destination duk_tval pointers may be the same, and + * the macros MUST deal with that correctly. + */ + +/* Original idiom used, minimal code size. */ +#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \ + duk_tval *tv__dst, *tv__src; duk_tval tv__tmp; \ + tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ + DUK_TVAL_INCREF((thr), tv__src); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +/* Faster alternative: avoid making a temporary copy of tvptr_dst and use + * fast incref/decref macros. + */ +#define DUK_TVAL_SET_TVAL_UPDREF_ALT1(thr,tvptr_dst,tvptr_src) do { \ + duk_tval *tv__dst, *tv__src; duk_heaphdr *h__obj; \ + tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ + DUK_TVAL_INCREF_FAST((thr), tv__src); \ + if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv__dst)) { \ + h__obj = DUK_TVAL_GET_HEAPHDR(tv__dst); \ + DUK_ASSERT(h__obj != NULL); \ + DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ + DUK_HEAPHDR_DECREF_FAST((thr), h__obj); /* side effects */ \ + } else { \ + DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ + } \ + } while (0) + +/* XXX: no optimized variants yet */ +#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 +#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0 +#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0 +#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0 +#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0 +#define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0 +#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0 +#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0 +#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0 +#if defined(DUK_USE_FASTINT) +#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_I48_UPDREF_ALT0 +#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_I32_UPDREF_ALT0 +#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_U32_UPDREF_ALT0 +#else +#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast int-to-double */ +#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF +#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF +#endif /* DUK_USE_FASTINT */ +#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_I48_UPDREF /* convenience */ +#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0 +#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0 +#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0 +#define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0 +#define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0 + +#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) +/* Optimized for speed. */ +#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT1 +#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT1 +#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0 +#else +/* Optimized for size. */ +#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0 +#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0 +#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0 +#endif + +#else /* DUK_USE_REFERENCE_COUNTING */ + +#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) 0 +#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 0 + +#define DUK_TVAL_INCREF_FAST(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_DECREF_FAST(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_DECREF_NORZ_FAST(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_INCREF_SLOW(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_DECREF_SLOW(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_DECREF_NORZ_SLOW(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_INCREF(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_DECREF(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_DECREF_NORZ(thr,v) do {} while (0) /* nop */ +#define DUK_HEAPHDR_INCREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_DECREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_DECREF_NORZ(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_INCREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_DECREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_INCREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_DECREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_DECREF_NORZ(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_INCREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_INCREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF_NORZ(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_INCREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_INCREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF_NORZ(thr,h) do {} while (0) /* nop */ + +#define DUK_HCOMPFUNC_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HCOMPFUNC_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) do {} while (0) /* nop */ +#define DUK_HNATFUNC_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HNATFUNC_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HNATFUNC_DECREF_NORZ(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFOBJ_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFOBJ_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFOBJ_DECREF_NORZ(thr,h) do {} while (0) /* nop */ +#define DUK_HTHREAD_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HTHREAD_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HTHREAD_DECREF_NORZ(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do {} while (0) /* nop */ + +#define DUK_REFZERO_CHECK_FAST(thr) do {} while (0) /* nop */ +#define DUK_REFZERO_CHECK_SLOW(thr) do {} while (0) /* nop */ + +#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_UNDEFINED(tv__dst); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_UNUSED(tv__dst); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_NULL(tv__dst); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) +#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) +#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) +#define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_NAN(tv__dst); \ + DUK_UNREF((thr)); \ + } while (0) +#if defined(DUK_USE_FASTINT) +#define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_I48(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) +#define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_I32(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) +#define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_U32(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) +#else +#define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \ + DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval)) +#endif /* DUK_USE_FASTINT */ + +#define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_STRING(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_POINTER(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \ + duk_tval *tv__dst, *tv__src; \ + tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ + DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 +#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 +#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0 +#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0 +#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0 +#define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0 +#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0 +#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0 +#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0 +#if defined(DUK_USE_FASTINT) +#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_I48_UPDREF_ALT0 +#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_I32_UPDREF_ALT0 +#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_U32_UPDREF_ALT0 +#else +#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast-int-to-double */ +#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF +#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF +#endif /* DUK_USE_FASTINT */ +#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_I48_UPDREF /* convenience */ +#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0 +#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0 +#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0 +#define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0 +#define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0 + +#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0 +#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0 +#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0 + +#endif /* DUK_USE_REFERENCE_COUNTING */ + +#if defined(DUK_USE_REFERENCE_COUNTING) +#if defined(DUK_USE_FINALIZER_SUPPORT) +DUK_INTERNAL_DECL void duk_refzero_check_slow(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_refzero_check_fast(duk_hthread *thr); +#endif +DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize_norz(duk_heap *heap, duk_heaphdr *hdr); +DUK_INTERNAL_DECL void duk_hobject_refcount_finalize_norz(duk_heap *heap, duk_hobject *h); +#if 0 /* Not needed: fast path handles inline; slow path uses duk_heaphdr_decref() which is needed anyway. */ +DUK_INTERNAL_DECL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h); +DUK_INTERNAL_DECL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h); +DUK_INTERNAL_DECL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h); +DUK_INTERNAL_DECL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h); +DUK_INTERNAL_DECL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h); +DUK_INTERNAL_DECL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h); +#endif +DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h); +DUK_INTERNAL_DECL void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h); +#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) +DUK_INTERNAL_DECL void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h); /* no 'norz' variant */ +DUK_INTERNAL_DECL void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h); /* no 'norz' variant */ +DUK_INTERNAL_DECL void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h); +DUK_INTERNAL_DECL void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h); +#else +DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv); +DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv); +DUK_INTERNAL_DECL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv); +DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h); +DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h); +DUK_INTERNAL_DECL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h); +#endif +#else /* DUK_USE_REFERENCE_COUNTING */ +/* no refcounting */ +#endif /* DUK_USE_REFERENCE_COUNTING */ + +#endif /* DUK_REFCOUNT_H_INCLUDED */ diff -Nru duktape-2.0.0/src-input/duk_regexp_compiler.c duktape-2.1.1/src-input/duk_regexp_compiler.c --- duktape-2.0.0/src-input/duk_regexp_compiler.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_regexp_compiler.c 2017-07-28 22:05:08.000000000 +0000 @@ -864,34 +864,34 @@ switch (c) { case (duk_uint8_t) 'g': { if (flags & DUK_RE_FLAG_GLOBAL) { - goto error; + goto flags_error; } flags |= DUK_RE_FLAG_GLOBAL; break; } case (duk_uint8_t) 'i': { if (flags & DUK_RE_FLAG_IGNORE_CASE) { - goto error; + goto flags_error; } flags |= DUK_RE_FLAG_IGNORE_CASE; break; } case (duk_uint8_t) 'm': { if (flags & DUK_RE_FLAG_MULTILINE) { - goto error; + goto flags_error; } flags |= DUK_RE_FLAG_MULTILINE; break; } default: { - goto error; + goto flags_error; } } } return flags; - error: + flags_error: DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_REGEXP_FLAGS); return 0; /* never here */ } diff -Nru duktape-2.0.0/src-input/duk_regexp_executor.c duktape-2.1.1/src-input/duk_regexp_executor.c --- duktape-2.0.0/src-input/duk_regexp_executor.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_regexp_executor.c 2017-07-28 22:05:08.000000000 +0000 @@ -818,6 +818,7 @@ char_offset = (duk_uint32_t) 0; } + DUK_ASSERT(char_offset <= DUK_HSTRING_GET_CHARLEN(h_input)); sp = re_ctx.input + duk_heap_strcache_offset_char2byte(thr, h_input, char_offset); /* diff -Nru duktape-2.0.0/src-input/duk_strings.h duktape-2.1.1/src-input/duk_strings.h --- duktape-2.0.0/src-input/duk_strings.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_strings.h 2017-07-28 22:05:08.000000000 +0000 @@ -136,6 +136,7 @@ #define DUK_STR_INVALID_REGEXP_ESCAPE "invalid regexp escape" #define DUK_STR_INVALID_BACKREFS "invalid backreference(s)" #define DUK_STR_INVALID_REGEXP_CHARACTER "invalid regexp character" +#define DUK_STR_INVALID_REGEXP_GROUP "invalid regexp group" #define DUK_STR_UNTERMINATED_CHARCLASS "unterminated character class" #define DUK_STR_INVALID_RANGE "invalid range" diff -Nru duktape-2.0.0/src-input/duktape.h.in duktape-2.1.1/src-input/duktape.h.in --- duktape-2.0.0/src-input/duktape.h.in 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duktape.h.in 2017-07-28 22:05:08.000000000 +0000 @@ -1,10 +1,10 @@ /* * Duktape public API for Duktape @DUK_VERSION_FORMATTED@. * - * See the API reference for documentation on call semantics. - * The exposed API is inside the DUK_API_PUBLIC_H_INCLUDED - * include guard. Other parts of the header are Duktape - * internal and related to platform/compiler/feature detection. + * See the API reference for documentation on call semantics. The exposed, + * supported API is between the "BEGIN PUBLIC API" and "END PUBLIC API" + * comments. Other parts of the header are Duktape internal and related to + * e.g. platform/compiler/feature detection. * * Git commit @GIT_COMMIT@ (@GIT_DESCRIBE@). * Git branch @GIT_BRANCH@. @@ -24,14 +24,1152 @@ @DUK_SINGLE_FILE@ +/* + * BEGIN PUBLIC API + */ + +/* + * Version and Git commit identification + */ + +/* Duktape version, (major * 10000) + (minor * 100) + patch. Allows C code + * to #if (DUK_VERSION >= NNN) against Duktape API version. The same value + * is also available to Ecmascript code in Duktape.version. Unofficial + * development snapshots have 99 for patch level (e.g. 0.10.99 would be a + * development version after 0.10.0 but before the next official release). + */ +#define DUK_VERSION 20101L + +/* Git commit, describe, and branch for Duktape build. Useful for + * non-official snapshot builds so that application code can easily log + * which Duktape snapshot was used. Not available in the Ecmascript + * environment. + */ +#define DUK_GIT_COMMIT @GIT_COMMIT_CSTRING@ +#define DUK_GIT_DESCRIBE @GIT_DESCRIBE_CSTRING@ +#define DUK_GIT_BRANCH @GIT_BRANCH_CSTRING@ + /* External duk_config.h provides platform/compiler/OS dependent * typedefs and macros, and DUK_USE_xxx config options so that * the rest of Duktape doesn't need to do any feature detection. + * DUK_VERSION is defined before including so that configuration + * snippets can react to it. */ #include "duk_config.h" -@DUK_API_PUBLIC_H@ +/* + * Avoid C++ name mangling + */ + +#if defined(__cplusplus) +extern "C" { +#endif + +/* + * Some defines forwarded from feature detection + */ + +#undef DUK_API_VARIADIC_MACROS +#if defined(DUK_USE_VARIADIC_MACROS) +#define DUK_API_VARIADIC_MACROS +#endif + +#define DUK_API_NORETURN(decl) DUK_NORETURN(decl) + +/* + * Public API specific typedefs + * + * Many types are wrapped by Duktape for portability to rare platforms + * where e.g. 'int' is a 16-bit type. See practical typing discussion + * in Duktape web documentation. + */ + +struct duk_thread_state; +struct duk_memory_functions; +struct duk_function_list_entry; +struct duk_number_list_entry; +struct duk_time_components; + +/* duk_context is now defined in duk_config.h because it may also be + * referenced there by prototypes. + */ +typedef struct duk_thread_state duk_thread_state; +typedef struct duk_memory_functions duk_memory_functions; +typedef struct duk_function_list_entry duk_function_list_entry; +typedef struct duk_number_list_entry duk_number_list_entry; +typedef struct duk_time_components duk_time_components; + +typedef duk_ret_t (*duk_c_function)(duk_context *ctx); +typedef void *(*duk_alloc_function) (void *udata, duk_size_t size); +typedef void *(*duk_realloc_function) (void *udata, void *ptr, duk_size_t size); +typedef void (*duk_free_function) (void *udata, void *ptr); +typedef void (*duk_fatal_function) (void *udata, const char *msg); +typedef void (*duk_decode_char_function) (void *udata, duk_codepoint_t codepoint); +typedef duk_codepoint_t (*duk_map_char_function) (void *udata, duk_codepoint_t codepoint); +typedef duk_ret_t (*duk_safe_call_function) (duk_context *ctx, void *udata); +typedef duk_size_t (*duk_debug_read_function) (void *udata, char *buffer, duk_size_t length); +typedef duk_size_t (*duk_debug_write_function) (void *udata, const char *buffer, duk_size_t length); +typedef duk_size_t (*duk_debug_peek_function) (void *udata); +typedef void (*duk_debug_read_flush_function) (void *udata); +typedef void (*duk_debug_write_flush_function) (void *udata); +typedef duk_idx_t (*duk_debug_request_function) (duk_context *ctx, void *udata, duk_idx_t nvalues); +typedef void (*duk_debug_detached_function) (duk_context *ctx, void *udata); + +struct duk_thread_state { + /* XXX: Enough space to hold internal suspend/resume structure. + * This is rather awkward and to be fixed when the internal + * structure is visible for the public API header. + */ + char data[128]; +}; + +struct duk_memory_functions { + duk_alloc_function alloc_func; + duk_realloc_function realloc_func; + duk_free_function free_func; + void *udata; +}; + +struct duk_function_list_entry { + const char *key; + duk_c_function value; + duk_idx_t nargs; +}; + +struct duk_number_list_entry { + const char *key; + duk_double_t value; +}; + +struct duk_time_components { + duk_double_t year; /* year, e.g. 2016, Ecmascript year range */ + duk_double_t month; /* month: 1-12 */ + duk_double_t day; /* day: 1-31 */ + duk_double_t hours; /* hour: 0-59 */ + duk_double_t minutes; /* minute: 0-59 */ + duk_double_t seconds; /* second: 0-59 (in POSIX time no leap second) */ + duk_double_t milliseconds; /* may contain sub-millisecond fractions */ + duk_double_t weekday; /* weekday: 0-6, 0=Sunday, 1=Monday, ..., 6=Saturday */ +}; + +/* + * Constants + */ + +/* Duktape debug protocol version used by this build. */ +#define DUK_DEBUG_PROTOCOL_VERSION 2 + +/* Used to represent invalid index; if caller uses this without checking, + * this index will map to a non-existent stack entry. Also used in some + * API calls as a marker to denote "no value". + */ +#define DUK_INVALID_INDEX DUK_IDX_MIN + +/* Indicates that a native function does not have a fixed number of args, + * and the argument stack should not be capped/extended at all. + */ +#define DUK_VARARGS ((duk_int_t) (-1)) + +/* Number of value stack entries (in addition to actual call arguments) + * guaranteed to be allocated on entry to a Duktape/C function. + */ +#define DUK_API_ENTRY_STACK 64 + +/* Value types, used by e.g. duk_get_type() */ +#define DUK_TYPE_MIN 0 +#define DUK_TYPE_NONE 0 /* no value, e.g. invalid index */ +#define DUK_TYPE_UNDEFINED 1 /* Ecmascript undefined */ +#define DUK_TYPE_NULL 2 /* Ecmascript null */ +#define DUK_TYPE_BOOLEAN 3 /* Ecmascript boolean: 0 or 1 */ +#define DUK_TYPE_NUMBER 4 /* Ecmascript number: double */ +#define DUK_TYPE_STRING 5 /* Ecmascript string: CESU-8 / extended UTF-8 encoded */ +#define DUK_TYPE_OBJECT 6 /* Ecmascript object: includes objects, arrays, functions, threads */ +#define DUK_TYPE_BUFFER 7 /* fixed or dynamic, garbage collected byte buffer */ +#define DUK_TYPE_POINTER 8 /* raw void pointer */ +#define DUK_TYPE_LIGHTFUNC 9 /* lightweight function pointer */ +#define DUK_TYPE_MAX 9 + +/* Value mask types, used by e.g. duk_get_type_mask() */ +#define DUK_TYPE_MASK_NONE (1 << DUK_TYPE_NONE) +#define DUK_TYPE_MASK_UNDEFINED (1 << DUK_TYPE_UNDEFINED) +#define DUK_TYPE_MASK_NULL (1 << DUK_TYPE_NULL) +#define DUK_TYPE_MASK_BOOLEAN (1 << DUK_TYPE_BOOLEAN) +#define DUK_TYPE_MASK_NUMBER (1 << DUK_TYPE_NUMBER) +#define DUK_TYPE_MASK_STRING (1 << DUK_TYPE_STRING) +#define DUK_TYPE_MASK_OBJECT (1 << DUK_TYPE_OBJECT) +#define DUK_TYPE_MASK_BUFFER (1 << DUK_TYPE_BUFFER) +#define DUK_TYPE_MASK_POINTER (1 << DUK_TYPE_POINTER) +#define DUK_TYPE_MASK_LIGHTFUNC (1 << DUK_TYPE_LIGHTFUNC) +#define DUK_TYPE_MASK_THROW (1 << 10) /* internal flag value: throw if mask doesn't match */ +#define DUK_TYPE_MASK_PROMOTE (1 << 11) /* internal flag value: promote to object if mask matches */ + +/* Coercion hints */ +#define DUK_HINT_NONE 0 /* prefer number, unless input is a Date, in which + * case prefer string (E5 Section 8.12.8) + */ +#define DUK_HINT_STRING 1 /* prefer string */ +#define DUK_HINT_NUMBER 2 /* prefer number */ + +/* Enumeration flags for duk_enum() */ +#define DUK_ENUM_INCLUDE_NONENUMERABLE (1 << 0) /* enumerate non-numerable properties in addition to enumerable */ +#define DUK_ENUM_INCLUDE_HIDDEN (1 << 1) /* enumerate hidden symbols too (in Duktape 1.x called internal properties) */ +#define DUK_ENUM_INCLUDE_SYMBOLS (1 << 2) /* enumerate symbols */ +#define DUK_ENUM_EXCLUDE_STRINGS (1 << 3) /* exclude strings */ +#define DUK_ENUM_OWN_PROPERTIES_ONLY (1 << 4) /* don't walk prototype chain, only check own properties */ +#define DUK_ENUM_ARRAY_INDICES_ONLY (1 << 5) /* only enumerate array indices */ +#define DUK_ENUM_SORT_ARRAY_INDICES (1 << 6) /* sort array indices (applied to full enumeration result, including inherited array indices) */ +#define DUK_ENUM_NO_PROXY_BEHAVIOR (1 << 7) /* enumerate a proxy object itself without invoking proxy behavior */ + +/* Compilation flags for duk_compile() and duk_eval() */ +/* DUK_COMPILE_xxx bits 0-2 are reserved for an internal 'nargs' argument. + */ +#define DUK_COMPILE_EVAL (1 << 3) /* compile eval code (instead of global code) */ +#define DUK_COMPILE_FUNCTION (1 << 4) /* compile function code (instead of global code) */ +#define DUK_COMPILE_STRICT (1 << 5) /* use strict (outer) context for global, eval, or function code */ +#define DUK_COMPILE_SHEBANG (1 << 6) /* allow shebang ('#! ...') comment on first line of source */ +#define DUK_COMPILE_SAFE (1 << 7) /* (internal) catch compilation errors */ +#define DUK_COMPILE_NORESULT (1 << 8) /* (internal) omit eval result */ +#define DUK_COMPILE_NOSOURCE (1 << 9) /* (internal) no source string on stack */ +#define DUK_COMPILE_STRLEN (1 << 10) /* (internal) take strlen() of src_buffer (avoids double evaluation in macro) */ +#define DUK_COMPILE_NOFILENAME (1 << 11) /* (internal) no filename on stack */ +#define DUK_COMPILE_FUNCEXPR (1 << 12) /* (internal) source is a function expression (used for Function constructor) */ + +/* Flags for duk_def_prop() and its variants */ +#define DUK_DEFPROP_WRITABLE (1 << 0) /* set writable (effective if DUK_DEFPROP_HAVE_WRITABLE set) */ +#define DUK_DEFPROP_ENUMERABLE (1 << 1) /* set enumerable (effective if DUK_DEFPROP_HAVE_ENUMERABLE set) */ +#define DUK_DEFPROP_CONFIGURABLE (1 << 2) /* set configurable (effective if DUK_DEFPROP_HAVE_CONFIGURABLE set) */ +#define DUK_DEFPROP_HAVE_WRITABLE (1 << 3) /* set/clear writable */ +#define DUK_DEFPROP_HAVE_ENUMERABLE (1 << 4) /* set/clear enumerable */ +#define DUK_DEFPROP_HAVE_CONFIGURABLE (1 << 5) /* set/clear configurable */ +#define DUK_DEFPROP_HAVE_VALUE (1 << 6) /* set value (given on value stack) */ +#define DUK_DEFPROP_HAVE_GETTER (1 << 7) /* set getter (given on value stack) */ +#define DUK_DEFPROP_HAVE_SETTER (1 << 8) /* set setter (given on value stack) */ +#define DUK_DEFPROP_FORCE (1 << 9) /* force change if possible, may still fail for e.g. virtual properties */ +#define DUK_DEFPROP_SET_WRITABLE (DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE) +#define DUK_DEFPROP_CLEAR_WRITABLE DUK_DEFPROP_HAVE_WRITABLE +#define DUK_DEFPROP_SET_ENUMERABLE (DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE) +#define DUK_DEFPROP_CLEAR_ENUMERABLE DUK_DEFPROP_HAVE_ENUMERABLE +#define DUK_DEFPROP_SET_CONFIGURABLE (DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE) +#define DUK_DEFPROP_CLEAR_CONFIGURABLE DUK_DEFPROP_HAVE_CONFIGURABLE + +/* Flags for duk_push_thread_raw() */ +#define DUK_THREAD_NEW_GLOBAL_ENV (1 << 0) /* create a new global environment */ + +/* Flags for duk_gc() */ +#define DUK_GC_COMPACT (1 << 0) /* compact heap objects */ + +/* Error codes (must be 8 bits at most, see duk_error.h) */ +#define DUK_ERR_NONE 0 /* no error (e.g. from duk_get_error_code()) */ +#define DUK_ERR_ERROR 1 /* Error */ +#define DUK_ERR_EVAL_ERROR 2 /* EvalError */ +#define DUK_ERR_RANGE_ERROR 3 /* RangeError */ +#define DUK_ERR_REFERENCE_ERROR 4 /* ReferenceError */ +#define DUK_ERR_SYNTAX_ERROR 5 /* SyntaxError */ +#define DUK_ERR_TYPE_ERROR 6 /* TypeError */ +#define DUK_ERR_URI_ERROR 7 /* URIError */ + +/* Return codes for C functions (shortcut for throwing an error) */ +#define DUK_RET_ERROR (-DUK_ERR_ERROR) +#define DUK_RET_EVAL_ERROR (-DUK_ERR_EVAL_ERROR) +#define DUK_RET_RANGE_ERROR (-DUK_ERR_RANGE_ERROR) +#define DUK_RET_REFERENCE_ERROR (-DUK_ERR_REFERENCE_ERROR) +#define DUK_RET_SYNTAX_ERROR (-DUK_ERR_SYNTAX_ERROR) +#define DUK_RET_TYPE_ERROR (-DUK_ERR_TYPE_ERROR) +#define DUK_RET_URI_ERROR (-DUK_ERR_URI_ERROR) + +/* Return codes for protected calls (duk_safe_call(), duk_pcall()) */ +#define DUK_EXEC_SUCCESS 0 +#define DUK_EXEC_ERROR 1 + +/* Debug levels for DUK_USE_DEBUG_WRITE(). */ +#define DUK_LEVEL_DEBUG 0 +#define DUK_LEVEL_DDEBUG 1 +#define DUK_LEVEL_DDDEBUG 2 + +/* + * If no variadic macros, __FILE__ and __LINE__ are passed through globals + * which is ugly and not thread safe. + */ + +#if !defined(DUK_API_VARIADIC_MACROS) +DUK_EXTERNAL_DECL const char *duk_api_global_filename; +DUK_EXTERNAL_DECL duk_int_t duk_api_global_line; +#endif + +/* + * Context management + */ + +DUK_EXTERNAL_DECL +duk_context *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_EXTERNAL_DECL void duk_destroy_heap(duk_context *ctx); + +DUK_EXTERNAL_DECL void duk_suspend(duk_context *ctx, duk_thread_state *state); +DUK_EXTERNAL_DECL void duk_resume(duk_context *ctx, const duk_thread_state *state); + +#define duk_create_heap_default() \ + duk_create_heap(NULL, NULL, NULL, NULL, NULL) + +/* + * Memory management + * + * Raw functions have no side effects (cannot trigger GC). + */ + +DUK_EXTERNAL_DECL void *duk_alloc_raw(duk_context *ctx, duk_size_t size); +DUK_EXTERNAL_DECL void duk_free_raw(duk_context *ctx, void *ptr); +DUK_EXTERNAL_DECL void *duk_realloc_raw(duk_context *ctx, void *ptr, duk_size_t size); +DUK_EXTERNAL_DECL void *duk_alloc(duk_context *ctx, duk_size_t size); +DUK_EXTERNAL_DECL void duk_free(duk_context *ctx, void *ptr); +DUK_EXTERNAL_DECL void *duk_realloc(duk_context *ctx, void *ptr, duk_size_t size); +DUK_EXTERNAL_DECL void duk_get_memory_functions(duk_context *ctx, duk_memory_functions *out_funcs); +DUK_EXTERNAL_DECL void duk_gc(duk_context *ctx, duk_uint_t flags); + +/* + * Error handling + */ + +DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_throw_raw(duk_context *ctx)); +#define duk_throw(ctx) \ + (duk_throw_raw((ctx)), (duk_ret_t) 0) +DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_fatal_raw(duk_context *ctx, const char *err_msg)); +#define duk_fatal(ctx,err_msg) \ + (duk_fatal_raw((ctx), (err_msg)), (duk_ret_t) 0) +DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...)); + +#if defined(DUK_API_VARIADIC_MACROS) +#define duk_error(ctx,err_code,...) \ + (duk_error_raw((ctx), (duk_errcode_t) (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) +#define duk_generic_error(ctx,...) \ + (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) +#define duk_eval_error(ctx,...) \ + (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_EVAL_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) +#define duk_range_error(ctx,...) \ + (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_RANGE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) +#define duk_reference_error(ctx,...) \ + (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_REFERENCE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) +#define duk_syntax_error(ctx,...) \ + (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_SYNTAX_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) +#define duk_type_error(ctx,...) \ + (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_TYPE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) +#define duk_uri_error(ctx,...) \ + (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_URI_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) +#else /* DUK_API_VARIADIC_MACROS */ +/* For legacy compilers without variadic macros a macro hack is used to allow + * variable arguments. While the macro allows "return duk_error(...)", it + * will fail with e.g. "(void) duk_error(...)". The calls are noreturn but + * with a return value to allow the "return duk_error(...)" idiom. This may + * cause some compiler warnings, but without noreturn the generated code is + * often worse. The same approach as with variadic macros (using + * "(duk_error(...), 0)") won't work due to the macro hack structure. + */ +DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_error_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...)); +DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_generic_error_stash(duk_context *ctx, const char *fmt, ...)); +DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_eval_error_stash(duk_context *ctx, const char *fmt, ...)); +DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_range_error_stash(duk_context *ctx, const char *fmt, ...)); +DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_reference_error_stash(duk_context *ctx, const char *fmt, ...)); +DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_syntax_error_stash(duk_context *ctx, const char *fmt, ...)); +DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_type_error_stash(duk_context *ctx, const char *fmt, ...)); +DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_uri_error_stash(duk_context *ctx, const char *fmt, ...)); +#define duk_error \ + (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ + duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ + duk_error_stash) /* last value is func pointer, arguments follow in parens */ +#define duk_generic_error \ + (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ + duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ + duk_generic_error_stash) +#define duk_eval_error \ + (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ + duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ + duk_eval_error_stash) +#define duk_range_error \ + (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ + duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ + duk_range_error_stash) +#define duk_reference_error \ + (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ + duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ + duk_reference_error_stash) +#define duk_syntax_error \ + (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ + duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ + duk_syntax_error_stash) +#define duk_type_error \ + (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ + duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ + duk_type_error_stash) +#define duk_uri_error \ + (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ + duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ + duk_uri_error_stash) +#endif /* DUK_API_VARIADIC_MACROS */ + +DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap)); + +#define duk_error_va(ctx,err_code,fmt,ap) \ + (duk_error_va_raw((ctx), (duk_errcode_t) (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) +#define duk_generic_error_va(ctx,fmt,ap) \ + (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) +#define duk_eval_error_va(ctx,fmt,ap) \ + (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_EVAL_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) +#define duk_range_error_va(ctx,fmt,ap) \ + (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_RANGE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) +#define duk_reference_error_va(ctx,fmt,ap) \ + (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_REFERENCE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) +#define duk_syntax_error_va(ctx,fmt,ap) \ + (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_SYNTAX_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) +#define duk_type_error_va(ctx,fmt,ap) \ + (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_TYPE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) +#define duk_uri_error_va(ctx,fmt,ap) \ + (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_URI_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) + +/* + * Other state related functions + */ + +DUK_EXTERNAL_DECL duk_bool_t duk_is_strict_call(duk_context *ctx); +DUK_EXTERNAL_DECL duk_bool_t duk_is_constructor_call(duk_context *ctx); + +/* + * Stack management + */ + +DUK_EXTERNAL_DECL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_idx_t duk_require_normalize_index(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_bool_t duk_is_valid_index(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL void duk_require_valid_index(duk_context *ctx, duk_idx_t idx); + +DUK_EXTERNAL_DECL duk_idx_t duk_get_top(duk_context *ctx); +DUK_EXTERNAL_DECL void duk_set_top(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_idx_t duk_get_top_index(duk_context *ctx); +DUK_EXTERNAL_DECL duk_idx_t duk_require_top_index(duk_context *ctx); + +/* Although extra/top could be an unsigned type here, using a signed type + * makes the API more robust to calling code calculation errors or corner + * cases (where caller might occasionally come up with negative values). + * Negative values are treated as zero, which is better than casting them + * to a large unsigned number. (This principle is used elsewhere in the + * API too.) + */ +DUK_EXTERNAL_DECL duk_bool_t duk_check_stack(duk_context *ctx, duk_idx_t extra); +DUK_EXTERNAL_DECL void duk_require_stack(duk_context *ctx, duk_idx_t extra); +DUK_EXTERNAL_DECL duk_bool_t duk_check_stack_top(duk_context *ctx, duk_idx_t top); +DUK_EXTERNAL_DECL void duk_require_stack_top(duk_context *ctx, duk_idx_t top); + +/* + * Stack manipulation (other than push/pop) + */ + +DUK_EXTERNAL_DECL void duk_swap(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2); +DUK_EXTERNAL_DECL void duk_swap_top(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL void duk_dup(duk_context *ctx, duk_idx_t from_idx); +DUK_EXTERNAL_DECL void duk_dup_top(duk_context *ctx); +DUK_EXTERNAL_DECL void duk_insert(duk_context *ctx, duk_idx_t to_idx); +DUK_EXTERNAL_DECL void duk_replace(duk_context *ctx, duk_idx_t to_idx); +DUK_EXTERNAL_DECL void duk_copy(duk_context *ctx, duk_idx_t from_idx, duk_idx_t to_idx); +DUK_EXTERNAL_DECL void duk_remove(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx, duk_idx_t count, duk_bool_t is_copy); + +#define duk_xmove_top(to_ctx,from_ctx,count) \ + duk_xcopymove_raw((to_ctx), (from_ctx), (count), 0 /*is_copy*/) +#define duk_xcopy_top(to_ctx,from_ctx,count) \ + duk_xcopymove_raw((to_ctx), (from_ctx), (count), 1 /*is_copy*/) + +/* + * Push operations + * + * Push functions return the absolute (relative to bottom of frame) + * position of the pushed value for convenience. + * + * Note: duk_dup() is technically a push. + */ + +DUK_EXTERNAL_DECL void duk_push_undefined(duk_context *ctx); +DUK_EXTERNAL_DECL void duk_push_null(duk_context *ctx); +DUK_EXTERNAL_DECL void duk_push_boolean(duk_context *ctx, duk_bool_t val); +DUK_EXTERNAL_DECL void duk_push_true(duk_context *ctx); +DUK_EXTERNAL_DECL void duk_push_false(duk_context *ctx); +DUK_EXTERNAL_DECL void duk_push_number(duk_context *ctx, duk_double_t val); +DUK_EXTERNAL_DECL void duk_push_nan(duk_context *ctx); +DUK_EXTERNAL_DECL void duk_push_int(duk_context *ctx, duk_int_t val); +DUK_EXTERNAL_DECL void duk_push_uint(duk_context *ctx, duk_uint_t val); +DUK_EXTERNAL_DECL const char *duk_push_string(duk_context *ctx, const char *str); +DUK_EXTERNAL_DECL const char *duk_push_lstring(duk_context *ctx, const char *str, duk_size_t len); +DUK_EXTERNAL_DECL void duk_push_pointer(duk_context *ctx, void *p); +DUK_EXTERNAL_DECL const char *duk_push_sprintf(duk_context *ctx, const char *fmt, ...); +DUK_EXTERNAL_DECL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va_list ap); + +DUK_EXTERNAL_DECL void duk_push_this(duk_context *ctx); +DUK_EXTERNAL_DECL void duk_push_current_function(duk_context *ctx); +DUK_EXTERNAL_DECL void duk_push_current_thread(duk_context *ctx); +DUK_EXTERNAL_DECL void duk_push_global_object(duk_context *ctx); +DUK_EXTERNAL_DECL void duk_push_heap_stash(duk_context *ctx); +DUK_EXTERNAL_DECL void duk_push_global_stash(duk_context *ctx); +DUK_EXTERNAL_DECL void duk_push_thread_stash(duk_context *ctx, duk_context *target_ctx); + +DUK_EXTERNAL_DECL duk_idx_t duk_push_object(duk_context *ctx); +DUK_EXTERNAL_DECL duk_idx_t duk_push_bare_object(duk_context *ctx); +DUK_EXTERNAL_DECL duk_idx_t duk_push_array(duk_context *ctx); +DUK_EXTERNAL_DECL duk_idx_t duk_push_c_function(duk_context *ctx, duk_c_function func, duk_idx_t nargs); +DUK_EXTERNAL_DECL duk_idx_t duk_push_c_lightfunc(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_idx_t length, duk_int_t magic); +DUK_EXTERNAL_DECL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags); + +#define duk_push_thread(ctx) \ + duk_push_thread_raw((ctx), 0 /*flags*/) + +#define duk_push_thread_new_globalenv(ctx) \ + duk_push_thread_raw((ctx), DUK_THREAD_NEW_GLOBAL_ENV /*flags*/) + +DUK_EXTERNAL_DECL duk_idx_t duk_push_error_object_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...); + +#if defined(DUK_API_VARIADIC_MACROS) +#define duk_push_error_object(ctx,err_code,...) \ + duk_push_error_object_raw((ctx), (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__) +#else +DUK_EXTERNAL_DECL duk_idx_t duk_push_error_object_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...); +/* Note: parentheses are required so that the comma expression works in assignments. */ +#define duk_push_error_object \ + (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \ + duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \ + duk_push_error_object_stash) /* last value is func pointer, arguments follow in parens */ +#endif + +DUK_EXTERNAL_DECL duk_idx_t duk_push_error_object_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap); +#define duk_push_error_object_va(ctx,err_code,fmt,ap) \ + duk_push_error_object_va_raw((ctx), (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)) + +#define DUK_BUF_FLAG_DYNAMIC (1 << 0) /* internal flag: dynamic buffer */ +#define DUK_BUF_FLAG_EXTERNAL (1 << 1) /* internal flag: external buffer */ +#define DUK_BUF_FLAG_NOZERO (1 << 2) /* internal flag: don't zero allocated buffer */ + +DUK_EXTERNAL_DECL void *duk_push_buffer_raw(duk_context *ctx, duk_size_t size, duk_small_uint_t flags); + +#define duk_push_buffer(ctx,size,dynamic) \ + duk_push_buffer_raw((ctx), (size), (dynamic) ? DUK_BUF_FLAG_DYNAMIC : 0) +#define duk_push_fixed_buffer(ctx,size) \ + duk_push_buffer_raw((ctx), (size), 0 /*flags*/) +#define duk_push_dynamic_buffer(ctx,size) \ + duk_push_buffer_raw((ctx), (size), DUK_BUF_FLAG_DYNAMIC /*flags*/) +#define duk_push_external_buffer(ctx) \ + ((void) duk_push_buffer_raw((ctx), 0, DUK_BUF_FLAG_DYNAMIC | DUK_BUF_FLAG_EXTERNAL)) + +#define DUK_BUFOBJ_ARRAYBUFFER 0 +#define DUK_BUFOBJ_NODEJS_BUFFER 1 +#define DUK_BUFOBJ_DATAVIEW 2 +#define DUK_BUFOBJ_INT8ARRAY 3 +#define DUK_BUFOBJ_UINT8ARRAY 4 +#define DUK_BUFOBJ_UINT8CLAMPEDARRAY 5 +#define DUK_BUFOBJ_INT16ARRAY 6 +#define DUK_BUFOBJ_UINT16ARRAY 7 +#define DUK_BUFOBJ_INT32ARRAY 8 +#define DUK_BUFOBJ_UINT32ARRAY 9 +#define DUK_BUFOBJ_FLOAT32ARRAY 10 +#define DUK_BUFOBJ_FLOAT64ARRAY 11 + +DUK_EXTERNAL_DECL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags); + +DUK_EXTERNAL_DECL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr); + +/* + * Pop operations + */ + +DUK_EXTERNAL_DECL void duk_pop(duk_context *ctx); +DUK_EXTERNAL_DECL void duk_pop_n(duk_context *ctx, duk_idx_t count); +DUK_EXTERNAL_DECL void duk_pop_2(duk_context *ctx); +DUK_EXTERNAL_DECL void duk_pop_3(duk_context *ctx); + +/* + * Type checks + * + * duk_is_none(), which would indicate whether index it outside of stack, + * is not needed; duk_is_valid_index() gives the same information. + */ + +DUK_EXTERNAL_DECL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_bool_t duk_check_type(duk_context *ctx, duk_idx_t idx, duk_int_t type); +DUK_EXTERNAL_DECL duk_uint_t duk_get_type_mask(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_bool_t duk_check_type_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t mask); + +DUK_EXTERNAL_DECL duk_bool_t duk_is_undefined(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_bool_t duk_is_null(duk_context *ctx, duk_idx_t idx); +#define duk_is_null_or_undefined(ctx, idx) \ + ((duk_get_type_mask((ctx), (idx)) & (DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_UNDEFINED)) ? 1 : 0) + +DUK_EXTERNAL_DECL duk_bool_t duk_is_boolean(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_bool_t duk_is_number(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_bool_t duk_is_nan(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_bool_t duk_is_string(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_bool_t duk_is_object(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_bool_t duk_is_buffer(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_bool_t duk_is_buffer_data(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_bool_t duk_is_pointer(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_bool_t duk_is_lightfunc(duk_context *ctx, duk_idx_t idx); + +DUK_EXTERNAL_DECL duk_bool_t duk_is_symbol(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_bool_t duk_is_array(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_bool_t duk_is_function(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_bool_t duk_is_c_function(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_bool_t duk_is_ecmascript_function(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_bool_t duk_is_bound_function(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t idx); + +#define duk_is_callable(ctx,idx) \ + duk_is_function((ctx), (idx)) +DUK_EXTERNAL_DECL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t idx); + +/* Buffers and lightfuncs are not considered primitive because they mimic + * objects and e.g. duk_to_primitive() will coerce them instead of returning + * them as is. Symbols are represented as strings internally. + */ +#define duk_is_primitive(ctx,idx) \ + duk_check_type_mask((ctx), (idx), DUK_TYPE_MASK_UNDEFINED | \ + DUK_TYPE_MASK_NULL | \ + DUK_TYPE_MASK_BOOLEAN | \ + DUK_TYPE_MASK_NUMBER | \ + DUK_TYPE_MASK_STRING | \ + DUK_TYPE_MASK_POINTER) + +/* Symbols are object coercible, covered by DUK_TYPE_MASK_STRING. */ +#define duk_is_object_coercible(ctx,idx) \ + duk_check_type_mask((ctx), (idx), DUK_TYPE_MASK_BOOLEAN | \ + DUK_TYPE_MASK_NUMBER | \ + DUK_TYPE_MASK_STRING | \ + DUK_TYPE_MASK_OBJECT | \ + DUK_TYPE_MASK_BUFFER | \ + DUK_TYPE_MASK_POINTER | \ + DUK_TYPE_MASK_LIGHTFUNC) + +DUK_EXTERNAL_DECL duk_errcode_t duk_get_error_code(duk_context *ctx, duk_idx_t idx); +#define duk_is_error(ctx,idx) \ + (duk_get_error_code((ctx), (idx)) != 0) +#define duk_is_eval_error(ctx,idx) \ + (duk_get_error_code((ctx), (idx)) == DUK_ERR_EVAL_ERROR) +#define duk_is_range_error(ctx,idx) \ + (duk_get_error_code((ctx), (idx)) == DUK_ERR_RANGE_ERROR) +#define duk_is_reference_error(ctx,idx) \ + (duk_get_error_code((ctx), (idx)) == DUK_ERR_REFERENCE_ERROR) +#define duk_is_syntax_error(ctx,idx) \ + (duk_get_error_code((ctx), (idx)) == DUK_ERR_SYNTAX_ERROR) +#define duk_is_type_error(ctx,idx) \ + (duk_get_error_code((ctx), (idx)) == DUK_ERR_TYPE_ERROR) +#define duk_is_uri_error(ctx,idx) \ + (duk_get_error_code((ctx), (idx)) == DUK_ERR_URI_ERROR) + +/* + * Get operations: no coercion, returns default value for invalid + * indices and invalid value types. + * + * duk_get_undefined() and duk_get_null() would be pointless and + * are not included. + */ + +DUK_EXTERNAL_DECL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL const char *duk_get_string(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL const char *duk_get_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len); +DUK_EXTERNAL_DECL void *duk_get_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size); +DUK_EXTERNAL_DECL void *duk_get_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size); +DUK_EXTERNAL_DECL void *duk_get_pointer(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_context *duk_get_context(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL void *duk_get_heapptr(duk_context *ctx, duk_idx_t idx); + +/* + * Get-with-explicit default operations: like get operations but with an + * explicit default value. + */ + +DUK_EXTERNAL_DECL duk_bool_t duk_get_boolean_default(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value); +DUK_EXTERNAL_DECL duk_double_t duk_get_number_default(duk_context *ctx, duk_idx_t idx, duk_double_t def_value); +DUK_EXTERNAL_DECL duk_int_t duk_get_int_default(duk_context *ctx, duk_idx_t idx, duk_int_t def_value); +DUK_EXTERNAL_DECL duk_uint_t duk_get_uint_default(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value); +DUK_EXTERNAL_DECL const char *duk_get_string_default(duk_context *ctx, duk_idx_t idx, const char *def_value); +DUK_EXTERNAL_DECL const char *duk_get_lstring_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len); +DUK_EXTERNAL_DECL void *duk_get_buffer_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len); +DUK_EXTERNAL_DECL void *duk_get_buffer_data_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len); +DUK_EXTERNAL_DECL void *duk_get_pointer_default(duk_context *ctx, duk_idx_t idx, void *def_value); +DUK_EXTERNAL_DECL duk_c_function duk_get_c_function_default(duk_context *ctx, duk_idx_t idx, duk_c_function def_value); +DUK_EXTERNAL_DECL duk_context *duk_get_context_default(duk_context *ctx, duk_idx_t idx, duk_context *def_value); +DUK_EXTERNAL_DECL void *duk_get_heapptr_default(duk_context *ctx, duk_idx_t idx, void *def_value); + +/* + * Opt operations: like require operations but with an explicit default value + * when value is undefined or index is invalid, null and non-matching types + * cause a TypeError. + */ + +DUK_EXTERNAL_DECL duk_bool_t duk_opt_boolean(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value); +DUK_EXTERNAL_DECL duk_double_t duk_opt_number(duk_context *ctx, duk_idx_t idx, duk_double_t def_value); +DUK_EXTERNAL_DECL duk_int_t duk_opt_int(duk_context *ctx, duk_idx_t idx, duk_int_t def_value); +DUK_EXTERNAL_DECL duk_uint_t duk_opt_uint(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value); +DUK_EXTERNAL_DECL const char *duk_opt_string(duk_context *ctx, duk_idx_t idx, const char *def_ptr); +DUK_EXTERNAL_DECL const char *duk_opt_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len); +DUK_EXTERNAL_DECL void *duk_opt_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size); +DUK_EXTERNAL_DECL void *duk_opt_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size); +DUK_EXTERNAL_DECL void *duk_opt_pointer(duk_context *ctx, duk_idx_t idx, void *def_value); +DUK_EXTERNAL_DECL duk_c_function duk_opt_c_function(duk_context *ctx, duk_idx_t idx, duk_c_function def_value); +DUK_EXTERNAL_DECL duk_context *duk_opt_context(duk_context *ctx, duk_idx_t idx, duk_context *def_value); +DUK_EXTERNAL_DECL void *duk_opt_heapptr(duk_context *ctx, duk_idx_t idx, void *def_value); + +/* + * Require operations: no coercion, throw error if index or type + * is incorrect. No defaulting. + */ + +#define duk_require_type_mask(ctx,idx,mask) \ + ((void) duk_check_type_mask((ctx), (idx), (mask) | DUK_TYPE_MASK_THROW)) -@DUK_DBLUNION_H@ +DUK_EXTERNAL_DECL void duk_require_undefined(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL void duk_require_null(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL const char *duk_require_string(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL const char *duk_require_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len); +DUK_EXTERNAL_DECL void *duk_require_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size); +DUK_EXTERNAL_DECL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size); +DUK_EXTERNAL_DECL void *duk_require_pointer(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_context *duk_require_context(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL void duk_require_function(duk_context *ctx, duk_idx_t idx); +#define duk_require_callable(ctx,idx) \ + duk_require_function((ctx), (idx)) +DUK_EXTERNAL_DECL void *duk_require_heapptr(duk_context *ctx, duk_idx_t idx); + +/* Symbols are object coercible and covered by DUK_TYPE_MASK_STRING. */ +#define duk_require_object_coercible(ctx,idx) \ + ((void) duk_check_type_mask((ctx), (idx), DUK_TYPE_MASK_BOOLEAN | \ + DUK_TYPE_MASK_NUMBER | \ + DUK_TYPE_MASK_STRING | \ + DUK_TYPE_MASK_OBJECT | \ + DUK_TYPE_MASK_BUFFER | \ + DUK_TYPE_MASK_POINTER | \ + DUK_TYPE_MASK_LIGHTFUNC | \ + DUK_TYPE_MASK_THROW)) + +/* + * Coercion operations: in-place coercion, return coerced value where + * applicable. If index is invalid, throw error. Some coercions may + * throw an expected error (e.g. from a toString() or valueOf() call) + * or an internal error (e.g. from out of memory). + */ + +DUK_EXTERNAL_DECL void duk_to_undefined(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL void duk_to_null(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_bool_t duk_to_boolean(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_double_t duk_to_number(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_uint32_t duk_to_uint32(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_uint16_t duk_to_uint16(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL const char *duk_to_string(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL const char *duk_to_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len); +DUK_EXTERNAL_DECL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_uint_t flags); +DUK_EXTERNAL_DECL void *duk_to_pointer(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL void duk_to_object(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL void duk_to_primitive(duk_context *ctx, duk_idx_t idx, duk_int_t hint); + +#define DUK_BUF_MODE_FIXED 0 /* internal: request fixed buffer result */ +#define DUK_BUF_MODE_DYNAMIC 1 /* internal: request dynamic buffer result */ +#define DUK_BUF_MODE_DONTCARE 2 /* internal: don't care about fixed/dynamic nature */ + +#define duk_to_buffer(ctx,idx,out_size) \ + duk_to_buffer_raw((ctx), (idx), (out_size), DUK_BUF_MODE_DONTCARE) +#define duk_to_fixed_buffer(ctx,idx,out_size) \ + duk_to_buffer_raw((ctx), (idx), (out_size), DUK_BUF_MODE_FIXED) +#define duk_to_dynamic_buffer(ctx,idx,out_size) \ + duk_to_buffer_raw((ctx), (idx), (out_size), DUK_BUF_MODE_DYNAMIC) + +/* safe variants of a few coercion operations */ +DUK_EXTERNAL_DECL const char *duk_safe_to_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len); +#define duk_safe_to_string(ctx,idx) \ + duk_safe_to_lstring((ctx), (idx), NULL) + +/* + * Value length + */ + +DUK_EXTERNAL_DECL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t idx, duk_size_t len); +#if 0 +/* duk_require_length()? */ +/* duk_opt_length()? */ +#endif + +/* + * Misc conversion + */ + +DUK_EXTERNAL_DECL const char *duk_base64_encode(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL void duk_base64_decode(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL const char *duk_hex_encode(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL void duk_hex_decode(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL const char *duk_json_encode(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL void duk_json_decode(duk_context *ctx, duk_idx_t idx); + +DUK_EXTERNAL_DECL const char *duk_buffer_to_string(duk_context *ctx, duk_idx_t idx); + +/* + * Buffer + */ + +DUK_EXTERNAL_DECL void *duk_resize_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t new_size); +DUK_EXTERNAL_DECL void *duk_steal_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size); +DUK_EXTERNAL_DECL void duk_config_buffer(duk_context *ctx, duk_idx_t idx, void *ptr, duk_size_t len); + +/* + * Property access + * + * The basic function assumes key is on stack. The _string variant takes + * a C string as a property name, while the _index variant takes an array + * index as a property name (e.g. 123 is equivalent to the key "123"). + */ + +DUK_EXTERNAL_DECL duk_bool_t duk_get_prop(duk_context *ctx, duk_idx_t obj_idx); +DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key); +DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len); +DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx); +DUK_EXTERNAL_DECL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_idx); +DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key); +DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len); +DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx); +DUK_EXTERNAL_DECL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_idx); +DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key); +DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len); +DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx); +DUK_EXTERNAL_DECL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_idx); +DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key); +DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len); +DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx); + +DUK_EXTERNAL_DECL void duk_get_prop_desc(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t flags); +DUK_EXTERNAL_DECL void duk_def_prop(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t flags); + +DUK_EXTERNAL_DECL duk_bool_t duk_get_global_string(duk_context *ctx, const char *key); +DUK_EXTERNAL_DECL duk_bool_t duk_get_global_lstring(duk_context *ctx, const char *key, duk_size_t key_len); +DUK_EXTERNAL_DECL duk_bool_t duk_put_global_string(duk_context *ctx, const char *key); +DUK_EXTERNAL_DECL duk_bool_t duk_put_global_lstring(duk_context *ctx, const char *key, duk_size_t key_len); + +/* + * Inspection + */ + +DUK_EXTERNAL_DECL void duk_inspect_value(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL void duk_inspect_callstack_entry(duk_context *ctx, duk_int_t level); + +/* + * Object prototype + */ + +DUK_EXTERNAL_DECL void duk_get_prototype(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL void duk_set_prototype(duk_context *ctx, duk_idx_t idx); + +/* + * Object finalizer + */ + +DUK_EXTERNAL_DECL void duk_get_finalizer(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL void duk_set_finalizer(duk_context *ctx, duk_idx_t idx); + +/* + * Global object + */ + +DUK_EXTERNAL_DECL void duk_set_global_object(duk_context *ctx); + +/* + * Duktape/C function magic value + */ + +DUK_EXTERNAL_DECL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL void duk_set_magic(duk_context *ctx, duk_idx_t idx, duk_int_t magic); +DUK_EXTERNAL_DECL duk_int_t duk_get_current_magic(duk_context *ctx); + +/* + * Module helpers: put multiple function or constant properties + */ + +DUK_EXTERNAL_DECL void duk_put_function_list(duk_context *ctx, duk_idx_t obj_idx, const duk_function_list_entry *funcs); +DUK_EXTERNAL_DECL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_idx, const duk_number_list_entry *numbers); + +/* + * Object operations + */ + +DUK_EXTERNAL_DECL void duk_compact(duk_context *ctx, duk_idx_t obj_idx); +DUK_EXTERNAL_DECL void duk_enum(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t enum_flags); +DUK_EXTERNAL_DECL duk_bool_t duk_next(duk_context *ctx, duk_idx_t enum_idx, duk_bool_t get_value); + +/* + * String manipulation + */ + +DUK_EXTERNAL_DECL void duk_concat(duk_context *ctx, duk_idx_t count); +DUK_EXTERNAL_DECL void duk_join(duk_context *ctx, duk_idx_t count); +DUK_EXTERNAL_DECL void duk_decode_string(duk_context *ctx, duk_idx_t idx, duk_decode_char_function callback, void *udata); +DUK_EXTERNAL_DECL void duk_map_string(duk_context *ctx, duk_idx_t idx, duk_map_char_function callback, void *udata); +DUK_EXTERNAL_DECL void duk_substring(duk_context *ctx, duk_idx_t idx, duk_size_t start_char_offset, duk_size_t end_char_offset); +DUK_EXTERNAL_DECL void duk_trim(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL duk_codepoint_t duk_char_code_at(duk_context *ctx, duk_idx_t idx, duk_size_t char_offset); + +/* + * Ecmascript operators + */ + +DUK_EXTERNAL_DECL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2); +DUK_EXTERNAL_DECL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2); +DUK_EXTERNAL_DECL duk_bool_t duk_samevalue(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2); +DUK_EXTERNAL_DECL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2); + +/* + * Function (method) calls + */ + +DUK_EXTERNAL_DECL void duk_call(duk_context *ctx, duk_idx_t nargs); +DUK_EXTERNAL_DECL void duk_call_method(duk_context *ctx, duk_idx_t nargs); +DUK_EXTERNAL_DECL void duk_call_prop(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t nargs); +DUK_EXTERNAL_DECL duk_int_t duk_pcall(duk_context *ctx, duk_idx_t nargs); +DUK_EXTERNAL_DECL duk_int_t duk_pcall_method(duk_context *ctx, duk_idx_t nargs); +DUK_EXTERNAL_DECL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t nargs); +DUK_EXTERNAL_DECL void duk_new(duk_context *ctx, duk_idx_t nargs); +DUK_EXTERNAL_DECL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs); +DUK_EXTERNAL_DECL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, void *udata, duk_idx_t nargs, duk_idx_t nrets); + +/* + * Thread management + */ + +/* There are currently no native functions to yield/resume, due to the internal + * limitations on coroutine handling. These will be added later. + */ + +/* + * Compilation and evaluation + */ + +DUK_EXTERNAL_DECL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags); +DUK_EXTERNAL_DECL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags); + +/* plain */ +#define duk_eval(ctx) \ + ((void) duk_eval_raw((ctx), NULL, 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOFILENAME)) + +#define duk_eval_noresult(ctx) \ + ((void) duk_eval_raw((ctx), NULL, 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME)) + +#define duk_peval(ctx) \ + (duk_eval_raw((ctx), NULL, 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOFILENAME)) + +#define duk_peval_noresult(ctx) \ + (duk_eval_raw((ctx), NULL, 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME)) + +#define duk_compile(ctx,flags) \ + ((void) duk_compile_raw((ctx), NULL, 0, 2 /*args*/ | (flags))) + +#define duk_pcompile(ctx,flags) \ + (duk_compile_raw((ctx), NULL, 0, 2 /*args*/ | (flags) | DUK_COMPILE_SAFE)) + +/* string */ +#define duk_eval_string(ctx,src) \ + ((void) duk_eval_raw((ctx), (src), 0, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME)) + +#define duk_eval_string_noresult(ctx,src) \ + ((void) duk_eval_raw((ctx), (src), 0, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME)) + +#define duk_peval_string(ctx,src) \ + (duk_eval_raw((ctx), (src), 0, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME)) + +#define duk_peval_string_noresult(ctx,src) \ + (duk_eval_raw((ctx), (src), 0, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME)) + +#define duk_compile_string(ctx,flags,src) \ + ((void) duk_compile_raw((ctx), (src), 0, 0 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME)) + +#define duk_compile_string_filename(ctx,flags,src) \ + ((void) duk_compile_raw((ctx), (src), 0, 1 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN)) + +#define duk_pcompile_string(ctx,flags,src) \ + (duk_compile_raw((ctx), (src), 0, 0 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME)) + +#define duk_pcompile_string_filename(ctx,flags,src) \ + (duk_compile_raw((ctx), (src), 0, 1 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN)) + +/* lstring */ +#define duk_eval_lstring(ctx,buf,len) \ + ((void) duk_eval_raw((ctx), buf, len, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NOFILENAME)) + +#define duk_eval_lstring_noresult(ctx,buf,len) \ + ((void) duk_eval_raw((ctx), buf, len, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME)) + +#define duk_peval_lstring(ctx,buf,len) \ + (duk_eval_raw((ctx), buf, len, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_SAFE | DUK_COMPILE_NOFILENAME)) + +#define duk_peval_lstring_noresult(ctx,buf,len) \ + (duk_eval_raw((ctx), buf, len, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME)) + +#define duk_compile_lstring(ctx,flags,buf,len) \ + ((void) duk_compile_raw((ctx), buf, len, 0 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NOFILENAME)) + +#define duk_compile_lstring_filename(ctx,flags,buf,len) \ + ((void) duk_compile_raw((ctx), buf, len, 1 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE)) + +#define duk_pcompile_lstring(ctx,flags,buf,len) \ + (duk_compile_raw((ctx), buf, len, 0 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NOFILENAME)) + +#define duk_pcompile_lstring_filename(ctx,flags,buf,len) \ + (duk_compile_raw((ctx), buf, len, 1 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE)) + +/* + * Bytecode load/dump + */ + +DUK_EXTERNAL_DECL void duk_dump_function(duk_context *ctx); +DUK_EXTERNAL_DECL void duk_load_function(duk_context *ctx); + +/* + * Debugging + */ + +DUK_EXTERNAL_DECL void duk_push_context_dump(duk_context *ctx); + +/* + * Debugger (debug protocol) + */ + +DUK_EXTERNAL_DECL void duk_debugger_attach(duk_context *ctx, + 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_EXTERNAL_DECL void duk_debugger_detach(duk_context *ctx); +DUK_EXTERNAL_DECL void duk_debugger_cooperate(duk_context *ctx); +DUK_EXTERNAL_DECL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues); +DUK_EXTERNAL_DECL void duk_debugger_pause(duk_context *ctx); + +/* + * Time handling + */ + +DUK_EXTERNAL_DECL duk_double_t duk_get_now(duk_context *ctx); +DUK_EXTERNAL_DECL void duk_time_to_components(duk_context *ctx, duk_double_t timeval, duk_time_components *comp); +DUK_EXTERNAL_DECL duk_double_t duk_components_to_time(duk_context *ctx, duk_time_components *comp); + +/* + * Date provider related constants + * + * NOTE: These are "semi public" - you should only use these if you write + * your own platform specific Date provider, see doc/datetime.rst. + */ + +/* Millisecond count constants. */ +#define DUK_DATE_MSEC_SECOND 1000L +#define DUK_DATE_MSEC_MINUTE (60L * 1000L) +#define DUK_DATE_MSEC_HOUR (60L * 60L * 1000L) +#define DUK_DATE_MSEC_DAY (24L * 60L * 60L * 1000L) + +/* Ecmascript date range is 100 million days from Epoch: + * > 100e6 * 24 * 60 * 60 * 1000 // 100M days in millisecs + * 8640000000000000 + * (= 8.64e15) + */ +#define DUK_DATE_MSEC_100M_DAYS (8.64e15) +#define DUK_DATE_MSEC_100M_DAYS_LEEWAY (8.64e15 + 24 * 3600e3) + +/* Ecmascript year range: + * > new Date(100e6 * 24 * 3600e3).toISOString() + * '+275760-09-13T00:00:00.000Z' + * > new Date(-100e6 * 24 * 3600e3).toISOString() + * '-271821-04-20T00:00:00.000Z' + */ +#define DUK_DATE_MIN_ECMA_YEAR (-271821L) +#define DUK_DATE_MAX_ECMA_YEAR 275760L + +/* Part indices for internal breakdowns. Part order from DUK_DATE_IDX_YEAR + * to DUK_DATE_IDX_MILLISECOND matches argument ordering of Ecmascript API + * calls (like Date constructor call). Some functions in duk_bi_date.c + * depend on the specific ordering, so change with care. 16 bits are not + * enough for all parts (year, specifically). + * + * Must be in-sync with genbuiltins.py. + */ +#define DUK_DATE_IDX_YEAR 0 /* year */ +#define DUK_DATE_IDX_MONTH 1 /* month: 0 to 11 */ +#define DUK_DATE_IDX_DAY 2 /* day within month: 0 to 30 */ +#define DUK_DATE_IDX_HOUR 3 +#define DUK_DATE_IDX_MINUTE 4 +#define DUK_DATE_IDX_SECOND 5 +#define DUK_DATE_IDX_MILLISECOND 6 +#define DUK_DATE_IDX_WEEKDAY 7 /* weekday: 0 to 6, 0=sunday, 1=monday, etc */ +#define DUK_DATE_IDX_NUM_PARTS 8 + +/* Internal API call flags, used for various functions in duk_bi_date.c. + * Certain flags are used by only certain functions, but since the flags + * don't overlap, a single flags value can be passed around to multiple + * functions. + * + * The unused top bits of the flags field are also used to pass values + * to helpers (duk__get_part_helper() and duk__set_part_helper()). + * + * Must be in-sync with genbuiltins.py. + */ + +/* NOTE: when writing a Date provider you only need a few specific + * flags from here, the rest are internal. Avoid using anything you + * don't need. + */ + +#define DUK_DATE_FLAG_NAN_TO_ZERO (1 << 0) /* timeval breakdown: internal time value NaN -> zero */ +#define DUK_DATE_FLAG_NAN_TO_RANGE_ERROR (1 << 1) /* timeval breakdown: internal time value NaN -> RangeError (toISOString) */ +#define DUK_DATE_FLAG_ONEBASED (1 << 2) /* timeval breakdown: convert month and day-of-month parts to one-based (default is zero-based) */ +#define DUK_DATE_FLAG_EQUIVYEAR (1 << 3) /* timeval breakdown: replace year with equivalent year in the [1971,2037] range for DST calculations */ +#define DUK_DATE_FLAG_LOCALTIME (1 << 4) /* convert time value to local time */ +#define DUK_DATE_FLAG_SUB1900 (1 << 5) /* getter: subtract 1900 from year when getting year part */ +#define DUK_DATE_FLAG_TOSTRING_DATE (1 << 6) /* include date part in string conversion result */ +#define DUK_DATE_FLAG_TOSTRING_TIME (1 << 7) /* include time part in string conversion result */ +#define DUK_DATE_FLAG_TOSTRING_LOCALE (1 << 8) /* use locale specific formatting if available */ +#define DUK_DATE_FLAG_TIMESETTER (1 << 9) /* setter: call is a time setter (affects hour, min, sec, ms); otherwise date setter (affects year, month, day-in-month) */ +#define DUK_DATE_FLAG_YEAR_FIXUP (1 << 10) /* setter: perform 2-digit year fixup (00...99 -> 1900...1999) */ +#define DUK_DATE_FLAG_SEP_T (1 << 11) /* string conversion: use 'T' instead of ' ' as a separator */ +#define DUK_DATE_FLAG_VALUE_SHIFT 12 /* additional values begin at bit 12 */ + +/* + * ROM pointer compression + */ + +/* Support array for ROM pointer compression. Only declared when ROM + * pointer compression is active. + */ +#if defined(DUK_USE_ROM_OBJECTS) && defined(DUK_USE_HEAPPTR16) +DUK_EXTERNAL_DECL const void * const duk_rom_compressed_pointers[]; +#endif + +/* + * C++ name mangling + */ + +#if defined(__cplusplus) +/* end 'extern "C"' wrapper */ +} +#endif + +/* + * END PUBLIC API + */ #endif /* DUKTAPE_H_INCLUDED */ diff -Nru duktape-2.0.0/src-input/duk_util_bitdecoder.c duktape-2.1.1/src-input/duk_util_bitdecoder.c --- duktape-2.0.0/src-input/duk_util_bitdecoder.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_util_bitdecoder.c 2017-07-28 22:05:08.000000000 +0000 @@ -58,8 +58,7 @@ } /* Decode a one-bit flag, and if set, decode a value of 'bits', otherwise return - * default value. Return value is signed so that negative marker value can be - * used by caller as a "not present" value. + * default value. */ DUK_INTERNAL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value) { if (duk_bd_decode_flag(ctx)) { @@ -69,6 +68,11 @@ } } +/* Signed variant, allows negative marker value. */ +DUK_INTERNAL duk_int32_t duk_bd_decode_flagged_signed(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value) { + return (duk_int32_t) duk_bd_decode_flagged(ctx, bits, (duk_uint32_t) def_value); +} + /* Shared varint encoding. Match dukutil.py BitEncode.varuint(). */ DUK_INTERNAL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx) { duk_small_uint_t t; diff -Nru duktape-2.0.0/src-input/duk_util_bufwriter.c duktape-2.1.1/src-input/duk_util_bufwriter.c --- duktape-2.0.0/src-input/duk_util_bufwriter.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_util_bufwriter.c 2017-07-28 22:05:08.000000000 +0000 @@ -63,7 +63,7 @@ curr_off = (duk_size_t) (bw_ctx->p - bw_ctx->p_base); add_sz = (curr_off >> DUK_BW_SPARE_SHIFT) + DUK_BW_SPARE_ADD; new_sz = curr_off + sz + add_sz; - if (new_sz < curr_off) { + if (DUK_UNLIKELY(new_sz < curr_off)) { /* overflow */ DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG); return NULL; /* not reachable */ diff -Nru duktape-2.0.0/src-input/duk_util.h duktape-2.1.1/src-input/duk_util.h --- duktape-2.0.0/src-input/duk_util.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_util.h 2017-07-28 22:05:08.000000000 +0000 @@ -5,10 +5,6 @@ #if !defined(DUK_UTIL_H_INCLUDED) #define DUK_UTIL_H_INCLUDED -#define DUK_UTIL_MIN_HASH_PRIME 17 /* must match genhashsizes.py */ - -#define DUK_UTIL_GET_HASH_PROBE_STEP(hash) (duk_util_probe_steps[(hash) & 0x1f]) - #if defined(DUK_USE_GET_RANDOM_DOUBLE) #define DUK_UTIL_GET_RANDOM_DOUBLE(thr) DUK_USE_GET_RANDOM_DOUBLE((thr)->heap_udata) #else @@ -494,7 +490,7 @@ #endif /* !DUK_SINGLE_FILE */ /* Note: assumes that duk_util_probe_steps size is 32 */ -#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE) +#if defined(DUK_USE_HOBJECT_HASH_PART) #if !defined(DUK_SINGLE_FILE) DUK_INTERNAL_DECL duk_uint8_t duk_util_probe_steps[32]; #endif /* !DUK_SINGLE_FILE */ @@ -504,13 +500,10 @@ DUK_INTERNAL_DECL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed); #endif -#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE) -DUK_INTERNAL_DECL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size); -#endif - DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits); DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx); DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value); +DUK_INTERNAL_DECL duk_int32_t duk_bd_decode_flagged_signed(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value); DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx); DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_bitpacked_string(duk_bitdecoder_ctx *bd, duk_uint8_t *out); diff -Nru duktape-2.0.0/src-input/duk_util_hashprime.c duktape-2.1.1/src-input/duk_util_hashprime.c --- duktape-2.0.0/src-input/duk_util_hashprime.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/duk_util_hashprime.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,77 +0,0 @@ -/* - * Round a number upwards to a prime (not usually the nearest one). - * - * Uses a table of successive 32-bit primes whose ratio is roughly - * constant. This keeps the relative upwards 'rounding error' bounded - * and the data size small. A simple 'predict-correct' compression is - * used to compress primes to one byte per prime. See genhashsizes.py - * for details. - * - * The minimum prime returned here must be coordinated with the possible - * probe sequence steps in duk_hobject and duk_heap stringtable. - */ - -#include "duk_internal.h" - -/* Awkward inclusion condition: drop out of compilation if not needed by any - * call site: object hash part or probing stringtable. - */ -#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE) - -/* hash size ratio goal, must match genhashsizes.py */ -#define DUK__HASH_SIZE_RATIO 1177 /* floor(1.15 * (1 << 10)) */ - -/* prediction corrections for prime list (see genhashsizes.py) */ -DUK_LOCAL const duk_int8_t duk__hash_size_corrections[] = { - 17, /* minimum prime */ - 4, 3, 4, 1, 4, 1, 1, 2, 2, 2, 2, 1, 6, 6, 9, 5, 1, 2, 2, 5, 1, 3, 3, 3, - 5, 4, 4, 2, 4, 8, 3, 4, 23, 2, 4, 7, 8, 11, 2, 12, 15, 10, 1, 1, 5, 1, 5, - 8, 9, 17, 14, 10, 7, 5, 2, 46, 21, 1, 9, 9, 4, 4, 10, 23, 36, 6, 20, 29, - 18, 6, 19, 21, 16, 11, 5, 5, 48, 9, 1, 39, 14, 8, 4, 29, 9, 1, 15, 48, 12, - 22, 6, 15, 27, 4, 2, 17, 28, 8, 9, 4, 5, 8, 3, 3, 8, 37, 11, 15, 8, 30, - 43, 6, 33, 41, 5, 20, 32, 41, 38, 24, 77, 14, 19, 11, 4, 35, 18, 19, 41, - 10, 23, 16, 9, 2, - -1 -}; - -/* probe steps (see genhashsizes.py), currently assumed to be 32 entries long - * (DUK_UTIL_GET_HASH_PROBE_STEP macro). - */ -DUK_INTERNAL duk_uint8_t duk_util_probe_steps[32] = { - 2, 3, 5, 7, 11, 13, 19, 31, 41, 47, 59, 67, 73, 79, 89, 101, 103, 107, - 109, 127, 137, 139, 149, 157, 163, 167, 173, 181, 191, 193, 197, 199 -}; - -DUK_INTERNAL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size) { - const duk_int8_t *p = duk__hash_size_corrections; - duk_uint32_t curr; - - curr = (duk_uint32_t) *p++; - for (;;) { - duk_small_int_t t = (duk_small_int_t) *p++; - if (t < 0) { - /* may happen if size is very close to 2^32-1 */ - break; - } - - /* prediction: portable variant using doubles if 64-bit values not available */ -#if defined(DUK_USE_64BIT_OPS) - curr = (duk_uint32_t) ((((duk_uint64_t) curr) * ((duk_uint64_t) DUK__HASH_SIZE_RATIO)) >> 10); -#else - /* 32-bit x 11-bit = 43-bit, fits accurately into a double */ - curr = (duk_uint32_t) DUK_FLOOR(((double) curr) * ((double) DUK__HASH_SIZE_RATIO) / 1024.0); -#endif - - /* correction */ - curr += t; - - DUK_DDD(DUK_DDDPRINT("size=%ld, curr=%ld", (long) size, (long) curr)); - - if (curr >= size) { - return curr; - } - } - return 0; -} - -#endif /* DUK_USE_HOBJECT_HASH_PART || DUK_USE_STRTAB_PROBE */ diff -Nru duktape-2.0.0/src-input/strings.yaml duktape-2.1.1/src-input/strings.yaml --- duktape-2.0.0/src-input/strings.yaml 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-input/strings.yaml 2017-07-28 22:05:08.000000000 +0000 @@ -766,8 +766,6 @@ duktape: true internal: true - # FIXME... - # internal properties for enumerator objects - str: "\u00ffTarget" duktape: true @@ -812,10 +810,10 @@ - str: "\u00ffMap" duktape: true internal: true - - str: "\u00ffCallee" + - str: "\u00ffVarenv" duktape: true internal: true - - str: "\u00ffVarenv" + - str: "\u00ffCallee" duktape: true internal: true @@ -835,25 +833,6 @@ duktape: true internal: true - # internal properties for declarative environment records - - str: "\u00ffCallee" # to access varmap - duktape: true - internal: true - - str: "\u00ffThread" # to identify valstack - duktape: true - internal: true - - str: "\u00ffRegbase" # to determine absolute valstack index - duktape: true - internal: true - - # internal properties for object environment records - - str: "\u00ffTarget" # target object - duktape: true - internal: true - - str: "\u00ffThis" # implicit this binding value - duktape: true - internal: true - # fake filename for compiled functions - str: "compile" # used as a filename for functions created with Function constructor duktape: true diff -Nru duktape-2.0.0/src-noline/duk_config.h duktape-2.1.1/src-noline/duk_config.h --- duktape-2.0.0/src-noline/duk_config.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-noline/duk_config.h 2017-07-28 22:05:08.000000000 +0000 @@ -1,9 +1,9 @@ /* * duk_config.h configuration header generated by genconfig.py. * - * Git commit: 4180966c47d6d87106008dd4338de8d507c8072b - * Git describe: v2.0.0 - * Git branch: master + * Git commit: 9c8fba6392d1913cb5359be7b8f386fa3cdd8b4d + * Git describe: v2.1.1 + * Git branch: v2.1-maintenance * * Supported platforms: * - Mac OSX, iPhone, Darwin @@ -12,6 +12,7 @@ * - Generic BSD * - Atari ST TOS * - AmigaOS + * - Durango (XboxOne) * - Windows * - Flashplayer (Crossbridge) * - QNX @@ -19,6 +20,8 @@ * - Emscripten * - Linux * - Solaris + * - AIX + * - HPUX * - Generic POSIX * - Cygwin * - Generic UNIX @@ -126,6 +129,11 @@ #endif #endif +/* Durango (Xbox One) */ +#if defined(_DURANGO) || defined(_XBOX_ONE) +#define DUK_F_DURANGO +#endif + /* Windows, both 32-bit and 64-bit */ #if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || \ defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__) @@ -170,6 +178,28 @@ /* illumos / Solaris */ #if defined(__sun) && defined(__SVR4) #define DUK_F_SUN +#if defined(__SUNPRO_C) && (__SUNPRO_C < 0x550) +#define DUK_F_OLD_SOLARIS +/* Defines _ILP32 / _LP64 required by DUK_F_X86/DUK_F_X64. Platforms + * are processed before architectures, so this happens before the + * DUK_F_X86/DUK_F_X64 detection is emitted. + */ +#include +#endif +#endif + +/* AIX */ +#if defined(_AIX) +/* defined(__xlc__) || defined(__IBMC__): works but too wide */ +#define DUK_F_AIX +#endif + +/* HPUX */ +#if defined(__hpux) +#define DUK_F_HPUX +#if defined(__ia64) +#define DUK_F_HPUX_ITANIUM +#endif #endif /* POSIX */ @@ -188,17 +218,6 @@ #define DUK_F_UNIX #endif -/* stdint.h not available */ -#if defined(DUK_F_WINDOWS) && defined(_MSC_VER) -#if (_MSC_VER < 1700) -/* VS2012+ has stdint.h, < VS2012 does not (but it's available for download). */ -#define DUK_F_NO_STDINT_H -#endif -#endif -#if !defined(DUK_F_NO_STDINT_H) && (defined(DUK_F_TOS) || defined(DUK_F_BCC)) -#define DUK_F_NO_STDINT_H -#endif - /* C++ */ #undef DUK_F_CPP #if defined(__cplusplus) @@ -208,6 +227,9 @@ /* Intel x86 (32-bit), x64 (64-bit) or x32 (64-bit but 32-bit pointers), * define only one of DUK_F_X86, DUK_F_X64, DUK_F_X32. * https://sites.google.com/site/x32abi/ + * + * With DUK_F_OLD_SOLARIS the header must be included + * before this. */ #if defined(__amd64__) || defined(__amd64) || \ defined(__x86_64__) || defined(__x86_64) || \ @@ -334,6 +356,15 @@ #define DUK_F_VBCC #endif +#if defined(ANDROID) || defined(__ANDROID__) +#define DUK_F_ANDROID +#endif + +/* Atari Mint */ +#if defined(__MINT__) +#define DUK_F_MINT +#endif + /* * Platform autodetection */ @@ -458,6 +489,40 @@ #if !defined(DUK_USE_BYTEORDER) && (defined(DUK_F_M68K) || defined(DUK_F_PPC)) #define DUK_USE_BYTEORDER 3 #endif +#elif defined(DUK_F_DURANGO) +/* --- Durango (XboxOne) --- */ +/* Durango = XboxOne + * Configuration is nearly identical to Windows, except for + * DUK_USE_DATE_TZO_WINDOWS. + */ + +/* Initial fix: disable secure CRT related warnings when compiling Duktape + * itself (must be defined before including Windows headers). Don't define + * for user code including duktape.h. + */ +#if defined(DUK_COMPILING_DUKTAPE) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +/* MSVC does not have sys/param.h */ +#define DUK_USE_DATE_NOW_WINDOWS +#define DUK_USE_DATE_TZO_WINDOWS_NO_DST +/* Note: PRS and FMT are intentionally left undefined for now. This means + * there is no platform specific date parsing/formatting but there is still + * the ISO 8601 standard format. + */ +#if defined(DUK_COMPILING_DUKTAPE) +/* Only include when compiling Duktape to avoid polluting application build + * with a lot of unnecessary defines. + */ +#include +#endif + +#define DUK_USE_OS_STRING "durango" + +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif #elif defined(DUK_F_WINDOWS) /* --- Windows --- */ /* Initial fix: disable secure CRT related warnings when compiling Duktape @@ -527,6 +592,10 @@ #define DUK_USE_OS_STRING "qnx" #elif defined(DUK_F_TINSPIRE) /* --- TI-Nspire --- */ +#if defined(DUK_COMPILING_DUKTAPE) && !defined(_XOPEN_SOURCE) +#define _XOPEN_SOURCE /* e.g. strptime */ +#endif + #define DUK_USE_DATE_NOW_GETTIMEOFDAY #define DUK_USE_DATE_TZO_GMTIME_R #define DUK_USE_DATE_PRS_STRPTIME @@ -607,12 +676,50 @@ #define DUK_USE_DATE_FMT_STRFTIME #include +#if defined(DUK_F_OLD_SOLARIS) +/* Old Solaris with no endian.h, stdint.h */ +#define DUK_F_NO_STDINT_H +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#else /* DUK_F_OLD_SOLARIS */ #include +#endif /* DUK_F_OLD_SOLARIS */ + #include #include #include #define DUK_USE_OS_STRING "solaris" +#elif defined(DUK_F_AIX) +/* --- AIX --- */ +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include + +#define DUK_USE_OS_STRING "aix" +#elif defined(DUK_F_HPUX) +/* --- HPUX --- */ +#define DUK_F_NO_STDINT_H +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include + +#define DUK_USE_OS_STRING "hpux" #elif defined(DUK_F_POSIX) /* --- Generic POSIX --- */ #define DUK_USE_DATE_NOW_GETTIMEOFDAY @@ -769,12 +876,8 @@ /* --- MIPS 32-bit --- */ #define DUK_USE_ARCH_STRING "mips32" /* MIPS byte order varies so rely on autodetection. */ -/* Based on 'make checkalign' there are no alignment requirements on - * Linux MIPS except for doubles, which need align by 4. Alignment - * requirements vary based on target though. - */ #if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 4 +#define DUK_USE_ALIGN_BY 8 #endif #define DUK_USE_PACKED_TVAL #define DUK_F_PACKED_TVAL_PROVIDED @@ -782,9 +885,6 @@ /* --- MIPS 64-bit --- */ #define DUK_USE_ARCH_STRING "mips64" /* MIPS byte order varies so rely on autodetection. */ -/* Good default is a bit arbitrary because alignment requirements - * depend on target. See https://github.com/svaarala/duktape/issues/102. - */ #if !defined(DUK_USE_ALIGN_BY) #define DUK_USE_ALIGN_BY 8 #endif @@ -908,6 +1008,9 @@ #define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) #endif +/* DUK_HOT */ +/* DUK_COLD */ + #if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) /* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're * compiling Duktape or the application. @@ -1018,6 +1121,12 @@ #define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) #endif +#if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && \ + defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40300) +#define DUK_HOT __attribute__((hot)) +#define DUK_COLD __attribute__((cold)) +#endif + #if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) /* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're * compiling Duktape or the application. @@ -1424,10 +1533,14 @@ #if defined(DUK_F_X86) || defined(DUK_F_X32) || \ defined(DUK_F_M68K) || defined(DUK_F_PPC32) || \ defined(DUK_F_BCC) || \ - (defined(__WORDSIZE) && (__WORDSIZE == 32)) + (defined(__WORDSIZE) && (__WORDSIZE == 32)) || \ + ((defined(DUK_F_OLD_SOLARIS) || defined(DUK_F_AIX) || \ + defined(DUK_F_HPUX)) && defined(_ILP32)) #define DUK_F_32BIT_PTRS #elif defined(DUK_F_X64) || \ - (defined(__WORDSIZE) && (__WORDSIZE == 64)) + (defined(__WORDSIZE) && (__WORDSIZE == 64)) || \ + ((defined(DUK_F_OLD_SOLARIS) || defined(DUK_F_AIX) || \ + defined(DUK_F_HPUX)) && defined(_LP64)) #define DUK_F_64BIT_PTRS #else /* not sure, not needed with C99 anyway */ @@ -2050,7 +2163,8 @@ #define DUK_DOUBLE_INFINITY (__builtin_inf()) #elif defined(INFINITY) #define DUK_DOUBLE_INFINITY ((double) INFINITY) -#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) +#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) && \ + !defined(DUK_F_OLD_SOLARIS) && !defined(DUK_F_AIX) #define DUK_DOUBLE_INFINITY (1.0 / 0.0) #else /* In VBCC (1.0 / 0.0) results in a warning and 0.0 instead of infinity. @@ -2066,7 +2180,8 @@ #undef DUK_USE_COMPUTED_NAN #if defined(NAN) #define DUK_DOUBLE_NAN NAN -#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) +#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) && \ + !defined(DUK_F_OLD_SOLARIS) && !defined(DUK_F_AIX) #define DUK_DOUBLE_NAN (0.0 / 0.0) #else /* In VBCC (0.0 / 0.0) results in a warning and 0.0 instead of NaN. @@ -2115,6 +2230,9 @@ * To be safe, use replacements. */ #define DUK_F_USE_REPL_ALL +#elif defined(DUK_F_AIX) +/* Older versions may be missing isnan(), etc. */ +#define DUK_F_USE_REPL_ALL #endif #if defined(DUK_F_USE_REPL_ALL) @@ -2203,9 +2321,10 @@ /* The functions below exist only in C99/C++11 or later and need a workaround * for platforms that don't include them. MSVC isn't detected as C99, but * these functions also exist in MSVC 2013 and later so include a clause for - * that too. + * that too. Android doesn't have log2; disable all of these for Android. */ -#if defined(DUK_F_C99) || defined(DUK_F_CPP11) || (defined(_MSC_VER) && (_MSC_VER >= 1800)) +#if (defined(DUK_F_C99) || defined(DUK_F_CPP11) || (defined(_MSC_VER) && (_MSC_VER >= 1800))) && \ + !defined(DUK_F_ANDROID) && !defined(DUK_F_MINT) #if !defined(DUK_CBRT) #define DUK_CBRT cbrt #endif @@ -2218,7 +2337,7 @@ #if !defined(DUK_TRUNC) #define DUK_TRUNC trunc #endif -#endif /* DUK_F_C99 */ +#endif /* DUK_F_C99 etc */ /* NetBSD 6.0 x86 (at least) has a few problems with pow() semantics, * see test-bug-netbsd-math-pow.js. MinGW has similar (but different) @@ -2431,7 +2550,8 @@ /* Macro for suppressing warnings for potentially unreferenced variables. * The variables can be actually unreferenced or unreferenced in some * specific cases only; for instance, if a variable is only debug printed, - * it is unreferenced when debug printing is disabled. + * it is unreferenced when debug printing is disabled. May cause warnings + * for volatile arguments. */ #define DUK_UNREF(x) do { (void) (x); } while (0) #endif @@ -2473,6 +2593,13 @@ #define DUK_ALWAYS_INLINE /*nop*/ #endif +#if !defined(DUK_HOT) +#define DUK_HOT /*nop*/ +#endif +#if !defined(DUK_COLD) +#define DUK_COLD /*nop*/ +#endif + #if !defined(DUK_EXTERNAL_DECL) #define DUK_EXTERNAL_DECL extern #endif @@ -2696,6 +2823,7 @@ #define DUK_USE_FAST_REFCOUNT_DEFAULT #undef DUK_USE_FATAL_HANDLER #define DUK_USE_FINALIZER_SUPPORT +#undef DUK_USE_FINALIZER_TORTURE #undef DUK_USE_FUNCPTR16 #undef DUK_USE_FUNCPTR_DEC16 #undef DUK_USE_FUNCPTR_ENC16 @@ -2704,16 +2832,26 @@ #define DUK_USE_FUNC_NAME_PROPERTY #undef DUK_USE_GC_TORTURE #undef DUK_USE_GET_RANDOM_DOUBLE +#undef DUK_USE_GLOBAL_BINDING #define DUK_USE_GLOBAL_BUILTIN #undef DUK_USE_HEAPPTR16 #undef DUK_USE_HEAPPTR_DEC16 #undef DUK_USE_HEAPPTR_ENC16 #define DUK_USE_HEX_FASTPATH +#define DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT 2 +#define DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT 9 +#define DUK_USE_HOBJECT_ARRAY_MINGROW_ADD 16 +#define DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR 8 +#define DUK_USE_HOBJECT_ENTRY_MINGROW_ADD 16 +#define DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR 8 #define DUK_USE_HOBJECT_HASH_PART +#define DUK_USE_HOBJECT_HASH_PROP_LIMIT 8 #define DUK_USE_HSTRING_ARRIDX #define DUK_USE_HSTRING_CLEN #undef DUK_USE_HSTRING_EXTDATA +#define DUK_USE_HTML_COMMENTS #define DUK_USE_IDCHAR_FASTPATH +#undef DUK_USE_INJECT_HEAP_ALLOC_ERROR #undef DUK_USE_INTERRUPT_COUNTER #undef DUK_USE_INTERRUPT_DEBUG_FIXUP #define DUK_USE_JC @@ -2729,10 +2867,8 @@ #define DUK_USE_JX #define DUK_USE_LEXER_SLIDING_WINDOW #undef DUK_USE_LIGHTFUNC_BUILTINS -#undef DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE #define DUK_USE_MARK_AND_SWEEP_RECLIMIT 256 #define DUK_USE_MATH_BUILTIN -#define DUK_USE_MS_STRINGTABLE_RESIZE #define DUK_USE_NATIVE_CALL_RECLIMIT 1000 #define DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER #define DUK_USE_NONSTD_ARRAY_MAP_TRAILER @@ -2752,9 +2888,9 @@ #undef DUK_USE_PREFER_SIZE #define DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS #undef DUK_USE_REFCOUNT16 +#define DUK_USE_REFCOUNT32 #define DUK_USE_REFERENCE_COUNTING #define DUK_USE_REFLECT_BUILTIN -#undef DUK_USE_REFZERO_FINALIZER_TORTURE #undef DUK_USE_REGEXP_CANON_WORKAROUND #define DUK_USE_REGEXP_COMPILER_RECLIMIT 10000 #define DUK_USE_REGEXP_EXECUTOR_RECLIMIT 10000 @@ -2766,6 +2902,7 @@ #undef DUK_USE_ROM_STRINGS #define DUK_USE_SECTION_B #undef DUK_USE_SELF_TESTS +#define DUK_USE_SHEBANG_COMMENTS #undef DUK_USE_SHUFFLE_TORTURE #define DUK_USE_SOURCE_NONBMP #undef DUK_USE_STRHASH16 @@ -2775,9 +2912,13 @@ #undef DUK_USE_STRICT_UTF8_SOURCE #define DUK_USE_STRING_BUILTIN #undef DUK_USE_STRLEN16 -#undef DUK_USE_STRTAB_CHAIN -#undef DUK_USE_STRTAB_CHAIN_SIZE -#define DUK_USE_STRTAB_PROBE +#define DUK_USE_STRTAB_GROW_LIMIT 17 +#define DUK_USE_STRTAB_MAXSIZE 268435456L +#define DUK_USE_STRTAB_MINSIZE 1024 +#undef DUK_USE_STRTAB_PTRCOMP +#define DUK_USE_STRTAB_RESIZE_CHECK_MASK 255 +#define DUK_USE_STRTAB_SHRINK_LIMIT 6 +#undef DUK_USE_STRTAB_TORTURE #undef DUK_USE_SYMBOL_BUILTIN #define DUK_USE_TAILCALL #define DUK_USE_TARGET_INFO "unknown" @@ -2822,10 +2963,12 @@ #if defined(DUK_USE_DATE_GET_LOCAL_TZOFFSET) /* External provider already defined. */ -#elif defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME) +#elif defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S) || defined(DUK_USE_DATE_TZO_GMTIME) #define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_gmtime((d)) #elif defined(DUK_USE_DATE_TZO_WINDOWS) #define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows((d)) +#elif defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST) +#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows_no_dst((d)) #else #error no provider for DUK_USE_DATE_GET_LOCAL_TZOFFSET() #endif @@ -3307,6 +3450,9 @@ #if defined(DUK_USE_INTEGER_ME) && defined(DUK_USE_INTEGER_BE) #error config option DUK_USE_INTEGER_ME conflicts with option DUK_USE_INTEGER_BE (which is also defined) #endif +#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE) +#error unsupported config option used (option has been removed): DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE +#endif #if defined(DUK_USE_MARK_AND_SWEEP) #error unsupported config option used (option has been removed): DUK_USE_MARK_AND_SWEEP #endif @@ -3319,6 +3465,9 @@ #if defined(DUK_USE_MATH_ROUND) #error unsupported config option used (option has been removed): DUK_USE_MATH_ROUND #endif +#if defined(DUK_USE_MS_STRINGTABLE_RESIZE) +#error unsupported config option used (option has been removed): DUK_USE_MS_STRINGTABLE_RESIZE +#endif #if defined(DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE) #error unsupported config option used (option has been removed): DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE #endif @@ -3349,6 +3498,9 @@ #if defined(DUK_USE_RDTSC) #error unsupported config option used (option has been removed): DUK_USE_RDTSC #endif +#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE) +#error unsupported config option used (option has been removed): DUK_USE_REFZERO_FINALIZER_TORTURE +#endif #if defined(DUK_USE_ROM_GLOBAL_CLONE) && !defined(DUK_USE_ROM_STRINGS) #error config option DUK_USE_ROM_GLOBAL_CLONE requires option DUK_USE_ROM_STRINGS (which is missing) #endif @@ -3379,9 +3531,21 @@ #if defined(DUK_USE_SIGSETJMP) #error unsupported config option used (option has been removed): DUK_USE_SIGSETJMP #endif +#if defined(DUK_USE_STRTAB_CHAIN) +#error unsupported config option used (option has been removed): DUK_USE_STRTAB_CHAIN +#endif +#if defined(DUK_USE_STRTAB_CHAIN_SIZE) +#error unsupported config option used (option has been removed): DUK_USE_STRTAB_CHAIN_SIZE +#endif #if defined(DUK_USE_STRTAB_CHAIN_SIZE) && !defined(DUK_USE_STRTAB_CHAIN) #error config option DUK_USE_STRTAB_CHAIN_SIZE requires option DUK_USE_STRTAB_CHAIN (which is missing) #endif +#if defined(DUK_USE_STRTAB_PROBE) +#error unsupported config option used (option has been removed): DUK_USE_STRTAB_PROBE +#endif +#if defined(DUK_USE_STRTAB_PTRCOMP) && !defined(DUK_USE_HEAPPTR16) +#error config option DUK_USE_STRTAB_PTRCOMP requires option DUK_USE_HEAPPTR16 (which is missing) +#endif #if defined(DUK_USE_TAILCALL) && defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) #error config option DUK_USE_TAILCALL conflicts with option DUK_USE_NONSTD_FUNC_CALLER_PROPERTY (which is also defined) #endif diff -Nru duktape-2.0.0/src-noline/duk_source_meta.json duktape-2.1.1/src-noline/duk_source_meta.json --- duktape-2.0.0/src-noline/duk_source_meta.json 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-noline/duk_source_meta.json 2017-07-28 22:05:08.000000000 +0000 @@ -1,652 +1,662 @@ { - "comment": "Metadata for Duktape build", - "duk_version_string": "2.0.0", + "comment": "Metadata for Duktape sources", + "duk_version_string": "2.1.1", "type": "duk_source_meta", "line_map": [ { "original_line": 1, - "combined_line": 128, + "combined_line": 130, "original_file": "duk_replacements.c" }, { "original_line": 1, - "combined_line": 137, + "combined_line": 139, "original_file": "duk_internal.h" }, { "original_line": 1, - "combined_line": 181, + "combined_line": 183, + "original_file": "duk_dblunion.h" + }, + { + "original_line": 1, + "combined_line": 607, "original_file": "duk_replacements.h" }, { "original_line": 1, - "combined_line": 211, + "combined_line": 637, "original_file": "duk_jmpbuf.h" }, { "original_line": 1, - "combined_line": 236, + "combined_line": 662, "original_file": "duk_exception.h" }, { "original_line": 1, - "combined_line": 255, + "combined_line": 681, "original_file": "duk_forwdecl.h" }, { "original_line": 1, - "combined_line": 380, + "combined_line": 810, "original_file": "duk_tval.h" }, { "original_line": 1, - "combined_line": 1013, + "combined_line": 1443, "original_file": "duk_builtins.h" }, { - "original_line": 50, - "combined_line": 1806, + "original_line": 51, + "combined_line": 2229, "original_file": "duk_internal.h" }, { "original_line": 1, - "combined_line": 1808, + "combined_line": 2231, "original_file": "duk_util.h" }, { "original_line": 1, - "combined_line": 2375, + "combined_line": 2791, "original_file": "duk_strings.h" }, { "original_line": 1, - "combined_line": 2535, + "combined_line": 2952, "original_file": "duk_js_bytecode.h" }, { "original_line": 1, - "combined_line": 3008, + "combined_line": 3424, "original_file": "duk_lexer.h" }, { "original_line": 1, - "combined_line": 3443, + "combined_line": 3861, "original_file": "duk_js_compiler.h" }, { "original_line": 1, - "combined_line": 3675, + "combined_line": 4089, "original_file": "duk_regexp.h" }, { "original_line": 1, - "combined_line": 3760, + "combined_line": 4174, "original_file": "duk_heaphdr.h" }, { "original_line": 1, - "combined_line": 4695, + "combined_line": 4480, + "original_file": "duk_refcount.h" + }, + { + "original_line": 1, + "combined_line": 5179, "original_file": "duk_api_internal.h" }, { "original_line": 1, - "combined_line": 5006, + "combined_line": 5492, "original_file": "duk_hstring.h" }, { "original_line": 1, - "combined_line": 5240, + "combined_line": 5719, "original_file": "duk_hobject.h" }, { "original_line": 1, - "combined_line": 6202, + "combined_line": 6674, "original_file": "duk_hcompfunc.h" }, { "original_line": 1, - "combined_line": 6466, + "combined_line": 6938, "original_file": "duk_hnatfunc.h" }, { "original_line": 1, - "combined_line": 6499, + "combined_line": 6971, "original_file": "duk_hbufobj.h" }, { "original_line": 1, - "combined_line": 6642, + "combined_line": 7114, "original_file": "duk_hthread.h" }, { "original_line": 1, - "combined_line": 7043, + "combined_line": 7521, "original_file": "duk_harray.h" }, { "original_line": 1, - "combined_line": 7091, + "combined_line": 7569, + "original_file": "duk_henv.h" + }, + { + "original_line": 1, + "combined_line": 7618, "original_file": "duk_hbuffer.h" }, { "original_line": 1, - "combined_line": 7420, + "combined_line": 7947, "original_file": "duk_heap.h" }, { "original_line": 1, - "combined_line": 8031, + "combined_line": 8554, "original_file": "duk_debugger.h" }, { "original_line": 1, - "combined_line": 8177, + "combined_line": 8706, "original_file": "duk_debug.h" }, { "original_line": 1, - "combined_line": 8362, + "combined_line": 8891, "original_file": "duk_error.h" }, { "original_line": 1, - "combined_line": 8845, + "combined_line": 9377, "original_file": "duk_unicode.h" }, { "original_line": 1, - "combined_line": 9124, + "combined_line": 9656, "original_file": "duk_json.h" }, { "original_line": 1, - "combined_line": 9193, + "combined_line": 9725, "original_file": "duk_js.h" }, { "original_line": 1, - "combined_line": 9297, + "combined_line": 9832, "original_file": "duk_numconv.h" }, { "original_line": 1, - "combined_line": 9398, + "combined_line": 9933, "original_file": "duk_bi_protos.h" }, { "original_line": 1, - "combined_line": 9467, + "combined_line": 10005, "original_file": "duk_selftest.h" }, { - "original_line": 77, - "combined_line": 9482, + "original_line": 80, + "combined_line": 10020, "original_file": "duk_internal.h" }, { "original_line": 10, - "combined_line": 9484, + "combined_line": 10022, "original_file": "duk_replacements.c" }, { "original_line": 1, - "combined_line": 9557, + "combined_line": 10095, "original_file": "duk_debug_macros.c" }, { "original_line": 1, - "combined_line": 9648, + "combined_line": 10186, "original_file": "duk_builtins.c" }, { "original_line": 1, - "combined_line": 10410, + "combined_line": 10965, "original_file": "duk_error_macros.c" }, { "original_line": 1, - "combined_line": 10546, + "combined_line": 11101, "original_file": "duk_unicode_support.c" }, { "original_line": 1, - "combined_line": 11729, + "combined_line": 12284, "original_file": "duk_util_misc.c" }, { "original_line": 1, - "combined_line": 12134, - "original_file": "duk_util_hashprime.c" - }, - { - "original_line": 1, - "combined_line": 12214, + "combined_line": 12689, "original_file": "duk_hobject_class.c" }, { "original_line": 1, - "combined_line": 12343, + "combined_line": 12818, "original_file": "duk_alloc_default.c" }, { "original_line": 1, - "combined_line": 12377, + "combined_line": 12852, "original_file": "duk_api_buffer.c" }, { "original_line": 1, - "combined_line": 12450, + "combined_line": 12925, "original_file": "duk_api_bytecode.c" }, { "original_line": 1, - "combined_line": 13222, + "combined_line": 13717, "original_file": "duk_api_call.c" }, { "original_line": 1, - "combined_line": 13832, + "combined_line": 14345, "original_file": "duk_api_codec.c" }, { "original_line": 1, - "combined_line": 14487, + "combined_line": 15003, "original_file": "duk_api_compile.c" }, { "original_line": 1, - "combined_line": 14672, + "combined_line": 15175, "original_file": "duk_api_debug.c" }, { "original_line": 1, - "combined_line": 14941, + "combined_line": 15448, "original_file": "duk_api_heap.c" }, { "original_line": 1, - "combined_line": 15130, + "combined_line": 15657, "original_file": "duk_api_inspect.c" }, { "original_line": 1, - "combined_line": 15376, + "combined_line": 15904, "original_file": "duk_api_memory.c" }, { "original_line": 1, - "combined_line": 15470, + "combined_line": 15998, "original_file": "duk_api_object.c" }, { "original_line": 1, - "combined_line": 16201, + "combined_line": 16751, "original_file": "duk_api_stack.c" }, { "original_line": 1, - "combined_line": 21580, + "combined_line": 22592, "original_file": "duk_api_string.c" }, { "original_line": 1, - "combined_line": 21916, + "combined_line": 22930, "original_file": "duk_api_time.c" }, { "original_line": 1, - "combined_line": 21986, + "combined_line": 23000, "original_file": "duk_bi_array.c" }, { "original_line": 1, - "combined_line": 23604, + "combined_line": 24618, "original_file": "duk_bi_boolean.c" }, { "original_line": 1, - "combined_line": 23676, + "combined_line": 24690, "original_file": "duk_bi_buffer.c" }, { "original_line": 1, - "combined_line": 26659, + "combined_line": 27683, "original_file": "duk_bi_date.c" }, { "original_line": 1, - "combined_line": 28421, + "combined_line": 29446, "original_file": "duk_bi_date_unix.c" }, { "original_line": 1, - "combined_line": 28734, + "combined_line": 29759, "original_file": "duk_bi_date_windows.c" }, { "original_line": 1, - "combined_line": 28832, + "combined_line": 29889, "original_file": "duk_bi_duktape.c" }, { "original_line": 1, - "combined_line": 28997, + "combined_line": 30054, "original_file": "duk_bi_encoding.c" }, { "original_line": 1, - "combined_line": 29530, + "combined_line": 30590, "original_file": "duk_bi_error.c" }, { "original_line": 1, - "combined_line": 29926, + "combined_line": 30987, "original_file": "duk_bi_function.c" }, { "original_line": 1, - "combined_line": 30347, + "combined_line": 31410, "original_file": "duk_bi_global.c" }, { "original_line": 1, - "combined_line": 31071, + "combined_line": 32139, "original_file": "duk_bi_json.c" }, { "original_line": 1, - "combined_line": 34284, + "combined_line": 35412, "original_file": "duk_bi_math.c" }, { "original_line": 1, - "combined_line": 34709, + "combined_line": 35837, "original_file": "duk_bi_number.c" }, { "original_line": 1, - "combined_line": 34952, + "combined_line": 36080, "original_file": "duk_bi_object.c" }, { "original_line": 1, - "combined_line": 35758, + "combined_line": 36888, "original_file": "duk_bi_pointer.c" }, { "original_line": 1, - "combined_line": 35832, + "combined_line": 36963, "original_file": "duk_bi_proxy.c" }, { "original_line": 1, - "combined_line": 35981, + "combined_line": 37113, "original_file": "duk_bi_reflect.c" }, { "original_line": 1, - "combined_line": 36086, + "combined_line": 37218, "original_file": "duk_bi_regexp.c" }, { "original_line": 1, - "combined_line": 36314, + "combined_line": 37446, "original_file": "duk_bi_string.c" }, { "original_line": 1, - "combined_line": 37765, + "combined_line": 39008, "original_file": "duk_bi_symbol.c" }, { "original_line": 1, - "combined_line": 37936, + "combined_line": 39181, "original_file": "duk_bi_thread.c" }, { "original_line": 1, - "combined_line": 38245, + "combined_line": 39492, "original_file": "duk_bi_thrower.c" }, { "original_line": 1, - "combined_line": 38254, + "combined_line": 39501, "original_file": "duk_debug_fixedbuffer.c" }, { "original_line": 1, - "combined_line": 38323, + "combined_line": 39570, "original_file": "duk_debug_vsnprintf.c" }, { "original_line": 1, - "combined_line": 39349, + "combined_line": 40609, "original_file": "duk_debugger.c" }, { "original_line": 1, - "combined_line": 42157, + "combined_line": 43462, "original_file": "duk_error_augment.c" }, { "original_line": 1, - "combined_line": 42746, + "combined_line": 44051, "original_file": "duk_error_longjmp.c" }, { "original_line": 1, - "combined_line": 42833, + "combined_line": 44157, "original_file": "duk_error_misc.c" }, { "original_line": 1, - "combined_line": 42958, + "combined_line": 44334, "original_file": "duk_error_throw.c" }, { "original_line": 1, - "combined_line": 43119, + "combined_line": 44509, "original_file": "duk_hbuffer_alloc.c" }, { "original_line": 1, - "combined_line": 43251, + "combined_line": 44641, "original_file": "duk_hbuffer_ops.c" }, { "original_line": 2, - "combined_line": 43334, + "combined_line": 44724, "original_file": "duk_hbufobj_misc.c" }, { "original_line": 1, - "combined_line": 43353, + "combined_line": 44743, "original_file": "duk_heap_alloc.c" }, { "original_line": 1, - "combined_line": 44412, + "combined_line": 45855, + "original_file": "duk_heap_finalize.c" + }, + { + "original_line": 1, + "combined_line": 46304, "original_file": "duk_heap_hashstring.c" }, { "original_line": 1, - "combined_line": 44533, + "combined_line": 46425, "original_file": "duk_heap_markandsweep.c" }, { "original_line": 1, - "combined_line": 45968, + "combined_line": 47661, "original_file": "duk_heap_memory.c" }, { "original_line": 1, - "combined_line": 46311, + "combined_line": 48022, "original_file": "duk_heap_misc.c" }, { "original_line": 1, - "combined_line": 46390, + "combined_line": 48203, "original_file": "duk_heap_refcount.c" }, { "original_line": 1, - "combined_line": 47151, + "combined_line": 49018, "original_file": "duk_heap_stringcache.c" }, { "original_line": 1, - "combined_line": 47449, + "combined_line": 49327, "original_file": "duk_heap_stringtable.c" }, { "original_line": 1, - "combined_line": 48609, + "combined_line": 50302, "original_file": "duk_hobject_alloc.c" }, { "original_line": 1, - "combined_line": 48826, + "combined_line": 50541, "original_file": "duk_hobject_enum.c" }, { "original_line": 1, - "combined_line": 49599, - "original_file": "duk_hobject_finalizer.c" - }, - { - "original_line": 1, - "combined_line": 49712, + "combined_line": 51317, "original_file": "duk_hobject_misc.c" }, { "original_line": 1, - "combined_line": 49764, + "combined_line": 51369, "original_file": "duk_hobject_pc2line.c" }, { "original_line": 1, - "combined_line": 50013, + "combined_line": 51618, "original_file": "duk_hobject_props.c" }, { "original_line": 1, - "combined_line": 56060, + "combined_line": 57709, "original_file": "duk_hstring_misc.c" }, { "original_line": 1, - "combined_line": 56123, + "combined_line": 57847, "original_file": "duk_hthread_alloc.c" }, { "original_line": 1, - "combined_line": 56218, + "combined_line": 57944, "original_file": "duk_hthread_builtins.c" }, { "original_line": 1, - "combined_line": 57042, + "combined_line": 58788, "original_file": "duk_hthread_misc.c" }, { "original_line": 1, - "combined_line": 57150, + "combined_line": 58889, "original_file": "duk_hthread_stacks.c" }, { "original_line": 1, - "combined_line": 57626, + "combined_line": 59470, "original_file": "duk_js_arith.c" }, { "original_line": 1, - "combined_line": 57763, + "combined_line": 59607, "original_file": "duk_js_call.c" }, { "original_line": 1, - "combined_line": 60491, + "combined_line": 62381, "original_file": "duk_js_compiler.c" }, { "original_line": 1, - "combined_line": 68427, + "combined_line": 70338, "original_file": "duk_js_executor.c" }, { "original_line": 1, - "combined_line": 73536, + "combined_line": 75520, "original_file": "duk_js_ops.c" }, { "original_line": 1, - "combined_line": 74916, + "combined_line": 76945, "original_file": "duk_js_var.c" }, { "original_line": 1, - "combined_line": 76741, + "combined_line": 78702, "original_file": "duk_lexer.c" }, { "original_line": 1, - "combined_line": 79108, + "combined_line": 81161, "original_file": "duk_numconv.c" }, { "original_line": 1, - "combined_line": 81385, + "combined_line": 83438, "original_file": "duk_regexp_compiler.c" }, { "original_line": 1, - "combined_line": 82528, + "combined_line": 84581, "original_file": "duk_regexp_executor.c" }, { "original_line": 1, - "combined_line": 83553, + "combined_line": 85607, "original_file": "duk_selftest.c" }, { "original_line": 2, - "combined_line": 84181, + "combined_line": 86235, "original_file": "duk_tval.c" }, { "original_line": 1, - "combined_line": 84322, + "combined_line": 86376, "original_file": "duk_unicode_tables.c" }, { "original_line": 1, - "combined_line": 90463, + "combined_line": 92517, "original_file": "duk_util_bitdecoder.c" }, { "original_line": 1, - "combined_line": 90625, + "combined_line": 92683, "original_file": "duk_util_bitencoder.c" }, { "original_line": 1, - "combined_line": 90668, + "combined_line": 92726, "original_file": "duk_util_bufwriter.c" }, { "original_line": 1, - "combined_line": 91028, + "combined_line": 93086, "original_file": "duk_util_hashbytes.c" }, { "original_line": 1, - "combined_line": 91089, + "combined_line": 93147, "original_file": "duk_util_tinyrandom.c" } ], - "duk_version": 20000, - "git_branch": "master", - "git_commit": "4180966c47d6d87106008dd4338de8d507c8072b", + "duk_version": 20101, + "git_branch": "v2.1-maintenance", + "git_commit": "9c8fba6392d1913cb5359be7b8f386fa3cdd8b4d", "builtin_strings_info": [ { "plain": "Undefined", @@ -1129,6 +1139,11 @@ "define": "DUK_STRIDX_INT_PC2LINE" }, { + "plain": "\u00ffThis", + "base64": "/1RoaXM=", + "define": "DUK_STRIDX_INT_THIS" + }, + { "plain": "\u00ffArgs", "base64": "/0FyZ3M=", "define": "DUK_STRIDX_INT_ARGS" @@ -1149,34 +1164,14 @@ "define": "DUK_STRIDX_INT_FINALIZER" }, { - "plain": "\u00ffHandler", - "base64": "/0hhbmRsZXI=", - "define": "DUK_STRIDX_INT_HANDLER" - }, - { - "plain": "\u00ffCallee", - "base64": "/0NhbGxlZQ==", - "define": "DUK_STRIDX_INT_CALLEE" - }, - { - "plain": "\u00ffThread", - "base64": "/1RocmVhZA==", - "define": "DUK_STRIDX_INT_THREAD" - }, - { - "plain": "\u00ffRegbase", - "base64": "/1JlZ2Jhc2U=", - "define": "DUK_STRIDX_INT_REGBASE" - }, - { "plain": "\u00ffTarget", "base64": "/1RhcmdldA==", "define": "DUK_STRIDX_INT_TARGET" }, { - "plain": "\u00ffThis", - "base64": "/1RoaXM=", - "define": "DUK_STRIDX_INT_THIS" + "plain": "\u00ffHandler", + "base64": "/0hhbmRsZXI=", + "define": "DUK_STRIDX_INT_HANDLER" }, { "plain": "compile", @@ -1581,16 +1576,13 @@ "/1Zhcm1hcA==", "/1NvdXJjZQ==", "/1BjMmxpbmU=", + "/1RoaXM=", "/0FyZ3M=", "/01hcA==", "/1ZhcmVudg==", "/0ZpbmFsaXplcg==", - "/0hhbmRsZXI=", - "/0NhbGxlZQ==", - "/1RocmVhZA==", - "/1JlZ2Jhc2U=", "/1RhcmdldA==", - "/1RoaXM=", + "/0hhbmRsZXI=", "Y29tcGlsZQ==", "aW5wdXQ=", "ZXJyQ3JlYXRl", @@ -1653,7 +1645,7 @@ "c3RhdGlj", "eWllbGQ=" ], - "git_describe": "v2.0.0", + "git_describe": "v2.1.1", "builtin_strings": [ "Undefined", "Null", @@ -1751,16 +1743,13 @@ "\u00ffVarmap", "\u00ffSource", "\u00ffPc2line", + "\u00ffThis", "\u00ffArgs", "\u00ffMap", "\u00ffVarenv", "\u00ffFinalizer", - "\u00ffHandler", - "\u00ffCallee", - "\u00ffThread", - "\u00ffRegbase", "\u00ffTarget", - "\u00ffThis", + "\u00ffHandler", "compile", "input", "errCreate", diff -Nru duktape-2.0.0/src-noline/duktape.c duktape-2.1.1/src-noline/duktape.c --- duktape-2.0.0/src-noline/duktape.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-noline/duktape.c 2017-07-28 22:05:08.000000000 +0000 @@ -1,8 +1,8 @@ /* - * Single source autogenerated distributable for Duktape 2.0.0. + * Single source autogenerated distributable for Duktape 2.1.1. * - * Git commit 4180966c47d6d87106008dd4338de8d507c8072b (v2.0.0). - * Git branch master. + * Git commit 9c8fba6392d1913cb5359be7b8f386fa3cdd8b4d (v2.1.1). + * Git branch v2.1-maintenance. * * See Duktape AUTHORS.rst and LICENSE.txt for copyright and * licensing information. @@ -82,6 +82,8 @@ * * Brett Vickers (https://github.com/beevik) * * Dominik Okwieka (https://github.com/okitec) * * Remko Tron\u00e7on (https://el-tramo.be) +* * Romero Malaquias (rbsm@ic.ufal.br) +* * Michael Drake * * Other contributions * =================== @@ -177,6 +179,430 @@ * dependencies. */ +/* #include duk_dblunion.h */ +/* + * 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/cross endian (e.g. ARM) DUK_USE_DOUBLE_ME + * + * ARM is a special case: ARM double values are in mixed/cross 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. + * + * 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] = 0x000000007ff80000ULL; \ + } while (0) +#define DUK__DBLUNION_IS_NAN_FULL(u) \ + ((((u)->ull[DUK_DBL_IDX_ULL0] & 0x000000007ff00000ULL) == 0x000000007ff00000ULL) && \ + ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0xffffffff000fffffULL) != 0)) +#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x000000007ff80000ULL) +#define DUK__DBLUNION_IS_ANYINF(u) \ + (((u)->ull[DUK_DBL_IDX_ULL0] & 0xffffffff7fffffffULL) == 0x000000007ff00000ULL) +#define DUK__DBLUNION_IS_POSINF(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x000000007ff00000ULL) +#define DUK__DBLUNION_IS_NEGINF(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x00000000fff00000ULL) +#define DUK__DBLUNION_IS_ANYZERO(u) \ + (((u)->ull[DUK_DBL_IDX_ULL0] & 0xffffffff7fffffffULL) == 0x0000000000000000ULL) +#define DUK__DBLUNION_IS_POSZERO(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000000000000ULL) +#define DUK__DBLUNION_IS_NEGZERO(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000080000000ULL) +#else +/* Macros for 64-bit ops + big/little endian doubles. */ +#define DUK__DBLUNION_SET_NAN_FULL(u) do { \ + (u)->ull[DUK_DBL_IDX_ULL0] = 0x7ff8000000000000ULL; \ + } while (0) +#define DUK__DBLUNION_IS_NAN_FULL(u) \ + ((((u)->ull[DUK_DBL_IDX_ULL0] & 0x7ff0000000000000ULL) == 0x7ff0000000000000UL) && \ + ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0x000fffffffffffffULL) != 0)) +#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x7ff8000000000000ULL) +#define DUK__DBLUNION_IS_ANYINF(u) \ + (((u)->ull[DUK_DBL_IDX_ULL0] & 0x7fffffffffffffffULL) == 0x7ff0000000000000ULL) +#define DUK__DBLUNION_IS_POSINF(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x7ff0000000000000ULL) +#define DUK__DBLUNION_IS_NEGINF(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0xfff0000000000000ULL) +#define DUK__DBLUNION_IS_ANYZERO(u) \ + (((u)->ull[DUK_DBL_IDX_ULL0] & 0x7fffffffffffffffULL) == 0x0000000000000000ULL) +#define DUK__DBLUNION_IS_POSZERO(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000000000000ULL) +#define DUK__DBLUNION_IS_NEGZERO(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x8000000000000000ULL) +#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] & 0x8000000000000000ULL) != 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 */ /* #include duk_replacements.h */ #if !defined(DUK_REPLACEMENTS_H_INCLUDED) #define DUK_REPLACEMENTS_H_INCLUDED @@ -280,6 +706,8 @@ struct duk_hnatfunc; struct duk_hthread; struct duk_hbufobj; +struct duk_hdecenv; +struct duk_hobjenv; struct duk_hbuffer; struct duk_hbuffer_fixed; struct duk_hbuffer_dynamic; @@ -334,8 +762,10 @@ typedef struct duk_hobject duk_hobject; typedef struct duk_hcompfunc duk_hcompfunc; typedef struct duk_hnatfunc duk_hnatfunc; -typedef struct duk_hbufobj duk_hbufobj; 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_hbuffer duk_hbuffer; typedef struct duk_hbuffer_fixed duk_hbuffer_fixed; typedef struct duk_hbuffer_dynamic duk_hbuffer_dynamic; @@ -1308,233 +1738,224 @@ #define DUK_STRIDX_INT_PC2LINE 95 /* '\xffPc2line' */ #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_ARGS 96 /* '\xffArgs' */ +#define DUK_STRIDX_INT_THIS 96 /* '\xffThis' */ +#define DUK_HEAP_STRING_INT_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THIS) +#define DUK_HTHREAD_STRING_INT_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THIS) +#define DUK_STRIDX_INT_ARGS 97 /* '\xffArgs' */ #define DUK_HEAP_STRING_INT_ARGS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_ARGS) #define DUK_HTHREAD_STRING_INT_ARGS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_ARGS) -#define DUK_STRIDX_INT_MAP 97 /* '\xffMap' */ +#define DUK_STRIDX_INT_MAP 98 /* '\xffMap' */ #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 98 /* '\xffVarenv' */ +#define DUK_STRIDX_INT_VARENV 99 /* '\xffVarenv' */ #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 99 /* '\xffFinalizer' */ +#define DUK_STRIDX_INT_FINALIZER 100 /* '\xffFinalizer' */ #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_HANDLER 100 /* '\xffHandler' */ -#define DUK_HEAP_STRING_INT_HANDLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_HANDLER) -#define DUK_HTHREAD_STRING_INT_HANDLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_HANDLER) -#define DUK_STRIDX_INT_CALLEE 101 /* '\xffCallee' */ -#define DUK_HEAP_STRING_INT_CALLEE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_CALLEE) -#define DUK_HTHREAD_STRING_INT_CALLEE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_CALLEE) -#define DUK_STRIDX_INT_THREAD 102 /* '\xffThread' */ -#define DUK_HEAP_STRING_INT_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THREAD) -#define DUK_HTHREAD_STRING_INT_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THREAD) -#define DUK_STRIDX_INT_REGBASE 103 /* '\xffRegbase' */ -#define DUK_HEAP_STRING_INT_REGBASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_REGBASE) -#define DUK_HTHREAD_STRING_INT_REGBASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_REGBASE) -#define DUK_STRIDX_INT_TARGET 104 /* '\xffTarget' */ +#define DUK_STRIDX_INT_TARGET 101 /* '\xffTarget' */ #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_THIS 105 /* '\xffThis' */ -#define DUK_HEAP_STRING_INT_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THIS) -#define DUK_HTHREAD_STRING_INT_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THIS) -#define DUK_STRIDX_COMPILE 106 /* 'compile' */ +#define DUK_STRIDX_INT_HANDLER 102 /* '\xffHandler' */ +#define DUK_HEAP_STRING_INT_HANDLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_HANDLER) +#define DUK_HTHREAD_STRING_INT_HANDLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_HANDLER) +#define DUK_STRIDX_COMPILE 103 /* '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 107 /* 'input' */ +#define DUK_STRIDX_INPUT 104 /* '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 108 /* 'errCreate' */ +#define DUK_STRIDX_ERR_CREATE 105 /* '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 109 /* 'errThrow' */ +#define DUK_STRIDX_ERR_THROW 106 /* '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 110 /* 'env' */ +#define DUK_STRIDX_ENV 107 /* '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 111 /* 'hex' */ +#define DUK_STRIDX_HEX 108 /* '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 112 /* 'base64' */ +#define DUK_STRIDX_BASE64 109 /* '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 113 /* 'jx' */ +#define DUK_STRIDX_JX 110 /* '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 114 /* 'jc' */ +#define DUK_STRIDX_JC 111 /* '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_RESUME 115 /* 'resume' */ +#define DUK_STRIDX_RESUME 112 /* 'resume' */ #define DUK_HEAP_STRING_RESUME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RESUME) #define DUK_HTHREAD_STRING_RESUME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RESUME) -#define DUK_STRIDX_JSON_EXT_UNDEFINED 116 /* '{"_undef":true}' */ +#define DUK_STRIDX_JSON_EXT_UNDEFINED 113 /* '{"_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_STRIDX_JSON_EXT_NAN 114 /* '{"_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_STRIDX_JSON_EXT_POSINF 115 /* '{"_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_STRIDX_JSON_EXT_NEGINF 116 /* '{"_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_STRIDX_JSON_EXT_FUNCTION1 117 /* '{"_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_STRIDX_JSON_EXT_FUNCTION2 118 /* '{_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_STRIDX_BREAK 119 /* '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_STRIDX_CASE 120 /* '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_STRIDX_CATCH 121 /* '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_STRIDX_CONTINUE 122 /* '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_STRIDX_DEBUGGER 123 /* '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_STRIDX_DEFAULT 124 /* '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_STRIDX_DELETE 125 /* '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_STRIDX_DO 126 /* '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_STRIDX_ELSE 127 /* '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_STRIDX_FINALLY 128 /* '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_STRIDX_FOR 129 /* '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_STRIDX_LC_FUNCTION 130 /* '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_STRIDX_IF 131 /* '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_STRIDX_IN 132 /* '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_STRIDX_INSTANCEOF 133 /* '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_STRIDX_NEW 134 /* '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_STRIDX_RETURN 135 /* '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_STRIDX_SWITCH 136 /* '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_STRIDX_THIS 137 /* '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_STRIDX_THROW 138 /* '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_STRIDX_TRY 139 /* '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_STRIDX_TYPEOF 140 /* '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_STRIDX_VAR 141 /* '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_STRIDX_CONST 142 /* '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_STRIDX_VOID 143 /* '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_STRIDX_WHILE 144 /* '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_STRIDX_WITH 145 /* '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_STRIDX_CLASS 146 /* '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_STRIDX_ENUM 147 /* '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_STRIDX_EXPORT 148 /* '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_STRIDX_EXTENDS 149 /* '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_STRIDX_IMPORT 150 /* '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_STRIDX_SUPER 151 /* '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_STRIDX_LC_NULL 152 /* '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_STRIDX_TRUE 153 /* '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_STRIDX_FALSE 154 /* '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_STRIDX_IMPLEMENTS 155 /* '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_STRIDX_INTERFACE 156 /* '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_STRIDX_LET 157 /* '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_STRIDX_PACKAGE 158 /* '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_STRIDX_PRIVATE 159 /* '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_STRIDX_PROTECTED 160 /* '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_STRIDX_PUBLIC 161 /* '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_STRIDX_STATIC 162 /* '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_STRIDX_YIELD 163 /* '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 */ +#define DUK_HEAP_NUM_STRINGS 164 +#define DUK_STRIDX_START_RESERVED 119 +#define DUK_STRIDX_START_STRICT_RESERVED 155 +#define DUK_STRIDX_END_RESERVED 164 /* 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[921]; +DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[903]; #endif /* !DUK_SINGLE_FILE */ #define DUK_STRDATA_MAX_STRLEN 17 -#define DUK_STRDATA_DATA_LENGTH 921 +#define DUK_STRDATA_DATA_LENGTH 903 #endif /* DUK_USE_ROM_STRINGS */ #if defined(DUK_USE_ROM_OBJECTS) @@ -1626,6 +2047,8 @@ 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_prototype_to_string(duk_context *ctx); @@ -1704,7 +2127,7 @@ 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); #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[164]; +DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[166]; #endif /* !DUK_SINGLE_FILE */ #define DUK_BIDX_GLOBAL 0 #define DUK_BIDX_GLOBAL_ENV 1 @@ -1785,19 +2208,19 @@ #define DUK_NUM_ALL_BUILTINS 74 #if defined(DUK_USE_DOUBLE_LE) #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3790]; +DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3819]; #endif /* !DUK_SINGLE_FILE */ -#define DUK_BUILTINS_DATA_LENGTH 3790 +#define DUK_BUILTINS_DATA_LENGTH 3819 #elif defined(DUK_USE_DOUBLE_BE) #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3790]; +DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3819]; #endif /* !DUK_SINGLE_FILE */ -#define DUK_BUILTINS_DATA_LENGTH 3790 +#define DUK_BUILTINS_DATA_LENGTH 3819 #elif defined(DUK_USE_DOUBLE_ME) #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3790]; +DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3819]; #endif /* !DUK_SINGLE_FILE */ -#define DUK_BUILTINS_DATA_LENGTH 3790 +#define DUK_BUILTINS_DATA_LENGTH 3819 #else #error invalid endianness defines #endif @@ -1812,10 +2235,6 @@ #if !defined(DUK_UTIL_H_INCLUDED) #define DUK_UTIL_H_INCLUDED -#define DUK_UTIL_MIN_HASH_PRIME 17 /* must match genhashsizes.py */ - -#define DUK_UTIL_GET_HASH_PROBE_STEP(hash) (duk_util_probe_steps[(hash) & 0x1f]) - #if defined(DUK_USE_GET_RANDOM_DOUBLE) #define DUK_UTIL_GET_RANDOM_DOUBLE(thr) DUK_USE_GET_RANDOM_DOUBLE((thr)->heap_udata) #else @@ -2301,7 +2720,7 @@ #endif /* !DUK_SINGLE_FILE */ /* Note: assumes that duk_util_probe_steps size is 32 */ -#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE) +#if defined(DUK_USE_HOBJECT_HASH_PART) #if !defined(DUK_SINGLE_FILE) DUK_INTERNAL_DECL duk_uint8_t duk_util_probe_steps[32]; #endif /* !DUK_SINGLE_FILE */ @@ -2311,13 +2730,10 @@ DUK_INTERNAL_DECL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed); #endif -#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE) -DUK_INTERNAL_DECL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size); -#endif - DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits); DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx); DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value); +DUK_INTERNAL_DECL duk_int32_t duk_bd_decode_flagged_signed(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value); DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx); DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_bitpacked_string(duk_bitdecoder_ctx *bd, duk_uint8_t *out); @@ -2510,6 +2926,7 @@ #define DUK_STR_INVALID_REGEXP_ESCAPE "invalid regexp escape" #define DUK_STR_INVALID_BACKREFS "invalid backreference(s)" #define DUK_STR_INVALID_REGEXP_CHARACTER "invalid regexp character" +#define DUK_STR_INVALID_REGEXP_GROUP "invalid regexp group" #define DUK_STR_UNTERMINATED_CHARCLASS "unterminated character class" #define DUK_STR_INVALID_RANGE "invalid range" @@ -2995,8 +3412,7 @@ #define DUK_BC_TRYCATCH_FLAG_WITH_BINDING (1 << 3) /* DUK_OP_DECLVAR flags in A; bottom bits are reserved for propdesc flags (DUK_PROPDESC_FLAG_XXX) */ -#define DUK_BC_DECLVAR_FLAG_UNDEF_VALUE (1 << 4) /* use 'undefined' for value automatically */ -#define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1 << 5) /* function declaration */ +#define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1 << 4) /* function declaration */ /* Misc constants and helper macros. */ #define DUK_BC_LDINT_BIAS (1L << 15) @@ -3039,7 +3455,7 @@ #define DUK_LEXER_GETPOINT(ctx,pt) duk_lexer_getpoint((ctx), (pt)) -/* currently 6 characters of lookup are actually needed (duk_lexer.c) */ +/* Currently 6 characters of lookup are actually needed (duk_lexer.c). */ #define DUK_LEXER_WINDOW_SIZE 6 #if defined(DUK_USE_LEXER_SLIDING_WINDOW) #define DUK_LEXER_BUFFER_SIZE 64 @@ -3417,6 +3833,8 @@ duk_int_t token_count; /* number of tokens parsed */ duk_int_t token_limit; /* maximum token count before error (sanity backstop) */ + + duk_small_uint_t flags; /* lexer flags, use compiler flag defines for now */ }; /* @@ -3664,10 +4082,6 @@ * Prototypes */ -#define DUK_JS_COMPILE_FLAG_EVAL (1 << 0) /* source is eval code (not global) */ -#define DUK_JS_COMPILE_FLAG_STRICT (1 << 1) /* strict outer context */ -#define DUK_JS_COMPILE_FLAG_FUNCEXPR (1 << 2) /* source is a function expression (used for Function constructor) */ - DUK_INTERNAL_DECL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer, duk_size_t src_length, duk_small_uint_t flags); #endif /* DUK_JS_COMPILER_H_INCLUDED */ @@ -3770,30 +4184,45 @@ * * 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 are held in the - * heap-wide string table so they don't need link 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). This - * means essentially that the refcount field must be as wide as data pointers. - * On 64-bit platforms this means that the refcount needs to be 64 bits even - * if an 'int' is 32 bits. This is a bit unfortunate, and compromising on - * this might be reasonable in the future. + * 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_refcount16; + duk_uint16_t h_refcount; +#elif defined(DUK_USE_REFCOUNT32) + duk_uint32_t h_refcount; #else duk_size_t h_refcount; #endif -#endif +#endif /* DUK_USE_REFERENCE_COUNTING */ #if defined(DUK_USE_HEAPPTR16) duk_uint16_t h_next16; @@ -3833,15 +4262,26 @@ 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_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 +#endif /* DUK_USE_REFERENCE_COUNTING */ + + duk_hstring *h_next; + /* No 'h_prev' pointer for strings. */ }; #define DUK_HEAPHDR_FLAGS_TYPE_MASK 0x00000003UL @@ -3897,21 +4337,13 @@ #endif #if defined(DUK_USE_REFERENCE_COUNTING) -#if defined(DUK_USE_REFCOUNT16) -#define DUK_HEAPHDR_GET_REFCOUNT(h) ((h)->h_refcount16) -#define DUK_HEAPHDR_SET_REFCOUNT(h,val) do { \ - (h)->h_refcount16 = (val); \ - } while (0) -#define DUK_HEAPHDR_PREINC_REFCOUNT(h) (++(h)->h_refcount16) /* result: updated refcount */ -#define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount16) /* result: updated refcount */ -#else #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 */ -#endif #else /* refcount macros not defined without refcounting, caller must #if defined() now */ #endif /* DUK_USE_REFERENCE_COUNTING */ @@ -3999,18 +4431,23 @@ } while (0) #endif -#define DUK_HEAPHDR_STRING_INIT_NULLS(h) /* currently nop */ +#define DUK_HEAPHDR_STRING_INIT_NULLS(h) do { \ + (h)->h_next = NULL; \ + } while (0) /* * Type tests */ -#define DUK_HEAPHDR_IS_OBJECT(h) \ - (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_OBJECT) -#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) +/* 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 @@ -4033,17 +4470,23 @@ #define DUK_ASSERT_HEAPHDR_LINKS(heap,h) do {} while (0) #endif +#define DUK_ASSERT_HEAPHDR_VALID(h) do { \ + DUK_ASSERT((h) != NULL); \ + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID((h))); \ + } while (0) + +#endif /* DUK_HEAPHDR_H_INCLUDED */ +/* #include duk_refcount.h */ /* * Reference counting helper macros. The macros take a thread argument * and must thus always be executed in a specific thread context. The - * thread argument is needed for features like finalization. Currently - * it is not required for INCREF, but it is included just in case. - * - * 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. + * thread argument is not really needed anymore: DECREF can operate with + * a heap pointer only, and INCREF needs neither. */ +#if !defined(DUK_REFCOUNT_H_INCLUDED) +#define DUK_REFCOUNT_H_INCLUDED + #if defined(DUK_USE_REFERENCE_COUNTING) #if defined(DUK_USE_ROM_OBJECTS) @@ -4073,6 +4516,7 @@ DUK_ASSERT(duk__h != NULL); \ DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \ + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) != 0); /* No wrapping. */ \ } \ } while (0) #define DUK_TVAL_DECREF_FAST(thr,tv) do { \ @@ -4107,6 +4551,7 @@ DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \ DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \ + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) != 0); /* No wrapping. */ \ } \ } while (0) #define DUK_HEAPHDR_DECREF_FAST_RAW(thr,h,rzcall,rzcast) do { \ @@ -4273,17 +4718,22 @@ } \ } while (0) -/* Free pending refzero entries; quick check to avoid call because often - * the queue is empty. +/* Called after one or more DECREF NORZ calls to handle pending side effects. + * At present DECREF NORZ does freeing inline but doesn't execute finalizers, + * so these macros check for pending finalizers and execute them. The FAST + * variant is performance critical. */ +#if defined(DUK_USE_FINALIZER_SUPPORT) #define DUK_REFZERO_CHECK_FAST(thr) do { \ - if ((thr)->heap->refzero_list != NULL) { \ - duk_refzero_free_pending((thr)); \ - } \ + duk_refzero_check_fast((thr)); \ } while (0) #define DUK_REFZERO_CHECK_SLOW(thr) do { \ - duk_refzero_free_pending((thr)); \ + duk_refzero_check_slow((thr)); \ } while (0) +#else /* DUK_USE_FINALIZER_SUPPORT */ +#define DUK_REFZERO_CHECK_FAST(thr) do { } while (0) +#define DUK_REFZERO_CHECK_SLOW(thr) do { } while (0) +#endif /* DUK_USE_FINALIZER_SUPPORT */ /* * Macros to set a duk_tval and update refcount of the target (decref the @@ -4690,7 +5140,41 @@ #endif /* DUK_USE_REFERENCE_COUNTING */ -#endif /* DUK_HEAPHDR_H_INCLUDED */ +#if defined(DUK_USE_REFERENCE_COUNTING) +#if defined(DUK_USE_FINALIZER_SUPPORT) +DUK_INTERNAL_DECL void duk_refzero_check_slow(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_refzero_check_fast(duk_hthread *thr); +#endif +DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize_norz(duk_heap *heap, duk_heaphdr *hdr); +DUK_INTERNAL_DECL void duk_hobject_refcount_finalize_norz(duk_heap *heap, duk_hobject *h); +#if 0 /* Not needed: fast path handles inline; slow path uses duk_heaphdr_decref() which is needed anyway. */ +DUK_INTERNAL_DECL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h); +DUK_INTERNAL_DECL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h); +DUK_INTERNAL_DECL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h); +DUK_INTERNAL_DECL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h); +DUK_INTERNAL_DECL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h); +DUK_INTERNAL_DECL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h); +#endif +DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h); +DUK_INTERNAL_DECL void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h); +#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) +DUK_INTERNAL_DECL void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h); /* no 'norz' variant */ +DUK_INTERNAL_DECL void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h); /* no 'norz' variant */ +DUK_INTERNAL_DECL void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h); +DUK_INTERNAL_DECL void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h); +#else +DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv); +DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv); +DUK_INTERNAL_DECL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv); +DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h); +DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h); +DUK_INTERNAL_DECL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h); +#endif +#else /* DUK_USE_REFERENCE_COUNTING */ +/* no refcounting */ +#endif /* DUK_USE_REFERENCE_COUNTING */ + +#endif /* DUK_REFCOUNT_H_INCLUDED */ /* #include duk_api_internal.h */ /* * Internal API calls which have (stack and other) semantics similar @@ -4795,7 +5279,7 @@ DUK_INTERNAL_DECL duk_hcompfunc *duk_get_hcompfunc(duk_context *ctx, duk_idx_t idx); DUK_INTERNAL_DECL duk_hnatfunc *duk_get_hnatfunc(duk_context *ctx, duk_idx_t idx); -DUK_INTERNAL_DECL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_bool_t throw_flag, duk_bool_t *out_found); +DUK_INTERNAL_DECL void *duk_get_buffer_data_raw(duk_context *ctx, 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_context *ctx, duk_idx_t idx, duk_small_uint_t classnum); @@ -4975,6 +5459,8 @@ DUK_INTERNAL_DECL duk_idx_t duk_get_top_require_min(duk_context *ctx, duk_idx_t min_top); DUK_INTERNAL_DECL duk_idx_t duk_get_top_index_unsafe(duk_context *ctx); +DUK_INTERNAL_DECL void duk_pop_n_unsafe(duk_context *ctx, duk_idx_t count); +DUK_INTERNAL_DECL void duk_pop_n_nodecref_unsafe(duk_context *ctx, duk_idx_t count); DUK_INTERNAL_DECL void duk_pop_unsafe(duk_context *ctx); DUK_INTERNAL_DECL void duk_compact_m1(duk_context *ctx); @@ -5084,7 +5570,7 @@ */ #define DUK_HSTRING_IS_ASCII(x) (DUK_HSTRING_GET_BYTELEN((x)) == DUK_HSTRING_GET_CHARLEN((x))) #endif -#define DUK_HSTRING_IS_ASCII(x) DUK_HSTRING_HAS_ASCII((x)) +#define DUK_HSTRING_IS_ASCII(x) DUK_HSTRING_HAS_ASCII((x)) /* lazily set! */ #define DUK_HSTRING_IS_EMPTY(x) (DUK_HSTRING_GET_BYTELEN((x)) == 0) #if defined(DUK_USE_STRHASH16) @@ -5105,7 +5591,7 @@ (x)->hdr.h_strextra16 = (v); \ } while (0) #if defined(DUK_USE_HSTRING_CLEN) -#define DUK_HSTRING_GET_CHARLEN(x) ((x)->clen16) +#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x)) #define DUK_HSTRING_SET_CHARLEN(x,v) do { \ (x)->clen16 = (v); \ } while (0) @@ -5120,7 +5606,7 @@ #define DUK_HSTRING_SET_BYTELEN(x,v) do { \ (x)->blen = (v); \ } while (0) -#define DUK_HSTRING_GET_CHARLEN(x) ((x)->clen) +#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x)) #define DUK_HSTRING_SET_CHARLEN(x,v) do { \ (x)->clen = (v); \ } while (0) @@ -5151,11 +5637,11 @@ * avoids helper call if string has no array index value. */ #define DUK_HSTRING_GET_ARRIDX_FAST(h) \ - (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_string_helper((h)) : DUK_HSTRING_NO_ARRAY_INDEX) + (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_hstring_fast_known((h)) : DUK_HSTRING_NO_ARRAY_INDEX) /* Slower but more compact variant. */ #define DUK_HSTRING_GET_ARRIDX_SLOW(h) \ - (duk_js_to_arrayindex_string_helper((h))) + (duk_js_to_arrayindex_hstring_fast((h))) #endif /* @@ -5170,30 +5656,26 @@ */ duk_heaphdr_string hdr; - /* Note: we could try to stuff a partial hash (e.g. 16 bits) into the - * shared heap header. Good hashing needs more hash bits though. - */ - - /* string hash */ + /* String hash. */ #if defined(DUK_USE_STRHASH16) /* If 16-bit hash is in use, stuff it into duk_heaphdr_string flags. */ #else duk_uint32_t hash; #endif - /* precomputed array index (or DUK_HSTRING_NO_ARRAY_INDEX) */ + /* Precomputed array index (or DUK_HSTRING_NO_ARRAY_INDEX). */ #if defined(DUK_USE_HSTRING_ARRIDX) duk_uarridx_t arridx; #endif - /* length in bytes (not counting NUL term) */ + /* Length in bytes (not counting NUL term). */ #if defined(DUK_USE_STRLEN16) /* placed in duk_heaphdr_string */ #else duk_uint32_t blen; #endif - /* length in codepoints (must be E5 compatible) */ + /* Length in codepoints (must be E5 compatible). */ #if defined(DUK_USE_STRLEN16) #if defined(DUK_USE_HSTRING_CLEN) duk_uint16_t clen16; @@ -5205,7 +5687,7 @@ #endif /* - * String value of 'blen+1' bytes follows (+1 for NUL termination + * String data of 'blen+1' bytes follows (+1 for NUL termination * convenience for C API). No alignment needs to be guaranteed * for strings, but fields above should guarantee alignment-by-4 * (but not alignment-by-8). @@ -5230,10 +5712,7 @@ */ DUK_INTERNAL_DECL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos, duk_bool_t surrogate_aware); - -#if !defined(DUK_USE_HSTRING_CLEN) DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h); -#endif #endif /* DUK_HSTRING_H_INCLUDED */ /* #include duk_hobject.h */ @@ -5271,8 +5750,8 @@ #if !defined(DUK_HOBJECT_H_INCLUDED) #define DUK_HOBJECT_H_INCLUDED -/* Object flag. There are currently 25 flag bits available. Make sure - * this stays in sync with debugger object inspection code. +/* 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 @@ -5284,14 +5763,14 @@ #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_THREAD DUK_HEAPHDR_USER_FLAG(7) /* object is a thread (duk_hthread) */ +#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_ENVRECCLOSED DUK_HEAPHDR_USER_FLAG(14) /* envrec: (declarative) record is closed */ +#define DUK_HOBJECT_FLAG_HAVE_FINALIZER DUK_HEAPHDR_USER_FLAG(14) /* object has a callable 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) */ @@ -5371,7 +5850,6 @@ #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_THREAD (1UL << DUK_HOBJECT_CLASS_THREAD) #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) @@ -5405,7 +5883,7 @@ #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) #define DUK_HOBJECT_IS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) -#define DUK_HOBJECT_IS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) +#define DUK_HOBJECT_IS_THREAD(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_THREAD) #define DUK_HOBJECT_IS_NONBOUND_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \ DUK_HOBJECT_FLAG_COMPFUNC | \ @@ -5443,14 +5921,14 @@ #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) #define DUK_HOBJECT_HAS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) -#define DUK_HOBJECT_HAS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) +#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_ENVRECCLOSED(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED) +#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) @@ -5463,14 +5941,14 @@ #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) #define DUK_HOBJECT_SET_BUFOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) -#define DUK_HOBJECT_SET_THREAD(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) +#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_ENVRECCLOSED(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED) +#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) @@ -5483,20 +5961,28 @@ #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) #define DUK_HOBJECT_CLEAR_BUFOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) -#define DUK_HOBJECT_CLEAR_THREAD(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) +#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_ENVRECCLOSED(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED) +#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) #define DUK_HOBJECT_CLEAR_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC) #define DUK_HOBJECT_CLEAR_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ) +/* Object can/cannot use FASTREFS, i.e. has no strong reference fields beyond + * duk_hobject base header. + */ +#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))) +#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. */ @@ -5878,6 +6364,16 @@ #define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr,h,p) duk_hobject_set_prototype_updref((thr), (h), (p)) /* + * 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 */ @@ -5890,22 +6386,9 @@ #if defined(DUK_USE_OBJSIZES16) #define DUK_HOBJECT_MAX_PROPERTIES 0x0000ffffUL #else -#define DUK_HOBJECT_MAX_PROPERTIES 0x7fffffffUL /* 2**31-1 ~= 2G properties */ +#define DUK_HOBJECT_MAX_PROPERTIES 0x3fffffffUL /* 2**30-1 ~= 1G properties */ #endif -/* higher value conserves memory; also note that linear scan is cache friendly */ -#define DUK_HOBJECT_E_USE_HASH_LIMIT 32 - -/* hash size relative to entries size: for value X, approx. hash_prime(e_size + e_size / X) */ -#define DUK_HOBJECT_H_SIZE_DIVISOR 4 /* hash size approx. 1.25 times entries size */ - -/* if new_size < L * old_size, resize without abandon check; L = 3-bit fixed point, e.g. 9 -> 9/8 = 112.5% */ -#define DUK_HOBJECT_A_FAST_RESIZE_LIMIT 9 /* 112.5%, i.e. new size less than 12.5% higher -> fast resize */ - -/* if density < L, abandon array part, L = 3-bit fixed point, e.g. 2 -> 2/8 = 25% */ -/* limit is quite low: one array entry is 8 bytes, one normal entry is 4+1+8+4 = 17 bytes (with hash entry) */ -#define DUK_HOBJECT_A_ABANDON_LIMIT 2 /* 25%, i.e. less than 25% used -> abandon */ - /* 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 @@ -5917,18 +6400,6 @@ #error invalid DUK_USE_ALIGN_BY #endif -/* controls for minimum entry part growth */ -#define DUK_HOBJECT_E_MIN_GROW_ADD 16 -#define DUK_HOBJECT_E_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */ - -/* controls for minimum array part growth */ -#define DUK_HOBJECT_A_MIN_GROW_ADD 16 -#define DUK_HOBJECT_A_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */ - -/* probe sequence */ -#define DUK_HOBJECT_HASH_INITIAL(hash,h_size) ((hash) % (h_size)) -#define DUK_HOBJECT_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash)) - /* * PC-to-line constants */ @@ -5958,7 +6429,7 @@ struct duk_propdesc { /* read-only values 'lifted' for ease of use */ - duk_small_int_t flags; + duk_small_uint_t flags; duk_hobject *get; duk_hobject *set; @@ -6082,17 +6553,18 @@ */ /* alloc and init */ -DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags); -#if 0 /* unused */ -DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags); -#endif -DUK_INTERNAL_DECL duk_harray *duk_harray_alloc(duk_heap *heap, duk_uint_t hobject_flags); -DUK_INTERNAL_DECL duk_hcompfunc *duk_hcompfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags); -DUK_INTERNAL_DECL duk_hnatfunc *duk_hnatfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags); +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); #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL_DECL duk_hbufobj *duk_hbufobj_alloc(duk_heap *heap, duk_uint_t hobject_flags); +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(duk_heap *heap, duk_uint_t hobject_flags); +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); /* resize */ DUK_INTERNAL_DECL void duk_hobject_realloc_props(duk_hthread *thr, @@ -6129,6 +6601,11 @@ 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 @@ -6175,11 +6652,6 @@ /* macros */ DUK_INTERNAL_DECL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p); -/* finalization */ -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_INTERNAL_DECL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj); -#endif - /* 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); @@ -6775,8 +7247,6 @@ #endif #endif /* DUK_USE_ROM_STRINGS */ -#define DUK_HTHREAD_GET_CURRENT_ACTIVATION(thr) (&(thr)->callstack[(thr)->callstack_top - 1]) - /* values for the state field */ #define DUK_HTHREAD_STATE_INACTIVE 1 /* thread not currently running */ #define DUK_HTHREAD_STATE_RUNNING 2 /* thread currently running (only one at a time) */ @@ -6958,8 +7428,9 @@ /* Call stack. [0,callstack_top[ is GC reachable. */ duk_activation *callstack; + duk_activation *callstack_curr; /* current activation (or NULL if none) */ duk_size_t callstack_size; /* allocation size */ - duk_size_t callstack_top; /* next to use, highest used is top - 1 */ + duk_size_t callstack_top; /* next to use, highest used is top - 1 (or none if top == 0) */ duk_size_t callstack_preventcount; /* number of activation records in callstack preventing a yield */ /* Catch stack. [0,catchstack_top[ is GC reachable. */ @@ -7021,12 +7492,19 @@ DUK_INTERNAL_DECL void duk_hthread_callstack_grow(duk_hthread *thr); DUK_INTERNAL_DECL void duk_hthread_callstack_shrink_check(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_hthread_callstack_unwind_norz(duk_hthread *thr, duk_size_t new_top); DUK_INTERNAL_DECL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top); DUK_INTERNAL_DECL void duk_hthread_catchstack_grow(duk_hthread *thr); DUK_INTERNAL_DECL void duk_hthread_catchstack_shrink_check(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_hthread_catchstack_unwind_norz(duk_hthread *thr, duk_size_t new_top); DUK_INTERNAL_DECL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top); -DUK_INTERNAL_DECL duk_activation *duk_hthread_get_current_activation(duk_hthread *thr); +#if defined(DUK_USE_FINALIZER_TORTURE) +DUK_INTERNAL_DECL void duk_hthread_valstack_torture_realloc(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_hthread_callstack_torture_realloc(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_hthread_catchstack_torture_realloc(duk_hthread *thr); +#endif + DUK_INTERNAL_DECL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */ DUK_INTERNAL_DECL void *duk_hthread_get_callstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */ DUK_INTERNAL_DECL void *duk_hthread_get_catchstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */ @@ -7087,6 +7565,55 @@ }; #endif /* DUK_HARRAY_H_INCLUDED */ +/* #include duk_henv.h */ +/* + * Environment object representation. + */ + +#if !defined(DUK_HENV_H_INCLUDED) +#define DUK_HENV_H_INCLUDED + +#define DUK_ASSERT_HDECENV_VALID(h) do { \ + DUK_ASSERT((h) != NULL); \ + DUK_ASSERT(DUK_HOBJECT_IS_DECENV((duk_hobject *) (h))); \ + DUK_ASSERT((h)->thread == NULL || (h)->varmap != NULL); \ + } while (0) + +#define DUK_ASSERT_HOBJENV_VALID(h) do { \ + 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); \ + } while (0) + +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; +}; + +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 */ /* #include duk_hbuffer.h */ /* * Heap buffer representation. @@ -7433,13 +7960,11 @@ * Heap flags */ -#define DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING (1 << 0) /* mark-and-sweep is currently running */ -#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1 << 1) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */ -#define DUK_HEAP_FLAG_REFZERO_FREE_RUNNING (1 << 2) /* refcount code is processing refzero list */ -#define DUK_HEAP_FLAG_ERRHANDLER_RUNNING (1 << 3) /* an error handler (user callback to augment/replace error) is running */ -#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1 << 4) /* executor interrupt running (used to avoid nested interrupts) */ -#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1 << 5) /* heap destruction ongoing, finalizer rescue no longer possible */ -#define DUK_HEAP_FLAG_DEBUGGER_PAUSED (1 << 6) /* debugger is paused: talk with debug client until step/resume */ +#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1 << 0) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */ +#define DUK_HEAP_FLAG_ERRHANDLER_RUNNING (1 << 1) /* an error handler (user callback to augment/replace error) is running */ +#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1 << 2) /* executor interrupt running (used to avoid nested interrupts) */ +#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1 << 3) /* heap destruction ongoing, finalizer rescue no longer possible */ +#define DUK_HEAP_FLAG_DEBUGGER_PAUSED (1 << 4) /* 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 { \ @@ -7449,25 +7974,19 @@ (heap)->flags &= ~(bits); \ } while (0) -#define DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) #define DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) -#define DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) #define DUK_HEAP_HAS_ERRHANDLER_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) #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_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) #define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) -#define DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) #define DUK_HEAP_SET_ERRHANDLER_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) #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_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) #define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) -#define DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) #define DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) #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) @@ -7494,11 +8013,25 @@ * field and the GC caller can impose further flags. */ -#define DUK_MS_FLAG_EMERGENCY (1 << 0) /* emergency mode: try extra hard */ -#define DUK_MS_FLAG_NO_STRINGTABLE_RESIZE (1 << 1) /* don't resize stringtable (but may sweep it); needed during stringtable resize */ -#define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1 << 2) /* don't compact objects; needed during object property allocation resize */ -#define DUK_MS_FLAG_NO_FINALIZERS (1 << 3) /* don't run finalizers; leave finalizable objects in finalize_list for next round */ -#define DUK_MS_FLAG_SKIP_FINALIZERS (1 << 4) /* don't run finalizers; queue finalizable objects back to heap_allocated */ +/* Emergency mark-and-sweep: try extra hard, even at the cost of + * performance. + */ +#define DUK_MS_FLAG_EMERGENCY (1 << 0) + +/* Voluntary mark-and-sweep: triggered periodically. */ +#define DUK_MS_FLAG_VOLUNTARY (1 << 1) + +/* 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 (1 << 2) + +/* 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 (1 << 2) /* * Thread switching @@ -7540,39 +8073,28 @@ #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 */ -/* helper to insert a (non-string) heap object into heap allocated list */ -#define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap,hdr) duk_heap_insert_into_heap_allocated((heap),(hdr)) - -/* - * Stringtable - */ - -/* initial stringtable size, must be prime and higher than DUK_UTIL_MIN_HASH_PRIME */ -#define DUK_STRTAB_INITIAL_SIZE 17 - -/* indicates a deleted string; any fixed non-NULL, non-hstring pointer works */ -#define DUK_STRTAB_DELETED_MARKER(heap) ((duk_hstring *) heap) - -/* resizing parameters */ -#define DUK_STRTAB_MIN_FREE_DIVISOR 4 /* load factor max 75% */ -#define DUK_STRTAB_MIN_USED_DIVISOR 4 /* load factor min 25% */ -#define DUK_STRTAB_GROW_ST_SIZE(n) ((n) + (n)) /* used entries + approx 100% -> reset load to 50% */ - -#define DUK_STRTAB_U32_MAX_STRLEN 10 /* 4'294'967'295 */ -#define DUK_STRTAB_HIGHEST_32BIT_PRIME 0xfffffffbUL - -/* probe sequence (open addressing) */ -#define DUK_STRTAB_HASH_INITIAL(hash,h_size) ((hash) % (h_size)) -#define DUK_STRTAB_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash)) - -/* fixed top level hashtable size (separate chaining) */ -#define DUK_STRTAB_CHAIN_SIZE DUK_USE_STRTAB_CHAIN_SIZE +/* 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 @@ -7643,10 +8165,17 @@ #define DUK_FREE(heap,ptr) duk_heap_mem_free((heap), (ptr)) /* + * Checked allocation, relative to a thread + */ + +#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)) + +/* * Memory constants */ -#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT 5 /* Retry allocation after mark-and-sweep for this +#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 @@ -7687,27 +8216,6 @@ duk_uint32_t line; }; -#if defined(DUK_USE_DEBUGGER_SUPPORT) -#define DUK_HEAP_IS_DEBUGGER_ATTACHED(heap) ((heap)->dbg_read_cb != NULL) -#define DUK_HEAP_CLEAR_STEP_STATE(heap) do { \ - (heap)->dbg_step_type = DUK_STEP_TYPE_NONE; \ - (heap)->dbg_step_thread = NULL; \ - (heap)->dbg_step_csindex = 0; \ - (heap)->dbg_step_startline = 0; \ - } while (0) -#define DUK_HEAP_SET_PAUSED(heap) do { \ - DUK_HEAP_SET_DEBUGGER_PAUSED(heap); \ - (heap)->dbg_state_dirty = 1; \ - DUK_HEAP_CLEAR_STEP_STATE((heap)); \ - } while (0) -#define DUK_HEAP_CLEAR_PAUSED(heap) do { \ - DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap); \ - (heap)->dbg_state_dirty = 1; \ - DUK_HEAP_CLEAR_STEP_STATE((heap)); \ - } while (0) -#define DUK_HEAP_IS_PAUSED(heap) (DUK_HEAP_HAS_DEBUGGER_PAUSED((heap))) -#endif /* DUK_USE_DEBUGGER_SUPPORT */ - /* * String cache should ideally be at duk_hthread level, but that would * cause string finalization to slow down relative to the number of @@ -7736,28 +8244,17 @@ duk_tval value2; /* 2nd related value (type specific) */ }; -/* - * Stringtable entry for fixed size stringtable - */ - -struct duk_strtab_entry { -#if defined(DUK_USE_HEAPPTR16) - /* A 16-bit listlen makes sense with 16-bit heap pointers: there - * won't be space for 64k strings anyway. - */ - duk_uint16_t listlen; /* if 0, 'str16' used, if > 0, 'strlist16' used */ - union { - duk_uint16_t strlist16; - duk_uint16_t str16; - } u; -#else - duk_size_t listlen; /* if 0, 'str' used, if > 0, 'strlist' used */ - union { - duk_hstring **strlist; - duk_hstring *str; - } u; -#endif -}; +#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) /* * Main heap structure @@ -7776,12 +8273,6 @@ */ void *heap_udata; - /* Precomputed pointers when using 16-bit heap pointer packing. */ -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t heapptr_null16; - duk_uint16_t heapptr_deleted16; -#endif - /* 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 @@ -7789,53 +8280,114 @@ */ duk_fatal_function fatal_func; - /* allocated heap objects */ + /* 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; - /* work list for objects whose refcounts are zero but which have not been - * "finalized"; avoids recursive C calls when refcounts go to zero in a - * chain of objects. + /* 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; - duk_heaphdr *refzero_list_tail; #endif - /* mark-and-sweep control */ +#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 + + /* 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 mark_and_sweep_trigger_counter; + duk_int_t ms_trigger_counter; #endif - duk_int_t mark_and_sweep_recursion_depth; - /* mark-and-sweep flags automatically active (used for critical sections) */ - duk_small_uint_t mark_and_sweep_base_flags; + /* 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; - /* work list for objects to be finalized (by mark-and-sweep) */ - duk_heaphdr *finalize_list; + /* Mark-and-sweep flags automatically active (used for critical sections). */ + duk_small_uint_t ms_base_flags; - /* longjmp state */ - duk_ljstate lj; + /* Mark-and-sweep running flag. Prevents re-entry, and also causes + * refzero events to be ignored (= objects won't be queued to refzero_list). + */ + 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; - /* marker for detecting internal "double faults", see duk_error_throw.c */ - duk_bool_t handling_error; +#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; + + /* Longjmp state. */ + duk_ljstate lj; - /* heap thread, used internally and for finalization */ + /* Heap thread, used internally and for finalization. */ duk_hthread *heap_thread; - /* current thread */ - duk_hthread *curr_thread; /* currently running thread */ + /* Current running thread. */ + duk_hthread *curr_thread; - /* heap level "stash" object (e.g., various reachability roots) */ + /* 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 */ + /* Mix-in value for computing string hashes; should be reasonably unpredictable. */ duk_uint32_t hash_seed; - /* rnd_state for duk_util_tinyrandom.c */ + /* 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 */ @@ -7844,7 +8396,7 @@ #endif #endif - /* counter for unique local symbol creation */ + /* 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. @@ -7860,10 +8412,9 @@ duk_int_t inst_count_interrupt; #endif - /* debugger */ - + /* Debugger state. */ #if defined(DUK_USE_DEBUGGER_SUPPORT) - /* callbacks and udata; dbg_read_cb != NULL is used to indicate attached state */ + /* 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; @@ -7873,7 +8424,7 @@ duk_debug_detached_function dbg_detached_cb; void *dbg_udata; - /* debugger state, only relevant when attached */ + /* 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) */ @@ -7897,30 +8448,25 @@ duk_uint8_t dbg_next_byte; #endif - /* string intern table (weak refs) */ -#if defined(DUK_USE_STRTAB_PROBE) -#if defined(DUK_USE_HEAPPTR16) + /* String intern table (weak refs). */ +#if defined(DUK_USE_STRTAB_PTRCOMP) duk_uint16_t *strtable16; #else duk_hstring **strtable; #endif - duk_uint32_t st_size; /* alloc size in elements */ - duk_uint32_t st_used; /* used elements (includes DELETED) */ -#endif - - /* XXX: static alloc is OK until separate chaining stringtable - * resizing is implemented. - */ -#if defined(DUK_USE_STRTAB_CHAIN) - duk_strtab_entry strtable[DUK_STRTAB_CHAIN_SIZE]; + 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 + /* String access cache (codepoint offset -> byte offset) for fast string * character looping; 'weak' reference which needs special handling in GC. */ duk_strcache strcache[DUK_HEAP_STRCACHE_SIZE]; - /* built-in strings */ + /* Built-in strings. */ #if defined(DUK_USE_ROM_STRINGS) /* No field needed when strings are in ROM. */ #else @@ -7949,32 +8495,32 @@ 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_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING) -DUK_INTERNAL_DECL void duk_heap_remove_any_from_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 -#if 0 /*unused*/ -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen); -#endif -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen); -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t len); -#if 0 /*unused*/ -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val); -#endif -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val); -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val); +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); +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_string_remove(duk_heap *heap, duk_hstring *h); +DUK_INTERNAL_DECL void duk_heap_strtable_unlink(duk_heap *heap, duk_hstring *h); #endif -#if defined(DUK_USE_MS_STRINGTABLE_RESIZE) -DUK_INTERNAL_DECL void duk_heap_force_strtab_resize(duk_heap *heap); -#endif -DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap); +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_dump_strtab(duk_heap *heap); +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); @@ -7988,41 +8534,18 @@ 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); -#if defined(DUK_USE_REFERENCE_COUNTING) -DUK_INTERNAL_DECL void duk_refzero_free_pending(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr); -#if 0 /* Not needed: fast path handles inline; slow path uses duk_heaphdr_decref() which is needed anyway. */ -DUK_INTERNAL_DECL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h); -DUK_INTERNAL_DECL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h); -DUK_INTERNAL_DECL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h); -DUK_INTERNAL_DECL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h); -DUK_INTERNAL_DECL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h); -DUK_INTERNAL_DECL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h); -#endif -DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h); -DUK_INTERNAL_DECL void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h); -#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) -DUK_INTERNAL_DECL void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h); /* no 'norz' variant */ -DUK_INTERNAL_DECL void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h); /* no 'norz' variant */ -DUK_INTERNAL_DECL void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h); -DUK_INTERNAL_DECL void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h); -#else -DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv); -DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv); -DUK_INTERNAL_DECL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv); -DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h); -DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h); -DUK_INTERNAL_DECL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h); -#endif -#else /* DUK_USE_REFERENCE_COUNTING */ -/* no refcounting */ -#endif /* DUK_USE_REFERENCE_COUNTING */ +#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 duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags); +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); @@ -8170,7 +8693,13 @@ 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); -#endif + +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_step_state(duk_heap *heap); +#endif /* DUK_USE_DEBUGGER_SUPPORT */ #endif /* DUK_DEBUGGER_H_INCLUDED */ /* #include duk_debug.h */ @@ -8836,7 +9365,10 @@ DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_fatal_handler(void *udata, const char *msg)); -DUK_INTERNAL_DECL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t lj_type); +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); @@ -9220,8 +9752,11 @@ DUK_INTERNAL_DECL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv); DUK_INTERNAL_DECL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv); DUK_INTERNAL_DECL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv); -DUK_INTERNAL_DECL duk_small_int_t duk_js_to_arrayindex_raw_string(const duk_uint8_t *str, duk_uint32_t blen, duk_uarridx_t *out_idx); -DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h); +DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string(const duk_uint8_t *str, duk_uint32_t blen); +#if !defined(DUK_USE_HSTRING_ARRIDX) +DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_hstring_fast_known(duk_hstring *h); +DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_hstring_fast(duk_hstring *h); +#endif DUK_INTERNAL_DECL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags); DUK_INTERNAL_DECL duk_small_int_t duk_js_data_compare(const duk_uint8_t *buf1, const duk_uint8_t *buf2, duk_size_t len1, duk_size_t len2); DUK_INTERNAL_DECL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2); @@ -9274,7 +9809,7 @@ DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name); DUK_INTERNAL_DECL duk_bool_t duk_js_declvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_small_int_t prop_flags, duk_bool_t is_func_decl); DUK_INTERNAL_DECL void duk_js_init_activation_environment_records_delayed(duk_hthread *thr, duk_activation *act); -DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env, duk_hobject *func, duk_size_t regbase); +DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env); DUK_INTERNAL_DECL duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_size_t idx_bottom); DUK_INTERNAL_DECL void duk_js_push_closure(duk_hthread *thr, @@ -9434,6 +9969,9 @@ #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_context *ctx, const char *str); #endif @@ -9651,10 +10189,16 @@ /* #include duk_internal.h -> already included */ +#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[921] = { +DUK_INTERNAL const duk_uint8_t duk_strings_data[903] = { 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, @@ -9682,31 +10226,31 @@ 171,115,147,136,4,65,130,96,35,64,194,32,168,89,56,208,48,135,123,144,217, 146,38,220,229,64,186,16,187,156,105,47,52,238,112,56,153,4,225,145,27,156, 43,162,192,46,71,220,229,65,22,1,231,220,228,157,72,136,136,220,227,197, -164,180,52,133,220,224,34,105,19,115,140,3,207,185,202,130,36,109,85,185, -194,161,160,90,50,72,163,115,135,3,70,178,68,251,156,16,22,178,16,251,156, -153,226,64,13,27,156,137,12,16,72,135,220,228,193,19,18,101,220,228,206, -137,28,78,99,208,178,21,13,125,38,146,70,60,20,72,9,145,4,140,121,51,197, -214,25,27,81,156,151,48,65,34,107,106,9,55,18,68,104,146,84,97,31,191,189, -181,70,140,133,222,249,212,227,66,125,245,187,251,219,77,3,119,190,117,56, -208,159,125,110,254,246,210,26,93,239,157,78,52,39,223,93,191,189,180,212, -52,187,223,58,156,104,79,190,187,127,123,104,180,104,183,190,117,56,208, -159,125,102,254,209,104,209,124,234,113,161,62,250,80,196,128,81,4,9,16, -162,4,196,116,9,205,154,27,66,32,100,13,12,98,68,227,33,65,69,204,195,34, -201,50,8,110,33,23,34,28,168,104,22,188,12,174,138,11,70,138,104,115,68, -130,137,13,82,27,41,129,162,35,138,54,146,198,137,39,72,180,210,178,38,35, -146,103,68,139,51,197,214,28,227,131,79,15,35,138,58,130,37,19,155,41,146, -174,64,203,99,161,100,37,145,51,148,75,4,164,66,54,140,49,46,247,70,103,37, -230,70,142,70,67,30,232,204,178,163,201,18,54,139,89,39,26,16,165,2,228,69, -33,143,89,24,70,206,73,67,102,72,148,2,32,214,73,157,224,18,128,98,29,241, -69,65,50,37,241,116,200,41,144,102,125,2,180,8,210,152,38,129,23,8,34,198, +164,180,52,133,220,228,206,137,23,115,128,137,164,77,206,48,15,62,231,42,8, +145,181,86,231,10,134,129,104,201,34,125,206,76,17,49,38,141,206,28,13,26, +201,19,137,204,122,22,66,161,175,164,210,72,199,130,137,1,50,32,145,143,38, +120,186,195,35,106,51,146,230,8,36,77,109,65,38,226,72,141,18,74,140,35, +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: 164 */ -DUK_INTERNAL const duk_c_function duk_bi_native_functions[164] = { +/* native functions: 166 */ +DUK_INTERNAL const duk_c_function duk_bi_native_functions[166] = { NULL, duk_bi_array_constructor, duk_bi_array_constructor_is_array, @@ -9841,6 +10385,7 @@ 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, @@ -9849,6 +10394,7 @@ 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, @@ -9873,540 +10419,549 @@ duk_bi_uint8array_plainof, }; #if defined(DUK_USE_DOUBLE_LE) -DUK_INTERNAL const duk_uint8_t duk_builtins_data[3790] = { +DUK_INTERNAL const duk_uint8_t duk_builtins_data[3819] = { 144,148,105,221,32,68,52,228,62,12,104,200,165,134,148,248,81,77,61,191, 135,35,154,103,34,72,6,157,159,197,145,77,245,126,52,130,106,234,163,196, 52,226,18,51,161,26,113,1,60,37,64,190,18,49,116,116,33,26,113,1,92,136,26, 98,112,145,139,163,165,8,211,136,14,228,72,82,68,141,17,56,72,197,209,212, 132,105,196,5,242,88,108,193,126,18,49,116,117,161,26,113,1,60,158,30,78, -18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,224,59, -147,60,93,110,79,15,39,9,24,186,33,13,63,79,185,39,26,121,223,110,77,66,53, -116,1,120,248,186,248,136,67,76,196,200,134,186,137,177,13,31,192,174,79, -15,32,248,8,196,24,8,107,254,39,97,161,175,248,159,16,215,252,80,186,26, -255,138,57,136,107,254,41,100,33,175,248,167,170,134,191,226,166,138,26, -255,138,187,40,107,254,43,111,33,171,86,181,16,209,241,11,228,201,121,240, -141,19,134,72,196,52,123,168,95,38,75,207,131,32,156,50,70,33,195,3,152, -128,0,0,0,0,0,1,240,255,153,128,0,0,0,0,0,1,224,255,151,137,0,214,9,188,35, -131,12,225,196,56,177,78,60,99,147,28,229,200,57,162,120,74,129,124,36,98, -232,156,241,92,136,26,98,112,145,139,162,116,71,114,36,41,34,70,136,156,36, -98,232,157,49,124,150,27,48,95,132,140,93,19,170,39,147,195,201,194,70,46, -137,215,17,218,69,4,236,98,232,157,153,39,110,81,220,15,193,209,83,3,200, -119,130,241,241,117,240,120,80,252,137,10,178,10,103,134,180,122,9,135,136, -154,120,169,199,142,158,121,10,7,146,162,121,74,71,150,166,121,138,135,154, -170,121,202,199,158,23,201,146,243,225,26,39,12,145,61,16,190,76,151,159,6, -65,56,100,137,233,35,93,205,144,33,224,140,137,196,54,121,244,5,60,17,145, -56,85,184,19,207,16,21,18,227,65,198,231,72,16,137,112,168,106,38,76,225,2, -70,65,56,100,237,34,140,177,4,134,65,56,100,237,34,129,117,204,123,154,70, -207,46,64,146,52,78,25,59,72,163,48,65,34,52,78,25,59,72,160,93,115,30,230, -145,179,204,144,24,146,16,30,76,209,2,40,210,72,64,121,52,4,0,156,88,97,5, -194,96,227,18,124,124,93,55,79,15,39,28,94,49,38,159,154,136,96,196,159,29, -102,241,241,115,201,25,227,131,36,133,20,62,110,142,253,2,102,36,248,235, -55,143,139,158,72,207,28,104,24,73,112,201,3,2,82,65,155,187,94,6,20,72,9, -147,120,128,225,144,168,105,56,248,185,228,140,241,190,96,128,200,84,52, -156,124,92,242,70,104,36,183,168,4,145,0,190,41,1,139,18,19,36,226,146,17, -124,73,82,54,124,37,230,70,201,14,108,184,132,8,68,185,34,1,100,31,8,129,8, -151,11,23,100,141,225,18,12,68,184,75,204,141,146,2,178,112,72,8,162,98,92, -50,10,152,147,227,172,222,62,46,121,35,60,114,88,96,92,185,112,201,65,34, -92,4,1,147,81,159,141,205,32,234,121,96,97,57,64,97,121,128,14,56,37,199, -89,188,124,92,242,70,120,227,144,53,18,227,226,233,186,120,121,56,226,242, -8,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,36,136,48,64,114,0, -250,156,168,1,64,247,175,25,36,2,8,11,94,80,248,16,40,104,242,103,200,48, -193,3,162,92,4,98,12,41,14,66,40,106,101,1,132,130,8,24,78,104,129,54,62, -96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,178, -58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,129, -232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,201, -126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,132, -0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,46, -36,29,4,78,69,6,60,226,31,192,7,255,252,24,160,163,11,23,51,130,56,35,193, -56,100,238,31,6,150,46,103,4,225,147,143,114,27,62,233,241,200,137,182,133, -42,142,167,216,6,23,216,0,97,28,17,224,39,223,32,80,142,8,240,78,25,56,9, -248,8,22,39,12,156,123,144,217,240,19,240,18,6,19,154,32,79,194,124,14,134, -140,151,227,139,226,52,11,88,37,62,33,163,37,248,226,248,141,32,213,184,64, -89,56,39,49,224,137,60,100,5,96,38,35,249,8,15,18,61,96,17,60,200,6,145,1, -17,31,206,64,89,45,2,39,161,0,178,122,209,63,74,2,101,64,202,113,67,77,235, -64,92,221,197,186,196,143,4,9,19,188,1,25,187,139,112,128,178,113,110,177, -35,193,2,68,239,0,46,110,229,30,242,71,130,4,137,222,4,35,55,113,110,16,22, -78,81,239,36,120,32,72,157,224,64,147,138,25,237,0,52,72,242,2,126,82,3,74, -129,148,227,234,66,12,112,28,140,155,104,203,169,158,9,133,158,4,25,36,1, -61,96,47,181,80,46,132,129,255,255,255,255,255,255,222,254,39,172,67,118, -170,5,208,144,0,64,0,0,0,0,0,0,51,16,0,0,0,0,0,0,62,31,200,245,238,146,38, -138,147,105,13,42,26,137,226,0,0,0,0,0,0,7,131,249,30,180,134,4,209,82,109, -33,165,67,81,60,64,0,0,0,0,0,0,240,255,28,144,155,104,0,0,0,0,0,0,0,0,16, -117,59,130,48,155,98,48,187,144,3,205,220,42,46,65,237,72,27,55,112,151, -123,154,70,205,0,94,208,129,115,119,31,18,9,18,67,155,183,34,12,176,96,175, -4,100,74,228,3,237,38,43,31,192,109,117,171,0,228,164,219,72,0,0,0,0,0,0, -248,127,196,234,111,0,50,110,224,193,50,114,83,138,26,107,192,131,38,238, -77,12,39,37,56,161,166,188,11,132,188,12,74,110,226,220,32,44,156,24,38,78, -74,113,67,77,120,28,148,221,197,184,64,89,57,52,48,156,148,226,134,154,240, -64,195,94,8,56,123,193,11,85,116,140,45,240,3,152,147,228,208,194,95,0,89, -137,62,22,139,95,48,64,70,200,67,28,98,79,180,152,139,218,45,124,193,1,27, -33,16,65,137,62,49,205,153,236,132,81,102,36,251,73,137,157,115,102,123,33, -24,57,137,62,12,19,37,144,142,40,196,159,105,49,15,160,153,44,132,128,198, -36,248,48,98,200,73,18,98,79,180,152,135,208,98,200,74,16,98,79,135,117,35, -43,33,44,89,137,62,210,98,63,93,72,202,200,76,20,98,79,140,67,105,50,74, -200,77,26,98,79,180,152,153,212,54,147,36,172,132,225,70,36,249,34,9,205, -28,172,132,241,166,36,251,73,138,93,32,156,209,202,200,80,30,98,79,140,66, -214,137,16,78,104,229,100,40,146,49,39,218,76,76,234,22,180,72,130,115,71, -43,33,72,137,137,62,77,12,38,92,210,113,197,44,137,59,64,7,145,39,201,161, -132,184,64,249,18,124,98,22,180,72,130,115,71,43,101,76,148,137,62,210,98, -103,80,181,162,68,19,154,57,91,42,130,164,73,242,68,19,154,57,91,95,84,108, -137,62,210,98,151,72,39,52,114,182,190,176,169,18,124,98,27,73,146,86,223, -215,27,34,79,180,152,153,212,54,147,36,173,191,176,34,68,159,14,234,70,86, -231,217,23,34,79,180,152,143,215,82,50,183,62,208,121,18,124,24,38,75,101, -108,84,137,62,210,98,31,65,50,91,43,130,36,73,241,142,108,207,109,125,209, -114,36,251,73,137,157,115,102,123,107,239,11,145,39,194,209,107,230,8,8, -219,127,124,116,137,62,210,98,47,104,181,243,4,4,109,191,192,135,49,39,204, -16,17,178,24,32,242,36,249,130,2,54,203,7,6,104,14,76,131,140,144,0,0,0,0, -0,0,0,1,141,207,215,12,78,126,193,46,190,126,192,98,179,246,4,197,231,236, -10,193,9,114,11,172,64,73,146,83,236,145,169,237,1,6,120,14,78,129,179,40, -249,18,149,175,207,141,199,27,76,248,156,81,177,207,139,198,9,169,199,129, -58,136,19,202,11,179,20,240,149,2,248,72,197,209,200,148,162,117,48,39,148, -151,102,42,228,64,211,19,132,140,93,28,137,74,39,85,2,121,81,118,98,238,68, -133,36,72,209,19,132,140,93,28,137,74,39,87,2,121,89,118,98,190,75,13,152, -47,194,70,46,142,68,165,19,172,129,60,176,187,49,79,39,135,147,132,140,93, -28,137,74,39,91,2,121,105,118,98,142,210,40,39,99,23,71,34,82,135,8,128, -120,72,13,42,226,145,97,87,224,168,1,58,182,232,232,64,22,85,181,187,177, -107,2,64,7,213,183,74,7,121,207,215,242,17,119,49,248,94,173,198,210,36,15, -232,34,182,84,113,95,115,240,221,91,141,163,160,72,1,220,164,194,175,121, -123,103,224,186,244,64,24,45,68,84,251,33,9,64,15,217,66,51,209,218,210, -129,154,118,254,205,61,65,204,126,23,178,132,103,165,3,52,237,253,154,122, -131,216,252,167,224,121,44,48,46,95,203,166,238,74,113,67,77,201,128,219, -152,164,82,6,0,203,76,64,64,9,210,211,18,4,4,144,221,49,40,64,76,13,211,19, -5,4,192,221,45,66,1,4,24,207,76,82,2,8,136,94,152,156,24,157,45,49,64,6,75, -191,76,80,66,149,110,116,116,197,8,41,240,247,79,70,188,6,183,27,76,80,194, -45,198,210,211,20,144,171,113,180,116,52,197,40,27,1,125,34,240,27,16,221, -42,240,27,221,109,66,32,104,129,163,115,52,224,5,139,168,209,233,138,32,57, -33,186,98,138,18,80,140,244,197,24,28,192,221,49,71,11,56,209,162,211,20, -183,1,66,188,17,145,52,40,9,148,226,134,153,5,198,137,136,32,14,12,30,164, -140,144,230,192,0,0,0,0,0,136,211,64,182,120,43,135,126,16,68,52,174,195, -144,12,2,158,4,128,70,22,24,128,101,67,112,163,192,100,104,176,131,192,99, -32,176,99,192,226,115,30,1,79,4,68,28,16,54,0,0,41,254,232,116,62,204,7,21, -35,18,54,127,80,28,192,132,28,32,14,96,197,212,243,193,48,188,240,39,130, -236,224,175,131,117,2,178,112,145,139,163,145,131,114,70,46,142,218,27,182, -72,197,209,219,56,26,53,161,166,32,128,56,18,2,129,239,94,50,76,130,68,230, -202,113,160,167,146,94,163,134,66,161,164,227,226,231,146,51,198,249,147, -71,209,67,73,210,94,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15, -155,163,191,68,28,98,79,143,139,166,233,225,228,227,139,198,37,210,244,208, -24,137,112,151,153,27,36,5,100,224,146,105,184,100,196,95,18,84,141,159,9, -121,145,178,67,155,46,33,38,187,168,252,211,243,81,92,2,14,40,16,50,37,202, -160,150,154,67,152,148,20,28,76,156,89,26,105,158,63,232,16,44,150,129,18, -146,44,28,96,14,98,216,80,113,50,113,100,105,166,120,255,160,20,28,76,156, -113,75,34,78,63,236,3,6,133,41,35,31,242,18,195,152,147,226,27,61,138,41, -140,16,98,79,148,67,103,177,69,45,136,49,39,196,54,122,58,212,83,26,36,196, -159,40,134,207,71,90,138,92,16,98,79,136,108,244,244,168,166,56,73,137,62, -81,13,158,158,149,20,186,40,196,159,10,183,2,122,122,84,82,240,163,18,124, -42,220,9,235,106,81,75,225,228,73,241,13,158,197,54,198,8,145,39,202,33, -179,216,166,214,196,72,147,226,27,61,29,106,109,141,19,34,79,148,67,103, -163,173,77,174,8,145,39,196,54,122,122,84,219,28,38,68,159,40,134,207,79, -74,155,93,21,34,79,133,91,129,61,61,42,109,120,84,137,62,21,110,4,245,181, -41,181,248,56,224,28,24,80,113,50,113,100,105,166,120,255,160,20,28,76,156, -113,75,34,78,63,236,3,6,133,41,35,31,242,11,174,254,160,34,84,8,35,16,98, -146,38,55,32,33,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,0,0,0,0,30, -7,230,56,199,161,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,0,0,0,0, -30,7,230,55,36,33,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,0,0,0,0, -30,7,234,40,11,91,133,199,172,8,111,248,128,239,88,16,222,56,191,242,49, -198,69,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,240,63, -49,185,65,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,240, -63,49,198,77,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0, -240,63,49,185,97,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0, -0,0,64,49,198,85,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0, -0,0,64,49,185,129,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0, -0,0,0,64,49,198,93,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0, -0,0,0,64,49,185,161,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0, -0,0,0,16,64,49,198,101,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0, -0,0,0,0,16,64,49,185,193,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0, -0,0,0,0,0,16,64,49,198,109,8,244,56,153,37,180,242,71,104,139,35,8,217,192, -0,0,0,0,0,0,16,64,49,185,225,8,244,56,153,37,180,242,71,104,139,35,8,217, -192,0,0,0,0,0,0,16,64,49,198,117,8,244,56,153,37,180,242,71,104,139,35,8, -217,192,0,0,0,0,0,0,16,64,49,186,1,8,244,56,153,37,180,242,71,104,139,35,8, -217,192,0,0,0,0,0,0,32,64,49,198,125,8,244,56,153,37,180,242,71,104,139,35, -8,217,192,0,0,0,0,0,0,32,64,32,232,130,0,97,57,162,4,245,72,10,68,184,70, -137,195,67,77,175,32,66,37,192,208,165,36,117,196,10,14,38,78,44,141,52, -207,169,64,56,156,199,130,36,160,141,146,52,38,32,76,72,1,246,136,235,103, -177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,171,37, -20,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,158,142, -183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,246,136, -235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,37,20, -138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,75,161, -37,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,39,208, -146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,129,89, -58,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,17,214, -207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,207, -161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,207, -98,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,78, -209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,146, -155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,104, -142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,146, -155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,217, -233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,162, -137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,77, -156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,117, -179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,162, -100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,59,22, -53,91,0,2,21,11,94,181,128,196,133,0,185,80,32,56,156,199,130,36,160,72,16, -78,126,53,144,5,146,208,34,82,72,1,109,20,76,155,40,32,233,0,115,70,130,8, -209,56,104,105,187,252,193,3,17,162,112,201,242,18,65,211,0,230,149,132,17, -162,112,208,211,119,248,0,82,130,96,95,127,128,130,80,102,186,36,232,92, -206,255,1,80,48,200,39,12,158,241,64, +18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,232,59, +147,60,93,110,79,15,39,9,24,186,33,13,63,111,185,16,211,206,251,114,98,17, +171,160,11,199,197,215,196,66,26,102,38,68,53,212,77,136,104,255,5,114,120, +121,7,192,70,32,192,67,95,249,59,13,13,127,228,248,134,191,242,133,208,215, +254,81,204,67,95,249,75,33,13,127,229,61,84,53,255,149,52,80,215,254,85, +217,67,95,249,91,121,13,90,181,168,134,143,152,95,38,75,207,132,104,156,50, +70,33,163,225,66,249,50,94,124,25,4,225,146,49,14,24,28,196,0,0,0,0,0,0,15, +135,252,204,0,0,0,0,0,0,15,7,252,188,72,6,176,77,225,28,24,103,14,33,197, +138,113,227,28,152,231,46,65,205,19,194,84,11,225,35,23,68,231,138,228,64, +211,19,132,140,93,19,162,59,145,33,73,18,52,68,225,35,23,68,233,139,228, +176,217,130,252,36,98,232,157,81,60,158,30,78,18,49,116,78,184,142,210,40, +39,99,23,68,236,201,59,114,142,224,126,14,138,152,30,67,188,23,143,139,175, +131,194,135,228,72,85,144,83,60,53,163,208,76,60,68,211,197,78,60,116,243, +200,80,60,149,19,202,82,60,181,51,204,84,60,213,83,206,86,60,240,190,76, +151,159,8,209,56,100,137,232,133,242,100,188,248,50,9,195,36,79,73,26,238, +108,129,15,4,100,78,33,179,207,160,41,224,140,137,194,173,192,158,120,128, +168,151,26,14,55,58,64,132,75,133,67,81,50,103,8,18,50,9,195,39,105,20,101, +136,36,50,9,195,39,105,20,11,174,99,220,210,54,121,114,4,145,162,112,201, +218,69,25,130,9,17,162,112,201,218,69,2,235,152,247,52,141,158,100,128,196, +144,128,242,102,136,17,70,146,66,3,201,160,32,0,130,225,48,113,137,62,62, +46,155,167,135,147,142,47,24,147,79,205,68,48,98,79,142,179,120,248,185, +228,140,241,193,146,66,138,31,55,71,126,129,51,18,124,117,155,199,197,207, +36,103,142,52,12,36,184,100,129,129,41,32,205,221,175,3,10,36,4,201,188,64, +112,200,84,52,156,124,92,242,70,120,223,48,64,100,42,26,78,62,46,121,35,52, +18,91,212,2,72,128,95,20,128,197,137,9,146,113,73,8,190,36,169,27,62,18, +243,35,100,135,54,92,66,4,34,92,145,0,178,15,132,64,132,75,133,139,178,70, +240,137,6,34,92,37,230,70,201,1,89,56,36,4,81,49,46,25,5,76,73,241,214,111, +31,23,60,145,158,57,44,48,46,92,184,100,160,145,46,2,0,201,168,207,198,230, +144,117,60,176,48,156,160,48,188,192,7,28,18,227,172,222,62,46,121,35,60, +113,200,26,137,113,241,116,221,60,60,156,113,121,4,20,124,92,242,70,120, +226,37,194,54,140,36,64,21,147,146,68,24,32,57,0,125,78,84,0,160,123,215, +140,146,1,4,5,175,40,124,8,20,52,121,51,228,24,96,129,209,46,2,49,6,20,135, +33,20,53,50,128,194,65,4,12,39,52,64,155,31,48,112,72,6,247,62,16,1,31,73, +30,25,240,60,73,82,70,68,138,0,89,29,5,156,96,2,201,104,17,35,160,18,78, +140,228,16,26,79,90,4,73,43,192,244,108,142,130,206,89,240,58,26,50,95,142, +43,159,65,107,4,167,196,52,100,191,28,87,63,128,15,255,240,164,169,35,136, +6,128,146,115,9,0,210,7,43,163,194,0,71,128,105,65,176,15,128,105,131,21, +11,153,35,0,211,134,137,7,65,18,33,244,23,18,14,130,39,34,131,30,113,15, +224,3,255,254,12,80,81,133,139,153,193,28,17,224,156,50,119,15,131,75,23, +51,130,112,201,199,185,13,159,116,248,228,68,219,66,149,83,83,238,3,11,238, +0,48,142,8,240,19,239,144,40,71,4,120,39,12,156,4,252,4,11,19,134,78,61, +200,108,248,9,248,9,3,9,205,16,39,225,62,7,67,70,75,241,197,241,154,5,172, +18,159,16,209,146,252,113,124,102,144,106,220,32,44,156,19,152,240,68,158, +66,2,176,19,17,252,164,7,137,30,176,8,158,116,3,72,128,136,143,232,32,44, +150,129,19,210,128,89,61,104,159,169,1,50,160,101,56,161,166,246,160,46, +110,226,221,98,71,130,4,137,222,0,140,221,197,184,64,89,56,183,88,145,224, +129,34,119,128,23,55,114,143,121,35,193,2,68,239,2,17,155,184,183,8,11,39, +40,247,146,60,16,36,78,240,32,73,197,12,247,128,26,36,121,1,63,49,2,165,48, +70,114,229,145,51,250,205,2,8,209,203,150,68,207,235,52,130,16,209,46,131, +36,188,70,128,210,160,101,56,251,16,131,28,7,35,38,218,50,234,103,130,97, +103,129,6,73,0,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,199,36,38, +218,0,0,0,0,0,0,0,0,4,29,78,224,140,38,216,140,46,228,0,243,119,10,139,144, +123,82,6,205,220,37,222,230,145,179,64,23,180,32,92,221,199,196,130,68,144, +230,237,200,131,44,24,43,193,25,18,185,0,251,73,138,199,240,27,93,106,192, +57,41,54,210,0,0,0,0,0,0,62,31,241,58,155,192,12,155,184,48,76,156,148,226, +134,154,240,32,201,187,147,67,9,201,78,40,105,175,2,225,47,3,18,155,184, +183,8,11,39,6,9,147,146,156,80,211,94,7,37,55,113,110,16,22,78,77,12,39,37, +56,161,166,188,16,48,215,130,14,30,240,66,213,93,35,11,124,0,230,36,249,52, +48,151,192,22,98,79,133,162,215,204,16,17,178,16,199,24,147,237,38,34,246, +139,95,48,64,70,200,68,16,98,79,140,115,102,123,33,20,89,137,62,210,98,103, +92,217,158,200,70,14,98,79,131,4,201,100,35,138,49,39,218,76,67,232,38,75, +33,32,49,137,62,12,24,178,18,68,152,147,237,38,33,244,24,178,18,132,24,147, +225,221,72,202,200,75,22,98,79,180,152,143,215,82,50,178,19,5,24,147,227, +16,218,76,146,178,19,70,152,147,237,38,38,117,13,164,201,43,33,56,81,137, +62,72,130,115,71,43,33,60,105,137,62,210,98,151,72,39,52,114,178,20,7,152, +147,227,16,181,162,68,19,154,57,89,10,36,140,73,246,147,19,58,133,173,18, +32,156,209,202,200,82,34,98,79,147,67,9,151,52,156,113,75,34,78,208,1,228, +73,242,104,97,46,16,62,68,159,24,133,173,18,32,156,209,202,217,83,37,34,79, +180,152,153,212,45,104,145,4,230,142,86,202,160,169,18,124,145,4,230,142, +86,215,213,27,34,79,180,152,165,210,9,205,28,173,175,172,42,68,159,24,134, +210,100,149,183,245,198,200,147,237,38,38,117,13,164,201,43,111,236,8,145, +39,195,186,145,149,185,246,69,200,147,237,38,35,245,212,140,173,207,180,30, +68,159,6,9,146,217,91,21,34,79,180,152,135,208,76,150,202,224,137,18,124, +99,155,51,219,95,116,92,137,62,210,98,103,92,217,158,218,251,194,228,73, +240,180,90,249,130,2,54,223,223,29,34,79,180,152,139,218,45,124,193,1,27, +111,240,33,204,73,243,4,4,108,134,8,60,137,62,96,128,141,178,193,193,154,3, +147,32,227,36,0,0,0,0,0,0,0,0,99,115,245,195,19,159,176,75,175,159,176,24, +172,253,129,49,121,251,2,176,66,92,130,235,16,18,100,148,251,36,106,123,64, +65,158,3,147,160,108,202,62,68,165,107,243,227,113,198,211,62,39,20,108, +115,226,241,130,106,113,224,78,162,4,242,130,236,197,60,37,64,190,18,49, +116,114,37,40,157,76,9,229,37,217,138,185,16,52,196,225,35,23,71,34,82,137, +213,64,158,84,93,152,187,145,33,73,18,52,68,225,35,23,71,34,82,137,213,192, +158,86,93,152,175,146,195,102,11,240,145,139,163,145,41,68,235,32,79,44,46, +204,83,201,225,228,225,35,23,71,34,82,137,214,192,158,90,93,152,163,180, +138,9,216,197,209,200,148,161,194,32,30,18,3,74,184,164,88,85,248,42,0,78, +173,186,58,16,5,149,109,110,236,90,192,144,1,245,109,210,129,222,115,245, +252,132,93,204,126,23,171,113,180,137,3,250,8,173,149,28,87,220,252,55,86, +227,104,232,18,0,119,41,48,171,222,94,217,248,46,189,16,6,11,81,21,62,200, +66,80,3,246,80,140,244,118,180,160,102,157,191,179,79,80,115,31,133,236, +161,25,233,64,205,59,127,102,158,160,246,63,41,248,30,75,12,11,151,242,233, +187,146,156,80,211,114,96,54,230,41,20,129,128,50,211,16,16,2,116,180,196, +129,1,36,55,76,74,16,19,3,116,196,193,65,48,55,75,80,128,65,6,51,211,20, +128,130,34,23,166,39,6,39,75,76,80,1,146,239,211,20,16,165,91,157,29,49,66, +10,124,61,211,209,175,1,173,198,211,20,48,139,113,180,180,197,36,42,220, +109,29,13,49,74,6,192,95,72,188,6,196,55,74,188,6,247,91,80,136,26,32,104, +220,205,56,1,98,234,52,122,98,136,14,72,110,152,162,132,148,35,61,49,70,7, +48,55,76,81,194,206,52,104,180,197,45,192,80,175,4,100,77,10,2,101,56,161, +166,65,113,162,98,8,3,131,7,169,35,36,57,176,0,0,0,0,16,40,116,208,45,158, +10,225,223,132,17,13,43,176,228,3,0,167,129,32,17,133,134,32,25,80,220,40, +240,25,26,44,32,240,24,200,44,24,240,56,156,199,128,83,193,17,7,4,13,128,0, +10,79,202,28,223,195,1,197,72,196,141,159,220,7,48,33,7,8,3,152,49,117,60, +240,76,47,60,9,224,187,56,43,224,221,64,172,156,36,98,232,228,96,220,145, +139,163,182,134,237,146,49,116,118,206,6,141,104,105,136,32,14,4,128,160, +123,215,140,147,32,145,57,178,156,104,41,228,151,168,225,144,168,105,56, +248,185,228,140,241,190,100,209,244,80,210,116,151,134,12,73,241,214,111, +31,23,60,145,158,56,50,72,81,67,230,232,239,209,7,24,147,227,226,233,186, +120,121,56,226,241,137,116,189,52,6,34,92,37,230,70,201,1,89,56,36,154,110, +25,49,23,196,149,35,103,194,94,100,108,144,230,203,136,73,174,234,63,52, +252,212,87,0,131,138,4,12,137,114,168,37,166,144,230,37,5,7,19,39,22,70, +154,103,143,252,4,11,37,160,68,164,139,7,24,3,152,182,20,28,76,156,89,26, +105,158,63,240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253,132, +176,230,36,248,134,207,98,138,99,4,24,147,229,16,217,236,81,75,98,12,73, +241,13,158,142,181,20,198,137,49,39,202,33,179,209,214,162,151,4,24,147, +226,27,61,61,42,41,142,18,98,79,148,67,103,167,165,69,46,138,49,39,194,173, +192,158,158,149,20,188,40,196,159,10,183,2,122,218,148,82,248,121,18,124, +67,103,177,77,177,130,36,73,242,136,108,246,41,181,177,18,36,248,134,207, +71,90,155,99,68,200,147,229,16,217,232,235,83,107,130,36,73,241,13,158,158, +149,54,199,9,145,39,202,33,179,211,210,166,215,69,72,147,225,86,224,79,79, +74,155,94,21,34,79,133,91,129,61,109,74,109,126,14,56,7,6,20,28,76,156,89, +26,105,158,63,240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253, +130,235,191,232,8,149,2,8,196,24,164,137,141,200,8,71,161,196,201,45,167, +146,59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,142,49,232,71,161,196,201,45, +167,146,59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,141,201,8,71,161,196,201, +45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,7,129,250,138,2,214,225,113,235, +2,27,128,0,10,66,3,189,96,67,120,226,224,0,2,148,140,113,145,66,61,14,38, +73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,60,15,204,110,80,66,61,14, +38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,60,15,204,113,147,66,61, +14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,60,15,204,110,88,66, +61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,0,16,12,113,149, +66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,0,16,12,110,96, +66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,0,16,12,113, +151,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,0,16,12, +110,104,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,4,16, +12,113,153,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,4, +16,12,110,112,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0, +4,16,12,113,155,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0, +0,4,16,12,110,120,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0, +0,0,4,16,12,113,157,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0, +0,0,0,4,16,12,110,128,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0, +0,0,0,0,8,16,12,113,159,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0, +0,0,0,0,0,8,16,8,58,32,128,24,78,104,129,61,82,2,145,46,17,162,112,208,211, +107,200,16,137,112,52,41,73,29,113,2,131,137,147,139,35,77,51,234,80,14,39, +49,224,137,40,35,100,141,9,136,19,18,0,125,162,58,217,236,81,64,68,72,1, +241,13,158,197,20,150,50,36,0,251,68,117,179,209,214,234,201,69,16,100,72, +1,246,136,235,103,163,173,208,146,138,68,23,18,0,124,67,103,163,173,213, +146,138,76,23,18,0,124,67,103,163,173,208,146,138,84,25,18,0,125,162,58, +217,233,233,117,100,162,138,50,36,0,251,68,117,179,211,210,232,73,69,34, +139,137,0,62,33,179,211,210,234,201,69,38,139,137,0,62,33,179,211,210,232, +73,69,42,139,137,0,62,21,110,4,250,178,81,70,23,18,0,124,42,220,9,244,36, +162,145,134,68,128,31,6,234,5,100,234,201,69,28,100,72,1,240,110,160,86,78, +132,148,82,56,168,144,3,237,17,214,207,171,37,22,128,42,36,0,251,68,117, +179,232,73,69,164,9,137,0,62,33,179,234,201,69,168,9,137,0,62,33,179,232, +73,69,172,10,180,81,50,118,136,235,103,177,77,129,54,138,38,78,33,179,216, +166,210,198,218,40,153,59,68,117,179,209,214,234,201,77,144,109,162,137, +147,180,71,91,61,29,110,132,148,218,32,203,69,19,39,16,217,232,235,117,100, +166,211,6,90,40,153,56,134,207,71,91,161,37,54,168,54,209,68,201,218,35, +173,158,158,151,86,74,108,163,109,20,76,157,162,58,217,233,233,116,36,166, +209,70,90,40,153,56,134,207,79,75,171,37,54,154,50,209,68,201,196,54,122, +122,93,9,41,181,81,150,138,38,78,21,110,4,250,178,83,102,25,104,162,100, +225,86,224,79,161,37,54,140,54,209,68,201,193,186,129,89,58,178,83,103,27, +104,162,100,224,221,64,172,157,9,41,180,113,118,138,38,78,209,29,108,250, +178,83,136,2,237,20,76,157,162,58,217,244,36,167,18,5,90,40,153,56,134,207, +171,37,56,160,42,209,68,201,196,54,125,9,41,197,141,78,197,141,86,192,0, +133,66,215,173,96,49,33,64,46,84,8,14,39,49,224,137,40,18,4,19,159,141,100, +1,100,180,8,148,146,0,91,69,19,38,202,8,58,64,28,209,160,130,52,78,26,26, +110,255,80,64,196,104,156,50,125,4,144,116,192,57,165,97,4,104,156,52,52, +221,254,64,20,160,152,23,223,228,32,148,25,174,137,58,23,51,191,200,84,12, +50,9,195,39,196,80, }; #elif defined(DUK_USE_DOUBLE_BE) -DUK_INTERNAL const duk_uint8_t duk_builtins_data[3790] = { +DUK_INTERNAL const duk_uint8_t duk_builtins_data[3819] = { 144,148,105,221,32,68,52,228,62,12,104,200,165,134,148,248,81,77,61,191, 135,35,154,103,34,72,6,157,159,197,145,77,245,126,52,130,106,234,163,196, 52,226,18,51,161,26,113,1,60,37,64,190,18,49,116,116,33,26,113,1,92,136,26, 98,112,145,139,163,165,8,211,136,14,228,72,82,68,141,17,56,72,197,209,212, 132,105,196,5,242,88,108,193,126,18,49,116,117,161,26,113,1,60,158,30,78, -18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,224,59, -147,60,93,110,79,15,39,9,24,186,33,13,63,79,185,39,26,121,223,110,77,66,53, -116,1,120,248,186,248,136,67,76,196,200,134,186,137,177,13,31,192,174,79, -15,32,248,8,196,24,8,107,254,39,97,161,175,248,159,16,215,252,80,186,26, -255,138,57,136,107,254,41,100,33,175,248,167,170,134,191,226,166,138,26, -255,138,187,40,107,254,43,111,33,171,86,181,16,209,241,11,228,201,121,240, -141,19,134,72,196,52,123,168,95,38,75,207,131,32,156,50,70,33,195,3,152, -128,255,240,0,0,0,0,0,1,153,128,255,224,0,0,0,0,0,1,151,137,0,214,9,188,35, -131,12,225,196,56,177,78,60,99,147,28,229,200,57,162,120,74,129,124,36,98, -232,156,241,92,136,26,98,112,145,139,162,116,71,114,36,41,34,70,136,156,36, -98,232,157,49,124,150,27,48,95,132,140,93,19,170,39,147,195,201,194,70,46, -137,215,17,218,69,4,236,98,232,157,153,39,110,81,220,15,193,209,83,3,200, -119,130,241,241,117,240,120,80,252,137,10,178,10,103,134,180,122,9,135,136, -154,120,169,199,142,158,121,10,7,146,162,121,74,71,150,166,121,138,135,154, -170,121,202,199,158,23,201,146,243,225,26,39,12,145,61,16,190,76,151,159,6, -65,56,100,137,233,35,93,205,144,33,224,140,137,196,54,121,244,5,60,17,145, -56,85,184,19,207,16,21,18,227,65,198,231,72,16,137,112,168,106,38,76,225,2, -70,65,56,100,237,34,140,177,4,134,65,56,100,237,34,129,117,204,123,154,70, -207,46,64,146,52,78,25,59,72,163,48,65,34,52,78,25,59,72,160,93,115,30,230, -145,179,204,144,24,146,16,30,76,209,2,40,210,72,64,121,52,4,0,156,88,97,5, -194,96,227,18,124,124,93,55,79,15,39,28,94,49,38,159,154,136,96,196,159,29, -102,241,241,115,201,25,227,131,36,133,20,62,110,142,253,2,102,36,248,235, -55,143,139,158,72,207,28,104,24,73,112,201,3,2,82,65,155,187,94,6,20,72,9, -147,120,128,225,144,168,105,56,248,185,228,140,241,190,96,128,200,84,52, -156,124,92,242,70,104,36,183,168,4,145,0,190,41,1,139,18,19,36,226,146,17, -124,73,82,54,124,37,230,70,201,14,108,184,132,8,68,185,34,1,100,31,8,129,8, -151,11,23,100,141,225,18,12,68,184,75,204,141,146,2,178,112,72,8,162,98,92, -50,10,152,147,227,172,222,62,46,121,35,60,114,88,96,92,185,112,201,65,34, -92,4,1,147,81,159,141,205,32,234,121,96,97,57,64,97,121,128,14,56,37,199, -89,188,124,92,242,70,120,227,144,53,18,227,226,233,186,120,121,56,226,242, -8,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,36,136,48,64,114,0, -250,156,168,1,64,247,175,25,36,2,8,11,94,80,248,16,40,104,242,103,200,48, -193,3,162,92,4,98,12,41,14,66,40,106,101,1,132,130,8,24,78,104,129,54,62, -96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,178, -58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,129, -232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,201, -126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,132, -0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,46, -36,29,4,78,69,6,60,226,31,192,7,255,252,24,160,163,11,23,51,130,56,35,193, -56,100,238,31,6,150,46,103,4,225,147,143,114,27,62,233,241,200,137,182,133, -42,142,167,216,6,23,216,0,97,28,17,224,39,223,32,80,142,8,240,78,25,56,9, -248,8,22,39,12,156,123,144,217,240,19,240,18,6,19,154,32,79,194,124,14,134, -140,151,227,139,226,52,11,88,37,62,33,163,37,248,226,248,141,32,213,184,64, -89,56,39,49,224,137,60,100,5,96,38,35,249,8,15,18,61,96,17,60,200,6,145,1, -17,31,206,64,89,45,2,39,161,0,178,122,209,63,74,2,101,64,202,113,67,77,235, -64,92,221,197,186,196,143,4,9,19,188,1,25,187,139,112,128,178,113,110,177, -35,193,2,68,239,0,46,110,229,30,242,71,130,4,137,222,4,35,55,113,110,16,22, -78,81,239,36,120,32,72,157,224,64,147,138,25,237,0,52,72,242,2,126,82,3,74, -129,148,227,234,66,12,112,28,140,155,104,203,169,158,9,133,158,4,25,36,1, -61,96,47,181,80,46,132,128,255,223,255,255,255,255,255,254,39,172,67,118, -170,5,208,144,0,0,0,0,0,0,0,0,115,16,31,254,0,0,0,0,0,0,8,245,238,146,38, -138,147,105,13,42,26,137,226,3,255,128,0,0,0,0,0,1,30,180,134,4,209,82,109, -33,165,67,81,60,64,255,240,0,0,0,0,0,0,28,144,155,104,0,0,0,0,0,0,0,0,16, -117,59,130,48,155,98,48,187,144,3,205,220,42,46,65,237,72,27,55,112,151, -123,154,70,205,0,94,208,129,115,119,31,18,9,18,67,155,183,34,12,176,96,175, -4,100,74,228,3,237,38,43,31,192,109,117,171,0,228,164,219,72,127,248,0,0,0, -0,0,0,196,234,111,0,50,110,224,193,50,114,83,138,26,107,192,131,38,238,77, -12,39,37,56,161,166,188,11,132,188,12,74,110,226,220,32,44,156,24,38,78,74, -113,67,77,120,28,148,221,197,184,64,89,57,52,48,156,148,226,134,154,240,64, -195,94,8,56,123,193,11,85,116,140,45,240,3,152,147,228,208,194,95,0,89,137, -62,22,139,95,48,64,70,200,67,28,98,79,180,152,139,218,45,124,193,1,27,33, -16,65,137,62,49,205,153,236,132,81,102,36,251,73,137,157,115,102,123,33,24, -57,137,62,12,19,37,144,142,40,196,159,105,49,15,160,153,44,132,128,198,36, -248,48,98,200,73,18,98,79,180,152,135,208,98,200,74,16,98,79,135,117,35,43, -33,44,89,137,62,210,98,63,93,72,202,200,76,20,98,79,140,67,105,50,74,200, -77,26,98,79,180,152,153,212,54,147,36,172,132,225,70,36,249,34,9,205,28, -172,132,241,166,36,251,73,138,93,32,156,209,202,200,80,30,98,79,140,66,214, -137,16,78,104,229,100,40,146,49,39,218,76,76,234,22,180,72,130,115,71,43, -33,72,137,137,62,77,12,38,92,210,113,197,44,137,59,64,7,145,39,201,161,132, -184,64,249,18,124,98,22,180,72,130,115,71,43,101,76,148,137,62,210,98,103, -80,181,162,68,19,154,57,91,42,130,164,73,242,68,19,154,57,91,95,84,108,137, -62,210,98,151,72,39,52,114,182,190,176,169,18,124,98,27,73,146,86,223,215, -27,34,79,180,152,153,212,54,147,36,173,191,176,34,68,159,14,234,70,86,231, -217,23,34,79,180,152,143,215,82,50,183,62,208,121,18,124,24,38,75,101,108, -84,137,62,210,98,31,65,50,91,43,130,36,73,241,142,108,207,109,125,209,114, -36,251,73,137,157,115,102,123,107,239,11,145,39,194,209,107,230,8,8,219, -127,124,116,137,62,210,98,47,104,181,243,4,4,109,191,192,135,49,39,204,16, -17,178,24,32,242,36,249,130,2,54,203,7,6,104,14,76,131,140,144,0,0,0,0,0,0, -0,1,141,207,215,12,78,126,193,46,190,126,192,98,179,246,4,197,231,236,10, -193,9,114,11,172,64,73,146,83,236,145,169,237,1,6,120,14,78,129,179,40,249, -18,149,175,207,141,199,27,76,248,156,81,177,207,139,198,9,169,199,129,58, -136,19,202,11,179,20,240,149,2,248,72,197,209,200,148,162,117,48,39,148, -151,102,42,228,64,211,19,132,140,93,28,137,74,39,85,2,121,81,118,98,238,68, -133,36,72,209,19,132,140,93,28,137,74,39,87,2,121,89,118,98,190,75,13,152, -47,194,70,46,142,68,165,19,172,129,60,176,187,49,79,39,135,147,132,140,93, -28,137,74,39,91,2,121,105,118,98,142,210,40,39,99,23,71,34,82,135,8,128, -120,72,8,0,183,225,81,98,138,237,33,58,182,232,232,64,64,2,107,177,187,181, -85,22,7,213,183,74,1,255,49,114,23,247,209,207,120,94,173,198,210,36,3,255, -113,84,118,82,184,47,224,221,91,141,163,160,72,7,251,121,111,98,164,220, -161,192,186,244,64,64,9,33,251,84,68,45,24,15,217,66,51,209,218,210,128, -127,205,65,60,204,254,119,154,23,178,132,103,165,0,255,218,130,121,153,252, -239,52,167,224,121,44,48,46,95,203,166,238,74,113,67,77,201,128,219,152, -164,82,6,0,203,76,64,64,9,210,211,18,4,4,144,221,49,40,64,76,13,211,19,5,4, -192,221,45,66,1,4,24,207,76,82,2,8,136,94,152,156,24,157,45,49,64,6,75,191, -76,80,66,149,110,116,116,197,8,41,240,247,79,70,188,6,183,27,76,80,194,45, -198,210,211,20,144,171,113,180,116,52,197,40,27,1,125,34,240,27,16,221,42, -240,27,221,109,66,32,104,129,163,115,52,224,5,139,168,209,233,138,32,57,33, -186,98,138,18,80,140,244,197,24,28,192,221,49,71,11,56,209,162,211,20,183, -1,66,188,17,145,52,40,9,148,226,134,153,5,198,137,136,32,14,12,30,164,140, -144,230,192,64,211,136,0,0,0,0,0,182,120,43,135,126,16,68,52,174,195,144, -12,2,158,4,128,70,22,24,128,101,67,112,163,192,100,104,176,131,192,99,32, -176,99,192,226,115,30,1,79,4,68,28,16,54,0,0,41,254,232,116,62,204,7,21,35, -18,54,127,80,28,192,132,28,32,14,96,197,212,243,193,48,188,240,39,130,236, -224,175,131,117,2,178,112,145,139,163,145,131,114,70,46,142,218,27,182,72, -197,209,219,56,26,53,161,166,32,128,56,18,2,129,239,94,50,76,130,68,230, -202,113,160,167,146,94,163,134,66,161,164,227,226,231,146,51,198,249,147, -71,209,67,73,210,94,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15, -155,163,191,68,28,98,79,143,139,166,233,225,228,227,139,198,37,210,244,208, -24,137,112,151,153,27,36,5,100,224,146,105,184,100,196,95,18,84,141,159,9, -121,145,178,67,155,46,33,38,187,168,252,211,243,81,92,2,14,40,16,50,37,202, -160,150,154,67,152,148,20,28,76,156,89,26,105,158,63,232,16,44,150,129,18, -146,44,28,96,14,98,216,80,113,50,113,100,105,166,120,255,160,20,28,76,156, -113,75,34,78,63,236,3,6,133,41,35,31,242,18,195,152,147,226,27,61,138,41, -140,16,98,79,148,67,103,177,69,45,136,49,39,196,54,122,58,212,83,26,36,196, -159,40,134,207,71,90,138,92,16,98,79,136,108,244,244,168,166,56,73,137,62, -81,13,158,158,149,20,186,40,196,159,10,183,2,122,122,84,82,240,163,18,124, -42,220,9,235,106,81,75,225,228,73,241,13,158,197,54,198,8,145,39,202,33, -179,216,166,214,196,72,147,226,27,61,29,106,109,141,19,34,79,148,67,103, -163,173,77,174,8,145,39,196,54,122,122,84,219,28,38,68,159,40,134,207,79, -74,155,93,21,34,79,133,91,129,61,61,42,109,120,84,137,62,21,110,4,245,181, -41,181,248,56,224,28,24,80,113,50,113,100,105,166,120,255,160,20,28,76,156, -113,75,34,78,63,236,3,6,133,41,35,31,242,11,174,254,160,34,84,8,35,16,98, -146,38,55,32,33,30,135,19,36,182,158,72,237,17,100,97,27,56,7,254,0,0,0,0, -0,0,6,56,199,161,30,135,19,36,182,158,72,237,17,100,97,27,56,7,254,0,0,0,0, -0,0,6,55,36,33,30,135,19,36,182,158,72,237,17,100,97,27,56,7,254,0,0,0,0,0, -0,10,40,11,91,133,199,172,8,111,248,128,239,88,16,222,56,191,242,49,198,69, -8,244,56,153,37,180,242,71,104,139,35,8,217,192,63,240,0,0,0,0,0,0,49,185, -65,8,244,56,153,37,180,242,71,104,139,35,8,217,192,63,240,0,0,0,0,0,0,49, -198,77,8,244,56,153,37,180,242,71,104,139,35,8,217,192,63,240,0,0,0,0,0,0, -49,185,97,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0,0, -49,198,85,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0,0, -49,185,129,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0, -0,49,198,93,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0, -0,49,185,161,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0,0,0, -0,0,49,198,101,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0,0, -0,0,0,49,185,193,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0, -0,0,0,0,49,198,109,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0, -0,0,0,0,0,49,185,225,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16, -0,0,0,0,0,0,49,198,117,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64, -16,0,0,0,0,0,0,49,186,1,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64, -32,0,0,0,0,0,0,49,198,125,8,244,56,153,37,180,242,71,104,139,35,8,217,192, -64,32,0,0,0,0,0,0,32,232,130,0,97,57,162,4,245,72,10,68,184,70,137,195,67, -77,175,32,66,37,192,208,165,36,117,196,10,14,38,78,44,141,52,207,169,64,56, -156,199,130,36,160,141,146,52,38,32,76,72,1,246,136,235,103,177,69,1,17,32, -7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,171,37,20,65,145,32,7, -218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,158,142,183,86,74,41,48, -92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,246,136,235,103,167,165, -213,146,138,40,200,144,3,237,17,214,207,79,75,161,37,20,138,46,36,0,248, -134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,75,161,37,20,170,46,36, -0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,39,208,146,138,70,25,18, -0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,129,89,58,18,81,72,226, -162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,17,214,207,161,37,22,144, -38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,207,161,37,22,176,42,209, -68,201,218,35,173,158,197,54,4,218,40,153,56,134,207,98,155,75,27,104,162, -100,237,17,214,207,71,91,171,37,54,65,182,138,38,78,209,29,108,244,117,186, -18,83,104,131,45,20,76,156,67,103,163,173,213,146,155,76,25,104,162,100, -226,27,61,29,110,132,148,218,160,219,69,19,39,104,142,182,122,122,93,89,41, -178,141,180,81,50,118,136,235,103,167,165,208,146,155,69,25,104,162,100, -226,27,61,61,46,172,148,218,104,203,69,19,39,16,217,233,233,116,36,166,213, -70,90,40,153,56,85,184,19,234,201,77,152,101,162,137,147,133,91,129,62,132, -148,218,48,219,69,19,39,6,234,5,100,234,201,77,156,109,162,137,147,131,117, -2,178,116,36,166,209,197,218,40,153,59,68,117,179,234,201,78,32,11,180,81, -50,118,136,235,103,208,146,156,72,21,104,162,100,226,27,62,172,148,226,128, -171,69,19,39,16,217,244,36,167,22,53,59,22,53,91,0,2,21,11,94,181,128,196, -133,0,185,80,32,56,156,199,130,36,160,72,16,78,126,53,144,5,146,208,34,82, -72,1,109,20,76,155,40,32,233,0,115,70,130,8,209,56,104,105,187,252,193,3, -17,162,112,201,242,18,65,211,0,230,149,132,17,162,112,208,211,119,248,0,82, -130,96,95,127,128,130,80,102,186,36,232,92,206,255,1,80,48,200,39,12,158, -241,64, +18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,232,59, +147,60,93,110,79,15,39,9,24,186,33,13,63,111,185,16,211,206,251,114,98,17, +171,160,11,199,197,215,196,66,26,102,38,68,53,212,77,136,104,255,5,114,120, +121,7,192,70,32,192,67,95,249,59,13,13,127,228,248,134,191,242,133,208,215, +254,81,204,67,95,249,75,33,13,127,229,61,84,53,255,149,52,80,215,254,85, +217,67,95,249,91,121,13,90,181,168,134,143,152,95,38,75,207,132,104,156,50, +70,33,163,225,66,249,50,94,124,25,4,225,146,49,14,24,28,196,7,255,128,0,0, +0,0,0,12,204,7,255,0,0,0,0,0,0,12,188,72,6,176,77,225,28,24,103,14,33,197, +138,113,227,28,152,231,46,65,205,19,194,84,11,225,35,23,68,231,138,228,64, +211,19,132,140,93,19,162,59,145,33,73,18,52,68,225,35,23,68,233,139,228, +176,217,130,252,36,98,232,157,81,60,158,30,78,18,49,116,78,184,142,210,40, +39,99,23,68,236,201,59,114,142,224,126,14,138,152,30,67,188,23,143,139,175, +131,194,135,228,72,85,144,83,60,53,163,208,76,60,68,211,197,78,60,116,243, +200,80,60,149,19,202,82,60,181,51,204,84,60,213,83,206,86,60,240,190,76, +151,159,8,209,56,100,137,232,133,242,100,188,248,50,9,195,36,79,73,26,238, +108,129,15,4,100,78,33,179,207,160,41,224,140,137,194,173,192,158,120,128, +168,151,26,14,55,58,64,132,75,133,67,81,50,103,8,18,50,9,195,39,105,20,101, +136,36,50,9,195,39,105,20,11,174,99,220,210,54,121,114,4,145,162,112,201, +218,69,25,130,9,17,162,112,201,218,69,2,235,152,247,52,141,158,100,128,196, +144,128,242,102,136,17,70,146,66,3,201,160,32,0,130,225,48,113,137,62,62, +46,155,167,135,147,142,47,24,147,79,205,68,48,98,79,142,179,120,248,185, +228,140,241,193,146,66,138,31,55,71,126,129,51,18,124,117,155,199,197,207, +36,103,142,52,12,36,184,100,129,129,41,32,205,221,175,3,10,36,4,201,188,64, +112,200,84,52,156,124,92,242,70,120,223,48,64,100,42,26,78,62,46,121,35,52, +18,91,212,2,72,128,95,20,128,197,137,9,146,113,73,8,190,36,169,27,62,18, +243,35,100,135,54,92,66,4,34,92,145,0,178,15,132,64,132,75,133,139,178,70, +240,137,6,34,92,37,230,70,201,1,89,56,36,4,81,49,46,25,5,76,73,241,214,111, +31,23,60,145,158,57,44,48,46,92,184,100,160,145,46,2,0,201,168,207,198,230, +144,117,60,176,48,156,160,48,188,192,7,28,18,227,172,222,62,46,121,35,60, +113,200,26,137,113,241,116,221,60,60,156,113,121,4,20,124,92,242,70,120, +226,37,194,54,140,36,64,21,147,146,68,24,32,57,0,125,78,84,0,160,123,215, +140,146,1,4,5,175,40,124,8,20,52,121,51,228,24,96,129,209,46,2,49,6,20,135, +33,20,53,50,128,194,65,4,12,39,52,64,155,31,48,112,72,6,247,62,16,1,31,73, +30,25,240,60,73,82,70,68,138,0,89,29,5,156,96,2,201,104,17,35,160,18,78, +140,228,16,26,79,90,4,73,43,192,244,108,142,130,206,89,240,58,26,50,95,142, +43,159,65,107,4,167,196,52,100,191,28,87,63,128,15,255,240,164,169,35,136, +6,128,146,115,9,0,210,7,43,163,194,0,71,128,105,65,176,15,128,105,131,21, +11,153,35,0,211,134,137,7,65,18,33,244,23,18,14,130,39,34,131,30,113,15, +224,3,255,254,12,80,81,133,139,153,193,28,17,224,156,50,119,15,131,75,23, +51,130,112,201,199,185,13,159,116,248,228,68,219,66,149,83,83,238,3,11,238, +0,48,142,8,240,19,239,144,40,71,4,120,39,12,156,4,252,4,11,19,134,78,61, +200,108,248,9,248,9,3,9,205,16,39,225,62,7,67,70,75,241,197,241,154,5,172, +18,159,16,209,146,252,113,124,102,144,106,220,32,44,156,19,152,240,68,158, +66,2,176,19,17,252,164,7,137,30,176,8,158,116,3,72,128,136,143,232,32,44, +150,129,19,210,128,89,61,104,159,169,1,50,160,101,56,161,166,246,160,46, +110,226,221,98,71,130,4,137,222,0,140,221,197,184,64,89,56,183,88,145,224, +129,34,119,128,23,55,114,143,121,35,193,2,68,239,2,17,155,184,183,8,11,39, +40,247,146,60,16,36,78,240,32,73,197,12,247,128,26,36,121,1,63,49,2,165,48, +70,114,229,145,51,250,205,2,8,209,203,150,68,207,235,52,130,16,209,46,131, +36,188,70,128,210,160,101,56,251,16,131,28,7,35,38,218,50,234,103,130,97, +103,129,6,73,0,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,7,36,38,218,0, +0,0,0,0,0,0,0,4,29,78,224,140,38,216,140,46,228,0,243,119,10,139,144,123, +82,6,205,220,37,222,230,145,179,64,23,180,32,92,221,199,196,130,68,144,230, +237,200,131,44,24,43,193,25,18,185,0,251,73,138,199,240,27,93,106,192,57, +41,54,210,31,254,0,0,0,0,0,0,49,58,155,192,12,155,184,48,76,156,148,226, +134,154,240,32,201,187,147,67,9,201,78,40,105,175,2,225,47,3,18,155,184, +183,8,11,39,6,9,147,146,156,80,211,94,7,37,55,113,110,16,22,78,77,12,39,37, +56,161,166,188,16,48,215,130,14,30,240,66,213,93,35,11,124,0,230,36,249,52, +48,151,192,22,98,79,133,162,215,204,16,17,178,16,199,24,147,237,38,34,246, +139,95,48,64,70,200,68,16,98,79,140,115,102,123,33,20,89,137,62,210,98,103, +92,217,158,200,70,14,98,79,131,4,201,100,35,138,49,39,218,76,67,232,38,75, +33,32,49,137,62,12,24,178,18,68,152,147,237,38,33,244,24,178,18,132,24,147, +225,221,72,202,200,75,22,98,79,180,152,143,215,82,50,178,19,5,24,147,227, +16,218,76,146,178,19,70,152,147,237,38,38,117,13,164,201,43,33,56,81,137, +62,72,130,115,71,43,33,60,105,137,62,210,98,151,72,39,52,114,178,20,7,152, +147,227,16,181,162,68,19,154,57,89,10,36,140,73,246,147,19,58,133,173,18, +32,156,209,202,200,82,34,98,79,147,67,9,151,52,156,113,75,34,78,208,1,228, +73,242,104,97,46,16,62,68,159,24,133,173,18,32,156,209,202,217,83,37,34,79, +180,152,153,212,45,104,145,4,230,142,86,202,160,169,18,124,145,4,230,142, +86,215,213,27,34,79,180,152,165,210,9,205,28,173,175,172,42,68,159,24,134, +210,100,149,183,245,198,200,147,237,38,38,117,13,164,201,43,111,236,8,145, +39,195,186,145,149,185,246,69,200,147,237,38,35,245,212,140,173,207,180,30, +68,159,6,9,146,217,91,21,34,79,180,152,135,208,76,150,202,224,137,18,124, +99,155,51,219,95,116,92,137,62,210,98,103,92,217,158,218,251,194,228,73, +240,180,90,249,130,2,54,223,223,29,34,79,180,152,139,218,45,124,193,1,27, +111,240,33,204,73,243,4,4,108,134,8,60,137,62,96,128,141,178,193,193,154,3, +147,32,227,36,0,0,0,0,0,0,0,0,99,115,245,195,19,159,176,75,175,159,176,24, +172,253,129,49,121,251,2,176,66,92,130,235,16,18,100,148,251,36,106,123,64, +65,158,3,147,160,108,202,62,68,165,107,243,227,113,198,211,62,39,20,108, +115,226,241,130,106,113,224,78,162,4,242,130,236,197,60,37,64,190,18,49, +116,114,37,40,157,76,9,229,37,217,138,185,16,52,196,225,35,23,71,34,82,137, +213,64,158,84,93,152,187,145,33,73,18,52,68,225,35,23,71,34,82,137,213,192, +158,86,93,152,175,146,195,102,11,240,145,139,163,145,41,68,235,32,79,44,46, +204,83,201,225,228,225,35,23,71,34,82,137,214,192,158,90,93,152,163,180, +138,9,216,197,209,200,148,161,194,32,30,18,2,0,45,248,84,88,162,187,72,78, +173,186,58,16,16,0,154,236,110,237,85,69,129,245,109,210,128,127,204,92, +133,253,244,115,222,23,171,113,180,137,0,255,220,85,29,148,174,11,248,55, +86,227,104,232,18,1,254,222,91,216,169,55,40,112,46,189,16,16,2,72,126,213, +17,11,70,3,246,80,140,244,118,180,160,31,243,80,79,51,63,157,230,133,236, +161,25,233,64,63,246,160,158,102,127,59,205,41,248,30,75,12,11,151,242,233, +187,146,156,80,211,114,96,54,230,41,20,129,128,50,211,16,16,2,116,180,196, +129,1,36,55,76,74,16,19,3,116,196,193,65,48,55,75,80,128,65,6,51,211,20, +128,130,34,23,166,39,6,39,75,76,80,1,146,239,211,20,16,165,91,157,29,49,66, +10,124,61,211,209,175,1,173,198,211,20,48,139,113,180,180,197,36,42,220, +109,29,13,49,74,6,192,95,72,188,6,196,55,74,188,6,247,91,80,136,26,32,104, +220,205,56,1,98,234,52,122,98,136,14,72,110,152,162,132,148,35,61,49,70,7, +48,55,76,81,194,206,52,104,180,197,45,192,80,175,4,100,77,10,2,101,56,161, +166,65,113,162,98,8,3,131,7,169,35,36,57,176,16,52,232,80,0,0,0,0,45,158, +10,225,223,132,17,13,43,176,228,3,0,167,129,32,17,133,134,32,25,80,220,40, +240,25,26,44,32,240,24,200,44,24,240,56,156,199,128,83,193,17,7,4,13,128,0, +10,79,202,28,223,195,1,197,72,196,141,159,220,7,48,33,7,8,3,152,49,117,60, +240,76,47,60,9,224,187,56,43,224,221,64,172,156,36,98,232,228,96,220,145, +139,163,182,134,237,146,49,116,118,206,6,141,104,105,136,32,14,4,128,160, +123,215,140,147,32,145,57,178,156,104,41,228,151,168,225,144,168,105,56, +248,185,228,140,241,190,100,209,244,80,210,116,151,134,12,73,241,214,111, +31,23,60,145,158,56,50,72,81,67,230,232,239,209,7,24,147,227,226,233,186, +120,121,56,226,241,137,116,189,52,6,34,92,37,230,70,201,1,89,56,36,154,110, +25,49,23,196,149,35,103,194,94,100,108,144,230,203,136,73,174,234,63,52, +252,212,87,0,131,138,4,12,137,114,168,37,166,144,230,37,5,7,19,39,22,70, +154,103,143,252,4,11,37,160,68,164,139,7,24,3,152,182,20,28,76,156,89,26, +105,158,63,240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253,132, +176,230,36,248,134,207,98,138,99,4,24,147,229,16,217,236,81,75,98,12,73, +241,13,158,142,181,20,198,137,49,39,202,33,179,209,214,162,151,4,24,147, +226,27,61,61,42,41,142,18,98,79,148,67,103,167,165,69,46,138,49,39,194,173, +192,158,158,149,20,188,40,196,159,10,183,2,122,218,148,82,248,121,18,124, +67,103,177,77,177,130,36,73,242,136,108,246,41,181,177,18,36,248,134,207, +71,90,155,99,68,200,147,229,16,217,232,235,83,107,130,36,73,241,13,158,158, +149,54,199,9,145,39,202,33,179,211,210,166,215,69,72,147,225,86,224,79,79, +74,155,94,21,34,79,133,91,129,61,109,74,109,126,14,56,7,6,20,28,76,156,89, +26,105,158,63,240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253, +130,235,191,232,8,149,2,8,196,24,164,137,141,200,8,71,161,196,201,45,167, +146,59,68,89,24,70,206,1,255,128,0,0,0,0,0,1,142,49,232,71,161,196,201,45, +167,146,59,68,89,24,70,206,1,255,128,0,0,0,0,0,1,141,201,8,71,161,196,201, +45,167,146,59,68,89,24,70,206,1,255,128,0,0,0,0,0,2,138,2,214,225,113,235, +2,27,128,0,10,66,3,189,96,67,120,226,224,0,2,148,140,113,145,66,61,14,38, +73,109,60,145,218,34,200,194,54,112,15,252,0,0,0,0,0,0,12,110,80,66,61,14, +38,73,109,60,145,218,34,200,194,54,112,15,252,0,0,0,0,0,0,12,113,147,66,61, +14,38,73,109,60,145,218,34,200,194,54,112,15,252,0,0,0,0,0,0,12,110,88,66, +61,14,38,73,109,60,145,218,34,200,194,54,112,16,0,0,0,0,0,0,0,12,113,149, +66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,0,0,0,0,0,0,0,12,110,96, +66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,0,0,0,0,0,0,0,12,113, +151,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,0,0,0,0,0,0,0,12, +110,104,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0,0,0,0,0,0, +12,113,153,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0,0,0,0,0, +0,12,110,112,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0,0,0,0, +0,0,12,113,155,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0,0,0, +0,0,0,12,110,120,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0,0, +0,0,0,0,12,113,157,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0, +0,0,0,0,0,12,110,128,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,8, +0,0,0,0,0,0,12,113,159,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16, +8,0,0,0,0,0,0,8,58,32,128,24,78,104,129,61,82,2,145,46,17,162,112,208,211, +107,200,16,137,112,52,41,73,29,113,2,131,137,147,139,35,77,51,234,80,14,39, +49,224,137,40,35,100,141,9,136,19,18,0,125,162,58,217,236,81,64,68,72,1, +241,13,158,197,20,150,50,36,0,251,68,117,179,209,214,234,201,69,16,100,72, +1,246,136,235,103,163,173,208,146,138,68,23,18,0,124,67,103,163,173,213, +146,138,76,23,18,0,124,67,103,163,173,208,146,138,84,25,18,0,125,162,58, +217,233,233,117,100,162,138,50,36,0,251,68,117,179,211,210,232,73,69,34, +139,137,0,62,33,179,211,210,234,201,69,38,139,137,0,62,33,179,211,210,232, +73,69,42,139,137,0,62,21,110,4,250,178,81,70,23,18,0,124,42,220,9,244,36, +162,145,134,68,128,31,6,234,5,100,234,201,69,28,100,72,1,240,110,160,86,78, +132,148,82,56,168,144,3,237,17,214,207,171,37,22,128,42,36,0,251,68,117, +179,232,73,69,164,9,137,0,62,33,179,234,201,69,168,9,137,0,62,33,179,232, +73,69,172,10,180,81,50,118,136,235,103,177,77,129,54,138,38,78,33,179,216, +166,210,198,218,40,153,59,68,117,179,209,214,234,201,77,144,109,162,137, +147,180,71,91,61,29,110,132,148,218,32,203,69,19,39,16,217,232,235,117,100, +166,211,6,90,40,153,56,134,207,71,91,161,37,54,168,54,209,68,201,218,35, +173,158,158,151,86,74,108,163,109,20,76,157,162,58,217,233,233,116,36,166, +209,70,90,40,153,56,134,207,79,75,171,37,54,154,50,209,68,201,196,54,122, +122,93,9,41,181,81,150,138,38,78,21,110,4,250,178,83,102,25,104,162,100, +225,86,224,79,161,37,54,140,54,209,68,201,193,186,129,89,58,178,83,103,27, +104,162,100,224,221,64,172,157,9,41,180,113,118,138,38,78,209,29,108,250, +178,83,136,2,237,20,76,157,162,58,217,244,36,167,18,5,90,40,153,56,134,207, +171,37,56,160,42,209,68,201,196,54,125,9,41,197,141,78,197,141,86,192,0, +133,66,215,173,96,49,33,64,46,84,8,14,39,49,224,137,40,18,4,19,159,141,100, +1,100,180,8,148,146,0,91,69,19,38,202,8,58,64,28,209,160,130,52,78,26,26, +110,255,80,64,196,104,156,50,125,4,144,116,192,57,165,97,4,104,156,52,52, +221,254,64,20,160,152,23,223,228,32,148,25,174,137,58,23,51,191,200,84,12, +50,9,195,39,196,80, }; #elif defined(DUK_USE_DOUBLE_ME) -DUK_INTERNAL const duk_uint8_t duk_builtins_data[3790] = { +DUK_INTERNAL const duk_uint8_t duk_builtins_data[3819] = { 144,148,105,221,32,68,52,228,62,12,104,200,165,134,148,248,81,77,61,191, 135,35,154,103,34,72,6,157,159,197,145,77,245,126,52,130,106,234,163,196, 52,226,18,51,161,26,113,1,60,37,64,190,18,49,116,116,33,26,113,1,92,136,26, 98,112,145,139,163,165,8,211,136,14,228,72,82,68,141,17,56,72,197,209,212, 132,105,196,5,242,88,108,193,126,18,49,116,117,161,26,113,1,60,158,30,78, -18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,224,59, -147,60,93,110,79,15,39,9,24,186,33,13,63,79,185,39,26,121,223,110,77,66,53, -116,1,120,248,186,248,136,67,76,196,200,134,186,137,177,13,31,192,174,79, -15,32,248,8,196,24,8,107,254,39,97,161,175,248,159,16,215,252,80,186,26, -255,138,57,136,107,254,41,100,33,175,248,167,170,134,191,226,166,138,26, -255,138,187,40,107,254,43,111,33,171,86,181,16,209,241,11,228,201,121,240, -141,19,134,72,196,52,123,168,95,38,75,207,131,32,156,50,70,33,195,3,152, -128,0,1,240,254,0,0,0,1,153,128,0,1,224,254,0,0,0,1,151,137,0,214,9,188,35, -131,12,225,196,56,177,78,60,99,147,28,229,200,57,162,120,74,129,124,36,98, -232,156,241,92,136,26,98,112,145,139,162,116,71,114,36,41,34,70,136,156,36, -98,232,157,49,124,150,27,48,95,132,140,93,19,170,39,147,195,201,194,70,46, -137,215,17,218,69,4,236,98,232,157,153,39,110,81,220,15,193,209,83,3,200, -119,130,241,241,117,240,120,80,252,137,10,178,10,103,134,180,122,9,135,136, -154,120,169,199,142,158,121,10,7,146,162,121,74,71,150,166,121,138,135,154, -170,121,202,199,158,23,201,146,243,225,26,39,12,145,61,16,190,76,151,159,6, -65,56,100,137,233,35,93,205,144,33,224,140,137,196,54,121,244,5,60,17,145, -56,85,184,19,207,16,21,18,227,65,198,231,72,16,137,112,168,106,38,76,225,2, -70,65,56,100,237,34,140,177,4,134,65,56,100,237,34,129,117,204,123,154,70, -207,46,64,146,52,78,25,59,72,163,48,65,34,52,78,25,59,72,160,93,115,30,230, -145,179,204,144,24,146,16,30,76,209,2,40,210,72,64,121,52,4,0,156,88,97,5, -194,96,227,18,124,124,93,55,79,15,39,28,94,49,38,159,154,136,96,196,159,29, -102,241,241,115,201,25,227,131,36,133,20,62,110,142,253,2,102,36,248,235, -55,143,139,158,72,207,28,104,24,73,112,201,3,2,82,65,155,187,94,6,20,72,9, -147,120,128,225,144,168,105,56,248,185,228,140,241,190,96,128,200,84,52, -156,124,92,242,70,104,36,183,168,4,145,0,190,41,1,139,18,19,36,226,146,17, -124,73,82,54,124,37,230,70,201,14,108,184,132,8,68,185,34,1,100,31,8,129,8, -151,11,23,100,141,225,18,12,68,184,75,204,141,146,2,178,112,72,8,162,98,92, -50,10,152,147,227,172,222,62,46,121,35,60,114,88,96,92,185,112,201,65,34, -92,4,1,147,81,159,141,205,32,234,121,96,97,57,64,97,121,128,14,56,37,199, -89,188,124,92,242,70,120,227,144,53,18,227,226,233,186,120,121,56,226,242, -8,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,36,136,48,64,114,0, -250,156,168,1,64,247,175,25,36,2,8,11,94,80,248,16,40,104,242,103,200,48, -193,3,162,92,4,98,12,41,14,66,40,106,101,1,132,130,8,24,78,104,129,54,62, -96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,178, -58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,129, -232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,201, -126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,132, -0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,46, -36,29,4,78,69,6,60,226,31,192,7,255,252,24,160,163,11,23,51,130,56,35,193, -56,100,238,31,6,150,46,103,4,225,147,143,114,27,62,233,241,200,137,182,133, -42,142,167,216,6,23,216,0,97,28,17,224,39,223,32,80,142,8,240,78,25,56,9, -248,8,22,39,12,156,123,144,217,240,19,240,18,6,19,154,32,79,194,124,14,134, -140,151,227,139,226,52,11,88,37,62,33,163,37,248,226,248,141,32,213,184,64, -89,56,39,49,224,137,60,100,5,96,38,35,249,8,15,18,61,96,17,60,200,6,145,1, -17,31,206,64,89,45,2,39,161,0,178,122,209,63,74,2,101,64,202,113,67,77,235, -64,92,221,197,186,196,143,4,9,19,188,1,25,187,139,112,128,178,113,110,177, -35,193,2,68,239,0,46,110,229,30,242,71,130,4,137,222,4,35,55,113,110,16,22, -78,81,239,36,120,32,72,157,224,64,147,138,25,237,0,52,72,242,2,126,82,3,74, -129,148,227,234,66,12,112,28,140,155,104,203,169,158,9,133,158,4,25,36,1, -61,96,47,181,80,46,132,129,255,255,222,255,255,255,255,254,39,172,67,118, -170,5,208,144,0,0,0,0,0,64,0,0,51,16,0,0,62,31,192,0,0,0,8,245,238,146,38, -138,147,105,13,42,26,137,226,0,0,7,131,248,0,0,0,1,30,180,134,4,209,82,109, -33,165,67,81,60,64,0,0,240,255,0,0,0,0,28,144,155,104,0,0,0,0,0,0,0,0,16, -117,59,130,48,155,98,48,187,144,3,205,220,42,46,65,237,72,27,55,112,151, -123,154,70,205,0,94,208,129,115,119,31,18,9,18,67,155,183,34,12,176,96,175, -4,100,74,228,3,237,38,43,31,192,109,117,171,0,228,164,219,72,0,0,248,127,0, -0,0,0,196,234,111,0,50,110,224,193,50,114,83,138,26,107,192,131,38,238,77, -12,39,37,56,161,166,188,11,132,188,12,74,110,226,220,32,44,156,24,38,78,74, -113,67,77,120,28,148,221,197,184,64,89,57,52,48,156,148,226,134,154,240,64, -195,94,8,56,123,193,11,85,116,140,45,240,3,152,147,228,208,194,95,0,89,137, -62,22,139,95,48,64,70,200,67,28,98,79,180,152,139,218,45,124,193,1,27,33, -16,65,137,62,49,205,153,236,132,81,102,36,251,73,137,157,115,102,123,33,24, -57,137,62,12,19,37,144,142,40,196,159,105,49,15,160,153,44,132,128,198,36, -248,48,98,200,73,18,98,79,180,152,135,208,98,200,74,16,98,79,135,117,35,43, -33,44,89,137,62,210,98,63,93,72,202,200,76,20,98,79,140,67,105,50,74,200, -77,26,98,79,180,152,153,212,54,147,36,172,132,225,70,36,249,34,9,205,28, -172,132,241,166,36,251,73,138,93,32,156,209,202,200,80,30,98,79,140,66,214, -137,16,78,104,229,100,40,146,49,39,218,76,76,234,22,180,72,130,115,71,43, -33,72,137,137,62,77,12,38,92,210,113,197,44,137,59,64,7,145,39,201,161,132, -184,64,249,18,124,98,22,180,72,130,115,71,43,101,76,148,137,62,210,98,103, -80,181,162,68,19,154,57,91,42,130,164,73,242,68,19,154,57,91,95,84,108,137, -62,210,98,151,72,39,52,114,182,190,176,169,18,124,98,27,73,146,86,223,215, -27,34,79,180,152,153,212,54,147,36,173,191,176,34,68,159,14,234,70,86,231, -217,23,34,79,180,152,143,215,82,50,183,62,208,121,18,124,24,38,75,101,108, -84,137,62,210,98,31,65,50,91,43,130,36,73,241,142,108,207,109,125,209,114, -36,251,73,137,157,115,102,123,107,239,11,145,39,194,209,107,230,8,8,219, -127,124,116,137,62,210,98,47,104,181,243,4,4,109,191,192,135,49,39,204,16, -17,178,24,32,242,36,249,130,2,54,203,7,6,104,14,76,131,140,144,0,0,0,0,0,0, -0,1,141,207,215,12,78,126,193,46,190,126,192,98,179,246,4,197,231,236,10, -193,9,114,11,172,64,73,146,83,236,145,169,237,1,6,120,14,78,129,179,40,249, -18,149,175,207,141,199,27,76,248,156,81,177,207,139,198,9,169,199,129,58, -136,19,202,11,179,20,240,149,2,248,72,197,209,200,148,162,117,48,39,148, -151,102,42,228,64,211,19,132,140,93,28,137,74,39,85,2,121,81,118,98,238,68, -133,36,72,209,19,132,140,93,28,137,74,39,87,2,121,89,118,98,190,75,13,152, -47,194,70,46,142,68,165,19,172,129,60,176,187,49,79,39,135,147,132,140,93, -28,137,74,39,91,2,121,105,118,98,142,210,40,39,99,23,71,34,82,135,8,128, -120,72,1,87,224,168,13,42,226,145,97,58,182,232,232,64,177,107,2,64,22,85, -181,187,7,213,183,74,2,17,119,49,255,121,207,215,240,94,173,198,210,36,4, -113,95,115,255,232,34,182,80,221,91,141,163,160,72,15,121,123,103,225,220, -164,194,160,186,244,64,251,33,9,64,24,45,68,84,15,217,66,51,209,218,210, -129,61,65,204,127,154,118,254,204,23,178,132,103,165,2,122,131,216,255,52, -237,253,152,167,224,121,44,48,46,95,203,166,238,74,113,67,77,201,128,219, -152,164,82,6,0,203,76,64,64,9,210,211,18,4,4,144,221,49,40,64,76,13,211,19, -5,4,192,221,45,66,1,4,24,207,76,82,2,8,136,94,152,156,24,157,45,49,64,6,75, -191,76,80,66,149,110,116,116,197,8,41,240,247,79,70,188,6,183,27,76,80,194, -45,198,210,211,20,144,171,113,180,116,52,197,40,27,1,125,34,240,27,16,221, -42,240,27,221,109,66,32,104,129,163,115,52,224,5,139,168,209,233,138,32,57, -33,186,98,138,18,80,140,244,197,24,28,192,221,49,71,11,56,209,162,211,20, -183,1,66,188,17,145,52,40,9,148,226,134,153,5,198,137,136,32,14,12,30,164, -140,144,230,192,0,136,211,64,0,0,0,0,182,120,43,135,126,16,68,52,174,195, -144,12,2,158,4,128,70,22,24,128,101,67,112,163,192,100,104,176,131,192,99, -32,176,99,192,226,115,30,1,79,4,68,28,16,54,0,0,41,254,232,116,62,204,7,21, -35,18,54,127,80,28,192,132,28,32,14,96,197,212,243,193,48,188,240,39,130, -236,224,175,131,117,2,178,112,145,139,163,145,131,114,70,46,142,218,27,182, -72,197,209,219,56,26,53,161,166,32,128,56,18,2,129,239,94,50,76,130,68,230, -202,113,160,167,146,94,163,134,66,161,164,227,226,231,146,51,198,249,147, -71,209,67,73,210,94,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15, -155,163,191,68,28,98,79,143,139,166,233,225,228,227,139,198,37,210,244,208, -24,137,112,151,153,27,36,5,100,224,146,105,184,100,196,95,18,84,141,159,9, -121,145,178,67,155,46,33,38,187,168,252,211,243,81,92,2,14,40,16,50,37,202, -160,150,154,67,152,148,20,28,76,156,89,26,105,158,63,232,16,44,150,129,18, -146,44,28,96,14,98,216,80,113,50,113,100,105,166,120,255,160,20,28,76,156, -113,75,34,78,63,236,3,6,133,41,35,31,242,18,195,152,147,226,27,61,138,41, -140,16,98,79,148,67,103,177,69,45,136,49,39,196,54,122,58,212,83,26,36,196, -159,40,134,207,71,90,138,92,16,98,79,136,108,244,244,168,166,56,73,137,62, -81,13,158,158,149,20,186,40,196,159,10,183,2,122,122,84,82,240,163,18,124, -42,220,9,235,106,81,75,225,228,73,241,13,158,197,54,198,8,145,39,202,33, -179,216,166,214,196,72,147,226,27,61,29,106,109,141,19,34,79,148,67,103, -163,173,77,174,8,145,39,196,54,122,122,84,219,28,38,68,159,40,134,207,79, -74,155,93,21,34,79,133,91,129,61,61,42,109,120,84,137,62,21,110,4,245,181, -41,181,248,56,224,28,24,80,113,50,113,100,105,166,120,255,160,20,28,76,156, -113,75,34,78,63,236,3,6,133,41,35,31,242,11,174,254,160,34,84,8,35,16,98, -146,38,55,32,33,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,30,7,224,0, -0,0,6,56,199,161,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,30,7,224, -0,0,0,6,55,36,33,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,30,7,224, -0,0,0,10,40,11,91,133,199,172,8,111,248,128,239,88,16,222,56,191,242,49, -198,69,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,240,63,0,0,0,0, -49,185,65,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,240,63,0,0,0, -0,49,198,77,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,240,63,0,0, -0,0,49,185,97,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,0, -0,0,49,198,85,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,0, -0,0,49,185,129,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0, -0,0,0,49,198,93,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0, -0,0,0,49,185,161,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,16,64, -0,0,0,0,49,198,101,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,16, -64,0,0,0,0,49,185,193,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0, -16,64,0,0,0,0,49,198,109,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0, -0,16,64,0,0,0,0,49,185,225,8,244,56,153,37,180,242,71,104,139,35,8,217,192, -0,0,16,64,0,0,0,0,49,198,117,8,244,56,153,37,180,242,71,104,139,35,8,217, -192,0,0,16,64,0,0,0,0,49,186,1,8,244,56,153,37,180,242,71,104,139,35,8,217, -192,0,0,32,64,0,0,0,0,49,198,125,8,244,56,153,37,180,242,71,104,139,35,8, -217,192,0,0,32,64,0,0,0,0,32,232,130,0,97,57,162,4,245,72,10,68,184,70,137, -195,67,77,175,32,66,37,192,208,165,36,117,196,10,14,38,78,44,141,52,207, -169,64,56,156,199,130,36,160,141,146,52,38,32,76,72,1,246,136,235,103,177, -69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,171,37,20, -65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,158,142,183, -86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,246,136,235, -103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,37,20,138,46, -36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,75,161,37,20, -170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,39,208,146,138, -70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,129,89,58,18, -81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,17,214,207,161, -37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,207,161,37,22, -176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,207,98,155,75, -27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,78,209,29,108, -244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,146,155,76,25, -104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,104,142,182,122, -122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,146,155,69,25, -104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,217,233,233, -116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,162,137,147, -133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,77,156,109, -162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,117,179,234, -201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,162,100,226, -27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,59,22,53,91,0,2, -21,11,94,181,128,196,133,0,185,80,32,56,156,199,130,36,160,72,16,78,126,53, -144,5,146,208,34,82,72,1,109,20,76,155,40,32,233,0,115,70,130,8,209,56,104, -105,187,252,193,3,17,162,112,201,242,18,65,211,0,230,149,132,17,162,112, -208,211,119,248,0,82,130,96,95,127,128,130,80,102,186,36,232,92,206,255,1, -80,48,200,39,12,158,241,64, +18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,232,59, +147,60,93,110,79,15,39,9,24,186,33,13,63,111,185,16,211,206,251,114,98,17, +171,160,11,199,197,215,196,66,26,102,38,68,53,212,77,136,104,255,5,114,120, +121,7,192,70,32,192,67,95,249,59,13,13,127,228,248,134,191,242,133,208,215, +254,81,204,67,95,249,75,33,13,127,229,61,84,53,255,149,52,80,215,254,85, +217,67,95,249,91,121,13,90,181,168,134,143,152,95,38,75,207,132,104,156,50, +70,33,163,225,66,249,50,94,124,25,4,225,146,49,14,24,28,196,0,0,15,135,240, +0,0,0,12,204,0,0,15,7,240,0,0,0,12,188,72,6,176,77,225,28,24,103,14,33,197, +138,113,227,28,152,231,46,65,205,19,194,84,11,225,35,23,68,231,138,228,64, +211,19,132,140,93,19,162,59,145,33,73,18,52,68,225,35,23,68,233,139,228, +176,217,130,252,36,98,232,157,81,60,158,30,78,18,49,116,78,184,142,210,40, +39,99,23,68,236,201,59,114,142,224,126,14,138,152,30,67,188,23,143,139,175, +131,194,135,228,72,85,144,83,60,53,163,208,76,60,68,211,197,78,60,116,243, +200,80,60,149,19,202,82,60,181,51,204,84,60,213,83,206,86,60,240,190,76, +151,159,8,209,56,100,137,232,133,242,100,188,248,50,9,195,36,79,73,26,238, +108,129,15,4,100,78,33,179,207,160,41,224,140,137,194,173,192,158,120,128, +168,151,26,14,55,58,64,132,75,133,67,81,50,103,8,18,50,9,195,39,105,20,101, +136,36,50,9,195,39,105,20,11,174,99,220,210,54,121,114,4,145,162,112,201, +218,69,25,130,9,17,162,112,201,218,69,2,235,152,247,52,141,158,100,128,196, +144,128,242,102,136,17,70,146,66,3,201,160,32,0,130,225,48,113,137,62,62, +46,155,167,135,147,142,47,24,147,79,205,68,48,98,79,142,179,120,248,185, +228,140,241,193,146,66,138,31,55,71,126,129,51,18,124,117,155,199,197,207, +36,103,142,52,12,36,184,100,129,129,41,32,205,221,175,3,10,36,4,201,188,64, +112,200,84,52,156,124,92,242,70,120,223,48,64,100,42,26,78,62,46,121,35,52, +18,91,212,2,72,128,95,20,128,197,137,9,146,113,73,8,190,36,169,27,62,18, +243,35,100,135,54,92,66,4,34,92,145,0,178,15,132,64,132,75,133,139,178,70, +240,137,6,34,92,37,230,70,201,1,89,56,36,4,81,49,46,25,5,76,73,241,214,111, +31,23,60,145,158,57,44,48,46,92,184,100,160,145,46,2,0,201,168,207,198,230, +144,117,60,176,48,156,160,48,188,192,7,28,18,227,172,222,62,46,121,35,60, +113,200,26,137,113,241,116,221,60,60,156,113,121,4,20,124,92,242,70,120, +226,37,194,54,140,36,64,21,147,146,68,24,32,57,0,125,78,84,0,160,123,215, +140,146,1,4,5,175,40,124,8,20,52,121,51,228,24,96,129,209,46,2,49,6,20,135, +33,20,53,50,128,194,65,4,12,39,52,64,155,31,48,112,72,6,247,62,16,1,31,73, +30,25,240,60,73,82,70,68,138,0,89,29,5,156,96,2,201,104,17,35,160,18,78, +140,228,16,26,79,90,4,73,43,192,244,108,142,130,206,89,240,58,26,50,95,142, +43,159,65,107,4,167,196,52,100,191,28,87,63,128,15,255,240,164,169,35,136, +6,128,146,115,9,0,210,7,43,163,194,0,71,128,105,65,176,15,128,105,131,21, +11,153,35,0,211,134,137,7,65,18,33,244,23,18,14,130,39,34,131,30,113,15, +224,3,255,254,12,80,81,133,139,153,193,28,17,224,156,50,119,15,131,75,23, +51,130,112,201,199,185,13,159,116,248,228,68,219,66,149,83,83,238,3,11,238, +0,48,142,8,240,19,239,144,40,71,4,120,39,12,156,4,252,4,11,19,134,78,61, +200,108,248,9,248,9,3,9,205,16,39,225,62,7,67,70,75,241,197,241,154,5,172, +18,159,16,209,146,252,113,124,102,144,106,220,32,44,156,19,152,240,68,158, +66,2,176,19,17,252,164,7,137,30,176,8,158,116,3,72,128,136,143,232,32,44, +150,129,19,210,128,89,61,104,159,169,1,50,160,101,56,161,166,246,160,46, +110,226,221,98,71,130,4,137,222,0,140,221,197,184,64,89,56,183,88,145,224, +129,34,119,128,23,55,114,143,121,35,193,2,68,239,2,17,155,184,183,8,11,39, +40,247,146,60,16,36,78,240,32,73,197,12,247,128,26,36,121,1,63,49,2,165,48, +70,114,229,145,51,250,205,2,8,209,203,150,68,207,235,52,130,16,209,46,131, +36,188,70,128,210,160,101,56,251,16,131,28,7,35,38,218,50,234,103,130,97, +103,129,6,73,0,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,7,36,38,218,0, +0,0,0,0,0,0,0,4,29,78,224,140,38,216,140,46,228,0,243,119,10,139,144,123, +82,6,205,220,37,222,230,145,179,64,23,180,32,92,221,199,196,130,68,144,230, +237,200,131,44,24,43,193,25,18,185,0,251,73,138,199,240,27,93,106,192,57, +41,54,210,0,0,62,31,192,0,0,0,49,58,155,192,12,155,184,48,76,156,148,226, +134,154,240,32,201,187,147,67,9,201,78,40,105,175,2,225,47,3,18,155,184, +183,8,11,39,6,9,147,146,156,80,211,94,7,37,55,113,110,16,22,78,77,12,39,37, +56,161,166,188,16,48,215,130,14,30,240,66,213,93,35,11,124,0,230,36,249,52, +48,151,192,22,98,79,133,162,215,204,16,17,178,16,199,24,147,237,38,34,246, +139,95,48,64,70,200,68,16,98,79,140,115,102,123,33,20,89,137,62,210,98,103, +92,217,158,200,70,14,98,79,131,4,201,100,35,138,49,39,218,76,67,232,38,75, +33,32,49,137,62,12,24,178,18,68,152,147,237,38,33,244,24,178,18,132,24,147, +225,221,72,202,200,75,22,98,79,180,152,143,215,82,50,178,19,5,24,147,227, +16,218,76,146,178,19,70,152,147,237,38,38,117,13,164,201,43,33,56,81,137, +62,72,130,115,71,43,33,60,105,137,62,210,98,151,72,39,52,114,178,20,7,152, +147,227,16,181,162,68,19,154,57,89,10,36,140,73,246,147,19,58,133,173,18, +32,156,209,202,200,82,34,98,79,147,67,9,151,52,156,113,75,34,78,208,1,228, +73,242,104,97,46,16,62,68,159,24,133,173,18,32,156,209,202,217,83,37,34,79, +180,152,153,212,45,104,145,4,230,142,86,202,160,169,18,124,145,4,230,142, +86,215,213,27,34,79,180,152,165,210,9,205,28,173,175,172,42,68,159,24,134, +210,100,149,183,245,198,200,147,237,38,38,117,13,164,201,43,111,236,8,145, +39,195,186,145,149,185,246,69,200,147,237,38,35,245,212,140,173,207,180,30, +68,159,6,9,146,217,91,21,34,79,180,152,135,208,76,150,202,224,137,18,124, +99,155,51,219,95,116,92,137,62,210,98,103,92,217,158,218,251,194,228,73, +240,180,90,249,130,2,54,223,223,29,34,79,180,152,139,218,45,124,193,1,27, +111,240,33,204,73,243,4,4,108,134,8,60,137,62,96,128,141,178,193,193,154,3, +147,32,227,36,0,0,0,0,0,0,0,0,99,115,245,195,19,159,176,75,175,159,176,24, +172,253,129,49,121,251,2,176,66,92,130,235,16,18,100,148,251,36,106,123,64, +65,158,3,147,160,108,202,62,68,165,107,243,227,113,198,211,62,39,20,108, +115,226,241,130,106,113,224,78,162,4,242,130,236,197,60,37,64,190,18,49, +116,114,37,40,157,76,9,229,37,217,138,185,16,52,196,225,35,23,71,34,82,137, +213,64,158,84,93,152,187,145,33,73,18,52,68,225,35,23,71,34,82,137,213,192, +158,86,93,152,175,146,195,102,11,240,145,139,163,145,41,68,235,32,79,44,46, +204,83,201,225,228,225,35,23,71,34,82,137,214,192,158,90,93,152,163,180, +138,9,216,197,209,200,148,161,194,32,30,18,0,85,248,42,3,74,184,164,88,78, +173,186,58,16,44,90,192,144,5,149,109,110,193,245,109,210,128,132,93,204, +127,222,115,245,252,23,171,113,180,137,1,28,87,220,255,250,8,173,148,55,86, +227,104,232,18,3,222,94,217,248,119,41,48,168,46,189,16,62,200,66,80,6,11, +81,21,3,246,80,140,244,118,180,160,79,80,115,31,230,157,191,179,5,236,161, +25,233,64,158,160,246,63,205,59,127,102,41,248,30,75,12,11,151,242,233,187, +146,156,80,211,114,96,54,230,41,20,129,128,50,211,16,16,2,116,180,196,129, +1,36,55,76,74,16,19,3,116,196,193,65,48,55,75,80,128,65,6,51,211,20,128, +130,34,23,166,39,6,39,75,76,80,1,146,239,211,20,16,165,91,157,29,49,66,10, +124,61,211,209,175,1,173,198,211,20,48,139,113,180,180,197,36,42,220,109, +29,13,49,74,6,192,95,72,188,6,196,55,74,188,6,247,91,80,136,26,32,104,220, +205,56,1,98,234,52,122,98,136,14,72,110,152,162,132,148,35,61,49,70,7,48, +55,76,81,194,206,52,104,180,197,45,192,80,175,4,100,77,10,2,101,56,161,166, +65,113,162,98,8,3,131,7,169,35,36,57,176,16,40,116,208,0,0,0,0,45,158,10, +225,223,132,17,13,43,176,228,3,0,167,129,32,17,133,134,32,25,80,220,40,240, +25,26,44,32,240,24,200,44,24,240,56,156,199,128,83,193,17,7,4,13,128,0,10, +79,202,28,223,195,1,197,72,196,141,159,220,7,48,33,7,8,3,152,49,117,60,240, +76,47,60,9,224,187,56,43,224,221,64,172,156,36,98,232,228,96,220,145,139, +163,182,134,237,146,49,116,118,206,6,141,104,105,136,32,14,4,128,160,123, +215,140,147,32,145,57,178,156,104,41,228,151,168,225,144,168,105,56,248, +185,228,140,241,190,100,209,244,80,210,116,151,134,12,73,241,214,111,31,23, +60,145,158,56,50,72,81,67,230,232,239,209,7,24,147,227,226,233,186,120,121, +56,226,241,137,116,189,52,6,34,92,37,230,70,201,1,89,56,36,154,110,25,49, +23,196,149,35,103,194,94,100,108,144,230,203,136,73,174,234,63,52,252,212, +87,0,131,138,4,12,137,114,168,37,166,144,230,37,5,7,19,39,22,70,154,103, +143,252,4,11,37,160,68,164,139,7,24,3,152,182,20,28,76,156,89,26,105,158, +63,240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253,132,176,230, +36,248,134,207,98,138,99,4,24,147,229,16,217,236,81,75,98,12,73,241,13,158, +142,181,20,198,137,49,39,202,33,179,209,214,162,151,4,24,147,226,27,61,61, +42,41,142,18,98,79,148,67,103,167,165,69,46,138,49,39,194,173,192,158,158, +149,20,188,40,196,159,10,183,2,122,218,148,82,248,121,18,124,67,103,177,77, +177,130,36,73,242,136,108,246,41,181,177,18,36,248,134,207,71,90,155,99,68, +200,147,229,16,217,232,235,83,107,130,36,73,241,13,158,158,149,54,199,9, +145,39,202,33,179,211,210,166,215,69,72,147,225,86,224,79,79,74,155,94,21, +34,79,133,91,129,61,109,74,109,126,14,56,7,6,20,28,76,156,89,26,105,158,63, +240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253,130,235,191, +232,8,149,2,8,196,24,164,137,141,200,8,71,161,196,201,45,167,146,59,68,89, +24,70,206,0,0,7,129,248,0,0,0,1,142,49,232,71,161,196,201,45,167,146,59,68, +89,24,70,206,0,0,7,129,248,0,0,0,1,141,201,8,71,161,196,201,45,167,146,59, +68,89,24,70,206,0,0,7,129,248,0,0,0,2,138,2,214,225,113,235,2,27,128,0,10, +66,3,189,96,67,120,226,224,0,2,148,140,113,145,66,61,14,38,73,109,60,145, +218,34,200,194,54,112,0,0,60,15,192,0,0,0,12,110,80,66,61,14,38,73,109,60, +145,218,34,200,194,54,112,0,0,60,15,192,0,0,0,12,113,147,66,61,14,38,73, +109,60,145,218,34,200,194,54,112,0,0,60,15,192,0,0,0,12,110,88,66,61,14,38, +73,109,60,145,218,34,200,194,54,112,0,0,0,16,0,0,0,0,12,113,149,66,61,14, +38,73,109,60,145,218,34,200,194,54,112,0,0,0,16,0,0,0,0,12,110,96,66,61,14, +38,73,109,60,145,218,34,200,194,54,112,0,0,0,16,0,0,0,0,12,113,151,66,61, +14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,16,0,0,0,0,12,110,104,66, +61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0,0,0,12,113,153, +66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0,0,0,12,110, +112,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0,0,0,12, +113,155,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0,0,0, +12,110,120,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0,0, +0,12,113,157,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0, +0,0,12,110,128,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,8,16,0, +0,0,0,12,113,159,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,8,16, +0,0,0,0,8,58,32,128,24,78,104,129,61,82,2,145,46,17,162,112,208,211,107, +200,16,137,112,52,41,73,29,113,2,131,137,147,139,35,77,51,234,80,14,39,49, +224,137,40,35,100,141,9,136,19,18,0,125,162,58,217,236,81,64,68,72,1,241, +13,158,197,20,150,50,36,0,251,68,117,179,209,214,234,201,69,16,100,72,1, +246,136,235,103,163,173,208,146,138,68,23,18,0,124,67,103,163,173,213,146, +138,76,23,18,0,124,67,103,163,173,208,146,138,84,25,18,0,125,162,58,217, +233,233,117,100,162,138,50,36,0,251,68,117,179,211,210,232,73,69,34,139, +137,0,62,33,179,211,210,234,201,69,38,139,137,0,62,33,179,211,210,232,73, +69,42,139,137,0,62,21,110,4,250,178,81,70,23,18,0,124,42,220,9,244,36,162, +145,134,68,128,31,6,234,5,100,234,201,69,28,100,72,1,240,110,160,86,78,132, +148,82,56,168,144,3,237,17,214,207,171,37,22,128,42,36,0,251,68,117,179, +232,73,69,164,9,137,0,62,33,179,234,201,69,168,9,137,0,62,33,179,232,73,69, +172,10,180,81,50,118,136,235,103,177,77,129,54,138,38,78,33,179,216,166, +210,198,218,40,153,59,68,117,179,209,214,234,201,77,144,109,162,137,147, +180,71,91,61,29,110,132,148,218,32,203,69,19,39,16,217,232,235,117,100,166, +211,6,90,40,153,56,134,207,71,91,161,37,54,168,54,209,68,201,218,35,173, +158,158,151,86,74,108,163,109,20,76,157,162,58,217,233,233,116,36,166,209, +70,90,40,153,56,134,207,79,75,171,37,54,154,50,209,68,201,196,54,122,122, +93,9,41,181,81,150,138,38,78,21,110,4,250,178,83,102,25,104,162,100,225,86, +224,79,161,37,54,140,54,209,68,201,193,186,129,89,58,178,83,103,27,104,162, +100,224,221,64,172,157,9,41,180,113,118,138,38,78,209,29,108,250,178,83, +136,2,237,20,76,157,162,58,217,244,36,167,18,5,90,40,153,56,134,207,171,37, +56,160,42,209,68,201,196,54,125,9,41,197,141,78,197,141,86,192,0,133,66, +215,173,96,49,33,64,46,84,8,14,39,49,224,137,40,18,4,19,159,141,100,1,100, +180,8,148,146,0,91,69,19,38,202,8,58,64,28,209,160,130,52,78,26,26,110,255, +80,64,196,104,156,50,125,4,144,116,192,57,165,97,4,104,156,52,52,221,254, +64,20,160,152,23,223,228,32,148,25,174,137,58,23,51,191,200,84,12,50,9,195, +39,196,80, }; #else #error invalid endianness defines #endif #endif /* DUK_USE_ROM_OBJECTS */ + +/* automatic undefs */ +#undef DUK__REFCINIT /* * Error and fatal handling. */ @@ -10417,7 +10972,7 @@ #if defined(DUK_USE_VERBOSE_ERRORS) -DUK_INTERNAL void duk_err_handle_error_fmt(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *fmt, ...) { +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); @@ -10427,13 +10982,13 @@ va_end(ap); /* dead code, but ensures portability (see Linux man page notes) */ } -DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg) { +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 void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) { +DUK_INTERNAL DUK_COLD void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) { duk_err_create_and_throw(thr, code); } @@ -10445,41 +11000,41 @@ #if defined(DUK_USE_VERBOSE_ERRORS) #if defined(DUK_USE_PARANOID_ERRORS) -DUK_INTERNAL 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_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((duk_context *) thr, idx), (long) idx); } #else -DUK_INTERNAL 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_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((duk_context *) thr, idx), (long) idx); } #endif -DUK_INTERNAL void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 void duk_err_error_alloc_failed(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 void duk_err_error(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) { +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 void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *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 void duk_err_range_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx) { +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 void duk_err_range_push_beyond(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 void duk_err_type_invalid_args(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 void duk_err_type_invalid_state(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 void duk_err_type_invalid_trap_result(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 @@ -10491,25 +11046,25 @@ DUK_LOCAL void duk__err_shared(duk_hthread *thr, duk_uint_t code) { DUK_ERROR_RAW(thr, NULL, 0, code, NULL); } -DUK_INTERNAL void duk_err_error(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_error(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_ERROR); } -DUK_INTERNAL void duk_err_range(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_range(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_RANGE_ERROR); } -DUK_INTERNAL void duk_err_eval(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_eval(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_EVAL_ERROR); } -DUK_INTERNAL void duk_err_reference(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_reference(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_REFERENCE_ERROR); } -DUK_INTERNAL void duk_err_syntax(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_syntax(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_SYNTAX_ERROR); } -DUK_INTERNAL void duk_err_type(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_type(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_TYPE_ERROR); } -DUK_INTERNAL void duk_err_uri(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_uri(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_URI_ERROR); } #endif @@ -10518,7 +11073,7 @@ * Default fatal error handler */ -DUK_INTERNAL void duk_default_fatal_handler(void *udata, const char *msg) { +DUK_INTERNAL DUK_COLD void duk_default_fatal_handler(void *udata, const char *msg) { DUK_UNREF(udata); DUK_UNREF(msg); @@ -12132,86 +12687,6 @@ return (x > y ? x : y); } /* - * Round a number upwards to a prime (not usually the nearest one). - * - * Uses a table of successive 32-bit primes whose ratio is roughly - * constant. This keeps the relative upwards 'rounding error' bounded - * and the data size small. A simple 'predict-correct' compression is - * used to compress primes to one byte per prime. See genhashsizes.py - * for details. - * - * The minimum prime returned here must be coordinated with the possible - * probe sequence steps in duk_hobject and duk_heap stringtable. - */ - -/* #include duk_internal.h -> already included */ - -/* Awkward inclusion condition: drop out of compilation if not needed by any - * call site: object hash part or probing stringtable. - */ -#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE) - -/* hash size ratio goal, must match genhashsizes.py */ -#define DUK__HASH_SIZE_RATIO 1177 /* floor(1.15 * (1 << 10)) */ - -/* prediction corrections for prime list (see genhashsizes.py) */ -DUK_LOCAL const duk_int8_t duk__hash_size_corrections[] = { - 17, /* minimum prime */ - 4, 3, 4, 1, 4, 1, 1, 2, 2, 2, 2, 1, 6, 6, 9, 5, 1, 2, 2, 5, 1, 3, 3, 3, - 5, 4, 4, 2, 4, 8, 3, 4, 23, 2, 4, 7, 8, 11, 2, 12, 15, 10, 1, 1, 5, 1, 5, - 8, 9, 17, 14, 10, 7, 5, 2, 46, 21, 1, 9, 9, 4, 4, 10, 23, 36, 6, 20, 29, - 18, 6, 19, 21, 16, 11, 5, 5, 48, 9, 1, 39, 14, 8, 4, 29, 9, 1, 15, 48, 12, - 22, 6, 15, 27, 4, 2, 17, 28, 8, 9, 4, 5, 8, 3, 3, 8, 37, 11, 15, 8, 30, - 43, 6, 33, 41, 5, 20, 32, 41, 38, 24, 77, 14, 19, 11, 4, 35, 18, 19, 41, - 10, 23, 16, 9, 2, - -1 -}; - -/* probe steps (see genhashsizes.py), currently assumed to be 32 entries long - * (DUK_UTIL_GET_HASH_PROBE_STEP macro). - */ -DUK_INTERNAL duk_uint8_t duk_util_probe_steps[32] = { - 2, 3, 5, 7, 11, 13, 19, 31, 41, 47, 59, 67, 73, 79, 89, 101, 103, 107, - 109, 127, 137, 139, 149, 157, 163, 167, 173, 181, 191, 193, 197, 199 -}; - -DUK_INTERNAL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size) { - const duk_int8_t *p = duk__hash_size_corrections; - duk_uint32_t curr; - - curr = (duk_uint32_t) *p++; - for (;;) { - duk_small_int_t t = (duk_small_int_t) *p++; - if (t < 0) { - /* may happen if size is very close to 2^32-1 */ - break; - } - - /* prediction: portable variant using doubles if 64-bit values not available */ -#if defined(DUK_USE_64BIT_OPS) - curr = (duk_uint32_t) ((((duk_uint64_t) curr) * ((duk_uint64_t) DUK__HASH_SIZE_RATIO)) >> 10); -#else - /* 32-bit x 11-bit = 43-bit, fits accurately into a double */ - curr = (duk_uint32_t) DUK_FLOOR(((double) curr) * ((double) DUK__HASH_SIZE_RATIO) / 1024.0); -#endif - - /* correction */ - curr += t; - - DUK_DDD(DUK_DDDPRINT("size=%ld, curr=%ld", (long) size, (long) curr)); - - if (curr >= size) { - return curr; - } - } - return 0; -} - -#endif /* DUK_USE_HOBJECT_HASH_PART || DUK_USE_STRTAB_PROBE */ - -/* automatic undefs */ -#undef DUK__HASH_SIZE_RATIO -/* * Hobject Ecmascript [[Class]]. */ @@ -12728,6 +13203,7 @@ DUK_RAW_WRITE_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_WRITE_U32_BE(p, tmp32); /* Bytecode instructions: endian conversion needed unless @@ -12907,7 +13383,7 @@ 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_HAS_THREAD(&h_fun->obj)); + DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(&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)); @@ -13033,14 +13509,23 @@ * Must create a lexical environment on loading to allow * recursive functions like 'function foo() { foo(); }'. */ - duk_hobject *new_env; + duk_hdecenv *new_env; - new_env = duk_push_object_helper_proto(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), - func_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); - func_env = new_env; + DUK_ASSERT(new_env->thread == NULL); /* Closed. */ + DUK_ASSERT(new_env->varmap == NULL); + DUK_ASSERT(new_env->regbase == 0); + DUK_ASSERT_HDECENV_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(ctx, (duk_hobject *) new_env); duk_dup_m2(ctx); /* -> [ func funcname env funcname ] */ duk_dup(ctx, idx_base); /* -> [ func funcname env funcname func ] */ @@ -13097,8 +13582,9 @@ /* If _Formals wasn't present in the original function, the list * here will be empty. Same happens if _Formals was present but - * had zero length. We can omit _Formals from the result if its - * length is zero and matches nargs. + * had zero length. We'll omit the _Formals list if it is empty, + * regardless of whether it was present in the original or not, + * this is a workaround for https://github.com/svaarala/duktape/issues/1513. */ duk_push_array(ctx); /* _Formals */ for (arr_idx = 0; ; arr_idx++) { @@ -13110,7 +13596,16 @@ } duk_put_prop_index(ctx, -2, arr_idx); } - if (arr_idx == 0 && h_fun->nargs == 0) { + if (arr_idx == 0) { + /* Omitting _Formals when the list is empty is technically + * incorrect because the result will differ from the input + * function. This could matter for function templates if: + * _Formals exists, _Formals.length == 0, and nargs > 0. + * This doesn't happen in practice. But if it did, it would + * affect the .length property of function instances created + * from the closure (0 with _Formals present, nargs with + * _Formals absent). + */ duk_pop(ctx); } else { duk_compact_m1(ctx); @@ -13265,7 +13760,7 @@ DUK_ASSERT(thr != NULL); idx_func = duk_get_top(ctx) - nargs - 1; - if (idx_func < 0 || nargs < 0) { + if (DUK_UNLIKELY(idx_func < 0 || nargs < 0)) { /* note that we can't reliably pop anything here */ DUK_ERROR_TYPE_INVALID_ARGS(thr); } @@ -13292,7 +13787,7 @@ DUK_ASSERT(thr != NULL); idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */ - if (idx_func < 0 || nargs < 0) { + if (DUK_UNLIKELY(idx_func < 0 || nargs < 0)) { /* note that we can't reliably pop anything here */ DUK_ERROR_TYPE_INVALID_ARGS(thr); } @@ -13331,7 +13826,7 @@ DUK_ASSERT(thr != NULL); idx_func = duk_get_top(ctx) - nargs - 1; /* must work for nargs <= 0 */ - if (idx_func < 0 || nargs < 0) { + if (DUK_UNLIKELY(idx_func < 0 || nargs < 0)) { /* We can't reliably pop anything here because the stack input * shape is incorrect. So we throw an error; if the caller has * no catch point for this, a fatal error will occur. Another @@ -13369,7 +13864,7 @@ DUK_ASSERT(thr != NULL); idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */ - if (idx_func < 0 || nargs < 0) { + if (DUK_UNLIKELY(idx_func < 0 || nargs < 0)) { /* See comments in duk_pcall(). */ DUK_ERROR_TYPE_INVALID_ARGS(thr); return DUK_EXEC_ERROR; /* unreachable */ @@ -13409,6 +13904,7 @@ } DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t nargs) { + duk_hthread *thr = (duk_hthread *) ctx; duk__pcall_prop_args args; /* @@ -13420,6 +13916,10 @@ args.obj_idx = obj_idx; args.nargs = nargs; + if (DUK_UNLIKELY(nargs < 0)) { + DUK_ERROR_TYPE_INVALID_ARGS(thr); + return DUK_EXEC_ERROR; /* unreachable */ + } /* Inputs: explicit arguments (nargs), +1 for key. If the value stack * does not contain enough args, an error is thrown; this matches @@ -13435,7 +13935,7 @@ DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(thr != NULL); - if (duk_get_top(ctx) < nargs || nrets < 0) { + if (DUK_UNLIKELY(duk_get_top(ctx) < nargs || nargs < 0 || nrets < 0)) { /* See comments in duk_pcall(). */ DUK_ERROR_TYPE_INVALID_ARGS(thr); return DUK_EXEC_ERROR; /* unreachable */ @@ -13500,6 +14000,10 @@ /* [... constructor arg1 ... argN] */ + if (DUK_UNLIKELY(nargs < 0)) { + /* note that we can't reliably pop anything here */ + DUK_ERROR_TYPE_INVALID_ARGS(thr); + } idx_cons = duk_require_normalize_index(ctx, -nargs - 1); DUK_DDD(DUK_DDDPRINT("top=%ld, nargs=%ld, idx_cons=%ld", @@ -13669,6 +14173,7 @@ } DUK_EXTERNAL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs) { + duk_hthread *thr = (duk_hthread *) ctx; duk_int_t rc; DUK_ASSERT_CTX_VALID(ctx); @@ -13681,6 +14186,11 @@ * wrapper. */ + if (DUK_UNLIKELY(nargs < 0)) { + DUK_ERROR_TYPE_INVALID_ARGS(thr); + return DUK_EXEC_ERROR; /* unreachable */ + } + rc = duk_safe_call(ctx, duk__pnew_helper, (void *) &nargs /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/); return rc; } @@ -13693,9 +14203,11 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT_DISABLE(thr->callstack_top >= 0); - act = duk_hthread_get_current_activation(thr); - DUK_ASSERT(act != NULL); /* because callstack_top > 0 */ - return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0); + act = thr->callstack_curr; + if (act != NULL) { + return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0); + } + return 0; } /* XXX: Make this obsolete by adding a function flag for rejecting a @@ -13724,12 +14236,13 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT_DISABLE(thr->callstack_top >= 0); - act = duk_hthread_get_current_activation(thr); - if (act == NULL) { + act = thr->callstack_curr; + if (act != NULL) { + return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0); + } else { /* Strict by default. */ return 1; } - return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0); } /* @@ -13745,7 +14258,7 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT_DISABLE(thr->callstack_top >= 0); - act = duk_hthread_get_current_activation(thr); + act = thr->callstack_curr; if (act) { func = DUK_ACT_GET_FUNC(act); if (!func) { @@ -13849,7 +14362,10 @@ DUK_ASSERT(duk_is_valid_index(ctx, idx)); /* checked by caller */ - ptr = duk_get_buffer_data_raw(ctx, idx, out_len, 0 /*throw_flag*/, &isbuffer); + /* XXX: with def_ptr set to a stack related pointer, isbuffer could + * be removed from the helper? + */ + ptr = duk_get_buffer_data_raw(ctx, idx, out_len, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, &isbuffer); if (isbuffer) { DUK_ASSERT(*out_len == 0 || ptr != NULL); return (const duk_uint8_t *) ptr; @@ -14041,13 +14557,13 @@ t <<= 6; } else { DUK_ASSERT(x == -1); - goto error; + goto decode_error; } } else { DUK_ASSERT(x >= 0 && x <= 63); if (n_equal > 0) { /* Don't allow actual chars after equal sign. */ - goto error; + goto decode_error; } t = (t << 6) + x; } @@ -14073,7 +14589,7 @@ /* XX== */ dst -= 2; } else { - goto error; /* invalid padding */ + goto decode_error; /* invalid padding */ } /* Continue parsing after padding, allows concatenated, @@ -14097,13 +14613,13 @@ * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not * accepted. */ - goto error; + goto decode_error; } *out_dst_final = dst; return 1; - error: + decode_error: return 0; } #else /* DUK_USE_BASE64_FASTPATH */ @@ -14145,12 +14661,12 @@ /* allow basic ASCII whitespace */ continue; } else { - goto error; + goto decode_error; } if (n_equal > 0) { /* Don't allow mixed padding and actual chars. */ - goto error; + goto decode_error; } t = (t << 6) + y; skip_add: @@ -14169,7 +14685,7 @@ } else if (n_equal == 2) { dst -= 2; } else { - goto error; /* invalid padding */ + goto decode_error; /* invalid padding */ } /* Here we can choose either to end parsing and ignore @@ -14192,13 +14708,13 @@ * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not * accepted. */ - goto error; + goto decode_error; } *out_dst_final = dst; return 1; - error: + decode_error: return 0; } #endif /* DUK_USE_BASE64_FASTPATH */ @@ -14499,7 +15015,6 @@ /* Eval is just a wrapper now. */ DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) { - duk_uint_t comp_flags; duk_int_t rc; DUK_ASSERT_CTX_VALID(ctx); @@ -14513,9 +15028,7 @@ /* [ ... source? filename? ] (depends on flags) */ - comp_flags = flags; - comp_flags |= DUK_COMPILE_EVAL; - rc = duk_compile_raw(ctx, src_buffer, src_length, comp_flags); /* may be safe, or non-safe depending on flags */ + rc = duk_compile_raw(ctx, src_buffer, src_length, flags | DUK_COMPILE_EVAL); /* may be safe, or non-safe depending on flags */ /* [ ... closure/error ] */ @@ -14548,7 +15061,6 @@ duk_hthread *thr = (duk_hthread *) ctx; duk__compile_raw_args *comp_args; duk_uint_t flags; - duk_small_uint_t comp_flags; duk_hcompfunc *h_templ; DUK_ASSERT_CTX_VALID(ctx); @@ -14587,22 +15099,13 @@ } DUK_ASSERT(comp_args->src_buffer != NULL); - /* XXX: unnecessary translation of flags */ - comp_flags = 0; - if (flags & DUK_COMPILE_EVAL) { - comp_flags |= DUK_JS_COMPILE_FLAG_EVAL; - } if (flags & DUK_COMPILE_FUNCTION) { - comp_flags |= DUK_JS_COMPILE_FLAG_EVAL | - DUK_JS_COMPILE_FLAG_FUNCEXPR; - } - if (flags & DUK_COMPILE_STRICT) { - comp_flags |= DUK_JS_COMPILE_FLAG_STRICT; + flags |= DUK_COMPILE_EVAL | DUK_COMPILE_FUNCEXPR; } /* [ ... source? filename ] */ - duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, comp_flags); + duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, flags); /* [ ... source? func_template ] */ @@ -14755,16 +15258,16 @@ /* Start in paused state. */ heap->dbg_processing = 0; - DUK_HEAP_SET_DEBUGGER_PAUSED(heap); - heap->dbg_state_dirty = 1; + heap->dbg_state_dirty = 0; heap->dbg_force_restart = 0; - heap->dbg_step_type = 0; + heap->dbg_step_type = DUK_STEP_TYPE_NONE; heap->dbg_step_thread = NULL; heap->dbg_step_csindex = 0; heap->dbg_step_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. @@ -14804,7 +15307,7 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->heap != NULL); - if (!DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + if (!duk_debug_is_attached(thr->heap)) { return; } if (thr->callstack_top > 0 || thr->heap->dbg_processing) { @@ -14837,7 +15340,7 @@ DUK_ERROR_RANGE(thr, "not enough stack values for notify"); return ret; /* unreachable */ } - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + 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(ctx, idx); @@ -14850,7 +15353,7 @@ * a transport error was not indicated by the transport write * callback. This is not a 100% guarantee of course. */ - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + if (duk_debug_is_attached(thr->heap)) { ret = 1; } } @@ -14869,15 +15372,19 @@ DUK_D(DUK_DPRINT("application called duk_debugger_pause()")); /* Treat like a debugger statement: ignore when not attached. */ - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { - DUK_HEAP_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; + 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; + } } } @@ -14948,7 +15455,7 @@ struct duk_internal_thread_state { duk_ljstate lj; - duk_bool_t handling_error; + duk_bool_t creating_error; duk_hthread *curr_thread; duk_int_t call_recursion_depth; }; @@ -15029,14 +15536,27 @@ 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(ctx, &lj->value1); duk_push_tval(ctx, &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->handling_error = heap->handling_error; + snapshot->creating_error = heap->creating_error; snapshot->curr_thread = heap->curr_thread; snapshot->call_recursion_depth = heap->call_recursion_depth; @@ -15044,7 +15564,7 @@ lj->type = DUK_LJ_TYPE_UNKNOWN; DUK_TVAL_SET_UNDEFINED(&lj->value1); DUK_TVAL_SET_UNDEFINED(&lj->value2); - heap->handling_error = 0; + heap->creating_error = 0; heap->curr_thread = NULL; heap->call_recursion_depth = 0; } @@ -15059,10 +15579,16 @@ 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->handling_error = snapshot->handling_error; + heap->creating_error = snapshot->creating_error; heap->curr_thread = snapshot->curr_thread; heap->call_recursion_depth = snapshot->call_recursion_depth; @@ -15074,7 +15600,7 @@ duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h_glob; duk_hobject *h_prev_glob; - duk_hobject *h_env; + duk_hobjenv *h_env; duk_hobject *h_prev_env; DUK_D(DUK_DPRINT("replace global object with: %!T", duk_get_tval(ctx, -1))); @@ -15101,29 +15627,30 @@ * same (initial) built-ins. */ - h_env = duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV), - -1); /* no prototype, updated below */ + 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_dup_m2(ctx); - duk_dup_m3(ctx); - duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); + 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 new_env ] */ + /* [ ... new_glob ] */ h_prev_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; - thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_env; - DUK_HOBJECT_INCREF(thr, h_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 new_env ] */ + /* [ ... new_glob ] */ - duk_pop_2(ctx); + duk_pop(ctx); /* [ ... ] */ } @@ -15195,18 +15722,19 @@ DUK_UNREF(thr); - tv = duk_get_tval_or_unused(ctx, idx); - h = (DUK_TVAL_IS_HEAP_ALLOCATED(tv) ? DUK_TVAL_GET_HEAPHDR(tv) : NULL); - /* 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 */ - duk_push_bare_object(ctx); + tv = duk_get_tval_or_unused(ctx, 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_uint_t) DUK_TVAL_GET_TAG(tv); + duk_push_bare_object(ctx); /* Invalidates 'tv'. */ + tv = NULL; + if (h == NULL) { goto finish; } @@ -16181,9 +16709,31 @@ } DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t idx) { + duk_hobject *h; + duk_bool_t callable; + DUK_ASSERT_CTX_VALID(ctx); + h = duk_require_hobject(ctx, idx); /* Get before 'put' so that 'idx' is correct. */ + callable = duk_is_callable(ctx, -1); duk_put_prop_stridx(ctx, idx, DUK_STRIDX_INT_FINALIZER); + + /* In addition to setting the finalizer property, keep a "have + * finalizer" flag in duk_hobject in sync so that refzero can do + * a very quick finalizer check by walking the prototype chain + * and checking the flag alone. (Note that this means that just + * setting _Finalizer on an object won't affect finalizer checks.) + * + * NOTE: if the argument is a Proxy object, this flag will be set + * on the Proxy, not the target. As a result, the target won't get + * a finalizer flag and the Proxy also won't be finalized as there's + * an explicit Proxy check in finalization now. + */ + if (callable) { + DUK_HOBJECT_SET_HAVE_FINALIZER(h); + } else { + DUK_HOBJECT_CLEAR_HAVE_FINALIZER(h); + } } #else /* DUK_USE_FINALIZER_SUPPORT */ DUK_EXTERNAL void duk_get_finalizer(duk_context *ctx, duk_idx_t idx) { @@ -16276,7 +16826,7 @@ DUK_LOCAL_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t idx, duk_uint_t tag); -DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t idx, duk_bool_t require) { +DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t idx, duk_int_t def_value, duk_bool_t require) { duk_hthread *thr; duk_tval *tv; duk_small_int_t c; @@ -16336,10 +16886,11 @@ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); /* not reachable */ } - return 0; + + return def_value; } -DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t idx, duk_bool_t require) { +DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value, duk_bool_t require) { duk_hthread *thr; duk_tval *tv; duk_small_int_t c; @@ -16389,7 +16940,8 @@ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); /* not reachable */ } - return 0; + + return def_value; } /* @@ -16556,7 +17108,7 @@ DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(DUK_INVALID_INDEX < 0); - if (duk_normalize_index(ctx, idx) < 0) { + if (DUK_UNLIKELY(duk_normalize_index(ctx, idx) < 0)) { DUK_ERROR_RANGE_INDEX(thr, idx); return; /* unreachable */ } @@ -16584,7 +17136,7 @@ DUK_ASSERT_CTX_VALID(ctx); ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); - if (ret < min_top) { + if (DUK_UNLIKELY(ret < min_top)) { DUK_ERROR_TYPE_INVALID_ARGS(thr); } return ret; @@ -16796,7 +17348,7 @@ new_alloc_size = sizeof(duk_tval) * new_size; new_valstack = (duk_tval *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_valstack_ptr, (void *) thr, new_alloc_size); - if (!new_valstack) { + if (DUK_UNLIKELY(new_valstack == NULL)) { /* Because new_size != 0, if condition doesn't need to be * (new_valstack != NULL || new_size == 0). */ @@ -16886,26 +17438,16 @@ return 1; } -DUK_INTERNAL -duk_bool_t duk_valstack_resize_raw(duk_context *ctx, - duk_size_t min_new_size, - duk_small_uint_t flags) { +DUK_LOCAL DUK_COLD DUK_NOINLINE duk_bool_t duk__valstack_do_resize(duk_context *ctx, + duk_size_t min_new_size, + duk_small_uint_t flags) { duk_hthread *thr = (duk_hthread *) ctx; duk_size_t old_size; duk_size_t new_size; - duk_bool_t is_shrink = 0; - duk_small_uint_t shrink_flag = (flags & DUK_VSRESIZE_FLAG_SHRINK); + duk_bool_t is_shrink; duk_small_uint_t compact_flag = (flags & DUK_VSRESIZE_FLAG_COMPACT); duk_small_uint_t throw_flag = (flags & DUK_VSRESIZE_FLAG_THROW); - DUK_DDD(DUK_DDDPRINT("check valstack resize: min_new_size=%lu, curr_size=%ld, curr_top=%ld, " - "curr_bottom=%ld, shrink=%d, compact=%d, throw=%d", - (unsigned long) min_new_size, - (long) (thr->valstack_end - thr->valstack), - (long) (thr->valstack_top - thr->valstack), - (long) (thr->valstack_bottom - thr->valstack), - (int) shrink_flag, (int) compact_flag, (int) throw_flag)); - DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->valstack_bottom >= thr->valstack); @@ -16921,11 +17463,8 @@ if (min_new_size <= old_size) { is_shrink = 1; - if (!shrink_flag || - old_size - min_new_size < DUK_VALSTACK_SHRINK_THRESHOLD) { - DUK_DDD(DUK_DDDPRINT("no need to grow or shrink valstack")); - return 1; - } + } else { + is_shrink = 0; } new_size = min_new_size; @@ -16944,7 +17483,7 @@ (unsigned long) old_size, (unsigned long) new_size, (unsigned long) min_new_size)); - if (new_size > thr->valstack_max) { + if (DUK_UNLIKELY(new_size > thr->valstack_max)) { /* Note: may be triggered even if minimal new_size would not reach the limit, * plan limit accordingly (taking DUK_VALSTACK_GROW_STEP into account). */ @@ -16967,7 +17506,7 @@ * size_t and pointer arithmetic won't wrap in duk__resize_valstack(). */ - if (!duk__resize_valstack(ctx, new_size)) { + if (DUK_UNLIKELY(!duk__resize_valstack(ctx, new_size))) { if (is_shrink) { DUK_DD(DUK_DDPRINT("valstack resize failed, but is a shrink, ignore")); return 1; @@ -16986,15 +17525,53 @@ return 1; } -DUK_EXTERNAL duk_bool_t duk_check_stack(duk_context *ctx, duk_idx_t extra) { +DUK_INTERNAL duk_bool_t duk_valstack_resize_raw(duk_context *ctx, + duk_size_t min_new_size, + duk_small_uint_t flags) { duk_hthread *thr = (duk_hthread *) ctx; - duk_size_t min_new_size; - - DUK_ASSERT_CTX_VALID(ctx); - DUK_ASSERT(thr != NULL); + duk_size_t old_size; - if (DUK_UNLIKELY(extra < 0)) { - /* Clamping to zero makes the API more robust to calling code + DUK_DDD(DUK_DDDPRINT("check valstack resize: min_new_size=%lu, curr_size=%ld, curr_top=%ld, " + "curr_bottom=%ld, flags=%lx", + (unsigned long) min_new_size, + (long) (thr->valstack_end - thr->valstack), + (long) (thr->valstack_top - thr->valstack), + (long) (thr->valstack_bottom - thr->valstack), + (unsigned long) flags)); + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + DUK_ASSERT(thr->valstack_bottom >= thr->valstack); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT(thr->valstack_end >= thr->valstack_top); + +#if defined(DUK_USE_PREFER_SIZE) + old_size = (duk_size_t) (thr->valstack_end - thr->valstack); +#else + DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size); + old_size = thr->valstack_size; +#endif + + if (DUK_LIKELY(min_new_size <= old_size)) { + if (DUK_LIKELY((flags & DUK_VSRESIZE_FLAG_SHRINK) == 0 || + old_size - min_new_size < DUK_VALSTACK_SHRINK_THRESHOLD)) { + DUK_DDD(DUK_DDDPRINT("no need to grow or shrink valstack")); + return 1; + } + } + + return duk__valstack_do_resize(ctx, min_new_size, flags); +} + +DUK_EXTERNAL duk_bool_t duk_check_stack(duk_context *ctx, duk_idx_t extra) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_size_t min_new_size; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + + if (DUK_UNLIKELY(extra < 0)) { + /* Clamping to zero makes the API more robust to calling code * calculation errors. */ extra = 0; @@ -17031,9 +17608,11 @@ } DUK_EXTERNAL duk_bool_t duk_check_stack_top(duk_context *ctx, duk_idx_t top) { + duk_hthread *thr; duk_size_t min_new_size; DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; if (DUK_UNLIKELY(top < 0)) { /* Clamping to zero makes the API more robust to calling code @@ -17042,7 +17621,7 @@ top = 0; } - min_new_size = top + DUK_VALSTACK_INTERNAL_EXTRA; + min_new_size = (thr->valstack_bottom - thr->valstack) + top + DUK_VALSTACK_INTERNAL_EXTRA; return duk_valstack_resize_raw(ctx, min_new_size, /* min_new_size */ 0 /* no shrink */ | /* flags */ @@ -17051,9 +17630,11 @@ } DUK_EXTERNAL void duk_require_stack_top(duk_context *ctx, duk_idx_t top) { + duk_hthread *thr; duk_size_t min_new_size; DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; if (DUK_UNLIKELY(top < 0)) { /* Clamping to zero makes the API more robust to calling code @@ -17062,7 +17643,7 @@ top = 0; } - min_new_size = top + DUK_VALSTACK_INTERNAL_EXTRA; + min_new_size = (thr->valstack_bottom - thr->valstack) + top + DUK_VALSTACK_INTERNAL_EXTRA; (void) duk_valstack_resize_raw(ctx, min_new_size, /* min_new_size */ 0 /* no shrink */ | /* flags */ @@ -17127,7 +17708,7 @@ thr = (duk_hthread *) ctx; DUK__CHECK_SPACE(); - if (thr->valstack_top - thr->valstack_bottom <= 0) { + if (DUK_UNLIKELY(thr->valstack_top - thr->valstack_bottom <= 0)) { DUK_ERROR_RANGE_INDEX(thr, -1); return; /* unreachable */ } @@ -17302,27 +17883,27 @@ DUK_ASSERT(to_ctx != NULL); DUK_ASSERT(from_ctx != NULL); - if (to_ctx == from_ctx) { + if (DUK_UNLIKELY(to_ctx == from_ctx)) { DUK_ERROR_TYPE(to_thr, DUK_STR_INVALID_CONTEXT); return; } - if ((count < 0) || - (count > (duk_idx_t) to_thr->valstack_max)) { + if (DUK_UNLIKELY((count < 0) || + (count > (duk_idx_t) to_thr->valstack_max))) { /* Maximum value check ensures 'nbytes' won't wrap below. */ DUK_ERROR_RANGE_INVALID_COUNT(to_thr); return; } nbytes = sizeof(duk_tval) * count; - if (nbytes == 0) { + if (DUK_UNLIKELY(nbytes == 0)) { return; } DUK_ASSERT(to_thr->valstack_top <= to_thr->valstack_end); - if ((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes) { + if (DUK_UNLIKELY((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes)) { DUK_ERROR_RANGE_PUSH_BEYOND(to_thr); } src = (void *) ((duk_uint8_t *) from_thr->valstack_top - nbytes); - if (src < (void *) from_thr->valstack_bottom) { + if (DUK_UNLIKELY(src < (void *) from_thr->valstack_bottom)) { DUK_ERROR_RANGE_INVALID_COUNT(to_thr); } @@ -17357,7 +17938,7 @@ } /* - * Get/require + * Get/opt/require */ DUK_EXTERNAL void duk_require_undefined(duk_context *ctx, duk_idx_t idx) { @@ -17368,7 +17949,7 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_UNDEFINED(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_UNDEFINED(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "undefined", DUK_STR_NOT_UNDEFINED); } } @@ -17381,13 +17962,13 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_NULL(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_NULL(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "null", DUK_STR_NOT_NULL); } } -DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t idx) { - duk_bool_t ret = 0; /* default: false */ +DUK_LOCAL DUK_ALWAYS_INLINE duk_bool_t duk__get_boolean_raw(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value) { + duk_bool_t ret; duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); @@ -17396,12 +17977,27 @@ DUK_ASSERT(tv != NULL); if (DUK_TVAL_IS_BOOLEAN(tv)) { ret = DUK_TVAL_GET_BOOLEAN(tv); + DUK_ASSERT(ret == 0 || ret == 1); + } else { + ret = def_value; + /* Not guaranteed to be 0 or 1. */ } - DUK_ASSERT(ret == 0 || ret == 1); return ret; } +DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t idx) { + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_boolean_raw(ctx, idx, 0); /* default: false */ +} + +DUK_EXTERNAL duk_bool_t duk_get_boolean_default(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_boolean_raw(ctx, idx, def_value); +} + DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -17411,35 +18007,61 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_BOOLEAN(tv)) { + if (DUK_LIKELY(DUK_TVAL_IS_BOOLEAN(tv))) { + ret = DUK_TVAL_GET_BOOLEAN(tv); + DUK_ASSERT(ret == 0 || ret == 1); + return ret; + } else { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "boolean", DUK_STR_NOT_BOOLEAN); } - ret = DUK_TVAL_GET_BOOLEAN(tv); - DUK_ASSERT(ret == 0 || ret == 1); - return ret; } -DUK_EXTERNAL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t idx) { +DUK_EXTERNAL duk_bool_t duk_opt_boolean(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_boolean(ctx, idx); +} + +DUK_LOCAL DUK_ALWAYS_INLINE duk_double_t duk__get_number_raw(duk_context *ctx, duk_idx_t idx, duk_double_t def_value) { duk_double_union ret; duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); - ret.d = DUK_DOUBLE_NAN; /* default: NaN */ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (DUK_TVAL_IS_NUMBER(tv)) { - ret.d = DUK_TVAL_GET_NUMBER(tv); +#if defined(DUK_USE_FASTINT) + if (DUK_TVAL_IS_FASTINT(tv)) { + ret.d = (duk_double_t) DUK_TVAL_GET_FASTINT(tv); /* XXX: cast trick */ + } + else +#endif + if (DUK_TVAL_IS_DOUBLE(tv)) { + /* When using packed duk_tval, number must be in NaN-normalized form + * for it to be a duk_tval, so no need to normalize. NOP for unpacked + * duk_tval. + */ + ret.d = DUK_TVAL_GET_DOUBLE(tv); + DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret)); + } else { + ret.d = def_value; + /* Default value (including NaN) may not be normalized. */ } - /* When using packed duk_tval, number must be in NaN-normalized form - * for it to be a duk_tval, so no need to normalize. NOP for unpacked - * duk_tval. - */ - DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret)); return ret.d; } +DUK_EXTERNAL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t idx) { + return duk__get_number_raw(ctx, idx, DUK_DOUBLE_NAN); /* default: NaN */ +} + +DUK_EXTERNAL duk_double_t duk_get_number_default(duk_context *ctx, duk_idx_t idx, duk_double_t def_value) { + return duk__get_number_raw(ctx, idx, def_value); +} + DUK_EXTERNAL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -17449,7 +18071,7 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_NUMBER(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_NUMBER(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); } @@ -17463,56 +18085,89 @@ return ret.d; } +DUK_EXTERNAL duk_double_t duk_opt_number(duk_context *ctx, duk_idx_t idx, duk_double_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + /* User provided default is not NaN normalized. */ + return def_value; + } + return duk_require_number(ctx, idx); +} + DUK_EXTERNAL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t idx) { - /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*require*/); + + return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*def_value*/, 0 /*require*/); } DUK_EXTERNAL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t idx) { - /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*require*/); + + return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*def_value*/, 0 /*require*/); +} + +DUK_EXTERNAL duk_int_t duk_get_int_default(duk_context *ctx, duk_idx_t idx, duk_int_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + return (duk_int_t) duk__api_coerce_d2i(ctx, idx, def_value, 0 /*require*/); +} + +DUK_EXTERNAL duk_uint_t duk_get_uint_default(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, def_value, 0 /*require*/); } DUK_EXTERNAL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t idx) { - /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 1 /*require*/); + + return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*def_value*/, 1 /*require*/); } DUK_EXTERNAL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t idx) { - /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 1 /*require*/); + + return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*def_value*/, 1 /*require*/); } -DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) { - const char *ret; - duk_tval *tv; +DUK_EXTERNAL duk_int_t duk_opt_int(duk_context *ctx, duk_idx_t idx, duk_int_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_int(ctx, idx); +} + +DUK_EXTERNAL duk_uint_t duk_opt_uint(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value) { DUK_ASSERT_CTX_VALID(ctx); - /* default: NULL, length 0 */ - ret = NULL; - if (out_len) { - *out_len = 0; + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; } + return duk_require_uint(ctx, idx); +} - tv = duk_get_tval_or_unused(ctx, idx); - DUK_ASSERT(tv != NULL); - if (DUK_TVAL_IS_STRING(tv)) { - /* Here we rely on duk_hstring instances always being zero - * terminated even if the actual string is not. - */ - duk_hstring *h = DUK_TVAL_GET_STRING(tv); - DUK_ASSERT(h != NULL); +DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) { + duk_hstring *h; + const char *ret; + duk_size_t len; + + DUK_ASSERT_CTX_VALID(ctx); + + h = duk_get_hstring(ctx, idx); + if (h != NULL) { + len = DUK_HSTRING_GET_BYTELEN(h); ret = (const char *) DUK_HSTRING_GET_DATA(h); - if (out_len) { - *out_len = DUK_HSTRING_GET_BYTELEN(h); - } + } else { + len = 0; + ret = NULL; } + if (out_len != NULL) { + *out_len = len; + } return ret; } @@ -17543,9 +18198,72 @@ } DUK_EXTERNAL const char *duk_get_string(duk_context *ctx, duk_idx_t idx) { + duk_hstring *h; + + DUK_ASSERT_CTX_VALID(ctx); + + h = duk_get_hstring(ctx, idx); + if (h != NULL) { + return (const char *) DUK_HSTRING_GET_DATA(h); + } else { + return NULL; + } +} + +DUK_EXTERNAL const char *duk_opt_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + if (out_len != NULL) { + *out_len = def_len; + } + return def_ptr; + } + return duk_require_lstring(ctx, idx, out_len); +} + +DUK_EXTERNAL const char *duk_opt_string(duk_context *ctx, duk_idx_t idx, const char *def_ptr) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_ptr; + } + return duk_require_string(ctx, idx); +} + +DUK_EXTERNAL const char *duk_get_lstring_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) { + duk_hstring *h; + const char *ret; + duk_size_t len; + + DUK_ASSERT_CTX_VALID(ctx); + + h = duk_get_hstring(ctx, idx); + if (h != NULL) { + len = DUK_HSTRING_GET_BYTELEN(h); + ret = (const char *) DUK_HSTRING_GET_DATA(h); + } else { + len = def_len; + ret = def_ptr; + } + + if (out_len != NULL) { + *out_len = len; + } + return ret; +} + +DUK_EXTERNAL const char *duk_get_string_default(duk_context *ctx, duk_idx_t idx, const char *def_value) { + duk_hstring *h; + DUK_ASSERT_CTX_VALID(ctx); - return duk_get_lstring(ctx, idx, NULL); + h = duk_get_hstring(ctx, idx); + if (h != NULL) { + return (const char *) DUK_HSTRING_GET_DATA(h); + } else { + return def_value; + } } DUK_INTERNAL const char *duk_get_string_notsymbol(duk_context *ctx, duk_idx_t idx) { @@ -17577,7 +18295,7 @@ return (const char *) DUK_HSTRING_GET_DATA(h); } -DUK_EXTERNAL void *duk_get_pointer(duk_context *ctx, duk_idx_t idx) { +DUK_LOCAL void *duk__get_pointer_raw(duk_context *ctx, duk_idx_t idx, void *def_value) { duk_tval *tv; void *p; @@ -17586,13 +18304,30 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); if (!DUK_TVAL_IS_POINTER(tv)) { - return NULL; + return def_value; } p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */ return p; } +DUK_EXTERNAL void *duk_get_pointer(duk_context *ctx, duk_idx_t idx) { + return duk__get_pointer_raw(ctx, idx, NULL /*def_value*/); +} + +DUK_EXTERNAL void *duk_opt_pointer(duk_context *ctx, duk_idx_t idx, void *def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_pointer(ctx, idx); +} + +DUK_EXTERNAL void *duk_get_pointer_default(duk_context *ctx, duk_idx_t idx, void *def_value) { + return duk__get_pointer_raw(ctx, idx, def_value); +} + DUK_EXTERNAL void *duk_require_pointer(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -17605,7 +18340,7 @@ */ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_POINTER(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_POINTER(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "pointer", DUK_STR_NOT_POINTER); } p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */ @@ -17631,10 +18366,12 @@ } #endif -DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_bool_t throw_flag) { +DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag) { duk_hthread *thr = (duk_hthread *) ctx; - duk_tval *tv; duk_hbuffer *h; + void *ret; + duk_size_t len; + duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); DUK_UNREF(thr); @@ -17645,27 +18382,54 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_BUFFER(tv)) { + if (DUK_LIKELY(DUK_TVAL_IS_BUFFER(tv))) { + h = DUK_TVAL_GET_BUFFER(tv); + DUK_ASSERT(h != NULL); + + len = DUK_HBUFFER_GET_SIZE(h); + ret = DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); + } else { if (throw_flag) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER); } - return NULL; + len = def_size; + ret = def_ptr; } - h = DUK_TVAL_GET_BUFFER(tv); - DUK_ASSERT(h != NULL); - if (out_size) { - *out_size = DUK_HBUFFER_GET_SIZE(h); + if (out_size != NULL) { + *out_size = len; } - return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */ + return ret; } DUK_EXTERNAL void *duk_get_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { - return duk__get_buffer_helper(ctx, idx, out_size, 0 /*throw_flag*/); + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_buffer_helper(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/); +} + +DUK_EXTERNAL void *duk_opt_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + if (out_size != NULL) { + *out_size = def_size; + } + return def_ptr; + } + return duk_require_buffer(ctx, idx, out_size); +} + +DUK_EXTERNAL void *duk_get_buffer_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len) { + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_buffer_helper(ctx, idx, out_size, def_ptr, def_len, 0 /*throw_flag*/); } DUK_EXTERNAL void *duk_require_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { - return duk__get_buffer_helper(ctx, idx, out_size, 1 /*throw_flag*/); + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_buffer_helper(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/); } /* Get the active buffer data area for a plain buffer or a buffer object. @@ -17673,7 +18437,7 @@ * have a NULL data pointer when its size is zero, the optional 'out_isbuffer' * argument allows caller to detect this reliably. */ -DUK_INTERNAL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_bool_t throw_flag, duk_bool_t *out_isbuffer) { +DUK_INTERNAL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag, duk_bool_t *out_isbuffer) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -17684,7 +18448,7 @@ *out_isbuffer = 0; } if (out_size != NULL) { - *out_size = 0; + *out_size = def_size; } tv = duk_get_tval_or_unused(ctx, idx); @@ -17733,15 +18497,31 @@ if (throw_flag) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER); } - return NULL; + return def_ptr; } DUK_EXTERNAL void *duk_get_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { - return duk_get_buffer_data_raw(ctx, idx, out_size, 0 /*throw_flag*/, NULL); + return duk_get_buffer_data_raw(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, NULL); +} + +DUK_EXTERNAL void *duk_get_buffer_data_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) { + return duk_get_buffer_data_raw(ctx, idx, out_size, def_ptr, def_size, 0 /*throw_flag*/, NULL); +} + +DUK_EXTERNAL void *duk_opt_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + if (out_size != NULL) { + *out_size = def_size; + } + return def_ptr; + } + return duk_require_buffer_data(ctx, idx, out_size); } DUK_EXTERNAL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { - return duk_get_buffer_data_raw(ctx, idx, out_size, 1 /*throw_flag*/, NULL); + return duk_get_buffer_data_raw(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/, NULL); } /* Raw helper for getting a value from the stack, checking its tag. @@ -17773,7 +18553,7 @@ DUK_INTERNAL duk_hstring *duk_get_hstring_notsymbol(duk_context *ctx, duk_idx_t idx) { duk_hstring *res = (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING); - if (res && DUK_HSTRING_HAS_SYMBOL(res)) { + if (DUK_UNLIKELY(res && DUK_HSTRING_HAS_SYMBOL(res))) { return NULL; } return res; @@ -17782,7 +18562,7 @@ DUK_INTERNAL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t idx) { duk_hstring *h; h = (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING); - if (h == NULL) { + if (DUK_UNLIKELY(h == NULL)) { DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "string", DUK_STR_NOT_STRING); } return h; @@ -17791,7 +18571,7 @@ DUK_INTERNAL duk_hstring *duk_require_hstring_notsymbol(duk_context *ctx, duk_idx_t idx) { duk_hstring *h; h = (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING); - if (h == NULL || DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(h == NULL || DUK_HSTRING_HAS_SYMBOL(h))) { DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "string", DUK_STR_NOT_STRING); } return h; @@ -17804,7 +18584,7 @@ DUK_INTERNAL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t idx) { duk_hobject *h; h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (h == NULL) { + if (DUK_UNLIKELY(h == NULL)) { DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "object", DUK_STR_NOT_OBJECT); } return h; @@ -17817,7 +18597,7 @@ DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t idx) { duk_hbuffer *h; h = (duk_hbuffer *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_BUFFER); - if (h == NULL) { + if (DUK_UNLIKELY(h == NULL)) { DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "buffer", DUK_STR_NOT_BUFFER); } return h; @@ -17825,7 +18605,7 @@ DUK_INTERNAL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t idx) { duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (h != NULL && !DUK_HOBJECT_IS_THREAD(h)) { + if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_THREAD(h))) { h = NULL; } return (duk_hthread *) h; @@ -17834,7 +18614,7 @@ DUK_INTERNAL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (!(h != NULL && DUK_HOBJECT_IS_THREAD(h))) { + if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_THREAD(h)))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "thread", DUK_STR_NOT_THREAD); } return (duk_hthread *) h; @@ -17842,7 +18622,7 @@ DUK_INTERNAL duk_hcompfunc *duk_get_hcompfunc(duk_context *ctx, duk_idx_t idx) { duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (h != NULL && !DUK_HOBJECT_IS_COMPFUNC(h)) { + if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_COMPFUNC(h))) { h = NULL; } return (duk_hcompfunc *) h; @@ -17851,7 +18631,7 @@ DUK_INTERNAL duk_hcompfunc *duk_require_hcompfunc(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (!(h != NULL && DUK_HOBJECT_IS_COMPFUNC(h))) { + if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_COMPFUNC(h)))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "compiledfunction", DUK_STR_NOT_COMPFUNC); } return (duk_hcompfunc *) h; @@ -17859,7 +18639,7 @@ DUK_INTERNAL duk_hnatfunc *duk_get_hnatfunc(duk_context *ctx, duk_idx_t idx) { duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (h != NULL && !DUK_HOBJECT_IS_NATFUNC(h)) { + if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_NATFUNC(h))) { h = NULL; } return (duk_hnatfunc *) h; @@ -17868,7 +18648,7 @@ DUK_INTERNAL duk_hnatfunc *duk_require_hnatfunc(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (!(h != NULL && DUK_HOBJECT_IS_NATFUNC(h))) { + if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_NATFUNC(h)))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC); } return (duk_hnatfunc *) h; @@ -17883,13 +18663,13 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_OBJECT(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_OBJECT(tv))) { return NULL; } h = DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(h != NULL); - if (!DUK_HOBJECT_IS_NATFUNC(h)) { + if (DUK_UNLIKELY(!DUK_HOBJECT_IS_NATFUNC(h))) { return NULL; } DUK_ASSERT(DUK_HOBJECT_HAS_NATFUNC(h)); @@ -17898,6 +18678,28 @@ return f->func; } +DUK_EXTERNAL duk_c_function duk_opt_c_function(duk_context *ctx, duk_idx_t idx, duk_c_function def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_c_function(ctx, idx); +} + +DUK_EXTERNAL duk_c_function duk_get_c_function_default(duk_context *ctx, duk_idx_t idx, duk_c_function def_value) { + duk_c_function ret; + + DUK_ASSERT_CTX_VALID(ctx); + + ret = duk_get_c_function(ctx, idx); + if (ret != NULL) { + return ret; + } + + return def_value; +} + DUK_EXTERNAL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_c_function ret; @@ -17905,14 +18707,14 @@ DUK_ASSERT_CTX_VALID(ctx); ret = duk_get_c_function(ctx, idx); - if (!ret) { + if (DUK_UNLIKELY(!ret)) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC); } return ret; } DUK_EXTERNAL void duk_require_function(duk_context *ctx, duk_idx_t idx) { - if (!duk_is_function(ctx, idx)) { + if (DUK_UNLIKELY(!duk_is_function(ctx, idx))) { DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, idx, "function", DUK_STR_NOT_FUNCTION); } } @@ -17921,7 +18723,7 @@ duk_hobject *h; h = duk_require_hobject_accept_mask(ctx, idx, DUK_TYPE_MASK_LIGHTFUNC); - if (h != NULL && !DUK_HOBJECT_HAS_CONSTRUCTABLE(h)) { + if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_HAS_CONSTRUCTABLE(h))) { DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, idx, "constructable", DUK_STR_NOT_CONSTRUCTABLE); } /* Lightfuncs (h == NULL) are constructable. */ @@ -17939,6 +18741,28 @@ return (duk_context *) duk_require_hthread(ctx, idx); } +DUK_EXTERNAL duk_context *duk_opt_context(duk_context *ctx, duk_idx_t idx, duk_context *def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_context(ctx, idx); +} + +DUK_EXTERNAL_DECL duk_context *duk_get_context_default(duk_context *ctx, duk_idx_t idx, duk_context *def_value) { + duk_context *ret; + + DUK_ASSERT_CTX_VALID(ctx); + + ret = duk_get_context(ctx, idx); + if (ret != NULL) { + return ret; + } + + return def_value; +} + DUK_EXTERNAL void *duk_get_heapptr(duk_context *ctx, duk_idx_t idx) { duk_tval *tv; void *ret; @@ -17947,7 +18771,7 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) { return (void *) NULL; } @@ -17956,6 +18780,28 @@ return ret; } +DUK_EXTERNAL void *duk_opt_heapptr(duk_context *ctx, duk_idx_t idx, void *def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_heapptr(ctx, idx); +} + +DUK_EXTERNAL_DECL void *duk_get_heapptr_default(duk_context *ctx, duk_idx_t idx, void *def_value) { + void *ret; + + DUK_ASSERT_CTX_VALID(ctx); + + ret = duk_get_heapptr(ctx, idx); + if (ret != NULL) { + return ret; + } + + return def_value; +} + DUK_EXTERNAL void *duk_require_heapptr(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -17965,7 +18811,7 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "heapobject", DUK_STR_UNEXPECTED_TYPE); } @@ -17982,7 +18828,7 @@ DUK_ASSERT_CTX_VALID(ctx); res = duk_get_hobject(ctx, idx); /* common case, not promoted */ - if (res != NULL) { + if (DUK_LIKELY(res != NULL)) { DUK_ASSERT(res != NULL); return res; } @@ -18037,7 +18883,7 @@ DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX); h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum) { + if (DUK_UNLIKELY(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum)) { h = NULL; } return h; @@ -18053,7 +18899,7 @@ thr = (duk_hthread *) ctx; h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum)) { + if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum))) { duk_hstring *h_class; h_class = DUK_HTHREAD_GET_STRING(thr, DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum)); DUK_UNREF(h_class); @@ -18095,7 +18941,7 @@ case DUK_TAG_STRING: { duk_hstring *h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { return 0; } return (duk_size_t) DUK_HSTRING_GET_CHARLEN(h); @@ -18397,6 +19243,16 @@ tv = duk_require_tval(ctx, idx); DUK_ASSERT(tv != NULL); + +#if defined(DUK_USE_FASTINT) + /* If argument is a fastint, guarantee that it remains one. + * There's no downgrade check for other cases. + */ + if (DUK_TVAL_IS_FASTINT(tv)) { + /* XXX: Unnecessary conversion back and forth. */ + return (duk_double_t) DUK_TVAL_GET_FASTINT(tv); + } +#endif d = coerce_func(thr, tv); /* XXX: fastint? */ @@ -18408,21 +19264,21 @@ } DUK_EXTERNAL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t idx) { - /* Value coercion (in stack): ToInteger(), E5 Section 9.4 - * API return value coercion: custom + /* Value coercion (in stack): ToInteger(), E5 Section 9.4, + * API return value coercion: custom. */ DUK_ASSERT_CTX_VALID(ctx); (void) duk__to_int_uint_helper(ctx, idx, duk_js_tointeger); - return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*require*/); + return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*def_value*/, 0 /*require*/); } DUK_EXTERNAL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t idx) { - /* Value coercion (in stack): ToInteger(), E5 Section 9.4 - * API return value coercion: custom + /* Value coercion (in stack): ToInteger(), E5 Section 9.4, + * API return value coercion: custom. */ DUK_ASSERT_CTX_VALID(ctx); (void) duk__to_int_uint_helper(ctx, idx, duk_js_tointeger); - return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*require*/); + return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*def_value*/, 0 /*require*/); } DUK_EXTERNAL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t idx) { @@ -18626,7 +19482,7 @@ duk_hstring *h; h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { stridx = DUK_STRIDX_UC_SYMBOL; } else { stridx = DUK_STRIDX_UC_STRING; @@ -18784,7 +19640,7 @@ duk_hstring *h; h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CANNOT_STRING_COERCE_SYMBOL); } else { goto skip_replace; @@ -18864,7 +19720,7 @@ duk_hstring *ret; DUK_ASSERT_CTX_VALID(ctx); ret = duk_get_hstring(ctx, idx); - if (ret && DUK_HSTRING_HAS_SYMBOL(ret)) { + if (DUK_UNLIKELY(ret && DUK_HSTRING_HAS_SYMBOL(ret))) { return ret; } return duk_to_hstring(ctx, idx); @@ -19017,6 +19873,7 @@ flags = DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_CONSTRUCTABLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_NATFUNC | DUK_HOBJECT_FLAG_NEWENV | DUK_HOBJECT_FLAG_STRICT | @@ -19067,6 +19924,7 @@ } case DUK_TAG_BOOLEAN: { flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BOOLEAN); proto = DUK_BIDX_BOOLEAN_PROTOTYPE; goto create_object; @@ -19075,12 +19933,14 @@ duk_hstring *h; h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_SYMBOL); proto = DUK_BIDX_SYMBOL_PROTOTYPE; } else { flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING); proto = DUK_BIDX_STRING_PROTOTYPE; @@ -19110,6 +19970,7 @@ #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ case DUK_TAG_POINTER: { flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER); proto = DUK_BIDX_POINTER_PROTOTYPE; goto create_object; @@ -19138,7 +19999,8 @@ DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); flags = DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_NUMBER); + DUK_HOBJECT_FLAG_FASTREFS | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_NUMBER); proto = DUK_BIDX_NUMBER_PROTOTYPE; goto create_object; } @@ -19356,7 +20218,7 @@ DUK_ASSERT_CTX_VALID(ctx); - if (duk_get_type_mask(ctx, idx) & mask) { + if (DUK_LIKELY(duk_get_type_mask(ctx, idx) & mask)) { return 1; } if (mask & DUK_TYPE_MASK_THROW) { @@ -19482,7 +20344,10 @@ DUK_ASSERT_CTX_VALID(ctx); h = duk_get_hstring(ctx, idx); - if (h != NULL && DUK_HSTRING_HAS_SYMBOL(h)) { + /* Use DUK_LIKELY() here because caller may be more likely to type + * check an expected symbol than not. + */ + if (DUK_LIKELY(h != NULL && DUK_HSTRING_HAS_SYMBOL(h))) { return 1; } return 0; @@ -19538,10 +20403,15 @@ } DUK_EXTERNAL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t idx) { + duk_hobject *obj; + DUK_ASSERT_CTX_VALID(ctx); - return duk__obj_flag_any_default_false(ctx, - idx, - DUK_HOBJECT_FLAG_THREAD); + + obj = duk_get_hobject(ctx, idx); + if (obj) { + return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_THREAD ? 1 : 0); + } + return 0; } DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t idx) { @@ -19812,9 +20682,7 @@ DUK_ASSERT_CTX_VALID(ctx); /* check stack before interning (avoid hanging temp) */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); /* NULL with zero length represents an empty string; NULL with higher * length is also now trated like an empty string although it is @@ -19826,11 +20694,11 @@ } /* Check for maximum string length */ - if (len > DUK_HSTRING_MAX_BYTELEN) { + if (DUK_UNLIKELY(len > DUK_HSTRING_MAX_BYTELEN)) { DUK_ERROR_RANGE(thr, DUK_STR_STRING_TOO_LONG); } - h = duk_heap_string_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len); + h = duk_heap_strtable_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len); DUK_ASSERT(h != NULL); tv_slot = thr->valstack_top++; @@ -19948,6 +20816,7 @@ thr = (duk_hthread *) ctx; DUK_ASSERT(thr->callstack_top > 0); /* caller required to know */ + DUK_ASSERT(thr->callstack_curr != NULL); DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* consequence of above */ DUK_ASSERT(thr->valstack_bottom - 1 >= thr->valstack); /* 'this' binding exists */ @@ -19963,8 +20832,8 @@ DUK_ASSERT_DISABLE(thr->callstack_top >= 0); DUK_ASSERT(thr->callstack_top <= thr->callstack_size); - act = duk_hthread_get_current_activation(thr); - if (act) { + act = thr->callstack_curr; + if (act != NULL) { duk_push_tval(ctx, &act->tv_func); } else { duk_push_undefined(ctx); @@ -20022,7 +20891,7 @@ DUK_EXTERNAL void duk_push_thread_stash(duk_context *ctx, duk_context *target_ctx) { duk_hthread *thr = (duk_hthread *) ctx; DUK_ASSERT_CTX_VALID(ctx); - if (!target_ctx) { + if (DUK_UNLIKELY(target_ctx == NULL)) { DUK_ERROR_TYPE_INVALID_ARGS(thr); return; /* not reached */ } @@ -20099,7 +20968,7 @@ /* failed, resize and try again */ sz = sz * 2; - if (sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT) { + if (DUK_UNLIKELY(sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT)) { DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG); } } @@ -20137,15 +21006,10 @@ DUK_ASSERT(prototype_bidx == -1 || (prototype_bidx >= 0 && prototype_bidx < DUK_NUM_BUILTINS)); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); - h = duk_hobject_alloc(thr->heap, hobject_flags_and_class); - if (!h) { - DUK_ERROR_ALLOC_FAILED(thr); - } + h = duk_hobject_alloc(thr, hobject_flags_and_class); + DUK_ASSERT(h != NULL); DUK_DDD(DUK_DDDPRINT("created object with flags: 0x%08lx", (unsigned long) h->hdr.h_flags)); @@ -20184,6 +21048,7 @@ (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), DUK_BIDX_OBJECT_PROTOTYPE); return duk_get_top_index_unsafe(ctx); @@ -20199,14 +21064,13 @@ DUK_ASSERT_CTX_VALID(ctx); flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_ARRAY_PART | DUK_HOBJECT_FLAG_EXOTIC_ARRAY | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAY); - obj = duk_harray_alloc(thr->heap, flags); - if (!obj) { - DUK_ERROR_ALLOC_FAILED(thr); - } + obj = duk_harray_alloc(thr, flags); + DUK_ASSERT(obj != NULL); /* XXX: since prototype is NULL, could save a check */ DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_ARRAY_PROTOTYPE]); @@ -20260,18 +21124,12 @@ DUK_ASSERT_CTX_VALID(ctx); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); - obj = duk_hthread_alloc(thr->heap, + obj = duk_hthread_alloc(thr, DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_THREAD | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD)); - if (!obj) { - DUK_ERROR_ALLOC_FAILED(thr); - } + DUK_ASSERT(obj != NULL); obj->state = DUK_HTHREAD_STATE_INACTIVE; #if defined(DUK_USE_ROM_STRINGS) /* Nothing to initialize, strs[] is in ROM. */ @@ -20292,7 +21150,7 @@ thr->valstack_top++; /* important to do this *after* pushing, to make the thread reachable for gc */ - if (!duk_hthread_init_stacks(thr->heap, obj)) { + if (DUK_UNLIKELY(!duk_hthread_init_stacks(thr->heap, obj))) { DUK_ERROR_ALLOC_FAILED(thr); } @@ -20323,21 +21181,18 @@ DUK_ASSERT_CTX_VALID(ctx); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); /* Template functions are not strictly constructable (they don't * have a "prototype" property for instance), so leave the * DUK_HOBJECT_FLAG_CONSRUCTABLE flag cleared here. */ - obj = duk_hcompfunc_alloc(thr->heap, + obj = duk_hcompfunc_alloc(thr, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_COMPFUNC | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION)); - if (!obj) { + if (DUK_UNLIKELY(obj == NULL)) { DUK_ERROR_ALLOC_FAILED(thr); } @@ -20362,11 +21217,9 @@ DUK_ASSERT_CTX_VALID(ctx); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } - if (func == NULL) { + DUK__CHECK_SPACE(); + + if (DUK_UNLIKELY(func == NULL)) { goto api_error; } if (nargs >= 0 && nargs < DUK_HNATFUNC_NARGS_MAX) { @@ -20377,10 +21230,8 @@ goto api_error; } - obj = duk_hnatfunc_alloc(thr->heap, flags); - if (!obj) { - DUK_ERROR_ALLOC_FAILED(thr); - } + obj = duk_hnatfunc_alloc(thr, flags); + DUK_ASSERT(obj != NULL); obj->func = func; obj->nargs = func_nargs; @@ -20411,6 +21262,7 @@ flags = DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_CONSTRUCTABLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_NATFUNC | DUK_HOBJECT_FLAG_NEWENV | DUK_HOBJECT_FLAG_STRICT | @@ -20428,6 +21280,7 @@ flags = DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_CONSTRUCTABLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_NATFUNC | DUK_HOBJECT_FLAG_NEWENV | DUK_HOBJECT_FLAG_STRICT | @@ -20443,6 +21296,7 @@ DUK_ASSERT_CTX_VALID(ctx); flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_NATFUNC | DUK_HOBJECT_FLAG_NEWENV | DUK_HOBJECT_FLAG_STRICT | @@ -20459,10 +21313,7 @@ DUK_ASSERT_CTX_VALID(ctx); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); if (nargs >= DUK_LFUNC_NARGS_MIN && nargs <= DUK_LFUNC_NARGS_MAX) { /* as is */ @@ -20471,10 +21322,10 @@ } else { goto api_error; } - if (!(length >= DUK_LFUNC_LENGTH_MIN && length <= DUK_LFUNC_LENGTH_MAX)) { + if (DUK_UNLIKELY(!(length >= DUK_LFUNC_LENGTH_MIN && length <= DUK_LFUNC_LENGTH_MAX))) { goto api_error; } - if (!(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX)) { + if (DUK_UNLIKELY(!(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX))) { goto api_error; } @@ -20498,15 +21349,10 @@ DUK_ASSERT(ctx != NULL); DUK_ASSERT(prototype_bidx >= 0); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); - obj = duk_hbufobj_alloc(thr->heap, hobject_flags_and_class); - if (!obj) { - DUK_ERROR_ALLOC_FAILED(thr); - } + obj = duk_hbufobj_alloc(thr, hobject_flags_and_class); + DUK_ASSERT(obj != NULL); DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[prototype_bidx]); DUK_ASSERT_HBUFOBJ_VALID(obj); @@ -20566,19 +21412,19 @@ uint_offset = (duk_uint_t) byte_offset; uint_length = (duk_uint_t) byte_length; if (sizeof(duk_size_t) != sizeof(duk_uint_t)) { - if ((duk_size_t) uint_offset != byte_offset || (duk_size_t) uint_length != byte_length) { + if (DUK_UNLIKELY((duk_size_t) uint_offset != byte_offset || (duk_size_t) uint_length != byte_length)) { goto range_error; } } uint_added = uint_offset + uint_length; - if (uint_added < uint_offset) { + if (DUK_UNLIKELY(uint_added < uint_offset)) { goto range_error; } DUK_ASSERT(uint_added >= uint_offset && uint_added >= uint_length); DUK_ASSERT_DISABLE(flags >= 0); /* flags is unsigned */ - lookupidx = flags & 0x0f; /* 4 low bits */ - if (lookupidx >= sizeof(duk__bufobj_flags_lookup) / sizeof(duk_uint32_t)) { + lookupidx = flags; + if (DUK_UNLIKELY(lookupidx >= sizeof(duk__bufobj_flags_lookup) / sizeof(duk_uint32_t))) { goto arg_error; } tmp = duk__bufobj_flags_lookup[lookupidx]; @@ -20607,39 +21453,9 @@ /* TypedArray views need an automatic ArrayBuffer which must be * provided as .buffer property of the view. The ArrayBuffer is * referenced via duk_hbufobj->buf_prop and an inherited .buffer - * accessor returns it. - * - * The ArrayBuffer offset is always set to zero, so that if one - * accesses the ArrayBuffer at the view's .byteOffset, the value - * matches the view at index 0. - */ - if (flags & DUK_BUFOBJ_CREATE_ARRBUF) { - duk_hbufobj *h_arrbuf; - - h_arrbuf = duk_push_bufobj_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), - DUK_BIDX_ARRAYBUFFER_PROTOTYPE); - DUK_ASSERT(h_arrbuf != NULL); - - h_arrbuf->buf = h_val; - DUK_HBUFFER_INCREF(thr, h_val); - h_arrbuf->offset = 0; - h_arrbuf->length = uint_offset + uint_length; /* Wrap checked above. */ - DUK_ASSERT(h_arrbuf->shift == 0); - h_arrbuf->elem_type = DUK_HBUFOBJ_ELEM_UINT8; - DUK_ASSERT(h_arrbuf->is_typedarray == 0); - DUK_ASSERT_HBUFOBJ_VALID(h_arrbuf); - DUK_ASSERT(h_arrbuf->buf_prop == NULL); - - DUK_ASSERT(h_bufobj->buf_prop == NULL); - h_bufobj->buf_prop = (duk_hobject *) h_arrbuf; - DUK_HBUFOBJ_INCREF(thr, h_arrbuf); /* Now reachable and accounted for. */ - - duk_pop(ctx); - } - + * accessor returns it. The ArrayBuffer is created lazily on first + * access so we don't need to do anything more here. + */ return; range_error: @@ -20682,6 +21498,7 @@ proto = duk_error_prototype_from_code(thr, err_code); (void) duk_push_object_helper_proto(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR), proto); @@ -20749,18 +21566,15 @@ DUK_ASSERT_CTX_VALID(ctx); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); /* Check for maximum buffer length. */ - if (size > DUK_HBUFFER_MAX_BYTELEN) { + if (DUK_UNLIKELY(size > DUK_HBUFFER_MAX_BYTELEN)) { DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG); } h = duk_hbuffer_alloc(thr->heap, size, flags, &buf_data); - if (!h) { + if (DUK_UNLIKELY(h == NULL)) { DUK_ERROR_ALLOC_FAILED(thr); } @@ -20788,9 +21602,110 @@ return ptr; } +#if defined(DUK_USE_ASSERTIONS) +DUK_LOCAL void duk__validate_push_heapptr(duk_context *ctx, void *ptr) { + duk_heaphdr *h; + duk_heaphdr *curr; + duk_hthread *thr; + duk_bool_t found = 0; + + thr = (duk_hthread *) ctx; + h = (duk_heaphdr *) ptr; + if (h == NULL) { + /* Allowed. */ + return; + } + DUK_ASSERT(h != NULL); + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); + + /* One particular problem case is where an object has been + * queued for finalization but the finalizer hasn't yet been + * executed. + * + * Corner case: we're running in a finalizer for object X, and + * user code calls duk_push_heapptr() for X itself. In this + * case X will be in finalize_list, and we can detect the case + * by seeing that X's FINALIZED flag is set (which is done before + * the finalizer starts executing). + */ +#if defined(DUK_USE_FINALIZER_SUPPORT) + for (curr = thr->heap->finalize_list; + curr != NULL; + curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) { + /* FINALIZABLE is set for all objects on finalize_list + * except for an object being finalized right now. So + * can't assert here. + */ +#if 0 + DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(curr)); +#endif + + if (curr == h) { + if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h)) { + /* Object is currently being finalized. */ + DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ + found = 1; + } else { + /* Not being finalized but on finalize_list, + * allowed since Duktape 2.1. + */ + DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ + found = 1; + } + } + } +#endif /* DUK_USE_FINALIZER_SUPPORT */ + +#if defined(DUK_USE_REFERENCE_COUNTING) + /* Because refzero_list is now processed to completion inline with + * no side effects, it's always empty here. + */ + DUK_ASSERT(thr->heap->refzero_list == NULL); +#endif + + /* If not present in finalize_list (or refzero_list), it + * must be either in heap_allocated or the string table. + */ + if (DUK_HEAPHDR_IS_STRING(h)) { + duk_uint32_t i; + duk_hstring *str; + duk_heap *heap = thr->heap; + + DUK_ASSERT(found == 0); + for (i = 0; i < heap->st_size; i++) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + str = DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, heap->strtable16[i]); +#else + str = heap->strtable[i]; +#endif + while (str != NULL) { + if (str == (duk_hstring *) h) { + DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ + found = 1; + break; + } + str = str->hdr.h_next; + } + } + DUK_ASSERT(found != 0); + } else { + for (curr = thr->heap->heap_allocated; + curr != NULL; + curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) { + if (curr == h) { + DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ + found = 1; + } + } + DUK_ASSERT(found != 0); + } +} +#endif /* DUK_USE_ASSERTIONS */ + DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr) { duk_hthread *thr = (duk_hthread *) ctx; duk_idx_t ret; + duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); @@ -20802,43 +21717,80 @@ */ #if defined(DUK_USE_ASSERTIONS) - { - /* One particular problem case is where an object has been - * queued for finalization but the finalizer hasn't been - * executed. - */ - duk_heaphdr *curr; - for (curr = thr->heap->finalize_list; - curr != NULL; - curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) { - DUK_ASSERT(curr != (duk_heaphdr *) ptr); - } - } + duk__validate_push_heapptr(ctx, ptr); #endif + DUK__CHECK_SPACE(); + ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); + tv = thr->valstack_top++; if (ptr == NULL) { - goto push_undefined; + DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); + return ret; + } + + DUK_ASSERT_HEAPHDR_VALID((duk_heaphdr *) ptr); + + /* If the argument is on finalize_list it has technically been + * unreachable before duk_push_heapptr() but it's still safe to + * push it. Starting from Duktape 2.1 allow application code to + * do so. There are two main cases: + * + * (1) The object is on the finalize_list and we're called by + * the finalizer for the object being finalized. In this + * case do nothing: finalize_list handling will deal with + * the object queueing. This is detected by the object not + * having a FINALIZABLE flag despite being on the finalize_list; + * the flag is cleared for the object being finalized only. + * + * (2) The object is on the finalize_list but is not currently + * being processed. In this case the object can be queued + * back to heap_allocated with a few flags cleared, in effect + * cancelling the finalizer. + */ + if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) ptr))) { + duk_heaphdr *curr; + + DUK_D(DUK_DPRINT("duk_push_heapptr() with a pointer on finalize_list, autorescue")); + + curr = (duk_heaphdr *) ptr; + DUK_HEAPHDR_CLEAR_FINALIZABLE(curr); + + /* Because FINALIZED is set prior to finalizer call, it will + * be set for the object being currently finalized, but not + * for other objects on finalize_list. + */ + DUK_HEAPHDR_CLEAR_FINALIZED(curr); + + /* Dequeue object from finalize_list and queue it back to + * heap_allocated. + */ +#if defined(DUK_USE_REFERENCE_COUNTING) + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) >= 1); /* Preincremented on finalize_list insert. */ + DUK_HEAPHDR_PREDEC_REFCOUNT(curr); +#endif + DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(thr->heap, curr); + DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(thr->heap, curr); + + /* Continue with the rest. */ } switch (DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) { case DUK_HTYPE_STRING: - duk_push_hstring(ctx, (duk_hstring *) ptr); + DUK_TVAL_SET_STRING(tv, (duk_hstring *) ptr); break; case DUK_HTYPE_OBJECT: - duk_push_hobject(ctx, (duk_hobject *) ptr); - break; - case DUK_HTYPE_BUFFER: - duk_push_hbuffer(ctx, (duk_hbuffer *) ptr); + DUK_TVAL_SET_OBJECT(tv, (duk_hobject *) ptr); break; default: - goto push_undefined; + DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr) == DUK_HTYPE_BUFFER); + DUK_TVAL_SET_BUFFER(tv, (duk_hbuffer *) ptr); + break; } - return ret; - push_undefined: - duk_push_undefined(ctx); + DUK_HEAPHDR_INCREF(thr, (duk_heaphdr *) ptr); + return ret; } @@ -20846,6 +21798,7 @@ DUK_EXTERNAL duk_idx_t duk_push_bare_object(duk_context *ctx) { (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), -1); /* no prototype */ return duk_get_top_index_unsafe(ctx); @@ -20909,28 +21862,52 @@ #endif DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); if (DUK_UNLIKELY(count < 0)) { DUK_ERROR_RANGE_INVALID_COUNT(thr); return; } - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); if (DUK_UNLIKELY((duk_size_t) (thr->valstack_top - thr->valstack_bottom) < (duk_size_t) count)) { DUK_ERROR_RANGE_INVALID_COUNT(thr); } - /* - * Must be very careful here, every DECREF may cause reallocation - * of our valstack. - */ +#if defined(DUK_USE_REFERENCE_COUNTING) + tv = thr->valstack_top; + tv_end = tv - count; + while (tv != tv_end) { + tv--; + DUK_ASSERT(tv >= thr->valstack_bottom); + DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv); + } + thr->valstack_top = tv; + DUK_REFZERO_CHECK_FAST(thr); +#else + tv = thr->valstack_top; + while (count > 0) { + count--; + tv--; + DUK_ASSERT(tv >= thr->valstack_bottom); + DUK_TVAL_SET_UNDEFINED(tv); + } + thr->valstack_top = tv; +#endif - /* XXX: inlined DECREF macro would be nice here: no NULL check, - * refzero queueing but no refzero algorithm run (= no pointer - * instability), inline code. - */ + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); +} - /* XXX: optimize loops */ +DUK_INTERNAL void duk_pop_n_unsafe(duk_context *ctx, duk_idx_t count) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; +#if defined(DUK_USE_REFERENCE_COUNTING) + duk_tval *tv_end; +#endif + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(count >= 0); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count); #if defined(DUK_USE_REFERENCE_COUNTING) tv = thr->valstack_top; @@ -20956,6 +21933,34 @@ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); } +/* Pop N elements without DECREF (in effect "stealing" the refcounts). */ +#if defined(DUK_USE_REFERENCE_COUNTING) +DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_context *ctx, duk_idx_t count) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(count >= 0); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count); + + tv = thr->valstack_top; + while (count > 0) { + count--; + tv--; + DUK_ASSERT(tv >= thr->valstack_bottom); + DUK_TVAL_SET_UNDEFINED(tv); + } + thr->valstack_top = tv; + + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); +} +#else /* DUK_USE_REFERENCE_COUNTING */ +DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_context *ctx, duk_idx_t count) { + duk_pop_n_unsafe(ctx, count); +} +#endif /* DUK_USE_REFERENCE_COUNTING */ + /* Popping one element is called so often that when footprint is not an issue, * compile a specialized function for it. */ @@ -20992,16 +21997,17 @@ #if defined(DUK_USE_PREFER_SIZE) DUK_INTERNAL void duk_pop_unsafe(duk_context *ctx) { DUK_ASSERT_CTX_VALID(ctx); - duk_pop_n(ctx, 1); + duk_pop_n_unsafe(ctx, 1); } #else DUK_INTERNAL void duk_pop_unsafe(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; - DUK_ASSERT_CTX_VALID(ctx); - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(thr->valstack_top != thr->valstack_bottom); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1); tv = --thr->valstack_top; /* tv points to element just below prev top */ DUK_ASSERT(tv >= thr->valstack_bottom); @@ -21010,6 +22016,7 @@ #else DUK_TVAL_SET_UNDEFINED(tv); #endif + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); } #endif /* !DUK_USE_PREFER_SIZE */ @@ -21042,7 +22049,7 @@ thr = (duk_hthread *) ctx; top = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); - if (count < 0 || count > top) { + if (DUK_UNLIKELY(count < 0 || count > top)) { DUK_ERROR_RANGE_INVALID_COUNT(thr); return; } @@ -21105,12 +22112,13 @@ DUK_EXTERNAL void duk_throw_raw(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv_val; DUK_ASSERT(thr->valstack_bottom >= thr->valstack); DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); DUK_ASSERT(thr->valstack_end >= thr->valstack_top); - if (thr->valstack_top == thr->valstack_bottom) { + if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) { DUK_ERROR_TYPE_INVALID_ARGS(thr); } @@ -21131,7 +22139,11 @@ #endif DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (after throw augment)", (duk_tval *) duk_get_tval(ctx, -1))); - duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW); + tv_val = DUK_GET_TVAL_NEGIDX(ctx, -1); + duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, tv_val); +#if defined(DUK_USE_DEBUGGER_SUPPORT) + duk_err_check_debugger_integration(thr); +#endif /* thr->heap->lj.jmpbuf_ptr is checked by duk_err_longjmp() so we don't * need to check that here. If the value is NULL, a fatal error occurs @@ -21275,7 +22287,7 @@ return duk_js_strict_equals(tv1, tv2); } -DUK_EXTERNAL_DECL duk_bool_t duk_samevalue(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) { +DUK_EXTERNAL duk_bool_t duk_samevalue(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) { duk_tval *tv1, *tv2; DUK_ASSERT_CTX_VALID(ctx); @@ -21773,6 +22785,7 @@ duk_hstring *res; duk_size_t start_byte_offset; duk_size_t end_byte_offset; + duk_size_t charlen; DUK_ASSERT_CTX_VALID(ctx); @@ -21780,8 +22793,9 @@ h = duk_require_hstring(ctx, idx); DUK_ASSERT(h != NULL); - if (end_offset >= DUK_HSTRING_GET_CHARLEN(h)) { - end_offset = DUK_HSTRING_GET_CHARLEN(h); + charlen = DUK_HSTRING_GET_CHARLEN(h); + if (end_offset >= charlen) { + end_offset = charlen; } if (start_offset > end_offset) { start_offset = end_offset; @@ -21803,9 +22817,9 @@ DUK_ASSERT(end_byte_offset - start_byte_offset <= DUK_UINT32_MAX); /* Guaranteed by string limits. */ /* No size check is necessary. */ - res = duk_heap_string_intern_checked(thr, - DUK_HSTRING_GET_DATA(h) + start_byte_offset, - (duk_uint32_t) (end_byte_offset - start_byte_offset)); + 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(ctx, res); duk_replace(ctx, idx); @@ -23923,39 +24937,19 @@ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); } -DUK_LOCAL duk_hbufobj *duk__push_arraybuffer_with_length(duk_context *ctx, duk_uint_t len) { - duk_hbuffer *h_val; - duk_hbufobj *h_bufobj; - - (void) duk_push_fixed_buffer_zero(ctx, (duk_size_t) len); - h_val = (duk_hbuffer *) duk_known_hbuffer(ctx, -1); - - h_bufobj = duk_push_bufobj_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), - DUK_BIDX_ARRAYBUFFER_PROTOTYPE); - DUK_ASSERT(h_bufobj != NULL); - - duk__set_bufobj_buffer(ctx, h_bufobj, h_val); - DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); - - return h_bufobj; -} - -/* Shared offset/length coercion helper. */ -DUK_LOCAL void duk__resolve_offset_opt_length(duk_context *ctx, - duk_hbufobj *h_bufarg, - duk_idx_t idx_offset, - duk_idx_t idx_length, - duk_uint_t *out_offset, - duk_uint_t *out_length, - duk_bool_t throw_flag) { - duk_hthread *thr; - duk_int_t offset_signed; - duk_int_t length_signed; - duk_uint_t offset; - duk_uint_t length; +/* Shared offset/length coercion helper. */ +DUK_LOCAL void duk__resolve_offset_opt_length(duk_context *ctx, + duk_hbufobj *h_bufarg, + duk_idx_t idx_offset, + duk_idx_t idx_length, + duk_uint_t *out_offset, + duk_uint_t *out_length, + duk_bool_t throw_flag) { + duk_hthread *thr; + duk_int_t offset_signed; + duk_int_t length_signed; + duk_uint_t offset; + duk_uint_t length; thr = (duk_hthread *) ctx; DUK_UNREF(thr); @@ -24396,7 +25390,6 @@ duk_tval *tv; duk_hobject *h_obj; duk_hbufobj *h_bufobj = NULL; - duk_hbufobj *h_bufarr = NULL; duk_hbufobj *h_bufarg = NULL; duk_hbuffer *h_val; duk_small_uint_t magic; @@ -24609,15 +25602,17 @@ /* ArrayBuffer argument is handled specially above; the rest of the * argument variants are handled by shared code below. + * + * ArrayBuffer in h_bufobj->buf_prop is intentionally left unset. + * It will be automatically created by the .buffer accessor on + * first access. */ - /* Push a new ArrayBuffer (becomes view .buffer) */ - h_bufarr = duk__push_arraybuffer_with_length(ctx, byte_length); - DUK_ASSERT(h_bufarr != NULL); - h_val = h_bufarr->buf; + /* Push the resulting view object on top of a plain fixed buffer. */ + (void) duk_push_fixed_buffer(ctx, byte_length); + h_val = duk_known_hbuffer(ctx, -1); DUK_ASSERT(h_val != NULL); - /* Push the resulting view object and attach the ArrayBuffer. */ h_bufobj = duk_push_bufobj_raw(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_BUFOBJ | @@ -24633,12 +25628,6 @@ h_bufobj->is_typedarray = 1; DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); - /* Set .buffer */ - DUK_ASSERT(h_bufobj->buf_prop == NULL); - h_bufobj->buf_prop = (duk_hobject *) h_bufarr; - DUK_ASSERT(h_bufarr != NULL); - DUK_HBUFOBJ_INCREF(thr, h_bufarr); - /* Copy values, the copy method depends on the arguments. * * Copy mode decision may depend on the validity of the underlying @@ -25356,7 +26345,7 @@ } duk_hbufobj_promote_plain(ctx, 0); - h_obj = duk_known_hobject(ctx, 0); + h_obj = duk_require_hobject(ctx, 0); /* XXX: V8 throws a TypeError for negative values. Would it * be more useful to interpret negative offsets here from the @@ -25746,7 +26735,7 @@ res_proto_bidx); DUK_ASSERT(h_bufobj != NULL); - h_bufobj->length = slice_length; + DUK_ASSERT(h_bufobj->length == 0); h_bufobj->shift = h_this->shift; /* inherit */ h_bufobj->elem_type = h_this->elem_type; /* inherit */ h_bufobj->is_typedarray = magic & 0x01; @@ -25777,12 +26766,14 @@ h_bufobj->buf = h_val; DUK_HBUFFER_INCREF(thr, h_val); + h_bufobj->length = slice_length; DUK_ASSERT(h_bufobj->offset == 0); duk_pop(ctx); /* reachable so pop OK */ } else { h_bufobj->buf = h_val; DUK_HBUFFER_INCREF(thr, h_val); + h_bufobj->length = slice_length; h_bufobj->offset = (duk_uint_t) (h_this->offset + start_offset); /* Copy the .buffer property, needed for TypedArray.prototype.subarray(). @@ -26553,30 +27544,63 @@ */ #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_LOCAL duk_hbufobj *duk__autospawn_arraybuffer(duk_context *ctx, duk_hbuffer *h_buf) { + duk_hbufobj *h_res; + + h_res = duk_push_bufobj_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFOBJ | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), + DUK_BIDX_ARRAYBUFFER_PROTOTYPE); + DUK_ASSERT(h_res != NULL); + DUK_UNREF(h_res); + + duk__set_bufobj_buffer(ctx, h_res, h_buf); + DUK_ASSERT_HBUFOBJ_VALID(h_res); + DUK_ASSERT(h_res->buf_prop == NULL); + return h_res; +} + DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_context *ctx) { duk_hbufobj *h_bufobj; h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(ctx, DUK__BUFOBJ_FLAG_THROW /*flags*/); DUK_ASSERT(h_bufobj != NULL); if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) { - duk_hbufobj *h_res; - duk_hbuffer *h_buf; + DUK_DD(DUK_DDPRINT("autospawn ArrayBuffer for plain buffer")); + (void) duk__autospawn_arraybuffer(ctx, (duk_hbuffer *) h_bufobj); + return 1; + } else { + if (h_bufobj->buf_prop == NULL && + DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_bufobj) != DUK_HOBJECT_CLASS_ARRAYBUFFER && + h_bufobj->buf != NULL) { + duk_hbufobj *h_arrbuf; + + DUK_DD(DUK_DDPRINT("autospawn ArrayBuffer for typed array or DataView")); + h_arrbuf = duk__autospawn_arraybuffer(ctx, h_bufobj->buf); + + if (h_bufobj->buf_prop == NULL) { + /* Must recheck buf_prop, in case ArrayBuffer + * alloc had a side effect which already filled + * it! + */ - h_buf = (duk_hbuffer *) h_bufobj; - h_res = duk_push_bufobj_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), - DUK_BIDX_ARRAYBUFFER_PROTOTYPE); - DUK_ASSERT(h_res != NULL); - DUK_UNREF(h_res); + /* Set ArrayBuffer's .byteOffset and .byteLength based + * on the view so that Arraybuffer[view.byteOffset] + * matches view[0]. + */ + h_arrbuf->offset = 0; + DUK_ASSERT(h_bufobj->offset + h_bufobj->length >= h_bufobj->offset); /* Wrap check on creation. */ + h_arrbuf->length = h_bufobj->offset + h_bufobj->length; + DUK_ASSERT(h_arrbuf->buf_prop == NULL); - duk__set_bufobj_buffer(ctx, h_res, h_buf); - DUK_ASSERT_HBUFOBJ_VALID(h_res); + DUK_ASSERT(h_bufobj->buf_prop == NULL); + h_bufobj->buf_prop = (duk_hobject *) h_arrbuf; + DUK_HBUFOBJ_INCREF(thr, h_arrbuf); /* Now reachable and accounted for. */ + } - DUK_DD(DUK_DDPRINT("autospawned .buffer ArrayBuffer: %!iT", duk_get_tval(ctx, -1))); - return 1; - } else { + /* Left on stack; pushed for the second time below (OK). */ + } if (h_bufobj->buf_prop) { duk_push_hobject(ctx, h_bufobj->buf_prop); return 1; @@ -28079,6 +29103,7 @@ (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATE), DUK_BIDX_DATE_PROTOTYPE); @@ -28591,7 +29616,7 @@ * an mktime() error return is the cast above. See e.g.: * http://pubs.opengroup.org/onlinepubs/009695299/functions/mktime.html */ - goto error; + goto mktime_error; } DUK_DDD(DUK_DDDPRINT("t1=%ld (utc), t2=%ld (local)", (long) t1, (long) t2)); @@ -28607,7 +29632,7 @@ #endif return (duk_int_t) difftime(t2, t1); - error: + mktime_error: /* XXX: return something more useful, so that caller can throw? */ DUK_D(DUK_DPRINT("mktime() failed, d=%lf", (double) d)); return 0; @@ -28829,6 +29854,38 @@ return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000000LL); /* seconds */ } #endif /* DUK_USE_DATE_TZO_WINDOWS */ + +#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) { + 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; + FileTimeToLocalFileTime((const FILETIME *) &ft1, &ft2); + + FileTimeToSystemTime((const FILETIME *) &ft2, &st2); + duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2); + + return (duk_int_t) (((LONGLONG) tmp2.QuadPart - (LONGLONG) tmp1.QuadPart) / 10000000LL); /* seconds */ +} +#endif /* DUK_USE_DATE_TZO_WINDOWS_NO_DST */ /* * Duktape built-ins * @@ -28860,15 +29917,14 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_small_uint_t flags; - duk_bool_t rc; flags = (duk_small_uint_t) duk_get_uint(ctx, 0); - rc = duk_heap_mark_and_sweep(thr->heap, flags); + duk_heap_mark_and_sweep(thr->heap, flags); /* XXX: Not sure what the best return value would be in the API. - * Return a boolean for now. Note that rc == 0 is success (true). + * Return true for now. */ - duk_push_boolean(ctx, !rc); + duk_push_true(ctx); return 1; } @@ -28880,15 +29936,16 @@ * 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. + * be deleted. Must use duk_set_finalizer() to keep + * DUK_HOBJECT_FLAG_HAVE_FINALIZER in sync. */ duk_set_top(ctx, 2); - (void) duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_INT_FINALIZER); + duk_set_finalizer(ctx, 0); return 0; } else { /* Get. */ DUK_ASSERT(duk_get_top(ctx) == 1); - duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_INT_FINALIZER); + duk_get_finalizer(ctx, 0); return 1; } } @@ -29139,6 +30196,7 @@ } } +#if defined(DUK_USE_ENCODING_BUILTINS) DUK_LOCAL void duk__utf8_encode_char(void *udata, duk_codepoint_t codepoint) { duk__encode_context *enc_ctx; @@ -29193,6 +30251,7 @@ */ enc_ctx->out += duk_unicode_encode_xutf8(codepoint, enc_ctx->out); } +#endif /* DUK_USE_ENCODING_BUILTINS */ /* Shared helper for buffer-to-string using a TextDecoder() compatible UTF-8 * decoder. @@ -29356,7 +30415,6 @@ DUK_ASSERT_TOP(ctx, 1); if (duk_is_undefined(ctx, 0)) { len = 0; - final_len = len; } else { duk_hstring *h_input; @@ -29414,6 +30472,8 @@ final_len = (duk_size_t) (enc_ctx.out - output); duk_resize_buffer(ctx, -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 @@ -29454,8 +30514,8 @@ * initialized explicitly. */ dec_ctx = (duk__decode_context *) duk_push_fixed_buffer(ctx, sizeof(duk__decode_context)); - dec_ctx->fatal = fatal; - dec_ctx->ignore_bom = ignore_bom; + 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_string(ctx, -2, "\xff" "Context"); @@ -29546,6 +30606,7 @@ /* 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); DUK_UNREF(thr); @@ -29986,7 +31047,7 @@ DUK_ASSERT_TOP(ctx, 3); /* strictness is not inherited, intentional */ - comp_flags = DUK_JS_COMPILE_FLAG_FUNCEXPR; + comp_flags = DUK_COMPILE_FUNCEXPR; duk_push_hstring_stridx(ctx, DUK_STRIDX_COMPILE); /* XXX: copy from caller? */ /* XXX: ignored now */ h_sourcecode = duk_require_hstring(ctx, -2); /* no symbol check needed; -2 is concat'd code */ @@ -30127,6 +31188,7 @@ /* XXX: [[Construct]] newTarget currently unsupported */ DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx); } + duk_set_top(ctx, 2); /* chop off extra arguments: [ constructor argArray ] */ idx_args = 1; break; } @@ -30257,6 +31319,7 @@ /* create bound function object */ h_bound = duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_BOUNDFUNC | DUK_HOBJECT_FLAG_CONSTRUCTABLE | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION), @@ -30777,7 +31840,8 @@ DUK_ASSERT(duk_get_top(ctx) == 1 || duk_get_top(ctx) == 2); /* 2 when called by debugger */ DUK_ASSERT(thr->callstack_top >= 1); /* at least this function exists */ - DUK_ASSERT(((thr->callstack + thr->callstack_top - 1)->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0 || /* indirect eval */ + 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 */ /* @@ -30807,8 +31871,9 @@ /* [ source ] */ - comp_flags = DUK_JS_COMPILE_FLAG_EVAL; - act_eval = thr->callstack + thr->callstack_top - 1; /* this function */ + comp_flags = DUK_COMPILE_EVAL; + act_eval = thr->callstack_curr; /* this function */ + DUK_ASSERT(act_eval != NULL); if (thr->callstack_top >= (duk_size_t) -level) { /* Have a calling activation, check for direct eval (otherwise * assume indirect eval. @@ -30819,7 +31884,7 @@ /* Only direct eval inherits strictness from calling code * (E5.1 Section 10.1.1). */ - comp_flags |= DUK_JS_COMPILE_FLAG_STRICT; + comp_flags |= DUK_COMPILE_STRICT; } } else { DUK_ASSERT((act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0); @@ -30839,7 +31904,7 @@ /* E5 Section 10.4.2 */ DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; /* this function */ + act = thr->callstack_curr; /* this function */ if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) { DUK_ASSERT(thr->callstack_top >= 2); act = thr->callstack + thr->callstack_top + level; /* caller */ @@ -30857,26 +31922,29 @@ this_to_global = 0; if (DUK_HOBJECT_HAS_STRICT((duk_hobject *) func)) { - duk_hobject *new_env; + 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 = thr->callstack + thr->callstack_top + level; /* caller */ act_lex_env = act->lex_env; act = NULL; /* invalidated */ - new_env = duk_push_object_helper_proto(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), - act_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(ctx, (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 = new_env; - outer_var_env = new_env; + outer_lex_env = (duk_hobject *) new_env; + outer_var_env = (duk_hobject *) new_env; duk_insert(ctx, 0); /* stash to bottom of value stack to keep new_env reachable for duration of eval */ @@ -30906,7 +31974,7 @@ /* 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*/); - /* [ source template closure ] */ + /* [ env? source template closure ] */ if (this_to_global) { DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); @@ -30925,11 +31993,11 @@ (duk_heaphdr *) outer_var_env, duk_get_tval(ctx, -1))); - /* [ source template closure this ] */ + /* [ env? source template closure this ] */ duk_call_method(ctx, 0); - /* [ source template result ] */ + /* [ env? source template result ] */ return 1; } @@ -31143,12 +32211,15 @@ DUK_LOCAL_DECL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv); #endif #if defined(DUK_USE_JX) || defined(DUK_USE_JC) -DUK_LOCAL_DECL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h); +DUK_LOCAL_DECL void duk__enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h); DUK_LOCAL_DECL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr); #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) DUK_LOCAL_DECL void duk__enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj); #endif #endif +#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) +DUK_LOCAL_DECL void duk__enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h); +#endif DUK_LOCAL_DECL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth); /* @@ -32628,13 +33699,60 @@ DUK_BW_SET_PTR(thr, &js_ctx->bw, q); } -DUK_LOCAL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) { +DUK_LOCAL void duk__enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) { duk__enc_buffer_data(js_ctx, (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h), (duk_size_t) DUK_HBUFFER_GET_SIZE(h)); } #endif /* DUK_USE_JX || DUK_USE_JC */ +#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) +DUK_LOCAL void duk__enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) { + duk_size_t i, n; + const duk_uint8_t *buf; + duk_uint8_t *q; + + n = DUK_HBUFFER_GET_SIZE(h); + if (n == 0) { + DUK__EMIT_2(js_ctx, DUK_ASC_LCURLY, DUK_ASC_RCURLY); + return; + } + + DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY); + + /* Maximum encoded length with 32-bit index: 1 + 10 + 2 + 3 + 1 + 1 = 18, + * with 64-bit index: 1 + 20 + 2 + 3 + 1 + 1 = 28. 32 has some spare. + * + * Note that because the output buffer is reallocated from time to time, + * side effects (such as finalizers) affecting the buffer 'h' must be + * disabled. This is the case in the JSON.stringify() fast path. + */ + + buf = (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h); + if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { + for (i = 0; i < n; i++) { + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth + 1); + q = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, 32); + q += DUK_SPRINTF((char *) q, "\"%lu\": %u,", (unsigned long) i, (unsigned int) buf[i]); + DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, q); + } + } else { + q = DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw); + for (i = 0; i < n; i++) { + q = DUK_BW_ENSURE_RAW(js_ctx->thr, &js_ctx->bw, 32, q); + q += DUK_SPRINTF((char *) q, "\"%lu\":%u,", (unsigned long) i, (unsigned int) buf[i]); + } + DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, q); + } + DUK__UNEMIT_1(js_ctx); /* eat trailing comma */ + + if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth); + } + DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY); +} +#endif /* DUK_USE_JSON_STRINGIFY_FASTPATH */ + #if defined(DUK_USE_JX) || defined(DUK_USE_JC) DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) { char buf[64]; /* XXX: how to figure correct size? */ @@ -33184,7 +34302,7 @@ case DUK_TAG_STRING: { duk_hstring *h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { goto pop2_undef; } duk__enc_quote_string(js_ctx, h); @@ -33215,12 +34333,13 @@ case DUK_TAG_BUFFER: { #if defined(DUK_USE_JX) || defined(DUK_USE_JC) if (js_ctx->flag_ext_custom_or_compatible) { - duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv)); + duk__enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv)); break; } #endif - /* Could implement a fast path, but object coerce and - * serialize the result for now. + + /* Could implement a fastpath, but the fast path would need + * to handle realloc side effects correctly. */ duk_to_object(ctx, -1); duk__enc_object(js_ctx); @@ -33280,7 +34399,7 @@ duk_hstring *h; h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { return 0; } return 1; @@ -33349,7 +34468,7 @@ duk_hstring *h; h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { goto emit_undefined; } duk__enc_quote_string(js_ctx, h); @@ -33514,7 +34633,7 @@ DUK_DD(DUK_DDPRINT("property is an accessor, abort fast path")); goto abort_fastpath; } - if (DUK_HSTRING_HAS_SYMBOL(k)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(k))) { continue; } @@ -33708,13 +34827,16 @@ #if defined(DUK_USE_JX) || defined(DUK_USE_JC) if (js_ctx->flag_ext_custom_or_compatible) { - duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv)); + duk__enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv)); break; } #endif - /* Could implement a fast path, but abort fast path for now. */ - DUK_DD(DUK_DDPRINT("value is a plain buffer and serializing as plain JSON, abort fast path")); - goto abort_fastpath; + + /* Plain buffers mimic Uint8Arrays, and have enumerable index + * properties. + */ + duk__enc_buffer_json_fastpath(js_ctx, DUK_TVAL_GET_BUFFER(tv)); + break; } case DUK_TAG_POINTER: { #if defined(DUK_USE_JX) || defined(DUK_USE_JC) @@ -34111,8 +35233,11 @@ } if (js_ctx->h_gap != NULL) { - /* if gap is empty, behave as if not given at all */ - if (DUK_HSTRING_GET_CHARLEN(js_ctx->h_gap) == 0) { + /* If gap is empty, behave as if not given at all. Check + * against byte length because character length is more + * expensive. + */ + if (DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) == 0) { js_ctx->h_gap = NULL; } } @@ -34128,7 +35253,7 @@ if (js_ctx->h_replacer == NULL && /* replacer is a mutation risk */ js_ctx->idx_proplist == -1) { /* proplist is very rare */ duk_int_t pcall_rc; - duk_small_uint_t prev_mark_and_sweep_base_flags; + duk_small_uint_t prev_ms_base_flags; DUK_DD(DUK_DDPRINT("try JSON.stringify() fast path")); @@ -34150,14 +35275,17 @@ duk_dup(ctx, idx_value); /* Must prevent finalizers which may have arbitrary side effects. */ - prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags; - thr->heap->mark_and_sweep_base_flags |= - DUK_MS_FLAG_NO_FINALIZERS | /* avoid attempts to add/remove object keys */ - DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid attempt to compact any objects */ + prev_ms_base_flags = thr->heap->ms_base_flags; + thr->heap->ms_base_flags |= + DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* Avoid attempt to compact any objects. */ + thr->heap->pf_prevent_count++; /* Prevent finalizers. */ + DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */ pcall_rc = duk_safe_call(ctx, duk__json_stringify_fast, (void *) js_ctx /*udata*/, 1 /*nargs*/, 0 /*nret*/); - thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; + DUK_ASSERT(thr->heap->pf_prevent_count > 0); + thr->heap->pf_prevent_count--; + thr->heap->ms_base_flags = prev_ms_base_flags; if (pcall_rc == DUK_EXEC_SUCCESS) { DUK_DD(DUK_DDPRINT("fast path successful")); @@ -35001,6 +36129,7 @@ (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), DUK_BIDX_OBJECT_PROTOTYPE); return 1; @@ -35063,6 +36192,7 @@ (void) duk_push_object_helper_proto(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), proto); @@ -35781,6 +36911,7 @@ if (duk_is_constructor_call(ctx)) { (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER), DUK_BIDX_POINTER_PROTOTYPE); @@ -35877,7 +37008,7 @@ goto skip_key; } } - if (DUK_HSTRING_HAS_SYMBOL(h)) { + 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(ctx, -1))); goto skip_key; @@ -35954,6 +37085,7 @@ */ (void) duk_push_object_helper_proto(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), NULL); @@ -36333,6 +37465,96 @@ #if defined(DUK_USE_STRING_BUILTIN) /* + * Helpers + */ + +DUK_LOCAL duk_hstring *duk__str_tostring_notregexp(duk_context *ctx, duk_idx_t idx) { + duk_hstring *h; + + if (duk_get_class_number(ctx, idx) == DUK_HOBJECT_CLASS_REGEXP) { + DUK_ERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx); + } + h = duk_to_hstring(ctx, idx); + DUK_ASSERT(h != NULL); + + return h; +} + +DUK_LOCAL duk_int_t duk__str_search_shared(duk_context *ctx, duk_hstring *h_this, duk_hstring *h_search, duk_int_t start_cpos, duk_bool_t backwards) { + duk_int_t cpos; + duk_int_t bpos; + const duk_uint8_t *p_start, *p_end, *p; + const duk_uint8_t *q_start; + duk_int_t q_blen; + duk_uint8_t firstbyte; + duk_uint8_t t; + + cpos = start_cpos; + + /* Empty searchstring always matches; cpos must be clamped here. + * (If q_blen were < 0 due to clamped coercion, it would also be + * caught here.) + */ + q_start = DUK_HSTRING_GET_DATA(h_search); + q_blen = (duk_int_t) DUK_HSTRING_GET_BYTELEN(h_search); + if (q_blen <= 0) { + return cpos; + } + DUK_ASSERT(q_blen > 0); + + bpos = (duk_int_t) duk_heap_strcache_offset_char2byte((duk_hthread *) ctx, h_this, (duk_uint32_t) cpos); + + p_start = DUK_HSTRING_GET_DATA(h_this); + p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_this); + p = p_start + bpos; + + /* This loop is optimized for size. For speed, there should be + * two separate loops, and we should ensure that memcmp() can be + * used without an extra "will searchstring fit" check. Doing + * the preconditioning for 'p' and 'p_end' is easy but cpos + * must be updated if 'p' is wound back (backward scanning). + */ + + firstbyte = q_start[0]; /* leading byte of match string */ + while (p <= p_end && p >= p_start) { + t = *p; + + /* For Ecmascript strings, this check can only match for + * initial UTF-8 bytes (not continuation bytes). For other + * strings all bets are off. + */ + + if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= (duk_size_t) q_blen)) { + DUK_ASSERT(q_blen > 0); /* no issues with memcmp() zero size, even if broken */ + if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { + return cpos; + } + } + + /* track cpos while scanning */ + if (backwards) { + /* when going backwards, we decrement cpos 'early'; + * 'p' may point to a continuation byte of the char + * at offset 'cpos', but that's OK because we'll + * backtrack all the way to the initial byte. + */ + if ((t & 0xc0) != 0x80) { + cpos--; + } + p--; + } else { + if ((t & 0xc0) != 0x80) { + cpos++; + } + p++; + } + } + + /* Not found. Empty string case is handled specially above. */ + return -1; +} + +/* * Constructor */ @@ -36354,7 +37576,7 @@ duk_push_hstring_empty(ctx); } else { h = duk_to_hstring_acceptsymbol(ctx, 0); - if (DUK_HSTRING_HAS_SYMBOL(h) && !duk_is_constructor_call(ctx)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h) && !duk_is_constructor_call(ctx))) { duk_push_symbol_descriptive_string(ctx, h); duk_replace(ctx, 0); } @@ -36366,6 +37588,7 @@ if (duk_is_constructor_call(ctx)) { /* String object internal value is immutable */ flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING); duk_push_object_helper(ctx, flags, DUK_BIDX_STRING_PROTOTYPE); @@ -36515,7 +37738,7 @@ pos = duk_to_int_clamped_raw(ctx, 0 /*index*/, 0 /*min(incl)*/, - DUK_HSTRING_GET_CHARLEN(h) - 1 /*max(incl)*/, + (duk_int_t) DUK_HSTRING_GET_CHARLEN(h) - 1 /*max(incl)*/, &clamped /*out_clamped*/); #if defined(DUK_USE_ES6) magic = duk_get_current_magic(ctx); @@ -36677,17 +37900,10 @@ */ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx) { - duk_hthread *thr = (duk_hthread *) ctx; duk_hstring *h_this; duk_hstring *h_search; duk_int_t clen_this; duk_int_t cpos; - duk_int_t bpos; - const duk_uint8_t *p_start, *p_end, *p; - const duk_uint8_t *q_start; - duk_int_t q_blen; - duk_uint8_t firstbyte; - duk_uint8_t t; duk_small_int_t is_lastindexof = duk_get_current_magic(ctx); /* 0=indexOf, 1=lastIndexOf */ h_this = duk_push_this_coercible_to_string(ctx); @@ -36696,8 +37912,6 @@ h_search = duk_to_hstring(ctx, 0); DUK_ASSERT(h_search != NULL); - q_start = DUK_HSTRING_GET_DATA(h_search); - q_blen = (duk_int_t) DUK_HSTRING_GET_BYTELEN(h_search); duk_to_number(ctx, 1); if (duk_is_nan(ctx, 1) && is_lastindexof) { @@ -36710,67 +37924,8 @@ cpos = duk_to_int_clamped(ctx, 1, 0, clen_this); } - /* Empty searchstring always matches; cpos must be clamped here. - * (If q_blen were < 0 due to clamped coercion, it would also be - * caught here.) - */ - if (q_blen <= 0) { - duk_push_int(ctx, cpos); - return 1; - } - DUK_ASSERT(q_blen > 0); - - bpos = (duk_int_t) duk_heap_strcache_offset_char2byte(thr, h_this, (duk_uint32_t) cpos); - - p_start = DUK_HSTRING_GET_DATA(h_this); - p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_this); - p = p_start + bpos; - - /* This loop is optimized for size. For speed, there should be - * two separate loops, and we should ensure that memcmp() can be - * used without an extra "will searchstring fit" check. Doing - * the preconditioning for 'p' and 'p_end' is easy but cpos - * must be updated if 'p' is wound back (backward scanning). - */ - - firstbyte = q_start[0]; /* leading byte of match string */ - while (p <= p_end && p >= p_start) { - t = *p; - - /* For Ecmascript strings, this check can only match for - * initial UTF-8 bytes (not continuation bytes). For other - * strings all bets are off. - */ - - if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= (duk_size_t) q_blen)) { - DUK_ASSERT(q_blen > 0); /* no issues with memcmp() zero size, even if broken */ - if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { - duk_push_int(ctx, cpos); - return 1; - } - } - - /* track cpos while scanning */ - if (is_lastindexof) { - /* when going backwards, we decrement cpos 'early'; - * 'p' may point to a continuation byte of the char - * at offset 'cpos', but that's OK because we'll - * backtrack all the way to the initial byte. - */ - if ((t & 0xc0) != 0x80) { - cpos--; - } - p--; - } else { - if ((t & 0xc0) != 0x80) { - cpos++; - } - p++; - } - } - - /* Not found. Empty string case is handled specially above. */ - duk_push_int(ctx, -1); + cpos = duk__str_search_shared(ctx, h_this, h_search, cpos, is_lastindexof /*backwards*/); + duk_push_int(ctx, cpos); return 1; } @@ -37067,9 +38222,10 @@ /* Use match charlen instead of bytelen, just in case the input and * match codepoint encodings would have different lengths. */ + /* XXX: charlen computed here, and also in char2byte helper. */ match_end_boff = duk_heap_strcache_offset_char2byte(thr, h_input, - match_start_coff + DUK_HSTRING_GET_CHARLEN(h_match)); + match_start_coff + (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h_match)); tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - match_end_boff); DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + match_end_boff, tmp_sz); @@ -37419,7 +38575,7 @@ DUK_DDD(DUK_DDDPRINT("split trailer; prev_end b=%ld,c=%ld", (long) prev_match_end_boff, (long) prev_match_end_coff)); - if (DUK_HSTRING_GET_CHARLEN(h_input) > 0 || !matched) { + if (DUK_HSTRING_GET_BYTELEN(h_input) > 0 || !matched) { /* Add trailer if: * a) non-empty input * b) empty input and no (zero size) match found (step 11) @@ -37679,10 +38835,10 @@ } else { DUK_MEMCPY((void *) p, (const void *) src, copy_size); p += copy_size; - copy_size *= 2; } src = (const duk_uint8_t *) buf; /* Use buf as source for larger copies. */ + copy_size = (duk_size_t) (p - buf); } #endif /* DUK_USE_PREFER_SIZE */ @@ -37761,6 +38917,93 @@ return 1; } +#if defined(DUK_USE_ES6) +DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_context *ctx) { + duk_int_t magic; + duk_hstring *h; + duk_hstring *h_search; + duk_size_t blen_search; + const duk_uint8_t *p_cmp_start; + duk_bool_t result; + + h = duk_push_this_coercible_to_string(ctx); + DUK_ASSERT(h != NULL); + + h_search = duk__str_tostring_notregexp(ctx, 0); + DUK_ASSERT(h_search != NULL); + + magic = duk_get_current_magic(ctx); + + p_cmp_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h); + blen_search = DUK_HSTRING_GET_BYTELEN(h_search); + + if (duk_is_undefined(ctx, 1)) { + if (magic) { + p_cmp_start += DUK_HSTRING_GET_BYTELEN(h) - blen_search; + } else { + /* p_cmp_start already OK */ + } + } else { + duk_int_t len; + duk_int_t pos; + + DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= DUK_INT_MAX); + len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h); + pos = duk_to_int_clamped(ctx, 1, 0, len); + DUK_ASSERT(pos >= 0 && pos <= len); + + if (magic) { + p_cmp_start -= blen_search; /* Conceptually subtracted last, but do already here. */ + } + DUK_ASSERT(pos >= 0 && pos <= len); + + p_cmp_start += duk_heap_strcache_offset_char2byte((duk_hthread *) ctx, h, pos); + } + + /* The main comparison can be done using a memcmp() rather than + * doing codepoint comparisons: for CESU-8 strings there is a + * canonical representation for every codepoint. But we do need + * to deal with the char/byte offset translation to find the + * comparison range. + */ + + result = 0; + if (p_cmp_start >= DUK_HSTRING_GET_DATA(h) && + p_cmp_start - (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h) + blen_search <= DUK_HSTRING_GET_BYTELEN(h)) { + if (DUK_MEMCMP((const void *) p_cmp_start, + (const void *) DUK_HSTRING_GET_DATA(h_search), + (size_t) blen_search) == 0) { + result = 1; + } + } + + duk_push_boolean(ctx, result); + return 1; +} +#endif /* DUK_USE_ES6 */ + +#if defined(DUK_USE_ES6) +DUK_INTERNAL duk_ret_t duk_bi_string_prototype_includes(duk_context *ctx) { + duk_hstring *h; + duk_hstring *h_search; + duk_int_t len; + duk_int_t pos; + + h = duk_push_this_coercible_to_string(ctx); + DUK_ASSERT(h != NULL); + + h_search = duk__str_tostring_notregexp(ctx, 0); + DUK_ASSERT(h_search != NULL); + + len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h); + pos = duk_to_int_clamped(ctx, 1, 0, len); + DUK_ASSERT(pos >= 0 && pos <= len); + + pos = duk__str_search_shared(ctx, h, h_search, pos, 0 /*backwards*/); + duk_push_boolean(ctx, pos >= 0); + return 1; +} +#endif /* DUK_USE_ES6 */ #endif /* DUK_USE_STRING_BUILTIN */ /* * Symbol built-in @@ -37868,7 +39111,8 @@ h_str = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h_str != NULL); - if (!DUK_HSTRING_HAS_SYMBOL(h_str)) { + /* Here symbol is more expected than not. */ + if (DUK_UNLIKELY(!DUK_HSTRING_HAS_SYMBOL(h_str))) { return NULL; } @@ -37888,6 +39132,7 @@ duk_push_symbol_descriptive_string(ctx, h_str); } else { /* .valueOf() */ + duk_push_hstring(ctx, h_str); } return 1; } @@ -38014,11 +39259,12 @@ DUK_DD(DUK_DDPRINT("resume state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.resume)")); goto state_error; } - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); /* us */ - DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL); /* caller */ + DUK_ASSERT(thr->callstack_curr != 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 - 1) != NULL); /* caller */ - caller_func = DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2); + caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr - 1); if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) { DUK_DD(DUK_DDPRINT("resume state invalid: caller must be Ecmascript code")); goto state_error; @@ -38168,11 +39414,12 @@ DUK_DD(DUK_DDPRINT("yield state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.yield)")); goto state_error; } - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); /* us */ - DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL); /* caller */ + DUK_ASSERT(thr->callstack_curr != 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 - 1) != NULL); /* caller */ - caller_func = DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2); + caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr - 1); if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) { DUK_DD(DUK_DDPRINT("yield state invalid: caller must be Ecmascript code")); goto state_error; @@ -38747,6 +39994,9 @@ } } if (st->internal) { + if (DUK_HOBJECT_IS_ARRAY(h)) { + DUK__COMMA(); duk_fb_sprintf(fb, "__array:true"); + } if (DUK_HOBJECT_HAS_EXTENSIBLE(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__extensible:true"); } @@ -38765,7 +40015,7 @@ if (DUK_HOBJECT_HAS_BUFOBJ(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__bufobj:true"); } - if (DUK_HOBJECT_HAS_THREAD(h)) { + if (DUK_HOBJECT_IS_THREAD(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__thread:true"); } if (DUK_HOBJECT_HAS_ARRAY_PART(h)) { @@ -38786,9 +40036,6 @@ if (DUK_HOBJECT_HAS_CREATEARGS(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__createargs:true"); } - if (DUK_HOBJECT_HAS_ENVRECCLOSED(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__envrecclosed:true"); - } if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_array:true"); } @@ -38833,6 +40080,15 @@ duk_fb_put_funcptr(fb, (duk_uint8_t *) &f->func, sizeof(f->func)); DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld", (long) f->nargs); DUK__COMMA(); duk_fb_sprintf(fb, "__magic:%ld", (long) f->magic); + } else if (st->internal && DUK_HOBJECT_IS_DECENV(h)) { + duk_hdecenv *e = (duk_hdecenv *) h; + DUK__COMMA(); duk_fb_sprintf(fb, "__thread:"); duk__print_hobject(st, (duk_hobject *) e->thread); + DUK__COMMA(); duk_fb_sprintf(fb, "__varmap:"); duk__print_hobject(st, (duk_hobject *) e->varmap); + DUK__COMMA(); duk_fb_sprintf(fb, "__regbase:%ld", (long) e->regbase); + } else if (st->internal && DUK_HOBJECT_IS_OBJENV(h)) { + duk_hobjenv *e = (duk_hobjenv *) h; + DUK__COMMA(); duk_fb_sprintf(fb, "__target:"); duk__print_hobject(st, (duk_hobject *) e->target); + DUK__COMMA(); duk_fb_sprintf(fb, "__has_this:%ld", (long) e->has_this); #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) } else if (st->internal && DUK_HOBJECT_IS_BUFOBJ(h)) { duk_hbufobj *b = (duk_hbufobj *) h; @@ -39066,6 +40322,10 @@ } #if defined(DUK_USE_FASTINT) case DUK_TAG_FASTINT: + DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); + DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + duk_fb_sprintf(fb, "%.18gF", (double) DUK_TVAL_GET_NUMBER(tv)); + break; #endif default: { /* IEEE double is approximately 16 decimal digits; print a couple extra */ @@ -39159,7 +40419,7 @@ if (ch == DUK_ASC_STAR) { /* unsupported: would consume multiple args */ - goto error; + goto format_error; } else if (ch == DUK_ASC_PERCENT) { duk_fb_put_byte(&fb, (duk_uint8_t) DUK_ASC_PERCENT); break; @@ -39211,7 +40471,7 @@ fmtlen = (duk_size_t) (p - p_begfmt); if (fmtlen >= sizeof(fmtbuf)) { /* format is too large, abort */ - goto error; + goto format_error; } DUK_MEMZERO(fmtbuf, sizeof(fmtbuf)); DUK_MEMCPY(fmtbuf, p_begfmt, fmtlen); @@ -39286,7 +40546,7 @@ } goto done; - error: + format_error: duk_fb_put_cstring(&fb, "FMTERR"); /* fall through */ @@ -39414,7 +40674,6 @@ /* heap->dbg_detached_cb: keep */ /* heap->dbg_udata: keep */ /* heap->dbg_processing: keep on purpose to avoid debugger re-entry in detaching state */ - DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap); heap->dbg_state_dirty = 0; heap->dbg_force_restart = 0; heap->dbg_step_type = 0; @@ -39422,6 +40681,8 @@ heap->dbg_step_csindex = 0; heap->dbg_step_startline = 0; heap->dbg_have_next_byte = 0; + duk_debug_clear_paused(heap); /* XXX: some overlap with field inits above */ + heap->dbg_state_dirty = 0; /* XXX: clear_paused sets dirty; rework? */ /* Ensure there are no stale active breakpoint pointers. * Breakpoint list is currently kept - we could empty it @@ -39440,7 +40701,10 @@ duk_context *ctx; thr = heap->heap_thread; - DUK_ASSERT(thr != NULL); + if (thr == NULL) { + DUK_ASSERT(heap->dbg_detached_cb == NULL); + return; + } ctx = (duk_context *) thr; /* Safe to call multiple times. */ @@ -39474,6 +40738,9 @@ */ DUK_LOCAL void duk__debug_null_most_callbacks(duk_hthread *thr) { duk_heap *heap; + + DUK_ASSERT(thr != NULL); + heap = thr->heap; DUK_D(DUK_DPRINT("transport read/write error, NULL all callbacks expected detached")); heap->dbg_read_cb = NULL; @@ -40321,7 +41588,7 @@ duk_uint_fast32_t line; duk_uint_fast32_t pc; - act = duk_hthread_get_current_activation(thr); /* may be NULL */ + act = thr->callstack_curr; if (act == NULL) { return 0; } @@ -40352,13 +41619,13 @@ duk_debug_write_int(thr, (DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) ? 1 : 0)); DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* unsigned */ - if (thr->callstack_top == 0) { + act = thr->callstack_curr; + if (act == NULL) { duk_debug_write_undefined(thr); duk_debug_write_undefined(thr); duk_debug_write_int(thr, 0); duk_debug_write_int(thr, 0); } else { - act = thr->callstack + thr->callstack_top - 1; duk_push_tval(ctx, &act->tv_func); duk_get_prop_string(ctx, -1, "fileName"); duk__debug_write_hstring_safe_top(thr); @@ -40367,6 +41634,7 @@ duk_pop_3(ctx); /* Report next pc/line to be executed. */ duk_debug_write_uint(thr, (duk_uint32_t) duk_debug_curr_line(thr)); + act = thr->callstack_curr; duk_debug_write_uint(thr, (duk_uint32_t) duk_hthread_get_act_curr_pc(thr, act)); } @@ -40399,18 +41667,29 @@ duk__debug_write_hstring_safe_top(thr); duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_LINE_NUMBER); duk_debug_write_uint(thr, duk_get_uint(ctx, -1)); + duk_pop_2(ctx); } else { - /* For anything other than an Error instance, we calculate the error - * location directly from the current activation. - */ - act = thr->callstack + thr->callstack_top - 1; - duk_push_tval(ctx, &act->tv_func); - duk_get_prop_string(ctx, -1, "fileName"); - duk__debug_write_hstring_safe_top(thr); - pc = duk_hthread_get_act_prev_pc(thr, act); - duk_debug_write_uint(thr, (duk_uint32_t) duk_hobject_pc2line_query(ctx, -2, pc)); + /* For anything other than an Error instance, we calculate the + * error location directly from the current activation if one + * exists. + */ + act = thr->callstack_curr; + if (act != NULL) { + duk_push_tval(ctx, &act->tv_func); + duk_get_prop_string(ctx, -1, "fileName"); + duk__debug_write_hstring_safe_top(thr); + act = thr->callstack_curr; + pc = duk_hthread_get_act_prev_pc(thr, act); + duk_debug_write_uint(thr, (duk_uint32_t) duk_hobject_pc2line_query(ctx, -2, pc)); + duk_pop_2(ctx); + } else { + /* Can happen if duk_throw() is called on an empty + * callstack. + */ + duk_debug_write_cstring(thr, ""); + duk_debug_write_uint(thr, 0); + } } - duk_pop_2(ctx); /* shared pop */ duk_debug_write_eom(thr); } @@ -40550,7 +41829,11 @@ DUK_LOCAL void duk__debug_handle_pause(duk_hthread *thr, duk_heap *heap) { DUK_D(DUK_DPRINT("debug command Pause")); - DUK_HEAP_SET_PAUSED(heap); + if (duk_debug_is_paused(heap)) { + DUK_D(DUK_DPRINT("Pause requested when already paused, ignore")); + } else { + duk_debug_set_paused(heap); + } duk_debug_write_reply(thr); duk_debug_write_eom(thr); } @@ -40558,7 +41841,7 @@ DUK_LOCAL void duk__debug_handle_resume(duk_hthread *thr, duk_heap *heap) { DUK_D(DUK_DPRINT("debug command Resume")); - DUK_HEAP_CLEAR_PAUSED(heap); + duk_debug_clear_paused(heap); duk_debug_write_reply(thr); duk_debug_write_eom(thr); } @@ -40580,7 +41863,7 @@ line = duk_debug_curr_line(thr); if (line > 0) { - DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap); + duk_debug_clear_paused(heap); /* XXX: overlap with fields below; separate macro/helper? */ heap->dbg_step_type = step_type; heap->dbg_step_thread = thr; heap->dbg_step_csindex = thr->callstack_top - 1; @@ -40842,6 +42125,7 @@ /* Read callstack index, if non-null. */ if (duk_debug_peek_byte(thr) == DUK_DBG_IB_NULL) { direct_eval = 0; + level = -1; /* Not needed, but silences warning. */ (void) duk_debug_read_byte(thr); } else { direct_eval = 1; @@ -41084,82 +42368,29 @@ } } -#if defined(DUK_USE_STRTAB_CHAIN) -DUK_LOCAL void duk__debug_dump_strtab_chain(duk_hthread *thr, duk_heap *heap) { - duk_uint_fast32_t i, j; - duk_strtab_entry *e; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t *lst; -#else - duk_hstring **lst; -#endif - duk_hstring *h; - - for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { - e = heap->strtable + i; - if (e->listlen > 0) { -#if defined(DUK_USE_HEAPPTR16) - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); -#else - lst = e->u.strlist; -#endif - DUK_ASSERT(lst != NULL); - - for (j = 0; j < e->listlen; j++) { -#if defined(DUK_USE_HEAPPTR16) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[j]); -#else - h = lst[j]; -#endif - if (h != NULL) { - duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h); - } - } - } else { -#if defined(DUK_USE_HEAPPTR16) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16); -#else - h = e->u.str; -#endif - if (h != NULL) { - duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h); - } - } - } -} -#endif /* DUK_USE_STRTAB_CHAIN */ - -#if defined(DUK_USE_STRTAB_PROBE) -DUK_LOCAL void duk__debug_dump_strtab_probe(duk_hthread *thr, duk_heap *heap) { +DUK_LOCAL void duk__debug_dump_strtab(duk_hthread *thr, duk_heap *heap) { duk_uint32_t i; duk_hstring *h; for (i = 0; i < heap->st_size; i++) { -#if defined(DUK_USE_HEAPPTR16) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); +#if defined(DUK_USE_STRTAB_PTRCOMP) + h = DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, heap->strtable16[i]); #else h = heap->strtable[i]; #endif - if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) { - continue; + while (h != NULL) { + duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h); + h = h->hdr.h_next; } - - duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h); } } -#endif /* DUK_USE_STRTAB_PROBE */ DUK_LOCAL void duk__debug_handle_dump_heap(duk_hthread *thr, duk_heap *heap) { DUK_D(DUK_DPRINT("debug command DumpHeap")); duk_debug_write_reply(thr); duk__debug_dump_heap_allocated(thr, heap); -#if defined(DUK_USE_STRTAB_CHAIN) - duk__debug_dump_strtab_chain(thr, heap); -#endif -#if defined(DUK_USE_STRTAB_PROBE) - duk__debug_dump_strtab_probe(thr, heap); -#endif + duk__debug_dump_strtab(thr, heap); duk_debug_write_eom(thr); } #endif /* DUK_USE_DEBUGGER_DUMPHEAP */ @@ -41297,14 +42528,14 @@ "compfunc", "natfunc", "bufobj", - "thread", + "fastrefs", "array_part", "strict", "notail", "newenv", "namebinding", "createargs", - "envrecclosed", + "have_finalizer", "exotic_array", "exotic_stringobj", "exotic_arguments", @@ -41319,14 +42550,14 @@ DUK_HOBJECT_FLAG_COMPFUNC, DUK_HOBJECT_FLAG_NATFUNC, DUK_HOBJECT_FLAG_BUFOBJ, - DUK_HOBJECT_FLAG_THREAD, + DUK_HOBJECT_FLAG_FASTREFS, DUK_HOBJECT_FLAG_ARRAY_PART, DUK_HOBJECT_FLAG_STRICT, DUK_HOBJECT_FLAG_NOTAIL, DUK_HOBJECT_FLAG_NEWENV, DUK_HOBJECT_FLAG_NAMEBINDING, DUK_HOBJECT_FLAG_CREATEARGS, - DUK_HOBJECT_FLAG_ENVRECCLOSED, + DUK_HOBJECT_FLAG_HAVE_FINALIZER, DUK_HOBJECT_FLAG_EXOTIC_ARRAY, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS, @@ -41374,7 +42605,7 @@ for (;;) { mask = *masks++; - if (!mask) { + if (mask == 0) { break; } key = *keys++; @@ -41456,6 +42687,10 @@ DUK_D(DUK_DPRINT("debug command GetHeapObjInfo")); DUK_UNREF(heap); + DUK_ASSERT(sizeof(duk__debug_getinfo_hstring_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hstring_masks) / sizeof(duk_uint_t) - 1); + DUK_ASSERT(sizeof(duk__debug_getinfo_hobject_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hobject_masks) / sizeof(duk_uint_t) - 1); + DUK_ASSERT(sizeof(duk__debug_getinfo_hbuffer_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hbuffer_masks) / sizeof(duk_uint_t) - 1); + h = duk_debug_read_any_ptr(thr); if (!h) { duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid target"); @@ -41494,9 +42729,9 @@ duk__debug_getinfo_hstring_keys, duk__debug_getinfo_hstring_masks, DUK_HEAPHDR_GET_FLAGS_RAW(h)); - duk__debug_getinfo_prop_uint(thr, "bytelen", DUK_HSTRING_GET_BYTELEN(h_str)); - duk__debug_getinfo_prop_uint(thr, "charlen", DUK_HSTRING_GET_CHARLEN(h_str)); - duk__debug_getinfo_prop_uint(thr, "hash", DUK_HSTRING_GET_HASH(h_str)); + duk__debug_getinfo_prop_uint(thr, "bytelen", (duk_uint_t) DUK_HSTRING_GET_BYTELEN(h_str)); + duk__debug_getinfo_prop_uint(thr, "charlen", (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h_str)); + duk__debug_getinfo_prop_uint(thr, "hash", (duk_uint_t) DUK_HSTRING_GET_HASH(h_str)); duk__debug_getinfo_flags_key(thr, "data"); duk_debug_write_hstring(thr, h_str); break; @@ -41594,6 +42829,26 @@ DUK_UNREF(h_thr); } + if (DUK_HOBJECT_IS_DECENV(h_obj)) { + duk_hdecenv *h_env; + h_env = (duk_hdecenv *) h_obj; + + duk__debug_getinfo_flags_key(thr, "thread"); + duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->thread)); + duk__debug_getinfo_flags_key(thr, "varmap"); + duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->varmap)); + duk__debug_getinfo_prop_uint(thr, "regbase", (duk_uint_t) h_env->regbase); + } + + if (DUK_HOBJECT_IS_OBJENV(h_obj)) { + duk_hobjenv *h_env; + h_env = (duk_hobjenv *) h_obj; + + duk__debug_getinfo_flags_key(thr, "target"); + duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->target)); + duk__debug_getinfo_prop_bool(thr, "has_this", h_env->has_this); + } + #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) { duk_hbufobj *h_bufobj; @@ -42016,12 +43271,13 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)); + DUK_ASSERT(duk_debug_is_attached(thr->heap)); DUK_ASSERT(thr->heap->dbg_processing == 0); + DUK_ASSERT(!duk_debug_is_paused(thr->heap)); - DUK_HEAP_SET_PAUSED(thr->heap); + duk_debug_set_paused(thr->heap); - act = duk_hthread_get_current_activation(thr); + act = thr->callstack_curr; /* NOTE: act may be NULL if an error is thrown outside of any activation, * which may happen in the case of, e.g. syntax errors. @@ -42054,8 +43310,8 @@ thr->heap->dbg_state_dirty = 1; while (DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap)) { - DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)); - DUK_ASSERT(thr->heap->dbg_processing); + DUK_ASSERT(duk_debug_is_attached(thr->heap)); + DUK_ASSERT(thr->heap->dbg_processing == 0); duk_debug_process_messages(thr, 0 /*no_block*/); } @@ -42117,7 +43373,7 @@ DUK_ASSERT(thr != NULL); heap = thr->heap; DUK_ASSERT(heap != NULL); - DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)); + DUK_ASSERT(duk_debug_is_attached(thr->heap)); DUK_ASSERT_DISABLE(breakpoint_index >= 0); /* unsigned */ if (breakpoint_index >= heap->dbg_breakpoint_count) { @@ -42146,6 +43402,55 @@ return 1; } +/* + * Misc state management + */ + +DUK_INTERNAL duk_bool_t duk_debug_is_attached(duk_heap *heap) { + return (heap->dbg_read_cb != NULL); +} + +DUK_INTERNAL duk_bool_t duk_debug_is_paused(duk_heap *heap) { + return (DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) != 0); +} + +DUK_INTERNAL void duk_debug_set_paused(duk_heap *heap) { + if (duk_debug_is_paused(heap)) { + DUK_D(DUK_DPRINT("trying to set paused state when already paused, ignoring")); + } else { + DUK_HEAP_SET_DEBUGGER_PAUSED(heap); + heap->dbg_state_dirty = 1; + duk_debug_clear_step_state(heap); + DUK_ASSERT(heap->ms_running == 0); /* debugger can't be triggered within mark-and-sweep */ + heap->ms_running = 1; /* prevent mark-and-sweep, prevent refzero queueing */ + heap->ms_prevent_count++; + DUK_ASSERT(heap->ms_prevent_count != 0); /* Wrap. */ + DUK_ASSERT(heap->heap_thread != NULL); + } +} + +DUK_INTERNAL void duk_debug_clear_paused(duk_heap *heap) { + if (duk_debug_is_paused(heap)) { + DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap); + heap->dbg_state_dirty = 1; + duk_debug_clear_step_state(heap); + DUK_ASSERT(heap->ms_running == 1); + DUK_ASSERT(heap->ms_prevent_count > 0); + heap->ms_prevent_count--; + heap->ms_running = 0; + DUK_ASSERT(heap->heap_thread != NULL); + } else { + DUK_D(DUK_DPRINT("trying to clear paused state when not paused, ignoring")); + } +} + +DUK_INTERNAL void duk_debug_clear_step_state(duk_heap *heap) { + heap->dbg_step_type = DUK_STEP_TYPE_NONE; + heap->dbg_step_thread = NULL; + heap->dbg_step_csindex = 0; + heap->dbg_step_startline = 0; +} + #else /* DUK_USE_DEBUGGER_SUPPORT */ /* No debugger support. */ @@ -42783,18 +44088,37 @@ 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)); - /* Perform a refzero check before throwing: this catches cases where - * some internal code uses no-refzero (NORZ) macro variants but an - * error occurs before it has the chance to DUK_REFZERO_CHECK_xxx() - * explicitly. Refzero'ed objects would otherwise remain pending - * until the next refzero (which is not a big issue but still). + /* 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_REFZERO_CHECK_SLOW(thr); + + 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 !defined(DUK_USE_CPP_EXCEPTIONS) /* If we don't have a jmpbuf_ptr, there is little we can do except @@ -42893,11 +44217,16 @@ } /* - * Exposed helper for setting up heap longjmp state. + * Helper for debugger throw notify and pause-on-uncaught integration. */ -DUK_INTERNAL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t lj_type) { #if defined(DUK_USE_DEBUGGER_SUPPORT) +#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) +DUK_INTERNAL void duk_err_check_debugger_integration(duk_hthread *thr) { + duk_context *ctx = (duk_context *) thr; + duk_bool_t fatal; + 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 @@ -42905,55 +44234,102 @@ * 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 defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap) && - !thr->heap->dbg_processing && - lj_type == DUK_LJ_TYPE_THROW) { - duk_context *ctx = (duk_context *) thr; - duk_bool_t fatal; - duk_hobject *h_obj; - /* 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. - */ - h_obj = duk_get_hobject(ctx, -1); - if (h_obj == thr->builtins[DUK_BIDX_DOUBLE_ERROR]) { - DUK_D(DUK_DPRINT("built-in DoubleError instance thrown, not intercepting")); - goto skip_throw_intercept; - } + 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; + } + + fatal = !duk__have_active_catcher(thr); - DUK_D(DUK_DPRINT("throw with debugger attached, report to client")); + /* 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(ctx, tv_obj); - fatal = !duk__have_active_catcher(thr); + /* 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_debug_send_throw(thr, fatal); + /* Report it to the debug client */ + DUK_D(DUK_DPRINT("throw with debugger attached, report to client")); + duk_debug_send_throw(thr, fatal); #endif #if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) - if (fatal) { - DUK_D(DUK_DPRINT("throw will be fatal, halt before longjmp")); - duk_debug_halt_execution(thr, 1 /*use_prev_pc*/); - } -#endif + if (fatal) { + DUK_D(DUK_DPRINT("throw will be fatal, halt before longjmp")); + duk_debug_halt_execution(thr, 1 /*use_prev_pc*/); } +#endif - skip_throw_intercept: + /* Restore longjmp state. */ + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + thr->heap->lj.type = DUK_LJ_TYPE_THROW; + tv_obj = DUK_GET_TVAL_NEGIDX(ctx, -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(ctx); +} +#else /* DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT */ +DUK_INTERNAL void duk_err_check_debugger_integration(duk_hthread *thr) { + DUK_UNREF(thr); +} #endif /* DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT */ #endif /* DUK_USE_DEBUGGER_SUPPORT */ - thr->heap->lj.type = lj_type; +/* + * Helpers for setting up heap longjmp state. + */ - DUK_ASSERT(thr->valstack_top > thr->valstack); - DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, thr->valstack_top - 1); /* side effects */ +DUK_INTERNAL void duk_err_setup_ljstate1(duk_hthread *thr, duk_small_uint_t lj_type, duk_tval *tv_val) { + duk_heap *heap; - duk_pop((duk_context *) thr); + 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); } /* * Create and throw an Ecmascript error object based on a code and a message. @@ -42973,7 +44349,7 @@ * * 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->handling_error flag; the recursion + * "double fault" through the heap->creating_error flag; the recursion * then stops at the second level. */ @@ -42983,7 +44359,6 @@ DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code) { #endif duk_context *ctx = (duk_context *) thr; - duk_bool_t double_error = thr->heap->handling_error; #if defined(DUK_USE_VERBOSE_ERRORS) DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld, msg=%s, filename=%s, line=%ld", @@ -42996,18 +44371,11 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT(ctx != NULL); - thr->heap->handling_error = 1; - - if (!double_error) { - /* Allow headroom for calls during error handling (see GH-191). - * We allow space for 10 additional recursions, with one extra - * for, e.g. a print() call at the deepest level. - */ - DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX); - thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11; - } - - DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11); /* just making sure */ + /* 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 @@ -43017,29 +44385,50 @@ /* * 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. */ - /* XXX: if attempt to push beyond allocated valstack, this double fault - * handling fails miserably. We should really write the double error - * directly to thr->heap->lj.value1 and avoid valstack use entirely. - */ - - if (double_error) { - if (thr->builtins[DUK_BIDX_DOUBLE_ERROR]) { - DUK_D(DUK_DPRINT("double fault detected -> push built-in fixed 'double error' instance")); - duk_push_hobject_bidx(ctx, DUK_BIDX_DOUBLE_ERROR); + if (thr->heap->creating_error) { + duk_tval tv_val; + duk_hobject *h_err; + +#if 0 /* XXX: not always true because the second throw may come from a different coroutine */ + DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11); +#endif + thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX; + 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 " - "-> push the error code as a number")); - duk_push_int(ctx, (duk_int_t) code); + "-> 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 { - /* Error object is augmented at its creation here. */ + /* Allow headroom for calls during error handling (see GH-191). + * We allow space for 10 additional recursions, with one extra + * for, e.g. a print() call at the deepest level. + */ +#if 0 /* XXX: not always true, second throw may come from a different coroutine */ + DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX); +#endif + thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11; + thr->heap->creating_error = 1; + duk_require_stack(ctx, 1); - /* XXX: unnecessary '%s' formatting here, but cannot use - * 'msg' as a format string directly. + + /* 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(ctx, @@ -43055,37 +44444,38 @@ 0, NULL); #endif - } - - /* - * Augment error (throw time), unless double error - * - * 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 (double_error) { - DUK_D(DUK_DPRINT("double error: skip throw augmenting to avoid further trouble")); - } else { + /* 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(ctx, -1))); duk_err_augment_error_throw(thr); #endif + + duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(ctx, -1)); + thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX; + 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_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW); - - thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX; /* reset callstack limit */ - thr->heap->handling_error = 0; - DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT, %!iT (after throw augment)", (duk_tval *) &thr->heap->lj.value1, (duk_tval *) &thr->heap->lj.value2)); @@ -43159,8 +44549,8 @@ } res = (duk_hbuffer *) DUK_ALLOC(heap, alloc_size); - if (!res) { - goto error; + if (DUK_UNLIKELY(res == NULL)) { + goto alloc_error; } /* zero everything unless requested not to do so */ @@ -43196,9 +44586,9 @@ #else ptr = DUK_ALLOC(heap, size); #endif - if (!ptr) { + if (DUK_UNLIKELY(ptr == NULL)) { /* Because size > 0, NULL check is correct */ - goto error; + goto alloc_error; } *out_bufdata = ptr; @@ -43234,7 +44624,7 @@ DUK_DDD(DUK_DDDPRINT("allocated hbuffer: %p", (void *) res)); return res; - error: + alloc_error: DUK_DD(DUK_DDPRINT("hbuffer allocation failed")); DUK_FREE(heap, res); @@ -43289,7 +44679,7 @@ */ res = DUK_REALLOC_INDIRECT(thr->heap, duk_hbuffer_get_dynalloc_ptr, (void *) buf, new_size); - if (res != NULL || new_size == 0) { + 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", @@ -43444,11 +44834,9 @@ case DUK_HTYPE_OBJECT: duk_free_hobject(heap, (duk_hobject *) hdr); break; - case DUK_HTYPE_BUFFER: - duk_free_hbuffer(heap, (duk_hbuffer *) hdr); - break; default: - DUK_UNREACHABLE(); + DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) == DUK_HTYPE_BUFFER); + duk_free_hbuffer(heap, (duk_hbuffer *) hdr); } } @@ -43484,23 +44872,8 @@ } } -#if defined(DUK_USE_REFERENCE_COUNTING) -DUK_LOCAL void duk__free_refzero_list(duk_heap *heap) { - duk_heaphdr *curr; - duk_heaphdr *next; - - curr = heap->refzero_list; - while (curr) { - DUK_DDD(DUK_DDDPRINT("FINALFREE (refzero_list): %!iO", - (duk_heaphdr *) curr)); - next = DUK_HEAPHDR_GET_NEXT(heap, curr); - duk_heap_free_heaphdr_raw(heap, curr); - curr = next; - } -} -#endif - -DUK_LOCAL void duk__free_markandsweep_finalize_list(duk_heap *heap) { +#if defined(DUK_USE_FINALIZER_SUPPORT) +DUK_LOCAL void duk__free_finalize_list(duk_heap *heap) { duk_heaphdr *curr; duk_heaphdr *next; @@ -43513,15 +44886,15 @@ curr = next; } } +#endif /* DUK_USE_FINALIZER_SUPPORT */ DUK_LOCAL void duk__free_stringtable(duk_heap *heap) { /* strings are only tracked by stringtable */ - duk_heap_free_strtab(heap); + duk_heap_strtable_free(heap); } #if defined(DUK_USE_FINALIZER_SUPPORT) DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) { - duk_hthread *thr; duk_heaphdr *curr; duk_uint_t round_no; duk_size_t count_all; @@ -43529,25 +44902,31 @@ duk_size_t curr_limit; DUK_ASSERT(heap != NULL); - DUK_ASSERT(heap->heap_thread != NULL); #if defined(DUK_USE_REFERENCE_COUNTING) DUK_ASSERT(heap->refzero_list == NULL); /* refzero not running -> must be empty */ #endif - DUK_ASSERT(heap->finalize_list == NULL); /* mark-and-sweep not running -> must be empty */ + DUK_ASSERT(heap->finalize_list == NULL); /* mark-and-sweep last pass */ - /* XXX: here again finalizer thread is the heap_thread which needs - * to be coordinated with finalizer thread fixes. - */ - thr = heap->heap_thread; - DUK_ASSERT(thr != NULL); + if (heap->heap_thread == NULL) { + /* May happen when heap allocation fails right off. There + * cannot be any finalizable objects in this case. + */ + DUK_D(DUK_DPRINT("no heap_thread in heap destruct, assume no finalizable objects")); + return; + } - /* Prevent mark-and-sweep for the pending finalizers, also prevents - * refzero handling from moving objects away from the heap_allocated - * list. (The flag meaning is slightly abused here.) - */ - DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)); - DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap); + /* Prevent finalize_list processing and mark-and-sweep entirely. + * Setting ms_running = 1 also prevents refzero handling from moving + * objects away from the heap_allocated list (the flag name is a bit + * misleading here). + */ + DUK_ASSERT(heap->pf_prevent_count == 0); + heap->pf_prevent_count = 1; + DUK_ASSERT(heap->ms_running == 0); + heap->ms_running = 1; + DUK_ASSERT(heap->ms_prevent_count == 0); + heap->ms_prevent_count = 1; /* Bump, because mark-and-sweep assumes it's bumped when ms_running is set. */ curr_limit = 0; /* suppress warning, not used */ for (round_no = 0; ; round_no++) { @@ -43556,18 +44935,17 @@ count_finalized = 0; while (curr) { count_all++; - if (DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT) { + if (DUK_HEAPHDR_IS_OBJECT(curr)) { /* Only objects in heap_allocated may have finalizers. Check that * the object itself has a _Finalizer property (own or inherited) * so that we don't execute finalizers for e.g. Proxy objects. */ - DUK_ASSERT(thr != NULL); DUK_ASSERT(curr != NULL); - if (duk_hobject_hasprop_raw(thr, (duk_hobject *) curr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) { + if (DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) curr)) { if (!DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) curr)) { DUK_ASSERT(DUK_HEAP_HAS_FINALIZER_NORESCUE(heap)); /* maps to finalizer 2nd argument */ - duk_hobject_run_finalizer(thr, (duk_hobject *) curr); + duk_heap_run_finalizer(heap, (duk_hobject *) curr); count_finalized++; } } @@ -43608,8 +44986,10 @@ } } - DUK_ASSERT(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)); - DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap); + DUK_ASSERT(heap->ms_running == 1); + heap->ms_running = 0; + DUK_ASSERT(heap->pf_prevent_count == 1); + heap->pf_prevent_count = 0; } #endif /* DUK_USE_FINALIZER_SUPPORT */ @@ -43617,7 +44997,7 @@ DUK_D(DUK_DPRINT("free heap: %p", (void *) heap)); #if defined(DUK_USE_DEBUG) - duk_heap_dump_strtab(heap); + duk_heap_strtable_dump(heap); #endif #if defined(DUK_USE_DEBUGGER_SUPPORT) @@ -43631,32 +45011,47 @@ #endif /* Execute finalizers before freeing the heap, even for reachable - * objects, and regardless of whether or not mark-and-sweep is - * enabled. This gives finalizers the chance to free any native + * objects. This gives finalizers the chance to free any native * resources like file handles, allocations made outside Duktape, * etc. This is quite tricky to get right, so that all finalizer * guarantees are honored. * - * XXX: this perhaps requires an execution time limit. - */ - DUK_D(DUK_DPRINT("execute finalizers before freeing heap")); - /* Run mark-and-sweep a few times just in case (unreachable object + * Run mark-and-sweep a few times just in case (unreachable object * finalizers run already here). The last round must rescue objects * from the previous round without running any more finalizers. This * ensures rescued objects get their FINALIZED flag cleared so that * their finalizer is called once more in forced finalization to * satisfy finalizer guarantees. However, we don't want to run any - * more finalizer because that'd required one more loop, and so on. + * more finalizers because that'd required one more loop, and so on. + * + * XXX: this perhaps requires an execution time limit. */ + DUK_D(DUK_DPRINT("execute finalizers before freeing heap")); + DUK_ASSERT(heap->pf_skip_finalizers == 0); DUK_D(DUK_DPRINT("forced gc #1 in heap destruction")); duk_heap_mark_and_sweep(heap, 0); DUK_D(DUK_DPRINT("forced gc #2 in heap destruction")); duk_heap_mark_and_sweep(heap, 0); DUK_D(DUK_DPRINT("forced gc #3 in heap destruction (don't run finalizers)")); - duk_heap_mark_and_sweep(heap, DUK_MS_FLAG_SKIP_FINALIZERS); /* skip finalizers; queue finalizable objects to heap_allocated */ + heap->pf_skip_finalizers = 1; + duk_heap_mark_and_sweep(heap, 0); /* Skip finalizers; queue finalizable objects to heap_allocated. */ + + /* There are never objects in refzero_list at this point, or at any + * point beyond a DECREF (even a DECREF_NORZ). Since Duktape 2.1 + * refzero_list processing is side effect free, so it is always + * processed to completion by a DECREF initially triggering a zero + * refcount. + */ +#if defined(DUK_USE_REFERENCE_COUNTING) + DUK_ASSERT(heap->refzero_list == NULL); /* Always processed to completion inline. */ +#endif +#if defined(DUK_USE_FINALIZER_SUPPORT) + DUK_ASSERT(heap->finalize_list == NULL); /* Last mark-and-sweep with skip_finalizers. */ +#endif #if defined(DUK_USE_FINALIZER_SUPPORT) - DUK_HEAP_SET_FINALIZER_NORESCUE(heap); /* rescue no longer supported */ + DUK_D(DUK_DPRINT("run finalizers for remaining finalizable objects")); + DUK_HEAP_SET_FINALIZER_NORESCUE(heap); /* Rescue no longer supported. */ duk__free_run_finalizers(heap); #endif /* DUK_USE_FINALIZER_SUPPORT */ @@ -43664,17 +45059,18 @@ * are on the heap allocated list. */ - DUK_D(DUK_DPRINT("freeing heap objects of heap: %p", (void *) heap)); + DUK_D(DUK_DPRINT("freeing heap_allocated of heap: %p", (void *) heap)); duk__free_allocated(heap); #if defined(DUK_USE_REFERENCE_COUNTING) - DUK_D(DUK_DPRINT("freeing refzero list of heap: %p", (void *) heap)); - duk__free_refzero_list(heap); + DUK_ASSERT(heap->refzero_list == NULL); /* Always processed to completion inline. */ +#endif + +#if defined(DUK_USE_FINALIZER_SUPPORT) + DUK_D(DUK_DPRINT("freeing finalize_list of heap: %p", (void *) heap)); + duk__free_finalize_list(heap); #endif - DUK_D(DUK_DPRINT("freeing mark-and-sweep finalize list of heap: %p", (void *) heap)); - duk__free_markandsweep_finalize_list(heap); - DUK_D(DUK_DPRINT("freeing string table of heap: %p", (void *) heap)); duk__free_stringtable(heap); @@ -43695,20 +45091,26 @@ duk_small_uint_t i; #endif + DUK_UNREF(heap); + /* With ROM-based strings, heap->strs[] and thr->strs[] are omitted * so nothing to initialize for strs[]. */ #if defined(DUK_USE_ASSERTIONS) - for (i = 0; i < sizeof(duk_rom_strings) / sizeof(const duk_hstring *); i++) { - duk_uint32_t hash; + for (i = 0; i < sizeof(duk_rom_strings_lookup) / sizeof(const duk_hstring *); i++) { const duk_hstring *h; - h = duk_rom_strings[i]; - DUK_ASSERT(h != NULL); - hash = duk_heap_hashstring(heap, (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); - DUK_DD(DUK_DDPRINT("duk_rom_strings[%d] -> hash 0x%08lx, computed 0x%08lx", - (int) i, (unsigned long) DUK_HSTRING_GET_HASH(h), (unsigned long) hash)); - DUK_ASSERT(hash == (duk_uint32_t) DUK_HSTRING_GET_HASH(h)); + duk_uint32_t hash; + + h = duk_rom_strings_lookup[i]; + while (h != NULL) { + hash = duk_heap_hashstring(heap, (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); + DUK_DD(DUK_DDPRINT("duk_rom_strings_lookup[%d] -> hash 0x%08lx, computed 0x%08lx", + (int) i, (unsigned long) DUK_HSTRING_GET_HASH(h), (unsigned long) hash)); + DUK_ASSERT(hash == (duk_uint32_t) DUK_HSTRING_GET_HASH(h)); + + h = (const duk_hstring *) h->hdr.h_next; + } } #endif return 1; @@ -43736,9 +45138,9 @@ */ DUK_ASSERT(len <= 0xffffUL); DUK_DDD(DUK_DDDPRINT("intern built-in string %ld", (long) i)); - h = duk_heap_string_intern(heap, tmp, len); + h = duk_heap_strtable_intern(heap, tmp, len); if (!h) { - goto error; + goto failed; } DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)); @@ -43773,7 +45175,7 @@ return 1; - error: + failed: return 0; } #endif /* DUK_USE_ROM_STRINGS */ @@ -43781,12 +45183,11 @@ DUK_LOCAL duk_bool_t duk__init_heap_thread(duk_heap *heap) { duk_hthread *thr; - DUK_DD(DUK_DDPRINT("heap init: alloc heap thread")); - thr = duk_hthread_alloc(heap, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_THREAD | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD)); - if (!thr) { + DUK_D(DUK_DPRINT("heap init: alloc heap thread")); + thr = duk_hthread_alloc_unchecked(heap, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD)); + if (thr == NULL) { DUK_D(DUK_DPRINT("failed to alloc heap_thread")); return 0; } @@ -43806,6 +45207,7 @@ /* 'thr' is now reachable */ + DUK_D(DUK_DPRINT("heap init: init heap thread stacks")); if (!duk_hthread_init_stacks(heap, thr)) { return 0; } @@ -43924,6 +45326,8 @@ DUK__DUMPSZ(duk_harray); DUK__DUMPSZ(duk_hcompfunc); DUK__DUMPSZ(duk_hnatfunc); + DUK__DUMPSZ(duk_hdecenv); + DUK__DUMPSZ(duk_hobjenv); DUK__DUMPSZ(duk_hthread); #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) DUK__DUMPSZ(duk_hbufobj); @@ -43936,9 +45340,6 @@ DUK__DUMPSZ(duk_propvalue); DUK__DUMPSZ(duk_propdesc); DUK__DUMPSZ(duk_heap); -#if defined(DUK_USE_STRTAB_CHAIN) - DUK__DUMPSZ(duk_strtab_entry); -#endif DUK__DUMPSZ(duk_activation); DUK__DUMPSZ(duk_catcher); DUK__DUMPSZ(duk_strcache); @@ -44047,10 +45448,21 @@ void *heap_udata, duk_fatal_function fatal_func) { duk_heap *res = NULL; + duk_uint32_t st_initsize; DUK_D(DUK_DPRINT("allocate heap")); /* + * Random config sanity asserts + */ + + DUK_ASSERT(DUK_USE_STRTAB_MINSIZE >= 64); + + DUK_ASSERT((DUK_HTYPE_STRING & 0x01U) == 0); + DUK_ASSERT((DUK_HTYPE_BUFFER & 0x01U) == 0); + DUK_ASSERT((DUK_HTYPE_OBJECT & 0x01U) == 1); /* DUK_HEAPHDR_IS_OBJECT() relies ont his. */ + + /* * Debug dump type sizes */ @@ -44065,9 +45477,11 @@ */ #if defined(DUK_USE_SELF_TESTS) + DUK_D(DUK_DPRINT("run self tests")); if (duk_selftest_run_tests(alloc_func, realloc_func, free_func, heap_udata) > 0) { fatal_func(heap_udata, "self test(s) failed"); } + DUK_D(DUK_DPRINT("self tests passed")); #endif /* @@ -44124,9 +45538,13 @@ * Use a raw call, all macros expect the heap to be initialized */ +#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 1) + goto failed; +#endif + DUK_D(DUK_DPRINT("alloc duk_heap object")); res = (duk_heap *) alloc_func(heap_udata, sizeof(duk_heap)); if (!res) { - goto error; + goto failed; } /* @@ -44134,6 +45552,9 @@ */ DUK_MEMZERO(res, sizeof(*res)); +#if defined(DUK_USE_ASSERTIONS) + res->heap_initializing = 1; +#endif /* explicit NULL inits */ #if defined(DUK_USE_EXPLICIT_NULL_INIT) @@ -44141,20 +45562,20 @@ res->heap_allocated = NULL; #if defined(DUK_USE_REFERENCE_COUNTING) res->refzero_list = NULL; - res->refzero_list_tail = NULL; #endif +#if defined(DUK_USE_FINALIZER_SUPPORT) res->finalize_list = NULL; +#if defined(DUK_USE_ASSERTIONS) + res->currently_finalizing = NULL; +#endif +#endif res->heap_thread = NULL; res->curr_thread = NULL; res->heap_object = NULL; -#if defined(DUK_USE_STRTAB_CHAIN) - /* nothing to NULL */ -#elif defined(DUK_USE_STRTAB_PROBE) -#if defined(DUK_USE_HEAPPTR16) - res->strtable16 = (duk_uint16_t *) NULL; +#if defined(DUK_USE_STRTAB_PTRCOMP) + res->strtable16 = NULL; #else - res->strtable = (duk_hstring **) NULL; -#endif + res->strtable = NULL; #endif #if defined(DUK_USE_ROM_STRINGS) /* no res->strs[] */ @@ -44188,13 +45609,21 @@ res->heap_udata = heap_udata; res->fatal_func = fatal_func; -#if defined(DUK_USE_HEAPPTR16) - /* XXX: zero assumption */ - res->heapptr_null16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) NULL); - res->heapptr_deleted16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) DUK_STRTAB_DELETED_MARKER(res)); -#endif + /* XXX: for now there's a pointer packing zero assumption, i.e. + * NULL <=> compressed pointer 0. If this is removed, may need + * to precompute e.g. null16 here. + */ - /* res->mark_and_sweep_trigger_counter == 0 -> now causes immediate GC; which is OK */ + /* res->ms_trigger_counter == 0 -> now causes immediate GC; which is OK */ + + /* Prevent mark-and-sweep and finalizer execution until heap is completely + * initialized. + */ + DUK_ASSERT(res->ms_prevent_count == 0); + DUK_ASSERT(res->pf_prevent_count == 0); + res->ms_prevent_count = 1; + res->pf_prevent_count = 1; + DUK_ASSERT(res->ms_running == 0); res->call_recursion_depth = 0; res->call_recursion_limit = DUK_USE_NATIVE_CALL_RECLIMIT; @@ -44222,71 +45651,49 @@ res->lj.jmpbuf_ptr = NULL; #endif DUK_ASSERT(res->lj.type == DUK_LJ_TYPE_UNKNOWN); /* zero */ - + DUK_ASSERT(res->lj.iserror == 0); DUK_TVAL_SET_UNDEFINED(&res->lj.value1); DUK_TVAL_SET_UNDEFINED(&res->lj.value2); -#if (DUK_STRTAB_INITIAL_SIZE < DUK_UTIL_MIN_HASH_PRIME) -#error initial heap stringtable size is defined incorrectly -#endif + DUK_ASSERT_LJSTATE_UNSET(res); /* * Init stringtable: fixed variant */ -#if defined(DUK_USE_STRTAB_CHAIN) - DUK_MEMZERO(res->strtable, sizeof(duk_strtab_entry) * DUK_STRTAB_CHAIN_SIZE); -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - { - duk_small_uint_t i; - for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { -#if defined(DUK_USE_HEAPPTR16) - res->strtable[i].u.str16 = res->heapptr_null16; + st_initsize = DUK_USE_STRTAB_MINSIZE; +#if defined(DUK_USE_STRTAB_PTRCOMP) + res->strtable16 = (duk_uint16_t *) alloc_func(heap_udata, sizeof(duk_uint16_t) * st_initsize); + if (res->strtable16 == NULL) { + goto failed; + } #else - res->strtable[i].u.str = NULL; -#endif - } + res->strtable = (duk_hstring **) alloc_func(heap_udata, sizeof(duk_hstring *) * st_initsize); + if (res->strtable == NULL) { + goto failed; } -#endif /* DUK_USE_EXPLICIT_NULL_INIT */ -#endif /* DUK_USE_STRTAB_CHAIN */ - - /* - * Init stringtable: probe variant - */ +#endif + res->st_size = st_initsize; + res->st_mask = st_initsize - 1; +#if (DUK_USE_STRTAB_MINSIZE != DUK_USE_STRTAB_MAXSIZE) + DUK_ASSERT(res->st_count == 0); +#endif -#if defined(DUK_USE_STRTAB_PROBE) -#if defined(DUK_USE_HEAPPTR16) - res->strtable16 = (duk_uint16_t *) alloc_func(heap_udata, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE); - if (!res->strtable16) { - goto error; - } -#else /* DUK_USE_HEAPPTR16 */ - res->strtable = (duk_hstring **) alloc_func(heap_udata, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE); - if (!res->strtable) { - goto error; - } -#endif /* DUK_USE_HEAPPTR16 */ - res->st_size = DUK_STRTAB_INITIAL_SIZE; +#if defined(DUK_USE_STRTAB_PTRCOMP) + /* zero assumption */ + DUK_MEMZERO(res->strtable16, sizeof(duk_uint16_t) * st_initsize); +#else #if defined(DUK_USE_EXPLICIT_NULL_INIT) { duk_small_uint_t i; - DUK_ASSERT(res->st_size == DUK_STRTAB_INITIAL_SIZE); - for (i = 0; i < DUK_STRTAB_INITIAL_SIZE; i++) { -#if defined(DUK_USE_HEAPPTR16) - res->strtable16[i] = res->heapptr_null16; -#else + for (i = 0; i < st_initsize; i++) { res->strtable[i] = NULL; -#endif } } -#else /* DUK_USE_EXPLICIT_NULL_INIT */ -#if defined(DUK_USE_HEAPPTR16) - DUK_MEMZERO(res->strtable16, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE); #else - DUK_MEMZERO(res->strtable, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE); -#endif + DUK_MEMZERO(res->strtable, sizeof(duk_hstring *) * st_initsize); #endif /* DUK_USE_EXPLICIT_NULL_INIT */ -#endif /* DUK_USE_STRTAB_PROBE */ +#endif /* DUK_USE_STRTAB_PTRCOMP */ /* * Init stringcache @@ -44311,30 +45718,40 @@ * Init built-in strings */ - DUK_DD(DUK_DDPRINT("HEAP: INIT STRINGS")); +#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 2) + goto failed; +#endif + DUK_D(DUK_DPRINT("heap init: initialize heap strings")); if (!duk__init_heap_strings(res)) { - goto error; + goto failed; } /* * Init the heap thread */ - DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP THREAD")); +#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 3) + goto failed; +#endif + DUK_D(DUK_DPRINT("heap init: initialize heap thread")); if (!duk__init_heap_thread(res)) { - goto error; + goto failed; } /* * Init the heap object */ - DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP OBJECT")); +#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 4) + goto failed; +#endif + DUK_D(DUK_DPRINT("heap init: initialize heap object")); DUK_ASSERT(res->heap_thread != NULL); - res->heap_object = duk_hobject_alloc(res, DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT)); - if (!res->heap_object) { - goto error; + res->heap_object = duk_hobject_alloc_unchecked(res, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT)); + if (res->heap_object == NULL) { + goto failed; } DUK_HOBJECT_INCREF(res->heap_thread, res->heap_object); @@ -44381,24 +45798,50 @@ #endif /* - * All done + * Allow finalizer and mark-and-sweep processing. + */ + + DUK_D(DUK_DPRINT("heap init: allow finalizer/mark-and-sweep processing")); + DUK_ASSERT(res->ms_prevent_count == 1); + DUK_ASSERT(res->pf_prevent_count == 1); + res->ms_prevent_count = 0; + res->pf_prevent_count = 0; + DUK_ASSERT(res->ms_running == 0); +#if defined(DUK_USE_ASSERTIONS) + res->heap_initializing = 0; +#endif + + /* + * All done. */ DUK_D(DUK_DPRINT("allocated heap: %p", (void *) res)); return res; - error: + failed: DUK_D(DUK_DPRINT("heap allocation failed")); - if (res) { - /* assumes that allocated pointers and alloc funcs are valid - * if res exists + if (res != NULL) { + /* Assumes that allocated pointers and alloc funcs are valid + * if res exists. */ + DUK_ASSERT(res->ms_prevent_count == 1); + DUK_ASSERT(res->pf_prevent_count == 1); + DUK_ASSERT(res->ms_running == 0); + if (res->heap_thread != NULL) { + res->ms_prevent_count = 0; + res->pf_prevent_count = 0; + } +#if defined(DUK_USE_ASSERTIONS) + res->heap_initializing = 0; +#endif + DUK_ASSERT(res->alloc_func != NULL); DUK_ASSERT(res->realloc_func != NULL); DUK_ASSERT(res->free_func != NULL); duk_heap_free(res); } + return NULL; } @@ -44410,6 +45853,455 @@ #undef DUK__DUMPSZ #undef DUK__FIXED_HASH_SEED /* + * Finalizer handling. + */ + +/* #include duk_internal.h -> already included */ + +#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_context *ctx) { + DUK_DD(DUK_DDPRINT("fake global torture finalizer executed")); + + /* Require a lot of stack to force a value stack grow/shrink. */ + duk_require_stack(ctx, 100000); + + /* Force a reallocation with pointer change for value, call, and + * catch stacks to maximize side effects. + */ + duk_hthread_valstack_torture_realloc((duk_hthread *) ctx); + duk_hthread_callstack_torture_realloc((duk_hthread *) ctx); + duk_hthread_catchstack_torture_realloc((duk_hthread *) ctx); + + /* Inner function call, error throw. */ + duk_eval_string_noresult(ctx, + "(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 has been reached. + * Otherwise a callstack limit error will be created, then refzero'ed. + */ + if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit || + thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) { + DUK_D(DUK_DPRINT("skip global torture finalizer because of call recursion or call stack size limit")); + return; + } + + /* Run fake finalizer. Avoid creating unnecessary garbage. */ + duk_push_c_function((duk_context *) thr, duk__fake_global_finalizer, 0 /*nargs*/); + (void) duk_pcall((duk_context *) thr, 0 /*nargs*/); + duk_pop((duk_context *) 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); + DUK_ASSERT(heap->heap_thread->callstack != NULL); + DUK_ASSERT(heap->heap_thread->catchstack != 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_context *ctx, void *udata) { + duk_hthread *thr; + + DUK_ASSERT(ctx != NULL); + thr = (duk_hthread *) ctx; + 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(ctx, -1, DUK_STRIDX_INT_FINALIZER); /* -> [... obj finalizer] */ + duk_dup_m2(ctx); + duk_push_boolean(ctx, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap)); + DUK_DDD(DUK_DDDPRINT("calling finalizer")); + duk_call(ctx, 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_context *ctx; + 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); + ctx = (duk_context *) 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(ctx); +#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 (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(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; + } + + duk_push_hobject(ctx, obj); /* this also increases refcount by one */ + rc = duk_safe_call(ctx, duk__finalize_helper, NULL /*udata*/, 0 /*nargs*/, 1 /*nrets*/); /* -> [... obj retval/error] */ + DUK_ASSERT_TOP(ctx, 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(ctx, -1))); + } + duk_pop_2(ctx); /* -> [...] */ + + DUK_ASSERT_TOP(ctx, entry_top); +} + +#else /* DUK_USE_FINALIZER_SUPPORT */ + +/* nothing */ + +#endif /* DUK_USE_FINALIZER_SUPPORT */ +/* * String hash computation (interning). * * String hashing is performance critical because a string hash is computed @@ -44540,22 +46432,7 @@ DUK_LOCAL_DECL void duk__mark_tval(duk_heap *heap, duk_tval *tv); /* - * Misc - */ - -/* Select a thread for mark-and-sweep use. - * - * XXX: This needs to change later. - */ -DUK_LOCAL duk_hthread *duk__get_temp_hthread(duk_heap *heap) { - if (heap->curr_thread) { - return heap->curr_thread; - } - return heap->heap_thread; /* may be NULL, too */ -} - -/* - * Marking functions for heap types: mark children recursively + * Marking functions for heap types: mark children recursively. */ DUK_LOCAL void duk__mark_hstring(duk_heap *heap, duk_hstring *h) { @@ -44579,7 +46456,7 @@ for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) { duk_hstring *key = DUK_HOBJECT_E_GET_KEY(heap, h, i); - if (!key) { + if (key == NULL) { continue; } duk__mark_heaphdr(heap, (duk_heaphdr *) key); @@ -44595,15 +46472,19 @@ duk__mark_tval(heap, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i)); } - /* hash part is a 'weak reference' and does not contribute */ + /* Hash part is a 'weak reference' and does not contribute. */ duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h)); - /* XXX: rearrange bits to allow a switch case to be used here? */ - /* XXX: add a fast path for objects (and arrays)? */ - /* DUK_HOBJECT_IS_ARRAY(h): needs no special handling now as there are - * no extra fields in need of marking. + /* Fast path for objects which don't have a subclass struct, or have a + * subclass struct but nothing that needs marking in the subclass struct. */ + if (DUK_HOBJECT_HAS_FASTREFS(h)) { + DUK_ASSERT(DUK_HOBJECT_ALLOWS_FASTREFS(h)); + return; + } + DUK_ASSERT(DUK_HOBJECT_PROHIBITS_FASTREFS(h)); + if (DUK_HOBJECT_IS_COMPFUNC(h)) { duk_hcompfunc *f = (duk_hcompfunc *) h; duk_tval *tv, *tv_end; @@ -44635,16 +46516,21 @@ /* May happen in some out-of-memory corner cases. */ DUK_D(DUK_DPRINT("duk_hcompfunc 'data' is NULL, skipping marking")); } - } else if (DUK_HOBJECT_IS_NATFUNC(h)) { - duk_hnatfunc *f = (duk_hnatfunc *) h; - DUK_UNREF(f); - /* nothing to mark */ #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) } else if (DUK_HOBJECT_IS_BUFOBJ(h)) { duk_hbufobj *b = (duk_hbufobj *) h; duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf); duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf_prop); #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + } else if (DUK_HOBJECT_IS_DECENV(h)) { + duk_hdecenv *e = (duk_hdecenv *) h; + DUK_ASSERT_HDECENV_VALID(e); + duk__mark_heaphdr(heap, (duk_heaphdr *) e->thread); + duk__mark_heaphdr(heap, (duk_heaphdr *) e->varmap); + } else if (DUK_HOBJECT_IS_OBJENV(h)) { + duk_hobjenv *e = (duk_hobjenv *) h; + DUK_ASSERT_HOBJENV_VALID(e); + duk__mark_heaphdr(heap, (duk_heaphdr *) e->target); } else if (DUK_HOBJECT_IS_THREAD(h)) { duk_hthread *t = (duk_hthread *) h; duk_tval *tv; @@ -44673,19 +46559,25 @@ duk__mark_heaphdr(heap, (duk_heaphdr *) t->resumer); - /* XXX: duk_small_uint_t would be enough for this loop */ for (i = 0; i < DUK_NUM_BUILTINS; i++) { duk__mark_heaphdr(heap, (duk_heaphdr *) t->builtins[i]); } + } 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); } } -/* recursion tracking happens here only */ +/* Mark any duk_heaphdr type. Recursion tracking happens only here. */ DUK_LOCAL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h) { DUK_DDD(DUK_DDDPRINT("duk__mark_heaphdr %p, type %ld", (void *) h, (h != NULL ? (long) DUK_HEAPHDR_GET_TYPE(h) : (long) -1))); - if (!h) { + if (h == NULL) { return; } #if defined(DUK_USE_ROM_OBJECTS) @@ -44694,21 +46586,24 @@ return; } #endif +#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) + h->h_assert_refcount++; /* Comparison refcount: bump even if already reachable. */ +#endif if (DUK_HEAPHDR_HAS_REACHABLE(h)) { DUK_DDD(DUK_DDDPRINT("already marked reachable, skip")); return; } DUK_HEAPHDR_SET_REACHABLE(h); - if (heap->mark_and_sweep_recursion_depth >= DUK_USE_MARK_AND_SWEEP_RECLIMIT) { - /* log this with a normal debug level because this should be relatively rare */ + if (heap->ms_recursion_depth >= DUK_USE_MARK_AND_SWEEP_RECLIMIT) { DUK_D(DUK_DPRINT("mark-and-sweep recursion limit reached, marking as temproot: %p", (void *) h)); DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap); DUK_HEAPHDR_SET_TEMPROOT(h); return; } - heap->mark_and_sweep_recursion_depth++; + heap->ms_recursion_depth++; + DUK_ASSERT(heap->ms_recursion_depth != 0); /* Wrap. */ switch (DUK_HEAPHDR_GET_TYPE(h)) { case DUK_HTYPE_STRING: @@ -44725,12 +46620,13 @@ DUK_UNREACHABLE(); } - heap->mark_and_sweep_recursion_depth--; + DUK_ASSERT(heap->ms_recursion_depth > 0); + heap->ms_recursion_depth--; } DUK_LOCAL void duk__mark_tval(duk_heap *heap, duk_tval *tv) { DUK_DDD(DUK_DDDPRINT("duk__mark_tval %p", (void *) tv)); - if (!tv) { + if (tv == NULL) { return; } if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { @@ -44766,37 +46662,12 @@ } /* - * Mark refzero_list objects. - * - * Objects on the refzero_list have no inbound references. They might have - * outbound references to objects that we might free, which would invalidate - * any references held by the refzero objects. A refzero object might also - * be rescued by refcount finalization. Refzero objects are treated as - * reachability roots to ensure they (or anything they point to) are not - * freed in mark-and-sweep. - */ - -#if defined(DUK_USE_REFERENCE_COUNTING) -DUK_LOCAL void duk__mark_refzero_list(duk_heap *heap) { - duk_heaphdr *hdr; - - DUK_DD(DUK_DDPRINT("duk__mark_refzero_list: %p", (void *) heap)); - - hdr = heap->refzero_list; - while (hdr) { - duk__mark_heaphdr(heap, hdr); - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -} -#endif - -/* * Mark unreachable, finalizable objects. * - * Such objects will be moved aside and their finalizers run later. They have - * to be treated as reachability roots for their properties etc to remain - * allocated. This marking is only done for unreachable values which would - * be swept later (refzero_list is thus excluded). + * Such objects will be moved aside and their finalizers run later. They + * have to be treated as reachability roots for their properties etc to + * remain allocated. This marking is only done for unreachable values which + * would be swept later. * * Objects are first marked FINALIZABLE and only then marked as reachability * roots; otherwise circular references might be handled inconsistently. @@ -44804,32 +46675,30 @@ #if defined(DUK_USE_FINALIZER_SUPPORT) DUK_LOCAL void duk__mark_finalizable(duk_heap *heap) { - duk_hthread *thr; duk_heaphdr *hdr; duk_size_t count_finalizable = 0; DUK_DD(DUK_DDPRINT("duk__mark_finalizable: %p", (void *) heap)); - thr = duk__get_temp_hthread(heap); - DUK_ASSERT(thr != NULL); + DUK_ASSERT(heap->heap_thread != NULL); hdr = heap->heap_allocated; - while (hdr) { - /* A finalizer is looked up from the object and up its prototype chain - * (which allows inherited finalizers). A prototype loop must not cause - * an error to be thrown here; duk_hobject_hasprop_raw() will ignore a - * prototype loop silently and indicate that the property doesn't exist. + while (hdr != NULL) { + /* A finalizer is looked up from the object and up its + * prototype chain (which allows inherited finalizers). + * The finalizer is checked for using a duk_hobject flag + * which is kept in sync with the presence and callability + * of a _Finalizer hidden symbol. */ if (!DUK_HEAPHDR_HAS_REACHABLE(hdr) && - DUK_HEAPHDR_GET_TYPE(hdr) == DUK_HTYPE_OBJECT && + DUK_HEAPHDR_IS_OBJECT(hdr) && !DUK_HEAPHDR_HAS_FINALIZED(hdr) && - duk_hobject_hasprop_raw(thr, (duk_hobject *) hdr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) { - + DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) hdr)) { /* heaphdr: * - is not reachable * - is an object - * - is not a finalized object + * - is not a finalized object waiting for rescue/keep decision * - has a finalizer */ @@ -44839,7 +46708,7 @@ (void *) hdr)); DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr)); DUK_HEAPHDR_SET_FINALIZABLE(hdr); - count_finalizable ++; + count_finalizable++; } hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); @@ -44853,7 +46722,7 @@ (long) count_finalizable)); hdr = heap->heap_allocated; - while (hdr) { + while (hdr != NULL) { if (DUK_HEAPHDR_HAS_FINALIZABLE(hdr)) { duk__mark_heaphdr(heap, hdr); } @@ -44867,7 +46736,6 @@ /* * Mark objects on finalize_list. - * */ #if defined(DUK_USE_FINALIZER_SUPPORT) @@ -44880,7 +46748,7 @@ DUK_DD(DUK_DDPRINT("duk__mark_finalize_list: %p", (void *) heap)); hdr = heap->finalize_list; - while (hdr) { + while (hdr != NULL) { duk__mark_heaphdr(heap, hdr); hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); #if defined(DUK_USE_DEBUG) @@ -44900,15 +46768,18 @@ /* * Fallback marking handler if recursion limit is reached. * - * Iterates 'temproots' until recursion limit is no longer hit. Note - * that temproots may reside either in heap allocated list or the - * refzero work list. This is a slow scan, but guarantees that we - * finish with a bounded C stack. - * - * Note that nodes may have been marked as temproots before this - * scan begun, OR they may have been marked during the scan (as - * we process nodes recursively also during the scan). This is - * intended behavior. + * Iterates 'temproots' until recursion limit is no longer hit. Temproots + * can be in heap_allocated or finalize_list; refzero_list is now always + * empty for mark-and-sweep. A temproot may occur in finalize_list now if + * there are objects on the finalize_list and user code creates a reference + * from an object in heap_allocated to the object in finalize_list (which is + * now allowed), and it happened to coincide with the recursion depth limit. + * + * This is a slow scan, but guarantees that we finish with a bounded C stack. + * + * Note that nodes may have been marked as temproots before this scan begun, + * OR they may have been marked during the scan (as we process nodes + * recursively also during the scan). This is intended behavior. */ #if defined(DUK_USE_DEBUG) @@ -44923,7 +46794,10 @@ DUK_DDD(DUK_DDDPRINT("found a temp root: %p", (void *) hdr)); DUK_HEAPHDR_CLEAR_TEMPROOT(hdr); - DUK_HEAPHDR_CLEAR_REACHABLE(hdr); /* done so that duk__mark_heaphdr() works correctly */ + DUK_HEAPHDR_CLEAR_REACHABLE(hdr); /* Done so that duk__mark_heaphdr() works correctly. */ +#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) + hdr->h_assert_refcount--; /* Same node visited twice. */ +#endif duk__mark_heaphdr(heap, hdr); #if defined(DUK_USE_DEBUG) @@ -44957,9 +46831,8 @@ hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); } - /* must also check refzero_list */ -#if defined(DUK_USE_REFERENCE_COUNTING) - hdr = heap->refzero_list; +#if defined(DUK_USE_FINALIZER_SUPPORT) + hdr = heap->finalize_list; while (hdr) { #if defined(DUK_USE_DEBUG) duk__handle_temproot(heap, hdr, &count); @@ -44968,7 +46841,7 @@ #endif hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); } -#endif /* DUK_USE_REFERENCE_COUNTING */ +#endif #if defined(DUK_USE_DEBUG) DUK_DD(DUK_DDPRINT("temproot mark heap scan processed %ld temp roots", (long) count)); @@ -44987,14 +46860,11 @@ #if defined(DUK_USE_REFERENCE_COUNTING) DUK_LOCAL void duk__finalize_refcounts(duk_heap *heap) { - duk_hthread *thr; duk_heaphdr *hdr; - thr = duk__get_temp_hthread(heap); - DUK_ASSERT(thr != NULL); + DUK_ASSERT(heap->heap_thread != NULL); - DUK_DD(DUK_DDPRINT("duk__finalize_refcounts: heap=%p, hthread=%p", - (void *) heap, (void *) thr)); + DUK_DD(DUK_DDPRINT("duk__finalize_refcounts: heap=%p", (void *) heap)); hdr = heap->heap_allocated; while (hdr) { @@ -45010,37 +46880,21 @@ */ DUK_DDD(DUK_DDDPRINT("unreachable object, refcount finalize before sweeping: %p", (void *) hdr)); - duk_heaphdr_refcount_finalize(thr, hdr); - } - - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -} -#endif /* DUK_USE_REFERENCE_COUNTING */ - -/* - * Clear (reachable) flags of refzero work list. - */ -#if defined(DUK_USE_REFERENCE_COUNTING) -DUK_LOCAL void duk__clear_refzero_list_flags(duk_heap *heap) { - duk_heaphdr *hdr; - - DUK_DD(DUK_DDPRINT("duk__clear_refzero_list_flags: %p", (void *) heap)); + /* Finalize using heap->heap_thread; DECREF has a + * suppress check for mark-and-sweep which is based + * on heap->ms_running. + */ + duk_heaphdr_refcount_finalize_norz(heap, hdr); + } - hdr = heap->refzero_list; - while (hdr) { - DUK_HEAPHDR_CLEAR_REACHABLE(hdr); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr)); hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); } } #endif /* DUK_USE_REFERENCE_COUNTING */ /* - * Clear (reachable) flags of finalize_list + * Clear (reachable) flags of finalize_list. * * We could mostly do in the sweep phase when we move objects from the * heap into the finalize_list. However, if a finalizer run is skipped @@ -45059,8 +46913,11 @@ hdr = heap->finalize_list; while (hdr) { DUK_HEAPHDR_CLEAR_REACHABLE(hdr); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr)); +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(hdr) || \ + (heap->currently_finalizing == hdr)); +#endif + /* DUK_HEAPHDR_FLAG_FINALIZED may be set. */ DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr)); hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); } @@ -45068,191 +46925,85 @@ #endif /* DUK_USE_FINALIZER_SUPPORT */ /* - * Sweep stringtable + * Sweep stringtable. */ -#if defined(DUK_USE_STRTAB_CHAIN) - -/* XXX: skip count_free w/o debug? */ -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL void duk__sweep_string_chain16(duk_heap *heap, duk_uint16_t *slot, duk_size_t *count_keep, duk_size_t *count_free) { - duk_uint16_t h16 = *slot; +DUK_LOCAL void duk__sweep_stringtable(duk_heap *heap, duk_size_t *out_count_keep) { duk_hstring *h; - duk_uint16_t null16 = heap->heapptr_null16; - - if (h16 == null16) { - /* nop */ - return; - } - h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, h16); - DUK_ASSERT(h != NULL); - - if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) { - DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h); - (*count_keep)++; - } else { -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0); -#endif - /* deal with weak references first */ - duk_heap_strcache_string_remove(heap, (duk_hstring *) h); - *slot = null16; - - /* free inner references (these exist e.g. when external - * strings are enabled) - */ - duk_free_hstring(heap, h); - (*count_free)++; - } -} -#else /* DUK_USE_HEAPPTR16 */ -DUK_LOCAL void duk__sweep_string_chain(duk_heap *heap, duk_hstring **slot, duk_size_t *count_keep, duk_size_t *count_free) { - duk_hstring *h = *slot; - - if (h == NULL) { - /* nop */ - return; - } - - if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) { - DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h); - (*count_keep)++; - } else { -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0); -#endif - /* deal with weak references first */ - duk_heap_strcache_string_remove(heap, (duk_hstring *) h); - *slot = NULL; - - /* free inner references (these exist e.g. when external - * strings are enabled) - */ - duk_free_hstring(heap, h); - (*count_free)++; - } -} -#endif /* DUK_USE_HEAPPTR16 */ - -DUK_LOCAL void duk__sweep_stringtable_chain(duk_heap *heap, duk_size_t *out_count_keep) { - duk_strtab_entry *e; - duk_uint_fast32_t i; + duk_hstring *prev; + duk_uint32_t i; +#if defined(DUK_USE_DEBUG) duk_size_t count_free = 0; - duk_size_t count_keep = 0; - duk_size_t j, n; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t *lst; -#else - duk_hstring **lst; #endif + duk_size_t count_keep = 0; DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap)); - /* Non-zero refcounts should not happen for unreachable strings, - * because we refcount finalize all unreachable objects which - * should have decreased unreachable string refcounts to zero - * (even for cycles). - */ - - for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { - e = heap->strtable + i; - if (e->listlen == 0) { -#if defined(DUK_USE_HEAPPTR16) - duk__sweep_string_chain16(heap, &e->u.str16, &count_keep, &count_free); -#else - duk__sweep_string_chain(heap, &e->u.str, &count_keep, &count_free); -#endif - } else { -#if defined(DUK_USE_HEAPPTR16) - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); -#else - lst = e->u.strlist; -#endif - for (j = 0, n = e->listlen; j < n; j++) { -#if defined(DUK_USE_HEAPPTR16) - duk__sweep_string_chain16(heap, lst + j, &count_keep, &count_free); +#if defined(DUK_USE_STRTAB_PTRCOMP) + if (heap->strtable16 == NULL) { #else - duk__sweep_string_chain(heap, lst + j, &count_keep, &count_free); + if (heap->strtable == NULL) { #endif - } - } + goto done; } - DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept", - (long) count_free, (long) count_keep)); - *out_count_keep = count_keep; -} -#endif /* DUK_USE_STRTAB_CHAIN */ - -#if defined(DUK_USE_STRTAB_PROBE) -DUK_LOCAL void duk__sweep_stringtable_probe(duk_heap *heap, duk_size_t *out_count_keep) { - duk_hstring *h; - duk_uint_fast32_t i; -#if defined(DUK_USE_DEBUG) - duk_size_t count_free = 0; -#endif - duk_size_t count_keep = 0; - - DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap)); - for (i = 0; i < heap->st_size; i++) { -#if defined(DUK_USE_HEAPPTR16) - h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); +#if defined(DUK_USE_STRTAB_PTRCOMP) + h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); #else h = heap->strtable[i]; #endif - if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) { - continue; - } else if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) { - DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h); - count_keep++; - continue; - } - + prev = NULL; + while (h != NULL) { + duk_hstring *next; + next = h->hdr.h_next; + + if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) { + DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h); + count_keep++; + prev = h; + } else { #if defined(DUK_USE_DEBUG) - count_free++; + count_free++; #endif #if defined(DUK_USE_REFERENCE_COUNTING) - /* Non-zero refcounts should not happen for unreachable strings, - * because we refcount finalize all unreachable objects which - * should have decreased unreachable string refcounts to zero - * (even for cycles). - */ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0); + /* Non-zero refcounts should not happen for unreachable strings, + * because we refcount finalize all unreachable objects which + * should have decreased unreachable string refcounts to zero + * (even for cycles). + */ + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0); #endif - DUK_DDD(DUK_DDDPRINT("sweep string, not reachable: %p", (void *) h)); + /* Deal with weak references first. */ + duk_heap_strcache_string_remove(heap, (duk_hstring *) h); - /* deal with weak references first */ - duk_heap_strcache_string_remove(heap, (duk_hstring *) h); + /* Remove the string from the string table. */ + duk_heap_strtable_unlink_prev(heap, (duk_hstring *) h, (duk_hstring *) prev); - /* remove the string (mark DELETED), could also call - * duk_heap_string_remove() but that would be slow and - * pointless because we already know the slot. - */ -#if defined(DUK_USE_HEAPPTR16) - heap->strtable16[i] = heap->heapptr_deleted16; -#else - heap->strtable[i] = DUK_STRTAB_DELETED_MARKER(heap); -#endif + /* Free inner references (these exist e.g. when external + * strings are enabled) and the struct itself. + */ + duk_free_hstring(heap, (duk_hstring *) h); - /* free inner references (these exist e.g. when external - * strings are enabled) and the struct itself. - */ - duk_free_hstring(heap, (duk_hstring *) h); + /* Don't update 'prev'; it should be last string kept. */ + } + + h = next; + } } + done: #if defined(DUK_USE_DEBUG) DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept", (long) count_free, (long) count_keep)); #endif *out_count_keep = count_keep; } -#endif /* DUK_USE_STRTAB_PROBE */ /* - * Sweep heap + * Sweep heap. */ DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_count_keep) { @@ -45281,65 +47032,62 @@ if (DUK_HEAPHDR_HAS_REACHABLE(curr)) { /* - * Reachable object, keep + * Reachable object: + * - If FINALIZABLE -> actually unreachable (but marked + * artificially reachable), queue to finalize_list. + * - If !FINALIZABLE but FINALIZED -> rescued after + * finalizer execution. + * - Otherwise just a normal, reachable object. + * + * Objects which are kept are queued to heap_allocated + * tail (we're essentially filtering heap_allocated in + * practice). */ - DUK_DDD(DUK_DDDPRINT("sweep, reachable: %p", (void *) curr)); - - if (DUK_HEAPHDR_HAS_FINALIZABLE(curr)) { - /* - * If object has been marked finalizable, move it to the - * "to be finalized" work list. It will be collected on - * the next mark-and-sweep if it is still unreachable - * after running the finalizer. - */ - +#if defined(DUK_USE_FINALIZER_SUPPORT) + if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZABLE(curr))) { DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); - DUK_DDD(DUK_DDDPRINT("object has finalizer, move to finalization work list: %p", (void *) curr)); + DUK_DD(DUK_DDPRINT("sweep; reachable, finalizable --> move to finalize_list: %p", (void *) curr)); -#if defined(DUK_USE_DOUBLE_LINKED_HEAP) - if (heap->finalize_list) { - DUK_HEAPHDR_SET_PREV(heap, heap->finalize_list, curr); - } - DUK_HEAPHDR_SET_PREV(heap, curr, NULL); +#if defined(DUK_USE_REFERENCE_COUNTING) + DUK_HEAPHDR_PREINC_REFCOUNT(curr); /* Bump refcount so that refzero never occurs when pending a finalizer call. */ #endif - DUK_HEAPHDR_SET_NEXT(heap, curr, heap->finalize_list); - DUK_ASSERT_HEAPHDR_LINKS(heap, curr); - heap->finalize_list = curr; + DUK_HEAP_INSERT_INTO_FINALIZE_LIST(heap, curr); #if defined(DUK_USE_DEBUG) count_finalize++; #endif - } else { - /* - * Object will be kept; queue object back to heap_allocated (to tail) - */ - - if (DUK_HEAPHDR_HAS_FINALIZED(curr)) { - /* - * Object's finalizer was executed on last round, and - * object has been happily rescued. - */ - + } + else +#endif /* DUK_USE_FINALIZER_SUPPORT */ + { + if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZED(curr))) { DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); - DUK_DD(DUK_DDPRINT("object rescued during mark-and-sweep finalization: %p", (void *) curr)); + + if (flags & DUK_MS_FLAG_POSTPONE_RESCUE) { + DUK_DD(DUK_DDPRINT("sweep; reachable, finalized, but postponing rescue decisions --> keep object (with FINALIZED set): %!iO", curr)); + count_keep++; + } else { + DUK_DD(DUK_DDPRINT("sweep; reachable, finalized --> rescued after finalization: %p", (void *) curr)); +#if defined(DUK_USE_FINALIZER_SUPPORT) + DUK_HEAPHDR_CLEAR_FINALIZED(curr); +#endif #if defined(DUK_USE_DEBUG) - count_rescue++; + count_rescue++; #endif + } } else { - /* - * Plain, boring reachable object. - */ - DUK_DD(DUK_DDPRINT("keep object: %!iO", curr)); + DUK_DD(DUK_DDPRINT("sweep; reachable --> keep: %!iO", curr)); count_keep++; } - if (!heap->heap_allocated) { - heap->heap_allocated = curr; - } - if (prev) { + if (prev != NULL) { + DUK_ASSERT(heap->heap_allocated != NULL); DUK_HEAPHDR_SET_NEXT(heap, prev, curr); + } else { + DUK_ASSERT(heap->heap_allocated == NULL); + heap->heap_allocated = curr; } #if defined(DUK_USE_DOUBLE_LINKED_HEAP) DUK_HEAPHDR_SET_PREV(heap, curr, prev); @@ -45350,21 +47098,23 @@ } DUK_HEAPHDR_CLEAR_REACHABLE(curr); - DUK_HEAPHDR_CLEAR_FINALIZED(curr); - DUK_HEAPHDR_CLEAR_FINALIZABLE(curr); - + /* Keep FINALIZED if set, used if rescue decisions are postponed. */ + /* Keep FINALIZABLE for objects on finalize_list. */ DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); - - curr = next; } else { /* - * Unreachable object, free + * Unreachable object: + * - If FINALIZED, object was finalized but not + * rescued. This doesn't affect freeing. + * - Otherwise normal unreachable object. + * + * There's no guard preventing a FINALIZED object + * from being freed while finalizers execute: the + * artificial finalize_list reachability roots can't + * cause an incorrect free decision (but can cause + * an incorrect rescue decision). */ - DUK_DDD(DUK_DDDPRINT("sweep, not reachable: %p", (void *) curr)); - #if defined(DUK_USE_REFERENCE_COUNTING) /* Non-zero refcounts should not happen because we refcount * finalize all unreachable objects which should cancel out @@ -45374,10 +47124,15 @@ #endif DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); +#if defined(DUK_USE_DEBUG) if (DUK_HEAPHDR_HAS_FINALIZED(curr)) { - DUK_DDD(DUK_DDDPRINT("finalized object not rescued: %p", (void *) curr)); + DUK_DD(DUK_DDPRINT("sweep; unreachable, finalized --> finalized object not rescued: %p", (void *) curr)); + } else { + DUK_DD(DUK_DDPRINT("sweep; not reachable --> free: %p", (void *) curr)); } +#endif + /* Note: object cannot be a finalizable unreachable object, as * they have been marked temporarily reachable for this round, * and are handled above. @@ -45387,17 +47142,18 @@ count_free++; #endif - /* weak refs should be handled here, but no weak refs for + /* Weak refs should be handled here, but no weak refs for * any non-string objects exist right now. */ - /* free object and all auxiliary (non-heap) allocs */ + /* Free object and all auxiliary (non-heap) allocs. */ duk_heap_free_heaphdr_raw(heap, curr); - - curr = next; } + + curr = next; } - if (prev) { + + if (prev != NULL) { DUK_HEAPHDR_SET_NEXT(heap, prev, NULL); } DUK_ASSERT_HEAPHDR_LINKS(heap, prev); @@ -45410,71 +47166,6 @@ } /* - * Run (object) finalizers in the "to be finalized" work list. - */ - -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_LOCAL void duk__run_object_finalizers(duk_heap *heap, duk_small_uint_t flags) { - duk_heaphdr *curr; - duk_heaphdr *next; -#if defined(DUK_USE_DEBUG) - duk_size_t count = 0; -#endif - duk_hthread *thr; - - DUK_DD(DUK_DDPRINT("duk__run_object_finalizers: %p", (void *) heap)); - - thr = duk__get_temp_hthread(heap); - DUK_ASSERT(thr != NULL); - - curr = heap->finalize_list; - while (curr) { - DUK_DDD(DUK_DDDPRINT("mark-and-sweep finalize: %p", (void *) curr)); - - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* only objects have finalizers */ - DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr)); /* flags have been already cleared */ - DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr)); /* No finalizers for ROM objects */ - - if (DUK_LIKELY((flags & DUK_MS_FLAG_SKIP_FINALIZERS) == 0)) { - /* Run the finalizer, duk_hobject_run_finalizer() sets FINALIZED. - * Next mark-and-sweep will collect the object unless it has - * become reachable (i.e. rescued). FINALIZED prevents the - * finalizer from being executed again before that. - */ - duk_hobject_run_finalizer(thr, (duk_hobject *) curr); /* must never longjmp */ - DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(curr)); - } 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)); - } - - /* queue back to heap_allocated */ - next = DUK_HEAPHDR_GET_NEXT(heap, curr); - DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr); - - curr = next; -#if defined(DUK_USE_DEBUG) - count++; -#endif - } - - /* finalize_list will always be processed completely */ - heap->finalize_list = NULL; - -#if defined(DUK_USE_DEBUG) - DUK_D(DUK_DPRINT("mark-and-sweep finalize objects: %ld finalizers called", (long) count)); -#endif -} -#endif /* DUK_USE_FINALIZER_SUPPORT */ - -/* * Object compaction. * * Compaction is assumed to never throw an error. @@ -45549,26 +47240,25 @@ duk_size_t count_compact = 0; duk_size_t count_bytes_saved = 0; #endif - duk_hthread *thr; DUK_DD(DUK_DDPRINT("duk__compact_objects: %p", (void *) heap)); - thr = duk__get_temp_hthread(heap); - DUK_ASSERT(thr != NULL); + DUK_ASSERT(heap->heap_thread != NULL); #if defined(DUK_USE_DEBUG) - duk__compact_object_list(heap, thr, heap->heap_allocated, &count_check, &count_compact, &count_bytes_saved); - duk__compact_object_list(heap, thr, heap->finalize_list, &count_check, &count_compact, &count_bytes_saved); -#if defined(DUK_USE_REFERENCE_COUNTING) - duk__compact_object_list(heap, thr, heap->refzero_list, &count_check, &count_compact, &count_bytes_saved); + duk__compact_object_list(heap, heap->heap_thread, heap->heap_allocated, &count_check, &count_compact, &count_bytes_saved); +#if defined(DUK_USE_FINALIZER_SUPPORT) + duk__compact_object_list(heap, heap->heap_thread, heap->finalize_list, &count_check, &count_compact, &count_bytes_saved); #endif #else - duk__compact_object_list(heap, thr, heap->heap_allocated); - duk__compact_object_list(heap, thr, heap->finalize_list); -#if defined(DUK_USE_REFERENCE_COUNTING) - duk__compact_object_list(heap, thr, heap->refzero_list); + duk__compact_object_list(heap, heap->heap_thread, heap->heap_allocated); +#if defined(DUK_USE_FINALIZER_SUPPORT) + duk__compact_object_list(heap, heap->heap_thread, heap->finalize_list); #endif #endif +#if defined(DUK_USE_REFERENCE_COUNTING) + DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ +#endif #if defined(DUK_USE_DEBUG) DUK_D(DUK_DPRINT("mark-and-sweep compact objects: %ld checked, %ld compaction attempts, %ld bytes saved by compaction", @@ -45594,166 +47284,189 @@ } #if defined(DUK_USE_REFERENCE_COUNTING) - hdr = heap->refzero_list; - while (hdr) { - DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr)); - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -#endif /* DUK_USE_REFERENCE_COUNTING */ + DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ +#endif } #if defined(DUK_USE_REFERENCE_COUNTING) DUK_LOCAL void duk__assert_valid_refcounts(duk_heap *heap) { duk_heaphdr *hdr = heap->heap_allocated; while (hdr) { + /* Cannot really assert much w.r.t. refcounts now. */ + if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0 && DUK_HEAPHDR_HAS_FINALIZED(hdr)) { /* An object may be in heap_allocated list with a zero * refcount if it has just been finalized and is waiting * to be collected by the next cycle. + * (This doesn't currently happen however.) */ } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0) { /* An object may be in heap_allocated list with a zero - * refcount also if it is a temporary object created by - * a finalizer; because finalization now runs inside - * mark-and-sweep, such objects will not be queued to - * refzero_list and will thus appear here with refcount - * zero. - */ -#if 0 /* this case can no longer occur because refcount is unsigned */ - } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) < 0) { - DUK_D(DUK_DPRINT("invalid refcount: %ld, %p -> %!O", - (hdr != NULL ? (long) DUK_HEAPHDR_GET_REFCOUNT(hdr) : (long) 0), - (void *) hdr, (duk_heaphdr *) hdr)); - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(hdr) > 0); -#endif + * refcount also if it is a temporary object created + * during debugger paused state. It will get collected + * by mark-and-sweep based on its reachability status + * (presumably not reachable because refcount is 0). + */ } + DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(hdr) >= 0); /* Unsigned. */ hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); } } -#endif /* DUK_USE_REFERENCE_COUNTING */ -#endif /* DUK_USE_ASSERTIONS */ -/* - * Finalizer torture. Do one fake finalizer call which causes side effects - * similar to one or more finalizers on actual objects. - */ +DUK_LOCAL void duk__clear_assert_refcounts(duk_heap *heap) { + duk_heaphdr *curr; + duk_uint32_t i; + for (curr = heap->heap_allocated; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { + curr->h_assert_refcount = 0; + } #if defined(DUK_USE_FINALIZER_SUPPORT) -#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE) -DUK_LOCAL duk_ret_t duk__markandsweep_fake_finalizer(duk_context *ctx) { - DUK_D(DUK_DPRINT("fake mark-and-sweep torture finalizer executed")); - - /* Require a lot of stack to force a value stack grow/shrink. - * Recursive mark-and-sweep is prevented by allocation macros - * so this won't trigger another mark-and-sweep. - */ - duk_require_stack(ctx, 100000); + for (curr = heap->finalize_list; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { + curr->h_assert_refcount = 0; + } +#endif +#if defined(DUK_USE_REFERENCE_COUNTING) + for (curr = heap->refzero_list; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { + curr->h_assert_refcount = 0; + } +#endif - /* XXX: do something to force a callstack grow/shrink, perhaps - * just a manual forced resize or a forced relocating realloc? - */ + for (i = 0; i < heap->st_size; i++) { + duk_hstring *h; - return 0; +#if defined(DUK_USE_STRTAB_PTRCOMP) + h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); +#else + h = heap->strtable[i]; +#endif + while (h != NULL) { + ((duk_heaphdr *) h)->h_assert_refcount = 0; + h = h->hdr.h_next; + } + } } -DUK_LOCAL void duk__markandsweep_torture_finalizer(duk_hthread *thr) { - duk_context *ctx; - duk_int_t rc; +DUK_LOCAL void duk__check_refcount_heaphdr(duk_heaphdr *hdr) { + duk_bool_t count_ok; - DUK_ASSERT(thr != NULL); - ctx = (duk_context *) thr; + /* The refcount check only makes sense for reachable objects on + * heap_allocated or string table, after the sweep phase. Prior to + * sweep phase refcounts will include references that are not visible + * via reachability roots. + * + * Because we're called after the sweep phase, all heap objects on + * heap_allocated are reachable. REACHABLE flags have already been + * cleared so we can't check them. + */ - /* Avoid fake finalization when callstack limit has been reached. - * Otherwise a callstack limit error will be created, then refzero'ed. + /* ROM objects have intentionally incorrect refcount (1), but we won't + * check them. */ - if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit || - thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) { - DUK_D(DUK_DPRINT("call recursion depth reached, avoid fake mark-and-sweep torture finalizer")); - return; + DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr)); + + count_ok = ((duk_size_t) DUK_HEAPHDR_GET_REFCOUNT(hdr) == hdr->h_assert_refcount); + if (!count_ok) { + DUK_D(DUK_DPRINT("refcount mismatch for: %p: header=%ld counted=%ld --> %!iO", + (void *) hdr, (long) DUK_HEAPHDR_GET_REFCOUNT(hdr), + (long) hdr->h_assert_refcount, hdr)); + DUK_ASSERT(0); } +} - /* Run fake finalizer. Avoid creating unnecessary garbage. */ - duk_push_c_function(ctx, duk__markandsweep_fake_finalizer, 0 /*nargs*/); - rc = duk_pcall(ctx, 0 /*nargs*/); - DUK_UNREF(rc); /* ignored */ - duk_pop(ctx); +DUK_LOCAL void duk__check_assert_refcounts(duk_heap *heap) { + duk_heaphdr *curr; + duk_uint32_t i; + + for (curr = heap->heap_allocated; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { + duk__check_refcount_heaphdr(curr); + } +#if defined(DUK_USE_FINALIZER_SUPPORT) + for (curr = heap->finalize_list; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { + duk__check_refcount_heaphdr(curr); + } +#endif + + for (i = 0; i < heap->st_size; i++) { + duk_hstring *h; + +#if defined(DUK_USE_STRTAB_PTRCOMP) + h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); +#else + h = heap->strtable[i]; +#endif + while (h != NULL) { + duk__check_refcount_heaphdr((duk_heaphdr *) h); + h = h->hdr.h_next; + } + } } -#endif /* DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE */ -#endif /* DUK_USE_FINALIZER_SUPPORT */ +#endif /* DUK_USE_REFERENCE_COUNTING */ +#endif /* DUK_USE_ASSERTIONS */ /* * Main mark-and-sweep function. * * 'flags' represents the features requested by the caller. The current - * heap->mark_and_sweep_base_flags is ORed automatically into the flags; - * the base flags mask typically prevents certain mark-and-sweep operations - * to avoid trouble. + * heap->ms_base_flags is ORed automatically into the flags; the base flags + * mask typically prevents certain mark-and-sweep operation to avoid trouble. */ -DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags) { - duk_hthread *thr; +DUK_INTERNAL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags) { duk_size_t count_keep_obj; duk_size_t count_keep_str; #if defined(DUK_USE_VOLUNTARY_GC) duk_size_t tmp; #endif - /* XXX: thread selection for mark-and-sweep is currently a hack. - * If we don't have a thread, the entire mark-and-sweep is now - * skipped (although we could just skip finalizations). + /* If debugger is paused, garbage collection is disabled by default. + * This is achieved by bumping ms_prevent_count when becoming paused. */ + DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) || heap->ms_prevent_count > 0); - /* If thr != NULL, the thr may still be in the middle of - * initialization. - * XXX: Improve the thread viability test. + /* Prevention/recursion check as soon as possible because we may + * be called a number of times when voluntary mark-and-sweep is + * pending. */ - thr = duk__get_temp_hthread(heap); - if (thr == NULL) { - DUK_D(DUK_DPRINT("gc skipped because we don't have a temp thread")); - - /* reset voluntary gc trigger count */ -#if defined(DUK_USE_VOLUNTARY_GC) - heap->mark_and_sweep_trigger_counter = DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP; -#endif - return 0; /* OK */ + if (heap->ms_prevent_count != 0) { + DUK_DD(DUK_DDPRINT("reject recursive mark-and-sweep")); + return; } + DUK_ASSERT(heap->ms_running == 0); /* ms_prevent_count is bumped when ms_running is set */ - /* If debugger is paused, garbage collection is disabled by default. */ - /* XXX: will need a force flag if garbage collection is triggered - * explicitly during paused state. + /* Heap_thread is used during mark-and-sweep for refcount finalization + * (it's also used for finalizer execution once mark-and-sweep is + * complete). Heap allocation code ensures heap_thread is set and + * properly initialized before setting ms_prevent_count to 0. */ -#if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_HEAP_IS_PAUSED(heap)) { - /* Checking this here rather that in memory alloc primitives - * reduces checking code there but means a failed allocation - * will go through a few retries before giving up. That's - * fine because this only happens during debugging. - */ - DUK_D(DUK_DPRINT("gc skipped because debugger is paused")); - return 0; - } -#endif + DUK_ASSERT(heap->heap_thread != NULL); + DUK_ASSERT(heap->heap_thread->valstack != NULL); + DUK_ASSERT(heap->heap_thread->callstack != NULL); + DUK_ASSERT(heap->heap_thread->catchstack != NULL); DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) starting, requested flags: 0x%08lx, effective flags: 0x%08lx", - (unsigned long) flags, (unsigned long) (flags | heap->mark_and_sweep_base_flags))); + (unsigned long) flags, (unsigned long) (flags | heap->ms_base_flags))); - flags |= heap->mark_and_sweep_base_flags; + flags |= heap->ms_base_flags; +#if defined(DUK_USE_FINALIZER_SUPPORT) + if (heap->finalize_list != NULL) { + flags |= DUK_MS_FLAG_POSTPONE_RESCUE; + } +#endif /* * Assertions before */ #if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)); + DUK_ASSERT(heap->ms_prevent_count == 0); + DUK_ASSERT(heap->ms_running == 0); + DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(heap)); DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)); - DUK_ASSERT(heap->mark_and_sweep_recursion_depth == 0); + DUK_ASSERT(heap->ms_recursion_depth == 0); duk__assert_heaphdr_flags(heap); #if defined(DUK_USE_REFERENCE_COUNTING) - /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount + /* Note: heap->refzero_free_running may be true; a refcount * finalizer may trigger a mark-and-sweep. */ duk__assert_valid_refcounts(heap); @@ -45764,7 +47477,10 @@ * Begin */ - DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap); + DUK_ASSERT(heap->ms_prevent_count == 0); + DUK_ASSERT(heap->ms_running == 0); + heap->ms_prevent_count = 1; + heap->ms_running = 1; /* * Mark roots, hoping that recursion limit is not normally hit. @@ -45782,17 +47498,20 @@ * previous run had finalizer skip flag. */ - duk__mark_roots_heap(heap); /* main reachability roots */ +#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) + duk__clear_assert_refcounts(heap); +#endif + duk__mark_roots_heap(heap); /* Mark main reachability roots. */ #if defined(DUK_USE_REFERENCE_COUNTING) - duk__mark_refzero_list(heap); /* refzero_list treated as reachability roots */ + DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ #endif - duk__mark_temproots_by_heap_scan(heap); /* temproots */ + duk__mark_temproots_by_heap_scan(heap); /* Temproots. */ #if defined(DUK_USE_FINALIZER_SUPPORT) - duk__mark_finalizable(heap); /* mark finalizable as reachability roots */ - duk__mark_finalize_list(heap); /* mark finalizer work list as reachability roots */ + duk__mark_finalizable(heap); /* Mark finalizable as reachability roots. */ + duk__mark_finalize_list(heap); /* Mark finalizer work list as reachability roots. */ #endif - duk__mark_temproots_by_heap_scan(heap); /* temproots */ + duk__mark_temproots_by_heap_scan(heap); /* Temproots. */ /* * Sweep garbage and remove marking flags, and move objects with @@ -45814,15 +47533,12 @@ duk__finalize_refcounts(heap); #endif duk__sweep_heap(heap, flags, &count_keep_obj); -#if defined(DUK_USE_STRTAB_CHAIN) - duk__sweep_stringtable_chain(heap, &count_keep_str); -#elif defined(DUK_USE_STRTAB_PROBE) - duk__sweep_stringtable_probe(heap, &count_keep_str); -#else -#error internal error, invalid strtab options + duk__sweep_stringtable(heap, &count_keep_str); +#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) + duk__check_assert_refcounts(heap); #endif #if defined(DUK_USE_REFERENCE_COUNTING) - duk__clear_refzero_list_flags(heap); + DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ #endif #if defined(DUK_USE_FINALIZER_SUPPORT) duk__clear_finalize_list_flags(heap); @@ -45853,94 +47569,39 @@ /* * String table resize check. * - * Note: this may silently (and safely) fail if GC is caused by an - * allocation call in stringtable resize_hash(). Resize_hash() - * will prevent a recursive call to itself by setting the - * DUK_MS_FLAG_NO_STRINGTABLE_RESIZE in heap->mark_and_sweep_base_flags. - */ - - /* XXX: stringtable emergency compaction? */ - - /* XXX: remove this feature entirely? it would only matter for - * emergency GC. Disable for lowest memory builds. - */ -#if defined(DUK_USE_MS_STRINGTABLE_RESIZE) - if (!(flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE)) { - DUK_DD(DUK_DDPRINT("resize stringtable: %p", (void *) heap)); - duk_heap_force_strtab_resize(heap); - } else { - DUK_D(DUK_DPRINT("stringtable resize skipped because DUK_MS_FLAG_NO_STRINGTABLE_RESIZE is set")); - } -#endif - - /* - * Finalize objects in the finalization work list. Finalized - * objects are queued back to heap_allocated with FINALIZED set. - * - * Since finalizers may cause arbitrary side effects, they are - * prevented during string table and object property allocation - * resizing using the DUK_MS_FLAG_NO_FINALIZERS flag in - * heap->mark_and_sweep_base_flags. In this case the objects - * remain in the finalization work list after mark-and-sweep - * exits and they may be finalized on the next pass. - * - * Finalization currently happens inside "MARKANDSWEEP_RUNNING" - * protection (no mark-and-sweep may be triggered by the - * finalizers). As a side effect: - * - * 1) an out-of-memory error inside a finalizer will not - * cause a mark-and-sweep and may cause the finalizer - * to fail unnecessarily - * - * 2) any temporary objects whose refcount decreases to zero - * during finalization will not be put into refzero_list; - * they can only be collected by another mark-and-sweep - * - * This is not optimal, but since the sweep for this phase has - * already happened, this is probably good enough for now. + * This is mainly useful in emergency GC: if the string table load + * factor is really low for some reason, we can shrink the string + * table to a smaller size and free some memory in the process. + * Only execute in emergency GC. String table has internal flags + * to protect against recursive resizing if this mark-and-sweep pass + * was triggered by a string table resize. */ -#if defined(DUK_USE_FINALIZER_SUPPORT) -#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE) - /* Cannot simulate individual finalizers because finalize_list only - * contains objects with actual finalizers. But simulate side effects - * from finalization by doing a bogus function call and resizing the - * stacks. - */ - if (flags & DUK_MS_FLAG_NO_FINALIZERS) { - DUK_D(DUK_DPRINT("skip mark-and-sweep torture finalizer, DUK_MS_FLAG_NO_FINALIZERS is set")); - } else if (!(thr->valstack != NULL && thr->callstack != NULL && thr->catchstack != NULL)) { - DUK_D(DUK_DPRINT("skip mark-and-sweep torture finalizer, thread not yet viable")); - } else { - DUK_D(DUK_DPRINT("run mark-and-sweep torture finalizer")); - duk__markandsweep_torture_finalizer(thr); - } -#endif /* DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE */ - - if (flags & DUK_MS_FLAG_NO_FINALIZERS) { - DUK_D(DUK_DPRINT("finalizer run skipped because DUK_MS_FLAG_NO_FINALIZERS is set")); - } else { - duk__run_object_finalizers(heap, flags); + if (flags & DUK_MS_FLAG_EMERGENCY) { + DUK_D(DUK_DPRINT("stringtable resize check in emergency gc")); + duk_heap_strtable_force_resize(heap); } -#endif /* DUK_USE_FINALIZER_SUPPORT */ /* * Finish */ - DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap); + DUK_ASSERT(heap->ms_prevent_count == 1); + heap->ms_prevent_count = 0; + DUK_ASSERT(heap->ms_running == 1); + heap->ms_running = 0; /* * Assertions after */ #if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)); + DUK_ASSERT(heap->ms_prevent_count == 0); DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)); - DUK_ASSERT(heap->mark_and_sweep_recursion_depth == 0); + DUK_ASSERT(heap->ms_recursion_depth == 0); duk__assert_heaphdr_flags(heap); #if defined(DUK_USE_REFERENCE_COUNTING) - /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount + /* Note: heap->refzero_free_running may be true; a refcount * finalizer may trigger a mark-and-sweep. */ duk__assert_valid_refcounts(heap); @@ -45953,17 +47614,49 @@ #if defined(DUK_USE_VOLUNTARY_GC) tmp = (count_keep_obj + count_keep_str) / 256; - heap->mark_and_sweep_trigger_counter = (duk_int_t) ( + heap->ms_trigger_counter = (duk_int_t) ( (tmp * DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT) + DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD); DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, trigger reset to %ld", - (long) count_keep_obj, (long) count_keep_str, (long) heap->mark_and_sweep_trigger_counter)); + (long) count_keep_obj, (long) count_keep_str, (long) heap->ms_trigger_counter)); #else DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, no voluntary trigger", (long) count_keep_obj, (long) count_keep_str)); #endif - return 0; /* OK */ + /* + * Finalize objects in the finalization work list. Finalized + * objects are queued back to heap_allocated with FINALIZED set. + * + * Since finalizers may cause arbitrary side effects, they are + * prevented e.g. during string table and object property allocation + * resizing using heap->pf_prevent_count. In this case the objects + * remain in the finalization work list after mark-and-sweep exits + * and they may be finalized on the next pass or any DECREF checking + * for finalize_list. + * + * As of Duktape 2.1 finalization happens outside mark-and-sweep + * protection. Mark-and-sweep is allowed while the finalize_list + * is being processed, but no rescue decisions are done while the + * process is on-going. This avoids incorrect rescue decisions + * if an object is considered reachable (and thus rescued) because + * of a reference via finalize_list (which is considered a reachability + * root). When finalize_list is being processed, reachable objects + * with FINALIZED set will just keep their FINALIZED flag for later + * mark-and-sweep processing. + * + * This could also be handled (a bit better) by having a more refined + * notion of reachability for rescue/free decisions. + * + * XXX: avoid finalizer execution when doing emergency GC? + */ + +#if defined(DUK_USE_FINALIZER_SUPPORT) + /* Attempt to process finalize_list, pf_prevent_count check + * is inside the target. + */ + duk_heap_process_finalize_list(heap); +#endif /* DUK_USE_FINALIZER_SUPPORT */ } /* * Memory allocation handling. @@ -45972,34 +47665,28 @@ /* #include duk_internal.h -> already included */ /* - * Helpers - * - * The fast path checks are done within a macro to ensure "inlining" - * while the slow path actions use a helper (which won't typically be - * inlined in size optimized builds). + * Voluntary GC check */ #if defined(DUK_USE_VOLUNTARY_GC) -#define DUK__VOLUNTARY_PERIODIC_GC(heap) do { \ - (heap)->mark_and_sweep_trigger_counter--; \ - if ((heap)->mark_and_sweep_trigger_counter <= 0) { \ - duk__run_voluntary_gc(heap); \ - } \ - } while (0) - -DUK_LOCAL void duk__run_voluntary_gc(duk_heap *heap) { - if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { - DUK_DD(DUK_DDPRINT("mark-and-sweep in progress -> skip voluntary mark-and-sweep now")); - } else { - duk_small_uint_t flags; - duk_bool_t rc; +DUK_LOCAL DUK_INLINE void duk__check_voluntary_gc(duk_heap *heap) { + if (DUK_UNLIKELY(--(heap)->ms_trigger_counter < 0)) { +#if defined(DUK_USE_DEBUG) + if (heap->ms_prevent_count == 0) { + DUK_D(DUK_DPRINT("triggering voluntary mark-and-sweep")); + } else { + DUK_DD(DUK_DDPRINT("gc blocked -> skip voluntary mark-and-sweep now")); + } +#endif - DUK_D(DUK_DPRINT("triggering voluntary mark-and-sweep")); - flags = 0; - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); + /* Prevention checks in the call target handle cases where + * voluntary GC is not allowed. The voluntary GC trigger + * counter is only rewritten if mark-and-sweep actually runs. + */ + duk_heap_mark_and_sweep(heap, DUK_MS_FLAG_VOLUNTARY /*flags*/); } } +#define DUK__VOLUNTARY_PERIODIC_GC(heap) do { duk__check_voluntary_gc((heap)); } while (0) #else #define DUK__VOLUNTARY_PERIODIC_GC(heap) /* no voluntary gc */ #endif /* DUK_USE_VOLUNTARY_GC */ @@ -46010,7 +47697,6 @@ DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) { void *res; - duk_bool_t rc; duk_small_int_t i; DUK_ASSERT(heap != NULL); @@ -46028,7 +47714,7 @@ #if defined(DUK_USE_GC_TORTURE) /* simulate alloc failure on every alloc (except when mark-and-sweep is running) */ - if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + if (heap->ms_prevent_count == 0) { DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first alloc attempt fails")); res = NULL; DUK_UNREF(res); @@ -46036,7 +47722,7 @@ } #endif res = heap->alloc_func(heap->heap_udata, size); - if (res || size == 0) { + if (DUK_LIKELY(res || size == 0)) { /* for zero size allocations NULL is allowed */ return res; } @@ -46046,16 +47732,22 @@ DUK_D(DUK_DPRINT("first alloc attempt failed, attempt to gc and retry")); +#if 0 /* * Avoid a GC if GC is already running. This can happen at a late * stage in a GC when we try to e.g. resize the stringtable * or compact objects. + * + * NOTE: explicit handling isn't actually be needed: if the GC is + * not allowed, duk_heap_mark_and_sweep() will reject it for every + * attempt in the loop below, resulting in a NULL same as here. */ - if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + 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 @@ -46071,8 +47763,7 @@ flags |= DUK_MS_FLAG_EMERGENCY; } - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); + duk_heap_mark_and_sweep(heap, flags); res = heap->alloc_func(heap->heap_udata, size); if (res) { @@ -46093,20 +47784,43 @@ DUK_ASSERT_DISABLE(size >= 0); res = DUK_ALLOC(heap, size); - if (res) { + if (DUK_LIKELY(res != NULL)) { /* assume memset with zero size is OK */ DUK_MEMZERO(res, size); } return res; } +DUK_INTERNAL void *duk_heap_mem_alloc_checked(duk_hthread *thr, duk_size_t size) { + void *res; + + DUK_ASSERT(thr != NULL); + res = duk_heap_mem_alloc(thr->heap, size); + if (DUK_LIKELY(res != NULL || size == 0)) { + return res; + } + DUK_ERROR_ALLOC_FAILED(thr); + return NULL; +} + +DUK_INTERNAL void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, duk_size_t size) { + void *res; + + DUK_ASSERT(thr != NULL); + res = duk_heap_mem_alloc_zeroed(thr->heap, size); + if (DUK_LIKELY(res != NULL || size == 0)) { + return res; + } + DUK_ERROR_ALLOC_FAILED(thr); + return NULL; +} + /* * Reallocate memory with garbage collection */ DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize) { void *res; - duk_bool_t rc; duk_small_int_t i; DUK_ASSERT(heap != NULL); @@ -46125,7 +47839,7 @@ #if defined(DUK_USE_GC_TORTURE) /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */ - if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + if (heap->ms_prevent_count == 0) { DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first realloc attempt fails")); res = NULL; DUK_UNREF(res); @@ -46133,7 +47847,7 @@ } #endif res = heap->realloc_func(heap->heap_udata, ptr, newsize); - if (res || newsize == 0) { + if (DUK_LIKELY(res || newsize == 0)) { /* for zero size allocations NULL is allowed */ return res; } @@ -46143,14 +47857,16 @@ 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 (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + 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 @@ -46166,8 +47882,7 @@ flags |= DUK_MS_FLAG_EMERGENCY; } - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); + duk_heap_mark_and_sweep(heap, flags); res = heap->realloc_func(heap->heap_udata, ptr, newsize); if (res || newsize == 0) { @@ -46189,7 +47904,6 @@ DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize) { void *res; - duk_bool_t rc; duk_small_int_t i; DUK_ASSERT(heap != NULL); @@ -46207,7 +47921,7 @@ #if defined(DUK_USE_GC_TORTURE) /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */ - if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + 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); @@ -46215,7 +47929,7 @@ } #endif res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize); - if (res || newsize == 0) { + if (DUK_LIKELY(res || newsize == 0)) { /* for zero size allocations NULL is allowed */ return res; } @@ -46225,14 +47939,16 @@ 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 (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + 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 @@ -46256,8 +47972,7 @@ flags |= DUK_MS_FLAG_EMERGENCY; } - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); + duk_heap_mark_and_sweep(heap, flags); #if defined(DUK_USE_ASSERTIONS) ptr_post = cb(heap, ud); if (ptr_pre != ptr_post) { @@ -46296,14 +48011,10 @@ */ heap->free_func(heap->heap_udata, ptr); - /* Count free operations toward triggering a GC but never actually trigger - * a GC from a free. Otherwise code which frees internal structures would - * need to put in NULLs at every turn to ensure the object is always in - * consistent state for a mark-and-sweep. + /* 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. */ -#if defined(DUK_USE_VOLUNTARY_GC) - heap->mark_and_sweep_trigger_counter--; -#endif } /* automatic undefs */ @@ -46314,44 +48025,146 @@ /* #include duk_internal.h -> already included */ -#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING) -/* arbitrary remove only works with double linked heap, and is only required by - * reference counting so far. - */ -DUK_INTERNAL void duk_heap_remove_any_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) { +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_ASSERT_HEAPHDR_LINKS(heap, hdr); + DUK_ASSERT_HEAPHDR_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); - if (DUK_HEAPHDR_GET_PREV(heap, hdr)) { - DUK_HEAPHDR_SET_NEXT(heap, DUK_HEAPHDR_GET_PREV(heap, hdr), DUK_HEAPHDR_GET_NEXT(heap, hdr)); + /* 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 { - heap->heap_allocated = DUK_HEAPHDR_GET_NEXT(heap, hdr); + DUK_ASSERT(heap->heap_allocated == hdr); + heap->heap_allocated = next; } - if (DUK_HEAPHDR_GET_NEXT(heap, hdr)) { - DUK_HEAPHDR_SET_PREV(heap, DUK_HEAPHDR_GET_NEXT(heap, hdr), DUK_HEAPHDR_GET_PREV(heap, hdr)); + if (next != NULL) { + DUK_HEAPHDR_SET_PREV(heap, next, prev); } else { ; } - - /* The prev/next pointers of the removed duk_heaphdr are left as garbage. - * It's up to the caller to ensure they're written before inserting the - * object back. - */ } -#endif +#endif /* DUK_USE_REFERENCE_COUNTING */ -DUK_INTERNAL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) { - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING); +#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) - if (heap->heap_allocated) { - DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, heap->heap_allocated) == NULL); - DUK_HEAPHDR_SET_PREV(heap, heap->heap_allocated, hdr); - } 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_ASSERT_HEAPHDR_LINKS(heap, hdr); + DUK_ASSERT_HEAPHDR_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 - DUK_HEAPHDR_SET_NEXT(heap, hdr, heap->heap_allocated); - heap->heap_allocated = hdr; } +#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) { @@ -46389,6 +48202,10 @@ #endif /* DUK_USE_INTERRUPT_COUNTER */ /* * 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 duk_internal.h -> already included */ @@ -46400,36 +48217,6 @@ #endif /* - * Misc - */ - -DUK_LOCAL void duk__queue_refzero(duk_heap *heap, duk_heaphdr *hdr) { - /* tail insert: don't disturb head in case refzero is running */ - - if (heap->refzero_list != NULL) { - duk_heaphdr *hdr_prev; - - hdr_prev = heap->refzero_list_tail; - DUK_ASSERT(hdr_prev != NULL); - DUK_ASSERT(DUK_HEAPHDR_GET_NEXT(heap, hdr_prev) == NULL); - - DUK_HEAPHDR_SET_NEXT(heap, hdr, NULL); - DUK_HEAPHDR_SET_PREV(heap, hdr, hdr_prev); - DUK_HEAPHDR_SET_NEXT(heap, hdr_prev, hdr); - DUK_ASSERT_HEAPHDR_LINKS(heap, hdr); - DUK_ASSERT_HEAPHDR_LINKS(heap, hdr_prev); - heap->refzero_list_tail = hdr; - } else { - DUK_ASSERT(heap->refzero_list_tail == NULL); - DUK_HEAPHDR_SET_NEXT(heap, hdr, NULL); - DUK_HEAPHDR_SET_PREV(heap, hdr, NULL); - DUK_ASSERT_HEAPHDR_LINKS(heap, hdr); - heap->refzero_list = hdr; - heap->refzero_list_tail = hdr; - } -} - -/* * Heap object refcount finalization. * * When an object is about to be freed, all other objects it refers to must @@ -46437,41 +48224,47 @@ * allocations (mark-and-sweep shares these helpers), it just manipulates * the refcounts. * - * Note that any of the decref's may cause a refcount to drop to zero, BUT - * it will not be processed inline. If refcount finalization is triggered - * by refzero processing, the objects will be just queued to the refzero - * list and processed later which eliminates C recursion. If refcount - * finalization is triggered by mark-and-sweep, any refzero situations are - * ignored because mark-and-sweep will deal with them. NORZ variants can - * be used here in both cases. + * 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__refcount_finalize_hobject(duk_hthread *thr, duk_hobject *h) { +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); - /* XXX: better to get base and walk forwards? */ + thr = heap->heap_thread; + DUK_ASSERT(thr != NULL); - p_key = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, h); - p_val = DUK_HOBJECT_E_GET_VALUE_BASE(thr->heap, h); - p_flag = DUK_HOBJECT_E_GET_FLAGS_BASE(thr->heap, h); + 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 (!key) { + if (DUK_UNLIKELY(key == NULL)) { continue; } DUK_HSTRING_DECREF_NORZ(thr, key); - if (p_flag[n] & DUK_PROPDESC_FLAG_ACCESSOR) { + 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)); @@ -46486,7 +48279,7 @@ } } - p_tv = DUK_HOBJECT_A_GET_BASE(thr->heap, h); + p_tv = DUK_HOBJECT_A_GET_BASE(heap, h); n = DUK_HOBJECT_GET_ASIZE(h); while (n-- > 0) { duk_tval *tv_val; @@ -46494,39 +48287,49 @@ DUK_TVAL_DECREF_NORZ(thr, tv_val); } - /* hash part is a 'weak reference' and does not contribute */ + /* Hash part is a 'weak reference' and doesn't contribute to refcounts. */ - { - duk_hobject *h_proto; - h_proto = (duk_hobject *) DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h); - DUK_ASSERT(h_proto == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_proto)); - DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_proto); + 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)); - /* XXX: rearrange bits to allow a switch case to be used here? */ - /* XXX: add a fast path for objects (and arrays)? */ + /* Slow path: special object, start bit checks from most likely. */ - /* DUK_HOBJECT_IS_ARRAY(h): needs no special handling now as there are - * no extra fields in need of decref. - */ if (DUK_HOBJECT_IS_COMPFUNC(h)) { duk_hcompfunc *f = (duk_hcompfunc *) h; duk_tval *tv, *tv_end; duk_hobject **funcs, **funcs_end; - if (DUK_HCOMPFUNC_GET_DATA(thr->heap, f) != NULL) { - tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, f); - tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, 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(thr->heap, f); - funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, f); + 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++; @@ -46536,13 +48339,19 @@ DUK_D(DUK_DPRINT("duk_hcompfunc 'data' is NULL, skipping decref")); } - DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_heaphdr *) DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f)); - DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_heaphdr *) DUK_HCOMPFUNC_GET_VARENV(thr->heap, f)); - DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(thr->heap, f)); - } else if (DUK_HOBJECT_IS_NATFUNC(h)) { - duk_hnatfunc *f = (duk_hnatfunc *) h; - DUK_UNREF(f); - /* nothing to finalize */ + 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_ASSERT_HDECENV_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_ASSERT_HOBJENV_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; @@ -46580,264 +48389,284 @@ } 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(duk_hthread *thr, duk_heaphdr *hdr) { - DUK_ASSERT(hdr); +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_GET_TYPE(hdr) == DUK_HTYPE_OBJECT) { - duk__refcount_finalize_hobject(thr, (duk_hobject *) hdr); + 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 */ } -#if defined(DUK_USE_FINALIZER_SUPPORT) -#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE) -DUK_LOCAL duk_ret_t duk__refcount_fake_finalizer(duk_context *ctx) { - DUK_UNREF(ctx); - DUK_D(DUK_DPRINT("fake refcount torture finalizer executed")); -#if 0 - DUK_DD(DUK_DDPRINT("fake torture finalizer for: %!T", duk_get_tval(ctx, 0))); -#endif - /* Require a lot of stack to force a value stack grow/shrink. */ - duk_require_stack(ctx, 100000); - - /* XXX: do something to force a callstack grow/shrink, perhaps - * just a manual forced resize? - */ - return 0; -} - -DUK_LOCAL void duk__refcount_run_torture_finalizer(duk_hthread *thr, duk_hobject *obj) { - duk_context *ctx; - duk_int_t rc; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(obj != NULL); - ctx = (duk_context *) thr; - - /* Avoid fake finalization for the duk__refcount_fake_finalizer function - * itself, otherwise we're in infinite recursion. - */ - if (DUK_HOBJECT_HAS_NATFUNC(obj)) { - if (((duk_hnatfunc *) obj)->func == duk__refcount_fake_finalizer) { - DUK_DD(DUK_DDPRINT("avoid fake torture finalizer for duk__refcount_fake_finalizer itself")); - return; - } - } - /* Avoid fake finalization when callstack limit has been reached. - * Otherwise a callstack limit error will be created, then refzero'ed, - * and we're in an infinite loop. - */ - if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit || - thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) { - DUK_D(DUK_DPRINT("call recursion depth reached, avoid fake torture finalizer")); - return; - } - - /* Run fake finalizer. Avoid creating new refzero queue entries - * so that we are not forced into a forever loop. - */ - duk_push_c_function(ctx, duk__refcount_fake_finalizer, 1 /*nargs*/); - duk_push_hobject(ctx, obj); - rc = duk_pcall(ctx, 1); - DUK_UNREF(rc); /* ignored */ - duk_pop(ctx); -} -#endif /* DUK_USE_REFZERO_FINALIZER_TORTURE */ -#endif /* DUK_USE_FINALIZER_SUPPORT */ - /* - * Refcount memory freeing loop. - * - * Frees objects in the refzero_pending list until the list becomes - * empty. When an object is freed, its references get decref'd and - * may cause further objects to be queued for freeing. + * 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. + * 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_INTERNAL void duk_refzero_free_pending(duk_hthread *thr) { - duk_heaphdr *h1, *h2; - duk_heap *heap; +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(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - heap = thr->heap; DUK_ASSERT(heap != NULL); - /* - * Detect recursive invocation - */ + 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. */ - if (DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap)) { - DUK_DDD(DUK_DDDPRINT("refzero free running, skip run")); - return; - } + do { + duk_heaphdr *prev; - /* - * Churn refzero_list until empty - */ + DUK_DDD(DUK_DDDPRINT("refzero processing %p: %!O", (void *) curr, (duk_heaphdr *) curr)); - DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap); - while (heap->refzero_list) { - duk_hobject *obj; -#if defined(DUK_USE_FINALIZER_SUPPORT) - duk_bool_t rescued = 0; -#endif /* DUK_USE_FINALIZER_SUPPORT */ +#if defined(DUK_USE_DEBUG) + count++; +#endif - /* - * Pick an object from the head (don't remove yet). + 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); - h1 = heap->refzero_list; - obj = (duk_hobject *) h1; - DUK_DD(DUK_DDPRINT("refzero processing %p: %!O", (void *) h1, (duk_heaphdr *) h1)); - DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, h1) == NULL); - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(h1) == DUK_HTYPE_OBJECT); /* currently, always the case */ + 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. */ -#if defined(DUK_USE_FINALIZER_SUPPORT) -#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE) - /* Torture option to shake out finalizer side effect issues: - * make a bogus function call for every finalizable object, - * essentially simulating the case where everything has a - * finalizer. - */ - DUK_DD(DUK_DDPRINT("refzero torture enabled, fake finalizer")); - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h1) == 0); - DUK_HEAPHDR_PREINC_REFCOUNT(h1); /* bump refcount to prevent refzero during finalizer processing */ - duk__refcount_run_torture_finalizer(thr, obj); /* must never longjmp */ - DUK_HEAPHDR_PREDEC_REFCOUNT(h1); /* remove artificial bump */ - DUK_ASSERT_DISABLE(h1->h_refcount >= 0); /* refcount is unsigned, so always true */ -#endif /* DUK_USE_REFZERO_FINALIZER_TORTURE */ -#endif /* DUK_USE_FINALIZER_SUPPORT */ + duk_free_hobject(heap, (duk_hobject *) curr); /* Invalidates 'curr'. */ - /* - * Finalizer check. - * - * Note: running a finalizer may have arbitrary side effects, e.g. - * queue more objects on refzero_list (tail), or even trigger a - * mark-and-sweep. - * - * Note: quick reject check should match vast majority of - * objects and must be safe (not throw any errors, ever). - * - * An object may have FINALIZED here if it was finalized by mark-and-sweep - * on a previous run and refcount then decreased to zero. We won't run the - * finalizer again here. - * - * A finalizer is looked up from the object and up its prototype chain - * (which allows inherited finalizers). - */ + curr = prev; + } while (curr != NULL); -#if defined(DUK_USE_FINALIZER_SUPPORT) - if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) { - DUK_DDD(DUK_DDDPRINT("object has a finalizer, run it")); + 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(DUK_HEAPHDR_GET_REFCOUNT(h1) == 0); - DUK_HEAPHDR_PREINC_REFCOUNT(h1); /* bump refcount to prevent refzero during finalizer processing */ + 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); - duk_hobject_run_finalizer(thr, obj); /* must never longjmp */ - DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1)); /* duk_hobject_run_finalizer() sets */ + hdr = (duk_heaphdr *) obj; - DUK_HEAPHDR_PREDEC_REFCOUNT(h1); /* remove artificial bump */ - DUK_ASSERT_DISABLE(h1->h_refcount >= 0); /* refcount is unsigned, so always true */ + /* 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 - if (DUK_HEAPHDR_GET_REFCOUNT(h1) != 0) { - DUK_DDD(DUK_DDDPRINT("-> object refcount after finalization non-zero, object will be rescued")); - rescued = 1; - } else { - DUK_DDD(DUK_DDDPRINT("-> object refcount still zero after finalization, object will be freed")); + 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))) { + /* 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 */ - /* Refzero head is still the same. This is the case even if finalizer - * inserted more refzero objects; they are inserted to the tail. - */ - DUK_ASSERT(h1 == heap->refzero_list); + /* No need to finalize, free object via refzero_list. */ - /* - * Remove the object from the refzero list. This cannot be done - * before a possible finalizer has been executed; the finalizer - * may trigger a mark-and-sweep, and mark-and-sweep must be able - * to traverse a complete refzero_list. - */ + root = heap->refzero_list; - h2 = DUK_HEAPHDR_GET_NEXT(heap, h1); - if (h2) { - DUK_HEAPHDR_SET_PREV(heap, h2, NULL); /* not strictly necessary */ - heap->refzero_list = h2; - } else { - heap->refzero_list = NULL; - heap->refzero_list_tail = NULL; - } + DUK_HEAPHDR_SET_PREV(heap, hdr, NULL); + /* 'next' is left as GARBAGE. */ + heap->refzero_list = hdr; - /* - * Rescue or free. + 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 (rescued) { - /* yes -> move back to heap allocated */ - DUK_DD(DUK_DDPRINT("object rescued during refcount finalization: %p", (void *) h1)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(h1)); - DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1)); - DUK_HEAPHDR_CLEAR_FINALIZED(h1); - h2 = heap->heap_allocated; - DUK_HEAPHDR_SET_PREV(heap, h1, NULL); - if (h2) { - DUK_HEAPHDR_SET_PREV(heap, h2, h1); - } - DUK_HEAPHDR_SET_NEXT(heap, h1, h2); - DUK_ASSERT_HEAPHDR_LINKS(heap, h1); - DUK_ASSERT_HEAPHDR_LINKS(heap, h2); - heap->heap_allocated = h1; - } else -#endif /* DUK_USE_FINALIZER_SUPPORT */ - { - /* no -> decref members, then free */ - duk__refcount_finalize_hobject(thr, obj); - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(h1) == DUK_HTYPE_OBJECT); /* currently, always the case */ - duk_free_hobject(heap, (duk_hobject *) h1); + 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); - count++; + /* 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. + */ } - DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap); +} - DUK_DDD(DUK_DDDPRINT("refzero processed %ld objects", (long) count)); +#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. */ - /* - * Once the whole refzero cascade has been freed, check for - * a voluntary mark-and-sweep. - */ + if (DUK_UNLIKELY(thr->heap->finalize_list != NULL)) { + duk_heap_process_finalize_list(thr->heap); + } +} -#if defined(DUK_USE_VOLUNTARY_GC) - /* 'count' is more or less comparable to normal trigger counter update - * which happens in memory block (re)allocation. - */ - heap->mark_and_sweep_trigger_counter -= count; - if (heap->mark_and_sweep_trigger_counter <= 0) { - duk_bool_t rc; - duk_small_uint_t flags = 0; /* not emergency */ - DUK_D(DUK_DPRINT("refcount triggering mark-and-sweep")); - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); - DUK_D(DUK_DPRINT("refcount triggered mark-and-sweep => rc %ld", (long) rc)); +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_VOLUNTARY_GC */ +} +#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. + * 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, @@ -46850,46 +48679,67 @@ * mark-and-sweep also calls finalizers which would use the ordinary decref * macros anyway. * - * The DUK__RZ_SUPPRESS_CHECK() must be enabled also when mark-and-sweep - * support has been disabled: the flag is also used in heap destruction when - * running finalizers for remaining objects, and the flag prevents objects - * from being moved around in heap linked lists. + * 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. */ -/* The suppress condition is important to performance. The flags being tested - * are in the same duk_heap field so a single TEST instruction (on x86) tests - * for them. - */ +#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); \ + /* When mark-and-sweep runs, the 'thr' argument always matches heap_thread. \ + * This could be used to e.g. suppress check against 'thr' directly (and \ + * knowing it would be heap_thread); not really used now. \ + */ \ + DUK_ASSERT(thr->heap->ms_running == 0 || 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_COND() \ - (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) || DUK_HEAP_IS_PAUSED(heap)) +#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_COND() \ - (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) -#endif +#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 when mark-and-sweep running, object: %p", (void *) h)); \ + 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_heap_strcache_string_remove(thr->heap, (duk_hstring *) h); \ - duk_heap_string_remove(heap, (duk_hstring *) h); \ - duk_free_hstring(heap, (duk_hstring *) h); \ + duk__refcount_refzero_hstring(heap, (duk_hstring *) h); \ } while (0) #define DUK__RZ_BUFFER() do { \ - duk_heap_remove_any_from_heap_allocated(heap, (duk_heaphdr *) h); \ - duk_free_hbuffer(heap, (duk_hbuffer *) h); \ + duk__refcount_refzero_hbuffer(heap, (duk_hbuffer *) h); \ } while (0) #define DUK__RZ_OBJECT() do { \ - duk_heap_remove_any_from_heap_allocated(heap, (duk_heaphdr *) h); \ - duk__queue_refzero(heap, (duk_heaphdr *) h); \ - if (!skip_free_pending) { \ - duk_refzero_free_pending(thr); \ - } \ + 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 @@ -46959,42 +48809,39 @@ DUK__RZ_OBJECT(); break; - case DUK_HTYPE_BUFFER: + 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; - - default: - DUK_D(DUK_DPRINT("invalid heap type in decref: %ld", (long) DUK_HEAPHDR_GET_TYPE(h))); - DUK_UNREACHABLE(); } } -DUK_INTERNAL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h) { +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 void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h) { +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 void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h) { +DUK_INTERNAL DUK_NOINLINE void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h) { duk__hstring_refzero_helper(thr, h); } -DUK_INTERNAL void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h) { +DUK_INTERNAL DUK_NOINLINE void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h) { duk__hbuffer_refzero_helper(thr, h); } -DUK_INTERNAL void duk_hobject_refzero(duk_hthread *thr, duk_hobject *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 void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h) { +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*/); } @@ -47008,6 +48855,7 @@ 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. */ } } @@ -47046,7 +48894,7 @@ } duk_heaphdr_refzero_norz(thr, h); #else - duk_heaphdr_decref(thr, h); + duk_heaphdr_decref_norz(thr, h); #endif } } @@ -47060,6 +48908,13 @@ 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; \ @@ -47069,6 +48924,10 @@ } \ } 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; \ @@ -47085,13 +48944,18 @@ DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0); - DUK_HEAPHDR_PREINC_REFCOUNT(h); + 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(); @@ -47142,10 +49006,13 @@ /* automatic undefs */ #undef DUK__DECREF_ASSERTS #undef DUK__DECREF_SHARED +#undef DUK__INCREF_SHARED #undef DUK__RZ_BUFFER #undef DUK__RZ_INLINE #undef DUK__RZ_OBJECT #undef DUK__RZ_STRING +#undef DUK__RZ_SUPPRESS_ASSERT1 +#undef DUK__RZ_SUPPRESS_ASSERT2 #undef DUK__RZ_SUPPRESS_CHECK #undef DUK__RZ_SUPPRESS_COND /* @@ -47234,6 +49101,10 @@ * * 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) { @@ -47243,20 +49114,27 @@ duk_small_int_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; - if (char_offset > DUK_HSTRING_GET_CHARLEN(h)) { - goto error; - } - /* * For ASCII strings, the answer is simple. */ - if (DUK_HSTRING_IS_ASCII(h)) { - /* clen == blen -> pure ascii */ + 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; } @@ -47278,7 +49156,7 @@ heap = thr->heap; sce = NULL; - use_cache = (DUK_HSTRING_GET_CHARLEN(h) > DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT); + use_cache = (char_length > DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT); if (use_cache) { #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) @@ -47309,7 +49187,7 @@ DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h) >= char_offset); dist_start = char_offset; - dist_end = DUK_HSTRING_GET_CHARLEN(h) - 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); @@ -47382,12 +49260,12 @@ scan_done: - if (!p_found) { + 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 error; + goto scan_error; } DUK_ASSERT(p_found >= p_start); @@ -47442,64 +49320,176 @@ return byte_offset; - error: + scan_error: DUK_ERROR_INTERNAL(thr); return 0; } /* - * Heap stringtable handling, string interning. + * Heap string table handling, string interning. */ /* #include duk_internal.h -> already included */ -#if defined(DUK_USE_STRTAB_PROBE) -#define DUK__HASH_INITIAL(hash,h_size) DUK_STRTAB_HASH_INITIAL((hash),(h_size)) -#define DUK__HASH_PROBE_STEP(hash) DUK_STRTAB_HASH_PROBE_STEP((hash)) -#define DUK__DELETED_MARKER(heap) DUK_STRTAB_DELETED_MARKER((heap)) +/* Resize checks not needed if minsize == maxsize, typical for low memory + * targets. + */ +#define DUK__STRTAB_RESIZE_CHECK +#if (DUK_USE_STRTAB_MINSIZE == DUK_USE_STRTAB_MAXSIZE) +#undef DUK__STRTAB_RESIZE_CHECK #endif -#define DUK__PREVENT_MS_SIDE_EFFECTS(heap) do { \ - (heap)->mark_and_sweep_base_flags |= \ - DUK_MS_FLAG_NO_STRINGTABLE_RESIZE | /* avoid recursive string table call */ \ - DUK_MS_FLAG_NO_FINALIZERS | /* avoid pressure to add/remove strings, invalidation of call data argument, etc. */ \ - DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid array abandoning which interns strings */ \ - } while (0) +#if defined(DUK_USE_STRTAB_PTRCOMP) +#define DUK__HEAPPTR_ENC16(heap,ptr) DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (ptr)) +#define DUK__HEAPPTR_DEC16(heap,val) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (val)) +#define DUK__GET_STRTABLE(heap) ((heap)->strtable16) +#else +#define DUK__HEAPPTR_ENC16(heap,ptr) (ptr) +#define DUK__HEAPPTR_DEC16(heap,val) (val) +#define DUK__GET_STRTABLE(heap) ((heap)->strtable) +#endif + +#define DUK__STRTAB_U32_MAX_STRLEN 10 /* 4'294'967'295 */ /* - * Create a hstring and insert into the heap. The created object - * is directly garbage collectable with reference count zero. + * Debug dump stringtable. + */ + +#if defined(DUK_USE_DEBUG) +DUK_INTERNAL void duk_heap_strtable_dump(duk_heap *heap) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *strtable; +#else + duk_hstring **strtable; +#endif + duk_uint32_t i; + duk_hstring *h; + duk_size_t count_total = 0; + duk_size_t count_chain; + duk_size_t count_chain_min = DUK_SIZE_MAX; + duk_size_t count_chain_max = 0; + duk_size_t count_len[8]; /* chain lengths from 0 to 7 */ + + if (heap == NULL) { + DUK_D(DUK_DPRINT("string table, heap=NULL")); + return; + } + + strtable = DUK__GET_STRTABLE(heap); + if (strtable == NULL) { + DUK_D(DUK_DPRINT("string table, strtab=NULL")); + return; + } + + DUK_MEMZERO((void *) count_len, sizeof(count_len)); + for (i = 0; i < heap->st_size; i++) { + h = DUK__HEAPPTR_DEC16(heap, strtable[i]); + count_chain = 0; + while (h != NULL) { + count_chain++; + h = h->hdr.h_next; + } + if (count_chain < sizeof(count_len) / sizeof(duk_size_t)) { + count_len[count_chain]++; + } + count_chain_max = (count_chain > count_chain_max ? count_chain : count_chain_max); + count_chain_min = (count_chain < count_chain_min ? count_chain : count_chain_min); + count_total += count_chain; + } + + DUK_D(DUK_DPRINT("string table, strtab=%p, count=%lu, chain min=%lu max=%lu avg=%lf: " + "counts: %lu %lu %lu %lu %lu %lu %lu %lu ...", + (void *) heap->strtable, (unsigned long) count_total, + (unsigned long) count_chain_min, (unsigned long) count_chain_max, + (double) count_total / (double) heap->st_size, + (unsigned long) count_len[0], (unsigned long) count_len[1], + (unsigned long) count_len[2], (unsigned long) count_len[3], + (unsigned long) count_len[4], (unsigned long) count_len[5], + (unsigned long) count_len[6], (unsigned long) count_len[7])); +} +#endif /* DUK_USE_DEBUG */ + +/* + * Assertion helper to ensure strtable is populated correctly. + */ + +#if defined(DUK_USE_ASSERTIONS) +DUK_LOCAL void duk__strtable_assert_checks(duk_heap *heap) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *strtable; +#else + duk_hstring **strtable; +#endif + duk_uint32_t i; + duk_hstring *h; + duk_size_t count = 0; + + DUK_ASSERT(heap != NULL); + + strtable = DUK__GET_STRTABLE(heap); + if (strtable != NULL) { + DUK_ASSERT(heap->st_size != 0); + DUK_ASSERT(heap->st_mask == heap->st_size - 1); + + for (i = 0; i < heap->st_size; i++) { + h = DUK__HEAPPTR_DEC16(heap, strtable[i]); + while (h != NULL) { + DUK_ASSERT((DUK_HSTRING_GET_HASH(h) & heap->st_mask) == i); + count++; + h = h->hdr.h_next; + } + } + } else { + DUK_ASSERT(heap->st_size == 0); + DUK_ASSERT(heap->st_mask == 0); + } + +#if defined(DUK__STRTAB_RESIZE_CHECK) + DUK_ASSERT(count == (duk_size_t) heap->st_count); +#endif +} +#endif /* DUK_USE_ASSERTIONS */ + +/* + * Allocate and initialize a duk_hstring. * - * The caller must place the interned string into the stringtable - * immediately (without chance of a longjmp); otherwise the string - * is lost. + * Returns a NULL if allocation or initialization fails for some reason. + * + * The string won't be inserted into the string table and isn't tracked in + * any way (link pointers will be NULL). The caller must place the string + * into the string table without any risk of a longjmp, otherwise the string + * is leaked. */ -DUK_LOCAL -duk_hstring *duk__alloc_init_hstring(duk_heap *heap, - const duk_uint8_t *str, - duk_uint32_t blen, - duk_uint32_t strhash, - const duk_uint8_t *extdata) { - duk_hstring *res = NULL; - duk_uint8_t *data; - duk_size_t alloc_size; +DUK_LOCAL duk_hstring *duk__strtable_alloc_hstring(duk_heap *heap, + const duk_uint8_t *str, + duk_uint32_t blen, + duk_uint32_t strhash, + const duk_uint8_t *extdata) { + duk_hstring *res; + const duk_uint8_t *data; #if !defined(DUK_USE_HSTRING_ARRIDX) duk_uarridx_t dummy; #endif - duk_uint32_t clen; + + DUK_ASSERT(heap != NULL); + DUK_UNREF(extdata); #if defined(DUK_USE_STRLEN16) /* If blen <= 0xffffUL, clen is also guaranteed to be <= 0xffffUL. */ if (blen > 0xffffUL) { DUK_D(DUK_DPRINT("16-bit string blen/clen active and blen over 16 bits, reject intern")); - return NULL; + goto alloc_error; } #endif + /* XXX: Memzeroing the allocated structure is not really necessary + * because we could just initialize all fields explicitly (almost + * all fields are initialized explicitly anyway). + */ +#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) if (extdata) { - alloc_size = (duk_size_t) sizeof(duk_hstring_external); - res = (duk_hstring *) DUK_ALLOC(heap, alloc_size); - if (!res) { + res = (duk_hstring *) DUK_ALLOC(heap, sizeof(duk_hstring_external)); + if (DUK_UNLIKELY(res == NULL)) { goto alloc_error; } DUK_MEMZERO(res, sizeof(duk_hstring_external)); @@ -47508,12 +49498,18 @@ #endif DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, DUK_HSTRING_FLAG_EXTDATA); + DUK_ASSERT(extdata[blen] == 0); /* Application responsibility. */ + data = extdata; ((duk_hstring_external *) res)->extdata = extdata; - } else { + } else +#endif /* DUK_USE_HSTRING_EXTDATA && DUK_USE_EXTSTR_INTERN_CHECK */ + { + duk_uint8_t *data_tmp; + /* NUL terminate for convenient C access */ - alloc_size = (duk_size_t) (sizeof(duk_hstring) + blen + 1); - res = (duk_hstring *) DUK_ALLOC(heap, alloc_size); - if (!res) { + DUK_ASSERT(sizeof(duk_hstring) + blen + 1 > blen); /* No wrap, limits ensure. */ + res = (duk_hstring *) DUK_ALLOC(heap, sizeof(duk_hstring) + blen + 1); + if (DUK_UNLIKELY(res == NULL)) { goto alloc_error; } DUK_MEMZERO(res, sizeof(duk_hstring)); @@ -47522,1090 +49518,787 @@ #endif DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, 0); - data = (duk_uint8_t *) (res + 1); - DUK_MEMCPY(data, str, blen); - data[blen] = (duk_uint8_t) 0; + data_tmp = (duk_uint8_t *) (res + 1); + DUK_MEMCPY(data_tmp, str, blen); + data_tmp[blen] = (duk_uint8_t) 0; + data = (const duk_uint8_t *) data_tmp; } + DUK_HSTRING_SET_BYTELEN(res, blen); + DUK_HSTRING_SET_HASH(res, strhash); + DUK_ASSERT(!DUK_HSTRING_HAS_ARRIDX(res)); #if defined(DUK_USE_HSTRING_ARRIDX) - if (duk_js_to_arrayindex_raw_string(str, blen, &res->arridx)) { + res->arridx = duk_js_to_arrayindex_string(data, blen); + if (res->arridx != DUK_HSTRING_NO_ARRAY_INDEX) { #else - if (duk_js_to_arrayindex_raw_string(str, blen, &dummy)) { + dummy = duk_js_to_arrayindex_string(data, blen); + if (dummy != DUK_HSTRING_NO_ARRAY_INDEX) { #endif + /* Array index strings cannot be symbol strings, + * and they're always pure ASCII so blen == clen. + */ DUK_HSTRING_SET_ARRIDX(res); - } - - /* All strings beginning with specific (invalid UTF-8) byte prefixes - * are treated as symbols. - */ - DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(res)); - DUK_ASSERT(!DUK_HSTRING_HAS_HIDDEN(res)); - if (blen > 0) { - if (str[0] == 0xffU) { - DUK_HSTRING_SET_SYMBOL(res); - DUK_HSTRING_SET_HIDDEN(res); - } else if ((str[0] & 0xc0U) == 0x80U) { - DUK_HSTRING_SET_SYMBOL(res); + DUK_HSTRING_SET_ASCII(res); + DUK_ASSERT(duk_unicode_unvalidated_utf8_length(data, (duk_size_t) blen) == blen); + } else { + /* Because 'data' is NUL-terminated, we don't need a + * blen > 0 check here. For NUL (0x00) the symbol + * checks will be false. + */ + if (DUK_UNLIKELY(data[0] >= 0x80U)) { + if (data[0] == 0xffU) { + DUK_HSTRING_SET_SYMBOL(res); + DUK_HSTRING_SET_HIDDEN(res); + } else if (data[0] <= 0xbf) { + /* Check equivalent to: (data[0] & 0xc0U) == 0x80U. */ + DUK_HSTRING_SET_SYMBOL(res); + } } - } - - DUK_HSTRING_SET_HASH(res, strhash); - DUK_HSTRING_SET_BYTELEN(res, blen); - - clen = (duk_uint32_t) duk_unicode_unvalidated_utf8_length(str, (duk_size_t) blen); - DUK_ASSERT(clen <= blen); -#if defined(DUK_USE_HSTRING_CLEN) - DUK_HSTRING_SET_CHARLEN(res, clen); -#endif - /* Using an explicit 'ASCII' flag has larger footprint (one call site - * only) but is quite useful for the case when there's no explicit - * 'clen' in duk_hstring. - */ - DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(res)); - if (clen == blen) { - DUK_HSTRING_SET_ASCII(res); + /* Using an explicit 'ASCII' flag has larger footprint (one call site + * only) but is quite useful for the case when there's no explicit + * 'clen' in duk_hstring. + * + * The flag is set lazily for RAM strings. + */ + DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(res)); } - DUK_DDD(DUK_DDDPRINT("interned string, hash=0x%08lx, blen=%ld, clen=%ld, has_arridx=%ld, has_extdata=%ld", + DUK_DDD(DUK_DDDPRINT("interned string, hash=0x%08lx, blen=%ld, has_arridx=%ld, has_extdata=%ld", (unsigned long) DUK_HSTRING_GET_HASH(res), (long) DUK_HSTRING_GET_BYTELEN(res), - (long) DUK_HSTRING_GET_CHARLEN(res), (long) (DUK_HSTRING_HAS_ARRIDX(res) ? 1 : 0), (long) (DUK_HSTRING_HAS_EXTDATA(res) ? 1 : 0))); + DUK_ASSERT(res != NULL); return res; alloc_error: - DUK_FREE(heap, res); return NULL; } /* - * String table algorithm: fixed size string table with array chaining - * - * The top level string table has a fixed size, with each slot holding - * either NULL, string pointer, or pointer to a separately allocated - * string pointer list. - * - * This is good for low memory environments using a pool allocator: the - * top level allocation has a fixed size and the pointer lists have quite - * small allocation size, which further matches the typical pool sizes - * needed by objects, strings, property tables, etc. + * Grow strtable allocation in-place. */ -#if defined(DUK_USE_STRTAB_CHAIN) +#if defined(DUK__STRTAB_RESIZE_CHECK) +DUK_LOCAL void duk__strtable_grow_inplace(duk_heap *heap) { + duk_uint32_t new_st_size; + duk_uint32_t old_st_size; + duk_uint32_t i; + duk_hstring *h; + duk_hstring *next; + duk_hstring *prev; +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *new_ptr; + duk_uint16_t *new_ptr_high; +#else + duk_hstring **new_ptr; + duk_hstring **new_ptr_high; +#endif -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL duk_bool_t duk__insert_hstring_chain(duk_heap *heap, duk_hstring *h) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_uint16_t *lst; - duk_uint16_t *new_lst; - duk_size_t i, n; - duk_uint16_t null16 = heap->heapptr_null16; - duk_uint16_t h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h); + DUK_DD(DUK_DDPRINT("grow in-place: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size * 2)); DUK_ASSERT(heap != NULL); - DUK_ASSERT(h != NULL); + DUK_ASSERT(heap->st_resizing == 1); + DUK_ASSERT(heap->st_size >= 2); + DUK_ASSERT((heap->st_size & (heap->st_size - 1)) == 0); /* 2^N */ + DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL); - slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); - - e = heap->strtable + slotidx; - if (e->listlen == 0) { - if (e->u.str16 == null16) { - e->u.str16 = h16; - } else { - /* Now two entries in the same slot, alloc list */ - lst = (duk_uint16_t *) DUK_ALLOC(heap, sizeof(duk_uint16_t) * 2); - if (lst == NULL) { - return 1; /* fail */ - } - lst[0] = e->u.str16; - lst[1] = h16; - e->u.strlist16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) lst); - e->listlen = 2; - } - } else { - DUK_ASSERT(e->u.strlist16 != null16); - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); - DUK_ASSERT(lst != NULL); - for (i = 0, n = e->listlen; i < n; i++) { - if (lst[i] == null16) { - lst[i] = h16; - return 0; - } - } + new_st_size = heap->st_size << 1U; + DUK_ASSERT(new_st_size > heap->st_size); /* No overflow. */ - if (e->listlen + 1 == 0) { - /* Overflow, relevant mainly when listlen is 16 bits. */ - return 1; /* fail */ - } + /* Reallocate the strtable first and then work in-place to rehash + * strings. We don't need an indirect allocation here: even if GC + * is triggered to satisfy the allocation, recursive strtable resize + * is prevented by flags. This is also why we don't need to use + * DUK_REALLOC_INDIRECT(). + */ - new_lst = (duk_uint16_t *) DUK_REALLOC(heap, lst, sizeof(duk_uint16_t) * (e->listlen + 1)); - if (new_lst == NULL) { - return 1; /* fail */ - } - new_lst[e->listlen++] = h16; - e->u.strlist16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) new_lst); +#if defined(DUK_USE_STRTAB_PTRCOMP) + new_ptr = (duk_uint16_t *) DUK_REALLOC(heap, heap->strtable16, sizeof(duk_uint16_t) * new_st_size); +#else + new_ptr = (duk_hstring **) DUK_REALLOC(heap, heap->strtable, sizeof(duk_hstring *) * new_st_size); +#endif + if (DUK_UNLIKELY(new_ptr == NULL)) { + /* If realloc fails we can continue normally: the string table + * won't "fill up" although chains will gradually get longer. + * When string insertions continue, we'll quite soon try again + * with no special handling. + */ + DUK_D(DUK_DPRINT("string table grow failed, ignoring")); + return; } - return 0; -} -#else /* DUK_USE_HEAPPTR16 */ -DUK_LOCAL duk_bool_t duk__insert_hstring_chain(duk_heap *heap, duk_hstring *h) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_hstring **lst; - duk_hstring **new_lst; - duk_size_t i, n; - - DUK_ASSERT(heap != NULL); - DUK_ASSERT(h != NULL); - - slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); - - e = heap->strtable + slotidx; - if (e->listlen == 0) { - if (e->u.str == NULL) { - e->u.str = h; - } else { - /* Now two entries in the same slot, alloc list */ - lst = (duk_hstring **) DUK_ALLOC(heap, sizeof(duk_hstring *) * 2); - if (lst == NULL) { - return 1; /* fail */ - } - lst[0] = e->u.str; - lst[1] = h; - e->u.strlist = lst; - e->listlen = 2; - } - } else { - DUK_ASSERT(e->u.strlist != NULL); - lst = e->u.strlist; - for (i = 0, n = e->listlen; i < n; i++) { - if (lst[i] == NULL) { - lst[i] = h; - return 0; - } - } +#if defined(DUK_USE_STRTAB_PTRCOMP) + heap->strtable16 = new_ptr; +#else + heap->strtable = new_ptr; +#endif - if (e->listlen + 1 == 0) { - /* Overflow, relevant mainly when listlen is 16 bits. */ - return 1; /* fail */ - } + /* Rehash a single bucket into two separate ones. When we grow + * by x2 the highest 'new' bit determines whether a string remains + * in its old position (bit is 0) or goes to a new one (bit is 1). + */ - new_lst = (duk_hstring **) DUK_REALLOC(heap, e->u.strlist, sizeof(duk_hstring *) * (e->listlen + 1)); - if (new_lst == NULL) { - return 1; /* fail */ - } - new_lst[e->listlen++] = h; - e->u.strlist = new_lst; - } - return 0; -} -#endif /* DUK_USE_HEAPPTR16 */ + old_st_size = heap->st_size; + new_ptr_high = new_ptr + old_st_size; + for (i = 0; i < old_st_size; i++) { + duk_hstring *new_root; + duk_hstring *new_root_high; -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_uint16_t *lst; - duk_size_t i, n; - duk_uint16_t null16 = heap->heapptr_null16; + h = DUK__HEAPPTR_DEC16(heap, new_ptr[i]); + new_root = h; + new_root_high = NULL; - DUK_ASSERT(heap != NULL); + prev = NULL; + while (h != NULL) { + duk_uint32_t mask; - slotidx = strhash % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); + DUK_ASSERT((DUK_HSTRING_GET_HASH(h) & heap->st_mask) == i); + next = h->hdr.h_next; - e = heap->strtable + slotidx; - if (e->listlen == 0) { - if (e->u.str16 != null16) { - duk_hstring *h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16); - DUK_ASSERT(h != NULL); - if (DUK_HSTRING_GET_BYTELEN(h) == blen && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) { - return h; - } - } - } else { - DUK_ASSERT(e->u.strlist16 != null16); - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); - DUK_ASSERT(lst != NULL); - for (i = 0, n = e->listlen; i < n; i++) { - if (lst[i] != null16) { - duk_hstring *h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[i]); - DUK_ASSERT(h != NULL); - if (DUK_HSTRING_GET_BYTELEN(h) == blen && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) { - return h; + /* Example: if previous size was 256, previous mask is 0xFF + * and size is 0x100 which corresponds to the new bit that + * comes into play. + */ + DUK_ASSERT(heap->st_mask == old_st_size - 1); + mask = old_st_size; + if (DUK_HSTRING_GET_HASH(h) & mask) { + if (prev != NULL) { + prev->hdr.h_next = h->hdr.h_next; + } else { + DUK_ASSERT(h == new_root); + new_root = h->hdr.h_next; } - } - } - } - return NULL; -} -#else /* DUK_USE_HEAPPTR16 */ -DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_hstring **lst; - duk_size_t i, n; - - DUK_ASSERT(heap != NULL); - - slotidx = strhash % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); - - e = heap->strtable + slotidx; - if (e->listlen == 0) { - if (e->u.str != NULL && - DUK_HSTRING_GET_BYTELEN(e->u.str) == blen && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(e->u.str), (size_t) blen) == 0) { - return e->u.str; - } - } else { - DUK_ASSERT(e->u.strlist != NULL); - lst = e->u.strlist; - for (i = 0, n = e->listlen; i < n; i++) { - if (lst[i] != NULL && - DUK_HSTRING_GET_BYTELEN(lst[i]) == blen && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(lst[i]), (size_t) blen) == 0) { - return lst[i]; + h->hdr.h_next = new_root_high; + new_root_high = h; + } else { + prev = h; } + h = next; } - } - return NULL; -} -#endif /* DUK_USE_HEAPPTR16 */ - -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL void duk__remove_matching_hstring_chain(duk_heap *heap, duk_hstring *h) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_uint16_t *lst; - duk_size_t i, n; - duk_uint16_t h16; - duk_uint16_t null16 = heap->heapptr_null16; - - DUK_ASSERT(heap != NULL); - DUK_ASSERT(h != NULL); - - slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); - - DUK_ASSERT(h != NULL); - h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h); - - e = heap->strtable + slotidx; - if (e->listlen == 0) { - if (e->u.str16 == h16) { - e->u.str16 = null16; - return; - } - } else { - DUK_ASSERT(e->u.strlist16 != null16); - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); - DUK_ASSERT(lst != NULL); - for (i = 0, n = e->listlen; i < n; i++) { - if (lst[i] == h16) { - lst[i] = null16; - return; - } - } + new_ptr[i] = DUK__HEAPPTR_ENC16(heap, new_root); + new_ptr_high[i] = DUK__HEAPPTR_ENC16(heap, new_root_high); } - DUK_D(DUK_DPRINT("failed to find string that should be in stringtable")); - DUK_UNREACHABLE(); - return; -} -#else /* DUK_USE_HEAPPTR16 */ -DUK_LOCAL void duk__remove_matching_hstring_chain(duk_heap *heap, duk_hstring *h) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_hstring **lst; - duk_size_t i, n; + heap->st_size = new_st_size; + heap->st_mask = new_st_size - 1; - DUK_ASSERT(heap != NULL); - DUK_ASSERT(h != NULL); - - slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); - - e = heap->strtable + slotidx; - if (e->listlen == 0) { - DUK_ASSERT(h != NULL); - if (e->u.str == h) { - e->u.str = NULL; - return; - } - } else { - DUK_ASSERT(e->u.strlist != NULL); - lst = e->u.strlist; - for (i = 0, n = e->listlen; i < n; i++) { - DUK_ASSERT(h != NULL); - if (lst[i] == h) { - lst[i] = NULL; - return; - } - } - } - - DUK_D(DUK_DPRINT("failed to find string that should be in stringtable")); - DUK_UNREACHABLE(); - return; +#if defined(DUK_USE_ASSERTIONS) + duk__strtable_assert_checks(heap); +#endif } -#endif /* DUK_USE_HEAPPTR16 */ +#endif /* DUK__STRTAB_RESIZE_CHECK */ -#if defined(DUK_USE_DEBUG) -DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap) { - duk_strtab_entry *e; - duk_small_uint_t i; - duk_size_t j, n, used; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t *lst; - duk_uint16_t null16 = heap->heapptr_null16; -#else - duk_hstring **lst; +/* + * Shrink strtable allocation in-place. + */ + +#if defined(DUK__STRTAB_RESIZE_CHECK) +DUK_LOCAL void duk__strtable_shrink_inplace(duk_heap *heap) { + duk_uint32_t new_st_size; + duk_uint32_t i; + duk_hstring *h; + duk_hstring *other; + duk_hstring *root; +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *old_ptr; + duk_uint16_t *old_ptr_high; + duk_uint16_t *new_ptr; +#else + duk_hstring **old_ptr; + duk_hstring **old_ptr_high; + duk_hstring **new_ptr; #endif - DUK_ASSERT(heap != NULL); + DUK_DD(DUK_DDPRINT("shrink in-place: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size / 2)); - for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { - e = heap->strtable + i; + DUK_ASSERT(heap != NULL); + DUK_ASSERT(heap->st_resizing == 1); + DUK_ASSERT(heap->st_size >= 2); + DUK_ASSERT((heap->st_size & (heap->st_size - 1)) == 0); /* 2^N */ + DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL); + + new_st_size = heap->st_size >> 1U; + + /* Combine two buckets into a single one. When we shrink, one hash + * bit (highest) disappears. + */ + old_ptr = DUK__GET_STRTABLE(heap); + old_ptr_high = old_ptr + new_st_size; + for (i = 0; i < new_st_size; i++) { + h = DUK__HEAPPTR_DEC16(heap, old_ptr[i]); + other = DUK__HEAPPTR_DEC16(heap, old_ptr_high[i]); - if (e->listlen == 0) { -#if defined(DUK_USE_HEAPPTR16) - DUK_DD(DUK_DDPRINT("[%03d] -> plain %d", (int) i, (int) (e->u.str16 != null16 ? 1 : 0))); -#else - DUK_DD(DUK_DDPRINT("[%03d] -> plain %d", (int) i, (int) (e->u.str ? 1 : 0))); -#endif + if (h == NULL) { + /* First chain is empty, so use second one as is. */ + root = other; } else { - used = 0; -#if defined(DUK_USE_HEAPPTR16) - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); -#else - lst = e->u.strlist; -#endif - DUK_ASSERT(lst != NULL); - for (j = 0, n = e->listlen; j < n; j++) { -#if defined(DUK_USE_HEAPPTR16) - if (lst[j] != null16) { -#else - if (lst[j] != NULL) { -#endif - used++; - } + /* Find end of first chain, and link in the second. */ + root = h; + while (h->hdr.h_next != NULL) { + h = h->hdr.h_next; } - DUK_DD(DUK_DDPRINT("[%03d] -> array %d/%d", (int) i, (int) used, (int) e->listlen)); + h->hdr.h_next = other; } - } -} -#endif /* DUK_USE_DEBUG */ -#endif /* DUK_USE_STRTAB_CHAIN */ + old_ptr[i] = DUK__HEAPPTR_ENC16(heap, root); + } -/* - * String table algorithm: closed hashing with a probe sequence - * - * This is the default algorithm and works fine for environments with - * minimal memory constraints. - */ + heap->st_size = new_st_size; + heap->st_mask = new_st_size - 1; -#if defined(DUK_USE_STRTAB_PROBE) + /* The strtable is now consistent and we can realloc safely. Even + * if side effects cause string interning or removal the strtable + * updates are safe. Recursive resize has been prevented by caller. + * This is also why we don't need to use DUK_REALLOC_INDIRECT(). + * + * We assume a realloc() to a smaller size is guaranteed to succeed. + * It would be relatively straightforward to handle the error by + * essentially performing a "grow" step to recover. + */ -/* Count actually used (non-NULL, non-DELETED) entries. */ -DUK_LOCAL duk_int_t duk__count_used_probe(duk_heap *heap) { - duk_int_t res = 0; - duk_uint_fast32_t i, n; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t null16 = heap->heapptr_null16; - duk_uint16_t deleted16 = heap->heapptr_deleted16; +#if defined(DUK_USE_STRTAB_PTRCOMP) + new_ptr = (duk_uint16_t *) DUK_REALLOC(heap, heap->strtable16, sizeof(duk_uint16_t) * new_st_size); + DUK_ASSERT(new_ptr != NULL); + heap->strtable16 = new_ptr; +#else + new_ptr = (duk_hstring **) DUK_REALLOC(heap, heap->strtable, sizeof(duk_hstring *) * new_st_size); + DUK_ASSERT(new_ptr != NULL); + heap->strtable = new_ptr; #endif - n = (duk_uint_fast32_t) heap->st_size; - for (i = 0; i < n; i++) { -#if defined(DUK_USE_HEAPPTR16) - if (heap->strtable16[i] != null16 && heap->strtable16[i] != deleted16) { -#else - if (heap->strtable[i] != NULL && heap->strtable[i] != DUK__DELETED_MARKER(heap)) { +#if defined(DUK_USE_ASSERTIONS) + duk__strtable_assert_checks(heap); #endif - res++; - } - } - return res; } +#endif /* DUK__STRTAB_RESIZE_CHECK */ -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL void duk__insert_hstring_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, duk_uint32_t *p_used, duk_hstring *h) { -#else -DUK_LOCAL void duk__insert_hstring_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, duk_uint32_t *p_used, duk_hstring *h) { -#endif - duk_uint32_t i; - duk_uint32_t step; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t null16 = heap->heapptr_null16; - duk_uint16_t deleted16 = heap->heapptr_deleted16; -#endif +/* + * Grow/shrink check. + */ - DUK_ASSERT(size > 0); +#if defined(DUK__STRTAB_RESIZE_CHECK) +DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__strtable_resize_check(duk_heap *heap) { + duk_uint32_t load_factor; /* fixed point */ - i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(h), size); - step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(h)); - for (;;) { -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t e16 = entries16[i]; -#else - duk_hstring *e = entries[i]; -#endif - -#if defined(DUK_USE_HEAPPTR16) - /* XXX: could check for e16 == 0 because NULL is guaranteed to - * encode to zero. - */ - if (e16 == null16) { -#else - if (e == NULL) { -#endif - DUK_DDD(DUK_DDDPRINT("insert hit (null): %ld", (long) i)); -#if defined(DUK_USE_HEAPPTR16) - entries16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h); -#else - entries[i] = h; -#endif - (*p_used)++; - break; -#if defined(DUK_USE_HEAPPTR16) - } else if (e16 == deleted16) { -#else - } else if (e == DUK__DELETED_MARKER(heap)) { -#endif - /* st_used remains the same, DELETED is counted as used */ - DUK_DDD(DUK_DDDPRINT("insert hit (deleted): %ld", (long) i)); -#if defined(DUK_USE_HEAPPTR16) - entries16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h); + DUK_ASSERT(heap != NULL); +#if defined(DUK_USE_STRTAB_PTRCOMP) + DUK_ASSERT(heap->strtable16 != NULL); #else - entries[i] = h; + DUK_ASSERT(heap->strtable != NULL); #endif - break; - } - DUK_DDD(DUK_DDDPRINT("insert miss: %ld", (long) i)); - i = (i + step) % size; - /* looping should never happen */ - DUK_ASSERT(i != DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(h), size)); + /* Prevent recursive resizing. */ + if (DUK_UNLIKELY(heap->st_resizing)) { + DUK_D(DUK_DPRINT("prevent recursive strtable resize")); + return; } -} -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL duk_hstring *duk__find_matching_string_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { -#else -DUK_LOCAL duk_hstring *duk__find_matching_string_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { -#endif - duk_uint32_t i; - duk_uint32_t step; + heap->st_resizing = 1; - DUK_ASSERT(size > 0); - - i = DUK__HASH_INITIAL(strhash, size); - step = DUK__HASH_PROBE_STEP(strhash); - for (;;) { - duk_hstring *e; -#if defined(DUK_USE_HEAPPTR16) - e = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, entries16[i]); -#else - e = entries[i]; + DUK_ASSERT(heap->st_size >= 16U); + DUK_ASSERT((heap->st_size >> 4U) >= 1); + load_factor = heap->st_count / (heap->st_size >> 4U); + + DUK_DD(DUK_DDPRINT("resize check string table: size=%lu, count=%lu, load_factor=%lu (fixed point .4; float %lf)", + (unsigned long) heap->st_size, (unsigned long) heap->st_count, + (unsigned long) load_factor, + (double) heap->st_count / (double) heap->st_size)); + + if (load_factor >= DUK_USE_STRTAB_GROW_LIMIT) { + if (heap->st_size >= DUK_USE_STRTAB_MAXSIZE) { + DUK_DD(DUK_DDPRINT("want to grow strtable (based on load factor) but already maximum size")); + } else { + DUK_D(DUK_DPRINT("grow string table: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size * 2)); +#if defined(DUK_USE_DEBUG) + duk_heap_strtable_dump(heap); #endif - - if (!e) { - return NULL; + duk__strtable_grow_inplace(heap); } - if (e != DUK__DELETED_MARKER(heap) && DUK_HSTRING_GET_BYTELEN(e) == blen) { - if (DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(e), (size_t) blen) == 0) { - DUK_DDD(DUK_DDDPRINT("find matching hit: %ld (step %ld, size %ld)", - (long) i, (long) step, (long) size)); - return e; - } + } else if (load_factor <= DUK_USE_STRTAB_SHRINK_LIMIT) { + if (heap->st_size <= DUK_USE_STRTAB_MINSIZE) { + DUK_DD(DUK_DDPRINT("want to shrink strtable (based on load factor) but already minimum size")); + } else { + DUK_D(DUK_DPRINT("shrink string table: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size / 2)); +#if defined(DUK_USE_DEBUG) + duk_heap_strtable_dump(heap); +#endif + duk__strtable_shrink_inplace(heap); } - DUK_DDD(DUK_DDDPRINT("find matching miss: %ld (step %ld, size %ld)", - (long) i, (long) step, (long) size)); - i = (i + step) % size; - - /* looping should never happen */ - DUK_ASSERT(i != DUK__HASH_INITIAL(strhash, size)); + } else { + DUK_DD(DUK_DDPRINT("no need for strtable resize")); } - DUK_UNREACHABLE(); -} -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL void duk__remove_matching_hstring_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, duk_hstring *h) { -#else -DUK_LOCAL void duk__remove_matching_hstring_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, duk_hstring *h) { -#endif - duk_uint32_t i; - duk_uint32_t step; - duk_uint32_t hash; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t null16 = heap->heapptr_null16; - duk_uint16_t h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h); -#endif + heap->st_resizing = 0; +} +#endif /* DUK__STRTAB_RESIZE_CHECK */ - DUK_ASSERT(size > 0); +/* + * Torture grow/shrink: unconditionally grow and shrink back. + */ - hash = DUK_HSTRING_GET_HASH(h); - i = DUK__HASH_INITIAL(hash, size); - step = DUK__HASH_PROBE_STEP(hash); - for (;;) { -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t e16 = entries16[i]; -#else - duk_hstring *e = entries[i]; -#endif +#if defined(DUK_USE_STRTAB_TORTURE) && defined(DUK__STRTAB_RESIZE_CHECK) +DUK_LOCAL void duk__strtable_resize_torture(duk_heap *heap) { + duk_uint32_t old_st_size; -#if defined(DUK_USE_HEAPPTR16) - if (e16 == null16) { -#else - if (!e) { -#endif - DUK_UNREACHABLE(); - break; - } -#if defined(DUK_USE_HEAPPTR16) - if (e16 == h16) { -#else - if (e == h) { -#endif - /* st_used remains the same, DELETED is counted as used */ - DUK_DDD(DUK_DDDPRINT("free matching hit: %ld", (long) i)); -#if defined(DUK_USE_HEAPPTR16) - entries16[i] = heap->heapptr_deleted16; -#else - entries[i] = DUK__DELETED_MARKER(heap); -#endif - break; - } + DUK_ASSERT(heap != NULL); - DUK_DDD(DUK_DDDPRINT("free matching miss: %ld", (long) i)); - i = (i + step) % size; + old_st_size = heap->st_size; + if (old_st_size >= DUK_USE_STRTAB_MAXSIZE) { + return; + } - /* looping should never happen */ - DUK_ASSERT(i != DUK__HASH_INITIAL(hash, size)); + heap->st_resizing = 1; + duk__strtable_grow_inplace(heap); + if (heap->st_size > old_st_size) { + duk__strtable_shrink_inplace(heap); } + heap->st_resizing = 0; } +#endif /* DUK_USE_STRTAB_TORTURE && DUK__STRTAB_RESIZE_CHECK */ -DUK_LOCAL duk_bool_t duk__resize_strtab_raw_probe(duk_heap *heap, duk_uint32_t new_size) { -#if defined(DUK_USE_DEBUG) - duk_uint32_t old_used = heap->st_used; -#endif - duk_uint32_t old_size = heap->st_size; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t *old_entries = heap->strtable16; - duk_uint16_t *new_entries = NULL; -#else - duk_hstring **old_entries = heap->strtable; - duk_hstring **new_entries = NULL; -#endif - duk_uint32_t new_used = 0; - duk_uint32_t i; +/* + * Raw intern; string already checked not to be present. + */ -#if defined(DUK_USE_DEBUG) - DUK_UNREF(old_used); /* unused with some debug level combinations */ +DUK_LOCAL duk_hstring *duk__strtable_do_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { + duk_hstring *res; + const duk_uint8_t *extdata; +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *slot; +#else + duk_hstring **slot; #endif -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) - DUK_DDD(DUK_DDDPRINT("attempt to resize stringtable: %ld entries, %ld bytes, %ld used, %ld%% load -> %ld entries, %ld bytes, %ld used, %ld%% load", - (long) old_size, (long) (sizeof(duk_hstring *) * old_size), (long) old_used, - (long) (((double) old_used) / ((double) old_size) * 100.0), - (long) new_size, (long) (sizeof(duk_hstring *) * new_size), (long) duk__count_used_probe(heap), - (long) (((double) duk__count_used_probe(heap)) / ((double) new_size) * 100.0))); -#endif + DUK_DDD(DUK_DDDPRINT("do_intern: heap=%p, str=%p, blen=%lu, strhash=%lx, st_size=%lu, st_count=%lu, load=%lf", + (void *) heap, (const void *) str, (unsigned long) blen, (unsigned long) strhash, + (unsigned long) heap->st_size, (unsigned long) heap->st_count, + (double) heap->st_count / (double) heap->st_size)); - DUK_ASSERT(new_size > (duk_uint32_t) duk__count_used_probe(heap)); /* required for rehash to succeed, equality not that useful */ - DUK_ASSERT(old_entries); + DUK_ASSERT(heap != NULL); - /* - * The attempt to allocate may cause a GC. Such a GC must not attempt to resize - * the stringtable (though it can be swept); finalizer execution and object - * compaction must also be postponed to avoid the pressure to add strings to the - * string table. Call site must prevent these. + /* Prevent any side effects on the string table and the caller provided + * str/blen arguments while interning is in progress. For example, if + * the caller provided str/blen from a dynamic buffer, a finalizer + * might resize or modify that dynamic buffer, invalidating the call + * arguments. + * + * While finalizers must be prevented, mark-and-sweep itself is fine. + * Recursive string table resize is prevented explicitly here. */ - DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE); - DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_FINALIZERS); - DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_OBJECT_COMPACTION); + heap->pf_prevent_count++; + DUK_ASSERT(heap->pf_prevent_count != 0); /* Wrap. */ -#if defined(DUK_USE_HEAPPTR16) - new_entries = (duk_uint16_t *) DUK_ALLOC(heap, sizeof(duk_uint16_t) * new_size); -#else - new_entries = (duk_hstring **) DUK_ALLOC(heap, sizeof(duk_hstring *) * new_size); +#if defined(DUK_USE_STRTAB_TORTURE) && defined(DUK__STRTAB_RESIZE_CHECK) + duk__strtable_resize_torture(heap); #endif - if (!new_entries) { - goto resize_error; - } + /* String table grow/shrink check. Because of chaining (and no + * accumulation issues as with hash probe chains and DELETED + * markers) there's never a mandatory need to resize right now. + * Check for the resize only periodically, based on st_count + * bit pattern. Because string table removal doesn't do a shrink + * check, we do that also here. + * + * Do the resize and possible grow/shrink before the new duk_hstring + * has been allocated. Otherwise we may trigger a GC when the result + * duk_hstring is not yet strongly referenced. + */ -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - for (i = 0; i < new_size; i++) { -#if defined(DUK_USE_HEAPPTR16) - new_entries[i] = heap->heapptr_null16; -#else - new_entries[i] = NULL; -#endif +#if defined(DUK__STRTAB_RESIZE_CHECK) + if (DUK_UNLIKELY((heap->st_count & DUK_USE_STRTAB_RESIZE_CHECK_MASK) == 0)) { + duk__strtable_resize_check(heap); } -#else -#if defined(DUK_USE_HEAPPTR16) - /* Relies on NULL encoding to zero. */ - DUK_MEMZERO(new_entries, sizeof(duk_uint16_t) * new_size); -#else - DUK_MEMZERO(new_entries, sizeof(duk_hstring *) * new_size); -#endif #endif - /* Because new_size > duk__count_used_probe(heap), guaranteed to work */ - for (i = 0; i < old_size; i++) { - duk_hstring *e; + /* External string check (low memory optimization). */ -#if defined(DUK_USE_HEAPPTR16) - e = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, old_entries[i]); -#else - e = old_entries[i]; -#endif - if (e == NULL || e == DUK__DELETED_MARKER(heap)) { - continue; - } - /* checking for DUK__DELETED_MARKER is not necessary here, but helper does it now */ - duk__insert_hstring_probe(heap, new_entries, new_size, &new_used, e); - } - -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1) - DUK_DD(DUK_DDPRINT("resized stringtable: %ld entries, %ld bytes, %ld used, %ld%% load -> %ld entries, %ld bytes, %ld used, %ld%% load", - (long) old_size, (long) (sizeof(duk_hstring *) * old_size), (long) old_used, - (long) (((double) old_used) / ((double) old_size) * 100.0), - (long) new_size, (long) (sizeof(duk_hstring *) * new_size), (long) new_used, - (long) (((double) new_used) / ((double) new_size) * 100.0))); -#endif - -#if defined(DUK_USE_HEAPPTR16) - DUK_FREE(heap, heap->strtable16); - heap->strtable16 = new_entries; +#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) + extdata = (const duk_uint8_t *) DUK_USE_EXTSTR_INTERN_CHECK(heap->heap_udata, (void *) DUK_LOSE_CONST(str), (duk_size_t) blen); #else - DUK_FREE(heap, heap->strtable); - heap->strtable = new_entries; + extdata = (const duk_uint8_t *) NULL; #endif - heap->st_size = new_size; - heap->st_used = new_used; /* may be less, since DELETED entries are NULLed by rehash */ - - return 0; /* OK */ - resize_error: - DUK_FREE(heap, new_entries); - return 1; /* FAIL */ -} - -DUK_LOCAL duk_bool_t duk__resize_strtab_probe(duk_heap *heap) { - duk_uint32_t new_size; - duk_bool_t ret; - - new_size = (duk_uint32_t) duk__count_used_probe(heap); - if (new_size >= 0x80000000UL) { - new_size = DUK_STRTAB_HIGHEST_32BIT_PRIME; - } else { - new_size = duk_util_get_hash_prime(DUK_STRTAB_GROW_ST_SIZE(new_size)); - new_size = duk_util_get_hash_prime(new_size); - } - DUK_ASSERT(new_size > 0); - - /* rehash even if old and new sizes are the same to get rid of - * DELETED entries. - */ - - ret = duk__resize_strtab_raw_probe(heap, new_size); - - return ret; -} - -DUK_LOCAL duk_bool_t duk__recheck_strtab_size_probe(duk_heap *heap, duk_uint32_t new_used) { - duk_uint32_t new_free; - duk_uint32_t tmp1; - duk_uint32_t tmp2; + /* Allocate and initialize string, not yet linked. This may cause a + * GC which may cause other strings to be interned and inserted into + * the string table before we insert our string. Finalizer execution + * is disabled intentionally to avoid a finalizer from e.g. resizing + * a buffer used as a data area for 'str'. + */ - DUK_ASSERT(new_used <= heap->st_size); /* grow by at most one */ - new_free = heap->st_size - new_used; /* unsigned intentionally */ + res = duk__strtable_alloc_hstring(heap, str, blen, strhash, extdata); - /* new_free / size <= 1 / DIV <=> new_free <= size / DIV */ - /* new_used / size <= 1 / DIV <=> new_used <= size / DIV */ + /* Allow side effects again: GC must be avoided until duk_hstring + * result (if successful) has been INCREF'd. + */ + DUK_ASSERT(heap->pf_prevent_count > 0); + heap->pf_prevent_count--; - tmp1 = heap->st_size / DUK_STRTAB_MIN_FREE_DIVISOR; - tmp2 = heap->st_size / DUK_STRTAB_MIN_USED_DIVISOR; + /* Alloc error handling. */ - if (new_free <= tmp1 || new_used <= tmp2) { - /* load factor too low or high, count actually used entries and resize */ - return duk__resize_strtab_probe(heap); - } else { - return 0; /* OK */ + if (DUK_UNLIKELY(res == NULL)) { +#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) + if (extdata != NULL) { + DUK_USE_EXTSTR_FREE(heap->heap_udata, (const void *) extdata); + } +#endif + return NULL; } -} -#if defined(DUK_USE_DEBUG) -DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap) { - duk_uint32_t i; - duk_hstring *h; + /* Insert into string table. */ - DUK_ASSERT(heap != NULL); -#if defined(DUK_USE_HEAPPTR16) - DUK_ASSERT(heap->strtable16 != NULL); +#if defined(DUK_USE_STRTAB_PTRCOMP) + slot = heap->strtable16 + (strhash & heap->st_mask); #else - DUK_ASSERT(heap->strtable != NULL); + slot = heap->strtable + (strhash & heap->st_mask); #endif - DUK_UNREF(h); + DUK_ASSERT(res->hdr.h_next == NULL); /* This is the case now, but unnecessary zeroing/NULLing. */ + res->hdr.h_next = DUK__HEAPPTR_DEC16(heap, *slot); + *slot = DUK__HEAPPTR_ENC16(heap, res); - for (i = 0; i < heap->st_size; i++) { -#if defined(DUK_USE_HEAPPTR16) - h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->strtable16[i]); -#else - h = heap->strtable[i]; + /* Update string count only for successful inserts. */ + +#if defined(DUK__STRTAB_RESIZE_CHECK) + heap->st_count++; #endif - DUK_DD(DUK_DDPRINT("[%03d] -> %p", (int) i, (void *) h)); - } -} -#endif /* DUK_USE_DEBUG */ + /* The duk_hstring is in the string table but is not yet strongly + * reachable. Calling code MUST NOT make any allocations or other + * side effects before the duk_hstring has been INCREF'd and made + * reachable. + */ -#endif /* DUK_USE_STRTAB_PROBE */ + return res; +} /* - * Raw intern and lookup + * Intern a string from str/blen, returning either an existing duk_hstring + * or adding a new one into the string table. The input string does -not- + * need to be NUL terminated. + * + * The input 'str' argument may point to a Duktape managed data area such as + * the data area of a dynamic buffer. It's crucial to avoid any side effects + * that might affect the data area (e.g. resize the dynamic buffer, or write + * to the buffer) before the string is fully interned. */ -DUK_LOCAL duk_hstring *duk__do_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { - duk_hstring *res; - const duk_uint8_t *extdata; - duk_small_uint_t prev_mark_and_sweep_base_flags; +#if defined(DUK_USE_ROM_STRINGS) +DUK_LOCAL duk_hstring *duk__strtab_romstring_lookup(duk_heap *heap, const duk_uint8_t *str, duk_size_t blen, duk_uint32_t strhash) { + duk_size_t lookup_hash; + duk_hstring *curr; - /* Prevent any side effects on the string table and the caller provided - * str/blen arguments while interning is in progress. For example, if - * the caller provided str/blen from a dynamic buffer, a finalizer might - * resize that dynamic buffer, invalidating the call arguments. - */ - DUK_ASSERT((heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE) == 0); - prev_mark_and_sweep_base_flags = heap->mark_and_sweep_base_flags; - DUK__PREVENT_MS_SIDE_EFFECTS(heap); + DUK_ASSERT(heap != NULL); + DUK_UNREF(heap); -#if defined(DUK_USE_STRTAB_PROBE) - if (duk__recheck_strtab_size_probe(heap, heap->st_used + 1)) { - goto failed; + lookup_hash = (blen << 4); + if (blen > 0) { + lookup_hash += str[0]; } -#endif + lookup_hash &= 0xff; -#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) - extdata = (const duk_uint8_t *) DUK_USE_EXTSTR_INTERN_CHECK(heap->heap_udata, (void *) DUK_LOSE_CONST(str), (duk_size_t) blen); -#else - extdata = (const duk_uint8_t *) NULL; -#endif - res = duk__alloc_init_hstring(heap, str, blen, strhash, extdata); - if (!res) { - goto failed; + curr = DUK_LOSE_CONST(duk_rom_strings_lookup[lookup_hash]); + while (curr != NULL) { + if (strhash == DUK_HSTRING_GET_HASH(curr) && + blen == DUK_HSTRING_GET_BYTELEN(curr) && + DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(curr), blen) == 0) { + DUK_DDD(DUK_DDDPRINT("intern check: rom string: %!O, computed hash 0x%08lx, rom hash 0x%08lx", + curr, (unsigned long) strhash, (unsigned long) DUK_HSTRING_GET_HASH(curr))); + return curr; + } + curr = curr->hdr.h_next; } -#if defined(DUK_USE_STRTAB_CHAIN) - if (duk__insert_hstring_chain(heap, res)) { - /* failed */ - DUK_FREE(heap, res); - goto failed; - } -#elif defined(DUK_USE_STRTAB_PROBE) - /* guaranteed to succeed */ - duk__insert_hstring_probe(heap, -#if defined(DUK_USE_HEAPPTR16) - heap->strtable16, -#else - heap->strtable, -#endif - heap->st_size, - &heap->st_used, - res); -#else -#error internal error, invalid strtab options -#endif - - /* Note: hstring is in heap but has refcount zero and is not strongly reachable. - * Caller should increase refcount and make the hstring reachable before any - * operations which require allocation (and possible gc). - */ + return NULL; +} +#endif /* DUK_USE_ROM_STRINGS */ - done: - heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; - return res; +DUK_INTERNAL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) { + duk_uint32_t strhash; + duk_hstring *h; - failed: - res = NULL; - goto done; -} + DUK_DDD(DUK_DDDPRINT("intern check: heap=%p, str=%p, blen=%lu", (void *) heap, (const void *) str, (unsigned long) blen)); -DUK_LOCAL duk_hstring *duk__do_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t *out_strhash) { - duk_hstring *res; + /* Preliminaries. */ - DUK_ASSERT(out_strhash); + DUK_ASSERT(heap != NULL); + DUK_ASSERT(blen == 0 || str != NULL); + DUK_ASSERT(blen <= DUK_HSTRING_MAX_BYTELEN); /* Caller is responsible for ensuring this. */ + strhash = duk_heap_hashstring(heap, str, (duk_size_t) blen); - *out_strhash = duk_heap_hashstring(heap, str, (duk_size_t) blen); + /* String table lookup. */ -#if defined(DUK_USE_ROM_STRINGS) - { - duk_small_uint_t i; - /* XXX: This is VERY inefficient now, and should be e.g. a - * binary search or perfect hash, to be fixed. - */ - for (i = 0; i < (duk_small_uint_t) (sizeof(duk_rom_strings) / sizeof(duk_hstring *)); i++) { - duk_hstring *romstr; - romstr = (duk_hstring *) DUK_LOSE_CONST(duk_rom_strings[i]); - if (blen == DUK_HSTRING_GET_BYTELEN(romstr) && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(romstr), blen) == 0) { - DUK_DD(DUK_DDPRINT("intern check: rom string: %!O, computed hash 0x%08lx, rom hash 0x%08lx", - romstr, (unsigned long) *out_strhash, (unsigned long) DUK_HSTRING_GET_HASH(romstr))); - DUK_ASSERT(*out_strhash == DUK_HSTRING_GET_HASH(romstr)); - *out_strhash = DUK_HSTRING_GET_HASH(romstr); - return romstr; - } + DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL); + DUK_ASSERT(heap->st_size > 0); + DUK_ASSERT(heap->st_size == heap->st_mask + 1); +#if defined(DUK_USE_STRTAB_PTRCOMP) + h = DUK__HEAPPTR_DEC16(heap, heap->strtable16[strhash & heap->st_mask]); +#else + h = heap->strtable[strhash & heap->st_mask]; +#endif + while (h != NULL) { + if (DUK_HSTRING_GET_HASH(h) == strhash && + DUK_HSTRING_GET_BYTELEN(h) == blen && + DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) { + /* Found existing entry. */ + return h; } + h = h->hdr.h_next; } -#endif /* DUK_USE_ROM_STRINGS */ -#if defined(DUK_USE_STRTAB_CHAIN) - res = duk__find_matching_string_chain(heap, str, blen, *out_strhash); -#elif defined(DUK_USE_STRTAB_PROBE) - res = duk__find_matching_string_probe(heap, -#if defined(DUK_USE_HEAPPTR16) - heap->strtable16, -#else - heap->strtable, -#endif - heap->st_size, - str, - blen, - *out_strhash); -#else -#error internal error, invalid strtab options + /* ROM table lookup. Because this lookup is slower, do it only after + * RAM lookup. This works because no ROM string is ever interned into + * the RAM string table. + */ + +#if defined(DUK_USE_ROM_STRINGS) + h = duk__strtab_romstring_lookup(heap, str, blen, strhash); + if (h != NULL) { + return h; + } #endif - return res; + /* Not found in string table; insert. */ + + h = duk__strtable_do_intern(heap, str, blen, strhash); + return h; /* may be NULL */ } /* - * Exposed calls + * Intern a string from u32. */ -#if 0 /*unused*/ -DUK_INTERNAL duk_hstring *duk_heap_string_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) { - duk_uint32_t strhash; /* dummy */ - return duk__do_lookup(heap, str, blen, &strhash); -} -#endif +/* XXX: Could arrange some special handling because we know that the result + * will have an arridx flag and an ASCII flag, won't need a clen check, etc. + */ -DUK_INTERNAL duk_hstring *duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) { - duk_hstring *res; - duk_uint32_t strhash; +DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32(duk_heap *heap, duk_uint32_t val) { + char buf[DUK__STRTAB_U32_MAX_STRLEN]; + char *p; - /* caller is responsible for ensuring this */ - DUK_ASSERT(blen <= DUK_HSTRING_MAX_BYTELEN); + DUK_ASSERT(heap != NULL); - res = duk__do_lookup(heap, str, blen, &strhash); - if (res) { - return res; - } + /* This is smaller and faster than a %lu sprintf. */ + p = buf + sizeof(buf); + do { + p--; + *p = duk_lc_digits[val % 10]; + val = val / 10; + } while (val != 0); /* For val == 0, emit exactly one '0'. */ + DUK_ASSERT(p >= buf); - res = duk__do_intern(heap, str, blen, strhash); - return res; /* may be NULL */ + return duk_heap_strtable_intern(heap, (const duk_uint8_t *) p, (duk_uint32_t) ((buf + sizeof(buf)) - p)); } -DUK_INTERNAL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) { - duk_hstring *res = duk_heap_string_intern(thr->heap, str, blen); - if (!res) { +/* + * Checked convenience variants. + * + * XXX: Because the main use case is for the checked variants, make them the + * main functionality and provide a safe variant separately (it is only needed + * during heap init). The problem with that is that longjmp state and error + * creation must already be possible to throw. + */ + +DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) { + duk_hstring *res; + + DUK_ASSERT(thr != NULL); + DUK_ASSERT(thr->heap != NULL); + DUK_ASSERT(blen == 0 || str != NULL); + + res = duk_heap_strtable_intern(thr->heap, str, blen); + if (DUK_UNLIKELY(res == NULL)) { DUK_ERROR_ALLOC_FAILED(thr); } return res; } -#if 0 /*unused*/ -DUK_INTERNAL duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val) { - char buf[DUK_STRTAB_U32_MAX_STRLEN+1]; - DUK_SNPRINTF(buf, sizeof(buf), "%lu", (unsigned long) val); - buf[sizeof(buf) - 1] = (char) 0; - DUK_ASSERT(DUK_STRLEN(buf) <= DUK_UINT32_MAX); /* formatted result limited */ - return duk_heap_string_lookup(heap, (const duk_uint8_t *) buf, (duk_uint32_t) DUK_STRLEN(buf)); -} -#endif +DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32_checked(duk_hthread *thr, duk_uint32_t val) { + duk_hstring *res; -DUK_INTERNAL duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val) { - char buf[DUK_STRTAB_U32_MAX_STRLEN+1]; - DUK_SNPRINTF(buf, sizeof(buf), "%lu", (unsigned long) val); - buf[sizeof(buf) - 1] = (char) 0; - DUK_ASSERT(DUK_STRLEN(buf) <= DUK_UINT32_MAX); /* formatted result limited */ - return duk_heap_string_intern(heap, (const duk_uint8_t *) buf, (duk_uint32_t) DUK_STRLEN(buf)); -} + DUK_ASSERT(thr != NULL); + DUK_ASSERT(thr->heap != NULL); -DUK_INTERNAL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val) { - duk_hstring *res = duk_heap_string_intern_u32(thr->heap, val); - if (!res) { + res = duk_heap_strtable_intern_u32(thr->heap, val); + if (DUK_UNLIKELY(res == NULL)) { DUK_ERROR_ALLOC_FAILED(thr); } return res; } -/* find and remove string from stringtable; caller must free the string itself */ +/* + * Remove (unlink) a string from the string table. + * + * Just unlinks the duk_hstring, leaving link pointers as garbage. + * Caller must free the string itself. + */ + #if defined(DUK_USE_REFERENCE_COUNTING) -DUK_INTERNAL void duk_heap_string_remove(duk_heap *heap, duk_hstring *h) { - DUK_DDD(DUK_DDDPRINT("remove string from stringtable: %!O", (duk_heaphdr *) h)); +/* Unlink without a 'prev' pointer. */ +DUK_INTERNAL void duk_heap_strtable_unlink(duk_heap *heap, duk_hstring *h) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *slot; +#else + duk_hstring **slot; +#endif + duk_hstring *other; + duk_hstring *prev; + + DUK_DDD(DUK_DDDPRINT("remove: heap=%p, h=%p, blen=%lu, strhash=%lx", + (void *) heap, (void *) h, + (unsigned long) (h != NULL ? DUK_HSTRING_GET_BYTELEN(h) : 0), + (unsigned long) (h != NULL ? DUK_HSTRING_GET_HASH(h) : 0))); -#if defined(DUK_USE_STRTAB_CHAIN) - duk__remove_matching_hstring_chain(heap, h); -#elif defined(DUK_USE_STRTAB_PROBE) - duk__remove_matching_hstring_probe(heap, -#if defined(DUK_USE_HEAPPTR16) - heap->strtable16, -#else - heap->strtable, + DUK_ASSERT(heap != NULL); + DUK_ASSERT(h != NULL); + +#if defined(DUK__STRTAB_RESIZE_CHECK) + DUK_ASSERT(heap->st_count > 0); + heap->st_count--; #endif - heap->st_size, - h); + +#if defined(DUK_USE_STRTAB_PTRCOMP) + slot = heap->strtable16 + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); #else -#error internal error, invalid strtab options + slot = heap->strtable + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); #endif + other = DUK__HEAPPTR_DEC16(heap, *slot); + DUK_ASSERT(other != NULL); /* At least argument string is in the chain. */ + + prev = NULL; + while (other != h) { + prev = other; + other = other->hdr.h_next; + DUK_ASSERT(other != NULL); /* We'll eventually find 'h'. */ + } + if (prev != NULL) { + /* Middle of list. */ + prev->hdr.h_next = h->hdr.h_next; + } else { + /* Head of list. */ + *slot = DUK__HEAPPTR_ENC16(heap, h->hdr.h_next); + } + + /* There's no resize check on a string free. The next string + * intern will do one. + */ } +#endif /* DUK_USE_REFERENCE_COUNTING */ + +/* Unlink with a 'prev' pointer. */ +DUK_INTERNAL void duk_heap_strtable_unlink_prev(duk_heap *heap, duk_hstring *h, duk_hstring *prev) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *slot; +#else + duk_hstring **slot; #endif -#if defined(DUK_USE_MS_STRINGTABLE_RESIZE) -DUK_INTERNAL void duk_heap_force_strtab_resize(duk_heap *heap) { - duk_small_uint_t prev_mark_and_sweep_base_flags; - /* Force a resize so that DELETED entries are eliminated. - * Another option would be duk__recheck_strtab_size_probe(); - * but since that happens on every intern anyway, this whole - * check can now be disabled. - */ + DUK_DDD(DUK_DDDPRINT("remove: heap=%p, prev=%p, h=%p, blen=%lu, strhash=%lx", + (void *) heap, (void *) prev, (void *) h, + (unsigned long) (h != NULL ? DUK_HSTRING_GET_BYTELEN(h) : 0), + (unsigned long) (h != NULL ? DUK_HSTRING_GET_HASH(h) : 0))); - DUK_ASSERT((heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE) == 0); - prev_mark_and_sweep_base_flags = heap->mark_and_sweep_base_flags; - DUK__PREVENT_MS_SIDE_EFFECTS(heap); + DUK_ASSERT(heap != NULL); + DUK_ASSERT(h != NULL); + DUK_ASSERT(prev == NULL || prev->hdr.h_next == h); -#if defined(DUK_USE_STRTAB_CHAIN) - DUK_UNREF(heap); -#elif defined(DUK_USE_STRTAB_PROBE) - (void) duk__resize_strtab_probe(heap); +#if defined(DUK__STRTAB_RESIZE_CHECK) + DUK_ASSERT(heap->st_count > 0); + heap->st_count--; #endif - heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; -} + if (prev != NULL) { + /* Middle of list. */ + prev->hdr.h_next = h->hdr.h_next; + } else { + /* Head of list. */ +#if defined(DUK_USE_STRTAB_PTRCOMP) + slot = heap->strtable16 + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); +#else + slot = heap->strtable + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); #endif + DUK_ASSERT(DUK__HEAPPTR_DEC16(heap, *slot) == h); + *slot = DUK__HEAPPTR_ENC16(heap, h->hdr.h_next); + } +} + +/* + * Force string table resize check in mark-and-sweep. + */ -#if defined(DUK_USE_STRTAB_CHAIN) -DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap) { - /* Free strings in the stringtable and any allocations needed - * by the stringtable itself. +DUK_INTERNAL void duk_heap_strtable_force_resize(duk_heap *heap) { + /* Does only one grow/shrink step if needed. The heap->st_resizing + * flag protects against recursive resizing. */ - duk_uint_fast32_t i, j; - duk_strtab_entry *e; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t *lst; - duk_uint16_t null16 = heap->heapptr_null16; -#else - duk_hstring **lst; -#endif - duk_hstring *h; - for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { - e = heap->strtable + i; - if (e->listlen > 0) { -#if defined(DUK_USE_HEAPPTR16) - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); -#else - lst = e->u.strlist; -#endif - DUK_ASSERT(lst != NULL); + DUK_ASSERT(heap != NULL); + DUK_UNREF(heap); - for (j = 0; j < e->listlen; j++) { -#if defined(DUK_USE_HEAPPTR16) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[j]); - lst[j] = null16; -#else - h = lst[j]; - lst[j] = NULL; -#endif - /* strings may have inner refs (extdata) in some cases */ - if (h != NULL) { - duk_free_hstring(heap, h); - } - } -#if defined(DUK_USE_HEAPPTR16) - e->u.strlist16 = null16; -#else - e->u.strlist = NULL; -#endif - DUK_FREE(heap, lst); - } else { -#if defined(DUK_USE_HEAPPTR16) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16); - e->u.str16 = null16; +#if defined(DUK__STRTAB_RESIZE_CHECK) +#if defined(DUK_USE_STRTAB_PTRCOMP) + if (heap->strtable16 != NULL) { #else - h = e->u.str; - e->u.str = NULL; + if (heap->strtable != NULL) { #endif - if (h != NULL) { - duk_free_hstring(heap, h); - } - } - e->listlen = 0; + duk__strtable_resize_check(heap); } +#endif } -#endif /* DUK_USE_STRTAB_CHAIN */ -#if defined(DUK_USE_STRTAB_PROBE) -DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap) { - duk_uint_fast32_t i; - duk_hstring *h; +/* + * Free strings in the string table and the string table itself. + */ -#if defined(DUK_USE_HEAPPTR16) - if (heap->strtable16) { +DUK_INTERNAL void duk_heap_strtable_free(duk_heap *heap) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *strtable; + duk_uint16_t *st; #else - if (heap->strtable) { + duk_hstring **strtable; + duk_hstring **st; #endif - for (i = 0; i < (duk_uint_fast32_t) heap->st_size; i++) { -#if defined(DUK_USE_HEAPPTR16) - h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); -#else - h = heap->strtable[i]; + duk_hstring *h; + + DUK_ASSERT(heap != NULL); + +#if defined(DUK_USE_ASSERTIONS) + duk__strtable_assert_checks(heap); #endif - if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) { - continue; - } - DUK_ASSERT(h != NULL); - /* strings may have inner refs (extdata) in some cases */ + /* Strtable can be NULL if heap init fails. However, in that case + * heap->st_size is 0, so strtable == strtable_end and we skip the + * loop without a special check. + */ + strtable = DUK__GET_STRTABLE(heap); + st = strtable + heap->st_size; + DUK_ASSERT(strtable != NULL || heap->st_size == 0); + + while (strtable != st) { + --st; + h = DUK__HEAPPTR_DEC16(heap, *st); + while (h) { + duk_hstring *h_next; + h_next = h->hdr.h_next; + + /* Strings may have inner refs (extdata) in some cases. */ duk_free_hstring(heap, h); -#if 0 /* not strictly necessary */ - heap->strtable[i] = NULL; -#endif + + h = h_next; } -#if defined(DUK_USE_HEAPPTR16) - DUK_FREE(heap, heap->strtable16); -#else - DUK_FREE(heap, heap->strtable); -#endif -#if 0 /* not strictly necessary */ - heap->strtable = NULL; -#endif } + + DUK_FREE(heap, strtable); } -#endif /* DUK_USE_STRTAB_PROBE */ /* automatic undefs */ -#undef DUK__DELETED_MARKER -#undef DUK__HASH_INITIAL -#undef DUK__HASH_PROBE_STEP -#undef DUK__PREVENT_MS_SIDE_EFFECTS +#undef DUK__GET_STRTABLE +#undef DUK__HEAPPTR_DEC16 +#undef DUK__HEAPPTR_ENC16 +#undef DUK__STRTAB_U32_MAX_STRLEN /* * Hobject allocation. * @@ -48614,19 +50307,29 @@ * 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 duk_internal.h -> already included */ -DUK_LOCAL void duk__init_object_parts(duk_heap *heap, duk_hobject *obj, duk_uint_t hobject_flags) { +/* + * 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 - - /* XXX: macro? sets both heaphdr and object flags */ - obj->hdr.h_flags = hobject_flags; - DUK_HEAPHDR_SET_TYPE(&obj->hdr, DUK_HTYPE_OBJECT); /* also goes into flags */ - #if defined(DUK_USE_HEAPPTR16) - /* Zero encoded pointer is required to match NULL */ + /* 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); @@ -48635,14 +50338,22 @@ DUK_ASSERT_HEAPHDR_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. + /* 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. * @@ -48654,7 +50365,7 @@ * count before invoking any operation that might require memory allocation. */ -DUK_INTERNAL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags) { +DUK_INTERNAL duk_hobject *duk_hobject_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags) { duk_hobject *res; DUK_ASSERT(heap != NULL); @@ -48662,30 +50373,30 @@ /* 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_THREAD) == 0); - res = (duk_hobject *) DUK_ALLOC(heap, sizeof(duk_hobject)); - if (!res) { + res = (duk_hobject *) DUK_ALLOC_ZEROED(heap, sizeof(duk_hobject)); + if (DUK_UNLIKELY(res == NULL)) { return NULL; } - DUK_MEMZERO(res, sizeof(duk_hobject)); + DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(res)); - duk__init_object_parts(heap, res, hobject_flags); + duk__init_object_parts(heap, hobject_flags, res); + DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(res)); return res; } -DUK_INTERNAL duk_hcompfunc *duk_hcompfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags) { - duk_hcompfunc *res; +DUK_INTERNAL duk_hobject *duk_hobject_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { + duk_hobject *res; - res = (duk_hcompfunc *) DUK_ALLOC(heap, sizeof(duk_hcompfunc)); - if (!res) { - return NULL; - } - DUK_MEMZERO(res, sizeof(duk_hcompfunc)); + res = (duk_hobject *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hobject)); + return res; +} - duk__init_object_parts(heap, &res->obj, hobject_flags); +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. */ @@ -48701,17 +50412,10 @@ return res; } -DUK_INTERNAL duk_hnatfunc *duk_hnatfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags) { +DUK_INTERNAL duk_hnatfunc *duk_hnatfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { duk_hnatfunc *res; - res = (duk_hnatfunc *) DUK_ALLOC(heap, sizeof(duk_hnatfunc)); - if (!res) { - return NULL; - } - DUK_MEMZERO(res, sizeof(duk_hnatfunc)); - - duk__init_object_parts(heap, &res->obj, hobject_flags); - + res = (duk_hnatfunc *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hnatfunc)); #if defined(DUK_USE_EXPLICIT_NULL_INIT) res->func = NULL; #endif @@ -48720,17 +50424,10 @@ } #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_hbufobj *duk_hbufobj_alloc(duk_heap *heap, duk_uint_t hobject_flags) { +DUK_INTERNAL duk_hbufobj *duk_hbufobj_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { duk_hbufobj *res; - res = (duk_hbufobj *) DUK_ALLOC(heap, sizeof(duk_hbufobj)); - if (!res) { - return NULL; - } - DUK_MEMZERO(res, sizeof(duk_hbufobj)); - - duk__init_object_parts(heap, &res->obj, hobject_flags); - + 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; @@ -48741,24 +50438,22 @@ } #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ -/* - * Allocate a new thread. +/* 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. + * 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(duk_heap *heap, duk_uint_t hobject_flags) { +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 (!res) { + if (DUK_UNLIKELY(res == NULL)) { return NULL; } DUK_MEMZERO(res, sizeof(duk_hthread)); - duk__init_object_parts(heap, &res->obj, hobject_flags); + duk__init_object_parts(heap, hobject_flags, &res->obj); #if defined(DUK_USE_EXPLICIT_NULL_INIT) res->ptr_curr_pc = NULL; @@ -48768,6 +50463,7 @@ res->valstack_bottom = NULL; res->valstack_top = NULL; res->callstack = NULL; + res->callstack_curr = NULL; res->catchstack = NULL; res->resumer = NULL; res->compile_ctx = NULL, @@ -48777,7 +50473,7 @@ res->strs = NULL; #endif { - int i; + duk_small_uint_t i; for (i = 0; i < DUK_NUM_BUILTINS; i++) { res->builtins[i] = NULL; } @@ -48794,32 +50490,51 @@ return res; } -#if 0 /* unused now */ -DUK_INTERNAL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags) { - duk_hobject *res = duk_hobject_alloc(thr->heap, hobject_flags); - if (!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); } 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 -/* - * Allocate a new array. - */ + DUK_ASSERT(res->thread == NULL); + DUK_ASSERT(res->varmap == NULL); + DUK_ASSERT(res->regbase == 0); -DUK_INTERNAL duk_harray *duk_harray_alloc(duk_heap *heap, duk_uint_t hobject_flags) { - duk_harray *res; + return res; +} - res = (duk_harray *) DUK_ALLOC(heap, sizeof(duk_harray)); - if (!res) { - return NULL; - } - DUK_MEMZERO(res, sizeof(duk_harray)); +DUK_INTERNAL duk_hobjenv *duk_hobjenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { + duk_hobjenv *res; - duk__init_object_parts(heap, &res->obj, hobject_flags); + 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->length == 0); + DUK_ASSERT(res->target == NULL); return res; } @@ -49067,6 +50782,9 @@ */ DUK_LOCAL void duk__add_enum_key(duk_context *ctx, duk_hstring *k) { + /* 'k' may be unreachable on entry so must push without any + * potential for GC. + */ duk_push_hstring(ctx, k); duk_push_true(ctx); duk_put_prop(ctx, -3); @@ -49267,7 +50985,7 @@ /* This is a bit fragile: the string is not * reachable until it is pushed by the helper. */ - k = duk_heap_string_intern_u32_checked(thr, i); + k = duk_heap_strtable_intern_u32_checked(thr, i); DUK_ASSERT(k); duk__add_enum_key(ctx, k); @@ -49301,7 +51019,7 @@ if (DUK_TVAL_IS_UNUSED(tv)) { continue; } - k = duk_heap_string_intern_u32_checked(thr, i); /* Fragile reachability. */ + k = duk_heap_strtable_intern_u32_checked(thr, i); /* Fragile reachability. */ DUK_ASSERT(k); duk__add_enum_key(ctx, k); @@ -49331,7 +51049,7 @@ !DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(thr->heap, curr, i)) { continue; } - if (DUK_HSTRING_HAS_SYMBOL(k)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(k))) { if (!(enum_flags & DUK_ENUM_INCLUDE_HIDDEN) && DUK_HSTRING_HAS_HIDDEN(k)) { continue; @@ -49597,119 +51315,6 @@ /* automatic undefs */ #undef DUK__ENUM_START_INDEX /* - * Run an duk_hobject finalizer. Used for both reference counting - * and mark-and-sweep algorithms. Must never throw an error. - * - * There is no return value. Any return value or error thrown by - * the finalizer is ignored (although errors are debug logged). - * - * Notes: - * - * - The thread used for calling the finalizer is the same as the - * 'thr' argument. This may need to change later. - * - * - 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). - */ - -/* #include duk_internal.h -> already included */ - -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_LOCAL duk_ret_t duk__finalize_helper(duk_context *ctx, void *udata) { - duk_hthread *thr; - - DUK_ASSERT(ctx != NULL); - thr = (duk_hthread *) ctx; - DUK_UNREF(udata); - - DUK_DDD(DUK_DDDPRINT("protected finalization helper running")); - - /* [... obj] */ - - /* 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(ctx, -1, DUK_STRIDX_INT_FINALIZER); /* -> [... obj finalizer] */ - if (!duk_is_callable(ctx, -1)) { - DUK_DDD(DUK_DDDPRINT("-> no finalizer or finalizer not callable")); - return 0; - } - duk_dup_m2(ctx); - duk_push_boolean(ctx, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap)); - DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling finalizer")); - duk_call(ctx, 2); /* [ ... obj finalizer obj heapDestruct ] -> [ ... obj retval ] */ - DUK_DDD(DUK_DDDPRINT("finalizer finished 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_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj) { - duk_context *ctx = (duk_context *) thr; - duk_ret_t rc; -#if defined(DUK_USE_ASSERTIONS) - duk_idx_t entry_top; -#endif - - DUK_DDD(DUK_DDDPRINT("running object finalizer for object: %p", (void *) obj)); - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(ctx != NULL); - DUK_ASSERT(obj != NULL); - DUK_ASSERT_VALSTACK_SPACE(thr, 1); - -#if defined(DUK_USE_ASSERTIONS) - entry_top = duk_get_top(ctx); -#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). - */ - - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); - if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj)) { - DUK_D(DUK_DPRINT("object already finalized, avoid running finalizer twice: %!O", obj)); - return; - } - DUK_HEAPHDR_SET_FINALIZED((duk_heaphdr *) obj); /* ensure never re-entered until rescue cycle complete */ - if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj)) { - /* This shouldn't happen; call sites should avoid looking up - * _Finalizer "through" a Proxy, but ignore if we come here - * with a Proxy to avoid finalizer re-entry. - */ - DUK_D(DUK_DPRINT("object is a proxy, skip finalizer call")); - return; - } - - /* XXX: use a NULL error handler for the finalizer call? */ - - DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling wrapped finalize helper")); - duk_push_hobject(ctx, obj); /* this also increases refcount by one */ - rc = duk_safe_call(ctx, duk__finalize_helper, NULL /*udata*/, 0 /*nargs*/, 1 /*nrets*/); /* -> [... obj retval/error] */ - DUK_ASSERT_TOP(ctx, 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(ctx, -1))); - } - duk_pop_2(ctx); /* -> [...] */ - - DUK_ASSERT_TOP(ctx, entry_top); -} -#endif /* DUK_USE_FINALIZER_SUPPORT */ -/* * Misc support functions */ @@ -49913,7 +51518,7 @@ 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 error; + goto pc2line_error; } hdr = (duk_uint32_t *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, buf); @@ -49922,7 +51527,7 @@ /* 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 error; + goto pc2line_error; } curr_line = hdr[1 + hdr_index * 2]; @@ -49930,7 +51535,7 @@ 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 error; + goto pc2line_error; } /* @@ -49981,7 +51586,7 @@ DUK_DDD(DUK_DDDPRINT("pc2line lookup result: pc %ld -> line %ld", (long) pc, (long) curr_line)); return curr_line; - error: + pc2line_error: DUK_D(DUK_DPRINT("pc2line conversion failed for pc=%ld", (long) pc)); return 0; } @@ -50011,7 +51616,7 @@ #endif /* DUK_USE_PC2LINE */ /* - * Hobject property set/get functionality. + * duk_hobject property access functionality. * * This is very central functionality for size, performance, and compliance. * It is also rather intricate; see hobject-algorithms.rst for discussion on @@ -50052,10 +51657,6 @@ * might be more appropriate. */ -/* - * XXX: duk_uint_fast32_t should probably be used in many places here. - */ - /* #include duk_internal.h -> already included */ /* @@ -50064,10 +51665,6 @@ #define DUK__NO_ARRAY_INDEX DUK_HSTRING_NO_ARRAY_INDEX -/* hash probe sequence */ -#define DUK__HASH_INITIAL(hash,h_size) DUK_HOBJECT_HASH_INITIAL((hash),(h_size)) -#define DUK__HASH_PROBE_STEP(hash) DUK_HOBJECT_HASH_PROBE_STEP((hash)) - /* marker values for hash part */ #define DUK__HASH_UNUSED DUK_HOBJECT_HASHIDX_UNUSED #define DUK__HASH_DELETED DUK_HOBJECT_HASHIDX_DELETED @@ -50230,14 +51827,26 @@ DUK_LOCAL duk_uint32_t duk__get_default_h_size(duk_uint32_t e_size) { DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES); - if (e_size >= DUK_HOBJECT_E_USE_HASH_LIMIT) { + if (e_size >= DUK_USE_HOBJECT_HASH_PROP_LIMIT) { duk_uint32_t res; + duk_uint32_t tmp; - /* result: hash_prime(floor(1.2 * e_size)) */ - res = duk_util_get_hash_prime(e_size + e_size / DUK_HOBJECT_H_SIZE_DIVISOR); - - /* if fails, e_size will be zero = not an issue, except performance-wise */ - DUK_ASSERT(res == 0 || res > e_size); + /* Hash size should be 2^N where N is chosen so that 2^N is + * larger than e_size. Extra shifting is used to ensure hash + * is relatively sparse. + */ + tmp = e_size; + res = 2; /* Result will be 2 ** (N + 1). */ + while (tmp >= 0x40) { + tmp >>= 6; + res <<= 6; + } + while (tmp != 0) { + tmp >>= 1; + res <<= 1; + } + DUK_ASSERT((DUK_HOBJECT_MAX_PROPERTIES << 2U) > DUK_HOBJECT_MAX_PROPERTIES); /* Won't wrap, even shifted by 2. */ + DUK_ASSERT(res > e_size); return res; } else { return 0; @@ -50251,7 +51860,7 @@ DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES); - res = (e_size + DUK_HOBJECT_E_MIN_GROW_ADD) / DUK_HOBJECT_E_MIN_GROW_DIVISOR; + res = (e_size + DUK_USE_HOBJECT_ENTRY_MINGROW_ADD) / DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR; DUK_ASSERT(res >= 1); /* important for callers */ return res; } @@ -50262,7 +51871,7 @@ DUK_ASSERT((duk_size_t) a_size <= DUK_HOBJECT_MAX_PROPERTIES); - res = (a_size + DUK_HOBJECT_A_MIN_GROW_ADD) / DUK_HOBJECT_A_MIN_GROW_DIVISOR; + res = (a_size + DUK_USE_HOBJECT_ARRAY_MINGROW_ADD) / DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR; DUK_ASSERT(res >= 1); /* important for callers */ return res; } @@ -50337,7 +51946,7 @@ * of the check, but may confuse debugging. */ - return (a_used < DUK_HOBJECT_A_ABANDON_LIMIT * (a_size >> 3)); + return (a_used < DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT * (a_size >> 3)); } /* Fast check for extending array: check whether or not a slow density check is required. */ @@ -50363,7 +51972,7 @@ * arr_idx > limit'' * ((old_size + 7) / 8) */ - return (arr_idx > DUK_HOBJECT_A_FAST_RESIZE_LIMIT * ((old_size + 7) >> 3)); + return (arr_idx > DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT * ((old_size + 7) >> 3)); } /* @@ -50515,29 +52124,26 @@ /* * Reallocate property allocation, moving properties to the new allocation. * - * Includes key compaction, rehashing, and can also optionally abandoning + * Includes key compaction, rehashing, and can also optionally abandon * the array part, 'migrating' array entries into the beginning of the - * new entry part. Arguments are not validated here, so e.g. new_h_size - * MUST be a valid prime. + * new entry part. * * There is no support for in-place reallocation or just compacting keys * without resizing the property allocation. This is intentional to keep - * code size minimal. + * code size minimal, but would be useful future work. * * The implementation is relatively straightforward, except for the array * abandonment process. Array abandonment requires that new string keys * are interned, which may trigger GC. All keys interned so far must be - * reachable for GC at all times; valstack is used for that now. + * reachable for GC at all times and correctly refcounted for; valstack is + * used for that now. * * Also, a GC triggered during this reallocation process must not interfere - * with the object being resized. This is currently controlled by using - * heap->mark_and_sweep_base_flags to indicate that no finalizers will be - * executed (as they can affect ANY object) and no objects are compacted - * (it would suffice to protect this particular object only, though). - * - * Note: a non-checked variant would be nice but is a bit tricky to - * implement for the array abandonment process. It's easy for - * everything else. + * with the object being resized. This is currently controlled by preventing + * finalizers (as they may affect ANY object) and object compaction in + * mark-and-sweep. It would suffice to protect only this particular object + * from compaction, however. DECREF refzero cascades are side effect free + * and OK. * * Note: because we need to potentially resize the valstack (as part * of abandoning the array part), any tval pointers to the valstack @@ -50551,7 +52157,7 @@ duk_uint32_t new_h_size, duk_bool_t abandon_array) { duk_context *ctx = (duk_context *) thr; - duk_small_uint_t prev_mark_and_sweep_base_flags; + duk_small_uint_t prev_ms_base_flags; duk_uint32_t new_alloc_size; duk_uint32_t new_e_size_adjusted; duk_uint8_t *new_p; @@ -50562,6 +52168,10 @@ duk_uint32_t *new_h; duk_uint32_t new_e_next; duk_uint_fast32_t i; + duk_size_t array_copy_size; +#if defined(DUK_USE_ASSERTIONS) + duk_bool_t prev_error_not_allowed; +#endif DUK_ASSERT(thr != NULL); DUK_ASSERT(ctx != NULL); @@ -50631,9 +52241,8 @@ /* * Property count check. This is the only point where we ensure that * we don't get more (allocated) property space that we can handle. - * There aren't hard limits as such, but some algorithms fail (e.g. - * finding next higher prime, selecting hash part size) if we get too - * close to the 4G property limit. + * There aren't hard limits as such, but some algorithms may fail + * if we get too close to the 4G property limit. * * Since this works based on allocation size (not actually used size), * the limit is a bit approximate but good enough in practice. @@ -50646,43 +52255,46 @@ /* * Compute new alloc size and alloc new area. * - * The new area is allocated as a dynamic buffer and placed into the - * valstack for reachability. The actual buffer is then detached at - * the end. - * - * Note: heap_mark_and_sweep_base_flags are altered here to ensure - * no-one touches this object while we're resizing and rehashing it. - * The flags must be reset on every exit path after it. Finalizers - * and compaction is prevented currently for all objects while it - * would be enough to restrict it only for the current object. + * The new area is not tracked in the heap at all, so it's critical + * we get to free/keep it in a controlled manner. */ - prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags; - thr->heap->mark_and_sweep_base_flags |= - DUK_MS_FLAG_NO_FINALIZERS | /* avoid attempts to add/remove object keys */ - DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid attempt to compact the current object */ +#if defined(DUK_USE_ASSERTIONS) + /* Whole path must be error throw free, but we may be called from + * within error handling so can't assert for error_not_allowed == 0. + */ + prev_error_not_allowed = thr->heap->error_not_allowed; + thr->heap->error_not_allowed = 1; +#endif + prev_ms_base_flags = thr->heap->ms_base_flags; + thr->heap->ms_base_flags |= + DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* Avoid attempt to compact the current object (all objects really). */ + thr->heap->pf_prevent_count++; /* Avoid finalizers. */ + DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */ new_alloc_size = DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size); DUK_DDD(DUK_DDDPRINT("new hobject allocation size is %ld", (long) new_alloc_size)); if (new_alloc_size == 0) { - /* for zero size, don't push anything on valstack */ DUK_ASSERT(new_e_size_adjusted == 0); DUK_ASSERT(new_a_size == 0); DUK_ASSERT(new_h_size == 0); new_p = NULL; } else { - /* This may trigger mark-and-sweep with arbitrary side effects, - * including an attempted resize of the object we're resizing, - * executing a finalizer which may add or remove properties of - * the object we're resizing etc. - */ - - /* Note: buffer is dynamic so that we can 'steal' the actual - * allocation later. + /* Alloc may trigger mark-and-sweep but no compaction, and + * cannot throw. */ - - new_p = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, new_alloc_size); /* errors out if out of memory */ - DUK_ASSERT(new_p != NULL); /* since new_alloc_size > 0 */ +#if 0 /* XXX: inject test */ + if (1) { + goto alloc_failed; + } +#endif + new_p = (duk_uint8_t *) DUK_ALLOC(thr->heap, new_alloc_size); + if (new_p == NULL) { + /* NULL always indicates alloc failure because + * new_alloc_size > 0. + */ + goto alloc_failed; + } } /* Set up pointers to the new property area: this is hidden behind a macro @@ -50703,27 +52315,27 @@ (void *) new_a, (void *) new_h)); /* - * Migrate array to start of entries if requested. + * Migrate array part to start of entries if requested. * * Note: from an enumeration perspective the order of entry keys matters. * Array keys should appear wherever they appeared before the array abandon - * operation. + * operation. (This no longer matters much because keys are ES2015 sorted.) */ if (abandon_array) { - /* - * Note: assuming new_a_size == 0, and that entry part contains - * no conflicting keys, refcounts do not need to be adjusted for - * the values, as they remain exactly the same. + /* Assuming new_a_size == 0, and that entry part contains + * no conflicting keys, refcounts do not need to be adjusted for + * the values, as they remain exactly the same. * - * The keys, however, need to be interned, incref'd, and be - * reachable for GC. Any intern attempt may trigger a GC and - * claim any non-reachable strings, so every key must be reachable - * at all times. + * The keys, however, need to be interned, incref'd, and be + * reachable for GC. Any intern attempt may trigger a GC and + * claim any non-reachable strings, so every key must be reachable + * at all times. Refcounts must be correct to satisfy refcount + * assertions. * - * A longjmp must not occur here, as the new_p allocation would - * be freed without these keys being decref'd, hence the messy - * decref handling if intern fails. + * A longjmp must not occur here, as the new_p allocation would + * leak. Refcounts would come out correctly as the interned + * strings are valstack tracked. */ DUK_ASSERT(new_a_size == 0); @@ -50752,20 +52364,29 @@ * must be careful. */ - /* never shrinks; auto-adds DUK_VALSTACK_INTERNAL_EXTRA, which is generous */ +#if 0 /* XXX: inject test */ + if (1) { + goto abandon_error; + } +#endif + /* Never shrinks; auto-adds DUK_VALSTACK_INTERNAL_EXTRA, which + * is generous. + */ if (!duk_check_stack(ctx, 1)) { goto abandon_error; } DUK_ASSERT_VALSTACK_SPACE(thr, 1); - key = duk_heap_string_intern_u32(thr->heap, i); - if (!key) { + key = duk_heap_strtable_intern_u32(thr->heap, i); + if (key == NULL) { goto abandon_error; } duk_push_hstring(ctx, key); /* keep key reachable for GC etc; guaranteed not to fail */ - /* key is now reachable in the valstack */ + /* Key is now reachable in the valstack, don't INCREF + * the new allocation yet (we'll steal the refcounts + * from the value stack once all keys are done). + */ - DUK_HSTRING_INCREF(thr, key); /* second incref for the entry reference */ new_e_k[new_e_next] = key; tv2 = &new_e_pv[new_e_next].v; /* array entries are all plain values */ DUK_TVAL_SET_TVAL(tv2, tv1); @@ -50779,8 +52400,9 @@ */ } + /* Steal refcounts from value stack. */ DUK_DDD(DUK_DDDPRINT("abandon array: pop %ld key temps from valstack", (long) new_e_next)); - duk_pop_n(ctx, new_e_next); + duk_pop_n_nodecref_unsafe(ctx, new_e_next); } /* @@ -50793,7 +52415,7 @@ DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL); key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i); - if (!key) { + if (key == NULL) { continue; } @@ -50808,53 +52430,46 @@ /* the entries [new_e_next, new_e_size_adjusted[ are left uninitialized on purpose (ok, not gc reachable) */ /* - * Copy array elements to new array part. + * Copy array elements to new array part. If the new array part is + * larger, initialize the unused entries as UNUSED because they are + * GC reachable. */ - if (new_a_size > DUK_HOBJECT_GET_ASIZE(obj)) { - /* copy existing entries as is */ - DUK_ASSERT(new_p != NULL && new_a != NULL); - if (DUK_HOBJECT_GET_ASIZE(obj) > 0) { - /* Avoid zero copy with an invalid pointer. If obj->p is NULL, - * the 'new_a' pointer will be invalid which is not allowed even - * when copy size is zero. - */ - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL); - DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0); - DUK_MEMCPY((void *) new_a, (void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), sizeof(duk_tval) * DUK_HOBJECT_GET_ASIZE(obj)); - } - - /* fill new entries with -unused- (required, gc reachable) */ - for (i = DUK_HOBJECT_GET_ASIZE(obj); i < new_a_size; i++) { - duk_tval *tv = &new_a[i]; - DUK_TVAL_SET_UNUSED(tv); - } - } else { #if defined(DUK_USE_ASSERTIONS) - /* caller must have decref'd values above new_a_size (if that is necessary) */ - if (!abandon_array) { - for (i = new_a_size; i < DUK_HOBJECT_GET_ASIZE(obj); i++) { - duk_tval *tv; - tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i); - - /* current assertion is quite strong: decref's and set to unused */ - DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv)); - } + /* Caller must have decref'd values above new_a_size (if that is necessary). */ + if (!abandon_array) { + for (i = new_a_size; i < DUK_HOBJECT_GET_ASIZE(obj); i++) { + duk_tval *tv; + tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i); + DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv)); } + } #endif - if (new_a_size > 0) { - /* Avoid zero copy with an invalid pointer. If obj->p is NULL, - * the 'new_a' pointer will be invalid which is not allowed even - * when copy size is zero. - */ - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL); - DUK_ASSERT(new_a_size > 0); - DUK_MEMCPY((void *) new_a, (void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), sizeof(duk_tval) * new_a_size); - } + if (new_a_size > DUK_HOBJECT_GET_ASIZE(obj)) { + array_copy_size = sizeof(duk_tval) * DUK_HOBJECT_GET_ASIZE(obj); + } else { + array_copy_size = sizeof(duk_tval) * new_a_size; + } + if (array_copy_size > 0) { + /* Avoid zero copy with an invalid pointer. If obj->p is NULL, + * the 'new_a' pointer will be invalid which is not allowed even + * when copy size is zero. + */ + DUK_ASSERT(new_a != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0); + DUK_MEMCPY((void *) new_a, + (const void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), + array_copy_size); + } + for (i = DUK_HOBJECT_GET_ASIZE(obj); i < new_a_size; i++) { + duk_tval *tv = &new_a[i]; + DUK_TVAL_SET_UNUSED(tv); } /* - * Rebuild the hash part always from scratch (guaranteed to finish). + * Rebuild the hash part always from scratch (guaranteed to finish + * as long as caller gave consistent parameters). * * Any resize of hash part requires rehashing. In addition, by rehashing * get rid of any elements marked deleted (DUK__HASH_DELETED) which is critical @@ -50862,7 +52477,11 @@ */ #if defined(DUK_USE_HOBJECT_HASH_PART) - if (DUK_UNLIKELY(new_h_size > 0)) { + if (new_h_size == 0) { + DUK_DDD(DUK_DDDPRINT("no hash part, no rehash")); + } else { + duk_uint32_t mask; + DUK_ASSERT(new_h != NULL); /* fill new_h with u32 0xff = UNUSED */ @@ -50871,13 +52490,15 @@ DUK_MEMSET(new_h, 0xff, sizeof(duk_uint32_t) * new_h_size); DUK_ASSERT(new_e_next <= new_h_size); /* equality not actually possible */ + + mask = new_h_size - 1; for (i = 0; i < new_e_next; i++) { duk_hstring *key = new_e_k[i]; duk_uint32_t j, step; DUK_ASSERT(key != NULL); - j = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), new_h_size); - step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key)); + j = DUK_HSTRING_GET_HASH(key) & mask; + step = 1; /* Cache friendly but clustering prone. */ for (;;) { DUK_ASSERT(new_h[j] != DUK__HASH_DELETED); /* should never happen */ @@ -50887,14 +52508,11 @@ break; } DUK_DDD(DUK_DDDPRINT("rebuild miss %ld, step %ld", (long) j, (long) step)); - j = (j + step) % new_h_size; + j = (j + step) & mask; - /* guaranteed to finish */ - DUK_ASSERT(j != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), new_h_size)); + /* Guaranteed to finish (hash is larger than #props). */ } } - } else { - DUK_DDD(DUK_DDDPRINT("no hash part, no rehash")); } #endif /* DUK_USE_HOBJECT_HASH_PART */ @@ -50933,30 +52551,20 @@ DUK_HOBJECT_SET_ASIZE(obj, new_a_size); DUK_HOBJECT_SET_HSIZE(obj, new_h_size); - if (new_p) { - /* - * Detach actual buffer from dynamic buffer in valstack, and - * pop it from the stack. - * - * XXX: the buffer object is certainly not reachable at this point, - * so it would be nice to free it forcibly even with only - * mark-and-sweep enabled. Not a big issue though. - */ - (void) duk_steal_buffer(ctx, -1, NULL); - duk_pop(ctx); - } else { - DUK_ASSERT(new_alloc_size == 0); - /* no need to pop, nothing was pushed */ - } - - /* clear array part flag only after switching */ + /* Clear array part flag only after switching. */ if (abandon_array) { DUK_HOBJECT_CLEAR_ARRAY_PART(obj); } DUK_DDD(DUK_DDDPRINT("resize result: %!O", (duk_heaphdr *) obj)); - thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; + DUK_ASSERT(thr->heap->pf_prevent_count > 0); + thr->heap->pf_prevent_count--; + thr->heap->ms_base_flags = prev_ms_base_flags; +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(thr->heap->error_not_allowed == 1); + thr->heap->error_not_allowed = prev_error_not_allowed; +#endif /* * Post resize assertions. @@ -50968,21 +52576,25 @@ return; /* - * Abandon array failed, need to decref keys already inserted - * into the beginning of new_e_k before unwinding valstack. + * Abandon array failed. We don't need to DECREF anything + * because the references in the new allocation are not + * INCREF'd until abandon is complete. The string interned + * keys are on the value stack and are handled normally by + * unwind. */ abandon_error: - DUK_D(DUK_DPRINT("hobject resize failed during abandon array, decref keys")); - i = new_e_next; - while (i > 0) { - i--; - DUK_ASSERT(new_e_k != NULL); - DUK_ASSERT(new_e_k[i] != NULL); - DUK_HSTRING_DECREF(thr, new_e_k[i]); /* side effects */ - } + alloc_failed: + DUK_D(DUK_DPRINT("object property table resize failed")); - thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; + DUK_FREE(thr->heap, new_p); /* OK for NULL. */ + + thr->heap->pf_prevent_count--; + thr->heap->ms_base_flags = prev_ms_base_flags; +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(thr->heap->error_not_allowed == 1); + thr->heap->error_not_allowed = prev_error_not_allowed; +#endif DUK_ERROR_ALLOC_FAILED(thr); } @@ -51134,7 +52746,7 @@ } #if defined(DUK_USE_HOBJECT_HASH_PART) - if (e_size >= DUK_HOBJECT_E_USE_HASH_LIMIT) { + if (e_size >= DUK_USE_HOBJECT_HASH_PROP_LIMIT) { h_size = duk__get_default_h_size(e_size); } else { h_size = 0; @@ -51195,13 +52807,15 @@ duk_uint32_t n; duk_uint32_t i, step; duk_uint32_t *h_base; + duk_uint32_t mask; DUK_DDD(DUK_DDDPRINT("duk_hobject_find_existing_entry() using hash part for lookup")); h_base = DUK_HOBJECT_H_GET_BASE(heap, obj); n = DUK_HOBJECT_GET_HSIZE(obj); - i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n); - step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key)); + mask = n - 1; + i = DUK_HSTRING_GET_HASH(key) & mask; + step = 1; /* Cache friendly but clustering prone. */ for (;;) { duk_uint32_t t; @@ -51229,10 +52843,9 @@ DUK_DDD(DUK_DDDPRINT("lookup miss i=%ld, t=%ld", (long) i, (long) t)); } - i = (i + step) % n; + i = (i + step) & mask; - /* guaranteed to finish, as hash is never full */ - DUK_ASSERT(i != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n)); + /* Guaranteed to finish (hash is larger than #props). */ } } #endif /* DUK_USE_HOBJECT_HASH_PART */ @@ -51337,13 +52950,14 @@ #if defined(DUK_USE_HOBJECT_HASH_PART) if (DUK_UNLIKELY(DUK_HOBJECT_GET_HSIZE(obj) > 0)) { - duk_uint32_t n; + duk_uint32_t n, mask; duk_uint32_t i, step; duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(thr->heap, obj); n = DUK_HOBJECT_GET_HSIZE(obj); - i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n); - step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key)); + mask = n - 1; + i = DUK_HSTRING_GET_HASH(key) & mask; + step = 1; /* Cache friendly but clustering prone. */ for (;;) { duk_uint32_t t = h_base[i]; @@ -51358,10 +52972,9 @@ break; } DUK_DDD(DUK_DDDPRINT("duk__alloc_entry_checked() miss %ld", (long) i)); - i = (i + step) % n; + i = (i + step) & mask; - /* guaranteed to find an empty slot */ - DUK_ASSERT(i != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), DUK_HOBJECT_GET_HSIZE(obj))); + /* Guaranteed to finish (hash is larger than #props). */ } } #endif /* DUK_USE_HOBJECT_HASH_PART */ @@ -51761,6 +53374,8 @@ DUK_DDD(DUK_DDDPRINT("string object exotic property get for key: %!O, arr_idx: %ld", (duk_heaphdr *) key, (long) arr_idx)); + /* XXX: charlen; avoid multiple lookups? */ + if (arr_idx != DUK__NO_ARRAY_INDEX) { duk_hstring *h_val; @@ -52001,7 +53616,7 @@ } /* not found in 'curr', next in prototype chain; impose max depth */ - if (sanity-- == 0) { + if (DUK_UNLIKELY(sanity-- == 0)) { if (flags & DUK_GETDESC_FLAG_IGNORE_PROTOLOOP) { /* treat like property not found */ break; @@ -52010,7 +53625,7 @@ } } curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); - } while (curr); + } while (curr != NULL); /* out_desc is left untouched (possibly garbage), caller must use return * value to determine whether out_desc can be looked up @@ -52360,7 +53975,7 @@ duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj); duk_int_t pop_count; - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { /* Symbols (ES2015 or hidden) don't have virtual properties. */ DUK_DDD(DUK_DDDPRINT("base object is a symbol, start lookup from symbol prototype")); curr = thr->builtins[DUK_BIDX_SYMBOL_PROTOTYPE]; @@ -52701,11 +54316,11 @@ /* XXX: option to pretend property doesn't exist if sanity limit is * hit might be useful. */ - if (sanity-- == 0) { + if (DUK_UNLIKELY(sanity-- == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); } curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); - } while (curr); + } while (curr != NULL); /* * Not found @@ -53385,7 +55000,7 @@ arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key); DUK_ASSERT(key != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { /* Symbols (ES2015 or hidden) don't have virtual properties. */ curr = thr->builtins[DUK_BIDX_SYMBOL_PROTOTYPE]; goto lookup; @@ -53801,11 +55416,11 @@ /* XXX: option to pretend property doesn't exist if sanity limit is * hit might be useful. */ - if (sanity-- == 0) { + if (DUK_UNLIKELY(sanity-- == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); } curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); - } while (curr); + } while (curr != NULL); /* * Property not found in prototype chain. @@ -54432,10 +56047,10 @@ /* Note: proxy handling must happen before key is string coerced. */ if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_DELETE_PROPERTY, tv_key, &h_target)) { - /* -> [ ... trap handler ] */ + /* -> [ ... obj key trap handler ] */ DUK_DDD(DUK_DDDPRINT("-> proxy object 'deleteProperty' for key %!T", (duk_tval *) tv_key)); duk_push_hobject(ctx, h_target); /* target */ - duk_push_tval(ctx, tv_key); /* P */ + duk_dup_m4(ctx); /* P */ duk_call_method(ctx, 2 /*nargs*/); tmp_bool = duk_to_boolean(ctx, -1); duk_pop(ctx); @@ -54446,6 +56061,7 @@ /* Target object must be checked for a conflicting * non-configurable property. */ + tv_key = DUK_GET_TVAL_NEGIDX(ctx, -1); arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key); DUK_ASSERT(key != NULL); @@ -54794,6 +56410,41 @@ } /* + * Fast finalizer check for an object. Walks the prototype chain, checking + * for finalizer presence using DUK_HOBJECT_FLAG_HAVE_FINALIZER which is kept + * in sync with the actual property when setting/removing the finalizer. + */ + +#if defined(DUK_USE_HEAPPTR16) +DUK_INTERNAL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_heap *heap, duk_hobject *obj) { +#else +DUK_INTERNAL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_hobject *obj) { +#endif + duk_uint_t sanity; + + DUK_ASSERT(obj != NULL); + + sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; + do { + if (DUK_UNLIKELY(DUK_HOBJECT_HAS_HAVE_FINALIZER(obj))) { + return 1; + } + if (DUK_UNLIKELY(sanity-- == 0)) { + DUK_D(DUK_DPRINT("prototype loop when checking for finalizer existence; returning false")); + return 0; + } +#if defined(DUK_USE_HEAPPTR16) + DUK_ASSERT(heap != NULL); + obj = DUK_HOBJECT_GET_PROTOTYPE(heap, obj); +#else + obj = DUK_HOBJECT_GET_PROTOTYPE(NULL, obj); /* 'heap' arg ignored */ +#endif + } while (obj != NULL); + + return 0; +} + +/* * Object.getOwnPropertyDescriptor() (E5 Sections 15.2.3.3, 8.10.4) * * [ ... key ] -> [ ... desc/undefined ] @@ -56051,8 +57702,6 @@ /* automatic undefs */ #undef DUK__HASH_DELETED -#undef DUK__HASH_INITIAL -#undef DUK__HASH_PROBE_STEP #undef DUK__HASH_UNUSED #undef DUK__NO_ARRAY_INDEX #undef DUK__VALSTACK_PROXY_LOOKUP @@ -56063,6 +57712,10 @@ /* #include duk_internal.h -> already included */ +/* + * duk_hstring charCodeAt, with and without surrogate awareness + */ + DUK_INTERNAL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos, duk_bool_t surrogate_aware) { duk_uint32_t boff; const duk_uint8_t *p, *p_start, *p_end; @@ -56110,16 +57763,87 @@ return cp1; } -#if !defined(DUK_USE_HSTRING_CLEN) -DUK_INTERNAL duk_size_t duk_hstring_get_charlen(duk_hstring *h) { - if (DUK_HSTRING_HAS_ASCII(h)) { +/* + * duk_hstring charlen access + */ + +#if defined(DUK_USE_HSTRING_CLEN) +DUK_LOCAL DUK_COLD duk_size_t duk__hstring_get_charlen_slowpath(duk_hstring *h) { + duk_size_t res; + + DUK_ASSERT(h->clen == 0); /* Checked by caller. */ + +#if defined(DUK_USE_ROM_STRINGS) + /* ROM strings have precomputed clen, but if the computed clen is zero + * we can still come here and can't write anything. + */ + if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { + return 0; + } +#endif + + res = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); +#if defined(DUK_USE_STRLEN16) + DUK_ASSERT(res <= 0xffffUL); /* Bytelength checked during interning. */ + h->clen16 = (duk_uint16_t) res; +#else + h->clen = (duk_uint32_t) res; +#endif + if (DUK_LIKELY(res == DUK_HSTRING_GET_BYTELEN(h))) { + DUK_HSTRING_SET_ASCII(h); + } + return res; +} +#else /* DUK_USE_HSTRING_CLEN */ +DUK_LOCAL duk_size_t duk__hstring_get_charlen_slowpath(duk_hstring *h) { + if (DUK_LIKELY(DUK_HSTRING_HAS_ASCII(h))) { /* Most practical strings will go here. */ return DUK_HSTRING_GET_BYTELEN(h); } else { - return duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); + /* ASCII flag is lazy, so set it here. */ + duk_size_t res; + + /* XXX: here we could use the strcache to speed up the + * computation (matters for 'i < str.length' loops). + */ + + res = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); + +#if defined(DUK_USE_ROM_STRINGS) + if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { + /* For ROM strings, can't write anything; ASCII flag + * is preset so we don't need to update it. + */ + return res; + } +#endif + if (DUK_LIKELY(res == DUK_HSTRING_GET_BYTELEN(h))) { + DUK_HSTRING_SET_ASCII(h); + } + return res; + } +} +#endif /* DUK_USE_HSTRING_CLEN */ + +#if defined(DUK_USE_HSTRING_CLEN) +DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) { +#if defined(DUK_USE_STRLEN16) + if (DUK_LIKELY(h->clen16 != 0)) { + return h->clen16; + } +#else + if (DUK_LIKELY(h->clen != 0)) { + return h->clen; } +#endif + return duk__hstring_get_charlen_slowpath(h); +} +#else /* DUK_USE_HSTRING_CLEN */ +DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) { + /* Always use slow path. */ + return duk__hstring_get_charlen_slowpath(h); } -#endif /* !DUK_USE_HSTRING_CLEN */ +#endif /* DUK_USE_HSTRING_CLEN */ /* * duk_hthread allocation and freeing. */ @@ -56143,6 +57867,7 @@ DUK_ASSERT(thr->valstack_bottom == NULL); DUK_ASSERT(thr->valstack_top == NULL); DUK_ASSERT(thr->callstack == NULL); + DUK_ASSERT(thr->callstack_curr == NULL); DUK_ASSERT(thr->catchstack == NULL); /* valstack */ @@ -56172,6 +57897,7 @@ DUK_MEMZERO(thr->callstack, alloc_size); thr->callstack_size = DUK_CALLSTACK_INITIAL_SIZE; DUK_ASSERT(thr->callstack_top == 0); + DUK_ASSERT(thr->callstack_curr == NULL); /* catchstack */ alloc_size = sizeof(duk_catcher) * DUK_CATCHSTACK_INITIAL_SIZE; @@ -56252,12 +57978,13 @@ #if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT) DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) { duk_context *ctx; - duk_hobject *h1; + duk_hobject *h_global; #if defined(DUK_USE_ROM_GLOBAL_CLONE) - duk_hobject *h2; + duk_hobject *h_oldglobal; duk_uint8_t *props; duk_size_t alloc_size; #endif + duk_hobject *h_objenv; ctx = (duk_context *) thr; @@ -56265,83 +57992,84 @@ #if defined(DUK_USE_ROM_GLOBAL_INHERIT) /* Inherit from ROM-based global object: less RAM usage, less transparent. */ - h1 = duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL), - DUK_BIDX_GLOBAL); - DUK_ASSERT(h1 != NULL); + h_global = duk_push_object_helper(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL), + DUK_BIDX_GLOBAL); + DUK_ASSERT(h_global != NULL); #elif defined(DUK_USE_ROM_GLOBAL_CLONE) /* Clone the properties of the ROM-based global object to create a * fully RAM-based global object. Uses more memory than the inherit * model but more compliant. */ - h1 = duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL), - DUK_BIDX_OBJECT_PROTOTYPE); - DUK_ASSERT(h1 != NULL); - h2 = thr->builtins[DUK_BIDX_GLOBAL]; - DUK_ASSERT(h2 != NULL); + h_global = duk_push_object_helper(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL), + DUK_BIDX_OBJECT_PROTOTYPE); + DUK_ASSERT(h_global != NULL); + h_oldglobal = thr->builtins[DUK_BIDX_GLOBAL]; + DUK_ASSERT(h_oldglobal != NULL); /* Copy the property table verbatim; this handles attributes etc. * For ROM objects it's not necessary (or possible) to update * refcounts so leave them as is. */ - alloc_size = DUK_HOBJECT_P_ALLOC_SIZE(h2); + alloc_size = DUK_HOBJECT_P_ALLOC_SIZE(h_oldglobal); DUK_ASSERT(alloc_size > 0); - props = DUK_ALLOC(thr->heap, alloc_size); - if (!props) { - DUK_ERROR_ALLOC_FAILED(thr); - return; - } - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h2) != NULL); - DUK_MEMCPY((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h2), alloc_size); + props = DUK_ALLOC_CHECKED(thr, alloc_size); + DUK_ASSERT(props != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal) != NULL); + DUK_MEMCPY((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal), alloc_size); /* XXX: keep property attributes or tweak them here? * Properties will now be non-configurable even when they're * normally configurable for the global object. */ - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h1) == NULL); - DUK_HOBJECT_SET_PROPS(thr->heap, h1, props); - DUK_HOBJECT_SET_ESIZE(h1, DUK_HOBJECT_GET_ESIZE(h2)); - DUK_HOBJECT_SET_ENEXT(h1, DUK_HOBJECT_GET_ENEXT(h2)); - DUK_HOBJECT_SET_ASIZE(h1, DUK_HOBJECT_GET_ASIZE(h2)); - DUK_HOBJECT_SET_HSIZE(h1, DUK_HOBJECT_GET_HSIZE(h2)); + DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h_global) == NULL); + DUK_HOBJECT_SET_PROPS(thr->heap, h_global, props); + DUK_HOBJECT_SET_ESIZE(h_global, DUK_HOBJECT_GET_ESIZE(h_oldglobal)); + DUK_HOBJECT_SET_ENEXT(h_global, DUK_HOBJECT_GET_ENEXT(h_oldglobal)); + DUK_HOBJECT_SET_ASIZE(h_global, DUK_HOBJECT_GET_ASIZE(h_oldglobal)); + DUK_HOBJECT_SET_HSIZE(h_global, DUK_HOBJECT_GET_HSIZE(h_oldglobal)); #else -#error internal error in defines +#error internal error in config defines #endif - duk_hobject_compact_props(thr, h1); + duk_hobject_compact_props(thr, h_global); DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); - DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL])); /* no need to decref */ - thr->builtins[DUK_BIDX_GLOBAL] = h1; - DUK_HOBJECT_INCREF(thr, h1); - DUK_D(DUK_DPRINT("duplicated global object: %!O", h1)); - + DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL])); /* no need to decref: ROM object */ + thr->builtins[DUK_BIDX_GLOBAL] = h_global; + DUK_HOBJECT_INCREF(thr, h_global); + DUK_D(DUK_DPRINT("duplicated global object: %!O", h_global)); /* Create a fresh object environment for the global scope. This is * needed so that the global scope points to the newly created RAM-based * global object. */ - h1 = duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV), - -1); /* no prototype */ - DUK_ASSERT(h1 != NULL); - duk_dup_m2(ctx); - duk_dup_top(ctx); /* -> [ ... new_global new_globalenv new_global new_global ] */ - duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); /* always provideThis=true */ + h_objenv = (duk_hobject *) duk_hobjenv_alloc(thr, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV)); + DUK_ASSERT(h_objenv != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_objenv) == NULL); + duk_push_hobject(ctx, h_objenv); + + DUK_ASSERT(h_global != NULL); + ((duk_hobjenv *) h_objenv)->target = h_global; + DUK_HOBJECT_INCREF(thr, h_global); + DUK_ASSERT(((duk_hobjenv *) h_objenv)->has_this == 0); - duk_hobject_compact_props(thr, h1); DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL); - DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL_ENV])); /* no need to decref */ - thr->builtins[DUK_BIDX_GLOBAL_ENV] = h1; - DUK_HOBJECT_INCREF(thr, h1); - DUK_D(DUK_DPRINT("duplicated global env: %!O", h1)); + DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL_ENV])); /* no need to decref: ROM object */ + thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_objenv; + DUK_HOBJECT_INCREF(thr, h_objenv); + DUK_D(DUK_DPRINT("duplicated global env: %!O", h_objenv)); - duk_pop_2(ctx); + DUK_ASSERT_HOBJENV_VALID((duk_hobjenv *) h_objenv); + + duk_pop_2(ctx); /* Pop global object and global env. */ } #endif /* DUK_USE_ROM_GLOBAL_CLONE || DUK_USE_ROM_GLOBAL_INHERIT */ @@ -56447,11 +58175,11 @@ duk_small_int_t len = -1; /* must be signed */ class_num = (duk_small_uint_t) duk_bd_decode_varuint(bd); - len = (duk_small_int_t) duk_bd_decode_flagged(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/); + len = (duk_small_int_t) duk_bd_decode_flagged_signed(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/); if (class_num == DUK_HOBJECT_CLASS_FUNCTION) { duk_small_uint_t natidx; - duk_int_t c_nargs; /* must hold DUK_VARARGS */ + duk_small_int_t c_nargs; /* must hold DUK_VARARGS */ duk_c_function c_func; duk_int16_t magic; @@ -56463,7 +58191,7 @@ c_func = duk_bi_native_functions[natidx]; DUK_ASSERT(c_func != NULL); - c_nargs = (duk_small_uint_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, len /*def_value*/); + c_nargs = (duk_small_int_t) duk_bd_decode_flagged_signed(bd, DUK__NARGS_BITS, len /*def_value*/); if (c_nargs == DUK__NARGS_VARARGS_MARKER) { c_nargs = DUK_VARARGS; } @@ -56506,8 +58234,31 @@ ((duk_hnatfunc *) h)->magic = magic; } else if (class_num == DUK_HOBJECT_CLASS_ARRAY) { duk_push_array(ctx); + } else if (class_num == DUK_HOBJECT_CLASS_OBJENV) { + duk_hobjenv *env; + duk_hobject *global; + + DUK_ASSERT(i == DUK_BIDX_GLOBAL_ENV); + DUK_ASSERT(DUK_BIDX_GLOBAL_ENV > DUK_BIDX_GLOBAL); + + env = duk_hobjenv_alloc(thr, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV)); + DUK_ASSERT(env->target == NULL); + duk_push_hobject(ctx, (duk_hobject *) env); + + global = duk_known_hobject(ctx, DUK_BIDX_GLOBAL); + DUK_ASSERT(global != NULL); + env->target = global; + DUK_HOBJECT_INCREF(thr, global); + DUK_ASSERT(env->has_this == 0); + + DUK_ASSERT_HOBJENV_VALID(env); } else { + DUK_ASSERT(class_num != DUK_HOBJECT_CLASS_DECENV); + (void) duk_push_object_helper(ctx, + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_EXTENSIBLE, -1); /* no prototype or class yet */ @@ -56556,14 +58307,13 @@ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_COMPFUNC(h)); /* DUK_HOBJECT_FLAG_NATFUNC varies */ - DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(h)); + DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(h) || class_num == DUK_HOBJECT_CLASS_ARRAY); /* DUK_HOBJECT_FLAG_STRICT varies */ DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(h) || /* all native functions have NEWENV */ DUK_HOBJECT_HAS_NEWENV(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(h)); - DUK_ASSERT(!DUK_HOBJECT_HAS_ENVRECCLOSED(h)); /* DUK_HOBJECT_FLAG_EXOTIC_ARRAY varies */ /* DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ varies */ DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h)); @@ -56912,12 +58662,8 @@ #endif " " /* Low memory options */ -#if defined(DUK_USE_STRTAB_CHAIN) - "c" /* chain */ -#elif defined(DUK_USE_STRTAB_PROBE) - "p" /* probe */ -#else - "?" +#if defined(DUK_USE_STRTAB_PTRCOMP) + "s" #endif #if !defined(DUK_USE_HEAPPTR16) && !defined(DUK_DATAPTR16) && !defined(DUK_FUNCPTR16) "n" @@ -57051,7 +58797,6 @@ /* Order of unwinding is important */ duk_hthread_catchstack_unwind(thr, 0); - duk_hthread_callstack_unwind(thr, 0); /* side effects, possibly errors */ thr->valstack_bottom = thr->valstack; @@ -57074,16 +58819,6 @@ */ } -DUK_INTERNAL duk_activation *duk_hthread_get_current_activation(duk_hthread *thr) { - DUK_ASSERT(thr != NULL); - - if (thr->callstack_top > 0) { - return thr->callstack + thr->callstack_top - 1; - } else { - return NULL; - } -} - #if defined(DUK_USE_DEBUGGER_SUPPORT) DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act) { duk_instr_t *bcode; @@ -57129,7 +58864,9 @@ if (thr->ptr_curr_pc != NULL) { /* ptr_curr_pc != NULL only when bytecode executor is active. */ DUK_ASSERT(thr->callstack_top > 0); - act = thr->callstack + thr->callstack_top - 1; + DUK_ASSERT(thr->callstack_curr != NULL); + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); act->curr_pc = *thr->ptr_curr_pc; } } @@ -57142,7 +58879,9 @@ if (thr->ptr_curr_pc != NULL) { /* ptr_curr_pc != NULL only when bytecode executor is active. */ DUK_ASSERT(thr->callstack_top > 0); - act = thr->callstack + thr->callstack_top - 1; + DUK_ASSERT(thr->callstack_curr != NULL); + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); act->curr_pc = *thr->ptr_curr_pc; thr->ptr_curr_pc = NULL; } @@ -57171,8 +58910,7 @@ /* #include duk_internal.h -> already included */ -/* check that there is space for at least one new entry */ -DUK_INTERNAL void duk_hthread_callstack_grow(duk_hthread *thr) { +DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__hthread_do_callstack_grow(duk_hthread *thr) { duk_activation *new_ptr; duk_size_t old_size; duk_size_t new_size; @@ -57181,10 +58919,6 @@ DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */ DUK_ASSERT(thr->callstack_size >= thr->callstack_top); - if (thr->callstack_top < thr->callstack_size) { - return; - } - old_size = thr->callstack_size; new_size = old_size + DUK_CALLSTACK_GROW_STEP; @@ -57209,10 +58943,28 @@ thr->callstack = new_ptr; thr->callstack_size = new_size; + if (thr->callstack_top > 0) { + thr->callstack_curr = thr->callstack + thr->callstack_top - 1; + } else { + thr->callstack_curr = NULL; + } + /* note: any entries above the callstack top are garbage and not zeroed */ } -DUK_INTERNAL void duk_hthread_callstack_shrink_check(duk_hthread *thr) { +/* check that there is space for at least one new entry */ +DUK_INTERNAL void duk_hthread_callstack_grow(duk_hthread *thr) { + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */ + DUK_ASSERT(thr->callstack_size >= thr->callstack_top); + + if (DUK_LIKELY(thr->callstack_top < thr->callstack_size)) { + return; + } + duk__hthread_do_callstack_grow(thr); +} + +DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__hthread_do_callstack_shrink(duk_hthread *thr) { duk_size_t new_size; duk_activation *p; @@ -57220,10 +58972,6 @@ DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */ DUK_ASSERT(thr->callstack_size >= thr->callstack_top); - if (thr->callstack_size - thr->callstack_top < DUK_CALLSTACK_SHRINK_THRESHOLD) { - return; - } - new_size = thr->callstack_top + DUK_CALLSTACK_SHRINK_SPARE; DUK_ASSERT(new_size >= thr->callstack_top); @@ -57239,6 +58987,12 @@ if (p) { thr->callstack = p; thr->callstack_size = new_size; + + if (thr->callstack_top > 0) { + thr->callstack_curr = thr->callstack + thr->callstack_top - 1; + } else { + thr->callstack_curr = NULL; + } } else { /* Because new_size != 0, if condition doesn't need to be * (p != NULL || new_size == 0). @@ -57250,7 +59004,19 @@ /* note: any entries above the callstack top are garbage and not zeroed */ } -DUK_INTERNAL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top) { +DUK_INTERNAL void duk_hthread_callstack_shrink_check(duk_hthread *thr) { + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */ + DUK_ASSERT(thr->callstack_size >= thr->callstack_top); + + if (DUK_LIKELY(thr->callstack_size - thr->callstack_top < DUK_CALLSTACK_SHRINK_THRESHOLD)) { + return; + } + + duk__hthread_do_callstack_shrink(thr); +} + +DUK_INTERNAL void duk_hthread_callstack_unwind_norz(duk_hthread *thr, duk_size_t new_top) { duk_size_t idx; DUK_DDD(DUK_DDDPRINT("unwind callstack top of thread %p from %ld to %ld", @@ -57279,9 +59045,7 @@ while (idx > new_top) { duk_activation *act; duk_hobject *func; -#if defined(DUK_USE_REFERENCE_COUNTING) duk_hobject *tmp; -#endif #if defined(DUK_USE_DEBUGGER_SUPPORT) duk_heap *heap; #endif @@ -57323,12 +59087,12 @@ DUK_TVAL_SET_NULL(tv_caller); /* no incref needed */ DUK_ASSERT(act->prev_caller == NULL); } - DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */ + DUK_TVAL_DECREF_NORZ(thr, &tv_tmp); } else { h_tmp = act->prev_caller; if (h_tmp) { act->prev_caller = NULL; - DUK_HOBJECT_DECREF(thr, h_tmp); /* side effects */ + DUK_HOBJECT_DECREF_NORZ(thr, h_tmp); } } act = thr->callstack + idx; /* avoid side effects */ @@ -57348,8 +59112,12 @@ /* Pause for all step types: step into, step over, step out. * This is the only place explicitly handling a step out. */ - DUK_HEAP_SET_PAUSED(heap); - DUK_ASSERT(heap->dbg_step_thread == NULL); + if (duk_debug_is_paused(heap)) { + DUK_D(DUK_DPRINT("step pause trigger but already paused, ignoring")); + } else { + duk_debug_set_paused(heap); + DUK_ASSERT(heap->dbg_step_thread == NULL); + } } #endif @@ -57370,42 +59138,19 @@ } /* func is NULL for lightfunc */ + /* Catch sites are required to clean up their environments + * in FINALLY part before propagating, so this should + * always hold here. + */ DUK_ASSERT(act->lex_env == act->var_env); + if (act->var_env != NULL) { DUK_DDD(DUK_DDDPRINT("closing var_env record %p -> %!O", (void *) act->var_env, (duk_heaphdr *) act->var_env)); - duk_js_close_environment_record(thr, act->var_env, func, act->idx_bottom); + duk_js_close_environment_record(thr, act->var_env); act = thr->callstack + idx; /* avoid side effect issues */ } -#if 0 - if (act->lex_env != NULL) { - if (act->lex_env == act->var_env) { - /* common case, already closed, so skip */ - DUK_DD(DUK_DDPRINT("lex_env and var_env are the same and lex_env " - "already closed -> skip closing lex_env")); - ; - } else { - DUK_DD(DUK_DDPRINT("closing lex_env record %p -> %!O", - (void *) act->lex_env, (duk_heaphdr *) act->lex_env)); - duk_js_close_environment_record(thr, act->lex_env, DUK_ACT_GET_FUNC(act), act->idx_bottom); - act = thr->callstack + idx; /* avoid side effect issues */ - } - } -#endif - - DUK_ASSERT((act->lex_env == NULL) || - ((duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_VARMAP(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL))); - - DUK_ASSERT((act->var_env == NULL) || - ((duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_VARMAP(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL))); - skip_env_close: /* @@ -57418,55 +59163,38 @@ } /* - * Reference count updates - * - * Note: careful manipulation of refcounts. The top is - * not updated yet, so all the activations are reachable - * for mark-and-sweep (which may be triggered by decref). - * However, the pointers are NULL so this is not an issue. + * Reference count updates, using NORZ macros so we don't + * need to handle side effects. */ -#if defined(DUK_USE_REFERENCE_COUNTING) - tmp = act->var_env; -#endif + DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, act->var_env); act->var_env = NULL; -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); - act = thr->callstack + idx; /* avoid side effect issues */ -#endif - -#if defined(DUK_USE_REFERENCE_COUNTING) - tmp = act->lex_env; -#endif + DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, act->lex_env); act->lex_env = NULL; -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); - act = thr->callstack + idx; /* avoid side effect issues */ -#endif /* Note: this may cause a corner case situation where a finalizer * may see a currently reachable activation whose 'func' is NULL. */ -#if defined(DUK_USE_REFERENCE_COUNTING) tmp = DUK_ACT_GET_FUNC(act); -#endif + DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp); + DUK_UNREF(tmp); act->func = NULL; -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); - act = thr->callstack + idx; /* avoid side effect issues */ - DUK_UNREF(act); -#endif } thr->callstack_top = new_top; + if (new_top > 0) { + thr->callstack_curr = thr->callstack + new_top - 1; + } else { + thr->callstack_curr = NULL; + } /* * We could clear the book-keeping variables for the topmost activation, * but don't do so now. */ #if 0 - if (thr->callstack_top > 0) { - duk_activation *act = thr->callstack + thr->callstack_top - 1; + if (thr->callstack_curr != NULL) { + duk_activation *act = thr->callstack_curr; act->idx_retval = 0; } #endif @@ -57477,7 +59205,12 @@ */ } -DUK_INTERNAL void duk_hthread_catchstack_grow(duk_hthread *thr) { +DUK_INTERNAL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top) { + duk_hthread_callstack_unwind_norz(thr, new_top); + DUK_REFZERO_CHECK_FAST(thr); +} + +DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__hthread_do_catchstack_grow(duk_hthread *thr) { duk_catcher *new_ptr; duk_size_t old_size; duk_size_t new_size; @@ -57486,10 +59219,6 @@ DUK_ASSERT_DISABLE(thr->catchstack_top); /* avoid warning (unsigned) */ DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top); - if (thr->catchstack_top < thr->catchstack_size) { - return; - } - old_size = thr->catchstack_size; new_size = old_size + DUK_CATCHSTACK_GROW_STEP; @@ -57517,7 +59246,19 @@ /* note: any entries above the catchstack top are garbage and not zeroed */ } -DUK_INTERNAL void duk_hthread_catchstack_shrink_check(duk_hthread *thr) { +DUK_INTERNAL void duk_hthread_catchstack_grow(duk_hthread *thr) { + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->catchstack_top); /* avoid warning (unsigned) */ + DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top); + + if (DUK_LIKELY(thr->catchstack_top < thr->catchstack_size)) { + return; + } + + duk__hthread_do_catchstack_grow(thr); +} + +DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__hthread_do_catchstack_shrink(duk_hthread *thr) { duk_size_t new_size; duk_catcher *p; @@ -57525,10 +59266,6 @@ DUK_ASSERT_DISABLE(thr->catchstack_top >= 0); /* avoid warning (unsigned) */ DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top); - if (thr->catchstack_size - thr->catchstack_top < DUK_CATCHSTACK_SHRINK_THRESHOLD) { - return; - } - new_size = thr->catchstack_top + DUK_CATCHSTACK_SHRINK_SPARE; DUK_ASSERT(new_size >= thr->catchstack_top); @@ -57555,7 +59292,19 @@ /* note: any entries above the catchstack top are garbage and not zeroed */ } -DUK_INTERNAL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top) { +DUK_INTERNAL void duk_hthread_catchstack_shrink_check(duk_hthread *thr) { + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->catchstack_top >= 0); /* avoid warning (unsigned) */ + DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top); + + if (DUK_LIKELY(thr->catchstack_size - thr->catchstack_top < DUK_CATCHSTACK_SHRINK_THRESHOLD)) { + return; + } + + duk__hthread_do_catchstack_shrink(thr); +} + +DUK_INTERNAL void duk_hthread_catchstack_unwind_norz(duk_hthread *thr, duk_size_t new_top) { duk_size_t idx; DUK_DDD(DUK_DDDPRINT("unwind catchstack top of thread %p from %ld to %ld", @@ -57611,7 +59360,8 @@ env = act->lex_env; /* current lex_env of the activation (created for catcher) */ DUK_ASSERT(env != NULL); /* must be, since env was created when catcher was created */ act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env); /* prototype is lex_env before catcher created */ - DUK_HOBJECT_DECREF(thr, env); + DUK_HOBJECT_INCREF(thr, act->lex_env); + DUK_HOBJECT_DECREF_NORZ(thr, env); /* There is no need to decref anything else than 'env': if 'env' * becomes unreachable, refzero will handle decref'ing its prototype. @@ -57623,6 +59373,100 @@ /* note: any entries above the catchstack top are garbage and not zeroed */ } + +DUK_INTERNAL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top) { + duk_hthread_catchstack_unwind_norz(thr, new_top); + DUK_REFZERO_CHECK_FAST(thr); +} + +#if defined(DUK_USE_FINALIZER_TORTURE) +DUK_INTERNAL void duk_hthread_valstack_torture_realloc(duk_hthread *thr) { + duk_size_t alloc_size; + duk_tval *new_ptr; + duk_ptrdiff_t end_off; + duk_ptrdiff_t bottom_off; + duk_ptrdiff_t top_off; + + if (thr->valstack == NULL) { + return; + } + + end_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack); + bottom_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack); + top_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack); + alloc_size = (duk_size_t) end_off; + if (alloc_size == 0) { + return; + } + + new_ptr = (duk_tval *) DUK_ALLOC(thr->heap, alloc_size); + if (new_ptr != NULL) { + DUK_MEMCPY((void *) new_ptr, (const void *) thr->valstack, alloc_size); + DUK_MEMSET((void *) thr->valstack, 0x55, alloc_size); + DUK_FREE(thr->heap, (void *) thr->valstack); + thr->valstack = new_ptr; + thr->valstack_end = (duk_tval *) ((duk_uint8_t *) new_ptr + end_off); + thr->valstack_bottom = (duk_tval *) ((duk_uint8_t *) new_ptr + bottom_off); + thr->valstack_top = (duk_tval *) ((duk_uint8_t *) new_ptr + top_off); + /* No change in size. */ + } else { + DUK_D(DUK_DPRINT("failed to realloc valstack for torture, ignore")); + } +} + +DUK_INTERNAL void duk_hthread_callstack_torture_realloc(duk_hthread *thr) { + duk_size_t alloc_size; + duk_activation *new_ptr; + duk_ptrdiff_t curr_off; + + if (thr->callstack == NULL) { + return; + } + + curr_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->callstack_curr - (duk_uint8_t *) thr->callstack); + alloc_size = sizeof(duk_activation) * thr->callstack_size; + if (alloc_size == 0) { + return; + } + + new_ptr = (duk_activation *) DUK_ALLOC(thr->heap, alloc_size); + if (new_ptr != NULL) { + DUK_MEMCPY((void *) new_ptr, (const void *) thr->callstack, alloc_size); + DUK_MEMSET((void *) thr->callstack, 0x55, alloc_size); + DUK_FREE(thr->heap, (void *) thr->callstack); + thr->callstack = new_ptr; + thr->callstack_curr = (duk_activation *) ((duk_uint8_t *) new_ptr + curr_off); + /* No change in size. */ + } else { + DUK_D(DUK_DPRINT("failed to realloc callstack for torture, ignore")); + } +} + +DUK_INTERNAL void duk_hthread_catchstack_torture_realloc(duk_hthread *thr) { + duk_size_t alloc_size; + duk_catcher *new_ptr; + + if (thr->catchstack == NULL) { + return; + } + + alloc_size = sizeof(duk_catcher) * thr->catchstack_size; + if (alloc_size == 0) { + return; + } + + new_ptr = (duk_catcher *) DUK_ALLOC(thr->heap, alloc_size); + if (new_ptr != NULL) { + DUK_MEMCPY((void *) new_ptr, (const void *) thr->catchstack, alloc_size); + DUK_MEMSET((void *) thr->catchstack, 0x55, alloc_size); + DUK_FREE(thr->heap, (void *) thr->catchstack); + thr->catchstack = new_ptr; + /* No change in size. */ + } else { + DUK_D(DUK_DPRINT("failed to realloc catchstack for torture, ignore")); + } +} +#endif /* DUK_USE_FINALIZER_TORTURE */ /* * Shared helpers for arithmetic operations */ @@ -57783,6 +59627,8 @@ /* #include duk_internal.h -> already included */ +/* XXX: heap->error_not_allowed for success path too? */ + /* * Forward declarations. */ @@ -57938,16 +59784,19 @@ arg = duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_ARRAY_PART | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARGUMENTS), DUK_BIDX_OBJECT_PROTOTYPE); DUK_ASSERT(arg != NULL); (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), -1); /* no prototype */ (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), -1); /* no prototype */ i_arg = duk_get_top(ctx) - 3; @@ -58235,6 +60084,8 @@ duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_LENGTH); /* -> [ ... func this arg1 ... argN _Args length ] */ len = (duk_idx_t) duk_require_int(ctx, -1); duk_pop(ctx); + + duk_require_stack(ctx, len); for (i = 0; i < len; i++) { /* XXX: very slow - better to bulk allocate a gap, and copy * from args_array directly (we know it has a compact array @@ -58257,7 +60108,7 @@ (long) num_stack_args, (long) idx_func, duk_get_tval(ctx, idx_func))); } while (--sanity > 0); - if (sanity == 0) { + if (DUK_UNLIKELY(sanity == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_BOUND_CHAIN_LIMIT); } @@ -58331,7 +60182,9 @@ return; } - act_callee = thr->callstack + thr->callstack_top - 1; + DUK_ASSERT(thr->callstack_top > 0); + act_callee = thr->callstack_curr; + DUK_ASSERT(act_callee != NULL); act_caller = (thr->callstack_top >= 2 ? act_callee - 1 : NULL); /* XXX: check .caller writability? */ @@ -58812,16 +60665,6 @@ */ duk__handle_call_inner(thr, num_stack_args, call_flags, idx_func); - /* Success path handles */ - DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth); - DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc); - - /* Longjmp state is kept clean in success path */ - DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN); - DUK_ASSERT(thr->heap->lj.iserror == 0); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1)); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); - thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr; return DUK_EXEC_SUCCESS; @@ -58848,11 +60691,6 @@ idx_func, old_jmpbuf_ptr); - /* Longjmp state is cleaned up by error handling */ - DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN); - DUK_ASSERT(thr->heap->lj.iserror == 0); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1)); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); return DUK_EXEC_ERROR; } #if defined(DUK_USE_CPP_EXCEPTIONS) @@ -58878,6 +60716,7 @@ entry_ptr_curr_pc, idx_func, old_jmpbuf_ptr); + return DUK_EXEC_ERROR; } } catch (...) { @@ -58898,6 +60737,7 @@ entry_ptr_curr_pc, idx_func, old_jmpbuf_ptr); + return DUK_EXEC_ERROR; } } @@ -59088,7 +60928,8 @@ duk_hthread_callstack_grow(thr); - if (thr->callstack_top > 0) { + act = thr->callstack_curr; + if (act != NULL) { /* * Update idx_retval of current activation. * @@ -59099,12 +60940,13 @@ * the Ecmascript call's idx_retval must be set for things to work. */ - (thr->callstack + thr->callstack_top - 1)->idx_retval = entry_valstack_bottom_index + idx_func; + act->idx_retval = entry_valstack_bottom_index + idx_func; } DUK_ASSERT(thr->callstack_top < thr->callstack_size); act = thr->callstack + thr->callstack_top; thr->callstack_top++; + thr->callstack_curr = act; DUK_ASSERT(thr->callstack_top <= thr->callstack_size); DUK_ASSERT(thr->valstack_top > thr->valstack_bottom); /* at least effective 'this' */ DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func)); @@ -59195,8 +61037,8 @@ #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) if (func) { duk__update_func_caller_prop(thr, func); + act = thr->callstack_curr; } - act = thr->callstack + thr->callstack_top - 1; #endif /* [ ... func this arg1 ... argN ] */ @@ -59241,7 +61083,7 @@ /* [ ... func this arg1 ... argN envobj ] */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; act->lex_env = env; act->var_env = env; DUK_HOBJECT_INCREF(thr, env); @@ -59256,6 +61098,7 @@ DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func)); duk__handle_oldenv_for_call(thr, func, act); + /* No need to re-lookup 'act' at present: no side effects. */ DUK_ASSERT(act->lex_env != NULL); DUK_ASSERT(act->var_env != NULL); @@ -59292,6 +61135,7 @@ * new value stack bottom, and call the target. */ + act = thr->callstack_curr; if (func != NULL && DUK_HOBJECT_IS_COMPFUNC(func)) { /* * Ecmascript call @@ -59334,10 +61178,9 @@ DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); /* may need unwind */ DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1); - DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1); - duk_hthread_catchstack_unwind(thr, entry_catchstack_top); + duk_hthread_catchstack_unwind_norz(thr, entry_catchstack_top); duk_hthread_catchstack_shrink_check(thr); - duk_hthread_callstack_unwind(thr, entry_callstack_top); + duk_hthread_callstack_unwind_norz(thr, entry_callstack_top); /* XXX: may now fail */ duk_hthread_callstack_shrink_check(thr); thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index; @@ -59399,7 +61242,7 @@ DUK_ASSERT(thr->catchstack_top == entry_catchstack_top); /* no need to unwind */ DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1); - duk_hthread_callstack_unwind(thr, entry_callstack_top); + duk_hthread_callstack_unwind_norz(thr, entry_callstack_top); duk_hthread_callstack_shrink_check(thr); thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index; @@ -59454,9 +61297,12 @@ DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */ thr->state = (duk_uint8_t) entry_thread_state; + /* Disabled assert: triggered with some torture tests. */ +#if 0 DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */ (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */ (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */ +#endif thr->heap->call_recursion_depth = entry_call_recursion_depth; @@ -59469,7 +61315,7 @@ * on every return should have no ill effect. */ #if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + if (duk_debug_is_attached(thr->heap)) { DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt")); DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init); thr->interrupt_init -= thr->interrupt_counter; @@ -59482,6 +61328,14 @@ duk__interrupt_fixup(thr, entry_curr_thread); #endif + /* Restored by success path. */ + DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth); + DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc); + + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + + DUK_REFZERO_CHECK_FAST(thr); + return; thread_state_error: @@ -59513,6 +61367,7 @@ * the error here. */ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW); + DUK_ASSERT_LJSTATE_SET(thr->heap); DUK_ASSERT(thr->callstack_top >= entry_callstack_top); DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); @@ -59534,9 +61389,9 @@ * scopes; this is a sandboxing issue, described in: * https://github.com/svaarala/duktape/issues/476 */ - duk_hthread_catchstack_unwind(thr, entry_catchstack_top); + duk_hthread_catchstack_unwind_norz(thr, entry_catchstack_top); duk_hthread_catchstack_shrink_check(thr); - duk_hthread_callstack_unwind(thr, entry_callstack_top); + duk_hthread_callstack_unwind_norz(thr, entry_callstack_top); duk_hthread_callstack_shrink_check(thr); thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index; @@ -59587,9 +61442,12 @@ DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */ thr->state = (duk_uint8_t) entry_thread_state; + /* Disabled assert: triggered with some torture tests. */ +#if 0 DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */ (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */ (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */ +#endif thr->heap->call_recursion_depth = entry_call_recursion_depth; @@ -59602,7 +61460,7 @@ * on every return should have no ill effect. */ #if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + if (duk_debug_is_attached(thr->heap)) { DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt")); DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init); thr->interrupt_init -= thr->interrupt_counter; @@ -59614,6 +61472,21 @@ #if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG) duk__interrupt_fixup(thr, entry_curr_thread); #endif + + /* Error handling complete, remove side effect protections and + * process pending finalizers. + */ +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(thr->heap->error_not_allowed == 1); + thr->heap->error_not_allowed = 0; +#endif + DUK_ASSERT(thr->heap->pf_prevent_count > 0); + thr->heap->pf_prevent_count--; + DUK_DD(DUK_DDPRINT("call error handled, pf_prevent_count updated to %ld", (long) thr->heap->pf_prevent_count)); + + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + + DUK_REFZERO_CHECK_SLOW(thr); } /* @@ -59711,12 +61584,6 @@ entry_callstack_top, entry_catchstack_top); - /* Longjmp state is kept clean in success path */ - DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN); - DUK_ASSERT(thr->heap->lj.iserror == 0); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1)); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); - /* Note: either pointer may be NULL (at entry), so don't assert */ thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr; @@ -59736,12 +61603,6 @@ entry_catchstack_top, old_jmpbuf_ptr); - /* Longjmp state is cleaned up by error handling */ - DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN); - DUK_ASSERT(thr->heap->lj.iserror == 0); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1)); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); - retval = DUK_EXEC_ERROR; } #if defined(DUK_USE_CPP_EXCEPTIONS) @@ -59786,6 +61647,8 @@ DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == old_jmpbuf_ptr); /* success/error path both do this */ + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + duk__handle_safe_call_shared(thr, idx_retbase, num_stack_rets, @@ -59900,6 +61763,10 @@ DUK_ASSERT(thr->callstack_top == entry_callstack_top); duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, rc); + + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + + DUK_REFZERO_CHECK_FAST(thr); return; thread_state_error: @@ -59934,6 +61801,7 @@ * the error here. */ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW); + DUK_ASSERT_LJSTATE_SET(thr->heap); DUK_ASSERT(thr->callstack_top >= entry_callstack_top); DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); @@ -59942,9 +61810,9 @@ DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); DUK_ASSERT(thr->callstack_top >= entry_callstack_top); - duk_hthread_catchstack_unwind(thr, entry_catchstack_top); + duk_hthread_catchstack_unwind_norz(thr, entry_catchstack_top); duk_hthread_catchstack_shrink_check(thr); - duk_hthread_callstack_unwind(thr, entry_callstack_top); + duk_hthread_callstack_unwind_norz(thr, entry_callstack_top); duk_hthread_callstack_shrink_check(thr); thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index; @@ -59976,6 +61844,21 @@ thr->heap->lj.iserror = 0; DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */ + + /* Error handling complete, remove side effect protections and + * process pending finalizers. + */ +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(thr->heap->error_not_allowed == 1); + thr->heap->error_not_allowed = 0; +#endif + DUK_ASSERT(thr->heap->pf_prevent_count > 0); + thr->heap->pf_prevent_count--; + DUK_DD(DUK_DDPRINT("safe call error handled, pf_prevent_count updated to %ld", (long) thr->heap->pf_prevent_count)); + + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + + DUK_REFZERO_CHECK_SLOW(thr); } DUK_LOCAL void duk__handle_safe_call_shared(duk_hthread *thr, @@ -60022,6 +61905,8 @@ #if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG) duk__interrupt_fixup(thr, entry_curr_thread); #endif + + DUK_ASSERT_LJSTATE_UNSET(thr->heap); } /* @@ -60209,7 +62094,8 @@ DUK_ASSERT(thr->callstack_top >= 1); DUK_ASSERT((call_flags & DUK_CALL_FLAG_IS_RESUME) == 0); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) { /* See: test-bug-tailcall-preventyield-assert.c. */ DUK_DDD(DUK_DDDPRINT("tail call prevented by current activation having DUK_ACT_FLAG_PREVENTYIELD")); @@ -60256,16 +62142,17 @@ break; } } - duk_hthread_catchstack_unwind(thr, i_stk + 1); + duk_hthread_catchstack_unwind_norz(thr, i_stk + 1); /* Unwind the topmost callstack entry before reusing it */ DUK_ASSERT(thr->callstack_top > 0); - duk_hthread_callstack_unwind(thr, thr->callstack_top - 1); + duk_hthread_callstack_unwind_norz(thr, thr->callstack_top - 1); /* Then reuse the unwound activation; callstack was not shrunk so there is always space */ + DUK_ASSERT(thr->callstack_top < thr->callstack_size); + act = thr->callstack + thr->callstack_top; thr->callstack_top++; - DUK_ASSERT(thr->callstack_top <= thr->callstack_size); - act = thr->callstack + thr->callstack_top - 1; + thr->callstack_curr = act; /* Start filling in the activation */ act->func = func; /* don't want an intermediate exposed state with func == NULL */ @@ -60282,7 +62169,7 @@ DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */ #if defined(DUK_USE_REFERENCE_COUNTING) DUK_HOBJECT_INCREF(thr, func); - act = thr->callstack + thr->callstack_top - 1; /* side effects (currently none though) */ + act = thr->callstack_curr; /* side effects (currently none though) */ #endif #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) @@ -60294,7 +62181,7 @@ * is in use. */ duk__update_func_caller_prop(thr, func); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; #endif act->flags = (DUK_HOBJECT_HAS_STRICT(func) ? @@ -60351,7 +62238,7 @@ DUK_DDD(DUK_DDDPRINT("update to current activation idx_retval")); DUK_ASSERT(thr->callstack_top < thr->callstack_size); DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL); DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act))); act->idx_retval = entry_valstack_bottom_index + idx_func; @@ -60360,6 +62247,7 @@ DUK_ASSERT(thr->callstack_top < thr->callstack_size); act = thr->callstack + thr->callstack_top; thr->callstack_top++; + thr->callstack_curr = act; DUK_ASSERT(thr->callstack_top <= thr->callstack_size); DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); @@ -60392,7 +62280,7 @@ #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) duk__update_func_caller_prop(thr, func); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; #endif } @@ -60421,6 +62309,7 @@ */ duk__handle_oldenv_for_call(thr, func, act); + /* No need to re-lookup 'act' at present: no side effects. */ DUK_ASSERT(act->lex_env != NULL); DUK_ASSERT(act->var_env != NULL); @@ -60450,7 +62339,7 @@ /* [ ... arg1 ... argN envobj ] */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; act->lex_env = env; act->var_env = env; DUK_HOBJECT_INCREF(thr, act->lex_env); @@ -60486,6 +62375,7 @@ * the topmost activation. */ + DUK_REFZERO_CHECK_FAST(thr); return 1; } /* @@ -62488,6 +64378,8 @@ duk_pop(ctx); return ret; #else + DUK_UNREF(comp_ctx); + DUK_UNREF(rc); DUK_ASSERT((rc & DUK__CONST_MARKER) == 0); /* caller removes const marker */ return 0; #endif @@ -62739,15 +64631,31 @@ DUK_DDD(DUK_DDDPRINT("arith inline check: d1=%lf, d2=%lf, op=%ld", (double) d1, (double) d2, (long) x->op)); switch (x->op) { - case DUK_OP_ADD: d3 = d1 + d2; break; - case DUK_OP_SUB: d3 = d1 - d2; break; - case DUK_OP_MUL: d3 = d1 * d2; break; - case DUK_OP_DIV: d3 = d1 / d2; break; + case DUK_OP_ADD: { + d3 = d1 + d2; + break; + } + case DUK_OP_SUB: { + d3 = d1 - d2; + break; + } + case DUK_OP_MUL: { + d3 = d1 * d2; + break; + } + case DUK_OP_DIV: { + d3 = d1 / d2; + break; + } case DUK_OP_EXP: { d3 = (duk_double_t) duk_js_arith_pow((double) d1, (double) d2); break; } - default: accept_fold = 0; break; + default: { + d3 = 0.0; /* Won't be used, but silence MSVC /W4 warning. */ + accept_fold = 0; + break; + } } if (accept_fold) { @@ -66661,6 +68569,7 @@ duk_small_uint_t stmt_flags = 0; duk_int_t label_id = -1; duk_small_uint_t tok; + duk_bool_t test_func_decl; DUK__RECURSION_INCREASE(comp_ctx, thr); @@ -66726,17 +68635,15 @@ * for function statements are modelled after V8, see * test-dev-func-decl-outside-top.js. */ - + test_func_decl = allow_source_elem; #if defined(DUK_USE_NONSTD_FUNC_STMT) /* Lenient: allow function declarations outside top level in * non-strict mode but reject them in strict mode. */ - if (allow_source_elem || !comp_ctx->curr_func.is_strict) -#else /* DUK_USE_NONSTD_FUNC_STMT */ - /* Strict: never allow function declarations outside top level. */ - if (allow_source_elem) + test_func_decl = test_func_decl || !comp_ctx->curr_func.is_strict; #endif /* DUK_USE_NONSTD_FUNC_STMT */ - { + /* Strict: never allow function declarations outside top level. */ + if (test_func_decl) { /* FunctionDeclaration: not strictly a statement but handled as such. * * O(depth^2) parse count for inner functions is handled by recording a @@ -67448,6 +69355,9 @@ (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1))); +#if defined(DUK_USE_FASTINT) + DUK_ASSERT(DUK_TVAL_IS_NULL(duk_get_tval(ctx, -1)) || DUK_TVAL_IS_FASTINT(duk_get_tval(ctx, -1))); +#endif duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */ } @@ -67513,8 +69423,7 @@ duk_push_null(ctx); declvar_flags = DUK_PROPDESC_FLAG_WRITABLE | - DUK_PROPDESC_FLAG_ENUMERABLE | - DUK_BC_DECLVAR_FLAG_UNDEF_VALUE; + DUK_PROPDESC_FLAG_ENUMERABLE; if (configurable_bindings) { declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE; } @@ -68191,9 +70100,9 @@ DUK_ASSERT(lex_pt != NULL); flags = comp_stk->flags; - is_eval = (flags & DUK_JS_COMPILE_FLAG_EVAL ? 1 : 0); - is_strict = (flags & DUK_JS_COMPILE_FLAG_STRICT ? 1 : 0); - is_funcexpr = (flags & DUK_JS_COMPILE_FLAG_FUNCEXPR ? 1 : 0); + is_eval = (flags & DUK_COMPILE_EVAL ? 1 : 0); + is_strict = (flags & DUK_COMPILE_STRICT ? 1 : 0); + is_funcexpr = (flags & DUK_COMPILE_FUNCEXPR ? 1 : 0); h_filename = duk_get_hstring(ctx, -1); /* may be undefined */ @@ -68269,7 +70178,7 @@ */ DUK_ASSERT(func->is_setget == 0); - func->is_strict = is_strict; + func->is_strict = (duk_uint8_t) is_strict; DUK_ASSERT(func->is_notail == 0); if (is_funcexpr) { @@ -68284,8 +70193,9 @@ (void) duk__parse_func_like_raw(comp_ctx, 0 /*flags*/); } else { DUK_ASSERT(func->is_function == 0); - func->is_eval = is_eval; - func->is_global = !is_eval; + DUK_ASSERT(is_eval == 0 || is_eval == 1); + func->is_eval = (duk_uint8_t) is_eval; + func->is_global = (duk_uint8_t) !is_eval; DUK_ASSERT(func->is_namebinding == 0); DUK_ASSERT(func->is_constructable == 0); @@ -68325,6 +70235,7 @@ DUK_LEXER_INITCTX(&comp_stk.comp_ctx_alloc.lex); comp_stk.comp_ctx_alloc.lex.input = src_buffer; comp_stk.comp_ctx_alloc.lex.input_length = src_length; + comp_stk.comp_ctx_alloc.lex.flags = flags; /* Forward flags directly for now. */ /* [ ... filename ] */ @@ -68702,7 +70613,7 @@ break; } default: { - DUK_UNREACHABLE(); + /* Possible with DUK_OP_EXP. */ goto skip_fastint; } } @@ -68959,8 +70870,7 @@ if (DUK_TVAL_IS_NUMBER(tv)) { d1 = DUK_TVAL_GET_NUMBER(tv); } else { - d1 = duk_to_number(ctx, idx_src); /* side effects, perform in-place */ - DUK_ASSERT(DUK_TVAL_IS_NUMBER(DUK_GET_TVAL_POSIDX(ctx, idx_src))); + d1 = duk_to_number_tval(ctx, tv); /* side effects */ } if (opcode == DUK_OP_UNP) { @@ -69012,7 +70922,9 @@ else #endif /* DUK_USE_FASTINT */ { - i1 = duk_to_int32(ctx, idx_src); /* side effects */ + duk_push_tval(ctx, tv); + i1 = duk_to_int32(ctx, -1); /* side effects */ + duk_pop_unsafe(ctx); } /* Result is always fastint compatible. */ @@ -69155,7 +71067,7 @@ DUK_ASSERT(DUK_TVAL_IS_STRING(tv_id)); name = DUK_TVAL_GET_STRING(tv_id); DUK_ASSERT(name != NULL); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [ ... val this ] */ /* XXX: Fastint fast path would be useful here. Also fastints @@ -69174,11 +71086,13 @@ if (op & 0x02) { duk_push_number(ctx, y); /* -> [ ... x this y ] */ + act = thr->callstack_curr; duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(ctx, -1), is_strict); duk_pop_2(ctx); /* -> [ ... x ] */ } else { duk_pop_2(ctx); /* -> [ ... ] */ duk_push_number(ctx, y); /* -> [ ... y ] */ + act = thr->callstack_curr; duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(ctx, -1), is_strict); } @@ -69308,17 +71222,19 @@ duk__set_catcher_regs(thr, cat_idx, tv_val_unstable, lj_type); - duk_hthread_catchstack_unwind(thr, cat_idx + 1); - duk_hthread_callstack_unwind(thr, thr->catchstack[cat_idx].callstack_index + 1); + duk_hthread_catchstack_unwind_norz(thr, cat_idx + 1); + duk_hthread_callstack_unwind_norz(thr, thr->catchstack[cat_idx].callstack_index + 1); DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))); + DUK_ASSERT(thr->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); duk__reconfig_valstack_ecma_catcher(thr, thr->callstack_top - 1, cat_idx); DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); act->curr_pc = thr->catchstack[cat_idx].pc_base + 0; /* +0 = catch */ act = NULL; @@ -69333,8 +71249,7 @@ */ if (DUK_CAT_HAS_CATCH_BINDING_ENABLED(&thr->catchstack[cat_idx])) { - duk_hobject *new_env; - duk_hobject *act_lex_env; + duk_hdecenv *new_env; DUK_DDD(DUK_DDDPRINT("catcher has an automatic catch binding")); @@ -69342,7 +71257,8 @@ * points, so we re-lookup it multiple times. */ DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); if (act->lex_env == NULL) { DUK_ASSERT(act->var_env == NULL); @@ -69350,22 +71266,26 @@ /* this may have side effects, so re-lookup act */ duk_js_init_activation_environment_records_delayed(thr, act); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); } DUK_ASSERT(act->lex_env != NULL); DUK_ASSERT(act->var_env != NULL); DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL); DUK_UNREF(act); /* unreferenced without assertions */ - act = thr->callstack + thr->callstack_top - 1; - act_lex_env = act->lex_env; - act = NULL; /* invalidated */ - - new_env = duk_push_object_helper_proto(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), - act_lex_env); + /* XXX: If an out-of-memory happens here, longjmp state asserts + * will be triggered at present and a try-catch fails to catch. + * That's not sandboxing fatal (C API protected calls are what + * matters), and script catch code can immediately throw anyway + * for almost any operation. + */ + 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(ctx, (duk_hobject *) new_env); + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL); DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", (duk_heaphdr *) new_env)); /* Note: currently the catch binding is handled without a register @@ -69374,14 +71294,20 @@ * record regbases etc. */ + /* XXX: duk_xdef_prop() may cause an out-of-memory, see above. */ DUK_ASSERT(thr->catchstack[cat_idx].h_varname != NULL); duk_push_hstring(ctx, thr->catchstack[cat_idx].h_varname); duk_push_tval(ctx, thr->valstack + thr->catchstack[cat_idx].idx_base); duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_W); /* writable, not configurable */ - act = thr->callstack + thr->callstack_top - 1; - act->lex_env = new_env; - DUK_HOBJECT_INCREF(thr, new_env); /* reachable through activation */ + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); + DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, act->lex_env); + act->lex_env = (duk_hobject *) new_env; + DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env); /* reachable through activation */ + /* Net refcount change to act->lex_env is 0: incref for new_env's + * prototype, decref for act->lex_env overwrite. + */ DUK_CAT_SET_LEXENV_ACTIVE(&thr->catchstack[cat_idx]); @@ -69401,17 +71327,19 @@ duk__set_catcher_regs(thr, cat_idx, tv_val_unstable, lj_type); - duk_hthread_catchstack_unwind(thr, cat_idx + 1); /* cat_idx catcher is kept, even for finally */ - duk_hthread_callstack_unwind(thr, thr->catchstack[cat_idx].callstack_index + 1); + duk_hthread_catchstack_unwind_norz(thr, cat_idx + 1); /* cat_idx catcher is kept, even for finally */ + duk_hthread_callstack_unwind_norz(thr, thr->catchstack[cat_idx].callstack_index + 1); DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))); + DUK_ASSERT(thr->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); duk__reconfig_valstack_ecma_catcher(thr, thr->callstack_top - 1, cat_idx); DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); act->curr_pc = thr->catchstack[cat_idx].pc_base + 1; /* +1 = finally */ act = NULL; @@ -69424,7 +71352,8 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL); DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(DUK_ACT_GET_FUNC(act))); @@ -69433,13 +71362,14 @@ act->curr_pc = thr->catchstack[cat_idx].pc_base + (lj_type == DUK_LJ_TYPE_CONTINUE ? 1 : 0); act = NULL; /* invalidated */ - duk_hthread_catchstack_unwind(thr, cat_idx + 1); /* keep label catcher */ + duk_hthread_catchstack_unwind_norz(thr, cat_idx + 1); /* keep label catcher */ /* no need to unwind callstack */ /* valstack should not need changes */ #if defined(DUK_USE_ASSERTIONS) DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) == (duk_size_t) ((duk_hcompfunc *) DUK_ACT_GET_FUNC(act))->nregs); #endif @@ -69461,7 +71391,7 @@ tv1 = resumer->valstack + resumer->callstack[act_idx].idx_retval; /* return value from Duktape.Thread.resume() */ DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable); /* side effects */ - duk_hthread_callstack_unwind(resumer, act_idx + 1); /* unwind to 'resume' caller */ + duk_hthread_callstack_unwind_norz(resumer, act_idx + 1); /* unwind to 'resume' caller */ /* no need to unwind catchstack */ duk__reconfig_valstack_ecma_return(resumer, act_idx); @@ -69524,10 +71454,11 @@ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged by Duktape.Thread.resume() */ DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))->func == duk_bi_thread_resume); - DUK_ASSERT_DISABLE((thr->callstack + thr->callstack_top - 2)->idx_retval >= 0); /* unsigned */ + DUK_ASSERT(thr->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack_curr))->func == duk_bi_thread_resume); + DUK_ASSERT_DISABLE((thr->callstack_curr - 1)->idx_retval >= 0); /* unsigned */ tv = &thr->heap->lj.value2; /* resumee */ DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); @@ -69542,11 +71473,11 @@ DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED || resumee->callstack_top >= 2); /* YIELDED: Ecmascript activation + Duktape.Thread.yield() activation */ DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED || - (DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1))->func == duk_bi_thread_yield)); + (DUK_ACT_GET_FUNC(resumee->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumee->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumee->callstack_curr))->func == duk_bi_thread_yield)); DUK_ASSERT_DISABLE(resumee->state != DUK_HTHREAD_STATE_YIELDED || - (resumee->callstack + resumee->callstack_top - 2)->idx_retval >= 0); /* idx_retval unsigned */ + (resumee->callstack_curr - 1)->idx_retval >= 0); /* idx_retval unsigned */ DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_INACTIVE || resumee->callstack_top == 0); /* INACTIVE: no activation, single function value on valstack */ @@ -69561,7 +71492,9 @@ * which we simply ignore. */ + DUK_ASSERT(resumee->resumer == NULL); resumee->resumer = thr; + DUK_HTHREAD_INCREF(thr, thr); resumee->state = DUK_HTHREAD_STATE_RUNNING; thr->state = DUK_HTHREAD_STATE_RESUMED; DUK_HEAP_SWITCH_THREAD(thr->heap, resumee); @@ -69585,13 +71518,15 @@ tv2 = &thr->heap->lj.value1; DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv2); /* side effects */ - duk_hthread_callstack_unwind(resumee, act_idx + 1); /* unwind to 'yield' caller */ + duk_hthread_callstack_unwind_norz(resumee, act_idx + 1); /* unwind to 'yield' caller */ /* no need to unwind catchstack */ duk__reconfig_valstack_ecma_return(resumee, act_idx); + DUK_ASSERT(resumee->resumer == NULL); resumee->resumer = thr; + DUK_HTHREAD_INCREF(thr, thr); resumee->state = DUK_HTHREAD_STATE_RUNNING; thr->state = DUK_HTHREAD_STATE_RESUMED; DUK_HEAP_SWITCH_THREAD(thr->heap, resumee); @@ -69627,7 +71562,9 @@ DUK_ERROR_INTERNAL(thr); } + DUK_ASSERT(resumee->resumer == NULL); resumee->resumer = thr; + DUK_HTHREAD_INCREF(thr, thr); resumee->state = DUK_HTHREAD_STATE_RUNNING; thr->state = DUK_HTHREAD_STATE_RESUMED; DUK_HEAP_SWITCH_THREAD(thr->heap, resumee); @@ -69660,28 +71597,31 @@ DUK_ASSERT(thr != entry_thread); /* Duktape.Thread.yield() should prevent */ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged from Duktape.Thread.yield() */ DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.yield() activation */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))->func == duk_bi_thread_yield); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2))); /* an Ecmascript function */ - DUK_ASSERT_DISABLE((thr->callstack + thr->callstack_top - 2)->idx_retval >= 0); /* unsigned */ + DUK_ASSERT(thr->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack_curr))->func == duk_bi_thread_yield); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr - 1) != NULL && + DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr - 1))); /* an Ecmascript function */ + DUK_ASSERT_DISABLE((thr->callstack_curr - 1)->idx_retval >= 0); /* unsigned */ resumer = thr->resumer; DUK_ASSERT(resumer != NULL); DUK_ASSERT(resumer->state == DUK_HTHREAD_STATE_RESUMED); /* written by a previous RESUME handling */ DUK_ASSERT(resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ - DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1))->func == duk_bi_thread_resume); - DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 2) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 2))); /* an Ecmascript function */ - DUK_ASSERT_DISABLE((resumer->callstack + resumer->callstack_top - 2)->idx_retval >= 0); /* unsigned */ + DUK_ASSERT(resumer->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumer->callstack_curr))->func == duk_bi_thread_resume); + DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr - 1) != NULL && + DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr - 1))); /* an Ecmascript function */ + DUK_ASSERT_DISABLE((resumer->callstack_curr - 1)->idx_retval >= 0); /* unsigned */ if (thr->heap->lj.iserror) { thr->state = DUK_HTHREAD_STATE_YIELDED; thr->resumer = NULL; + DUK_HTHREAD_DECREF_NORZ(thr, resumer); resumer->state = DUK_HTHREAD_STATE_RUNNING; DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); thr = resumer; @@ -69697,6 +71637,7 @@ thr->state = DUK_HTHREAD_STATE_YIELDED; thr->resumer = NULL; + DUK_HTHREAD_DECREF_NORZ(thr, resumer); resumer->state = DUK_HTHREAD_STATE_RUNNING; DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); #if 0 @@ -69777,9 +71718,9 @@ * final catcher unwind everything */ #if 0 - duk_hthread_catchstack_unwind(thr, (cat - thr->catchstack) + 1); /* leave 'cat' as top catcher (also works if catchstack exhausted) */ - duk_hthread_callstack_unwind(thr, entry_callstack_index + 1); - + duk_hthread_catchstack_unwind_norz(thr, (cat - thr->catchstack) + 1); /* leave 'cat' as top catcher (also works if catchstack exhausted) */ + duk_hthread_callstack_unwind_norz(thr, entry_callstack_index + 1); + DUK_REFZERO_CHECK_SLOW(thr); #endif DUK_D(DUK_DPRINT("-> throw propagated up to entry level, rethrow and exit bytecode executor")); retval = DUK__LONGJMP_RETHROW; @@ -69796,11 +71737,12 @@ DUK_ASSERT(thr->resumer != NULL); DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2))); /* an Ecmascript function */ + DUK_ASSERT(thr->resumer->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack_curr))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */ + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr - 1) != NULL && + DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr - 1))); /* an Ecmascript function */ resumer = thr->resumer; @@ -69813,6 +71755,7 @@ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED); thr->resumer = NULL; + DUK_HTHREAD_DECREF_NORZ(thr, resumer); resumer->state = DUK_HTHREAD_STATE_RUNNING; DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); thr = resumer; @@ -69841,6 +71784,8 @@ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */ + DUK_GC_TORTURE(thr->heap); + just_return: return retval; @@ -69981,6 +71926,7 @@ cat = thr->catchstack + thr->catchstack_top - 1; /* may be < thr->catchstack initially */ DUK_ASSERT(thr->callstack_top > 0); /* ensures callstack_top - 1 >= 0 */ + DUK_ASSERT(thr->callstack_curr != NULL); orig_callstack_index = thr->callstack_top - 1; while (cat >= thr->catchstack) { @@ -70028,22 +71974,22 @@ */ DUK_DDD(DUK_DDDPRINT("return to Ecmascript caller, idx_retval=%ld, lj_value1=%!T", - (long) (thr->callstack + thr->callstack_top - 2)->idx_retval, + (long) (thr->callstack_curr - 1)->idx_retval, (duk_tval *) &thr->heap->lj.value1)); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2))); /* must be ecmascript */ + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr - 1))); /* must be ecmascript */ - tv1 = thr->valstack + (thr->callstack + thr->callstack_top - 2)->idx_retval; + tv1 = thr->valstack + (thr->callstack_curr - 1)->idx_retval; DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom); tv2 = thr->valstack_top - 1; DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */ DUK_DDD(DUK_DDDPRINT("return value at idx_retval=%ld is %!T", - (long) (thr->callstack + thr->callstack_top - 2)->idx_retval, - (duk_tval *) (thr->valstack + (thr->callstack + thr->callstack_top - 2)->idx_retval))); + (long) (thr->callstack_curr - 1)->idx_retval, + (duk_tval *) (thr->valstack + (thr->callstack_curr - 1)->idx_retval))); - duk_hthread_catchstack_unwind(thr, new_cat_top); /* leave 'cat' as top catcher (also works if catchstack exhausted) */ - duk_hthread_callstack_unwind(thr, thr->callstack_top - 1); + duk_hthread_catchstack_unwind_norz(thr, new_cat_top); /* leave 'cat' as top catcher (also works if catchstack exhausted) */ + duk_hthread_callstack_unwind_norz(thr, thr->callstack_top - 1); duk__reconfig_valstack_ecma_return(thr, thr->callstack_top - 1); DUK_DD(DUK_DDPRINT("-> return not intercepted, restart execution in caller")); @@ -70055,12 +72001,13 @@ DUK_ASSERT(thr->resumer != NULL); DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2))); /* an Ecmascript function */ - DUK_ASSERT_DISABLE((thr->resumer->callstack + thr->resumer->callstack_top - 2)->idx_retval >= 0); /* unsigned */ + DUK_ASSERT(thr->resumer->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack_curr))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */ + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr - 1) != NULL && + DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr - 1))); /* an Ecmascript function */ + DUK_ASSERT_DISABLE((thr->resumer->callstack_curr - 1)->idx_retval >= 0); /* unsigned */ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED); @@ -70074,6 +72021,7 @@ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED); thr->resumer = NULL; + DUK_HTHREAD_DECREF(thr, resumer); resumer->state = DUK_HTHREAD_STATE_RUNNING; DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); #if 0 @@ -70132,7 +72080,8 @@ DUK_ASSERT(thr->heap->dbg_processing == 0); /* don't re-enter e.g. during Eval */ ctx = (duk_context *) thr; - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); /* It might seem that replacing 'thr->heap' with just 'heap' below * might be a good idea, but it increases code size slightly @@ -70157,8 +72106,7 @@ (line != thr->heap->dbg_step_startline)) { DUK_D(DUK_DPRINT("STEP STATE TRIGGERED PAUSE at line %ld", (long) line)); - - DUK_HEAP_SET_PAUSED(thr->heap); + duk_debug_set_paused(thr->heap); } /* Check for breakpoints only on line transition. @@ -70184,8 +72132,7 @@ if (act->prev_line != bp->line && line == bp->line) { DUK_D(DUK_DPRINT("BREAKPOINT TRIGGERED at %!O:%ld", (duk_heaphdr *) bp->filename, (long) bp->line)); - - DUK_HEAP_SET_PAUSED(thr->heap); + duk_debug_set_paused(thr->heap); } } } else { @@ -70272,8 +72219,9 @@ * above, so we must recheck attach status. */ - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { - act = thr->callstack + thr->callstack_top - 1; /* relookup, may have changed */ + if (duk_debug_is_attached(thr->heap)) { + act = thr->callstack_curr; /* relookup, may have changed */ + DUK_ASSERT(act != NULL); if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE || ((thr->heap->dbg_step_type == DUK_STEP_TYPE_INTO || thr->heap->dbg_step_type == DUK_STEP_TYPE_OVER) && @@ -70296,7 +72244,7 @@ } #endif /* DUK_USE_DEBUGGER_SUPPORT */ -DUK_LOCAL duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) { +DUK_LOCAL DUK_NOINLINE DUK_COLD duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) { duk_int_t ctr; duk_activation *act; duk_hcompfunc *fun; @@ -70346,7 +72294,8 @@ } DUK_HEAP_SET_INTERRUPT_RUNNING(thr->heap); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC((duk_hobject *) fun)); @@ -70382,7 +72331,7 @@ * detaching (to finish off the pending detach). */ duk__interrupt_handle_debugger(thr, &immediate, &retval); - act = thr->callstack + thr->callstack_top - 1; /* relookup if changed */ + act = thr->callstack_curr; /* relookup if changed */ DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */ } #endif /* DUK_USE_DEBUGGER_SUPPORT */ @@ -70524,7 +72473,7 @@ (thr->heap->dbg_step_thread != thr || thr->heap->dbg_step_csindex != thr->callstack_top - 1)) { DUK_D(DUK_DPRINT("STEP INTO ACTIVE, FORCE PAUSED")); - DUK_HEAP_SET_PAUSED(thr->heap); + duk_debug_set_paused(thr->heap); } /* Force interrupt right away if we're paused or in "checked mode". @@ -70579,7 +72528,7 @@ #if defined(DUK_USE_EXEC_FUN_LOCAL) #define DUK__FUN() fun #else -#define DUK__FUN() ((duk_hcompfunc *) DUK_ACT_GET_FUNC((thr)->callstack + (thr)->callstack_top - 1)) +#define DUK__FUN() ((duk_hcompfunc *) DUK_ACT_GET_FUNC((thr)->callstack_curr)) #endif #define DUK__STRICT() (DUK_HOBJECT_HAS_STRICT((duk_hobject *) DUK__FUN())) @@ -70656,12 +72605,12 @@ #define DUK__SYNC_CURR_PC() do { \ duk_activation *act; \ - act = thr->callstack + thr->callstack_top - 1; \ + act = thr->callstack_curr; \ act->curr_pc = curr_pc; \ } while (0) #define DUK__SYNC_AND_NULL_CURR_PC() do { \ duk_activation *act; \ - act = thr->callstack + thr->callstack_top - 1; \ + act = thr->callstack_curr; \ act->curr_pc = curr_pc; \ thr->ptr_curr_pc = NULL; \ } while (0) @@ -70713,15 +72662,27 @@ lj_ret = duk__handle_longjmp(heap->curr_thread, entry_thread, entry_callstack_top); + /* Error handling complete, remove side effect protections. + */ +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(heap->error_not_allowed == 1); + heap->error_not_allowed = 0; +#endif + DUK_ASSERT(heap->pf_prevent_count > 0); + heap->pf_prevent_count--; + DUK_DD(DUK_DDPRINT("executor error handled, pf_prevent_count updated to %ld", (long) heap->pf_prevent_count)); + if (lj_ret == DUK__LONGJMP_RESTART) { /* Restart bytecode execution, possibly with a changed thread. */ - ; + DUK_REFZERO_CHECK_SLOW(heap->curr_thread); } else { - /* Rethrow error to calling state. */ - DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW); + /* If an error is propagated, don't run refzero checks here. + * The next catcher will deal with that. Pf_prevent_count + * will be re-bumped by the longjmp. + */ - /* Longjmp handling has restored jmpbuf_ptr. */ - DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr); + DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW); /* Rethrow error to calling state. */ + DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr); /* Longjmp handling has restored jmpbuf_ptr. */ /* Thread may have changed, e.g. YIELD converted to THROW. */ duk_err_longjmp(heap->curr_thread); @@ -70744,8 +72705,10 @@ DUK_ASSERT(exec_thr->heap->curr_thread != NULL); DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR((duk_heaphdr *) exec_thr); DUK_ASSERT(exec_thr->callstack_top >= 1); /* at least one activation, ours */ - DUK_ASSERT(DUK_ACT_GET_FUNC(exec_thr->callstack + exec_thr->callstack_top - 1) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(exec_thr->callstack + exec_thr->callstack_top - 1))); + DUK_ASSERT(DUK_ACT_GET_FUNC(exec_thr->callstack_curr) != NULL); + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(exec_thr->callstack_curr))); + + DUK_GC_TORTURE(exec_thr->heap); entry_thread = exec_thr; heap = entry_thread->heap; @@ -70836,7 +72799,7 @@ } /* Inner executor, performance critical. */ -DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_size_t entry_callstack_top) { +DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_size_t entry_callstack_top) { /* Current PC, accessed by other functions through thr->ptr_to_curr_pc. * Critical for performance. It would be safest to make this volatile, * but that eliminates performance benefits; aliasing guarantees @@ -70877,6 +72840,8 @@ #endif #endif + DUK_GC_TORTURE(entry_thread->heap); + /* * Restart execution by reloading thread state. * @@ -70926,8 +72891,11 @@ thr = entry_thread->heap->curr_thread; DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))); + DUK_ASSERT(thr->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); + + DUK_GC_TORTURE(thr->heap); thr->ptr_curr_pc = &curr_pc; @@ -70941,7 +72909,8 @@ /* Assume interrupt init/counter are properly initialized here. */ /* Assume that thr->valstack_bottom has been set-up before getting here. */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); DUK_ASSERT(fun != NULL); DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == fun->nregs); @@ -70949,9 +72918,10 @@ DUK_ASSERT(consts != NULL); #if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap) && !thr->heap->dbg_processing) { + if (duk_debug_is_attached(thr->heap) && !thr->heap->dbg_processing) { duk__executor_recheck_debugger(thr, act, fun); - act = thr->callstack + thr->callstack_top - 1; /* relookup after side effects (no side effects currently however) */ + act = thr->callstack_curr; /* relookup after side effects (no side effects currently however) */ + DUK_ASSERT(act != NULL); } #endif /* DUK_USE_DEBUGGER_SUPPORT */ @@ -71001,10 +72971,11 @@ duk_small_uint_t exec_int_ret; /* Write curr_pc back for the debugger. */ - DUK_ASSERT(thr->callstack_top > 0); { duk_activation *act; - act = thr->callstack + thr->callstack_top - 1; + DUK_ASSERT(thr->callstack_top > 0); + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); act->curr_pc = (duk_instr_t *) curr_pc; } @@ -71038,7 +73009,7 @@ #if defined(DUK_USE_ASSERTIONS) || defined(DUK_USE_DEBUG) { duk_activation *act; - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; DUK_ASSERT(curr_pc >= DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, DUK__FUN())); DUK_ASSERT(curr_pc < DUK_HCOMPFUNC_GET_CODE_END(thr->heap, DUK__FUN())); DUK_UNREF(act); /* if debugging disabled */ @@ -71330,7 +73301,7 @@ DUK_ASSERT(DUK_TVAL_IS_STRING(tv)); name = DUK_TVAL_GET_STRING(tv); tv = NULL; /* lookup has side effects */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; if (duk_js_getvar_activation(thr, act, name, 0 /*throw*/)) { /* -> [... val this] */ tv = DUK_GET_TVAL_NEGIDX(ctx, -2); @@ -72058,14 +74029,12 @@ duk_hstring *name; duk_small_uint_t prop_flags; duk_bool_t is_func_decl; - duk_bool_t is_undef_value; tv1 = DUK__REGCONSTP_B(ins); DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); name = DUK_TVAL_GET_STRING(tv1); DUK_ASSERT(name != NULL); - is_undef_value = ((a & DUK_BC_DECLVAR_FLAG_UNDEF_VALUE) != 0); is_func_decl = ((a & DUK_BC_DECLVAR_FLAG_FUNC_DECL) != 0); /* XXX: declvar takes an duk_tval pointer, which is awkward and @@ -72077,19 +74046,25 @@ */ prop_flags = a & DUK_PROPDESC_FLAGS_MASK; - if (is_undef_value) { + if (is_func_decl) { + duk_push_tval(ctx, DUK__REGCONSTP_C(ins)); + } else { DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */ thr->valstack_top++; - } else { - duk_push_tval(ctx, DUK__REGCONSTP_C(ins)); } tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; if (duk_js_declvar_activation(thr, act, name, tv1, prop_flags, is_func_decl)) { - /* already declared, must update binding value */ - tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1); - duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT()); + if (is_func_decl) { + /* Already declared, update value. */ + tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1); + duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT()); + } else { + /* Already declared but no initializer value + * (e.g. 'var xyz;'), no-op. + */ + } } duk_pop(ctx); @@ -72143,7 +74118,7 @@ DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); name = DUK_TVAL_GET_STRING(tv1); DUK_ASSERT(name != NULL); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */ idx = (duk_uint_fast_t) DUK_DEC_A(ins); @@ -72170,7 +74145,7 @@ DUK_ASSERT_DISABLE(bc >= 0); /* unsigned */ DUK_ASSERT((duk_uint_t) bc < (duk_uint_t) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, DUK__FUN())); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; fun_act = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); fun_temp = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, fun_act)[bc]; DUK_ASSERT(fun_temp != NULL); @@ -72182,6 +74157,7 @@ if (act->lex_env == NULL) { DUK_ASSERT(act->var_env == NULL); duk_js_init_activation_environment_records_delayed(thr, act); + act = thr->callstack_curr; } DUK_ASSERT(act->lex_env != NULL); DUK_ASSERT(act->var_env != NULL); @@ -72208,7 +74184,7 @@ DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); name = DUK_TVAL_GET_STRING(tv1); DUK_ASSERT(name != NULL); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */ duk_pop(ctx); /* 'this' binding is not needed here */ DUK__REPLACE_TOP_A_BREAK(); @@ -72229,7 +74205,7 @@ */ tv1 = DUK__REGP_A(ins); /* val */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT()); break; } @@ -72244,7 +74220,7 @@ DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); name = DUK_TVAL_GET_STRING(tv1); DUK_ASSERT(name != NULL); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; rc = duk_js_delvar_activation(thr, act, name); DUK__REPLACE_BOOL_A_BREAK(rc); } @@ -72305,6 +74281,7 @@ thr->valstack_top++; DUK__RETURN_SHARED(); } + /* This will be unused without refcounting. */ case DUK_OP_RETCONST: { duk_tval *tv; @@ -72321,7 +74298,10 @@ DUK__SYNC_AND_NULL_CURR_PC(); tv = DUK__CONSTP_BC(ins); DUK_TVAL_SET_TVAL(thr->valstack_top, tv); +#if defined(DUK_USE_REFERENCE_COUNTING) + /* Without refcounting only RETCONSTN is used. */ DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv)); /* no INCREF for this constant */ +#endif thr->valstack_top++; DUK__RETURN_SHARED(); } @@ -72445,57 +74425,44 @@ a = DUK_DEC_A(ins); bc = DUK_DEC_BC(ins); - act = thr->callstack + thr->callstack_top - 1; - DUK_ASSERT(thr->callstack_top >= 1); - - /* 'with' target must be created first, in case we run out of memory */ - /* XXX: refactor out? */ - - if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) { - DUK_DDD(DUK_DDDPRINT("need to initialize a with binding object")); - - if (act->lex_env == NULL) { - DUK_ASSERT(act->var_env == NULL); - DUK_DDD(DUK_DDDPRINT("delayed environment initialization")); - - /* must relookup act in case of side effects */ - duk_js_init_activation_environment_records_delayed(thr, act); - act = thr->callstack + thr->callstack_top - 1; - DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */ - } - DUK_ASSERT(act->lex_env != NULL); - DUK_ASSERT(act->var_env != NULL); - - (void) duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV), - -1); /* no prototype, updated below */ - - duk_push_tval(ctx, DUK__REGP(bc)); - duk_to_object(ctx, -1); - duk_dup_top(ctx); - - /* [ ... env target ] */ - /* [ ... env target target ] */ - - duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); /* always provideThis=true */ - - /* [ ... env ] */ + /* Registers 'bc' and 'bc + 1' are written in longjmp handling + * and if their previous values (which are temporaries) become + * unreachable -and- have a finalizer, there'll be a function + * call during error handling which is not supported now (GH-287). + * Ensure that both 'bc' and 'bc + 1' have primitive values to + * guarantee no finalizer calls in error handling. Scrubbing also + * ensures finalizers for the previous values run here rather than + * later. Error handling related values are also written to 'bc' + * and 'bc + 1' but those values never become unreachable during + * error handling, so there's no side effect problem even if the + * error value has a finalizer. + */ + duk_dup(ctx, bc); /* Stabilize value. */ + duk_to_undefined(ctx, bc); + duk_to_undefined(ctx, bc + 1); - DUK_DDD(DUK_DDDPRINT("environment for with binding: %!iT", - (duk_tval *) duk_get_tval(ctx, -1))); - } + /* Ensure a catchstack entry is available. One entry + * is guaranteed even if side effects cause function + * calls and the catchstack is shrunk because some + * spare room is left behind by a shrink operation. + */ + duk_hthread_catchstack_grow(thr); - /* allocate catcher and populate it (should be atomic) */ + /* Allocate catcher and populate it. Doesn't have to + * be fully atomic, but the catcher must be in a + * consistent state if side effects (such as finalizer + * calls) occur. + */ - duk_hthread_catchstack_grow(thr); - cat = thr->catchstack + thr->catchstack_top; DUK_ASSERT(thr->catchstack_top + 1 <= thr->catchstack_size); + cat = thr->catchstack + thr->catchstack_top; thr->catchstack_top++; cat->flags = DUK_CAT_TYPE_TCF; cat->h_varname = NULL; + cat->callstack_index = thr->callstack_top - 1; + cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */ + cat->idx_base = (duk_size_t) (thr->valstack_bottom - thr->valstack) + bc; if (a & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) { cat->flags |= DUK_CAT_FLAG_CATCH_ENABLED; @@ -72506,7 +74473,7 @@ if (a & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING) { DUK_DDD(DUK_DDDPRINT("catch binding flag set to catcher")); cat->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED; - tv1 = DUK__REGP(bc); + tv1 = DUK_GET_TVAL_NEGIDX(thr, -1); DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); /* borrowed reference; although 'tv1' comes from a register, @@ -72515,54 +74482,69 @@ */ cat->h_varname = DUK_TVAL_GET_STRING(tv1); } else if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) { - /* env created above to stack top */ - duk_hobject *new_env; + duk_hobjenv *env; + duk_hobject *target; - DUK_DDD(DUK_DDDPRINT("lexenv active flag set to catcher")); - cat->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE; + /* Delayed env initialization for activation (if needed). */ + DUK_ASSERT(thr->callstack_top >= 1); + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); + if (act->lex_env == NULL) { + DUK_DDD(DUK_DDDPRINT("delayed environment initialization")); + DUK_ASSERT(act->var_env == NULL); - DUK_DDD(DUK_DDDPRINT("activating object env: %!iT", - (duk_tval *) duk_get_tval(ctx, -1))); + duk_js_init_activation_environment_records_delayed(thr, act); + act = thr->callstack_curr; /* relookup, side effects */ + DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */ + } DUK_ASSERT(act->lex_env != NULL); - new_env = DUK_GET_HOBJECT_NEGIDX(ctx, -1); - DUK_ASSERT(new_env != NULL); + DUK_ASSERT(act->var_env != NULL); - act = thr->callstack + thr->callstack_top - 1; /* relookup (side effects) */ - DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, new_env, act->lex_env); /* side effects */ + /* Coerce 'with' target. */ + target = duk_to_hobject(ctx, -1); + DUK_ASSERT(target != NULL); + + /* Create an object environment; it is not pushed + * so avoid side effects very carefully until it is + * referenced. + */ + env = duk_hobjenv_alloc(thr, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV)); + DUK_ASSERT(env != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL); + env->target = target; /* always provideThis=true */ + DUK_HOBJECT_INCREF(thr, target); + env->has_this = 1; + DUK_ASSERT_HOBJENV_VALID(env); + DUK_DDD(DUK_DDDPRINT("environment for with binding: %!iO", env)); - act = thr->callstack + thr->callstack_top - 1; /* relookup (side effects) */ - act->lex_env = new_env; - DUK_HOBJECT_INCREF(thr, new_env); - duk_pop(ctx); + act = thr->callstack_curr; /* relookup (side effects) */ + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL); + DUK_ASSERT(act->lex_env != NULL); + DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) env, act->lex_env); + act->lex_env = (duk_hobject *) env; /* Now reachable. */ + DUK_HOBJECT_INCREF(thr, (duk_hobject *) env); + /* Net refcount change to act->lex_env is 0: incref for env's + * prototype, decref for act->lex_env overwrite. + */ + + /* Set catcher lex_env active (affects unwind) + * only when the whole setup is complete. + */ + cat = thr->catchstack + thr->catchstack_top - 1; + cat->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE; } else { ; } - /* Registers 'bc' and 'bc + 1' are written in longjmp handling - * and if their previous values (which are temporaries) become - * unreachable -and- have a finalizer, there'll be a function - * call during error handling which is not supported now (GH-287). - * Ensure that both 'bc' and 'bc + 1' have primitive values to - * guarantee no finalizer calls in error handling. Scrubbing also - * ensures finalizers for the previous values run here rather than - * later. Error handling related values are also written to 'bc' - * and 'bc + 1' but those values never become unreachable during - * error handling, so there's no side effect problem even if the - * error value has a finalizer. - */ - duk_to_undefined(ctx, bc); - duk_to_undefined(ctx, bc + 1); - - cat = thr->catchstack + thr->catchstack_top - 1; /* relookup (side effects) */ - cat->callstack_index = thr->callstack_top - 1; - cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */ - cat->idx_base = (duk_size_t) (thr->valstack_bottom - thr->valstack) + bc; - DUK_DDD(DUK_DDDPRINT("TRYCATCH catcher: flags=0x%08lx, callstack_index=%ld, pc_base=%ld, " "idx_base=%ld, h_varname=%!O", (unsigned long) cat->flags, (long) cat->callstack_index, (long) cat->pc_base, (long) cat->idx_base, (duk_heaphdr *) cat->h_varname)); + duk_pop(ctx); + curr_pc += 2; /* skip jump slots */ break; } @@ -72616,7 +74598,8 @@ cat = thr->catchstack + thr->catchstack_top - 1; DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat)); /* cleared before entering catch part */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) { duk_hobject *prev_env; @@ -72631,6 +74614,7 @@ DUK_ASSERT(prev_env != NULL); act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, prev_env); DUK_CAT_CLEAR_LEXENV_ACTIVE(cat); + DUK_HOBJECT_INCREF(thr, act->lex_env); DUK_HOBJECT_DECREF(thr, prev_env); /* side effects */ } @@ -72755,7 +74739,8 @@ duk_push_tval(ctx, thr->valstack + cat->idx_base); - duk_err_setup_heap_ljstate(thr, (duk_small_int_t) cont_type); + duk_err_setup_ljstate1(thr, (duk_small_int_t) cont_type, thr->valstack + cat->idx_base); + /* No debugger Throw notify check on purpose (rethrow). */ DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */ duk_err_longjmp(thr); @@ -72792,7 +74777,10 @@ (duk_tval *) duk_get_tval(ctx, -1))); #endif - duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW); + duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(ctx, -1)); +#if defined(DUK_USE_DEBUGGER_SUPPORT) + duk_err_check_debugger_integration(thr); +#endif DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */ duk_err_longjmp(thr); @@ -73329,7 +75317,7 @@ * from precompiled bytecode. */ #if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + if (duk_debug_is_attached(thr->heap)) { DUK_D(DUK_DPRINT("DEBUGGER statement encountered, halt execution")); DUK__SYNC_AND_NULL_CURR_PC(); duk_debug_halt_execution(thr, 1 /*use_prev_pc*/); @@ -73422,22 +75410,18 @@ case DUK_OP_UNUSED252: case DUK_OP_UNUSED253: case DUK_OP_UNUSED254: - case DUK_OP_UNUSED255: { - /* Force all case clauses to map to an actual handler - * so that the compiler can emit a jump without a bounds - * check: the switch argument is a duk_uint8_t so that - * the compiler may be able to figure it out. This is - * a small detail and obviously compiler dependent. - */ - volatile duk_small_int_t dummy_volatile; - dummy_volatile = 0; - DUK_UNREF(dummy_volatile); - DUK_D(DUK_DPRINT("invalid opcode: %ld - %!I", (long) op, ins)); - DUK__INTERNAL_ERROR("invalid opcode"); - break; - } + case DUK_OP_UNUSED255: + /* Force all case clauses to map to an actual handler + * so that the compiler can emit a jump without a bounds + * check: the switch argument is a duk_uint8_t so that + * the compiler may be able to figure it out. This is + * a small detail and obviously compiler dependent. + */ + /* default: clause omitted on purpose */ +#else + default: #endif /* DUK_USE_EXEC_PREFER_SIZE */ - default: { + { /* Default case catches invalid/unsupported opcodes. */ DUK_D(DUK_DPRINT("invalid opcode: %ld - %!I", (long) op, ins)); DUK__INTERNAL_ERROR("invalid opcode"); @@ -73753,7 +75737,7 @@ case DUK_TAG_STRING: { /* For Symbols ToNumber() is always a TypeError. */ duk_hstring *h = DUK_TVAL_GET_STRING(tv); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { DUK_ERROR_TYPE(thr, DUK_STR_CANNOT_NUMBER_COERCE_SYMBOL); } duk_push_hstring(ctx, h); @@ -74485,7 +76469,7 @@ DUK_ASSERT(h1 != NULL); DUK_ASSERT(h2 != NULL); - if (!DUK_HSTRING_HAS_SYMBOL(h1) && !DUK_HSTRING_HAS_SYMBOL(h2)) { + if (DUK_LIKELY(!DUK_HSTRING_HAS_SYMBOL(h1) && !DUK_HSTRING_HAS_SYMBOL(h2))) { rc = duk_js_string_compare(h1, h2); duk_pop_2(ctx); if (rc < 0) { @@ -74615,7 +76599,7 @@ /* func support for [[HasInstance]] checked in the beginning of the loop */ } while (--sanity > 0); - if (sanity == 0) { + if (DUK_UNLIKELY(sanity == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_BOUND_CHAIN_LIMIT); } @@ -74701,7 +76685,7 @@ val = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, val); } while (--sanity > 0); - if (sanity == 0) { + if (DUK_UNLIKELY(sanity == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); } DUK_UNREACHABLE(); @@ -74802,7 +76786,7 @@ /* All internal keys are identified as Symbols. */ str = DUK_TVAL_GET_STRING(tv_x); DUK_ASSERT(str != NULL); - if (DUK_HSTRING_HAS_SYMBOL(str)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(str))) { stridx = DUK_STRIDX_LC_SYMBOL; } else { stridx = DUK_STRIDX_LC_STRING; @@ -74852,67 +76836,112 @@ * * Array index: E5 Section 15.4 * Array length: E5 Section 15.4.5.1 steps 3.c - 3.d (array length write) - * - * duk_js_to_arrayindex_string_helper() computes the array index from - * string contents alone. Depending on options it's only called during - * string intern (and value stored to duk_hstring) or it's called also - * at runtime. */ -DUK_INTERNAL duk_small_int_t duk_js_to_arrayindex_raw_string(const duk_uint8_t *str, duk_uint32_t blen, duk_uarridx_t *out_idx) { - duk_uarridx_t res, new_res; - - if (blen == 0 || blen > 10) { - goto parse_fail; - } - if (str[0] == (duk_uint8_t) '0' && blen > 1) { - goto parse_fail; - } +/* Compure array index from string context, or return a "not array index" + * indicator. + */ +DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_string(const duk_uint8_t *str, duk_uint32_t blen) { + duk_uarridx_t res; - /* Accept 32-bit decimal integers, no leading zeroes, signs, etc. - * Leading zeroes are not accepted (zero index "0" is an exception - * handled above). + /* Only strings with byte length 1-10 can be 32-bit array indices. + * Leading zeroes (except '0' alone), plus/minus signs are not allowed. + * We could do a lot of prechecks here, but since most strings won't + * start with any digits, it's simpler to just parse the number and + * fail quickly. */ res = 0; - while (blen-- > 0) { - duk_uint8_t c = *str++; - if (c >= (duk_uint8_t) '0' && c <= (duk_uint8_t) '9') { - new_res = res * 10 + (duk_uint32_t) (c - (duk_uint8_t) '0'); - if (new_res < res) { - /* overflow, more than 32 bits -> not an array index */ - goto parse_fail; + if (blen == 0) { + goto parse_fail; + } + do { + duk_uarridx_t dig; + dig = (duk_uarridx_t) (*str++) - DUK_ASC_0; + + if (dig <= 9U) { + /* Careful overflow handling. When multiplying by 10: + * - 0x19999998 x 10 = 0xfffffff0: no overflow, and adding + * 0...9 is safe. + * - 0x19999999 x 10 = 0xfffffffa: no overflow, adding + * 0...5 is safe, 6...9 overflows. + * - 0x1999999a x 10 = 0x100000004: always overflow. + */ + if (DUK_UNLIKELY(res >= 0x19999999UL)) { + if (res >= 0x1999999aUL) { + /* Always overflow. */ + goto parse_fail; + } + DUK_ASSERT(res == 0x19999999UL); + if (dig >= 6U) { + goto parse_fail; + } + res = 0xfffffffaUL + dig; + DUK_ASSERT(res >= 0xfffffffaUL); + DUK_ASSERT_DISABLE(res <= 0xffffffffUL); /* range */ + } else { + res = res * 10U + dig; + if (DUK_UNLIKELY(res == 0)) { + /* If 'res' is 0, previous 'res' must + * have been 0 and we scanned in a zero. + * This is only allowed if blen == 1, + * i.e. the exact string '0'. + */ + if (blen == (duk_uint32_t) 1) { + return 0; + } + goto parse_fail; + } } - res = new_res; } else { + /* Because 'dig' is unsigned, catches both values + * above '9' and below '0'. + */ goto parse_fail; } - } + } while (--blen > 0); - *out_idx = res; - return 1; + return res; parse_fail: - *out_idx = DUK_HSTRING_NO_ARRAY_INDEX; - return 0; + return DUK_HSTRING_NO_ARRAY_INDEX; } -/* Called by duk_hstring.h macros */ -DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h) { +#if !defined(DUK_USE_HSTRING_ARRIDX) +/* Get array index for a string which is known to be an array index. This helper + * is needed when duk_hstring doesn't concretely store the array index, but strings + * are flagged as array indices at intern time. + */ +DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_hstring_fast_known(duk_hstring *h) { + const duk_uint8_t *p; duk_uarridx_t res; - duk_small_int_t rc; + duk_uint8_t t; + + DUK_ASSERT(h != NULL); + DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(h)); + + p = DUK_HSTRING_GET_DATA(h); + res = 0; + for (;;) { + t = *p++; + if (DUK_UNLIKELY(t == 0)) { + /* Scanning to NUL is always safe for interned strings. */ + break; + } + DUK_ASSERT(t >= DUK_ASC_0 && t <= DUK_ASC_9); + res = res * 10U + (t - DUK_ASC_0); + } + return res; +} +DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_hstring_fast(duk_hstring *h) { + DUK_ASSERT(h != NULL); if (!DUK_HSTRING_HAS_ARRIDX(h)) { return DUK_HSTRING_NO_ARRAY_INDEX; } - - rc = duk_js_to_arrayindex_raw_string(DUK_HSTRING_GET_DATA(h), - DUK_HSTRING_GET_BYTELEN(h), - &res); - DUK_UNREF(rc); - DUK_ASSERT(rc != 0); - return res; + return duk_js_to_arrayindex_hstring_fast_known(h); } +#endif /* DUK_USE_HSTRING_ARRIDX */ /* * Identifier access and function closure handling. * @@ -74952,11 +76981,11 @@ */ typedef struct { + duk_hobject *env; duk_hobject *holder; /* for object-bound identifiers */ duk_tval *value; /* for register-bound and declarative env identifiers */ duk_int_t attrs; /* property attributes for identifier (relevant if value != NULL) */ - duk_tval *this_binding; - duk_hobject *env; + duk_bool_t has_this; /* for object-bound identifiers: provide 'this' binding */ } duk__id_lookup_result; /* @@ -75109,7 +77138,7 @@ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&fun_clos->obj)); DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(&fun_clos->obj)); DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(&fun_clos->obj)); - DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(&fun_clos->obj)); + DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(&fun_clos->obj)); /* DUK_HOBJECT_FLAG_ARRAY_PART: don't care */ /* DUK_HOBJECT_FLAG_NEWENV: handled below */ DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&fun_clos->obj)); @@ -75144,7 +77173,7 @@ #if defined(DUK_USE_FUNC_NAME_PROPERTY) if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_clos->obj)) { duk_hobject *proto; - duk_hobject *new_env; + duk_hdecenv *new_env; /* * Named function expression, name needs to be bound @@ -75162,11 +77191,18 @@ } /* -> [ ... closure template env ] */ - new_env = duk_push_object_helper_proto(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), - proto); + 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(ctx, (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, proto); + DUK_HOBJECT_INCREF_ALLOWNULL(thr, proto); + + DUK_ASSERT(new_env->thread == NULL); /* Closed. */ + DUK_ASSERT(new_env->varmap == NULL); /* It's important that duk_xdef_prop() is a 'raw define' so that any * properties in an ancestor are never an issue (they should never be @@ -75185,10 +77221,10 @@ /* [ ... closure template env ] */ - DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, new_env); - DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, new_env); - DUK_HOBJECT_INCREF(thr, new_env); - DUK_HOBJECT_INCREF(thr, new_env); + DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, (duk_hobject *) new_env); + DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, (duk_hobject *) new_env); + DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env); + DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env); duk_pop(ctx); /* [ ... closure template ] */ @@ -75410,10 +77446,11 @@ duk_hobject *func, duk_size_t idx_bottom) { duk_context *ctx = (duk_context *) thr; - duk_hobject *env; + duk_hdecenv *env; duk_hobject *parent; duk_hcompfunc *f; + DUK_ASSERT(ctx != NULL); DUK_ASSERT(thr != NULL); DUK_ASSERT(func != NULL); @@ -75423,25 +77460,44 @@ parent = thr->builtins[DUK_BIDX_GLOBAL_ENV]; } - (void) duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), - -1); /* no prototype, updated below */ - env = duk_known_hobject(ctx, -1); - DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, env, parent); /* parent env is the prototype */ + env = duk_hdecenv_alloc(thr, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV)); + DUK_ASSERT(env != NULL); + duk_push_hobject(ctx, (duk_hobject *) env); + + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL); + DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) env, parent); + DUK_HOBJECT_INCREF_ALLOWNULL(thr, parent); /* parent env is the prototype */ /* open scope information, for compiled functions only */ + DUK_ASSERT(env->thread == NULL); + DUK_ASSERT(env->varmap == NULL); + DUK_ASSERT(env->regbase == 0); if (DUK_HOBJECT_IS_COMPFUNC(func)) { - duk_push_hthread(ctx, thr); - duk_xdef_prop_stridx_short_wec(ctx, -2, DUK_STRIDX_INT_THREAD); - duk_push_hobject(ctx, func); - duk_xdef_prop_stridx_short_wec(ctx, -2, DUK_STRIDX_INT_CALLEE); - duk_push_size_t(ctx, idx_bottom); - duk_xdef_prop_stridx_short_wec(ctx, -2, DUK_STRIDX_INT_REGBASE); + duk_hobject *varmap; + duk_tval *tv; + + tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARMAP(thr)); + if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) { + DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); + varmap = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(varmap != NULL); + env->varmap = varmap; + DUK_HOBJECT_INCREF(thr, varmap); + env->thread = thr; + DUK_HTHREAD_INCREF(thr, thr); + env->regbase = idx_bottom; + } else { + /* If function has no _Varmap, leave the environment closed. */ + DUK_ASSERT(env->thread == NULL); + DUK_ASSERT(env->varmap == NULL); + DUK_ASSERT(env->regbase == 0); + } } - return env; + return (duk_hobject *) env; } DUK_INTERNAL @@ -75450,7 +77506,10 @@ duk_context *ctx = (duk_context *) thr; duk_hobject *func; duk_hobject *env; + duk_size_t act_off; + DUK_ASSERT(act != NULL); + act_off = (duk_size_t) ((duk_uint8_t *) act - (duk_uint8_t *) thr->callstack); func = DUK_ACT_GET_FUNC(act); DUK_ASSERT(func != NULL); DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound functions are never in act 'func' */ @@ -75465,6 +77524,7 @@ env = duk_create_activation_environment_record(thr, func, act->idx_bottom); DUK_ASSERT(env != NULL); + act = (duk_activation *) (void *) ((duk_uint8_t *) thr->callstack + act_off); DUK_DDD(DUK_DDDPRINT("created delayed fresh env: %!ipO", (duk_heaphdr *) env)); #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) @@ -75489,156 +77549,103 @@ * Closing environment records. * * The environment record MUST be closed with the thread where its activation - * is. In other words (if 'env' is open): - * - * - 'thr' must match _env.thread - * - 'func' must match _env.callee - * - 'regbase' must match _env.regbase - * - * These are not looked up from the env to minimize code size. - * - * XXX: should access the own properties directly instead of using the API + * is; i.e. if 'env' is open, 'thr' must match env->thread, and the regbase + * and varmap must still be valid. On entry, 'env' must be reachable. */ -DUK_INTERNAL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env, duk_hobject *func, duk_size_t regbase) { +DUK_INTERNAL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env) { duk_context *ctx = (duk_context *) thr; duk_uint_fast32_t i; + duk_hobject *varmap; + duk_hstring *key; + duk_tval *tv; + duk_uint_t regnum; DUK_ASSERT(thr != NULL); DUK_ASSERT(env != NULL); - /* func is NULL for lightfuncs */ - if (!DUK_HOBJECT_IS_DECENV(env) || DUK_HOBJECT_HAS_ENVRECCLOSED(env)) { - DUK_DDD(DUK_DDDPRINT("environment record not a declarative record, " - "or already closed: %!iO", - (duk_heaphdr *) env)); + if (DUK_UNLIKELY(!DUK_HOBJECT_IS_DECENV(env))) { + DUK_DDD(DUK_DDDPRINT("env not a declarative record: %!iO", (duk_heaphdr *) env)); return; } - DUK_DDD(DUK_DDDPRINT("closing environment record: %!iO, func: %!iO, regbase: %ld", - (duk_heaphdr *) env, (duk_heaphdr *) func, (long) regbase)); - - duk_push_hobject(ctx, env); - - /* assertions: env must be closed in the same thread as where it runs */ -#if defined(DUK_USE_ASSERTIONS) - { - /* [... env] */ - - if (duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_CALLEE)) { - DUK_ASSERT(duk_is_object(ctx, -1)); - DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) func); - } - duk_pop(ctx); - - if (duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_THREAD)) { - DUK_ASSERT(duk_is_object(ctx, -1)); - DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) thr); - } - duk_pop(ctx); - - if (duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_REGBASE)) { - DUK_ASSERT(duk_is_number(ctx, -1)); - DUK_ASSERT(duk_get_number(ctx, -1) == (double) regbase); - } - duk_pop(ctx); + varmap = ((duk_hdecenv *) env)->varmap; + if (varmap == NULL) { + DUK_DDD(DUK_DDDPRINT("env already closed: %!iO", (duk_heaphdr *) env)); - /* [... env] */ + return; } -#endif - - if (func != NULL && DUK_HOBJECT_IS_COMPFUNC(func)) { - duk_hobject *varmap; - duk_hstring *key; - duk_tval *tv; - duk_uint_t regnum; - - /* XXX: additional conditions when to close variables? we don't want to do it - * unless the environment may have "escaped" (referenced in a function closure). - * With delayed environments, the existence is probably good enough of a check. - */ - - /* XXX: any way to detect faster whether something needs to be closed? - * We now look up _Callee and then skip the rest. - */ - - /* Note: we rely on the _Varmap having a bunch of nice properties, like: - * - being compacted and unmodified during this process - * - not containing an array part - * - having correct value types - */ - - /* [... env] */ - - if (!duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_CALLEE)) { - DUK_DDD(DUK_DDDPRINT("env has no callee property, nothing to close; re-delete the control properties just in case")); - duk_pop(ctx); - goto skip_varmap; - } - - /* [... env callee] */ - - if (!duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VARMAP)) { - DUK_DDD(DUK_DDDPRINT("callee has no varmap property, nothing to close; delete the control properties")); - duk_pop_2(ctx); - goto skip_varmap; - } - varmap = duk_require_hobject(ctx, -1); - DUK_ASSERT(varmap != NULL); + DUK_ASSERT(((duk_hdecenv *) env)->thread != NULL); + DUK_ASSERT_HDECENV_VALID((duk_hdecenv *) env); - DUK_DDD(DUK_DDDPRINT("varmap: %!O", (duk_heaphdr *) varmap)); + DUK_DDD(DUK_DDDPRINT("closing env: %!iO", (duk_heaphdr *) env)); + DUK_DDD(DUK_DDDPRINT("varmap: %!O", (duk_heaphdr *) varmap)); - /* [... env callee varmap] */ + /* Env must be closed in the same thread as where it runs. */ + DUK_ASSERT(((duk_hdecenv *) env)->thread == thr); - DUK_DDD(DUK_DDDPRINT("copying bound register values, %ld bound regs", (long) DUK_HOBJECT_GET_ENEXT(varmap))); + /* XXX: additional conditions when to close variables? we don't want to do it + * unless the environment may have "escaped" (referenced in a function closure). + * With delayed environments, the existence is probably good enough of a check. + */ - for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) { - key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i); - DUK_ASSERT(key != NULL); /* assume keys are compacted */ + /* Note: we rely on the _Varmap having a bunch of nice properties, like: + * - being compacted and unmodified during this process + * - not containing an array part + * - having correct value types + */ - DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, varmap, i)); /* assume plain values */ + DUK_DDD(DUK_DDDPRINT("copying bound register values, %ld bound regs", (long) DUK_HOBJECT_GET_ENEXT(varmap))); - tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, varmap, i); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); /* assume value is a number */ - regnum = (duk_uint_t) DUK_TVAL_GET_NUMBER(tv); - DUK_ASSERT_DISABLE(regnum >= 0); /* unsigned */ - DUK_ASSERT(regnum < ((duk_hcompfunc *) func)->nregs); /* regnum is sane */ - DUK_ASSERT(thr->valstack + regbase + regnum >= thr->valstack); - DUK_ASSERT(thr->valstack + regbase + regnum < thr->valstack_top); + /* Copy over current variable values from value stack to the + * environment record. The scope object is empty but may + * inherit from another scope which has conflicting names. + */ - /* XXX: slightly awkward */ - duk_push_hstring(ctx, key); - duk_push_tval(ctx, thr->valstack + regbase + regnum); - DUK_DDD(DUK_DDDPRINT("closing identifier '%s' -> reg %ld, value %!T", - (const char *) duk_require_string(ctx, -2), - (long) regnum, - (duk_tval *) duk_get_tval(ctx, -1))); + /* XXX: Do this using a once allocated entry area, no side effects. + * Hash part would need special treatment however (maybe copy, and + * then realloc with hash part if large enough). + */ + for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) { + duk_size_t regbase; - /* [... env callee varmap key val] */ + key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i); + DUK_ASSERT(key != NULL); /* assume keys are compact in _Varmap */ + DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, varmap, i)); /* assume plain values */ - /* if property already exists, overwrites silently */ - duk_xdef_prop(ctx, -5, DUK_PROPDESC_FLAGS_WE); /* writable but not deletable */ - } + tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, varmap, i); + DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (duk_double_t) DUK_UINT32_MAX); /* limits */ +#if defined(DUK_USE_FASTINT) + DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv)); + regnum = (duk_uint_t) DUK_TVAL_GET_FASTINT_U32(tv); +#else + regnum = (duk_uint_t) DUK_TVAL_GET_NUMBER(tv); +#endif - duk_pop_2(ctx); + regbase = ((duk_hdecenv *) env)->regbase; + DUK_ASSERT(thr->valstack + regbase + regnum >= thr->valstack); + DUK_ASSERT(thr->valstack + regbase + regnum < thr->valstack_top); - /* [... env] */ + /* If property already exists, overwrites silently. + * Property is writable, but not deletable (not configurable + * in terms of property attributes). + */ + duk_push_tval(ctx, thr->valstack + regbase + regnum); + DUK_DDD(DUK_DDDPRINT("closing identifier %!O -> reg %ld, value %!T", + (duk_heaphdr *) key, + (long) regnum, + (duk_tval *) duk_get_tval(ctx, -1))); + duk_hobject_define_property_internal(thr, env, key, DUK_PROPDESC_FLAGS_WE); } - skip_varmap: - - /* [... env] */ - - duk_del_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_CALLEE); - duk_del_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_THREAD); - duk_del_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_REGBASE); - - duk_pop(ctx); - - DUK_HOBJECT_SET_ENVRECCLOSED(env); + /* NULL atomically to avoid inconsistent state + side effects. */ + DUK_HOBJECT_DECREF_NORZ(thr, ((duk_hdecenv *) env)->thread); + DUK_HOBJECT_DECREF_NORZ(thr, ((duk_hdecenv *) env)->varmap); + ((duk_hdecenv *) env)->thread = NULL; + ((duk_hdecenv *) env)->varmap = NULL; - DUK_DDD(DUK_DDDPRINT("environment record after being closed: %!O", - (duk_heaphdr *) env)); + DUK_DDD(DUK_DDDPRINT("env after closing: %!O", (duk_heaphdr *) env)); } /* @@ -75668,12 +77675,8 @@ DUK_LOCAL duk_bool_t duk__getid_open_decl_env_regs(duk_hthread *thr, duk_hstring *name, - duk_hobject *env, + duk_hdecenv *env, duk__id_lookup_result *out) { - duk_hthread *env_thr; - duk_hobject *env_func; - duk_size_t env_regbase; - duk_hobject *varmap; duk_tval *tv; duk_size_t reg_rel; duk_size_t idx; @@ -75683,69 +77686,39 @@ DUK_ASSERT(env != NULL); DUK_ASSERT(out != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_DECENV(env)); + DUK_ASSERT(DUK_HOBJECT_IS_DECENV((duk_hobject *) env)); + DUK_ASSERT_HDECENV_VALID(env); - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_CALLEE(thr)); - if (!tv) { - /* env is closed, should be missing _Callee, _Thread, _Regbase */ - DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL); - DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL); - DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL); + if (env->thread == NULL) { + /* already closed */ return 0; } + DUK_ASSERT(env->varmap != NULL); - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); - DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_TVAL_GET_OBJECT(tv))); - env_func = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(env_func != NULL); - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env_func, DUK_HTHREAD_STRING_INT_VARMAP(thr)); - if (!tv) { + tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env->varmap, name); + if (DUK_UNLIKELY(tv == NULL)) { return 0; } - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); - varmap = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(varmap != NULL); - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, varmap, name); - if (!tv) { - return 0; - } DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (duk_double_t) DUK_UINT32_MAX); /* limits */ +#if defined(DUK_USE_FASTINT) + DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv)); + reg_rel = (duk_size_t) DUK_TVAL_GET_FASTINT_U32(tv); +#else reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv); +#endif DUK_ASSERT_DISABLE(reg_rel >= 0); /* unsigned */ - DUK_ASSERT(reg_rel < ((duk_hcompfunc *) env_func)->nregs); - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THREAD(thr)); - DUK_ASSERT(tv != NULL); - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); - DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_THREAD(DUK_TVAL_GET_OBJECT(tv))); - env_thr = (duk_hthread *) DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(env_thr != NULL); - - /* Note: env_thr != thr is quite possible and normal, so careful - * with what thread is used for valstack lookup. - */ - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_REGBASE(thr)); - DUK_ASSERT(tv != NULL); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); - env_regbase = (duk_size_t) DUK_TVAL_GET_NUMBER(tv); - idx = env_regbase + reg_rel; - tv = env_thr->valstack + idx; - DUK_ASSERT(tv >= env_thr->valstack && tv < env_thr->valstack_end); /* XXX: more accurate? */ + idx = env->regbase + reg_rel; + tv = env->thread->valstack + idx; + DUK_ASSERT(tv >= env->thread->valstack && tv < env->thread->valstack_end); /* XXX: more accurate? */ out->value = tv; out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */ - out->this_binding = NULL; /* implicit this value always undefined for - * declarative environment records. - */ - out->env = env; + out->env = (duk_hobject *) env; out->holder = NULL; - + out->has_this = 0; return 1; } @@ -75774,6 +77747,7 @@ return 0; } + /* XXX: move varmap to duk_hcompfunc struct field. */ tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARMAP(thr)); if (!tv) { return 0; @@ -75797,12 +77771,9 @@ out->value = tv; out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */ - out->this_binding = NULL; /* implicit this value always undefined for - * declarative environment records. - */ out->env = NULL; out->holder = NULL; - + out->has_this = 0; return 1; } @@ -75814,7 +77785,6 @@ duk_bool_t parents, duk__id_lookup_result *out) { duk_tval *tv; - duk_tval *tv_target; duk_tval tv_name; duk_uint_t sanity; @@ -75855,10 +77825,10 @@ if (duk__getid_activation_regs(thr, name, act, out)) { DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " - "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O " + "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " "(found from register bindings when env=NULL)", (duk_heaphdr *) name, (duk_tval *) out->value, - (long) out->attrs, (duk_tval *) out->this_binding, + (long) out->attrs, (long) out->has_this, (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); return 1; } @@ -75935,37 +77905,30 @@ * register-bound variables. */ - if (DUK_HOBJECT_HAS_ENVRECCLOSED(env)) { - /* already closed */ - goto skip_regs; - } - - if (duk__getid_open_decl_env_regs(thr, name, env, out)) { + DUK_ASSERT_HDECENV_VALID((duk_hdecenv *) env); + if (duk__getid_open_decl_env_regs(thr, name, (duk_hdecenv *) env, out)) { DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " - "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O " + "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " "(declarative environment record, scope open, found in regs)", (duk_heaphdr *) name, (duk_tval *) out->value, - (long) out->attrs, (duk_tval *) out->this_binding, + (long) out->attrs, (long) out->has_this, (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); return 1; } - skip_regs: tv = duk_hobject_find_existing_entry_tval_ptr_and_attrs(thr->heap, env, name, &attrs); if (tv) { out->value = tv; out->attrs = attrs; - out->this_binding = NULL; /* implicit this value always undefined for - * declarative environment records. - */ out->env = env; out->holder = env; + out->has_this = 0; DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " - "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O " + "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " "(declarative environment record, found in properties)", (duk_heaphdr *) name, (duk_tval *) out->value, - (long) out->attrs, (duk_tval *) out->this_binding, + (long) out->attrs, (long) out->has_this, (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); return 1; } @@ -75988,11 +77951,9 @@ duk_bool_t found; DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV); + DUK_ASSERT_HOBJENV_VALID((duk_hobjenv *) env); - tv_target = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_TARGET(thr)); - DUK_ASSERT(tv_target != NULL); - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_target)); - target = DUK_TVAL_GET_OBJECT(tv_target); + target = ((duk_hobjenv *) env)->target; DUK_ASSERT(target != NULL); /* Target may be a Proxy or property may be an accessor, so we must @@ -76003,10 +77964,13 @@ */ if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(target)) { + duk_tval tv_target_tmp; + DUK_ASSERT(name != NULL); DUK_TVAL_SET_STRING(&tv_name, name); + DUK_TVAL_SET_OBJECT(&tv_target_tmp, target); - found = duk_hobject_hasprop(thr, tv_target, &tv_name); + found = duk_hobject_hasprop(thr, &tv_target_tmp, &tv_name); } else { /* XXX: duk_hobject_hasprop() would be correct for * non-Proxy objects too, but it is about ~20-25% @@ -76019,16 +77983,15 @@ if (found) { out->value = NULL; /* can't get value, may be accessor */ out->attrs = 0; /* irrelevant when out->value == NULL */ - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THIS(thr)); - out->this_binding = tv; /* may be NULL */ out->env = env; out->holder = target; + out->has_this = ((duk_hobjenv *) env)->has_this; DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " - "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O " + "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " "(object environment record)", (duk_heaphdr *) name, (duk_tval *) out->value, - (long) out->attrs, (duk_tval *) out->this_binding, + (long) out->attrs, (long) out->has_this, (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); return 1; } @@ -76040,11 +78003,11 @@ goto fail_not_found; } - if (sanity-- == 0) { + if (DUK_UNLIKELY(sanity-- == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); } env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env); - }; + } /* * Not found (even in global object) @@ -76151,29 +78114,27 @@ parents = 1; /* follow parent chain */ if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) { if (ref.value) { - DUK_ASSERT(ref.this_binding == NULL); /* always for register bindings */ duk_push_tval(ctx, ref.value); duk_push_undefined(ctx); } else { DUK_ASSERT(ref.holder != NULL); - /* Note: getprop may invoke any getter and invalidate any - * duk_tval pointers, so this must be done first. + /* ref.holder is safe across the getprop call (even + * with side effects) because 'env' is reachable and + * ref.holder is a direct heap pointer. */ - if (ref.this_binding) { - duk_push_tval(ctx, ref.this_binding); - } else { - duk_push_undefined(ctx); - } - DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder); DUK_TVAL_SET_STRING(&tv_tmp_key, name); - (void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key); /* [this value] */ + (void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key); /* [value] */ - /* ref.value, ref.this.binding invalidated here by getprop call */ + if (ref.has_this) { + duk_push_hobject(ctx, ref.holder); + } else { + duk_push_undefined(ctx); + } - duk_insert(ctx, -2); /* [this value] -> [value this] */ + /* [value this] */ } return 1; @@ -76276,13 +78237,11 @@ */ duk_tval *tv_val; - DUK_ASSERT(ref.this_binding == NULL); /* always for register bindings */ - tv_val = ref.value; DUK_ASSERT(tv_val != NULL); DUK_TVAL_SET_TVAL_UPDREF(thr, tv_val, val); /* side effects */ - /* ref.value and ref.this_binding invalidated here */ + /* ref.value invalidated here */ } else { DUK_ASSERT(ref.holder != NULL); @@ -76290,7 +78249,7 @@ DUK_TVAL_SET_STRING(&tv_tmp_key, name); (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, strict); - /* ref.value and ref.this_binding invalidated here */ + /* ref.value invalidated here */ } return; @@ -76663,14 +78622,11 @@ */ if (DUK_HOBJECT_IS_DECENV(env)) { + DUK_ASSERT_HDECENV_VALID((duk_hdecenv *) env); holder = env; } else { - DUK_ASSERT(DUK_HOBJECT_IS_OBJENV(env)); - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_TARGET(thr)); - DUK_ASSERT(tv != NULL); - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); - holder = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT_HOBJENV_VALID((duk_hobjenv *) env); + holder = ((duk_hobjenv *) env)->target; DUK_ASSERT(holder != NULL); } @@ -76712,6 +78668,10 @@ duk_bool_t is_func_decl) { duk_hobject *env; duk_tval tv_val_copy; + duk_size_t act_off; + + DUK_ASSERT(act != NULL); + act_off = (duk_size_t) ((duk_uint8_t *) act - (duk_uint8_t *) thr->callstack); /* * Make a value copy of the input val. This ensures that @@ -76728,6 +78688,7 @@ if (!act->var_env) { DUK_ASSERT(act->lex_env == NULL); duk_js_init_activation_environment_records_delayed(thr, act); + act = (duk_activation *) (void *) ((duk_uint8_t *) thr->callstack + act_off); } DUK_ASSERT(act->lex_env != NULL); DUK_ASSERT(act->var_env != NULL); @@ -77484,6 +79445,68 @@ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE); } +/* Parse legacy octal escape of the form \N{1,3}, e.g. \0, \5, \0377. Maximum + * allowed value is \0377 (U+00FF), longest match is used. Used for both string + * RegExp octal escape parsing. Window[0] must be the slash '\' and the first + * digit must already be validated to be in [0-9] by the caller. + */ +DUK_LOCAL duk_codepoint_t duk__lexer_parse_legacy_octal(duk_lexer_ctx *lex_ctx, duk_small_int_t *out_adv, duk_bool_t reject_annex_b) { + duk_codepoint_t cp; + duk_small_uint_t lookup_idx; + duk_small_int_t adv; + duk_codepoint_t tmp; + + DUK_ASSERT(out_adv != NULL); + DUK_ASSERT(DUK__LOOKUP(lex_ctx, 0) == DUK_ASC_BACKSLASH); + DUK_ASSERT(DUK__LOOKUP(lex_ctx, 1) >= DUK_ASC_0 && DUK__LOOKUP(lex_ctx, 1) <= DUK_ASC_9); + + cp = 0; + for (lookup_idx = 1; lookup_idx <= 3; lookup_idx++) { + DUK_DDD(DUK_DDDPRINT("lookup_idx=%ld, cp=%ld", (long) lookup_idx, (long) cp)); + tmp = DUK__LOOKUP(lex_ctx, lookup_idx); + if (tmp < DUK_ASC_0 || tmp > DUK_ASC_7) { + /* No more valid digits. */ + break; + } + tmp = (cp << 3) + (tmp - DUK_ASC_0); + if (tmp > 0xff) { + /* Three digit octal escapes above \377 (= 0xff) + * are not allowed. + */ + break; + } + cp = tmp; + } + DUK_DDD(DUK_DDDPRINT("final lookup_idx=%ld, cp=%ld", (long) lookup_idx, (long) cp)); + + adv = lookup_idx; + if (lookup_idx == 1) { + DUK_DDD(DUK_DDDPRINT("\\8 or \\9 -> treat as literal, accept in strict mode too")); + DUK_ASSERT(tmp == DUK_ASC_8 || tmp == DUK_ASC_9); + cp = tmp; + adv++; /* correction to above, eat offending character */ + } else if (lookup_idx == 2 && cp == 0) { + /* Note: 'foo\0bar' is OK in strict mode, but 'foo\00bar' is not. + * It won't be interpreted as 'foo\u{0}0bar' but as a SyntaxError. + */ + DUK_DDD(DUK_DDDPRINT("\\0 -> accept in strict mode too")); + } else { + /* This clause also handles non-shortest zero, e.g. \00. */ + if (reject_annex_b) { + DUK_DDD(DUK_DDDPRINT("non-zero octal literal %ld -> reject in strict-mode", (long) cp)); + cp = -1; + } else { + DUK_DDD(DUK_DDDPRINT("non-zero octal literal %ld -> accepted", (long) cp)); + DUK_ASSERT(cp >= 0 && cp <= 0xff); + } + } + + *out_adv = adv; + + DUK_ASSERT((cp >= 0 && cp <= 0xff) || (cp == -1 && reject_annex_b)); + return cp; +} + /* XXX: move strict mode to lex_ctx? */ DUK_LOCAL void duk__lexer_parse_string_literal(duk_lexer_ctx *lex_ctx, duk_token *out_token, duk_small_int_t quote, duk_bool_t strict_mode) { duk_small_int_t adv; @@ -77569,46 +79592,9 @@ * Parse octal (up to 3 digits) from the lookup window. */ - duk_codepoint_t tmp; - duk_small_uint_t lookup_idx; - - emitcp = 0; - for (lookup_idx = 1; lookup_idx <= 3; lookup_idx++) { - DUK_DDD(DUK_DDDPRINT("lookup_idx=%ld, emitcp=%ld", (long) lookup_idx, (long) emitcp)); - tmp = DUK__LOOKUP(lex_ctx, lookup_idx); - if (tmp < DUK_ASC_0 || tmp > DUK_ASC_7) { - /* No more valid digits. */ - break; - } - tmp = (emitcp << 3) + (tmp - DUK_ASC_0); - if (tmp > 0xff) { - /* Three digit octal escapes above \377 (= 0xff) - * are not allowed. - */ - break; - } - emitcp = tmp; - } - DUK_DDD(DUK_DDDPRINT("final lookup_idx=%ld, emitcp=%ld", (long) lookup_idx, (long) emitcp)); - - adv = lookup_idx; - if (lookup_idx == 1) { - /* \8 or \9 -> treat as literal, accept also - * in strict mode. - */ - DUK_DDD(DUK_DDDPRINT("\\8 or \\9 -> treat as literal, accept in strict mode too")); - emitcp = x; - adv++; /* correction to above, eat offending character */ - } else if (lookup_idx == 2 && emitcp == 0) { - /* Zero escape, also allowed in non-strict mode. */ - DUK_DDD(DUK_DDDPRINT("\\0 -> accept in strict mode too")); - } else { - /* Valid octal, only accept in non-strict mode. */ - DUK_DDD(DUK_DDDPRINT("octal literal %ld -> accept only in non-strict-mode", (long) emitcp)); - DUK_ASSERT(emitcp >= 0 && emitcp <= 0xff); - if (strict_mode) { - goto fail_escape; - } + emitcp = duk__lexer_parse_legacy_octal(lex_ctx, &adv, strict_mode /*reject_annex_b*/); + if (emitcp < 0) { + goto fail_escape; } } else if (x < 0) { goto fail_unterminated; @@ -77659,6 +79645,19 @@ return; } +/* Skip to end-of-line (or end-of-file), used for single line comments. */ +DUK_LOCAL void duk__lexer_skip_to_endofline(duk_lexer_ctx *lex_ctx) { + for (;;) { + duk_codepoint_t x; + + x = DUK__L0(); + if (x < 0 || duk_unicode_is_line_terminator(x)) { + break; + } + DUK__ADVANCECHARS(lex_ctx, 1); + } +} + /* * Parse Ecmascript source InputElementDiv or InputElementRegExp * (E5 Section 7), skipping whitespace, comments, and line terminators. @@ -77797,6 +79796,17 @@ DUK__ADVANCECHARS(lex_ctx, 1); got_lineterm = 1; goto restart_lineupdate; +#if defined(DUK_USE_SHEBANG_COMMENTS) + case DUK_ASC_HASH: /* '#' */ + if (DUK__L1() == DUK_ASC_EXCLAMATION && lex_ctx->window[0].offset == 0 && + (lex_ctx->flags & DUK_COMPILE_SHEBANG)) { + /* "Shebang" comment ('#! ...') on first line. */ + /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but not necessary */ + duk__lexer_skip_to_endofline(lex_ctx); + goto restart; /* line terminator will be handled on next round */ + } + goto fail_token; +#endif /* DUK_USE_SHEBANG_COMMENTS */ case DUK_ASC_SLASH: /* '/' */ if (DUK__L1() == DUK_ASC_SLASH) { /* @@ -77804,14 +79814,8 @@ * code point). */ - /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but it unnecessary */ - for (;;) { - x = DUK__L0(); - if (x < 0 || duk_unicode_is_line_terminator(x)) { - break; - } - DUK__ADVANCECHARS(lex_ctx, 1); - } + /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but not necessary */ + duk__lexer_skip_to_endofline(lex_ctx); goto restart; /* line terminator will be handled on next round */ } else if (DUK__L1() == DUK_ASC_STAR) { /* @@ -77996,6 +80000,18 @@ advtok = DUK__ADVTOK(1, DUK_TOK_COMMA); break; case DUK_ASC_LANGLE: /* '<' */ +#if defined(DUK_USE_HTML_COMMENTS) + if (DUK__L1() == DUK_ASC_EXCLAMATION && DUK__L2() == DUK_ASC_MINUS && DUK__L3() == DUK_ASC_MINUS) { + /* + * ES6: B.1.3, handle "" SingleLineHTMLCloseComment + * Only allowed: + * - on new line + * - preceded only by whitespace + * - preceded by end of multiline comment and optional whitespace + * + * Since whitespace generates no tokens, and multiline comments + * are treated as a line ending, consulting `got_lineterm` is + * sufficient to test for these three options. + */ + + /* DUK__ADVANCECHARS(lex_ctx, 3) would be correct here, but not necessary */ + duk__lexer_skip_to_endofline(lex_ctx); + goto restart; /* line terminator will be handled on next round */ + } else +#endif /* DUK_USE_HTML_COMMENTS */ if (DUK__L1() == DUK_ASC_MINUS) { advtok = DUK__ADVTOK(2, DUK_TOK_DECREMENT); } else if (DUK__L1() == DUK_ASC_EQUALS) { @@ -78760,6 +80795,8 @@ } else if (DUK__L2() == DUK_ASC_COLON) { /* (?: */ advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_START_NONCAPTURE_GROUP); + } else { + goto fail_group; } } else { /* ( */ @@ -78827,6 +80864,10 @@ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_ESCAPE); return; + fail_group: + DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_GROUP); + return; + #if !defined(DUK_USE_ES6_REGEXP_SYNTAX) fail_invalid_char: DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_CHARACTER); @@ -78903,7 +80944,7 @@ DUK__ADVANCECHARS(lex_ctx, 1); /* eat ']' before finishing */ break; } else if (x == DUK_ASC_MINUS) { - if (start >= 0 && !dash && DUK__L0() != DUK_ASC_RBRACKET) { + if (start >= 0 && !dash && DUK__L1() != DUK_ASC_RBRACKET) { /* '-' as a range indicator */ dash = 1; continue; @@ -79000,12 +81041,24 @@ sizeof(duk_unicode_re_ranges_not_wordchar) / sizeof(duk_uint16_t)); ch = -1; } else if (DUK__ISDIGIT(x)) { - /* DecimalEscape, only \0 is allowed, no leading zeroes are allowed */ + /* DecimalEscape, only \0 is allowed, no leading + * zeroes are allowed. + * + * ES2015 Annex B also allows (maximal match) legacy + * octal escapes up to \377 and \8 and \9 are + * accepted as literal '8' and '9', also in strict mode. + */ + +#if defined(DUK_USE_ES6_REGEXP_SYNTAX) + ch = duk__lexer_parse_legacy_octal(lex_ctx, &adv, 0 /*reject_annex_b*/); + DUK_ASSERT(ch >= 0); /* no rejections */ +#else if (x == DUK_ASC_0 && !DUK__ISDIGIT(DUK__L2())) { ch = 0x0000; } else { goto fail_escape; } +#endif #if defined(DUK_USE_ES6_REGEXP_SYNTAX) } else if (x >= 0) { /* IdentityEscape: ES2015 Annex B allows almost all @@ -82248,34 +84301,34 @@ switch (c) { case (duk_uint8_t) 'g': { if (flags & DUK_RE_FLAG_GLOBAL) { - goto error; + goto flags_error; } flags |= DUK_RE_FLAG_GLOBAL; break; } case (duk_uint8_t) 'i': { if (flags & DUK_RE_FLAG_IGNORE_CASE) { - goto error; + goto flags_error; } flags |= DUK_RE_FLAG_IGNORE_CASE; break; } case (duk_uint8_t) 'm': { if (flags & DUK_RE_FLAG_MULTILINE) { - goto error; + goto flags_error; } flags |= DUK_RE_FLAG_MULTILINE; break; } default: { - goto error; + goto flags_error; } } } return flags; - error: + flags_error: DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_REGEXP_FLAGS); return 0; /* never here */ } @@ -83345,6 +85398,7 @@ char_offset = (duk_uint32_t) 0; } + DUK_ASSERT(char_offset <= DUK_HSTRING_GET_CHARLEN(h_input)); sp = re_ctx.input + duk_heap_strcache_offset_char2byte(thr, h_input, char_offset); /* @@ -90520,8 +92574,7 @@ } /* Decode a one-bit flag, and if set, decode a value of 'bits', otherwise return - * default value. Return value is signed so that negative marker value can be - * used by caller as a "not present" value. + * default value. */ DUK_INTERNAL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value) { if (duk_bd_decode_flag(ctx)) { @@ -90531,6 +92584,11 @@ } } +/* Signed variant, allows negative marker value. */ +DUK_INTERNAL duk_int32_t duk_bd_decode_flagged_signed(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value) { + return (duk_int32_t) duk_bd_decode_flagged(ctx, bits, (duk_uint32_t) def_value); +} + /* Shared varint encoding. Match dukutil.py BitEncode.varuint(). */ DUK_INTERNAL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx) { duk_small_uint_t t; @@ -90730,7 +92788,7 @@ curr_off = (duk_size_t) (bw_ctx->p - bw_ctx->p_base); add_sz = (curr_off >> DUK_BW_SPARE_SHIFT) + DUK_BW_SPARE_ADD; new_sz = curr_off + sz + add_sz; - if (new_sz < curr_off) { + if (DUK_UNLIKELY(new_sz < curr_off)) { /* overflow */ DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG); return NULL; /* not reachable */ diff -Nru duktape-2.0.0/src-noline/duktape.h duktape-2.1.1/src-noline/duktape.h --- duktape-2.0.0/src-noline/duktape.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-noline/duktape.h 2017-07-28 22:05:08.000000000 +0000 @@ -1,13 +1,13 @@ /* - * Duktape public API for Duktape 2.0.0. + * Duktape public API for Duktape 2.1.1. * - * See the API reference for documentation on call semantics. - * The exposed API is inside the DUK_API_PUBLIC_H_INCLUDED - * include guard. Other parts of the header are Duktape - * internal and related to platform/compiler/feature detection. + * See the API reference for documentation on call semantics. The exposed, + * supported API is between the "BEGIN PUBLIC API" and "END PUBLIC API" + * comments. Other parts of the header are Duktape internal and related to + * e.g. platform/compiler/feature detection. * - * Git commit 4180966c47d6d87106008dd4338de8d507c8072b (v2.0.0). - * Git branch master. + * Git commit 9c8fba6392d1913cb5359be7b8f386fa3cdd8b4d (v2.1.1). + * Git branch v2.1-maintenance. * * See Duktape AUTHORS.rst and LICENSE.txt for copyright and * licensing information. @@ -87,6 +87,8 @@ * * Brett Vickers (https://github.com/beevik) * * Dominik Okwieka (https://github.com/okitec) * * Remko Tron\u00e7on (https://el-tramo.be) + * * Romero Malaquias (rbsm@ic.ufal.br) + * * Michael Drake * * Other contributions * =================== @@ -135,18 +137,38 @@ #define DUK_SINGLE_FILE -/* External duk_config.h provides platform/compiler/OS dependent - * typedefs and macros, and DUK_USE_xxx config options so that - * the rest of Duktape doesn't need to do any feature detection. +/* + * BEGIN PUBLIC API */ -#include "duk_config.h" /* - * BEGIN PUBLIC API + * Version and Git commit identification + */ + +/* Duktape version, (major * 10000) + (minor * 100) + patch. Allows C code + * to #if (DUK_VERSION >= NNN) against Duktape API version. The same value + * is also available to Ecmascript code in Duktape.version. Unofficial + * development snapshots have 99 for patch level (e.g. 0.10.99 would be a + * development version after 0.10.0 but before the next official release). */ +#define DUK_VERSION 20101L -#if !defined(DUK_API_PUBLIC_H_INCLUDED) -#define DUK_API_PUBLIC_H_INCLUDED +/* Git commit, describe, and branch for Duktape build. Useful for + * non-official snapshot builds so that application code can easily log + * which Duktape snapshot was used. Not available in the Ecmascript + * environment. + */ +#define DUK_GIT_COMMIT "9c8fba6392d1913cb5359be7b8f386fa3cdd8b4d" +#define DUK_GIT_DESCRIBE "v2.1.1" +#define DUK_GIT_BRANCH "v2.1-maintenance" + +/* External duk_config.h provides platform/compiler/OS dependent + * typedefs and macros, and DUK_USE_xxx config options so that + * the rest of Duktape doesn't need to do any feature detection. + * DUK_VERSION is defined before including so that configuration + * snippets can react to it. + */ +#include "duk_config.h" /* * Avoid C++ name mangling @@ -247,23 +269,6 @@ * Constants */ -/* Duktape version, (major * 10000) + (minor * 100) + patch. Allows C code - * to #if (DUK_VERSION >= NNN) against Duktape API version. The same value - * is also available to Ecmascript code in Duktape.version. Unofficial - * development snapshots have 99 for patch level (e.g. 0.10.99 would be a - * development version after 0.10.0 but before the next official release). - */ -#define DUK_VERSION 20000L - -/* Git commit, describe, and branch for Duktape build. Useful for - * non-official snapshot builds so that application code can easily log - * which Duktape snapshot was used. Not available in the Ecmascript - * environment. - */ -#define DUK_GIT_COMMIT "4180966c47d6d87106008dd4338de8d507c8072b" -#define DUK_GIT_DESCRIBE "v2.0.0" -#define DUK_GIT_BRANCH "master" - /* Duktape debug protocol version used by this build. */ #define DUK_DEBUG_PROTOCOL_VERSION 2 @@ -334,11 +339,13 @@ #define DUK_COMPILE_EVAL (1 << 3) /* compile eval code (instead of global code) */ #define DUK_COMPILE_FUNCTION (1 << 4) /* compile function code (instead of global code) */ #define DUK_COMPILE_STRICT (1 << 5) /* use strict (outer) context for global, eval, or function code */ -#define DUK_COMPILE_SAFE (1 << 6) /* (internal) catch compilation errors */ -#define DUK_COMPILE_NORESULT (1 << 7) /* (internal) omit eval result */ -#define DUK_COMPILE_NOSOURCE (1 << 8) /* (internal) no source string on stack */ -#define DUK_COMPILE_STRLEN (1 << 9) /* (internal) take strlen() of src_buffer (avoids double evaluation in macro) */ -#define DUK_COMPILE_NOFILENAME (1 << 10) /* (internal) no filename on stack */ +#define DUK_COMPILE_SHEBANG (1 << 6) /* allow shebang ('#! ...') comment on first line of source */ +#define DUK_COMPILE_SAFE (1 << 7) /* (internal) catch compilation errors */ +#define DUK_COMPILE_NORESULT (1 << 8) /* (internal) omit eval result */ +#define DUK_COMPILE_NOSOURCE (1 << 9) /* (internal) no source string on stack */ +#define DUK_COMPILE_STRLEN (1 << 10) /* (internal) take strlen() of src_buffer (avoids double evaluation in macro) */ +#define DUK_COMPILE_NOFILENAME (1 << 11) /* (internal) no filename on stack */ +#define DUK_COMPILE_FUNCEXPR (1 << 12) /* (internal) source is a function expression (used for Function constructor) */ /* Flags for duk_def_prop() and its variants */ #define DUK_DEFPROP_WRITABLE (1 << 0) /* set writable (effective if DUK_DEFPROP_HAVE_WRITABLE set) */ @@ -445,9 +452,9 @@ DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_fatal_raw(duk_context *ctx, const char *err_msg)); #define duk_fatal(ctx,err_msg) \ (duk_fatal_raw((ctx), (err_msg)), (duk_ret_t) 0) +DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...)); #if defined(DUK_API_VARIADIC_MACROS) -DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...)); #define duk_error(ctx,err_code,...) \ (duk_error_raw((ctx), (duk_errcode_t) (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) #define duk_generic_error(ctx,...) \ @@ -516,6 +523,7 @@ #endif /* DUK_API_VARIADIC_MACROS */ DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap)); + #define duk_error_va(ctx,err_code,fmt,ap) \ (duk_error_va_raw((ctx), (duk_errcode_t) (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) #define duk_generic_error_va(ctx,fmt,ap) \ @@ -663,19 +671,18 @@ #define duk_push_external_buffer(ctx) \ ((void) duk_push_buffer_raw((ctx), 0, DUK_BUF_FLAG_DYNAMIC | DUK_BUF_FLAG_EXTERNAL)) -#define DUK_BUFOBJ_CREATE_ARRBUF (1 << 4) /* internal flag: create backing ArrayBuffer; keep in one byte */ #define DUK_BUFOBJ_ARRAYBUFFER 0 -#define DUK_BUFOBJ_NODEJS_BUFFER (1 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_DATAVIEW (2 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_INT8ARRAY (3 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_UINT8ARRAY (4 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_UINT8CLAMPEDARRAY (5 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_INT16ARRAY (6 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_UINT16ARRAY (7 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_INT32ARRAY (8 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_UINT32ARRAY (9 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_FLOAT32ARRAY (10 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_FLOAT64ARRAY (11 | DUK_BUFOBJ_CREATE_ARRBUF) +#define DUK_BUFOBJ_NODEJS_BUFFER 1 +#define DUK_BUFOBJ_DATAVIEW 2 +#define DUK_BUFOBJ_INT8ARRAY 3 +#define DUK_BUFOBJ_UINT8ARRAY 4 +#define DUK_BUFOBJ_UINT8CLAMPEDARRAY 5 +#define DUK_BUFOBJ_INT16ARRAY 6 +#define DUK_BUFOBJ_UINT16ARRAY 7 +#define DUK_BUFOBJ_INT32ARRAY 8 +#define DUK_BUFOBJ_UINT32ARRAY 9 +#define DUK_BUFOBJ_FLOAT32ARRAY 10 +#define DUK_BUFOBJ_FLOAT64ARRAY 11 DUK_EXTERNAL_DECL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags); @@ -789,8 +796,43 @@ DUK_EXTERNAL_DECL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t idx); DUK_EXTERNAL_DECL duk_context *duk_get_context(duk_context *ctx, duk_idx_t idx); DUK_EXTERNAL_DECL void *duk_get_heapptr(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t idx, duk_size_t len); + +/* + * Get-with-explicit default operations: like get operations but with an + * explicit default value. + */ + +DUK_EXTERNAL_DECL duk_bool_t duk_get_boolean_default(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value); +DUK_EXTERNAL_DECL duk_double_t duk_get_number_default(duk_context *ctx, duk_idx_t idx, duk_double_t def_value); +DUK_EXTERNAL_DECL duk_int_t duk_get_int_default(duk_context *ctx, duk_idx_t idx, duk_int_t def_value); +DUK_EXTERNAL_DECL duk_uint_t duk_get_uint_default(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value); +DUK_EXTERNAL_DECL const char *duk_get_string_default(duk_context *ctx, duk_idx_t idx, const char *def_value); +DUK_EXTERNAL_DECL const char *duk_get_lstring_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len); +DUK_EXTERNAL_DECL void *duk_get_buffer_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len); +DUK_EXTERNAL_DECL void *duk_get_buffer_data_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len); +DUK_EXTERNAL_DECL void *duk_get_pointer_default(duk_context *ctx, duk_idx_t idx, void *def_value); +DUK_EXTERNAL_DECL duk_c_function duk_get_c_function_default(duk_context *ctx, duk_idx_t idx, duk_c_function def_value); +DUK_EXTERNAL_DECL duk_context *duk_get_context_default(duk_context *ctx, duk_idx_t idx, duk_context *def_value); +DUK_EXTERNAL_DECL void *duk_get_heapptr_default(duk_context *ctx, duk_idx_t idx, void *def_value); + +/* + * Opt operations: like require operations but with an explicit default value + * when value is undefined or index is invalid, null and non-matching types + * cause a TypeError. + */ + +DUK_EXTERNAL_DECL duk_bool_t duk_opt_boolean(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value); +DUK_EXTERNAL_DECL duk_double_t duk_opt_number(duk_context *ctx, duk_idx_t idx, duk_double_t def_value); +DUK_EXTERNAL_DECL duk_int_t duk_opt_int(duk_context *ctx, duk_idx_t idx, duk_int_t def_value); +DUK_EXTERNAL_DECL duk_uint_t duk_opt_uint(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value); +DUK_EXTERNAL_DECL const char *duk_opt_string(duk_context *ctx, duk_idx_t idx, const char *def_ptr); +DUK_EXTERNAL_DECL const char *duk_opt_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len); +DUK_EXTERNAL_DECL void *duk_opt_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size); +DUK_EXTERNAL_DECL void *duk_opt_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size); +DUK_EXTERNAL_DECL void *duk_opt_pointer(duk_context *ctx, duk_idx_t idx, void *def_value); +DUK_EXTERNAL_DECL duk_c_function duk_opt_c_function(duk_context *ctx, duk_idx_t idx, duk_c_function def_value); +DUK_EXTERNAL_DECL duk_context *duk_opt_context(duk_context *ctx, duk_idx_t idx, duk_context *def_value); +DUK_EXTERNAL_DECL void *duk_opt_heapptr(duk_context *ctx, duk_idx_t idx, void *def_value); /* * Require operations: no coercion, throw error if index or type @@ -869,6 +911,17 @@ duk_safe_to_lstring((ctx), (idx), NULL) /* + * Value length + */ + +DUK_EXTERNAL_DECL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t idx, duk_size_t len); +#if 0 +/* duk_require_length()? */ +/* duk_opt_length()? */ +#endif + +/* * Misc conversion */ @@ -1228,434 +1281,8 @@ } #endif -#endif /* DUK_API_PUBLIC_H_INCLUDED */ - /* * END PUBLIC API */ -/* - * 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/cross endian (e.g. ARM) DUK_USE_DOUBLE_ME - * - * ARM is a special case: ARM double values are in mixed/cross 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. - * - * 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] = 0x000000007ff80000ULL; \ - } while (0) -#define DUK__DBLUNION_IS_NAN_FULL(u) \ - ((((u)->ull[DUK_DBL_IDX_ULL0] & 0x000000007ff00000ULL) == 0x000000007ff00000ULL) && \ - ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0xffffffff000fffffULL) != 0)) -#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x000000007ff80000ULL) -#define DUK__DBLUNION_IS_ANYINF(u) \ - (((u)->ull[DUK_DBL_IDX_ULL0] & 0xffffffff7fffffffULL) == 0x000000007ff00000ULL) -#define DUK__DBLUNION_IS_POSINF(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x000000007ff00000ULL) -#define DUK__DBLUNION_IS_NEGINF(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x00000000fff00000ULL) -#define DUK__DBLUNION_IS_ANYZERO(u) \ - (((u)->ull[DUK_DBL_IDX_ULL0] & 0xffffffff7fffffffULL) == 0x0000000000000000ULL) -#define DUK__DBLUNION_IS_POSZERO(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000000000000ULL) -#define DUK__DBLUNION_IS_NEGZERO(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000080000000ULL) -#else -/* Macros for 64-bit ops + big/little endian doubles. */ -#define DUK__DBLUNION_SET_NAN_FULL(u) do { \ - (u)->ull[DUK_DBL_IDX_ULL0] = 0x7ff8000000000000ULL; \ - } while (0) -#define DUK__DBLUNION_IS_NAN_FULL(u) \ - ((((u)->ull[DUK_DBL_IDX_ULL0] & 0x7ff0000000000000ULL) == 0x7ff0000000000000UL) && \ - ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0x000fffffffffffffULL) != 0)) -#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x7ff8000000000000ULL) -#define DUK__DBLUNION_IS_ANYINF(u) \ - (((u)->ull[DUK_DBL_IDX_ULL0] & 0x7fffffffffffffffULL) == 0x7ff0000000000000ULL) -#define DUK__DBLUNION_IS_POSINF(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x7ff0000000000000ULL) -#define DUK__DBLUNION_IS_NEGINF(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0xfff0000000000000ULL) -#define DUK__DBLUNION_IS_ANYZERO(u) \ - (((u)->ull[DUK_DBL_IDX_ULL0] & 0x7fffffffffffffffULL) == 0x0000000000000000ULL) -#define DUK__DBLUNION_IS_POSZERO(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000000000000ULL) -#define DUK__DBLUNION_IS_NEGZERO(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x8000000000000000ULL) -#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] & 0x8000000000000000ULL) != 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 */ - #endif /* DUKTAPE_H_INCLUDED */ diff -Nru duktape-2.0.0/src-separate/duk_api_bytecode.c duktape-2.1.1/src-separate/duk_api_bytecode.c --- duktape-2.0.0/src-separate/duk_api_bytecode.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_api_bytecode.c 2017-07-28 22:05:08.000000000 +0000 @@ -279,6 +279,7 @@ DUK_RAW_WRITE_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_WRITE_U32_BE(p, tmp32); /* Bytecode instructions: endian conversion needed unless @@ -458,7 +459,7 @@ 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_HAS_THREAD(&h_fun->obj)); + DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(&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)); @@ -584,14 +585,23 @@ * Must create a lexical environment on loading to allow * recursive functions like 'function foo() { foo(); }'. */ - duk_hobject *new_env; + duk_hdecenv *new_env; - new_env = duk_push_object_helper_proto(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), - func_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); - func_env = new_env; + DUK_ASSERT(new_env->thread == NULL); /* Closed. */ + DUK_ASSERT(new_env->varmap == NULL); + DUK_ASSERT(new_env->regbase == 0); + DUK_ASSERT_HDECENV_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(ctx, (duk_hobject *) new_env); duk_dup_m2(ctx); /* -> [ func funcname env funcname ] */ duk_dup(ctx, idx_base); /* -> [ func funcname env funcname func ] */ @@ -648,8 +658,9 @@ /* If _Formals wasn't present in the original function, the list * here will be empty. Same happens if _Formals was present but - * had zero length. We can omit _Formals from the result if its - * length is zero and matches nargs. + * had zero length. We'll omit the _Formals list if it is empty, + * regardless of whether it was present in the original or not, + * this is a workaround for https://github.com/svaarala/duktape/issues/1513. */ duk_push_array(ctx); /* _Formals */ for (arr_idx = 0; ; arr_idx++) { @@ -661,7 +672,16 @@ } duk_put_prop_index(ctx, -2, arr_idx); } - if (arr_idx == 0 && h_fun->nargs == 0) { + if (arr_idx == 0) { + /* Omitting _Formals when the list is empty is technically + * incorrect because the result will differ from the input + * function. This could matter for function templates if: + * _Formals exists, _Formals.length == 0, and nargs > 0. + * This doesn't happen in practice. But if it did, it would + * affect the .length property of function instances created + * from the closure (0 with _Formals present, nargs with + * _Formals absent). + */ duk_pop(ctx); } else { duk_compact_m1(ctx); diff -Nru duktape-2.0.0/src-separate/duk_api_call.c duktape-2.1.1/src-separate/duk_api_call.c --- duktape-2.0.0/src-separate/duk_api_call.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_api_call.c 2017-07-28 22:05:08.000000000 +0000 @@ -44,7 +44,7 @@ DUK_ASSERT(thr != NULL); idx_func = duk_get_top(ctx) - nargs - 1; - if (idx_func < 0 || nargs < 0) { + if (DUK_UNLIKELY(idx_func < 0 || nargs < 0)) { /* note that we can't reliably pop anything here */ DUK_ERROR_TYPE_INVALID_ARGS(thr); } @@ -71,7 +71,7 @@ DUK_ASSERT(thr != NULL); idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */ - if (idx_func < 0 || nargs < 0) { + if (DUK_UNLIKELY(idx_func < 0 || nargs < 0)) { /* note that we can't reliably pop anything here */ DUK_ERROR_TYPE_INVALID_ARGS(thr); } @@ -110,7 +110,7 @@ DUK_ASSERT(thr != NULL); idx_func = duk_get_top(ctx) - nargs - 1; /* must work for nargs <= 0 */ - if (idx_func < 0 || nargs < 0) { + if (DUK_UNLIKELY(idx_func < 0 || nargs < 0)) { /* We can't reliably pop anything here because the stack input * shape is incorrect. So we throw an error; if the caller has * no catch point for this, a fatal error will occur. Another @@ -148,7 +148,7 @@ DUK_ASSERT(thr != NULL); idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */ - if (idx_func < 0 || nargs < 0) { + if (DUK_UNLIKELY(idx_func < 0 || nargs < 0)) { /* See comments in duk_pcall(). */ DUK_ERROR_TYPE_INVALID_ARGS(thr); return DUK_EXEC_ERROR; /* unreachable */ @@ -188,6 +188,7 @@ } DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t nargs) { + duk_hthread *thr = (duk_hthread *) ctx; duk__pcall_prop_args args; /* @@ -199,6 +200,10 @@ args.obj_idx = obj_idx; args.nargs = nargs; + if (DUK_UNLIKELY(nargs < 0)) { + DUK_ERROR_TYPE_INVALID_ARGS(thr); + return DUK_EXEC_ERROR; /* unreachable */ + } /* Inputs: explicit arguments (nargs), +1 for key. If the value stack * does not contain enough args, an error is thrown; this matches @@ -214,7 +219,7 @@ DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(thr != NULL); - if (duk_get_top(ctx) < nargs || nrets < 0) { + if (DUK_UNLIKELY(duk_get_top(ctx) < nargs || nargs < 0 || nrets < 0)) { /* See comments in duk_pcall(). */ DUK_ERROR_TYPE_INVALID_ARGS(thr); return DUK_EXEC_ERROR; /* unreachable */ @@ -279,6 +284,10 @@ /* [... constructor arg1 ... argN] */ + if (DUK_UNLIKELY(nargs < 0)) { + /* note that we can't reliably pop anything here */ + DUK_ERROR_TYPE_INVALID_ARGS(thr); + } idx_cons = duk_require_normalize_index(ctx, -nargs - 1); DUK_DDD(DUK_DDDPRINT("top=%ld, nargs=%ld, idx_cons=%ld", @@ -448,6 +457,7 @@ } DUK_EXTERNAL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs) { + duk_hthread *thr = (duk_hthread *) ctx; duk_int_t rc; DUK_ASSERT_CTX_VALID(ctx); @@ -460,6 +470,11 @@ * wrapper. */ + if (DUK_UNLIKELY(nargs < 0)) { + DUK_ERROR_TYPE_INVALID_ARGS(thr); + return DUK_EXEC_ERROR; /* unreachable */ + } + rc = duk_safe_call(ctx, duk__pnew_helper, (void *) &nargs /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/); return rc; } @@ -472,9 +487,11 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT_DISABLE(thr->callstack_top >= 0); - act = duk_hthread_get_current_activation(thr); - DUK_ASSERT(act != NULL); /* because callstack_top > 0 */ - return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0); + act = thr->callstack_curr; + if (act != NULL) { + return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0); + } + return 0; } /* XXX: Make this obsolete by adding a function flag for rejecting a @@ -503,12 +520,13 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT_DISABLE(thr->callstack_top >= 0); - act = duk_hthread_get_current_activation(thr); - if (act == NULL) { + act = thr->callstack_curr; + if (act != NULL) { + return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0); + } else { /* Strict by default. */ return 1; } - return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0); } /* @@ -524,7 +542,7 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT_DISABLE(thr->callstack_top >= 0); - act = duk_hthread_get_current_activation(thr); + act = thr->callstack_curr; if (act) { func = DUK_ACT_GET_FUNC(act); if (!func) { diff -Nru duktape-2.0.0/src-separate/duk_api_codec.c duktape-2.1.1/src-separate/duk_api_codec.c --- duktape-2.0.0/src-separate/duk_api_codec.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_api_codec.c 2017-07-28 22:05:08.000000000 +0000 @@ -18,7 +18,10 @@ DUK_ASSERT(duk_is_valid_index(ctx, idx)); /* checked by caller */ - ptr = duk_get_buffer_data_raw(ctx, idx, out_len, 0 /*throw_flag*/, &isbuffer); + /* XXX: with def_ptr set to a stack related pointer, isbuffer could + * be removed from the helper? + */ + ptr = duk_get_buffer_data_raw(ctx, idx, out_len, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, &isbuffer); if (isbuffer) { DUK_ASSERT(*out_len == 0 || ptr != NULL); return (const duk_uint8_t *) ptr; @@ -210,13 +213,13 @@ t <<= 6; } else { DUK_ASSERT(x == -1); - goto error; + goto decode_error; } } else { DUK_ASSERT(x >= 0 && x <= 63); if (n_equal > 0) { /* Don't allow actual chars after equal sign. */ - goto error; + goto decode_error; } t = (t << 6) + x; } @@ -242,7 +245,7 @@ /* XX== */ dst -= 2; } else { - goto error; /* invalid padding */ + goto decode_error; /* invalid padding */ } /* Continue parsing after padding, allows concatenated, @@ -266,13 +269,13 @@ * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not * accepted. */ - goto error; + goto decode_error; } *out_dst_final = dst; return 1; - error: + decode_error: return 0; } #else /* DUK_USE_BASE64_FASTPATH */ @@ -314,12 +317,12 @@ /* allow basic ASCII whitespace */ continue; } else { - goto error; + goto decode_error; } if (n_equal > 0) { /* Don't allow mixed padding and actual chars. */ - goto error; + goto decode_error; } t = (t << 6) + y; skip_add: @@ -338,7 +341,7 @@ } else if (n_equal == 2) { dst -= 2; } else { - goto error; /* invalid padding */ + goto decode_error; /* invalid padding */ } /* Here we can choose either to end parsing and ignore @@ -361,13 +364,13 @@ * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not * accepted. */ - goto error; + goto decode_error; } *out_dst_final = dst; return 1; - error: + decode_error: return 0; } #endif /* DUK_USE_BASE64_FASTPATH */ diff -Nru duktape-2.0.0/src-separate/duk_api_compile.c duktape-2.1.1/src-separate/duk_api_compile.c --- duktape-2.0.0/src-separate/duk_api_compile.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_api_compile.c 2017-07-28 22:05:08.000000000 +0000 @@ -13,7 +13,6 @@ /* Eval is just a wrapper now. */ DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) { - duk_uint_t comp_flags; duk_int_t rc; DUK_ASSERT_CTX_VALID(ctx); @@ -27,9 +26,7 @@ /* [ ... source? filename? ] (depends on flags) */ - comp_flags = flags; - comp_flags |= DUK_COMPILE_EVAL; - rc = duk_compile_raw(ctx, src_buffer, src_length, comp_flags); /* may be safe, or non-safe depending on flags */ + rc = duk_compile_raw(ctx, src_buffer, src_length, flags | DUK_COMPILE_EVAL); /* may be safe, or non-safe depending on flags */ /* [ ... closure/error ] */ @@ -62,7 +59,6 @@ duk_hthread *thr = (duk_hthread *) ctx; duk__compile_raw_args *comp_args; duk_uint_t flags; - duk_small_uint_t comp_flags; duk_hcompfunc *h_templ; DUK_ASSERT_CTX_VALID(ctx); @@ -101,22 +97,13 @@ } DUK_ASSERT(comp_args->src_buffer != NULL); - /* XXX: unnecessary translation of flags */ - comp_flags = 0; - if (flags & DUK_COMPILE_EVAL) { - comp_flags |= DUK_JS_COMPILE_FLAG_EVAL; - } if (flags & DUK_COMPILE_FUNCTION) { - comp_flags |= DUK_JS_COMPILE_FLAG_EVAL | - DUK_JS_COMPILE_FLAG_FUNCEXPR; - } - if (flags & DUK_COMPILE_STRICT) { - comp_flags |= DUK_JS_COMPILE_FLAG_STRICT; + flags |= DUK_COMPILE_EVAL | DUK_COMPILE_FUNCEXPR; } /* [ ... source? filename ] */ - duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, comp_flags); + duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, flags); /* [ ... source? func_template ] */ diff -Nru duktape-2.0.0/src-separate/duk_api_debug.c duktape-2.1.1/src-separate/duk_api_debug.c --- duktape-2.0.0/src-separate/duk_api_debug.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_api_debug.c 2017-07-28 22:05:08.000000000 +0000 @@ -84,16 +84,16 @@ /* Start in paused state. */ heap->dbg_processing = 0; - DUK_HEAP_SET_DEBUGGER_PAUSED(heap); - heap->dbg_state_dirty = 1; + heap->dbg_state_dirty = 0; heap->dbg_force_restart = 0; - heap->dbg_step_type = 0; + heap->dbg_step_type = DUK_STEP_TYPE_NONE; heap->dbg_step_thread = NULL; heap->dbg_step_csindex = 0; heap->dbg_step_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. @@ -133,7 +133,7 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->heap != NULL); - if (!DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + if (!duk_debug_is_attached(thr->heap)) { return; } if (thr->callstack_top > 0 || thr->heap->dbg_processing) { @@ -166,7 +166,7 @@ DUK_ERROR_RANGE(thr, "not enough stack values for notify"); return ret; /* unreachable */ } - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + 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(ctx, idx); @@ -179,7 +179,7 @@ * a transport error was not indicated by the transport write * callback. This is not a 100% guarantee of course. */ - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + if (duk_debug_is_attached(thr->heap)) { ret = 1; } } @@ -198,15 +198,19 @@ DUK_D(DUK_DPRINT("application called duk_debugger_pause()")); /* Treat like a debugger statement: ignore when not attached. */ - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { - DUK_HEAP_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; + 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; + } } } diff -Nru duktape-2.0.0/src-separate/duk_api_heap.c duktape-2.1.1/src-separate/duk_api_heap.c --- duktape-2.0.0/src-separate/duk_api_heap.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_api_heap.c 2017-07-28 22:05:08.000000000 +0000 @@ -8,7 +8,7 @@ struct duk_internal_thread_state { duk_ljstate lj; - duk_bool_t handling_error; + duk_bool_t creating_error; duk_hthread *curr_thread; duk_int_t call_recursion_depth; }; @@ -89,14 +89,27 @@ 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(ctx, &lj->value1); duk_push_tval(ctx, &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->handling_error = heap->handling_error; + snapshot->creating_error = heap->creating_error; snapshot->curr_thread = heap->curr_thread; snapshot->call_recursion_depth = heap->call_recursion_depth; @@ -104,7 +117,7 @@ lj->type = DUK_LJ_TYPE_UNKNOWN; DUK_TVAL_SET_UNDEFINED(&lj->value1); DUK_TVAL_SET_UNDEFINED(&lj->value2); - heap->handling_error = 0; + heap->creating_error = 0; heap->curr_thread = NULL; heap->call_recursion_depth = 0; } @@ -119,10 +132,16 @@ 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->handling_error = snapshot->handling_error; + heap->creating_error = snapshot->creating_error; heap->curr_thread = snapshot->curr_thread; heap->call_recursion_depth = snapshot->call_recursion_depth; @@ -134,7 +153,7 @@ duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h_glob; duk_hobject *h_prev_glob; - duk_hobject *h_env; + duk_hobjenv *h_env; duk_hobject *h_prev_env; DUK_D(DUK_DPRINT("replace global object with: %!T", duk_get_tval(ctx, -1))); @@ -161,29 +180,30 @@ * same (initial) built-ins. */ - h_env = duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV), - -1); /* no prototype, updated below */ + 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_dup_m2(ctx); - duk_dup_m3(ctx); - duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); + 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 new_env ] */ + /* [ ... new_glob ] */ h_prev_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; - thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_env; - DUK_HOBJECT_INCREF(thr, h_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 new_env ] */ + /* [ ... new_glob ] */ - duk_pop_2(ctx); + duk_pop(ctx); /* [ ... ] */ } diff -Nru duktape-2.0.0/src-separate/duk_api_inspect.c duktape-2.1.1/src-separate/duk_api_inspect.c --- duktape-2.0.0/src-separate/duk_api_inspect.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_api_inspect.c 2017-07-28 22:05:08.000000000 +0000 @@ -66,18 +66,19 @@ DUK_UNREF(thr); - tv = duk_get_tval_or_unused(ctx, idx); - h = (DUK_TVAL_IS_HEAP_ALLOCATED(tv) ? DUK_TVAL_GET_HEAPHDR(tv) : NULL); - /* 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 */ - duk_push_bare_object(ctx); + tv = duk_get_tval_or_unused(ctx, 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_uint_t) DUK_TVAL_GET_TAG(tv); + duk_push_bare_object(ctx); /* Invalidates 'tv'. */ + tv = NULL; + if (h == NULL) { goto finish; } diff -Nru duktape-2.0.0/src-separate/duk_api_internal.h duktape-2.1.1/src-separate/duk_api_internal.h --- duktape-2.0.0/src-separate/duk_api_internal.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_api_internal.h 2017-07-28 22:05:08.000000000 +0000 @@ -101,7 +101,7 @@ DUK_INTERNAL_DECL duk_hcompfunc *duk_get_hcompfunc(duk_context *ctx, duk_idx_t idx); DUK_INTERNAL_DECL duk_hnatfunc *duk_get_hnatfunc(duk_context *ctx, duk_idx_t idx); -DUK_INTERNAL_DECL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_bool_t throw_flag, duk_bool_t *out_found); +DUK_INTERNAL_DECL void *duk_get_buffer_data_raw(duk_context *ctx, 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_context *ctx, duk_idx_t idx, duk_small_uint_t classnum); @@ -281,6 +281,8 @@ DUK_INTERNAL_DECL duk_idx_t duk_get_top_require_min(duk_context *ctx, duk_idx_t min_top); DUK_INTERNAL_DECL duk_idx_t duk_get_top_index_unsafe(duk_context *ctx); +DUK_INTERNAL_DECL void duk_pop_n_unsafe(duk_context *ctx, duk_idx_t count); +DUK_INTERNAL_DECL void duk_pop_n_nodecref_unsafe(duk_context *ctx, duk_idx_t count); DUK_INTERNAL_DECL void duk_pop_unsafe(duk_context *ctx); DUK_INTERNAL_DECL void duk_compact_m1(duk_context *ctx); diff -Nru duktape-2.0.0/src-separate/duk_api_object.c duktape-2.1.1/src-separate/duk_api_object.c --- duktape-2.0.0/src-separate/duk_api_object.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_api_object.c 2017-07-28 22:05:08.000000000 +0000 @@ -712,9 +712,31 @@ } DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t idx) { + duk_hobject *h; + duk_bool_t callable; + DUK_ASSERT_CTX_VALID(ctx); + h = duk_require_hobject(ctx, idx); /* Get before 'put' so that 'idx' is correct. */ + callable = duk_is_callable(ctx, -1); duk_put_prop_stridx(ctx, idx, DUK_STRIDX_INT_FINALIZER); + + /* In addition to setting the finalizer property, keep a "have + * finalizer" flag in duk_hobject in sync so that refzero can do + * a very quick finalizer check by walking the prototype chain + * and checking the flag alone. (Note that this means that just + * setting _Finalizer on an object won't affect finalizer checks.) + * + * NOTE: if the argument is a Proxy object, this flag will be set + * on the Proxy, not the target. As a result, the target won't get + * a finalizer flag and the Proxy also won't be finalized as there's + * an explicit Proxy check in finalization now. + */ + if (callable) { + DUK_HOBJECT_SET_HAVE_FINALIZER(h); + } else { + DUK_HOBJECT_CLEAR_HAVE_FINALIZER(h); + } } #else /* DUK_USE_FINALIZER_SUPPORT */ DUK_EXTERNAL void duk_get_finalizer(duk_context *ctx, duk_idx_t idx) { diff -Nru duktape-2.0.0/src-separate/duk_api_stack.c duktape-2.1.1/src-separate/duk_api_stack.c --- duktape-2.0.0/src-separate/duk_api_stack.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_api_stack.c 2017-07-28 22:05:08.000000000 +0000 @@ -76,7 +76,7 @@ DUK_LOCAL_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t idx, duk_uint_t tag); -DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t idx, duk_bool_t require) { +DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t idx, duk_int_t def_value, duk_bool_t require) { duk_hthread *thr; duk_tval *tv; duk_small_int_t c; @@ -136,10 +136,11 @@ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); /* not reachable */ } - return 0; + + return def_value; } -DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t idx, duk_bool_t require) { +DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value, duk_bool_t require) { duk_hthread *thr; duk_tval *tv; duk_small_int_t c; @@ -189,7 +190,8 @@ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); /* not reachable */ } - return 0; + + return def_value; } /* @@ -356,7 +358,7 @@ DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(DUK_INVALID_INDEX < 0); - if (duk_normalize_index(ctx, idx) < 0) { + if (DUK_UNLIKELY(duk_normalize_index(ctx, idx) < 0)) { DUK_ERROR_RANGE_INDEX(thr, idx); return; /* unreachable */ } @@ -384,7 +386,7 @@ DUK_ASSERT_CTX_VALID(ctx); ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); - if (ret < min_top) { + if (DUK_UNLIKELY(ret < min_top)) { DUK_ERROR_TYPE_INVALID_ARGS(thr); } return ret; @@ -596,7 +598,7 @@ new_alloc_size = sizeof(duk_tval) * new_size; new_valstack = (duk_tval *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_valstack_ptr, (void *) thr, new_alloc_size); - if (!new_valstack) { + if (DUK_UNLIKELY(new_valstack == NULL)) { /* Because new_size != 0, if condition doesn't need to be * (new_valstack != NULL || new_size == 0). */ @@ -686,26 +688,16 @@ return 1; } -DUK_INTERNAL -duk_bool_t duk_valstack_resize_raw(duk_context *ctx, - duk_size_t min_new_size, - duk_small_uint_t flags) { +DUK_LOCAL DUK_COLD DUK_NOINLINE duk_bool_t duk__valstack_do_resize(duk_context *ctx, + duk_size_t min_new_size, + duk_small_uint_t flags) { duk_hthread *thr = (duk_hthread *) ctx; duk_size_t old_size; duk_size_t new_size; - duk_bool_t is_shrink = 0; - duk_small_uint_t shrink_flag = (flags & DUK_VSRESIZE_FLAG_SHRINK); + duk_bool_t is_shrink; duk_small_uint_t compact_flag = (flags & DUK_VSRESIZE_FLAG_COMPACT); duk_small_uint_t throw_flag = (flags & DUK_VSRESIZE_FLAG_THROW); - DUK_DDD(DUK_DDDPRINT("check valstack resize: min_new_size=%lu, curr_size=%ld, curr_top=%ld, " - "curr_bottom=%ld, shrink=%d, compact=%d, throw=%d", - (unsigned long) min_new_size, - (long) (thr->valstack_end - thr->valstack), - (long) (thr->valstack_top - thr->valstack), - (long) (thr->valstack_bottom - thr->valstack), - (int) shrink_flag, (int) compact_flag, (int) throw_flag)); - DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->valstack_bottom >= thr->valstack); @@ -721,11 +713,8 @@ if (min_new_size <= old_size) { is_shrink = 1; - if (!shrink_flag || - old_size - min_new_size < DUK_VALSTACK_SHRINK_THRESHOLD) { - DUK_DDD(DUK_DDDPRINT("no need to grow or shrink valstack")); - return 1; - } + } else { + is_shrink = 0; } new_size = min_new_size; @@ -744,7 +733,7 @@ (unsigned long) old_size, (unsigned long) new_size, (unsigned long) min_new_size)); - if (new_size > thr->valstack_max) { + if (DUK_UNLIKELY(new_size > thr->valstack_max)) { /* Note: may be triggered even if minimal new_size would not reach the limit, * plan limit accordingly (taking DUK_VALSTACK_GROW_STEP into account). */ @@ -767,7 +756,7 @@ * size_t and pointer arithmetic won't wrap in duk__resize_valstack(). */ - if (!duk__resize_valstack(ctx, new_size)) { + if (DUK_UNLIKELY(!duk__resize_valstack(ctx, new_size))) { if (is_shrink) { DUK_DD(DUK_DDPRINT("valstack resize failed, but is a shrink, ignore")); return 1; @@ -786,6 +775,44 @@ return 1; } +DUK_INTERNAL duk_bool_t duk_valstack_resize_raw(duk_context *ctx, + duk_size_t min_new_size, + duk_small_uint_t flags) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_size_t old_size; + + DUK_DDD(DUK_DDDPRINT("check valstack resize: min_new_size=%lu, curr_size=%ld, curr_top=%ld, " + "curr_bottom=%ld, flags=%lx", + (unsigned long) min_new_size, + (long) (thr->valstack_end - thr->valstack), + (long) (thr->valstack_top - thr->valstack), + (long) (thr->valstack_bottom - thr->valstack), + (unsigned long) flags)); + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + DUK_ASSERT(thr->valstack_bottom >= thr->valstack); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT(thr->valstack_end >= thr->valstack_top); + +#if defined(DUK_USE_PREFER_SIZE) + old_size = (duk_size_t) (thr->valstack_end - thr->valstack); +#else + DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size); + old_size = thr->valstack_size; +#endif + + if (DUK_LIKELY(min_new_size <= old_size)) { + if (DUK_LIKELY((flags & DUK_VSRESIZE_FLAG_SHRINK) == 0 || + old_size - min_new_size < DUK_VALSTACK_SHRINK_THRESHOLD)) { + DUK_DDD(DUK_DDDPRINT("no need to grow or shrink valstack")); + return 1; + } + } + + return duk__valstack_do_resize(ctx, min_new_size, flags); +} + DUK_EXTERNAL duk_bool_t duk_check_stack(duk_context *ctx, duk_idx_t extra) { duk_hthread *thr = (duk_hthread *) ctx; duk_size_t min_new_size; @@ -831,9 +858,11 @@ } DUK_EXTERNAL duk_bool_t duk_check_stack_top(duk_context *ctx, duk_idx_t top) { + duk_hthread *thr; duk_size_t min_new_size; DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; if (DUK_UNLIKELY(top < 0)) { /* Clamping to zero makes the API more robust to calling code @@ -842,7 +871,7 @@ top = 0; } - min_new_size = top + DUK_VALSTACK_INTERNAL_EXTRA; + min_new_size = (thr->valstack_bottom - thr->valstack) + top + DUK_VALSTACK_INTERNAL_EXTRA; return duk_valstack_resize_raw(ctx, min_new_size, /* min_new_size */ 0 /* no shrink */ | /* flags */ @@ -851,9 +880,11 @@ } DUK_EXTERNAL void duk_require_stack_top(duk_context *ctx, duk_idx_t top) { + duk_hthread *thr; duk_size_t min_new_size; DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; if (DUK_UNLIKELY(top < 0)) { /* Clamping to zero makes the API more robust to calling code @@ -862,7 +893,7 @@ top = 0; } - min_new_size = top + DUK_VALSTACK_INTERNAL_EXTRA; + min_new_size = (thr->valstack_bottom - thr->valstack) + top + DUK_VALSTACK_INTERNAL_EXTRA; (void) duk_valstack_resize_raw(ctx, min_new_size, /* min_new_size */ 0 /* no shrink */ | /* flags */ @@ -927,7 +958,7 @@ thr = (duk_hthread *) ctx; DUK__CHECK_SPACE(); - if (thr->valstack_top - thr->valstack_bottom <= 0) { + if (DUK_UNLIKELY(thr->valstack_top - thr->valstack_bottom <= 0)) { DUK_ERROR_RANGE_INDEX(thr, -1); return; /* unreachable */ } @@ -1102,27 +1133,27 @@ DUK_ASSERT(to_ctx != NULL); DUK_ASSERT(from_ctx != NULL); - if (to_ctx == from_ctx) { + if (DUK_UNLIKELY(to_ctx == from_ctx)) { DUK_ERROR_TYPE(to_thr, DUK_STR_INVALID_CONTEXT); return; } - if ((count < 0) || - (count > (duk_idx_t) to_thr->valstack_max)) { + if (DUK_UNLIKELY((count < 0) || + (count > (duk_idx_t) to_thr->valstack_max))) { /* Maximum value check ensures 'nbytes' won't wrap below. */ DUK_ERROR_RANGE_INVALID_COUNT(to_thr); return; } nbytes = sizeof(duk_tval) * count; - if (nbytes == 0) { + if (DUK_UNLIKELY(nbytes == 0)) { return; } DUK_ASSERT(to_thr->valstack_top <= to_thr->valstack_end); - if ((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes) { + if (DUK_UNLIKELY((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes)) { DUK_ERROR_RANGE_PUSH_BEYOND(to_thr); } src = (void *) ((duk_uint8_t *) from_thr->valstack_top - nbytes); - if (src < (void *) from_thr->valstack_bottom) { + if (DUK_UNLIKELY(src < (void *) from_thr->valstack_bottom)) { DUK_ERROR_RANGE_INVALID_COUNT(to_thr); } @@ -1157,7 +1188,7 @@ } /* - * Get/require + * Get/opt/require */ DUK_EXTERNAL void duk_require_undefined(duk_context *ctx, duk_idx_t idx) { @@ -1168,7 +1199,7 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_UNDEFINED(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_UNDEFINED(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "undefined", DUK_STR_NOT_UNDEFINED); } } @@ -1181,13 +1212,13 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_NULL(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_NULL(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "null", DUK_STR_NOT_NULL); } } -DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t idx) { - duk_bool_t ret = 0; /* default: false */ +DUK_LOCAL DUK_ALWAYS_INLINE duk_bool_t duk__get_boolean_raw(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value) { + duk_bool_t ret; duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); @@ -1196,12 +1227,27 @@ DUK_ASSERT(tv != NULL); if (DUK_TVAL_IS_BOOLEAN(tv)) { ret = DUK_TVAL_GET_BOOLEAN(tv); + DUK_ASSERT(ret == 0 || ret == 1); + } else { + ret = def_value; + /* Not guaranteed to be 0 or 1. */ } - DUK_ASSERT(ret == 0 || ret == 1); return ret; } +DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t idx) { + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_boolean_raw(ctx, idx, 0); /* default: false */ +} + +DUK_EXTERNAL duk_bool_t duk_get_boolean_default(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_boolean_raw(ctx, idx, def_value); +} + DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -1211,35 +1257,61 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_BOOLEAN(tv)) { + if (DUK_LIKELY(DUK_TVAL_IS_BOOLEAN(tv))) { + ret = DUK_TVAL_GET_BOOLEAN(tv); + DUK_ASSERT(ret == 0 || ret == 1); + return ret; + } else { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "boolean", DUK_STR_NOT_BOOLEAN); } - ret = DUK_TVAL_GET_BOOLEAN(tv); - DUK_ASSERT(ret == 0 || ret == 1); - return ret; } -DUK_EXTERNAL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t idx) { +DUK_EXTERNAL duk_bool_t duk_opt_boolean(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_boolean(ctx, idx); +} + +DUK_LOCAL DUK_ALWAYS_INLINE duk_double_t duk__get_number_raw(duk_context *ctx, duk_idx_t idx, duk_double_t def_value) { duk_double_union ret; duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); - ret.d = DUK_DOUBLE_NAN; /* default: NaN */ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (DUK_TVAL_IS_NUMBER(tv)) { - ret.d = DUK_TVAL_GET_NUMBER(tv); +#if defined(DUK_USE_FASTINT) + if (DUK_TVAL_IS_FASTINT(tv)) { + ret.d = (duk_double_t) DUK_TVAL_GET_FASTINT(tv); /* XXX: cast trick */ + } + else +#endif + if (DUK_TVAL_IS_DOUBLE(tv)) { + /* When using packed duk_tval, number must be in NaN-normalized form + * for it to be a duk_tval, so no need to normalize. NOP for unpacked + * duk_tval. + */ + ret.d = DUK_TVAL_GET_DOUBLE(tv); + DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret)); + } else { + ret.d = def_value; + /* Default value (including NaN) may not be normalized. */ } - /* When using packed duk_tval, number must be in NaN-normalized form - * for it to be a duk_tval, so no need to normalize. NOP for unpacked - * duk_tval. - */ - DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret)); return ret.d; } +DUK_EXTERNAL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t idx) { + return duk__get_number_raw(ctx, idx, DUK_DOUBLE_NAN); /* default: NaN */ +} + +DUK_EXTERNAL duk_double_t duk_get_number_default(duk_context *ctx, duk_idx_t idx, duk_double_t def_value) { + return duk__get_number_raw(ctx, idx, def_value); +} + DUK_EXTERNAL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -1249,7 +1321,7 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_NUMBER(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_NUMBER(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); } @@ -1263,56 +1335,89 @@ return ret.d; } +DUK_EXTERNAL duk_double_t duk_opt_number(duk_context *ctx, duk_idx_t idx, duk_double_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + /* User provided default is not NaN normalized. */ + return def_value; + } + return duk_require_number(ctx, idx); +} + DUK_EXTERNAL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t idx) { - /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*require*/); + + return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*def_value*/, 0 /*require*/); } DUK_EXTERNAL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t idx) { - /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*require*/); + + return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*def_value*/, 0 /*require*/); +} + +DUK_EXTERNAL duk_int_t duk_get_int_default(duk_context *ctx, duk_idx_t idx, duk_int_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + return (duk_int_t) duk__api_coerce_d2i(ctx, idx, def_value, 0 /*require*/); +} + +DUK_EXTERNAL duk_uint_t duk_get_uint_default(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, def_value, 0 /*require*/); } DUK_EXTERNAL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t idx) { - /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 1 /*require*/); + + return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*def_value*/, 1 /*require*/); } DUK_EXTERNAL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t idx) { - /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 1 /*require*/); + + return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*def_value*/, 1 /*require*/); } -DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) { - const char *ret; - duk_tval *tv; +DUK_EXTERNAL duk_int_t duk_opt_int(duk_context *ctx, duk_idx_t idx, duk_int_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_int(ctx, idx); +} +DUK_EXTERNAL duk_uint_t duk_opt_uint(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value) { DUK_ASSERT_CTX_VALID(ctx); - /* default: NULL, length 0 */ - ret = NULL; - if (out_len) { - *out_len = 0; + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; } + return duk_require_uint(ctx, idx); +} - tv = duk_get_tval_or_unused(ctx, idx); - DUK_ASSERT(tv != NULL); - if (DUK_TVAL_IS_STRING(tv)) { - /* Here we rely on duk_hstring instances always being zero - * terminated even if the actual string is not. - */ - duk_hstring *h = DUK_TVAL_GET_STRING(tv); - DUK_ASSERT(h != NULL); +DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) { + duk_hstring *h; + const char *ret; + duk_size_t len; + + DUK_ASSERT_CTX_VALID(ctx); + + h = duk_get_hstring(ctx, idx); + if (h != NULL) { + len = DUK_HSTRING_GET_BYTELEN(h); ret = (const char *) DUK_HSTRING_GET_DATA(h); - if (out_len) { - *out_len = DUK_HSTRING_GET_BYTELEN(h); - } + } else { + len = 0; + ret = NULL; } + if (out_len != NULL) { + *out_len = len; + } return ret; } @@ -1343,9 +1448,72 @@ } DUK_EXTERNAL const char *duk_get_string(duk_context *ctx, duk_idx_t idx) { + duk_hstring *h; + + DUK_ASSERT_CTX_VALID(ctx); + + h = duk_get_hstring(ctx, idx); + if (h != NULL) { + return (const char *) DUK_HSTRING_GET_DATA(h); + } else { + return NULL; + } +} + +DUK_EXTERNAL const char *duk_opt_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + if (out_len != NULL) { + *out_len = def_len; + } + return def_ptr; + } + return duk_require_lstring(ctx, idx, out_len); +} + +DUK_EXTERNAL const char *duk_opt_string(duk_context *ctx, duk_idx_t idx, const char *def_ptr) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_ptr; + } + return duk_require_string(ctx, idx); +} + +DUK_EXTERNAL const char *duk_get_lstring_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) { + duk_hstring *h; + const char *ret; + duk_size_t len; + + DUK_ASSERT_CTX_VALID(ctx); + + h = duk_get_hstring(ctx, idx); + if (h != NULL) { + len = DUK_HSTRING_GET_BYTELEN(h); + ret = (const char *) DUK_HSTRING_GET_DATA(h); + } else { + len = def_len; + ret = def_ptr; + } + + if (out_len != NULL) { + *out_len = len; + } + return ret; +} + +DUK_EXTERNAL const char *duk_get_string_default(duk_context *ctx, duk_idx_t idx, const char *def_value) { + duk_hstring *h; + DUK_ASSERT_CTX_VALID(ctx); - return duk_get_lstring(ctx, idx, NULL); + h = duk_get_hstring(ctx, idx); + if (h != NULL) { + return (const char *) DUK_HSTRING_GET_DATA(h); + } else { + return def_value; + } } DUK_INTERNAL const char *duk_get_string_notsymbol(duk_context *ctx, duk_idx_t idx) { @@ -1377,7 +1545,7 @@ return (const char *) DUK_HSTRING_GET_DATA(h); } -DUK_EXTERNAL void *duk_get_pointer(duk_context *ctx, duk_idx_t idx) { +DUK_LOCAL void *duk__get_pointer_raw(duk_context *ctx, duk_idx_t idx, void *def_value) { duk_tval *tv; void *p; @@ -1386,13 +1554,30 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); if (!DUK_TVAL_IS_POINTER(tv)) { - return NULL; + return def_value; } p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */ return p; } +DUK_EXTERNAL void *duk_get_pointer(duk_context *ctx, duk_idx_t idx) { + return duk__get_pointer_raw(ctx, idx, NULL /*def_value*/); +} + +DUK_EXTERNAL void *duk_opt_pointer(duk_context *ctx, duk_idx_t idx, void *def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_pointer(ctx, idx); +} + +DUK_EXTERNAL void *duk_get_pointer_default(duk_context *ctx, duk_idx_t idx, void *def_value) { + return duk__get_pointer_raw(ctx, idx, def_value); +} + DUK_EXTERNAL void *duk_require_pointer(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -1405,7 +1590,7 @@ */ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_POINTER(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_POINTER(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "pointer", DUK_STR_NOT_POINTER); } p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */ @@ -1431,10 +1616,12 @@ } #endif -DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_bool_t throw_flag) { +DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag) { duk_hthread *thr = (duk_hthread *) ctx; - duk_tval *tv; duk_hbuffer *h; + void *ret; + duk_size_t len; + duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); DUK_UNREF(thr); @@ -1445,27 +1632,54 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_BUFFER(tv)) { + if (DUK_LIKELY(DUK_TVAL_IS_BUFFER(tv))) { + h = DUK_TVAL_GET_BUFFER(tv); + DUK_ASSERT(h != NULL); + + len = DUK_HBUFFER_GET_SIZE(h); + ret = DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); + } else { if (throw_flag) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER); } - return NULL; + len = def_size; + ret = def_ptr; } - h = DUK_TVAL_GET_BUFFER(tv); - DUK_ASSERT(h != NULL); - if (out_size) { - *out_size = DUK_HBUFFER_GET_SIZE(h); + if (out_size != NULL) { + *out_size = len; } - return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */ + return ret; } DUK_EXTERNAL void *duk_get_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { - return duk__get_buffer_helper(ctx, idx, out_size, 0 /*throw_flag*/); + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_buffer_helper(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/); +} + +DUK_EXTERNAL void *duk_opt_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + if (out_size != NULL) { + *out_size = def_size; + } + return def_ptr; + } + return duk_require_buffer(ctx, idx, out_size); +} + +DUK_EXTERNAL void *duk_get_buffer_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len) { + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_buffer_helper(ctx, idx, out_size, def_ptr, def_len, 0 /*throw_flag*/); } DUK_EXTERNAL void *duk_require_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { - return duk__get_buffer_helper(ctx, idx, out_size, 1 /*throw_flag*/); + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_buffer_helper(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/); } /* Get the active buffer data area for a plain buffer or a buffer object. @@ -1473,7 +1687,7 @@ * have a NULL data pointer when its size is zero, the optional 'out_isbuffer' * argument allows caller to detect this reliably. */ -DUK_INTERNAL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_bool_t throw_flag, duk_bool_t *out_isbuffer) { +DUK_INTERNAL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag, duk_bool_t *out_isbuffer) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -1484,7 +1698,7 @@ *out_isbuffer = 0; } if (out_size != NULL) { - *out_size = 0; + *out_size = def_size; } tv = duk_get_tval_or_unused(ctx, idx); @@ -1533,15 +1747,31 @@ if (throw_flag) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER); } - return NULL; + return def_ptr; } DUK_EXTERNAL void *duk_get_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { - return duk_get_buffer_data_raw(ctx, idx, out_size, 0 /*throw_flag*/, NULL); + return duk_get_buffer_data_raw(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, NULL); +} + +DUK_EXTERNAL void *duk_get_buffer_data_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) { + return duk_get_buffer_data_raw(ctx, idx, out_size, def_ptr, def_size, 0 /*throw_flag*/, NULL); +} + +DUK_EXTERNAL void *duk_opt_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + if (out_size != NULL) { + *out_size = def_size; + } + return def_ptr; + } + return duk_require_buffer_data(ctx, idx, out_size); } DUK_EXTERNAL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { - return duk_get_buffer_data_raw(ctx, idx, out_size, 1 /*throw_flag*/, NULL); + return duk_get_buffer_data_raw(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/, NULL); } /* Raw helper for getting a value from the stack, checking its tag. @@ -1573,7 +1803,7 @@ DUK_INTERNAL duk_hstring *duk_get_hstring_notsymbol(duk_context *ctx, duk_idx_t idx) { duk_hstring *res = (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING); - if (res && DUK_HSTRING_HAS_SYMBOL(res)) { + if (DUK_UNLIKELY(res && DUK_HSTRING_HAS_SYMBOL(res))) { return NULL; } return res; @@ -1582,7 +1812,7 @@ DUK_INTERNAL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t idx) { duk_hstring *h; h = (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING); - if (h == NULL) { + if (DUK_UNLIKELY(h == NULL)) { DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "string", DUK_STR_NOT_STRING); } return h; @@ -1591,7 +1821,7 @@ DUK_INTERNAL duk_hstring *duk_require_hstring_notsymbol(duk_context *ctx, duk_idx_t idx) { duk_hstring *h; h = (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING); - if (h == NULL || DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(h == NULL || DUK_HSTRING_HAS_SYMBOL(h))) { DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "string", DUK_STR_NOT_STRING); } return h; @@ -1604,7 +1834,7 @@ DUK_INTERNAL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t idx) { duk_hobject *h; h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (h == NULL) { + if (DUK_UNLIKELY(h == NULL)) { DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "object", DUK_STR_NOT_OBJECT); } return h; @@ -1617,7 +1847,7 @@ DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t idx) { duk_hbuffer *h; h = (duk_hbuffer *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_BUFFER); - if (h == NULL) { + if (DUK_UNLIKELY(h == NULL)) { DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "buffer", DUK_STR_NOT_BUFFER); } return h; @@ -1625,7 +1855,7 @@ DUK_INTERNAL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t idx) { duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (h != NULL && !DUK_HOBJECT_IS_THREAD(h)) { + if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_THREAD(h))) { h = NULL; } return (duk_hthread *) h; @@ -1634,7 +1864,7 @@ DUK_INTERNAL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (!(h != NULL && DUK_HOBJECT_IS_THREAD(h))) { + if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_THREAD(h)))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "thread", DUK_STR_NOT_THREAD); } return (duk_hthread *) h; @@ -1642,7 +1872,7 @@ DUK_INTERNAL duk_hcompfunc *duk_get_hcompfunc(duk_context *ctx, duk_idx_t idx) { duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (h != NULL && !DUK_HOBJECT_IS_COMPFUNC(h)) { + if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_COMPFUNC(h))) { h = NULL; } return (duk_hcompfunc *) h; @@ -1651,7 +1881,7 @@ DUK_INTERNAL duk_hcompfunc *duk_require_hcompfunc(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (!(h != NULL && DUK_HOBJECT_IS_COMPFUNC(h))) { + if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_COMPFUNC(h)))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "compiledfunction", DUK_STR_NOT_COMPFUNC); } return (duk_hcompfunc *) h; @@ -1659,7 +1889,7 @@ DUK_INTERNAL duk_hnatfunc *duk_get_hnatfunc(duk_context *ctx, duk_idx_t idx) { duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (h != NULL && !DUK_HOBJECT_IS_NATFUNC(h)) { + if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_NATFUNC(h))) { h = NULL; } return (duk_hnatfunc *) h; @@ -1668,7 +1898,7 @@ DUK_INTERNAL duk_hnatfunc *duk_require_hnatfunc(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (!(h != NULL && DUK_HOBJECT_IS_NATFUNC(h))) { + if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_NATFUNC(h)))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC); } return (duk_hnatfunc *) h; @@ -1683,13 +1913,13 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_OBJECT(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_OBJECT(tv))) { return NULL; } h = DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(h != NULL); - if (!DUK_HOBJECT_IS_NATFUNC(h)) { + if (DUK_UNLIKELY(!DUK_HOBJECT_IS_NATFUNC(h))) { return NULL; } DUK_ASSERT(DUK_HOBJECT_HAS_NATFUNC(h)); @@ -1698,6 +1928,28 @@ return f->func; } +DUK_EXTERNAL duk_c_function duk_opt_c_function(duk_context *ctx, duk_idx_t idx, duk_c_function def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_c_function(ctx, idx); +} + +DUK_EXTERNAL duk_c_function duk_get_c_function_default(duk_context *ctx, duk_idx_t idx, duk_c_function def_value) { + duk_c_function ret; + + DUK_ASSERT_CTX_VALID(ctx); + + ret = duk_get_c_function(ctx, idx); + if (ret != NULL) { + return ret; + } + + return def_value; +} + DUK_EXTERNAL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_c_function ret; @@ -1705,14 +1957,14 @@ DUK_ASSERT_CTX_VALID(ctx); ret = duk_get_c_function(ctx, idx); - if (!ret) { + if (DUK_UNLIKELY(!ret)) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC); } return ret; } DUK_EXTERNAL void duk_require_function(duk_context *ctx, duk_idx_t idx) { - if (!duk_is_function(ctx, idx)) { + if (DUK_UNLIKELY(!duk_is_function(ctx, idx))) { DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, idx, "function", DUK_STR_NOT_FUNCTION); } } @@ -1721,7 +1973,7 @@ duk_hobject *h; h = duk_require_hobject_accept_mask(ctx, idx, DUK_TYPE_MASK_LIGHTFUNC); - if (h != NULL && !DUK_HOBJECT_HAS_CONSTRUCTABLE(h)) { + if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_HAS_CONSTRUCTABLE(h))) { DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, idx, "constructable", DUK_STR_NOT_CONSTRUCTABLE); } /* Lightfuncs (h == NULL) are constructable. */ @@ -1739,6 +1991,28 @@ return (duk_context *) duk_require_hthread(ctx, idx); } +DUK_EXTERNAL duk_context *duk_opt_context(duk_context *ctx, duk_idx_t idx, duk_context *def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_context(ctx, idx); +} + +DUK_EXTERNAL_DECL duk_context *duk_get_context_default(duk_context *ctx, duk_idx_t idx, duk_context *def_value) { + duk_context *ret; + + DUK_ASSERT_CTX_VALID(ctx); + + ret = duk_get_context(ctx, idx); + if (ret != NULL) { + return ret; + } + + return def_value; +} + DUK_EXTERNAL void *duk_get_heapptr(duk_context *ctx, duk_idx_t idx) { duk_tval *tv; void *ret; @@ -1747,7 +2021,7 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) { return (void *) NULL; } @@ -1756,6 +2030,28 @@ return ret; } +DUK_EXTERNAL void *duk_opt_heapptr(duk_context *ctx, duk_idx_t idx, void *def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_heapptr(ctx, idx); +} + +DUK_EXTERNAL_DECL void *duk_get_heapptr_default(duk_context *ctx, duk_idx_t idx, void *def_value) { + void *ret; + + DUK_ASSERT_CTX_VALID(ctx); + + ret = duk_get_heapptr(ctx, idx); + if (ret != NULL) { + return ret; + } + + return def_value; +} + DUK_EXTERNAL void *duk_require_heapptr(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -1765,7 +2061,7 @@ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (!DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { + if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "heapobject", DUK_STR_UNEXPECTED_TYPE); } @@ -1782,7 +2078,7 @@ DUK_ASSERT_CTX_VALID(ctx); res = duk_get_hobject(ctx, idx); /* common case, not promoted */ - if (res != NULL) { + if (DUK_LIKELY(res != NULL)) { DUK_ASSERT(res != NULL); return res; } @@ -1837,7 +2133,7 @@ DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX); h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum) { + if (DUK_UNLIKELY(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum)) { h = NULL; } return h; @@ -1853,7 +2149,7 @@ thr = (duk_hthread *) ctx; h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT); - if (!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum)) { + if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum))) { duk_hstring *h_class; h_class = DUK_HTHREAD_GET_STRING(thr, DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum)); DUK_UNREF(h_class); @@ -1895,7 +2191,7 @@ case DUK_TAG_STRING: { duk_hstring *h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { return 0; } return (duk_size_t) DUK_HSTRING_GET_CHARLEN(h); @@ -2197,6 +2493,16 @@ tv = duk_require_tval(ctx, idx); DUK_ASSERT(tv != NULL); + +#if defined(DUK_USE_FASTINT) + /* If argument is a fastint, guarantee that it remains one. + * There's no downgrade check for other cases. + */ + if (DUK_TVAL_IS_FASTINT(tv)) { + /* XXX: Unnecessary conversion back and forth. */ + return (duk_double_t) DUK_TVAL_GET_FASTINT(tv); + } +#endif d = coerce_func(thr, tv); /* XXX: fastint? */ @@ -2208,21 +2514,21 @@ } DUK_EXTERNAL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t idx) { - /* Value coercion (in stack): ToInteger(), E5 Section 9.4 - * API return value coercion: custom + /* Value coercion (in stack): ToInteger(), E5 Section 9.4, + * API return value coercion: custom. */ DUK_ASSERT_CTX_VALID(ctx); (void) duk__to_int_uint_helper(ctx, idx, duk_js_tointeger); - return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*require*/); + return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*def_value*/, 0 /*require*/); } DUK_EXTERNAL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t idx) { - /* Value coercion (in stack): ToInteger(), E5 Section 9.4 - * API return value coercion: custom + /* Value coercion (in stack): ToInteger(), E5 Section 9.4, + * API return value coercion: custom. */ DUK_ASSERT_CTX_VALID(ctx); (void) duk__to_int_uint_helper(ctx, idx, duk_js_tointeger); - return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*require*/); + return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*def_value*/, 0 /*require*/); } DUK_EXTERNAL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t idx) { @@ -2426,7 +2732,7 @@ duk_hstring *h; h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { stridx = DUK_STRIDX_UC_SYMBOL; } else { stridx = DUK_STRIDX_UC_STRING; @@ -2584,7 +2890,7 @@ duk_hstring *h; h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CANNOT_STRING_COERCE_SYMBOL); } else { goto skip_replace; @@ -2664,7 +2970,7 @@ duk_hstring *ret; DUK_ASSERT_CTX_VALID(ctx); ret = duk_get_hstring(ctx, idx); - if (ret && DUK_HSTRING_HAS_SYMBOL(ret)) { + if (DUK_UNLIKELY(ret && DUK_HSTRING_HAS_SYMBOL(ret))) { return ret; } return duk_to_hstring(ctx, idx); @@ -2817,6 +3123,7 @@ flags = DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_CONSTRUCTABLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_NATFUNC | DUK_HOBJECT_FLAG_NEWENV | DUK_HOBJECT_FLAG_STRICT | @@ -2867,6 +3174,7 @@ } case DUK_TAG_BOOLEAN: { flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BOOLEAN); proto = DUK_BIDX_BOOLEAN_PROTOTYPE; goto create_object; @@ -2875,12 +3183,14 @@ duk_hstring *h; h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_SYMBOL); proto = DUK_BIDX_SYMBOL_PROTOTYPE; } else { flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING); proto = DUK_BIDX_STRING_PROTOTYPE; @@ -2910,6 +3220,7 @@ #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ case DUK_TAG_POINTER: { flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER); proto = DUK_BIDX_POINTER_PROTOTYPE; goto create_object; @@ -2938,7 +3249,8 @@ DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); flags = DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_NUMBER); + DUK_HOBJECT_FLAG_FASTREFS | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_NUMBER); proto = DUK_BIDX_NUMBER_PROTOTYPE; goto create_object; } @@ -3156,7 +3468,7 @@ DUK_ASSERT_CTX_VALID(ctx); - if (duk_get_type_mask(ctx, idx) & mask) { + if (DUK_LIKELY(duk_get_type_mask(ctx, idx) & mask)) { return 1; } if (mask & DUK_TYPE_MASK_THROW) { @@ -3282,7 +3594,10 @@ DUK_ASSERT_CTX_VALID(ctx); h = duk_get_hstring(ctx, idx); - if (h != NULL && DUK_HSTRING_HAS_SYMBOL(h)) { + /* Use DUK_LIKELY() here because caller may be more likely to type + * check an expected symbol than not. + */ + if (DUK_LIKELY(h != NULL && DUK_HSTRING_HAS_SYMBOL(h))) { return 1; } return 0; @@ -3338,10 +3653,15 @@ } DUK_EXTERNAL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t idx) { + duk_hobject *obj; + DUK_ASSERT_CTX_VALID(ctx); - return duk__obj_flag_any_default_false(ctx, - idx, - DUK_HOBJECT_FLAG_THREAD); + + obj = duk_get_hobject(ctx, idx); + if (obj) { + return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_THREAD ? 1 : 0); + } + return 0; } DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t idx) { @@ -3612,9 +3932,7 @@ DUK_ASSERT_CTX_VALID(ctx); /* check stack before interning (avoid hanging temp) */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); /* NULL with zero length represents an empty string; NULL with higher * length is also now trated like an empty string although it is @@ -3626,11 +3944,11 @@ } /* Check for maximum string length */ - if (len > DUK_HSTRING_MAX_BYTELEN) { + if (DUK_UNLIKELY(len > DUK_HSTRING_MAX_BYTELEN)) { DUK_ERROR_RANGE(thr, DUK_STR_STRING_TOO_LONG); } - h = duk_heap_string_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len); + h = duk_heap_strtable_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len); DUK_ASSERT(h != NULL); tv_slot = thr->valstack_top++; @@ -3748,6 +4066,7 @@ thr = (duk_hthread *) ctx; DUK_ASSERT(thr->callstack_top > 0); /* caller required to know */ + DUK_ASSERT(thr->callstack_curr != NULL); DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* consequence of above */ DUK_ASSERT(thr->valstack_bottom - 1 >= thr->valstack); /* 'this' binding exists */ @@ -3763,8 +4082,8 @@ DUK_ASSERT_DISABLE(thr->callstack_top >= 0); DUK_ASSERT(thr->callstack_top <= thr->callstack_size); - act = duk_hthread_get_current_activation(thr); - if (act) { + act = thr->callstack_curr; + if (act != NULL) { duk_push_tval(ctx, &act->tv_func); } else { duk_push_undefined(ctx); @@ -3822,7 +4141,7 @@ DUK_EXTERNAL void duk_push_thread_stash(duk_context *ctx, duk_context *target_ctx) { duk_hthread *thr = (duk_hthread *) ctx; DUK_ASSERT_CTX_VALID(ctx); - if (!target_ctx) { + if (DUK_UNLIKELY(target_ctx == NULL)) { DUK_ERROR_TYPE_INVALID_ARGS(thr); return; /* not reached */ } @@ -3899,7 +4218,7 @@ /* failed, resize and try again */ sz = sz * 2; - if (sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT) { + if (DUK_UNLIKELY(sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT)) { DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG); } } @@ -3937,15 +4256,10 @@ DUK_ASSERT(prototype_bidx == -1 || (prototype_bidx >= 0 && prototype_bidx < DUK_NUM_BUILTINS)); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); - h = duk_hobject_alloc(thr->heap, hobject_flags_and_class); - if (!h) { - DUK_ERROR_ALLOC_FAILED(thr); - } + h = duk_hobject_alloc(thr, hobject_flags_and_class); + DUK_ASSERT(h != NULL); DUK_DDD(DUK_DDDPRINT("created object with flags: 0x%08lx", (unsigned long) h->hdr.h_flags)); @@ -3984,6 +4298,7 @@ (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), DUK_BIDX_OBJECT_PROTOTYPE); return duk_get_top_index_unsafe(ctx); @@ -3999,14 +4314,13 @@ DUK_ASSERT_CTX_VALID(ctx); flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_ARRAY_PART | DUK_HOBJECT_FLAG_EXOTIC_ARRAY | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAY); - obj = duk_harray_alloc(thr->heap, flags); - if (!obj) { - DUK_ERROR_ALLOC_FAILED(thr); - } + obj = duk_harray_alloc(thr, flags); + DUK_ASSERT(obj != NULL); /* XXX: since prototype is NULL, could save a check */ DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_ARRAY_PROTOTYPE]); @@ -4060,18 +4374,12 @@ DUK_ASSERT_CTX_VALID(ctx); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); - obj = duk_hthread_alloc(thr->heap, + obj = duk_hthread_alloc(thr, DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_THREAD | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD)); - if (!obj) { - DUK_ERROR_ALLOC_FAILED(thr); - } + DUK_ASSERT(obj != NULL); obj->state = DUK_HTHREAD_STATE_INACTIVE; #if defined(DUK_USE_ROM_STRINGS) /* Nothing to initialize, strs[] is in ROM. */ @@ -4092,7 +4400,7 @@ thr->valstack_top++; /* important to do this *after* pushing, to make the thread reachable for gc */ - if (!duk_hthread_init_stacks(thr->heap, obj)) { + if (DUK_UNLIKELY(!duk_hthread_init_stacks(thr->heap, obj))) { DUK_ERROR_ALLOC_FAILED(thr); } @@ -4123,21 +4431,18 @@ DUK_ASSERT_CTX_VALID(ctx); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); /* Template functions are not strictly constructable (they don't * have a "prototype" property for instance), so leave the * DUK_HOBJECT_FLAG_CONSRUCTABLE flag cleared here. */ - obj = duk_hcompfunc_alloc(thr->heap, + obj = duk_hcompfunc_alloc(thr, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_COMPFUNC | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION)); - if (!obj) { + if (DUK_UNLIKELY(obj == NULL)) { DUK_ERROR_ALLOC_FAILED(thr); } @@ -4162,11 +4467,9 @@ DUK_ASSERT_CTX_VALID(ctx); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } - if (func == NULL) { + DUK__CHECK_SPACE(); + + if (DUK_UNLIKELY(func == NULL)) { goto api_error; } if (nargs >= 0 && nargs < DUK_HNATFUNC_NARGS_MAX) { @@ -4177,10 +4480,8 @@ goto api_error; } - obj = duk_hnatfunc_alloc(thr->heap, flags); - if (!obj) { - DUK_ERROR_ALLOC_FAILED(thr); - } + obj = duk_hnatfunc_alloc(thr, flags); + DUK_ASSERT(obj != NULL); obj->func = func; obj->nargs = func_nargs; @@ -4211,6 +4512,7 @@ flags = DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_CONSTRUCTABLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_NATFUNC | DUK_HOBJECT_FLAG_NEWENV | DUK_HOBJECT_FLAG_STRICT | @@ -4228,6 +4530,7 @@ flags = DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_CONSTRUCTABLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_NATFUNC | DUK_HOBJECT_FLAG_NEWENV | DUK_HOBJECT_FLAG_STRICT | @@ -4243,6 +4546,7 @@ DUK_ASSERT_CTX_VALID(ctx); flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_NATFUNC | DUK_HOBJECT_FLAG_NEWENV | DUK_HOBJECT_FLAG_STRICT | @@ -4259,10 +4563,7 @@ DUK_ASSERT_CTX_VALID(ctx); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); if (nargs >= DUK_LFUNC_NARGS_MIN && nargs <= DUK_LFUNC_NARGS_MAX) { /* as is */ @@ -4271,10 +4572,10 @@ } else { goto api_error; } - if (!(length >= DUK_LFUNC_LENGTH_MIN && length <= DUK_LFUNC_LENGTH_MAX)) { + if (DUK_UNLIKELY(!(length >= DUK_LFUNC_LENGTH_MIN && length <= DUK_LFUNC_LENGTH_MAX))) { goto api_error; } - if (!(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX)) { + if (DUK_UNLIKELY(!(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX))) { goto api_error; } @@ -4298,15 +4599,10 @@ DUK_ASSERT(ctx != NULL); DUK_ASSERT(prototype_bidx >= 0); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); - obj = duk_hbufobj_alloc(thr->heap, hobject_flags_and_class); - if (!obj) { - DUK_ERROR_ALLOC_FAILED(thr); - } + obj = duk_hbufobj_alloc(thr, hobject_flags_and_class); + DUK_ASSERT(obj != NULL); DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[prototype_bidx]); DUK_ASSERT_HBUFOBJ_VALID(obj); @@ -4366,19 +4662,19 @@ uint_offset = (duk_uint_t) byte_offset; uint_length = (duk_uint_t) byte_length; if (sizeof(duk_size_t) != sizeof(duk_uint_t)) { - if ((duk_size_t) uint_offset != byte_offset || (duk_size_t) uint_length != byte_length) { + if (DUK_UNLIKELY((duk_size_t) uint_offset != byte_offset || (duk_size_t) uint_length != byte_length)) { goto range_error; } } uint_added = uint_offset + uint_length; - if (uint_added < uint_offset) { + if (DUK_UNLIKELY(uint_added < uint_offset)) { goto range_error; } DUK_ASSERT(uint_added >= uint_offset && uint_added >= uint_length); DUK_ASSERT_DISABLE(flags >= 0); /* flags is unsigned */ - lookupidx = flags & 0x0f; /* 4 low bits */ - if (lookupidx >= sizeof(duk__bufobj_flags_lookup) / sizeof(duk_uint32_t)) { + lookupidx = flags; + if (DUK_UNLIKELY(lookupidx >= sizeof(duk__bufobj_flags_lookup) / sizeof(duk_uint32_t))) { goto arg_error; } tmp = duk__bufobj_flags_lookup[lookupidx]; @@ -4407,39 +4703,9 @@ /* TypedArray views need an automatic ArrayBuffer which must be * provided as .buffer property of the view. The ArrayBuffer is * referenced via duk_hbufobj->buf_prop and an inherited .buffer - * accessor returns it. - * - * The ArrayBuffer offset is always set to zero, so that if one - * accesses the ArrayBuffer at the view's .byteOffset, the value - * matches the view at index 0. - */ - if (flags & DUK_BUFOBJ_CREATE_ARRBUF) { - duk_hbufobj *h_arrbuf; - - h_arrbuf = duk_push_bufobj_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), - DUK_BIDX_ARRAYBUFFER_PROTOTYPE); - DUK_ASSERT(h_arrbuf != NULL); - - h_arrbuf->buf = h_val; - DUK_HBUFFER_INCREF(thr, h_val); - h_arrbuf->offset = 0; - h_arrbuf->length = uint_offset + uint_length; /* Wrap checked above. */ - DUK_ASSERT(h_arrbuf->shift == 0); - h_arrbuf->elem_type = DUK_HBUFOBJ_ELEM_UINT8; - DUK_ASSERT(h_arrbuf->is_typedarray == 0); - DUK_ASSERT_HBUFOBJ_VALID(h_arrbuf); - DUK_ASSERT(h_arrbuf->buf_prop == NULL); - - DUK_ASSERT(h_bufobj->buf_prop == NULL); - h_bufobj->buf_prop = (duk_hobject *) h_arrbuf; - DUK_HBUFOBJ_INCREF(thr, h_arrbuf); /* Now reachable and accounted for. */ - - duk_pop(ctx); - } - + * accessor returns it. The ArrayBuffer is created lazily on first + * access so we don't need to do anything more here. + */ return; range_error: @@ -4482,6 +4748,7 @@ proto = duk_error_prototype_from_code(thr, err_code); (void) duk_push_object_helper_proto(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR), proto); @@ -4549,18 +4816,15 @@ DUK_ASSERT_CTX_VALID(ctx); - /* check stack first */ - if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR_RANGE_PUSH_BEYOND(thr); - } + DUK__CHECK_SPACE(); /* Check for maximum buffer length. */ - if (size > DUK_HBUFFER_MAX_BYTELEN) { + if (DUK_UNLIKELY(size > DUK_HBUFFER_MAX_BYTELEN)) { DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG); } h = duk_hbuffer_alloc(thr->heap, size, flags, &buf_data); - if (!h) { + if (DUK_UNLIKELY(h == NULL)) { DUK_ERROR_ALLOC_FAILED(thr); } @@ -4588,9 +4852,110 @@ return ptr; } +#if defined(DUK_USE_ASSERTIONS) +DUK_LOCAL void duk__validate_push_heapptr(duk_context *ctx, void *ptr) { + duk_heaphdr *h; + duk_heaphdr *curr; + duk_hthread *thr; + duk_bool_t found = 0; + + thr = (duk_hthread *) ctx; + h = (duk_heaphdr *) ptr; + if (h == NULL) { + /* Allowed. */ + return; + } + DUK_ASSERT(h != NULL); + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); + + /* One particular problem case is where an object has been + * queued for finalization but the finalizer hasn't yet been + * executed. + * + * Corner case: we're running in a finalizer for object X, and + * user code calls duk_push_heapptr() for X itself. In this + * case X will be in finalize_list, and we can detect the case + * by seeing that X's FINALIZED flag is set (which is done before + * the finalizer starts executing). + */ +#if defined(DUK_USE_FINALIZER_SUPPORT) + for (curr = thr->heap->finalize_list; + curr != NULL; + curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) { + /* FINALIZABLE is set for all objects on finalize_list + * except for an object being finalized right now. So + * can't assert here. + */ +#if 0 + DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(curr)); +#endif + + if (curr == h) { + if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h)) { + /* Object is currently being finalized. */ + DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ + found = 1; + } else { + /* Not being finalized but on finalize_list, + * allowed since Duktape 2.1. + */ + DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ + found = 1; + } + } + } +#endif /* DUK_USE_FINALIZER_SUPPORT */ + +#if defined(DUK_USE_REFERENCE_COUNTING) + /* Because refzero_list is now processed to completion inline with + * no side effects, it's always empty here. + */ + DUK_ASSERT(thr->heap->refzero_list == NULL); +#endif + + /* If not present in finalize_list (or refzero_list), it + * must be either in heap_allocated or the string table. + */ + if (DUK_HEAPHDR_IS_STRING(h)) { + duk_uint32_t i; + duk_hstring *str; + duk_heap *heap = thr->heap; + + DUK_ASSERT(found == 0); + for (i = 0; i < heap->st_size; i++) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + str = DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, heap->strtable16[i]); +#else + str = heap->strtable[i]; +#endif + while (str != NULL) { + if (str == (duk_hstring *) h) { + DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ + found = 1; + break; + } + str = str->hdr.h_next; + } + } + DUK_ASSERT(found != 0); + } else { + for (curr = thr->heap->heap_allocated; + curr != NULL; + curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) { + if (curr == h) { + DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ + found = 1; + } + } + DUK_ASSERT(found != 0); + } +} +#endif /* DUK_USE_ASSERTIONS */ + DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr) { duk_hthread *thr = (duk_hthread *) ctx; duk_idx_t ret; + duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); @@ -4602,43 +4967,80 @@ */ #if defined(DUK_USE_ASSERTIONS) - { - /* One particular problem case is where an object has been - * queued for finalization but the finalizer hasn't been - * executed. - */ - duk_heaphdr *curr; - for (curr = thr->heap->finalize_list; - curr != NULL; - curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) { - DUK_ASSERT(curr != (duk_heaphdr *) ptr); - } - } + duk__validate_push_heapptr(ctx, ptr); #endif + DUK__CHECK_SPACE(); + ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); + tv = thr->valstack_top++; if (ptr == NULL) { - goto push_undefined; + DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); + return ret; + } + + DUK_ASSERT_HEAPHDR_VALID((duk_heaphdr *) ptr); + + /* If the argument is on finalize_list it has technically been + * unreachable before duk_push_heapptr() but it's still safe to + * push it. Starting from Duktape 2.1 allow application code to + * do so. There are two main cases: + * + * (1) The object is on the finalize_list and we're called by + * the finalizer for the object being finalized. In this + * case do nothing: finalize_list handling will deal with + * the object queueing. This is detected by the object not + * having a FINALIZABLE flag despite being on the finalize_list; + * the flag is cleared for the object being finalized only. + * + * (2) The object is on the finalize_list but is not currently + * being processed. In this case the object can be queued + * back to heap_allocated with a few flags cleared, in effect + * cancelling the finalizer. + */ + if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) ptr))) { + duk_heaphdr *curr; + + DUK_D(DUK_DPRINT("duk_push_heapptr() with a pointer on finalize_list, autorescue")); + + curr = (duk_heaphdr *) ptr; + DUK_HEAPHDR_CLEAR_FINALIZABLE(curr); + + /* Because FINALIZED is set prior to finalizer call, it will + * be set for the object being currently finalized, but not + * for other objects on finalize_list. + */ + DUK_HEAPHDR_CLEAR_FINALIZED(curr); + + /* Dequeue object from finalize_list and queue it back to + * heap_allocated. + */ +#if defined(DUK_USE_REFERENCE_COUNTING) + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) >= 1); /* Preincremented on finalize_list insert. */ + DUK_HEAPHDR_PREDEC_REFCOUNT(curr); +#endif + DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(thr->heap, curr); + DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(thr->heap, curr); + + /* Continue with the rest. */ } switch (DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) { case DUK_HTYPE_STRING: - duk_push_hstring(ctx, (duk_hstring *) ptr); + DUK_TVAL_SET_STRING(tv, (duk_hstring *) ptr); break; case DUK_HTYPE_OBJECT: - duk_push_hobject(ctx, (duk_hobject *) ptr); - break; - case DUK_HTYPE_BUFFER: - duk_push_hbuffer(ctx, (duk_hbuffer *) ptr); + DUK_TVAL_SET_OBJECT(tv, (duk_hobject *) ptr); break; default: - goto push_undefined; + DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr) == DUK_HTYPE_BUFFER); + DUK_TVAL_SET_BUFFER(tv, (duk_hbuffer *) ptr); + break; } - return ret; - push_undefined: - duk_push_undefined(ctx); + DUK_HEAPHDR_INCREF(thr, (duk_heaphdr *) ptr); + return ret; } @@ -4646,6 +5048,7 @@ DUK_EXTERNAL duk_idx_t duk_push_bare_object(duk_context *ctx) { (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), -1); /* no prototype */ return duk_get_top_index_unsafe(ctx); @@ -4709,28 +5112,52 @@ #endif DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); if (DUK_UNLIKELY(count < 0)) { DUK_ERROR_RANGE_INVALID_COUNT(thr); return; } - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); if (DUK_UNLIKELY((duk_size_t) (thr->valstack_top - thr->valstack_bottom) < (duk_size_t) count)) { DUK_ERROR_RANGE_INVALID_COUNT(thr); } - /* - * Must be very careful here, every DECREF may cause reallocation - * of our valstack. - */ +#if defined(DUK_USE_REFERENCE_COUNTING) + tv = thr->valstack_top; + tv_end = tv - count; + while (tv != tv_end) { + tv--; + DUK_ASSERT(tv >= thr->valstack_bottom); + DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv); + } + thr->valstack_top = tv; + DUK_REFZERO_CHECK_FAST(thr); +#else + tv = thr->valstack_top; + while (count > 0) { + count--; + tv--; + DUK_ASSERT(tv >= thr->valstack_bottom); + DUK_TVAL_SET_UNDEFINED(tv); + } + thr->valstack_top = tv; +#endif - /* XXX: inlined DECREF macro would be nice here: no NULL check, - * refzero queueing but no refzero algorithm run (= no pointer - * instability), inline code. - */ + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); +} + +DUK_INTERNAL void duk_pop_n_unsafe(duk_context *ctx, duk_idx_t count) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; +#if defined(DUK_USE_REFERENCE_COUNTING) + duk_tval *tv_end; +#endif - /* XXX: optimize loops */ + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(count >= 0); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count); #if defined(DUK_USE_REFERENCE_COUNTING) tv = thr->valstack_top; @@ -4756,6 +5183,34 @@ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); } +/* Pop N elements without DECREF (in effect "stealing" the refcounts). */ +#if defined(DUK_USE_REFERENCE_COUNTING) +DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_context *ctx, duk_idx_t count) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(count >= 0); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count); + + tv = thr->valstack_top; + while (count > 0) { + count--; + tv--; + DUK_ASSERT(tv >= thr->valstack_bottom); + DUK_TVAL_SET_UNDEFINED(tv); + } + thr->valstack_top = tv; + + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); +} +#else /* DUK_USE_REFERENCE_COUNTING */ +DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_context *ctx, duk_idx_t count) { + duk_pop_n_unsafe(ctx, count); +} +#endif /* DUK_USE_REFERENCE_COUNTING */ + /* Popping one element is called so often that when footprint is not an issue, * compile a specialized function for it. */ @@ -4792,16 +5247,17 @@ #if defined(DUK_USE_PREFER_SIZE) DUK_INTERNAL void duk_pop_unsafe(duk_context *ctx) { DUK_ASSERT_CTX_VALID(ctx); - duk_pop_n(ctx, 1); + duk_pop_n_unsafe(ctx, 1); } #else DUK_INTERNAL void duk_pop_unsafe(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; - DUK_ASSERT_CTX_VALID(ctx); - DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(thr->valstack_top != thr->valstack_bottom); + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); + DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1); tv = --thr->valstack_top; /* tv points to element just below prev top */ DUK_ASSERT(tv >= thr->valstack_bottom); @@ -4810,6 +5266,7 @@ #else DUK_TVAL_SET_UNDEFINED(tv); #endif + DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); } #endif /* !DUK_USE_PREFER_SIZE */ @@ -4842,7 +5299,7 @@ thr = (duk_hthread *) ctx; top = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); - if (count < 0 || count > top) { + if (DUK_UNLIKELY(count < 0 || count > top)) { DUK_ERROR_RANGE_INVALID_COUNT(thr); return; } @@ -4905,12 +5362,13 @@ DUK_EXTERNAL void duk_throw_raw(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv_val; DUK_ASSERT(thr->valstack_bottom >= thr->valstack); DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); DUK_ASSERT(thr->valstack_end >= thr->valstack_top); - if (thr->valstack_top == thr->valstack_bottom) { + if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) { DUK_ERROR_TYPE_INVALID_ARGS(thr); } @@ -4931,7 +5389,11 @@ #endif DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (after throw augment)", (duk_tval *) duk_get_tval(ctx, -1))); - duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW); + tv_val = DUK_GET_TVAL_NEGIDX(ctx, -1); + duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, tv_val); +#if defined(DUK_USE_DEBUGGER_SUPPORT) + duk_err_check_debugger_integration(thr); +#endif /* thr->heap->lj.jmpbuf_ptr is checked by duk_err_longjmp() so we don't * need to check that here. If the value is NULL, a fatal error occurs @@ -5075,7 +5537,7 @@ return duk_js_strict_equals(tv1, tv2); } -DUK_EXTERNAL_DECL duk_bool_t duk_samevalue(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) { +DUK_EXTERNAL duk_bool_t duk_samevalue(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) { duk_tval *tv1, *tv2; DUK_ASSERT_CTX_VALID(ctx); diff -Nru duktape-2.0.0/src-separate/duk_api_string.c duktape-2.1.1/src-separate/duk_api_string.c --- duktape-2.0.0/src-separate/duk_api_string.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_api_string.c 2017-07-28 22:05:08.000000000 +0000 @@ -194,6 +194,7 @@ duk_hstring *res; duk_size_t start_byte_offset; duk_size_t end_byte_offset; + duk_size_t charlen; DUK_ASSERT_CTX_VALID(ctx); @@ -201,8 +202,9 @@ h = duk_require_hstring(ctx, idx); DUK_ASSERT(h != NULL); - if (end_offset >= DUK_HSTRING_GET_CHARLEN(h)) { - end_offset = DUK_HSTRING_GET_CHARLEN(h); + charlen = DUK_HSTRING_GET_CHARLEN(h); + if (end_offset >= charlen) { + end_offset = charlen; } if (start_offset > end_offset) { start_offset = end_offset; @@ -224,9 +226,9 @@ DUK_ASSERT(end_byte_offset - start_byte_offset <= DUK_UINT32_MAX); /* Guaranteed by string limits. */ /* No size check is necessary. */ - res = duk_heap_string_intern_checked(thr, - DUK_HSTRING_GET_DATA(h) + start_byte_offset, - (duk_uint32_t) (end_byte_offset - start_byte_offset)); + 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(ctx, res); duk_replace(ctx, idx); diff -Nru duktape-2.0.0/src-separate/duk_bi_buffer.c duktape-2.1.1/src-separate/duk_bi_buffer.c --- duktape-2.0.0/src-separate/duk_bi_buffer.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_bi_buffer.c 2017-07-28 22:05:08.000000000 +0000 @@ -248,26 +248,6 @@ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); } -DUK_LOCAL duk_hbufobj *duk__push_arraybuffer_with_length(duk_context *ctx, duk_uint_t len) { - duk_hbuffer *h_val; - duk_hbufobj *h_bufobj; - - (void) duk_push_fixed_buffer_zero(ctx, (duk_size_t) len); - h_val = (duk_hbuffer *) duk_known_hbuffer(ctx, -1); - - h_bufobj = duk_push_bufobj_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), - DUK_BIDX_ARRAYBUFFER_PROTOTYPE); - DUK_ASSERT(h_bufobj != NULL); - - duk__set_bufobj_buffer(ctx, h_bufobj, h_val); - DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); - - return h_bufobj; -} - /* Shared offset/length coercion helper. */ DUK_LOCAL void duk__resolve_offset_opt_length(duk_context *ctx, duk_hbufobj *h_bufarg, @@ -721,7 +701,6 @@ duk_tval *tv; duk_hobject *h_obj; duk_hbufobj *h_bufobj = NULL; - duk_hbufobj *h_bufarr = NULL; duk_hbufobj *h_bufarg = NULL; duk_hbuffer *h_val; duk_small_uint_t magic; @@ -934,15 +913,17 @@ /* ArrayBuffer argument is handled specially above; the rest of the * argument variants are handled by shared code below. + * + * ArrayBuffer in h_bufobj->buf_prop is intentionally left unset. + * It will be automatically created by the .buffer accessor on + * first access. */ - /* Push a new ArrayBuffer (becomes view .buffer) */ - h_bufarr = duk__push_arraybuffer_with_length(ctx, byte_length); - DUK_ASSERT(h_bufarr != NULL); - h_val = h_bufarr->buf; + /* Push the resulting view object on top of a plain fixed buffer. */ + (void) duk_push_fixed_buffer(ctx, byte_length); + h_val = duk_known_hbuffer(ctx, -1); DUK_ASSERT(h_val != NULL); - /* Push the resulting view object and attach the ArrayBuffer. */ h_bufobj = duk_push_bufobj_raw(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_BUFOBJ | @@ -958,12 +939,6 @@ h_bufobj->is_typedarray = 1; DUK_ASSERT_HBUFOBJ_VALID(h_bufobj); - /* Set .buffer */ - DUK_ASSERT(h_bufobj->buf_prop == NULL); - h_bufobj->buf_prop = (duk_hobject *) h_bufarr; - DUK_ASSERT(h_bufarr != NULL); - DUK_HBUFOBJ_INCREF(thr, h_bufarr); - /* Copy values, the copy method depends on the arguments. * * Copy mode decision may depend on the validity of the underlying @@ -1681,7 +1656,7 @@ } duk_hbufobj_promote_plain(ctx, 0); - h_obj = duk_known_hobject(ctx, 0); + h_obj = duk_require_hobject(ctx, 0); /* XXX: V8 throws a TypeError for negative values. Would it * be more useful to interpret negative offsets here from the @@ -2071,7 +2046,7 @@ res_proto_bidx); DUK_ASSERT(h_bufobj != NULL); - h_bufobj->length = slice_length; + DUK_ASSERT(h_bufobj->length == 0); h_bufobj->shift = h_this->shift; /* inherit */ h_bufobj->elem_type = h_this->elem_type; /* inherit */ h_bufobj->is_typedarray = magic & 0x01; @@ -2102,12 +2077,14 @@ h_bufobj->buf = h_val; DUK_HBUFFER_INCREF(thr, h_val); + h_bufobj->length = slice_length; DUK_ASSERT(h_bufobj->offset == 0); duk_pop(ctx); /* reachable so pop OK */ } else { h_bufobj->buf = h_val; DUK_HBUFFER_INCREF(thr, h_val); + h_bufobj->length = slice_length; h_bufobj->offset = (duk_uint_t) (h_this->offset + start_offset); /* Copy the .buffer property, needed for TypedArray.prototype.subarray(). @@ -2878,30 +2855,63 @@ */ #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) +DUK_LOCAL duk_hbufobj *duk__autospawn_arraybuffer(duk_context *ctx, duk_hbuffer *h_buf) { + duk_hbufobj *h_res; + + h_res = duk_push_bufobj_raw(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_BUFOBJ | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), + DUK_BIDX_ARRAYBUFFER_PROTOTYPE); + DUK_ASSERT(h_res != NULL); + DUK_UNREF(h_res); + + duk__set_bufobj_buffer(ctx, h_res, h_buf); + DUK_ASSERT_HBUFOBJ_VALID(h_res); + DUK_ASSERT(h_res->buf_prop == NULL); + return h_res; +} + DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_context *ctx) { duk_hbufobj *h_bufobj; h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(ctx, DUK__BUFOBJ_FLAG_THROW /*flags*/); DUK_ASSERT(h_bufobj != NULL); if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) { - duk_hbufobj *h_res; - duk_hbuffer *h_buf; - - h_buf = (duk_hbuffer *) h_bufobj; - h_res = duk_push_bufobj_raw(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_BUFOBJ | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), - DUK_BIDX_ARRAYBUFFER_PROTOTYPE); - DUK_ASSERT(h_res != NULL); - DUK_UNREF(h_res); - - duk__set_bufobj_buffer(ctx, h_res, h_buf); - DUK_ASSERT_HBUFOBJ_VALID(h_res); - - DUK_DD(DUK_DDPRINT("autospawned .buffer ArrayBuffer: %!iT", duk_get_tval(ctx, -1))); + DUK_DD(DUK_DDPRINT("autospawn ArrayBuffer for plain buffer")); + (void) duk__autospawn_arraybuffer(ctx, (duk_hbuffer *) h_bufobj); return 1; } else { + if (h_bufobj->buf_prop == NULL && + DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_bufobj) != DUK_HOBJECT_CLASS_ARRAYBUFFER && + h_bufobj->buf != NULL) { + duk_hbufobj *h_arrbuf; + + DUK_DD(DUK_DDPRINT("autospawn ArrayBuffer for typed array or DataView")); + h_arrbuf = duk__autospawn_arraybuffer(ctx, h_bufobj->buf); + + if (h_bufobj->buf_prop == NULL) { + /* Must recheck buf_prop, in case ArrayBuffer + * alloc had a side effect which already filled + * it! + */ + + /* Set ArrayBuffer's .byteOffset and .byteLength based + * on the view so that Arraybuffer[view.byteOffset] + * matches view[0]. + */ + h_arrbuf->offset = 0; + DUK_ASSERT(h_bufobj->offset + h_bufobj->length >= h_bufobj->offset); /* Wrap check on creation. */ + h_arrbuf->length = h_bufobj->offset + h_bufobj->length; + DUK_ASSERT(h_arrbuf->buf_prop == NULL); + + DUK_ASSERT(h_bufobj->buf_prop == NULL); + h_bufobj->buf_prop = (duk_hobject *) h_arrbuf; + DUK_HBUFOBJ_INCREF(thr, h_arrbuf); /* Now reachable and accounted for. */ + } + + /* Left on stack; pushed for the second time below (OK). */ + } if (h_bufobj->buf_prop) { duk_push_hobject(ctx, h_bufobj->buf_prop); return 1; diff -Nru duktape-2.0.0/src-separate/duk_bi_date.c duktape-2.1.1/src-separate/duk_bi_date.c --- duktape-2.0.0/src-separate/duk_bi_date.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_bi_date.c 2017-07-28 22:05:08.000000000 +0000 @@ -1421,6 +1421,7 @@ (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATE), DUK_BIDX_DATE_PROTOTYPE); diff -Nru duktape-2.0.0/src-separate/duk_bi_date_unix.c duktape-2.1.1/src-separate/duk_bi_date_unix.c --- duktape-2.0.0/src-separate/duk_bi_date_unix.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_bi_date_unix.c 2017-07-28 22:05:08.000000000 +0000 @@ -171,7 +171,7 @@ * an mktime() error return is the cast above. See e.g.: * http://pubs.opengroup.org/onlinepubs/009695299/functions/mktime.html */ - goto error; + goto mktime_error; } DUK_DDD(DUK_DDDPRINT("t1=%ld (utc), t2=%ld (local)", (long) t1, (long) t2)); @@ -187,7 +187,7 @@ #endif return (duk_int_t) difftime(t2, t1); - error: + mktime_error: /* XXX: return something more useful, so that caller can throw? */ DUK_D(DUK_DPRINT("mktime() failed, d=%lf", (double) d)); return 0; diff -Nru duktape-2.0.0/src-separate/duk_bi_date_windows.c duktape-2.1.1/src-separate/duk_bi_date_windows.c --- duktape-2.0.0/src-separate/duk_bi_date_windows.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_bi_date_windows.c 2017-07-28 22:05:08.000000000 +0000 @@ -96,3 +96,35 @@ return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000000LL); /* seconds */ } #endif /* DUK_USE_DATE_TZO_WINDOWS */ + +#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) { + 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; + FileTimeToLocalFileTime((const FILETIME *) &ft1, &ft2); + + FileTimeToSystemTime((const FILETIME *) &ft2, &st2); + duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2); + + return (duk_int_t) (((LONGLONG) tmp2.QuadPart - (LONGLONG) tmp1.QuadPart) / 10000000LL); /* seconds */ +} +#endif /* DUK_USE_DATE_TZO_WINDOWS_NO_DST */ diff -Nru duktape-2.0.0/src-separate/duk_bi_duktape.c duktape-2.1.1/src-separate/duk_bi_duktape.c --- duktape-2.0.0/src-separate/duk_bi_duktape.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_bi_duktape.c 2017-07-28 22:05:08.000000000 +0000 @@ -29,15 +29,14 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_small_uint_t flags; - duk_bool_t rc; flags = (duk_small_uint_t) duk_get_uint(ctx, 0); - rc = duk_heap_mark_and_sweep(thr->heap, flags); + duk_heap_mark_and_sweep(thr->heap, flags); /* XXX: Not sure what the best return value would be in the API. - * Return a boolean for now. Note that rc == 0 is success (true). + * Return true for now. */ - duk_push_boolean(ctx, !rc); + duk_push_true(ctx); return 1; } @@ -49,15 +48,16 @@ * 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. + * be deleted. Must use duk_set_finalizer() to keep + * DUK_HOBJECT_FLAG_HAVE_FINALIZER in sync. */ duk_set_top(ctx, 2); - (void) duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_INT_FINALIZER); + duk_set_finalizer(ctx, 0); return 0; } else { /* Get. */ DUK_ASSERT(duk_get_top(ctx) == 1); - duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_INT_FINALIZER); + duk_get_finalizer(ctx, 0); return 1; } } diff -Nru duktape-2.0.0/src-separate/duk_bi_encoding.c duktape-2.1.1/src-separate/duk_bi_encoding.c --- duktape-2.0.0/src-separate/duk_bi_encoding.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_bi_encoding.c 2017-07-28 22:05:08.000000000 +0000 @@ -143,6 +143,7 @@ } } +#if defined(DUK_USE_ENCODING_BUILTINS) DUK_LOCAL void duk__utf8_encode_char(void *udata, duk_codepoint_t codepoint) { duk__encode_context *enc_ctx; @@ -197,6 +198,7 @@ */ enc_ctx->out += duk_unicode_encode_xutf8(codepoint, enc_ctx->out); } +#endif /* DUK_USE_ENCODING_BUILTINS */ /* Shared helper for buffer-to-string using a TextDecoder() compatible UTF-8 * decoder. @@ -360,7 +362,6 @@ DUK_ASSERT_TOP(ctx, 1); if (duk_is_undefined(ctx, 0)) { len = 0; - final_len = len; } else { duk_hstring *h_input; @@ -418,6 +419,8 @@ final_len = (duk_size_t) (enc_ctx.out - output); duk_resize_buffer(ctx, -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 @@ -458,8 +461,8 @@ * initialized explicitly. */ dec_ctx = (duk__decode_context *) duk_push_fixed_buffer(ctx, sizeof(duk__decode_context)); - dec_ctx->fatal = fatal; - dec_ctx->ignore_bom = ignore_bom; + 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_string(ctx, -2, "\xff" "Context"); diff -Nru duktape-2.0.0/src-separate/duk_bi_error.c duktape-2.1.1/src-separate/duk_bi_error.c --- duktape-2.0.0/src-separate/duk_bi_error.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_bi_error.c 2017-07-28 22:05:08.000000000 +0000 @@ -17,6 +17,7 @@ /* 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); DUK_UNREF(thr); diff -Nru duktape-2.0.0/src-separate/duk_bi_function.c duktape-2.1.1/src-separate/duk_bi_function.c --- duktape-2.0.0/src-separate/duk_bi_function.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_bi_function.c 2017-07-28 22:05:08.000000000 +0000 @@ -61,7 +61,7 @@ DUK_ASSERT_TOP(ctx, 3); /* strictness is not inherited, intentional */ - comp_flags = DUK_JS_COMPILE_FLAG_FUNCEXPR; + comp_flags = DUK_COMPILE_FUNCEXPR; duk_push_hstring_stridx(ctx, DUK_STRIDX_COMPILE); /* XXX: copy from caller? */ /* XXX: ignored now */ h_sourcecode = duk_require_hstring(ctx, -2); /* no symbol check needed; -2 is concat'd code */ @@ -202,6 +202,7 @@ /* XXX: [[Construct]] newTarget currently unsupported */ DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx); } + duk_set_top(ctx, 2); /* chop off extra arguments: [ constructor argArray ] */ idx_args = 1; break; } @@ -332,6 +333,7 @@ /* create bound function object */ h_bound = duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_BOUNDFUNC | DUK_HOBJECT_FLAG_CONSTRUCTABLE | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION), diff -Nru duktape-2.0.0/src-separate/duk_bi_global.c duktape-2.1.1/src-separate/duk_bi_global.c --- duktape-2.0.0/src-separate/duk_bi_global.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_bi_global.c 2017-07-28 22:05:08.000000000 +0000 @@ -431,7 +431,8 @@ DUK_ASSERT(duk_get_top(ctx) == 1 || duk_get_top(ctx) == 2); /* 2 when called by debugger */ DUK_ASSERT(thr->callstack_top >= 1); /* at least this function exists */ - DUK_ASSERT(((thr->callstack + thr->callstack_top - 1)->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0 || /* indirect eval */ + 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 */ /* @@ -461,8 +462,9 @@ /* [ source ] */ - comp_flags = DUK_JS_COMPILE_FLAG_EVAL; - act_eval = thr->callstack + thr->callstack_top - 1; /* this function */ + comp_flags = DUK_COMPILE_EVAL; + act_eval = thr->callstack_curr; /* this function */ + DUK_ASSERT(act_eval != NULL); if (thr->callstack_top >= (duk_size_t) -level) { /* Have a calling activation, check for direct eval (otherwise * assume indirect eval. @@ -473,7 +475,7 @@ /* Only direct eval inherits strictness from calling code * (E5.1 Section 10.1.1). */ - comp_flags |= DUK_JS_COMPILE_FLAG_STRICT; + comp_flags |= DUK_COMPILE_STRICT; } } else { DUK_ASSERT((act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0); @@ -493,7 +495,7 @@ /* E5 Section 10.4.2 */ DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; /* this function */ + act = thr->callstack_curr; /* this function */ if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) { DUK_ASSERT(thr->callstack_top >= 2); act = thr->callstack + thr->callstack_top + level; /* caller */ @@ -511,26 +513,29 @@ this_to_global = 0; if (DUK_HOBJECT_HAS_STRICT((duk_hobject *) func)) { - duk_hobject *new_env; + 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 = thr->callstack + thr->callstack_top + level; /* caller */ act_lex_env = act->lex_env; act = NULL; /* invalidated */ - new_env = duk_push_object_helper_proto(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), - act_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(ctx, (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 = new_env; - outer_var_env = new_env; + outer_lex_env = (duk_hobject *) new_env; + outer_var_env = (duk_hobject *) new_env; duk_insert(ctx, 0); /* stash to bottom of value stack to keep new_env reachable for duration of eval */ @@ -560,7 +565,7 @@ /* 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*/); - /* [ source template closure ] */ + /* [ env? source template closure ] */ if (this_to_global) { DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); @@ -579,11 +584,11 @@ (duk_heaphdr *) outer_var_env, duk_get_tval(ctx, -1))); - /* [ source template closure this ] */ + /* [ env? source template closure this ] */ duk_call_method(ctx, 0); - /* [ source template result ] */ + /* [ env? source template result ] */ return 1; } diff -Nru duktape-2.0.0/src-separate/duk_bi_json.c duktape-2.1.1/src-separate/duk_bi_json.c --- duktape-2.0.0/src-separate/duk_bi_json.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_bi_json.c 2017-07-28 22:05:08.000000000 +0000 @@ -73,12 +73,15 @@ DUK_LOCAL_DECL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv); #endif #if defined(DUK_USE_JX) || defined(DUK_USE_JC) -DUK_LOCAL_DECL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h); +DUK_LOCAL_DECL void duk__enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h); DUK_LOCAL_DECL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr); #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) DUK_LOCAL_DECL void duk__enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj); #endif #endif +#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) +DUK_LOCAL_DECL void duk__enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h); +#endif DUK_LOCAL_DECL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth); /* @@ -1558,13 +1561,60 @@ DUK_BW_SET_PTR(thr, &js_ctx->bw, q); } -DUK_LOCAL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) { +DUK_LOCAL void duk__enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) { duk__enc_buffer_data(js_ctx, (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h), (duk_size_t) DUK_HBUFFER_GET_SIZE(h)); } #endif /* DUK_USE_JX || DUK_USE_JC */ +#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) +DUK_LOCAL void duk__enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) { + duk_size_t i, n; + const duk_uint8_t *buf; + duk_uint8_t *q; + + n = DUK_HBUFFER_GET_SIZE(h); + if (n == 0) { + DUK__EMIT_2(js_ctx, DUK_ASC_LCURLY, DUK_ASC_RCURLY); + return; + } + + DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY); + + /* Maximum encoded length with 32-bit index: 1 + 10 + 2 + 3 + 1 + 1 = 18, + * with 64-bit index: 1 + 20 + 2 + 3 + 1 + 1 = 28. 32 has some spare. + * + * Note that because the output buffer is reallocated from time to time, + * side effects (such as finalizers) affecting the buffer 'h' must be + * disabled. This is the case in the JSON.stringify() fast path. + */ + + buf = (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h); + if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { + for (i = 0; i < n; i++) { + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth + 1); + q = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, 32); + q += DUK_SPRINTF((char *) q, "\"%lu\": %u,", (unsigned long) i, (unsigned int) buf[i]); + DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, q); + } + } else { + q = DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw); + for (i = 0; i < n; i++) { + q = DUK_BW_ENSURE_RAW(js_ctx->thr, &js_ctx->bw, 32, q); + q += DUK_SPRINTF((char *) q, "\"%lu\":%u,", (unsigned long) i, (unsigned int) buf[i]); + } + DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, q); + } + DUK__UNEMIT_1(js_ctx); /* eat trailing comma */ + + if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth); + } + DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY); +} +#endif /* DUK_USE_JSON_STRINGIFY_FASTPATH */ + #if defined(DUK_USE_JX) || defined(DUK_USE_JC) DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) { char buf[64]; /* XXX: how to figure correct size? */ @@ -2114,7 +2164,7 @@ case DUK_TAG_STRING: { duk_hstring *h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { goto pop2_undef; } duk__enc_quote_string(js_ctx, h); @@ -2145,12 +2195,13 @@ case DUK_TAG_BUFFER: { #if defined(DUK_USE_JX) || defined(DUK_USE_JC) if (js_ctx->flag_ext_custom_or_compatible) { - duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv)); + duk__enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv)); break; } #endif - /* Could implement a fast path, but object coerce and - * serialize the result for now. + + /* Could implement a fastpath, but the fast path would need + * to handle realloc side effects correctly. */ duk_to_object(ctx, -1); duk__enc_object(js_ctx); @@ -2210,7 +2261,7 @@ duk_hstring *h; h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { return 0; } return 1; @@ -2279,7 +2330,7 @@ duk_hstring *h; h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { goto emit_undefined; } duk__enc_quote_string(js_ctx, h); @@ -2444,7 +2495,7 @@ DUK_DD(DUK_DDPRINT("property is an accessor, abort fast path")); goto abort_fastpath; } - if (DUK_HSTRING_HAS_SYMBOL(k)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(k))) { continue; } @@ -2638,13 +2689,16 @@ #if defined(DUK_USE_JX) || defined(DUK_USE_JC) if (js_ctx->flag_ext_custom_or_compatible) { - duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv)); + duk__enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv)); break; } #endif - /* Could implement a fast path, but abort fast path for now. */ - DUK_DD(DUK_DDPRINT("value is a plain buffer and serializing as plain JSON, abort fast path")); - goto abort_fastpath; + + /* Plain buffers mimic Uint8Arrays, and have enumerable index + * properties. + */ + duk__enc_buffer_json_fastpath(js_ctx, DUK_TVAL_GET_BUFFER(tv)); + break; } case DUK_TAG_POINTER: { #if defined(DUK_USE_JX) || defined(DUK_USE_JC) @@ -3041,8 +3095,11 @@ } if (js_ctx->h_gap != NULL) { - /* if gap is empty, behave as if not given at all */ - if (DUK_HSTRING_GET_CHARLEN(js_ctx->h_gap) == 0) { + /* If gap is empty, behave as if not given at all. Check + * against byte length because character length is more + * expensive. + */ + if (DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) == 0) { js_ctx->h_gap = NULL; } } @@ -3058,7 +3115,7 @@ if (js_ctx->h_replacer == NULL && /* replacer is a mutation risk */ js_ctx->idx_proplist == -1) { /* proplist is very rare */ duk_int_t pcall_rc; - duk_small_uint_t prev_mark_and_sweep_base_flags; + duk_small_uint_t prev_ms_base_flags; DUK_DD(DUK_DDPRINT("try JSON.stringify() fast path")); @@ -3080,14 +3137,17 @@ duk_dup(ctx, idx_value); /* Must prevent finalizers which may have arbitrary side effects. */ - prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags; - thr->heap->mark_and_sweep_base_flags |= - DUK_MS_FLAG_NO_FINALIZERS | /* avoid attempts to add/remove object keys */ - DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid attempt to compact any objects */ + prev_ms_base_flags = thr->heap->ms_base_flags; + thr->heap->ms_base_flags |= + DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* Avoid attempt to compact any objects. */ + thr->heap->pf_prevent_count++; /* Prevent finalizers. */ + DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */ pcall_rc = duk_safe_call(ctx, duk__json_stringify_fast, (void *) js_ctx /*udata*/, 1 /*nargs*/, 0 /*nret*/); - thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; + DUK_ASSERT(thr->heap->pf_prevent_count > 0); + thr->heap->pf_prevent_count--; + thr->heap->ms_base_flags = prev_ms_base_flags; if (pcall_rc == DUK_EXEC_SUCCESS) { DUK_DD(DUK_DDPRINT("fast path successful")); diff -Nru duktape-2.0.0/src-separate/duk_bi_object.c duktape-2.1.1/src-separate/duk_bi_object.c --- duktape-2.0.0/src-separate/duk_bi_object.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_bi_object.c 2017-07-28 22:05:08.000000000 +0000 @@ -50,6 +50,7 @@ (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), DUK_BIDX_OBJECT_PROTOTYPE); return 1; @@ -112,6 +113,7 @@ (void) duk_push_object_helper_proto(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), proto); diff -Nru duktape-2.0.0/src-separate/duk_bi_pointer.c duktape-2.1.1/src-separate/duk_bi_pointer.c --- duktape-2.0.0/src-separate/duk_bi_pointer.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_bi_pointer.c 2017-07-28 22:05:08.000000000 +0000 @@ -24,6 +24,7 @@ if (duk_is_constructor_call(ctx)) { (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER), DUK_BIDX_POINTER_PROTOTYPE); diff -Nru duktape-2.0.0/src-separate/duk_bi_protos.h duktape-2.1.1/src-separate/duk_bi_protos.h --- duktape-2.0.0/src-separate/duk_bi_protos.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_bi_protos.h 2017-07-28 22:05:08.000000000 +0000 @@ -37,6 +37,9 @@ #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_context *ctx, const char *str); #endif diff -Nru duktape-2.0.0/src-separate/duk_bi_proxy.c duktape-2.1.1/src-separate/duk_bi_proxy.c --- duktape-2.0.0/src-separate/duk_bi_proxy.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_bi_proxy.c 2017-07-28 22:05:08.000000000 +0000 @@ -46,7 +46,7 @@ goto skip_key; } } - if (DUK_HSTRING_HAS_SYMBOL(h)) { + 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(ctx, -1))); goto skip_key; @@ -123,6 +123,7 @@ */ (void) duk_push_object_helper_proto(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), NULL); diff -Nru duktape-2.0.0/src-separate/duk_bi_string.c duktape-2.1.1/src-separate/duk_bi_string.c --- duktape-2.0.0/src-separate/duk_bi_string.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_bi_string.c 2017-07-28 22:05:08.000000000 +0000 @@ -20,6 +20,96 @@ #if defined(DUK_USE_STRING_BUILTIN) /* + * Helpers + */ + +DUK_LOCAL duk_hstring *duk__str_tostring_notregexp(duk_context *ctx, duk_idx_t idx) { + duk_hstring *h; + + if (duk_get_class_number(ctx, idx) == DUK_HOBJECT_CLASS_REGEXP) { + DUK_ERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx); + } + h = duk_to_hstring(ctx, idx); + DUK_ASSERT(h != NULL); + + return h; +} + +DUK_LOCAL duk_int_t duk__str_search_shared(duk_context *ctx, duk_hstring *h_this, duk_hstring *h_search, duk_int_t start_cpos, duk_bool_t backwards) { + duk_int_t cpos; + duk_int_t bpos; + const duk_uint8_t *p_start, *p_end, *p; + const duk_uint8_t *q_start; + duk_int_t q_blen; + duk_uint8_t firstbyte; + duk_uint8_t t; + + cpos = start_cpos; + + /* Empty searchstring always matches; cpos must be clamped here. + * (If q_blen were < 0 due to clamped coercion, it would also be + * caught here.) + */ + q_start = DUK_HSTRING_GET_DATA(h_search); + q_blen = (duk_int_t) DUK_HSTRING_GET_BYTELEN(h_search); + if (q_blen <= 0) { + return cpos; + } + DUK_ASSERT(q_blen > 0); + + bpos = (duk_int_t) duk_heap_strcache_offset_char2byte((duk_hthread *) ctx, h_this, (duk_uint32_t) cpos); + + p_start = DUK_HSTRING_GET_DATA(h_this); + p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_this); + p = p_start + bpos; + + /* This loop is optimized for size. For speed, there should be + * two separate loops, and we should ensure that memcmp() can be + * used without an extra "will searchstring fit" check. Doing + * the preconditioning for 'p' and 'p_end' is easy but cpos + * must be updated if 'p' is wound back (backward scanning). + */ + + firstbyte = q_start[0]; /* leading byte of match string */ + while (p <= p_end && p >= p_start) { + t = *p; + + /* For Ecmascript strings, this check can only match for + * initial UTF-8 bytes (not continuation bytes). For other + * strings all bets are off. + */ + + if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= (duk_size_t) q_blen)) { + DUK_ASSERT(q_blen > 0); /* no issues with memcmp() zero size, even if broken */ + if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { + return cpos; + } + } + + /* track cpos while scanning */ + if (backwards) { + /* when going backwards, we decrement cpos 'early'; + * 'p' may point to a continuation byte of the char + * at offset 'cpos', but that's OK because we'll + * backtrack all the way to the initial byte. + */ + if ((t & 0xc0) != 0x80) { + cpos--; + } + p--; + } else { + if ((t & 0xc0) != 0x80) { + cpos++; + } + p++; + } + } + + /* Not found. Empty string case is handled specially above. */ + return -1; +} + +/* * Constructor */ @@ -41,7 +131,7 @@ duk_push_hstring_empty(ctx); } else { h = duk_to_hstring_acceptsymbol(ctx, 0); - if (DUK_HSTRING_HAS_SYMBOL(h) && !duk_is_constructor_call(ctx)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h) && !duk_is_constructor_call(ctx))) { duk_push_symbol_descriptive_string(ctx, h); duk_replace(ctx, 0); } @@ -53,6 +143,7 @@ if (duk_is_constructor_call(ctx)) { /* String object internal value is immutable */ flags = DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING); duk_push_object_helper(ctx, flags, DUK_BIDX_STRING_PROTOTYPE); @@ -202,7 +293,7 @@ pos = duk_to_int_clamped_raw(ctx, 0 /*index*/, 0 /*min(incl)*/, - DUK_HSTRING_GET_CHARLEN(h) - 1 /*max(incl)*/, + (duk_int_t) DUK_HSTRING_GET_CHARLEN(h) - 1 /*max(incl)*/, &clamped /*out_clamped*/); #if defined(DUK_USE_ES6) magic = duk_get_current_magic(ctx); @@ -364,17 +455,10 @@ */ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx) { - duk_hthread *thr = (duk_hthread *) ctx; duk_hstring *h_this; duk_hstring *h_search; duk_int_t clen_this; duk_int_t cpos; - duk_int_t bpos; - const duk_uint8_t *p_start, *p_end, *p; - const duk_uint8_t *q_start; - duk_int_t q_blen; - duk_uint8_t firstbyte; - duk_uint8_t t; duk_small_int_t is_lastindexof = duk_get_current_magic(ctx); /* 0=indexOf, 1=lastIndexOf */ h_this = duk_push_this_coercible_to_string(ctx); @@ -383,8 +467,6 @@ h_search = duk_to_hstring(ctx, 0); DUK_ASSERT(h_search != NULL); - q_start = DUK_HSTRING_GET_DATA(h_search); - q_blen = (duk_int_t) DUK_HSTRING_GET_BYTELEN(h_search); duk_to_number(ctx, 1); if (duk_is_nan(ctx, 1) && is_lastindexof) { @@ -397,67 +479,8 @@ cpos = duk_to_int_clamped(ctx, 1, 0, clen_this); } - /* Empty searchstring always matches; cpos must be clamped here. - * (If q_blen were < 0 due to clamped coercion, it would also be - * caught here.) - */ - if (q_blen <= 0) { - duk_push_int(ctx, cpos); - return 1; - } - DUK_ASSERT(q_blen > 0); - - bpos = (duk_int_t) duk_heap_strcache_offset_char2byte(thr, h_this, (duk_uint32_t) cpos); - - p_start = DUK_HSTRING_GET_DATA(h_this); - p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_this); - p = p_start + bpos; - - /* This loop is optimized for size. For speed, there should be - * two separate loops, and we should ensure that memcmp() can be - * used without an extra "will searchstring fit" check. Doing - * the preconditioning for 'p' and 'p_end' is easy but cpos - * must be updated if 'p' is wound back (backward scanning). - */ - - firstbyte = q_start[0]; /* leading byte of match string */ - while (p <= p_end && p >= p_start) { - t = *p; - - /* For Ecmascript strings, this check can only match for - * initial UTF-8 bytes (not continuation bytes). For other - * strings all bets are off. - */ - - if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= (duk_size_t) q_blen)) { - DUK_ASSERT(q_blen > 0); /* no issues with memcmp() zero size, even if broken */ - if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { - duk_push_int(ctx, cpos); - return 1; - } - } - - /* track cpos while scanning */ - if (is_lastindexof) { - /* when going backwards, we decrement cpos 'early'; - * 'p' may point to a continuation byte of the char - * at offset 'cpos', but that's OK because we'll - * backtrack all the way to the initial byte. - */ - if ((t & 0xc0) != 0x80) { - cpos--; - } - p--; - } else { - if ((t & 0xc0) != 0x80) { - cpos++; - } - p++; - } - } - - /* Not found. Empty string case is handled specially above. */ - duk_push_int(ctx, -1); + cpos = duk__str_search_shared(ctx, h_this, h_search, cpos, is_lastindexof /*backwards*/); + duk_push_int(ctx, cpos); return 1; } @@ -754,9 +777,10 @@ /* Use match charlen instead of bytelen, just in case the input and * match codepoint encodings would have different lengths. */ + /* XXX: charlen computed here, and also in char2byte helper. */ match_end_boff = duk_heap_strcache_offset_char2byte(thr, h_input, - match_start_coff + DUK_HSTRING_GET_CHARLEN(h_match)); + match_start_coff + (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h_match)); tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - match_end_boff); DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + match_end_boff, tmp_sz); @@ -1106,7 +1130,7 @@ DUK_DDD(DUK_DDDPRINT("split trailer; prev_end b=%ld,c=%ld", (long) prev_match_end_boff, (long) prev_match_end_coff)); - if (DUK_HSTRING_GET_CHARLEN(h_input) > 0 || !matched) { + if (DUK_HSTRING_GET_BYTELEN(h_input) > 0 || !matched) { /* Add trailer if: * a) non-empty input * b) empty input and no (zero size) match found (step 11) @@ -1366,10 +1390,10 @@ } else { DUK_MEMCPY((void *) p, (const void *) src, copy_size); p += copy_size; - copy_size *= 2; } src = (const duk_uint8_t *) buf; /* Use buf as source for larger copies. */ + copy_size = (duk_size_t) (p - buf); } #endif /* DUK_USE_PREFER_SIZE */ @@ -1448,4 +1472,91 @@ return 1; } +#if defined(DUK_USE_ES6) +DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_context *ctx) { + duk_int_t magic; + duk_hstring *h; + duk_hstring *h_search; + duk_size_t blen_search; + const duk_uint8_t *p_cmp_start; + duk_bool_t result; + + h = duk_push_this_coercible_to_string(ctx); + DUK_ASSERT(h != NULL); + + h_search = duk__str_tostring_notregexp(ctx, 0); + DUK_ASSERT(h_search != NULL); + + magic = duk_get_current_magic(ctx); + + p_cmp_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h); + blen_search = DUK_HSTRING_GET_BYTELEN(h_search); + + if (duk_is_undefined(ctx, 1)) { + if (magic) { + p_cmp_start += DUK_HSTRING_GET_BYTELEN(h) - blen_search; + } else { + /* p_cmp_start already OK */ + } + } else { + duk_int_t len; + duk_int_t pos; + + DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= DUK_INT_MAX); + len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h); + pos = duk_to_int_clamped(ctx, 1, 0, len); + DUK_ASSERT(pos >= 0 && pos <= len); + + if (magic) { + p_cmp_start -= blen_search; /* Conceptually subtracted last, but do already here. */ + } + DUK_ASSERT(pos >= 0 && pos <= len); + + p_cmp_start += duk_heap_strcache_offset_char2byte((duk_hthread *) ctx, h, pos); + } + + /* The main comparison can be done using a memcmp() rather than + * doing codepoint comparisons: for CESU-8 strings there is a + * canonical representation for every codepoint. But we do need + * to deal with the char/byte offset translation to find the + * comparison range. + */ + + result = 0; + if (p_cmp_start >= DUK_HSTRING_GET_DATA(h) && + p_cmp_start - (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h) + blen_search <= DUK_HSTRING_GET_BYTELEN(h)) { + if (DUK_MEMCMP((const void *) p_cmp_start, + (const void *) DUK_HSTRING_GET_DATA(h_search), + (size_t) blen_search) == 0) { + result = 1; + } + } + + duk_push_boolean(ctx, result); + return 1; +} +#endif /* DUK_USE_ES6 */ + +#if defined(DUK_USE_ES6) +DUK_INTERNAL duk_ret_t duk_bi_string_prototype_includes(duk_context *ctx) { + duk_hstring *h; + duk_hstring *h_search; + duk_int_t len; + duk_int_t pos; + + h = duk_push_this_coercible_to_string(ctx); + DUK_ASSERT(h != NULL); + + h_search = duk__str_tostring_notregexp(ctx, 0); + DUK_ASSERT(h_search != NULL); + + len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h); + pos = duk_to_int_clamped(ctx, 1, 0, len); + DUK_ASSERT(pos >= 0 && pos <= len); + + pos = duk__str_search_shared(ctx, h, h_search, pos, 0 /*backwards*/); + duk_push_boolean(ctx, pos >= 0); + return 1; +} +#endif /* DUK_USE_ES6 */ #endif /* DUK_USE_STRING_BUILTIN */ diff -Nru duktape-2.0.0/src-separate/duk_bi_symbol.c duktape-2.1.1/src-separate/duk_bi_symbol.c --- duktape-2.0.0/src-separate/duk_bi_symbol.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_bi_symbol.c 2017-07-28 22:05:08.000000000 +0000 @@ -104,7 +104,8 @@ h_str = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h_str != NULL); - if (!DUK_HSTRING_HAS_SYMBOL(h_str)) { + /* Here symbol is more expected than not. */ + if (DUK_UNLIKELY(!DUK_HSTRING_HAS_SYMBOL(h_str))) { return NULL; } @@ -124,6 +125,7 @@ duk_push_symbol_descriptive_string(ctx, h_str); } else { /* .valueOf() */ + duk_push_hstring(ctx, h_str); } return 1; } diff -Nru duktape-2.0.0/src-separate/duk_bi_thread.c duktape-2.1.1/src-separate/duk_bi_thread.c --- duktape-2.0.0/src-separate/duk_bi_thread.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_bi_thread.c 2017-07-28 22:05:08.000000000 +0000 @@ -79,11 +79,12 @@ DUK_DD(DUK_DDPRINT("resume state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.resume)")); goto state_error; } - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); /* us */ - DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL); /* caller */ + DUK_ASSERT(thr->callstack_curr != 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 - 1) != NULL); /* caller */ - caller_func = DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2); + caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr - 1); if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) { DUK_DD(DUK_DDPRINT("resume state invalid: caller must be Ecmascript code")); goto state_error; @@ -233,11 +234,12 @@ DUK_DD(DUK_DDPRINT("yield state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.yield)")); goto state_error; } - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); /* us */ - DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL); /* caller */ + DUK_ASSERT(thr->callstack_curr != 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 - 1) != NULL); /* caller */ - caller_func = DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2); + caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr - 1); if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) { DUK_DD(DUK_DDPRINT("yield state invalid: caller must be Ecmascript code")); goto state_error; diff -Nru duktape-2.0.0/src-separate/duk_builtins.c duktape-2.1.1/src-separate/duk_builtins.c --- duktape-2.0.0/src-separate/duk_builtins.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_builtins.c 2017-07-28 22:05:08.000000000 +0000 @@ -4,10 +4,16 @@ #include "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[921] = { +DUK_INTERNAL const duk_uint8_t duk_strings_data[903] = { 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, @@ -35,31 +41,31 @@ 171,115,147,136,4,65,130,96,35,64,194,32,168,89,56,208,48,135,123,144,217, 146,38,220,229,64,186,16,187,156,105,47,52,238,112,56,153,4,225,145,27,156, 43,162,192,46,71,220,229,65,22,1,231,220,228,157,72,136,136,220,227,197, -164,180,52,133,220,224,34,105,19,115,140,3,207,185,202,130,36,109,85,185, -194,161,160,90,50,72,163,115,135,3,70,178,68,251,156,16,22,178,16,251,156, -153,226,64,13,27,156,137,12,16,72,135,220,228,193,19,18,101,220,228,206, -137,28,78,99,208,178,21,13,125,38,146,70,60,20,72,9,145,4,140,121,51,197, -214,25,27,81,156,151,48,65,34,107,106,9,55,18,68,104,146,84,97,31,191,189, -181,70,140,133,222,249,212,227,66,125,245,187,251,219,77,3,119,190,117,56, -208,159,125,110,254,246,210,26,93,239,157,78,52,39,223,93,191,189,180,212, -52,187,223,58,156,104,79,190,187,127,123,104,180,104,183,190,117,56,208, -159,125,102,254,209,104,209,124,234,113,161,62,250,80,196,128,81,4,9,16, -162,4,196,116,9,205,154,27,66,32,100,13,12,98,68,227,33,65,69,204,195,34, -201,50,8,110,33,23,34,28,168,104,22,188,12,174,138,11,70,138,104,115,68, -130,137,13,82,27,41,129,162,35,138,54,146,198,137,39,72,180,210,178,38,35, -146,103,68,139,51,197,214,28,227,131,79,15,35,138,58,130,37,19,155,41,146, -174,64,203,99,161,100,37,145,51,148,75,4,164,66,54,140,49,46,247,70,103,37, -230,70,142,70,67,30,232,204,178,163,201,18,54,139,89,39,26,16,165,2,228,69, -33,143,89,24,70,206,73,67,102,72,148,2,32,214,73,157,224,18,128,98,29,241, -69,65,50,37,241,116,200,41,144,102,125,2,180,8,210,152,38,129,23,8,34,198, +164,180,52,133,220,228,206,137,23,115,128,137,164,77,206,48,15,62,231,42,8, +145,181,86,231,10,134,129,104,201,34,125,206,76,17,49,38,141,206,28,13,26, +201,19,137,204,122,22,66,161,175,164,210,72,199,130,137,1,50,32,145,143,38, +120,186,195,35,106,51,146,230,8,36,77,109,65,38,226,72,141,18,74,140,35, +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: 164 */ -DUK_INTERNAL const duk_c_function duk_bi_native_functions[164] = { +/* native functions: 166 */ +DUK_INTERNAL const duk_c_function duk_bi_native_functions[166] = { NULL, duk_bi_array_constructor, duk_bi_array_constructor_is_array, @@ -194,6 +200,7 @@ 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, @@ -202,6 +209,7 @@ 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, @@ -226,535 +234,541 @@ duk_bi_uint8array_plainof, }; #if defined(DUK_USE_DOUBLE_LE) -DUK_INTERNAL const duk_uint8_t duk_builtins_data[3790] = { +DUK_INTERNAL const duk_uint8_t duk_builtins_data[3819] = { 144,148,105,221,32,68,52,228,62,12,104,200,165,134,148,248,81,77,61,191, 135,35,154,103,34,72,6,157,159,197,145,77,245,126,52,130,106,234,163,196, 52,226,18,51,161,26,113,1,60,37,64,190,18,49,116,116,33,26,113,1,92,136,26, 98,112,145,139,163,165,8,211,136,14,228,72,82,68,141,17,56,72,197,209,212, 132,105,196,5,242,88,108,193,126,18,49,116,117,161,26,113,1,60,158,30,78, -18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,224,59, -147,60,93,110,79,15,39,9,24,186,33,13,63,79,185,39,26,121,223,110,77,66,53, -116,1,120,248,186,248,136,67,76,196,200,134,186,137,177,13,31,192,174,79, -15,32,248,8,196,24,8,107,254,39,97,161,175,248,159,16,215,252,80,186,26, -255,138,57,136,107,254,41,100,33,175,248,167,170,134,191,226,166,138,26, -255,138,187,40,107,254,43,111,33,171,86,181,16,209,241,11,228,201,121,240, -141,19,134,72,196,52,123,168,95,38,75,207,131,32,156,50,70,33,195,3,152, -128,0,0,0,0,0,1,240,255,153,128,0,0,0,0,0,1,224,255,151,137,0,214,9,188,35, -131,12,225,196,56,177,78,60,99,147,28,229,200,57,162,120,74,129,124,36,98, -232,156,241,92,136,26,98,112,145,139,162,116,71,114,36,41,34,70,136,156,36, -98,232,157,49,124,150,27,48,95,132,140,93,19,170,39,147,195,201,194,70,46, -137,215,17,218,69,4,236,98,232,157,153,39,110,81,220,15,193,209,83,3,200, -119,130,241,241,117,240,120,80,252,137,10,178,10,103,134,180,122,9,135,136, -154,120,169,199,142,158,121,10,7,146,162,121,74,71,150,166,121,138,135,154, -170,121,202,199,158,23,201,146,243,225,26,39,12,145,61,16,190,76,151,159,6, -65,56,100,137,233,35,93,205,144,33,224,140,137,196,54,121,244,5,60,17,145, -56,85,184,19,207,16,21,18,227,65,198,231,72,16,137,112,168,106,38,76,225,2, -70,65,56,100,237,34,140,177,4,134,65,56,100,237,34,129,117,204,123,154,70, -207,46,64,146,52,78,25,59,72,163,48,65,34,52,78,25,59,72,160,93,115,30,230, -145,179,204,144,24,146,16,30,76,209,2,40,210,72,64,121,52,4,0,156,88,97,5, -194,96,227,18,124,124,93,55,79,15,39,28,94,49,38,159,154,136,96,196,159,29, -102,241,241,115,201,25,227,131,36,133,20,62,110,142,253,2,102,36,248,235, -55,143,139,158,72,207,28,104,24,73,112,201,3,2,82,65,155,187,94,6,20,72,9, -147,120,128,225,144,168,105,56,248,185,228,140,241,190,96,128,200,84,52, -156,124,92,242,70,104,36,183,168,4,145,0,190,41,1,139,18,19,36,226,146,17, -124,73,82,54,124,37,230,70,201,14,108,184,132,8,68,185,34,1,100,31,8,129,8, -151,11,23,100,141,225,18,12,68,184,75,204,141,146,2,178,112,72,8,162,98,92, -50,10,152,147,227,172,222,62,46,121,35,60,114,88,96,92,185,112,201,65,34, -92,4,1,147,81,159,141,205,32,234,121,96,97,57,64,97,121,128,14,56,37,199, -89,188,124,92,242,70,120,227,144,53,18,227,226,233,186,120,121,56,226,242, -8,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,36,136,48,64,114,0, -250,156,168,1,64,247,175,25,36,2,8,11,94,80,248,16,40,104,242,103,200,48, -193,3,162,92,4,98,12,41,14,66,40,106,101,1,132,130,8,24,78,104,129,54,62, -96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,178, -58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,129, -232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,201, -126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,132, -0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,46, -36,29,4,78,69,6,60,226,31,192,7,255,252,24,160,163,11,23,51,130,56,35,193, -56,100,238,31,6,150,46,103,4,225,147,143,114,27,62,233,241,200,137,182,133, -42,142,167,216,6,23,216,0,97,28,17,224,39,223,32,80,142,8,240,78,25,56,9, -248,8,22,39,12,156,123,144,217,240,19,240,18,6,19,154,32,79,194,124,14,134, -140,151,227,139,226,52,11,88,37,62,33,163,37,248,226,248,141,32,213,184,64, -89,56,39,49,224,137,60,100,5,96,38,35,249,8,15,18,61,96,17,60,200,6,145,1, -17,31,206,64,89,45,2,39,161,0,178,122,209,63,74,2,101,64,202,113,67,77,235, -64,92,221,197,186,196,143,4,9,19,188,1,25,187,139,112,128,178,113,110,177, -35,193,2,68,239,0,46,110,229,30,242,71,130,4,137,222,4,35,55,113,110,16,22, -78,81,239,36,120,32,72,157,224,64,147,138,25,237,0,52,72,242,2,126,82,3,74, -129,148,227,234,66,12,112,28,140,155,104,203,169,158,9,133,158,4,25,36,1, -61,96,47,181,80,46,132,129,255,255,255,255,255,255,222,254,39,172,67,118, -170,5,208,144,0,64,0,0,0,0,0,0,51,16,0,0,0,0,0,0,62,31,200,245,238,146,38, -138,147,105,13,42,26,137,226,0,0,0,0,0,0,7,131,249,30,180,134,4,209,82,109, -33,165,67,81,60,64,0,0,0,0,0,0,240,255,28,144,155,104,0,0,0,0,0,0,0,0,16, -117,59,130,48,155,98,48,187,144,3,205,220,42,46,65,237,72,27,55,112,151, -123,154,70,205,0,94,208,129,115,119,31,18,9,18,67,155,183,34,12,176,96,175, -4,100,74,228,3,237,38,43,31,192,109,117,171,0,228,164,219,72,0,0,0,0,0,0, -248,127,196,234,111,0,50,110,224,193,50,114,83,138,26,107,192,131,38,238, -77,12,39,37,56,161,166,188,11,132,188,12,74,110,226,220,32,44,156,24,38,78, -74,113,67,77,120,28,148,221,197,184,64,89,57,52,48,156,148,226,134,154,240, -64,195,94,8,56,123,193,11,85,116,140,45,240,3,152,147,228,208,194,95,0,89, -137,62,22,139,95,48,64,70,200,67,28,98,79,180,152,139,218,45,124,193,1,27, -33,16,65,137,62,49,205,153,236,132,81,102,36,251,73,137,157,115,102,123,33, -24,57,137,62,12,19,37,144,142,40,196,159,105,49,15,160,153,44,132,128,198, -36,248,48,98,200,73,18,98,79,180,152,135,208,98,200,74,16,98,79,135,117,35, -43,33,44,89,137,62,210,98,63,93,72,202,200,76,20,98,79,140,67,105,50,74, -200,77,26,98,79,180,152,153,212,54,147,36,172,132,225,70,36,249,34,9,205, -28,172,132,241,166,36,251,73,138,93,32,156,209,202,200,80,30,98,79,140,66, -214,137,16,78,104,229,100,40,146,49,39,218,76,76,234,22,180,72,130,115,71, -43,33,72,137,137,62,77,12,38,92,210,113,197,44,137,59,64,7,145,39,201,161, -132,184,64,249,18,124,98,22,180,72,130,115,71,43,101,76,148,137,62,210,98, -103,80,181,162,68,19,154,57,91,42,130,164,73,242,68,19,154,57,91,95,84,108, -137,62,210,98,151,72,39,52,114,182,190,176,169,18,124,98,27,73,146,86,223, -215,27,34,79,180,152,153,212,54,147,36,173,191,176,34,68,159,14,234,70,86, -231,217,23,34,79,180,152,143,215,82,50,183,62,208,121,18,124,24,38,75,101, -108,84,137,62,210,98,31,65,50,91,43,130,36,73,241,142,108,207,109,125,209, -114,36,251,73,137,157,115,102,123,107,239,11,145,39,194,209,107,230,8,8, -219,127,124,116,137,62,210,98,47,104,181,243,4,4,109,191,192,135,49,39,204, -16,17,178,24,32,242,36,249,130,2,54,203,7,6,104,14,76,131,140,144,0,0,0,0, -0,0,0,1,141,207,215,12,78,126,193,46,190,126,192,98,179,246,4,197,231,236, -10,193,9,114,11,172,64,73,146,83,236,145,169,237,1,6,120,14,78,129,179,40, -249,18,149,175,207,141,199,27,76,248,156,81,177,207,139,198,9,169,199,129, -58,136,19,202,11,179,20,240,149,2,248,72,197,209,200,148,162,117,48,39,148, -151,102,42,228,64,211,19,132,140,93,28,137,74,39,85,2,121,81,118,98,238,68, -133,36,72,209,19,132,140,93,28,137,74,39,87,2,121,89,118,98,190,75,13,152, -47,194,70,46,142,68,165,19,172,129,60,176,187,49,79,39,135,147,132,140,93, -28,137,74,39,91,2,121,105,118,98,142,210,40,39,99,23,71,34,82,135,8,128, -120,72,13,42,226,145,97,87,224,168,1,58,182,232,232,64,22,85,181,187,177, -107,2,64,7,213,183,74,7,121,207,215,242,17,119,49,248,94,173,198,210,36,15, -232,34,182,84,113,95,115,240,221,91,141,163,160,72,1,220,164,194,175,121, -123,103,224,186,244,64,24,45,68,84,251,33,9,64,15,217,66,51,209,218,210, -129,154,118,254,205,61,65,204,126,23,178,132,103,165,3,52,237,253,154,122, -131,216,252,167,224,121,44,48,46,95,203,166,238,74,113,67,77,201,128,219, -152,164,82,6,0,203,76,64,64,9,210,211,18,4,4,144,221,49,40,64,76,13,211,19, -5,4,192,221,45,66,1,4,24,207,76,82,2,8,136,94,152,156,24,157,45,49,64,6,75, -191,76,80,66,149,110,116,116,197,8,41,240,247,79,70,188,6,183,27,76,80,194, -45,198,210,211,20,144,171,113,180,116,52,197,40,27,1,125,34,240,27,16,221, -42,240,27,221,109,66,32,104,129,163,115,52,224,5,139,168,209,233,138,32,57, -33,186,98,138,18,80,140,244,197,24,28,192,221,49,71,11,56,209,162,211,20, -183,1,66,188,17,145,52,40,9,148,226,134,153,5,198,137,136,32,14,12,30,164, -140,144,230,192,0,0,0,0,0,136,211,64,182,120,43,135,126,16,68,52,174,195, -144,12,2,158,4,128,70,22,24,128,101,67,112,163,192,100,104,176,131,192,99, -32,176,99,192,226,115,30,1,79,4,68,28,16,54,0,0,41,254,232,116,62,204,7,21, -35,18,54,127,80,28,192,132,28,32,14,96,197,212,243,193,48,188,240,39,130, -236,224,175,131,117,2,178,112,145,139,163,145,131,114,70,46,142,218,27,182, -72,197,209,219,56,26,53,161,166,32,128,56,18,2,129,239,94,50,76,130,68,230, -202,113,160,167,146,94,163,134,66,161,164,227,226,231,146,51,198,249,147, -71,209,67,73,210,94,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15, -155,163,191,68,28,98,79,143,139,166,233,225,228,227,139,198,37,210,244,208, -24,137,112,151,153,27,36,5,100,224,146,105,184,100,196,95,18,84,141,159,9, -121,145,178,67,155,46,33,38,187,168,252,211,243,81,92,2,14,40,16,50,37,202, -160,150,154,67,152,148,20,28,76,156,89,26,105,158,63,232,16,44,150,129,18, -146,44,28,96,14,98,216,80,113,50,113,100,105,166,120,255,160,20,28,76,156, -113,75,34,78,63,236,3,6,133,41,35,31,242,18,195,152,147,226,27,61,138,41, -140,16,98,79,148,67,103,177,69,45,136,49,39,196,54,122,58,212,83,26,36,196, -159,40,134,207,71,90,138,92,16,98,79,136,108,244,244,168,166,56,73,137,62, -81,13,158,158,149,20,186,40,196,159,10,183,2,122,122,84,82,240,163,18,124, -42,220,9,235,106,81,75,225,228,73,241,13,158,197,54,198,8,145,39,202,33, -179,216,166,214,196,72,147,226,27,61,29,106,109,141,19,34,79,148,67,103, -163,173,77,174,8,145,39,196,54,122,122,84,219,28,38,68,159,40,134,207,79, -74,155,93,21,34,79,133,91,129,61,61,42,109,120,84,137,62,21,110,4,245,181, -41,181,248,56,224,28,24,80,113,50,113,100,105,166,120,255,160,20,28,76,156, -113,75,34,78,63,236,3,6,133,41,35,31,242,11,174,254,160,34,84,8,35,16,98, -146,38,55,32,33,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,0,0,0,0,30, -7,230,56,199,161,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,0,0,0,0, -30,7,230,55,36,33,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,0,0,0,0, -30,7,234,40,11,91,133,199,172,8,111,248,128,239,88,16,222,56,191,242,49, -198,69,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,240,63, -49,185,65,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,240, -63,49,198,77,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0, -240,63,49,185,97,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0, -0,0,64,49,198,85,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0, -0,0,64,49,185,129,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0, -0,0,0,64,49,198,93,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0, -0,0,0,64,49,185,161,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0, -0,0,0,16,64,49,198,101,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0, -0,0,0,0,16,64,49,185,193,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0, -0,0,0,0,0,16,64,49,198,109,8,244,56,153,37,180,242,71,104,139,35,8,217,192, -0,0,0,0,0,0,16,64,49,185,225,8,244,56,153,37,180,242,71,104,139,35,8,217, -192,0,0,0,0,0,0,16,64,49,198,117,8,244,56,153,37,180,242,71,104,139,35,8, -217,192,0,0,0,0,0,0,16,64,49,186,1,8,244,56,153,37,180,242,71,104,139,35,8, -217,192,0,0,0,0,0,0,32,64,49,198,125,8,244,56,153,37,180,242,71,104,139,35, -8,217,192,0,0,0,0,0,0,32,64,32,232,130,0,97,57,162,4,245,72,10,68,184,70, -137,195,67,77,175,32,66,37,192,208,165,36,117,196,10,14,38,78,44,141,52, -207,169,64,56,156,199,130,36,160,141,146,52,38,32,76,72,1,246,136,235,103, -177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,171,37, -20,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,158,142, -183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,246,136, -235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,37,20, -138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,75,161, -37,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,39,208, -146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,129,89, -58,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,17,214, -207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,207, -161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,207, -98,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,78, -209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,146, -155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,104, -142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,146, -155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,217, -233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,162, -137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,77, -156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,117, -179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,162, -100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,59,22, -53,91,0,2,21,11,94,181,128,196,133,0,185,80,32,56,156,199,130,36,160,72,16, -78,126,53,144,5,146,208,34,82,72,1,109,20,76,155,40,32,233,0,115,70,130,8, -209,56,104,105,187,252,193,3,17,162,112,201,242,18,65,211,0,230,149,132,17, -162,112,208,211,119,248,0,82,130,96,95,127,128,130,80,102,186,36,232,92, -206,255,1,80,48,200,39,12,158,241,64, +18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,232,59, +147,60,93,110,79,15,39,9,24,186,33,13,63,111,185,16,211,206,251,114,98,17, +171,160,11,199,197,215,196,66,26,102,38,68,53,212,77,136,104,255,5,114,120, +121,7,192,70,32,192,67,95,249,59,13,13,127,228,248,134,191,242,133,208,215, +254,81,204,67,95,249,75,33,13,127,229,61,84,53,255,149,52,80,215,254,85, +217,67,95,249,91,121,13,90,181,168,134,143,152,95,38,75,207,132,104,156,50, +70,33,163,225,66,249,50,94,124,25,4,225,146,49,14,24,28,196,0,0,0,0,0,0,15, +135,252,204,0,0,0,0,0,0,15,7,252,188,72,6,176,77,225,28,24,103,14,33,197, +138,113,227,28,152,231,46,65,205,19,194,84,11,225,35,23,68,231,138,228,64, +211,19,132,140,93,19,162,59,145,33,73,18,52,68,225,35,23,68,233,139,228, +176,217,130,252,36,98,232,157,81,60,158,30,78,18,49,116,78,184,142,210,40, +39,99,23,68,236,201,59,114,142,224,126,14,138,152,30,67,188,23,143,139,175, +131,194,135,228,72,85,144,83,60,53,163,208,76,60,68,211,197,78,60,116,243, +200,80,60,149,19,202,82,60,181,51,204,84,60,213,83,206,86,60,240,190,76, +151,159,8,209,56,100,137,232,133,242,100,188,248,50,9,195,36,79,73,26,238, +108,129,15,4,100,78,33,179,207,160,41,224,140,137,194,173,192,158,120,128, +168,151,26,14,55,58,64,132,75,133,67,81,50,103,8,18,50,9,195,39,105,20,101, +136,36,50,9,195,39,105,20,11,174,99,220,210,54,121,114,4,145,162,112,201, +218,69,25,130,9,17,162,112,201,218,69,2,235,152,247,52,141,158,100,128,196, +144,128,242,102,136,17,70,146,66,3,201,160,32,0,130,225,48,113,137,62,62, +46,155,167,135,147,142,47,24,147,79,205,68,48,98,79,142,179,120,248,185, +228,140,241,193,146,66,138,31,55,71,126,129,51,18,124,117,155,199,197,207, +36,103,142,52,12,36,184,100,129,129,41,32,205,221,175,3,10,36,4,201,188,64, +112,200,84,52,156,124,92,242,70,120,223,48,64,100,42,26,78,62,46,121,35,52, +18,91,212,2,72,128,95,20,128,197,137,9,146,113,73,8,190,36,169,27,62,18, +243,35,100,135,54,92,66,4,34,92,145,0,178,15,132,64,132,75,133,139,178,70, +240,137,6,34,92,37,230,70,201,1,89,56,36,4,81,49,46,25,5,76,73,241,214,111, +31,23,60,145,158,57,44,48,46,92,184,100,160,145,46,2,0,201,168,207,198,230, +144,117,60,176,48,156,160,48,188,192,7,28,18,227,172,222,62,46,121,35,60, +113,200,26,137,113,241,116,221,60,60,156,113,121,4,20,124,92,242,70,120, +226,37,194,54,140,36,64,21,147,146,68,24,32,57,0,125,78,84,0,160,123,215, +140,146,1,4,5,175,40,124,8,20,52,121,51,228,24,96,129,209,46,2,49,6,20,135, +33,20,53,50,128,194,65,4,12,39,52,64,155,31,48,112,72,6,247,62,16,1,31,73, +30,25,240,60,73,82,70,68,138,0,89,29,5,156,96,2,201,104,17,35,160,18,78, +140,228,16,26,79,90,4,73,43,192,244,108,142,130,206,89,240,58,26,50,95,142, +43,159,65,107,4,167,196,52,100,191,28,87,63,128,15,255,240,164,169,35,136, +6,128,146,115,9,0,210,7,43,163,194,0,71,128,105,65,176,15,128,105,131,21, +11,153,35,0,211,134,137,7,65,18,33,244,23,18,14,130,39,34,131,30,113,15, +224,3,255,254,12,80,81,133,139,153,193,28,17,224,156,50,119,15,131,75,23, +51,130,112,201,199,185,13,159,116,248,228,68,219,66,149,83,83,238,3,11,238, +0,48,142,8,240,19,239,144,40,71,4,120,39,12,156,4,252,4,11,19,134,78,61, +200,108,248,9,248,9,3,9,205,16,39,225,62,7,67,70,75,241,197,241,154,5,172, +18,159,16,209,146,252,113,124,102,144,106,220,32,44,156,19,152,240,68,158, +66,2,176,19,17,252,164,7,137,30,176,8,158,116,3,72,128,136,143,232,32,44, +150,129,19,210,128,89,61,104,159,169,1,50,160,101,56,161,166,246,160,46, +110,226,221,98,71,130,4,137,222,0,140,221,197,184,64,89,56,183,88,145,224, +129,34,119,128,23,55,114,143,121,35,193,2,68,239,2,17,155,184,183,8,11,39, +40,247,146,60,16,36,78,240,32,73,197,12,247,128,26,36,121,1,63,49,2,165,48, +70,114,229,145,51,250,205,2,8,209,203,150,68,207,235,52,130,16,209,46,131, +36,188,70,128,210,160,101,56,251,16,131,28,7,35,38,218,50,234,103,130,97, +103,129,6,73,0,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,199,36,38, +218,0,0,0,0,0,0,0,0,4,29,78,224,140,38,216,140,46,228,0,243,119,10,139,144, +123,82,6,205,220,37,222,230,145,179,64,23,180,32,92,221,199,196,130,68,144, +230,237,200,131,44,24,43,193,25,18,185,0,251,73,138,199,240,27,93,106,192, +57,41,54,210,0,0,0,0,0,0,62,31,241,58,155,192,12,155,184,48,76,156,148,226, +134,154,240,32,201,187,147,67,9,201,78,40,105,175,2,225,47,3,18,155,184, +183,8,11,39,6,9,147,146,156,80,211,94,7,37,55,113,110,16,22,78,77,12,39,37, +56,161,166,188,16,48,215,130,14,30,240,66,213,93,35,11,124,0,230,36,249,52, +48,151,192,22,98,79,133,162,215,204,16,17,178,16,199,24,147,237,38,34,246, +139,95,48,64,70,200,68,16,98,79,140,115,102,123,33,20,89,137,62,210,98,103, +92,217,158,200,70,14,98,79,131,4,201,100,35,138,49,39,218,76,67,232,38,75, +33,32,49,137,62,12,24,178,18,68,152,147,237,38,33,244,24,178,18,132,24,147, +225,221,72,202,200,75,22,98,79,180,152,143,215,82,50,178,19,5,24,147,227, +16,218,76,146,178,19,70,152,147,237,38,38,117,13,164,201,43,33,56,81,137, +62,72,130,115,71,43,33,60,105,137,62,210,98,151,72,39,52,114,178,20,7,152, +147,227,16,181,162,68,19,154,57,89,10,36,140,73,246,147,19,58,133,173,18, +32,156,209,202,200,82,34,98,79,147,67,9,151,52,156,113,75,34,78,208,1,228, +73,242,104,97,46,16,62,68,159,24,133,173,18,32,156,209,202,217,83,37,34,79, +180,152,153,212,45,104,145,4,230,142,86,202,160,169,18,124,145,4,230,142, +86,215,213,27,34,79,180,152,165,210,9,205,28,173,175,172,42,68,159,24,134, +210,100,149,183,245,198,200,147,237,38,38,117,13,164,201,43,111,236,8,145, +39,195,186,145,149,185,246,69,200,147,237,38,35,245,212,140,173,207,180,30, +68,159,6,9,146,217,91,21,34,79,180,152,135,208,76,150,202,224,137,18,124, +99,155,51,219,95,116,92,137,62,210,98,103,92,217,158,218,251,194,228,73, +240,180,90,249,130,2,54,223,223,29,34,79,180,152,139,218,45,124,193,1,27, +111,240,33,204,73,243,4,4,108,134,8,60,137,62,96,128,141,178,193,193,154,3, +147,32,227,36,0,0,0,0,0,0,0,0,99,115,245,195,19,159,176,75,175,159,176,24, +172,253,129,49,121,251,2,176,66,92,130,235,16,18,100,148,251,36,106,123,64, +65,158,3,147,160,108,202,62,68,165,107,243,227,113,198,211,62,39,20,108, +115,226,241,130,106,113,224,78,162,4,242,130,236,197,60,37,64,190,18,49, +116,114,37,40,157,76,9,229,37,217,138,185,16,52,196,225,35,23,71,34,82,137, +213,64,158,84,93,152,187,145,33,73,18,52,68,225,35,23,71,34,82,137,213,192, +158,86,93,152,175,146,195,102,11,240,145,139,163,145,41,68,235,32,79,44,46, +204,83,201,225,228,225,35,23,71,34,82,137,214,192,158,90,93,152,163,180, +138,9,216,197,209,200,148,161,194,32,30,18,3,74,184,164,88,85,248,42,0,78, +173,186,58,16,5,149,109,110,236,90,192,144,1,245,109,210,129,222,115,245, +252,132,93,204,126,23,171,113,180,137,3,250,8,173,149,28,87,220,252,55,86, +227,104,232,18,0,119,41,48,171,222,94,217,248,46,189,16,6,11,81,21,62,200, +66,80,3,246,80,140,244,118,180,160,102,157,191,179,79,80,115,31,133,236, +161,25,233,64,205,59,127,102,158,160,246,63,41,248,30,75,12,11,151,242,233, +187,146,156,80,211,114,96,54,230,41,20,129,128,50,211,16,16,2,116,180,196, +129,1,36,55,76,74,16,19,3,116,196,193,65,48,55,75,80,128,65,6,51,211,20, +128,130,34,23,166,39,6,39,75,76,80,1,146,239,211,20,16,165,91,157,29,49,66, +10,124,61,211,209,175,1,173,198,211,20,48,139,113,180,180,197,36,42,220, +109,29,13,49,74,6,192,95,72,188,6,196,55,74,188,6,247,91,80,136,26,32,104, +220,205,56,1,98,234,52,122,98,136,14,72,110,152,162,132,148,35,61,49,70,7, +48,55,76,81,194,206,52,104,180,197,45,192,80,175,4,100,77,10,2,101,56,161, +166,65,113,162,98,8,3,131,7,169,35,36,57,176,0,0,0,0,16,40,116,208,45,158, +10,225,223,132,17,13,43,176,228,3,0,167,129,32,17,133,134,32,25,80,220,40, +240,25,26,44,32,240,24,200,44,24,240,56,156,199,128,83,193,17,7,4,13,128,0, +10,79,202,28,223,195,1,197,72,196,141,159,220,7,48,33,7,8,3,152,49,117,60, +240,76,47,60,9,224,187,56,43,224,221,64,172,156,36,98,232,228,96,220,145, +139,163,182,134,237,146,49,116,118,206,6,141,104,105,136,32,14,4,128,160, +123,215,140,147,32,145,57,178,156,104,41,228,151,168,225,144,168,105,56, +248,185,228,140,241,190,100,209,244,80,210,116,151,134,12,73,241,214,111, +31,23,60,145,158,56,50,72,81,67,230,232,239,209,7,24,147,227,226,233,186, +120,121,56,226,241,137,116,189,52,6,34,92,37,230,70,201,1,89,56,36,154,110, +25,49,23,196,149,35,103,194,94,100,108,144,230,203,136,73,174,234,63,52, +252,212,87,0,131,138,4,12,137,114,168,37,166,144,230,37,5,7,19,39,22,70, +154,103,143,252,4,11,37,160,68,164,139,7,24,3,152,182,20,28,76,156,89,26, +105,158,63,240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253,132, +176,230,36,248,134,207,98,138,99,4,24,147,229,16,217,236,81,75,98,12,73, +241,13,158,142,181,20,198,137,49,39,202,33,179,209,214,162,151,4,24,147, +226,27,61,61,42,41,142,18,98,79,148,67,103,167,165,69,46,138,49,39,194,173, +192,158,158,149,20,188,40,196,159,10,183,2,122,218,148,82,248,121,18,124, +67,103,177,77,177,130,36,73,242,136,108,246,41,181,177,18,36,248,134,207, +71,90,155,99,68,200,147,229,16,217,232,235,83,107,130,36,73,241,13,158,158, +149,54,199,9,145,39,202,33,179,211,210,166,215,69,72,147,225,86,224,79,79, +74,155,94,21,34,79,133,91,129,61,109,74,109,126,14,56,7,6,20,28,76,156,89, +26,105,158,63,240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253, +130,235,191,232,8,149,2,8,196,24,164,137,141,200,8,71,161,196,201,45,167, +146,59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,142,49,232,71,161,196,201,45, +167,146,59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,141,201,8,71,161,196,201, +45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,7,129,250,138,2,214,225,113,235, +2,27,128,0,10,66,3,189,96,67,120,226,224,0,2,148,140,113,145,66,61,14,38, +73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,60,15,204,110,80,66,61,14, +38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,60,15,204,113,147,66,61, +14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,60,15,204,110,88,66, +61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,0,16,12,113,149, +66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,0,16,12,110,96, +66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,0,16,12,113, +151,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,0,16,12, +110,104,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,4,16, +12,113,153,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,4, +16,12,110,112,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0, +4,16,12,113,155,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0, +0,4,16,12,110,120,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0, +0,0,4,16,12,113,157,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0, +0,0,0,4,16,12,110,128,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0, +0,0,0,0,8,16,12,113,159,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0, +0,0,0,0,0,8,16,8,58,32,128,24,78,104,129,61,82,2,145,46,17,162,112,208,211, +107,200,16,137,112,52,41,73,29,113,2,131,137,147,139,35,77,51,234,80,14,39, +49,224,137,40,35,100,141,9,136,19,18,0,125,162,58,217,236,81,64,68,72,1, +241,13,158,197,20,150,50,36,0,251,68,117,179,209,214,234,201,69,16,100,72, +1,246,136,235,103,163,173,208,146,138,68,23,18,0,124,67,103,163,173,213, +146,138,76,23,18,0,124,67,103,163,173,208,146,138,84,25,18,0,125,162,58, +217,233,233,117,100,162,138,50,36,0,251,68,117,179,211,210,232,73,69,34, +139,137,0,62,33,179,211,210,234,201,69,38,139,137,0,62,33,179,211,210,232, +73,69,42,139,137,0,62,21,110,4,250,178,81,70,23,18,0,124,42,220,9,244,36, +162,145,134,68,128,31,6,234,5,100,234,201,69,28,100,72,1,240,110,160,86,78, +132,148,82,56,168,144,3,237,17,214,207,171,37,22,128,42,36,0,251,68,117, +179,232,73,69,164,9,137,0,62,33,179,234,201,69,168,9,137,0,62,33,179,232, +73,69,172,10,180,81,50,118,136,235,103,177,77,129,54,138,38,78,33,179,216, +166,210,198,218,40,153,59,68,117,179,209,214,234,201,77,144,109,162,137, +147,180,71,91,61,29,110,132,148,218,32,203,69,19,39,16,217,232,235,117,100, +166,211,6,90,40,153,56,134,207,71,91,161,37,54,168,54,209,68,201,218,35, +173,158,158,151,86,74,108,163,109,20,76,157,162,58,217,233,233,116,36,166, +209,70,90,40,153,56,134,207,79,75,171,37,54,154,50,209,68,201,196,54,122, +122,93,9,41,181,81,150,138,38,78,21,110,4,250,178,83,102,25,104,162,100, +225,86,224,79,161,37,54,140,54,209,68,201,193,186,129,89,58,178,83,103,27, +104,162,100,224,221,64,172,157,9,41,180,113,118,138,38,78,209,29,108,250, +178,83,136,2,237,20,76,157,162,58,217,244,36,167,18,5,90,40,153,56,134,207, +171,37,56,160,42,209,68,201,196,54,125,9,41,197,141,78,197,141,86,192,0, +133,66,215,173,96,49,33,64,46,84,8,14,39,49,224,137,40,18,4,19,159,141,100, +1,100,180,8,148,146,0,91,69,19,38,202,8,58,64,28,209,160,130,52,78,26,26, +110,255,80,64,196,104,156,50,125,4,144,116,192,57,165,97,4,104,156,52,52, +221,254,64,20,160,152,23,223,228,32,148,25,174,137,58,23,51,191,200,84,12, +50,9,195,39,196,80, }; #elif defined(DUK_USE_DOUBLE_BE) -DUK_INTERNAL const duk_uint8_t duk_builtins_data[3790] = { +DUK_INTERNAL const duk_uint8_t duk_builtins_data[3819] = { 144,148,105,221,32,68,52,228,62,12,104,200,165,134,148,248,81,77,61,191, 135,35,154,103,34,72,6,157,159,197,145,77,245,126,52,130,106,234,163,196, 52,226,18,51,161,26,113,1,60,37,64,190,18,49,116,116,33,26,113,1,92,136,26, 98,112,145,139,163,165,8,211,136,14,228,72,82,68,141,17,56,72,197,209,212, 132,105,196,5,242,88,108,193,126,18,49,116,117,161,26,113,1,60,158,30,78, -18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,224,59, -147,60,93,110,79,15,39,9,24,186,33,13,63,79,185,39,26,121,223,110,77,66,53, -116,1,120,248,186,248,136,67,76,196,200,134,186,137,177,13,31,192,174,79, -15,32,248,8,196,24,8,107,254,39,97,161,175,248,159,16,215,252,80,186,26, -255,138,57,136,107,254,41,100,33,175,248,167,170,134,191,226,166,138,26, -255,138,187,40,107,254,43,111,33,171,86,181,16,209,241,11,228,201,121,240, -141,19,134,72,196,52,123,168,95,38,75,207,131,32,156,50,70,33,195,3,152, -128,255,240,0,0,0,0,0,1,153,128,255,224,0,0,0,0,0,1,151,137,0,214,9,188,35, -131,12,225,196,56,177,78,60,99,147,28,229,200,57,162,120,74,129,124,36,98, -232,156,241,92,136,26,98,112,145,139,162,116,71,114,36,41,34,70,136,156,36, -98,232,157,49,124,150,27,48,95,132,140,93,19,170,39,147,195,201,194,70,46, -137,215,17,218,69,4,236,98,232,157,153,39,110,81,220,15,193,209,83,3,200, -119,130,241,241,117,240,120,80,252,137,10,178,10,103,134,180,122,9,135,136, -154,120,169,199,142,158,121,10,7,146,162,121,74,71,150,166,121,138,135,154, -170,121,202,199,158,23,201,146,243,225,26,39,12,145,61,16,190,76,151,159,6, -65,56,100,137,233,35,93,205,144,33,224,140,137,196,54,121,244,5,60,17,145, -56,85,184,19,207,16,21,18,227,65,198,231,72,16,137,112,168,106,38,76,225,2, -70,65,56,100,237,34,140,177,4,134,65,56,100,237,34,129,117,204,123,154,70, -207,46,64,146,52,78,25,59,72,163,48,65,34,52,78,25,59,72,160,93,115,30,230, -145,179,204,144,24,146,16,30,76,209,2,40,210,72,64,121,52,4,0,156,88,97,5, -194,96,227,18,124,124,93,55,79,15,39,28,94,49,38,159,154,136,96,196,159,29, -102,241,241,115,201,25,227,131,36,133,20,62,110,142,253,2,102,36,248,235, -55,143,139,158,72,207,28,104,24,73,112,201,3,2,82,65,155,187,94,6,20,72,9, -147,120,128,225,144,168,105,56,248,185,228,140,241,190,96,128,200,84,52, -156,124,92,242,70,104,36,183,168,4,145,0,190,41,1,139,18,19,36,226,146,17, -124,73,82,54,124,37,230,70,201,14,108,184,132,8,68,185,34,1,100,31,8,129,8, -151,11,23,100,141,225,18,12,68,184,75,204,141,146,2,178,112,72,8,162,98,92, -50,10,152,147,227,172,222,62,46,121,35,60,114,88,96,92,185,112,201,65,34, -92,4,1,147,81,159,141,205,32,234,121,96,97,57,64,97,121,128,14,56,37,199, -89,188,124,92,242,70,120,227,144,53,18,227,226,233,186,120,121,56,226,242, -8,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,36,136,48,64,114,0, -250,156,168,1,64,247,175,25,36,2,8,11,94,80,248,16,40,104,242,103,200,48, -193,3,162,92,4,98,12,41,14,66,40,106,101,1,132,130,8,24,78,104,129,54,62, -96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,178, -58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,129, -232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,201, -126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,132, -0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,46, -36,29,4,78,69,6,60,226,31,192,7,255,252,24,160,163,11,23,51,130,56,35,193, -56,100,238,31,6,150,46,103,4,225,147,143,114,27,62,233,241,200,137,182,133, -42,142,167,216,6,23,216,0,97,28,17,224,39,223,32,80,142,8,240,78,25,56,9, -248,8,22,39,12,156,123,144,217,240,19,240,18,6,19,154,32,79,194,124,14,134, -140,151,227,139,226,52,11,88,37,62,33,163,37,248,226,248,141,32,213,184,64, -89,56,39,49,224,137,60,100,5,96,38,35,249,8,15,18,61,96,17,60,200,6,145,1, -17,31,206,64,89,45,2,39,161,0,178,122,209,63,74,2,101,64,202,113,67,77,235, -64,92,221,197,186,196,143,4,9,19,188,1,25,187,139,112,128,178,113,110,177, -35,193,2,68,239,0,46,110,229,30,242,71,130,4,137,222,4,35,55,113,110,16,22, -78,81,239,36,120,32,72,157,224,64,147,138,25,237,0,52,72,242,2,126,82,3,74, -129,148,227,234,66,12,112,28,140,155,104,203,169,158,9,133,158,4,25,36,1, -61,96,47,181,80,46,132,128,255,223,255,255,255,255,255,254,39,172,67,118, -170,5,208,144,0,0,0,0,0,0,0,0,115,16,31,254,0,0,0,0,0,0,8,245,238,146,38, -138,147,105,13,42,26,137,226,3,255,128,0,0,0,0,0,1,30,180,134,4,209,82,109, -33,165,67,81,60,64,255,240,0,0,0,0,0,0,28,144,155,104,0,0,0,0,0,0,0,0,16, -117,59,130,48,155,98,48,187,144,3,205,220,42,46,65,237,72,27,55,112,151, -123,154,70,205,0,94,208,129,115,119,31,18,9,18,67,155,183,34,12,176,96,175, -4,100,74,228,3,237,38,43,31,192,109,117,171,0,228,164,219,72,127,248,0,0,0, -0,0,0,196,234,111,0,50,110,224,193,50,114,83,138,26,107,192,131,38,238,77, -12,39,37,56,161,166,188,11,132,188,12,74,110,226,220,32,44,156,24,38,78,74, -113,67,77,120,28,148,221,197,184,64,89,57,52,48,156,148,226,134,154,240,64, -195,94,8,56,123,193,11,85,116,140,45,240,3,152,147,228,208,194,95,0,89,137, -62,22,139,95,48,64,70,200,67,28,98,79,180,152,139,218,45,124,193,1,27,33, -16,65,137,62,49,205,153,236,132,81,102,36,251,73,137,157,115,102,123,33,24, -57,137,62,12,19,37,144,142,40,196,159,105,49,15,160,153,44,132,128,198,36, -248,48,98,200,73,18,98,79,180,152,135,208,98,200,74,16,98,79,135,117,35,43, -33,44,89,137,62,210,98,63,93,72,202,200,76,20,98,79,140,67,105,50,74,200, -77,26,98,79,180,152,153,212,54,147,36,172,132,225,70,36,249,34,9,205,28, -172,132,241,166,36,251,73,138,93,32,156,209,202,200,80,30,98,79,140,66,214, -137,16,78,104,229,100,40,146,49,39,218,76,76,234,22,180,72,130,115,71,43, -33,72,137,137,62,77,12,38,92,210,113,197,44,137,59,64,7,145,39,201,161,132, -184,64,249,18,124,98,22,180,72,130,115,71,43,101,76,148,137,62,210,98,103, -80,181,162,68,19,154,57,91,42,130,164,73,242,68,19,154,57,91,95,84,108,137, -62,210,98,151,72,39,52,114,182,190,176,169,18,124,98,27,73,146,86,223,215, -27,34,79,180,152,153,212,54,147,36,173,191,176,34,68,159,14,234,70,86,231, -217,23,34,79,180,152,143,215,82,50,183,62,208,121,18,124,24,38,75,101,108, -84,137,62,210,98,31,65,50,91,43,130,36,73,241,142,108,207,109,125,209,114, -36,251,73,137,157,115,102,123,107,239,11,145,39,194,209,107,230,8,8,219, -127,124,116,137,62,210,98,47,104,181,243,4,4,109,191,192,135,49,39,204,16, -17,178,24,32,242,36,249,130,2,54,203,7,6,104,14,76,131,140,144,0,0,0,0,0,0, -0,1,141,207,215,12,78,126,193,46,190,126,192,98,179,246,4,197,231,236,10, -193,9,114,11,172,64,73,146,83,236,145,169,237,1,6,120,14,78,129,179,40,249, -18,149,175,207,141,199,27,76,248,156,81,177,207,139,198,9,169,199,129,58, -136,19,202,11,179,20,240,149,2,248,72,197,209,200,148,162,117,48,39,148, -151,102,42,228,64,211,19,132,140,93,28,137,74,39,85,2,121,81,118,98,238,68, -133,36,72,209,19,132,140,93,28,137,74,39,87,2,121,89,118,98,190,75,13,152, -47,194,70,46,142,68,165,19,172,129,60,176,187,49,79,39,135,147,132,140,93, -28,137,74,39,91,2,121,105,118,98,142,210,40,39,99,23,71,34,82,135,8,128, -120,72,8,0,183,225,81,98,138,237,33,58,182,232,232,64,64,2,107,177,187,181, -85,22,7,213,183,74,1,255,49,114,23,247,209,207,120,94,173,198,210,36,3,255, -113,84,118,82,184,47,224,221,91,141,163,160,72,7,251,121,111,98,164,220, -161,192,186,244,64,64,9,33,251,84,68,45,24,15,217,66,51,209,218,210,128, -127,205,65,60,204,254,119,154,23,178,132,103,165,0,255,218,130,121,153,252, -239,52,167,224,121,44,48,46,95,203,166,238,74,113,67,77,201,128,219,152, -164,82,6,0,203,76,64,64,9,210,211,18,4,4,144,221,49,40,64,76,13,211,19,5,4, -192,221,45,66,1,4,24,207,76,82,2,8,136,94,152,156,24,157,45,49,64,6,75,191, -76,80,66,149,110,116,116,197,8,41,240,247,79,70,188,6,183,27,76,80,194,45, -198,210,211,20,144,171,113,180,116,52,197,40,27,1,125,34,240,27,16,221,42, -240,27,221,109,66,32,104,129,163,115,52,224,5,139,168,209,233,138,32,57,33, -186,98,138,18,80,140,244,197,24,28,192,221,49,71,11,56,209,162,211,20,183, -1,66,188,17,145,52,40,9,148,226,134,153,5,198,137,136,32,14,12,30,164,140, -144,230,192,64,211,136,0,0,0,0,0,182,120,43,135,126,16,68,52,174,195,144, -12,2,158,4,128,70,22,24,128,101,67,112,163,192,100,104,176,131,192,99,32, -176,99,192,226,115,30,1,79,4,68,28,16,54,0,0,41,254,232,116,62,204,7,21,35, -18,54,127,80,28,192,132,28,32,14,96,197,212,243,193,48,188,240,39,130,236, -224,175,131,117,2,178,112,145,139,163,145,131,114,70,46,142,218,27,182,72, -197,209,219,56,26,53,161,166,32,128,56,18,2,129,239,94,50,76,130,68,230, -202,113,160,167,146,94,163,134,66,161,164,227,226,231,146,51,198,249,147, -71,209,67,73,210,94,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15, -155,163,191,68,28,98,79,143,139,166,233,225,228,227,139,198,37,210,244,208, -24,137,112,151,153,27,36,5,100,224,146,105,184,100,196,95,18,84,141,159,9, -121,145,178,67,155,46,33,38,187,168,252,211,243,81,92,2,14,40,16,50,37,202, -160,150,154,67,152,148,20,28,76,156,89,26,105,158,63,232,16,44,150,129,18, -146,44,28,96,14,98,216,80,113,50,113,100,105,166,120,255,160,20,28,76,156, -113,75,34,78,63,236,3,6,133,41,35,31,242,18,195,152,147,226,27,61,138,41, -140,16,98,79,148,67,103,177,69,45,136,49,39,196,54,122,58,212,83,26,36,196, -159,40,134,207,71,90,138,92,16,98,79,136,108,244,244,168,166,56,73,137,62, -81,13,158,158,149,20,186,40,196,159,10,183,2,122,122,84,82,240,163,18,124, -42,220,9,235,106,81,75,225,228,73,241,13,158,197,54,198,8,145,39,202,33, -179,216,166,214,196,72,147,226,27,61,29,106,109,141,19,34,79,148,67,103, -163,173,77,174,8,145,39,196,54,122,122,84,219,28,38,68,159,40,134,207,79, -74,155,93,21,34,79,133,91,129,61,61,42,109,120,84,137,62,21,110,4,245,181, -41,181,248,56,224,28,24,80,113,50,113,100,105,166,120,255,160,20,28,76,156, -113,75,34,78,63,236,3,6,133,41,35,31,242,11,174,254,160,34,84,8,35,16,98, -146,38,55,32,33,30,135,19,36,182,158,72,237,17,100,97,27,56,7,254,0,0,0,0, -0,0,6,56,199,161,30,135,19,36,182,158,72,237,17,100,97,27,56,7,254,0,0,0,0, -0,0,6,55,36,33,30,135,19,36,182,158,72,237,17,100,97,27,56,7,254,0,0,0,0,0, -0,10,40,11,91,133,199,172,8,111,248,128,239,88,16,222,56,191,242,49,198,69, -8,244,56,153,37,180,242,71,104,139,35,8,217,192,63,240,0,0,0,0,0,0,49,185, -65,8,244,56,153,37,180,242,71,104,139,35,8,217,192,63,240,0,0,0,0,0,0,49, -198,77,8,244,56,153,37,180,242,71,104,139,35,8,217,192,63,240,0,0,0,0,0,0, -49,185,97,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0,0, -49,198,85,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0,0, -49,185,129,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0, -0,49,198,93,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0, -0,49,185,161,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0,0,0, -0,0,49,198,101,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0,0, -0,0,0,49,185,193,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0, -0,0,0,0,49,198,109,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0, -0,0,0,0,0,49,185,225,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16, -0,0,0,0,0,0,49,198,117,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64, -16,0,0,0,0,0,0,49,186,1,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64, -32,0,0,0,0,0,0,49,198,125,8,244,56,153,37,180,242,71,104,139,35,8,217,192, -64,32,0,0,0,0,0,0,32,232,130,0,97,57,162,4,245,72,10,68,184,70,137,195,67, -77,175,32,66,37,192,208,165,36,117,196,10,14,38,78,44,141,52,207,169,64,56, -156,199,130,36,160,141,146,52,38,32,76,72,1,246,136,235,103,177,69,1,17,32, -7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,171,37,20,65,145,32,7, -218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,158,142,183,86,74,41,48, -92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,246,136,235,103,167,165, -213,146,138,40,200,144,3,237,17,214,207,79,75,161,37,20,138,46,36,0,248, -134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,75,161,37,20,170,46,36, -0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,39,208,146,138,70,25,18, -0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,129,89,58,18,81,72,226, -162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,17,214,207,161,37,22,144, -38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,207,161,37,22,176,42,209, -68,201,218,35,173,158,197,54,4,218,40,153,56,134,207,98,155,75,27,104,162, -100,237,17,214,207,71,91,171,37,54,65,182,138,38,78,209,29,108,244,117,186, -18,83,104,131,45,20,76,156,67,103,163,173,213,146,155,76,25,104,162,100, -226,27,61,29,110,132,148,218,160,219,69,19,39,104,142,182,122,122,93,89,41, -178,141,180,81,50,118,136,235,103,167,165,208,146,155,69,25,104,162,100, -226,27,61,61,46,172,148,218,104,203,69,19,39,16,217,233,233,116,36,166,213, -70,90,40,153,56,85,184,19,234,201,77,152,101,162,137,147,133,91,129,62,132, -148,218,48,219,69,19,39,6,234,5,100,234,201,77,156,109,162,137,147,131,117, -2,178,116,36,166,209,197,218,40,153,59,68,117,179,234,201,78,32,11,180,81, -50,118,136,235,103,208,146,156,72,21,104,162,100,226,27,62,172,148,226,128, -171,69,19,39,16,217,244,36,167,22,53,59,22,53,91,0,2,21,11,94,181,128,196, -133,0,185,80,32,56,156,199,130,36,160,72,16,78,126,53,144,5,146,208,34,82, -72,1,109,20,76,155,40,32,233,0,115,70,130,8,209,56,104,105,187,252,193,3, -17,162,112,201,242,18,65,211,0,230,149,132,17,162,112,208,211,119,248,0,82, -130,96,95,127,128,130,80,102,186,36,232,92,206,255,1,80,48,200,39,12,158, -241,64, +18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,232,59, +147,60,93,110,79,15,39,9,24,186,33,13,63,111,185,16,211,206,251,114,98,17, +171,160,11,199,197,215,196,66,26,102,38,68,53,212,77,136,104,255,5,114,120, +121,7,192,70,32,192,67,95,249,59,13,13,127,228,248,134,191,242,133,208,215, +254,81,204,67,95,249,75,33,13,127,229,61,84,53,255,149,52,80,215,254,85, +217,67,95,249,91,121,13,90,181,168,134,143,152,95,38,75,207,132,104,156,50, +70,33,163,225,66,249,50,94,124,25,4,225,146,49,14,24,28,196,7,255,128,0,0, +0,0,0,12,204,7,255,0,0,0,0,0,0,12,188,72,6,176,77,225,28,24,103,14,33,197, +138,113,227,28,152,231,46,65,205,19,194,84,11,225,35,23,68,231,138,228,64, +211,19,132,140,93,19,162,59,145,33,73,18,52,68,225,35,23,68,233,139,228, +176,217,130,252,36,98,232,157,81,60,158,30,78,18,49,116,78,184,142,210,40, +39,99,23,68,236,201,59,114,142,224,126,14,138,152,30,67,188,23,143,139,175, +131,194,135,228,72,85,144,83,60,53,163,208,76,60,68,211,197,78,60,116,243, +200,80,60,149,19,202,82,60,181,51,204,84,60,213,83,206,86,60,240,190,76, +151,159,8,209,56,100,137,232,133,242,100,188,248,50,9,195,36,79,73,26,238, +108,129,15,4,100,78,33,179,207,160,41,224,140,137,194,173,192,158,120,128, +168,151,26,14,55,58,64,132,75,133,67,81,50,103,8,18,50,9,195,39,105,20,101, +136,36,50,9,195,39,105,20,11,174,99,220,210,54,121,114,4,145,162,112,201, +218,69,25,130,9,17,162,112,201,218,69,2,235,152,247,52,141,158,100,128,196, +144,128,242,102,136,17,70,146,66,3,201,160,32,0,130,225,48,113,137,62,62, +46,155,167,135,147,142,47,24,147,79,205,68,48,98,79,142,179,120,248,185, +228,140,241,193,146,66,138,31,55,71,126,129,51,18,124,117,155,199,197,207, +36,103,142,52,12,36,184,100,129,129,41,32,205,221,175,3,10,36,4,201,188,64, +112,200,84,52,156,124,92,242,70,120,223,48,64,100,42,26,78,62,46,121,35,52, +18,91,212,2,72,128,95,20,128,197,137,9,146,113,73,8,190,36,169,27,62,18, +243,35,100,135,54,92,66,4,34,92,145,0,178,15,132,64,132,75,133,139,178,70, +240,137,6,34,92,37,230,70,201,1,89,56,36,4,81,49,46,25,5,76,73,241,214,111, +31,23,60,145,158,57,44,48,46,92,184,100,160,145,46,2,0,201,168,207,198,230, +144,117,60,176,48,156,160,48,188,192,7,28,18,227,172,222,62,46,121,35,60, +113,200,26,137,113,241,116,221,60,60,156,113,121,4,20,124,92,242,70,120, +226,37,194,54,140,36,64,21,147,146,68,24,32,57,0,125,78,84,0,160,123,215, +140,146,1,4,5,175,40,124,8,20,52,121,51,228,24,96,129,209,46,2,49,6,20,135, +33,20,53,50,128,194,65,4,12,39,52,64,155,31,48,112,72,6,247,62,16,1,31,73, +30,25,240,60,73,82,70,68,138,0,89,29,5,156,96,2,201,104,17,35,160,18,78, +140,228,16,26,79,90,4,73,43,192,244,108,142,130,206,89,240,58,26,50,95,142, +43,159,65,107,4,167,196,52,100,191,28,87,63,128,15,255,240,164,169,35,136, +6,128,146,115,9,0,210,7,43,163,194,0,71,128,105,65,176,15,128,105,131,21, +11,153,35,0,211,134,137,7,65,18,33,244,23,18,14,130,39,34,131,30,113,15, +224,3,255,254,12,80,81,133,139,153,193,28,17,224,156,50,119,15,131,75,23, +51,130,112,201,199,185,13,159,116,248,228,68,219,66,149,83,83,238,3,11,238, +0,48,142,8,240,19,239,144,40,71,4,120,39,12,156,4,252,4,11,19,134,78,61, +200,108,248,9,248,9,3,9,205,16,39,225,62,7,67,70,75,241,197,241,154,5,172, +18,159,16,209,146,252,113,124,102,144,106,220,32,44,156,19,152,240,68,158, +66,2,176,19,17,252,164,7,137,30,176,8,158,116,3,72,128,136,143,232,32,44, +150,129,19,210,128,89,61,104,159,169,1,50,160,101,56,161,166,246,160,46, +110,226,221,98,71,130,4,137,222,0,140,221,197,184,64,89,56,183,88,145,224, +129,34,119,128,23,55,114,143,121,35,193,2,68,239,2,17,155,184,183,8,11,39, +40,247,146,60,16,36,78,240,32,73,197,12,247,128,26,36,121,1,63,49,2,165,48, +70,114,229,145,51,250,205,2,8,209,203,150,68,207,235,52,130,16,209,46,131, +36,188,70,128,210,160,101,56,251,16,131,28,7,35,38,218,50,234,103,130,97, +103,129,6,73,0,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,7,36,38,218,0, +0,0,0,0,0,0,0,4,29,78,224,140,38,216,140,46,228,0,243,119,10,139,144,123, +82,6,205,220,37,222,230,145,179,64,23,180,32,92,221,199,196,130,68,144,230, +237,200,131,44,24,43,193,25,18,185,0,251,73,138,199,240,27,93,106,192,57, +41,54,210,31,254,0,0,0,0,0,0,49,58,155,192,12,155,184,48,76,156,148,226, +134,154,240,32,201,187,147,67,9,201,78,40,105,175,2,225,47,3,18,155,184, +183,8,11,39,6,9,147,146,156,80,211,94,7,37,55,113,110,16,22,78,77,12,39,37, +56,161,166,188,16,48,215,130,14,30,240,66,213,93,35,11,124,0,230,36,249,52, +48,151,192,22,98,79,133,162,215,204,16,17,178,16,199,24,147,237,38,34,246, +139,95,48,64,70,200,68,16,98,79,140,115,102,123,33,20,89,137,62,210,98,103, +92,217,158,200,70,14,98,79,131,4,201,100,35,138,49,39,218,76,67,232,38,75, +33,32,49,137,62,12,24,178,18,68,152,147,237,38,33,244,24,178,18,132,24,147, +225,221,72,202,200,75,22,98,79,180,152,143,215,82,50,178,19,5,24,147,227, +16,218,76,146,178,19,70,152,147,237,38,38,117,13,164,201,43,33,56,81,137, +62,72,130,115,71,43,33,60,105,137,62,210,98,151,72,39,52,114,178,20,7,152, +147,227,16,181,162,68,19,154,57,89,10,36,140,73,246,147,19,58,133,173,18, +32,156,209,202,200,82,34,98,79,147,67,9,151,52,156,113,75,34,78,208,1,228, +73,242,104,97,46,16,62,68,159,24,133,173,18,32,156,209,202,217,83,37,34,79, +180,152,153,212,45,104,145,4,230,142,86,202,160,169,18,124,145,4,230,142, +86,215,213,27,34,79,180,152,165,210,9,205,28,173,175,172,42,68,159,24,134, +210,100,149,183,245,198,200,147,237,38,38,117,13,164,201,43,111,236,8,145, +39,195,186,145,149,185,246,69,200,147,237,38,35,245,212,140,173,207,180,30, +68,159,6,9,146,217,91,21,34,79,180,152,135,208,76,150,202,224,137,18,124, +99,155,51,219,95,116,92,137,62,210,98,103,92,217,158,218,251,194,228,73, +240,180,90,249,130,2,54,223,223,29,34,79,180,152,139,218,45,124,193,1,27, +111,240,33,204,73,243,4,4,108,134,8,60,137,62,96,128,141,178,193,193,154,3, +147,32,227,36,0,0,0,0,0,0,0,0,99,115,245,195,19,159,176,75,175,159,176,24, +172,253,129,49,121,251,2,176,66,92,130,235,16,18,100,148,251,36,106,123,64, +65,158,3,147,160,108,202,62,68,165,107,243,227,113,198,211,62,39,20,108, +115,226,241,130,106,113,224,78,162,4,242,130,236,197,60,37,64,190,18,49, +116,114,37,40,157,76,9,229,37,217,138,185,16,52,196,225,35,23,71,34,82,137, +213,64,158,84,93,152,187,145,33,73,18,52,68,225,35,23,71,34,82,137,213,192, +158,86,93,152,175,146,195,102,11,240,145,139,163,145,41,68,235,32,79,44,46, +204,83,201,225,228,225,35,23,71,34,82,137,214,192,158,90,93,152,163,180, +138,9,216,197,209,200,148,161,194,32,30,18,2,0,45,248,84,88,162,187,72,78, +173,186,58,16,16,0,154,236,110,237,85,69,129,245,109,210,128,127,204,92, +133,253,244,115,222,23,171,113,180,137,0,255,220,85,29,148,174,11,248,55, +86,227,104,232,18,1,254,222,91,216,169,55,40,112,46,189,16,16,2,72,126,213, +17,11,70,3,246,80,140,244,118,180,160,31,243,80,79,51,63,157,230,133,236, +161,25,233,64,63,246,160,158,102,127,59,205,41,248,30,75,12,11,151,242,233, +187,146,156,80,211,114,96,54,230,41,20,129,128,50,211,16,16,2,116,180,196, +129,1,36,55,76,74,16,19,3,116,196,193,65,48,55,75,80,128,65,6,51,211,20, +128,130,34,23,166,39,6,39,75,76,80,1,146,239,211,20,16,165,91,157,29,49,66, +10,124,61,211,209,175,1,173,198,211,20,48,139,113,180,180,197,36,42,220, +109,29,13,49,74,6,192,95,72,188,6,196,55,74,188,6,247,91,80,136,26,32,104, +220,205,56,1,98,234,52,122,98,136,14,72,110,152,162,132,148,35,61,49,70,7, +48,55,76,81,194,206,52,104,180,197,45,192,80,175,4,100,77,10,2,101,56,161, +166,65,113,162,98,8,3,131,7,169,35,36,57,176,16,52,232,80,0,0,0,0,45,158, +10,225,223,132,17,13,43,176,228,3,0,167,129,32,17,133,134,32,25,80,220,40, +240,25,26,44,32,240,24,200,44,24,240,56,156,199,128,83,193,17,7,4,13,128,0, +10,79,202,28,223,195,1,197,72,196,141,159,220,7,48,33,7,8,3,152,49,117,60, +240,76,47,60,9,224,187,56,43,224,221,64,172,156,36,98,232,228,96,220,145, +139,163,182,134,237,146,49,116,118,206,6,141,104,105,136,32,14,4,128,160, +123,215,140,147,32,145,57,178,156,104,41,228,151,168,225,144,168,105,56, +248,185,228,140,241,190,100,209,244,80,210,116,151,134,12,73,241,214,111, +31,23,60,145,158,56,50,72,81,67,230,232,239,209,7,24,147,227,226,233,186, +120,121,56,226,241,137,116,189,52,6,34,92,37,230,70,201,1,89,56,36,154,110, +25,49,23,196,149,35,103,194,94,100,108,144,230,203,136,73,174,234,63,52, +252,212,87,0,131,138,4,12,137,114,168,37,166,144,230,37,5,7,19,39,22,70, +154,103,143,252,4,11,37,160,68,164,139,7,24,3,152,182,20,28,76,156,89,26, +105,158,63,240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253,132, +176,230,36,248,134,207,98,138,99,4,24,147,229,16,217,236,81,75,98,12,73, +241,13,158,142,181,20,198,137,49,39,202,33,179,209,214,162,151,4,24,147, +226,27,61,61,42,41,142,18,98,79,148,67,103,167,165,69,46,138,49,39,194,173, +192,158,158,149,20,188,40,196,159,10,183,2,122,218,148,82,248,121,18,124, +67,103,177,77,177,130,36,73,242,136,108,246,41,181,177,18,36,248,134,207, +71,90,155,99,68,200,147,229,16,217,232,235,83,107,130,36,73,241,13,158,158, +149,54,199,9,145,39,202,33,179,211,210,166,215,69,72,147,225,86,224,79,79, +74,155,94,21,34,79,133,91,129,61,109,74,109,126,14,56,7,6,20,28,76,156,89, +26,105,158,63,240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253, +130,235,191,232,8,149,2,8,196,24,164,137,141,200,8,71,161,196,201,45,167, +146,59,68,89,24,70,206,1,255,128,0,0,0,0,0,1,142,49,232,71,161,196,201,45, +167,146,59,68,89,24,70,206,1,255,128,0,0,0,0,0,1,141,201,8,71,161,196,201, +45,167,146,59,68,89,24,70,206,1,255,128,0,0,0,0,0,2,138,2,214,225,113,235, +2,27,128,0,10,66,3,189,96,67,120,226,224,0,2,148,140,113,145,66,61,14,38, +73,109,60,145,218,34,200,194,54,112,15,252,0,0,0,0,0,0,12,110,80,66,61,14, +38,73,109,60,145,218,34,200,194,54,112,15,252,0,0,0,0,0,0,12,113,147,66,61, +14,38,73,109,60,145,218,34,200,194,54,112,15,252,0,0,0,0,0,0,12,110,88,66, +61,14,38,73,109,60,145,218,34,200,194,54,112,16,0,0,0,0,0,0,0,12,113,149, +66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,0,0,0,0,0,0,0,12,110,96, +66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,0,0,0,0,0,0,0,12,113, +151,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,0,0,0,0,0,0,0,12, +110,104,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0,0,0,0,0,0, +12,113,153,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0,0,0,0,0, +0,12,110,112,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0,0,0,0, +0,0,12,113,155,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0,0,0, +0,0,0,12,110,120,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0,0, +0,0,0,0,12,113,157,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0, +0,0,0,0,0,12,110,128,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,8, +0,0,0,0,0,0,12,113,159,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16, +8,0,0,0,0,0,0,8,58,32,128,24,78,104,129,61,82,2,145,46,17,162,112,208,211, +107,200,16,137,112,52,41,73,29,113,2,131,137,147,139,35,77,51,234,80,14,39, +49,224,137,40,35,100,141,9,136,19,18,0,125,162,58,217,236,81,64,68,72,1, +241,13,158,197,20,150,50,36,0,251,68,117,179,209,214,234,201,69,16,100,72, +1,246,136,235,103,163,173,208,146,138,68,23,18,0,124,67,103,163,173,213, +146,138,76,23,18,0,124,67,103,163,173,208,146,138,84,25,18,0,125,162,58, +217,233,233,117,100,162,138,50,36,0,251,68,117,179,211,210,232,73,69,34, +139,137,0,62,33,179,211,210,234,201,69,38,139,137,0,62,33,179,211,210,232, +73,69,42,139,137,0,62,21,110,4,250,178,81,70,23,18,0,124,42,220,9,244,36, +162,145,134,68,128,31,6,234,5,100,234,201,69,28,100,72,1,240,110,160,86,78, +132,148,82,56,168,144,3,237,17,214,207,171,37,22,128,42,36,0,251,68,117, +179,232,73,69,164,9,137,0,62,33,179,234,201,69,168,9,137,0,62,33,179,232, +73,69,172,10,180,81,50,118,136,235,103,177,77,129,54,138,38,78,33,179,216, +166,210,198,218,40,153,59,68,117,179,209,214,234,201,77,144,109,162,137, +147,180,71,91,61,29,110,132,148,218,32,203,69,19,39,16,217,232,235,117,100, +166,211,6,90,40,153,56,134,207,71,91,161,37,54,168,54,209,68,201,218,35, +173,158,158,151,86,74,108,163,109,20,76,157,162,58,217,233,233,116,36,166, +209,70,90,40,153,56,134,207,79,75,171,37,54,154,50,209,68,201,196,54,122, +122,93,9,41,181,81,150,138,38,78,21,110,4,250,178,83,102,25,104,162,100, +225,86,224,79,161,37,54,140,54,209,68,201,193,186,129,89,58,178,83,103,27, +104,162,100,224,221,64,172,157,9,41,180,113,118,138,38,78,209,29,108,250, +178,83,136,2,237,20,76,157,162,58,217,244,36,167,18,5,90,40,153,56,134,207, +171,37,56,160,42,209,68,201,196,54,125,9,41,197,141,78,197,141,86,192,0, +133,66,215,173,96,49,33,64,46,84,8,14,39,49,224,137,40,18,4,19,159,141,100, +1,100,180,8,148,146,0,91,69,19,38,202,8,58,64,28,209,160,130,52,78,26,26, +110,255,80,64,196,104,156,50,125,4,144,116,192,57,165,97,4,104,156,52,52, +221,254,64,20,160,152,23,223,228,32,148,25,174,137,58,23,51,191,200,84,12, +50,9,195,39,196,80, }; #elif defined(DUK_USE_DOUBLE_ME) -DUK_INTERNAL const duk_uint8_t duk_builtins_data[3790] = { +DUK_INTERNAL const duk_uint8_t duk_builtins_data[3819] = { 144,148,105,221,32,68,52,228,62,12,104,200,165,134,148,248,81,77,61,191, 135,35,154,103,34,72,6,157,159,197,145,77,245,126,52,130,106,234,163,196, 52,226,18,51,161,26,113,1,60,37,64,190,18,49,116,116,33,26,113,1,92,136,26, 98,112,145,139,163,165,8,211,136,14,228,72,82,68,141,17,56,72,197,209,212, 132,105,196,5,242,88,108,193,126,18,49,116,117,161,26,113,1,60,158,30,78, -18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,224,59, -147,60,93,110,79,15,39,9,24,186,33,13,63,79,185,39,26,121,223,110,77,66,53, -116,1,120,248,186,248,136,67,76,196,200,134,186,137,177,13,31,192,174,79, -15,32,248,8,196,24,8,107,254,39,97,161,175,248,159,16,215,252,80,186,26, -255,138,57,136,107,254,41,100,33,175,248,167,170,134,191,226,166,138,26, -255,138,187,40,107,254,43,111,33,171,86,181,16,209,241,11,228,201,121,240, -141,19,134,72,196,52,123,168,95,38,75,207,131,32,156,50,70,33,195,3,152, -128,0,1,240,254,0,0,0,1,153,128,0,1,224,254,0,0,0,1,151,137,0,214,9,188,35, -131,12,225,196,56,177,78,60,99,147,28,229,200,57,162,120,74,129,124,36,98, -232,156,241,92,136,26,98,112,145,139,162,116,71,114,36,41,34,70,136,156,36, -98,232,157,49,124,150,27,48,95,132,140,93,19,170,39,147,195,201,194,70,46, -137,215,17,218,69,4,236,98,232,157,153,39,110,81,220,15,193,209,83,3,200, -119,130,241,241,117,240,120,80,252,137,10,178,10,103,134,180,122,9,135,136, -154,120,169,199,142,158,121,10,7,146,162,121,74,71,150,166,121,138,135,154, -170,121,202,199,158,23,201,146,243,225,26,39,12,145,61,16,190,76,151,159,6, -65,56,100,137,233,35,93,205,144,33,224,140,137,196,54,121,244,5,60,17,145, -56,85,184,19,207,16,21,18,227,65,198,231,72,16,137,112,168,106,38,76,225,2, -70,65,56,100,237,34,140,177,4,134,65,56,100,237,34,129,117,204,123,154,70, -207,46,64,146,52,78,25,59,72,163,48,65,34,52,78,25,59,72,160,93,115,30,230, -145,179,204,144,24,146,16,30,76,209,2,40,210,72,64,121,52,4,0,156,88,97,5, -194,96,227,18,124,124,93,55,79,15,39,28,94,49,38,159,154,136,96,196,159,29, -102,241,241,115,201,25,227,131,36,133,20,62,110,142,253,2,102,36,248,235, -55,143,139,158,72,207,28,104,24,73,112,201,3,2,82,65,155,187,94,6,20,72,9, -147,120,128,225,144,168,105,56,248,185,228,140,241,190,96,128,200,84,52, -156,124,92,242,70,104,36,183,168,4,145,0,190,41,1,139,18,19,36,226,146,17, -124,73,82,54,124,37,230,70,201,14,108,184,132,8,68,185,34,1,100,31,8,129,8, -151,11,23,100,141,225,18,12,68,184,75,204,141,146,2,178,112,72,8,162,98,92, -50,10,152,147,227,172,222,62,46,121,35,60,114,88,96,92,185,112,201,65,34, -92,4,1,147,81,159,141,205,32,234,121,96,97,57,64,97,121,128,14,56,37,199, -89,188,124,92,242,70,120,227,144,53,18,227,226,233,186,120,121,56,226,242, -8,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,36,136,48,64,114,0, -250,156,168,1,64,247,175,25,36,2,8,11,94,80,248,16,40,104,242,103,200,48, -193,3,162,92,4,98,12,41,14,66,40,106,101,1,132,130,8,24,78,104,129,54,62, -96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,178, -58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,129, -232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,201, -126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,132, -0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,46, -36,29,4,78,69,6,60,226,31,192,7,255,252,24,160,163,11,23,51,130,56,35,193, -56,100,238,31,6,150,46,103,4,225,147,143,114,27,62,233,241,200,137,182,133, -42,142,167,216,6,23,216,0,97,28,17,224,39,223,32,80,142,8,240,78,25,56,9, -248,8,22,39,12,156,123,144,217,240,19,240,18,6,19,154,32,79,194,124,14,134, -140,151,227,139,226,52,11,88,37,62,33,163,37,248,226,248,141,32,213,184,64, -89,56,39,49,224,137,60,100,5,96,38,35,249,8,15,18,61,96,17,60,200,6,145,1, -17,31,206,64,89,45,2,39,161,0,178,122,209,63,74,2,101,64,202,113,67,77,235, -64,92,221,197,186,196,143,4,9,19,188,1,25,187,139,112,128,178,113,110,177, -35,193,2,68,239,0,46,110,229,30,242,71,130,4,137,222,4,35,55,113,110,16,22, -78,81,239,36,120,32,72,157,224,64,147,138,25,237,0,52,72,242,2,126,82,3,74, -129,148,227,234,66,12,112,28,140,155,104,203,169,158,9,133,158,4,25,36,1, -61,96,47,181,80,46,132,129,255,255,222,255,255,255,255,254,39,172,67,118, -170,5,208,144,0,0,0,0,0,64,0,0,51,16,0,0,62,31,192,0,0,0,8,245,238,146,38, -138,147,105,13,42,26,137,226,0,0,7,131,248,0,0,0,1,30,180,134,4,209,82,109, -33,165,67,81,60,64,0,0,240,255,0,0,0,0,28,144,155,104,0,0,0,0,0,0,0,0,16, -117,59,130,48,155,98,48,187,144,3,205,220,42,46,65,237,72,27,55,112,151, -123,154,70,205,0,94,208,129,115,119,31,18,9,18,67,155,183,34,12,176,96,175, -4,100,74,228,3,237,38,43,31,192,109,117,171,0,228,164,219,72,0,0,248,127,0, -0,0,0,196,234,111,0,50,110,224,193,50,114,83,138,26,107,192,131,38,238,77, -12,39,37,56,161,166,188,11,132,188,12,74,110,226,220,32,44,156,24,38,78,74, -113,67,77,120,28,148,221,197,184,64,89,57,52,48,156,148,226,134,154,240,64, -195,94,8,56,123,193,11,85,116,140,45,240,3,152,147,228,208,194,95,0,89,137, -62,22,139,95,48,64,70,200,67,28,98,79,180,152,139,218,45,124,193,1,27,33, -16,65,137,62,49,205,153,236,132,81,102,36,251,73,137,157,115,102,123,33,24, -57,137,62,12,19,37,144,142,40,196,159,105,49,15,160,153,44,132,128,198,36, -248,48,98,200,73,18,98,79,180,152,135,208,98,200,74,16,98,79,135,117,35,43, -33,44,89,137,62,210,98,63,93,72,202,200,76,20,98,79,140,67,105,50,74,200, -77,26,98,79,180,152,153,212,54,147,36,172,132,225,70,36,249,34,9,205,28, -172,132,241,166,36,251,73,138,93,32,156,209,202,200,80,30,98,79,140,66,214, -137,16,78,104,229,100,40,146,49,39,218,76,76,234,22,180,72,130,115,71,43, -33,72,137,137,62,77,12,38,92,210,113,197,44,137,59,64,7,145,39,201,161,132, -184,64,249,18,124,98,22,180,72,130,115,71,43,101,76,148,137,62,210,98,103, -80,181,162,68,19,154,57,91,42,130,164,73,242,68,19,154,57,91,95,84,108,137, -62,210,98,151,72,39,52,114,182,190,176,169,18,124,98,27,73,146,86,223,215, -27,34,79,180,152,153,212,54,147,36,173,191,176,34,68,159,14,234,70,86,231, -217,23,34,79,180,152,143,215,82,50,183,62,208,121,18,124,24,38,75,101,108, -84,137,62,210,98,31,65,50,91,43,130,36,73,241,142,108,207,109,125,209,114, -36,251,73,137,157,115,102,123,107,239,11,145,39,194,209,107,230,8,8,219, -127,124,116,137,62,210,98,47,104,181,243,4,4,109,191,192,135,49,39,204,16, -17,178,24,32,242,36,249,130,2,54,203,7,6,104,14,76,131,140,144,0,0,0,0,0,0, -0,1,141,207,215,12,78,126,193,46,190,126,192,98,179,246,4,197,231,236,10, -193,9,114,11,172,64,73,146,83,236,145,169,237,1,6,120,14,78,129,179,40,249, -18,149,175,207,141,199,27,76,248,156,81,177,207,139,198,9,169,199,129,58, -136,19,202,11,179,20,240,149,2,248,72,197,209,200,148,162,117,48,39,148, -151,102,42,228,64,211,19,132,140,93,28,137,74,39,85,2,121,81,118,98,238,68, -133,36,72,209,19,132,140,93,28,137,74,39,87,2,121,89,118,98,190,75,13,152, -47,194,70,46,142,68,165,19,172,129,60,176,187,49,79,39,135,147,132,140,93, -28,137,74,39,91,2,121,105,118,98,142,210,40,39,99,23,71,34,82,135,8,128, -120,72,1,87,224,168,13,42,226,145,97,58,182,232,232,64,177,107,2,64,22,85, -181,187,7,213,183,74,2,17,119,49,255,121,207,215,240,94,173,198,210,36,4, -113,95,115,255,232,34,182,80,221,91,141,163,160,72,15,121,123,103,225,220, -164,194,160,186,244,64,251,33,9,64,24,45,68,84,15,217,66,51,209,218,210, -129,61,65,204,127,154,118,254,204,23,178,132,103,165,2,122,131,216,255,52, -237,253,152,167,224,121,44,48,46,95,203,166,238,74,113,67,77,201,128,219, -152,164,82,6,0,203,76,64,64,9,210,211,18,4,4,144,221,49,40,64,76,13,211,19, -5,4,192,221,45,66,1,4,24,207,76,82,2,8,136,94,152,156,24,157,45,49,64,6,75, -191,76,80,66,149,110,116,116,197,8,41,240,247,79,70,188,6,183,27,76,80,194, -45,198,210,211,20,144,171,113,180,116,52,197,40,27,1,125,34,240,27,16,221, -42,240,27,221,109,66,32,104,129,163,115,52,224,5,139,168,209,233,138,32,57, -33,186,98,138,18,80,140,244,197,24,28,192,221,49,71,11,56,209,162,211,20, -183,1,66,188,17,145,52,40,9,148,226,134,153,5,198,137,136,32,14,12,30,164, -140,144,230,192,0,136,211,64,0,0,0,0,182,120,43,135,126,16,68,52,174,195, -144,12,2,158,4,128,70,22,24,128,101,67,112,163,192,100,104,176,131,192,99, -32,176,99,192,226,115,30,1,79,4,68,28,16,54,0,0,41,254,232,116,62,204,7,21, -35,18,54,127,80,28,192,132,28,32,14,96,197,212,243,193,48,188,240,39,130, -236,224,175,131,117,2,178,112,145,139,163,145,131,114,70,46,142,218,27,182, -72,197,209,219,56,26,53,161,166,32,128,56,18,2,129,239,94,50,76,130,68,230, -202,113,160,167,146,94,163,134,66,161,164,227,226,231,146,51,198,249,147, -71,209,67,73,210,94,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15, -155,163,191,68,28,98,79,143,139,166,233,225,228,227,139,198,37,210,244,208, -24,137,112,151,153,27,36,5,100,224,146,105,184,100,196,95,18,84,141,159,9, -121,145,178,67,155,46,33,38,187,168,252,211,243,81,92,2,14,40,16,50,37,202, -160,150,154,67,152,148,20,28,76,156,89,26,105,158,63,232,16,44,150,129,18, -146,44,28,96,14,98,216,80,113,50,113,100,105,166,120,255,160,20,28,76,156, -113,75,34,78,63,236,3,6,133,41,35,31,242,18,195,152,147,226,27,61,138,41, -140,16,98,79,148,67,103,177,69,45,136,49,39,196,54,122,58,212,83,26,36,196, -159,40,134,207,71,90,138,92,16,98,79,136,108,244,244,168,166,56,73,137,62, -81,13,158,158,149,20,186,40,196,159,10,183,2,122,122,84,82,240,163,18,124, -42,220,9,235,106,81,75,225,228,73,241,13,158,197,54,198,8,145,39,202,33, -179,216,166,214,196,72,147,226,27,61,29,106,109,141,19,34,79,148,67,103, -163,173,77,174,8,145,39,196,54,122,122,84,219,28,38,68,159,40,134,207,79, -74,155,93,21,34,79,133,91,129,61,61,42,109,120,84,137,62,21,110,4,245,181, -41,181,248,56,224,28,24,80,113,50,113,100,105,166,120,255,160,20,28,76,156, -113,75,34,78,63,236,3,6,133,41,35,31,242,11,174,254,160,34,84,8,35,16,98, -146,38,55,32,33,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,30,7,224,0, -0,0,6,56,199,161,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,30,7,224, -0,0,0,6,55,36,33,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,30,7,224, -0,0,0,10,40,11,91,133,199,172,8,111,248,128,239,88,16,222,56,191,242,49, -198,69,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,240,63,0,0,0,0, -49,185,65,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,240,63,0,0,0, -0,49,198,77,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,240,63,0,0, -0,0,49,185,97,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,0, -0,0,49,198,85,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,0, -0,0,49,185,129,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0, -0,0,0,49,198,93,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0, -0,0,0,49,185,161,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,16,64, -0,0,0,0,49,198,101,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,16, -64,0,0,0,0,49,185,193,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0, -16,64,0,0,0,0,49,198,109,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0, -0,16,64,0,0,0,0,49,185,225,8,244,56,153,37,180,242,71,104,139,35,8,217,192, -0,0,16,64,0,0,0,0,49,198,117,8,244,56,153,37,180,242,71,104,139,35,8,217, -192,0,0,16,64,0,0,0,0,49,186,1,8,244,56,153,37,180,242,71,104,139,35,8,217, -192,0,0,32,64,0,0,0,0,49,198,125,8,244,56,153,37,180,242,71,104,139,35,8, -217,192,0,0,32,64,0,0,0,0,32,232,130,0,97,57,162,4,245,72,10,68,184,70,137, -195,67,77,175,32,66,37,192,208,165,36,117,196,10,14,38,78,44,141,52,207, -169,64,56,156,199,130,36,160,141,146,52,38,32,76,72,1,246,136,235,103,177, -69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,171,37,20, -65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,158,142,183, -86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,246,136,235, -103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,37,20,138,46, -36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,75,161,37,20, -170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,39,208,146,138, -70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,129,89,58,18, -81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,17,214,207,161, -37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,207,161,37,22, -176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,207,98,155,75, -27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,78,209,29,108, -244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,146,155,76,25, -104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,104,142,182,122, -122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,146,155,69,25, -104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,217,233,233, -116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,162,137,147, -133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,77,156,109, -162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,117,179,234, -201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,162,100,226, -27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,59,22,53,91,0,2, -21,11,94,181,128,196,133,0,185,80,32,56,156,199,130,36,160,72,16,78,126,53, -144,5,146,208,34,82,72,1,109,20,76,155,40,32,233,0,115,70,130,8,209,56,104, -105,187,252,193,3,17,162,112,201,242,18,65,211,0,230,149,132,17,162,112, -208,211,119,248,0,82,130,96,95,127,128,130,80,102,186,36,232,92,206,255,1, -80,48,200,39,12,158,241,64, +18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,232,59, +147,60,93,110,79,15,39,9,24,186,33,13,63,111,185,16,211,206,251,114,98,17, +171,160,11,199,197,215,196,66,26,102,38,68,53,212,77,136,104,255,5,114,120, +121,7,192,70,32,192,67,95,249,59,13,13,127,228,248,134,191,242,133,208,215, +254,81,204,67,95,249,75,33,13,127,229,61,84,53,255,149,52,80,215,254,85, +217,67,95,249,91,121,13,90,181,168,134,143,152,95,38,75,207,132,104,156,50, +70,33,163,225,66,249,50,94,124,25,4,225,146,49,14,24,28,196,0,0,15,135,240, +0,0,0,12,204,0,0,15,7,240,0,0,0,12,188,72,6,176,77,225,28,24,103,14,33,197, +138,113,227,28,152,231,46,65,205,19,194,84,11,225,35,23,68,231,138,228,64, +211,19,132,140,93,19,162,59,145,33,73,18,52,68,225,35,23,68,233,139,228, +176,217,130,252,36,98,232,157,81,60,158,30,78,18,49,116,78,184,142,210,40, +39,99,23,68,236,201,59,114,142,224,126,14,138,152,30,67,188,23,143,139,175, +131,194,135,228,72,85,144,83,60,53,163,208,76,60,68,211,197,78,60,116,243, +200,80,60,149,19,202,82,60,181,51,204,84,60,213,83,206,86,60,240,190,76, +151,159,8,209,56,100,137,232,133,242,100,188,248,50,9,195,36,79,73,26,238, +108,129,15,4,100,78,33,179,207,160,41,224,140,137,194,173,192,158,120,128, +168,151,26,14,55,58,64,132,75,133,67,81,50,103,8,18,50,9,195,39,105,20,101, +136,36,50,9,195,39,105,20,11,174,99,220,210,54,121,114,4,145,162,112,201, +218,69,25,130,9,17,162,112,201,218,69,2,235,152,247,52,141,158,100,128,196, +144,128,242,102,136,17,70,146,66,3,201,160,32,0,130,225,48,113,137,62,62, +46,155,167,135,147,142,47,24,147,79,205,68,48,98,79,142,179,120,248,185, +228,140,241,193,146,66,138,31,55,71,126,129,51,18,124,117,155,199,197,207, +36,103,142,52,12,36,184,100,129,129,41,32,205,221,175,3,10,36,4,201,188,64, +112,200,84,52,156,124,92,242,70,120,223,48,64,100,42,26,78,62,46,121,35,52, +18,91,212,2,72,128,95,20,128,197,137,9,146,113,73,8,190,36,169,27,62,18, +243,35,100,135,54,92,66,4,34,92,145,0,178,15,132,64,132,75,133,139,178,70, +240,137,6,34,92,37,230,70,201,1,89,56,36,4,81,49,46,25,5,76,73,241,214,111, +31,23,60,145,158,57,44,48,46,92,184,100,160,145,46,2,0,201,168,207,198,230, +144,117,60,176,48,156,160,48,188,192,7,28,18,227,172,222,62,46,121,35,60, +113,200,26,137,113,241,116,221,60,60,156,113,121,4,20,124,92,242,70,120, +226,37,194,54,140,36,64,21,147,146,68,24,32,57,0,125,78,84,0,160,123,215, +140,146,1,4,5,175,40,124,8,20,52,121,51,228,24,96,129,209,46,2,49,6,20,135, +33,20,53,50,128,194,65,4,12,39,52,64,155,31,48,112,72,6,247,62,16,1,31,73, +30,25,240,60,73,82,70,68,138,0,89,29,5,156,96,2,201,104,17,35,160,18,78, +140,228,16,26,79,90,4,73,43,192,244,108,142,130,206,89,240,58,26,50,95,142, +43,159,65,107,4,167,196,52,100,191,28,87,63,128,15,255,240,164,169,35,136, +6,128,146,115,9,0,210,7,43,163,194,0,71,128,105,65,176,15,128,105,131,21, +11,153,35,0,211,134,137,7,65,18,33,244,23,18,14,130,39,34,131,30,113,15, +224,3,255,254,12,80,81,133,139,153,193,28,17,224,156,50,119,15,131,75,23, +51,130,112,201,199,185,13,159,116,248,228,68,219,66,149,83,83,238,3,11,238, +0,48,142,8,240,19,239,144,40,71,4,120,39,12,156,4,252,4,11,19,134,78,61, +200,108,248,9,248,9,3,9,205,16,39,225,62,7,67,70,75,241,197,241,154,5,172, +18,159,16,209,146,252,113,124,102,144,106,220,32,44,156,19,152,240,68,158, +66,2,176,19,17,252,164,7,137,30,176,8,158,116,3,72,128,136,143,232,32,44, +150,129,19,210,128,89,61,104,159,169,1,50,160,101,56,161,166,246,160,46, +110,226,221,98,71,130,4,137,222,0,140,221,197,184,64,89,56,183,88,145,224, +129,34,119,128,23,55,114,143,121,35,193,2,68,239,2,17,155,184,183,8,11,39, +40,247,146,60,16,36,78,240,32,73,197,12,247,128,26,36,121,1,63,49,2,165,48, +70,114,229,145,51,250,205,2,8,209,203,150,68,207,235,52,130,16,209,46,131, +36,188,70,128,210,160,101,56,251,16,131,28,7,35,38,218,50,234,103,130,97, +103,129,6,73,0,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,7,36,38,218,0, +0,0,0,0,0,0,0,4,29,78,224,140,38,216,140,46,228,0,243,119,10,139,144,123, +82,6,205,220,37,222,230,145,179,64,23,180,32,92,221,199,196,130,68,144,230, +237,200,131,44,24,43,193,25,18,185,0,251,73,138,199,240,27,93,106,192,57, +41,54,210,0,0,62,31,192,0,0,0,49,58,155,192,12,155,184,48,76,156,148,226, +134,154,240,32,201,187,147,67,9,201,78,40,105,175,2,225,47,3,18,155,184, +183,8,11,39,6,9,147,146,156,80,211,94,7,37,55,113,110,16,22,78,77,12,39,37, +56,161,166,188,16,48,215,130,14,30,240,66,213,93,35,11,124,0,230,36,249,52, +48,151,192,22,98,79,133,162,215,204,16,17,178,16,199,24,147,237,38,34,246, +139,95,48,64,70,200,68,16,98,79,140,115,102,123,33,20,89,137,62,210,98,103, +92,217,158,200,70,14,98,79,131,4,201,100,35,138,49,39,218,76,67,232,38,75, +33,32,49,137,62,12,24,178,18,68,152,147,237,38,33,244,24,178,18,132,24,147, +225,221,72,202,200,75,22,98,79,180,152,143,215,82,50,178,19,5,24,147,227, +16,218,76,146,178,19,70,152,147,237,38,38,117,13,164,201,43,33,56,81,137, +62,72,130,115,71,43,33,60,105,137,62,210,98,151,72,39,52,114,178,20,7,152, +147,227,16,181,162,68,19,154,57,89,10,36,140,73,246,147,19,58,133,173,18, +32,156,209,202,200,82,34,98,79,147,67,9,151,52,156,113,75,34,78,208,1,228, +73,242,104,97,46,16,62,68,159,24,133,173,18,32,156,209,202,217,83,37,34,79, +180,152,153,212,45,104,145,4,230,142,86,202,160,169,18,124,145,4,230,142, +86,215,213,27,34,79,180,152,165,210,9,205,28,173,175,172,42,68,159,24,134, +210,100,149,183,245,198,200,147,237,38,38,117,13,164,201,43,111,236,8,145, +39,195,186,145,149,185,246,69,200,147,237,38,35,245,212,140,173,207,180,30, +68,159,6,9,146,217,91,21,34,79,180,152,135,208,76,150,202,224,137,18,124, +99,155,51,219,95,116,92,137,62,210,98,103,92,217,158,218,251,194,228,73, +240,180,90,249,130,2,54,223,223,29,34,79,180,152,139,218,45,124,193,1,27, +111,240,33,204,73,243,4,4,108,134,8,60,137,62,96,128,141,178,193,193,154,3, +147,32,227,36,0,0,0,0,0,0,0,0,99,115,245,195,19,159,176,75,175,159,176,24, +172,253,129,49,121,251,2,176,66,92,130,235,16,18,100,148,251,36,106,123,64, +65,158,3,147,160,108,202,62,68,165,107,243,227,113,198,211,62,39,20,108, +115,226,241,130,106,113,224,78,162,4,242,130,236,197,60,37,64,190,18,49, +116,114,37,40,157,76,9,229,37,217,138,185,16,52,196,225,35,23,71,34,82,137, +213,64,158,84,93,152,187,145,33,73,18,52,68,225,35,23,71,34,82,137,213,192, +158,86,93,152,175,146,195,102,11,240,145,139,163,145,41,68,235,32,79,44,46, +204,83,201,225,228,225,35,23,71,34,82,137,214,192,158,90,93,152,163,180, +138,9,216,197,209,200,148,161,194,32,30,18,0,85,248,42,3,74,184,164,88,78, +173,186,58,16,44,90,192,144,5,149,109,110,193,245,109,210,128,132,93,204, +127,222,115,245,252,23,171,113,180,137,1,28,87,220,255,250,8,173,148,55,86, +227,104,232,18,3,222,94,217,248,119,41,48,168,46,189,16,62,200,66,80,6,11, +81,21,3,246,80,140,244,118,180,160,79,80,115,31,230,157,191,179,5,236,161, +25,233,64,158,160,246,63,205,59,127,102,41,248,30,75,12,11,151,242,233,187, +146,156,80,211,114,96,54,230,41,20,129,128,50,211,16,16,2,116,180,196,129, +1,36,55,76,74,16,19,3,116,196,193,65,48,55,75,80,128,65,6,51,211,20,128, +130,34,23,166,39,6,39,75,76,80,1,146,239,211,20,16,165,91,157,29,49,66,10, +124,61,211,209,175,1,173,198,211,20,48,139,113,180,180,197,36,42,220,109, +29,13,49,74,6,192,95,72,188,6,196,55,74,188,6,247,91,80,136,26,32,104,220, +205,56,1,98,234,52,122,98,136,14,72,110,152,162,132,148,35,61,49,70,7,48, +55,76,81,194,206,52,104,180,197,45,192,80,175,4,100,77,10,2,101,56,161,166, +65,113,162,98,8,3,131,7,169,35,36,57,176,16,40,116,208,0,0,0,0,45,158,10, +225,223,132,17,13,43,176,228,3,0,167,129,32,17,133,134,32,25,80,220,40,240, +25,26,44,32,240,24,200,44,24,240,56,156,199,128,83,193,17,7,4,13,128,0,10, +79,202,28,223,195,1,197,72,196,141,159,220,7,48,33,7,8,3,152,49,117,60,240, +76,47,60,9,224,187,56,43,224,221,64,172,156,36,98,232,228,96,220,145,139, +163,182,134,237,146,49,116,118,206,6,141,104,105,136,32,14,4,128,160,123, +215,140,147,32,145,57,178,156,104,41,228,151,168,225,144,168,105,56,248, +185,228,140,241,190,100,209,244,80,210,116,151,134,12,73,241,214,111,31,23, +60,145,158,56,50,72,81,67,230,232,239,209,7,24,147,227,226,233,186,120,121, +56,226,241,137,116,189,52,6,34,92,37,230,70,201,1,89,56,36,154,110,25,49, +23,196,149,35,103,194,94,100,108,144,230,203,136,73,174,234,63,52,252,212, +87,0,131,138,4,12,137,114,168,37,166,144,230,37,5,7,19,39,22,70,154,103, +143,252,4,11,37,160,68,164,139,7,24,3,152,182,20,28,76,156,89,26,105,158, +63,240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253,132,176,230, +36,248,134,207,98,138,99,4,24,147,229,16,217,236,81,75,98,12,73,241,13,158, +142,181,20,198,137,49,39,202,33,179,209,214,162,151,4,24,147,226,27,61,61, +42,41,142,18,98,79,148,67,103,167,165,69,46,138,49,39,194,173,192,158,158, +149,20,188,40,196,159,10,183,2,122,218,148,82,248,121,18,124,67,103,177,77, +177,130,36,73,242,136,108,246,41,181,177,18,36,248,134,207,71,90,155,99,68, +200,147,229,16,217,232,235,83,107,130,36,73,241,13,158,158,149,54,199,9, +145,39,202,33,179,211,210,166,215,69,72,147,225,86,224,79,79,74,155,94,21, +34,79,133,91,129,61,109,74,109,126,14,56,7,6,20,28,76,156,89,26,105,158,63, +240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253,130,235,191, +232,8,149,2,8,196,24,164,137,141,200,8,71,161,196,201,45,167,146,59,68,89, +24,70,206,0,0,7,129,248,0,0,0,1,142,49,232,71,161,196,201,45,167,146,59,68, +89,24,70,206,0,0,7,129,248,0,0,0,1,141,201,8,71,161,196,201,45,167,146,59, +68,89,24,70,206,0,0,7,129,248,0,0,0,2,138,2,214,225,113,235,2,27,128,0,10, +66,3,189,96,67,120,226,224,0,2,148,140,113,145,66,61,14,38,73,109,60,145, +218,34,200,194,54,112,0,0,60,15,192,0,0,0,12,110,80,66,61,14,38,73,109,60, +145,218,34,200,194,54,112,0,0,60,15,192,0,0,0,12,113,147,66,61,14,38,73, +109,60,145,218,34,200,194,54,112,0,0,60,15,192,0,0,0,12,110,88,66,61,14,38, +73,109,60,145,218,34,200,194,54,112,0,0,0,16,0,0,0,0,12,113,149,66,61,14, +38,73,109,60,145,218,34,200,194,54,112,0,0,0,16,0,0,0,0,12,110,96,66,61,14, +38,73,109,60,145,218,34,200,194,54,112,0,0,0,16,0,0,0,0,12,113,151,66,61, +14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,16,0,0,0,0,12,110,104,66, +61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0,0,0,12,113,153, +66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0,0,0,12,110, +112,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0,0,0,12, +113,155,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0,0,0, +12,110,120,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0,0, +0,12,113,157,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0, +0,0,12,110,128,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,8,16,0, +0,0,0,12,113,159,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,8,16, +0,0,0,0,8,58,32,128,24,78,104,129,61,82,2,145,46,17,162,112,208,211,107, +200,16,137,112,52,41,73,29,113,2,131,137,147,139,35,77,51,234,80,14,39,49, +224,137,40,35,100,141,9,136,19,18,0,125,162,58,217,236,81,64,68,72,1,241, +13,158,197,20,150,50,36,0,251,68,117,179,209,214,234,201,69,16,100,72,1, +246,136,235,103,163,173,208,146,138,68,23,18,0,124,67,103,163,173,213,146, +138,76,23,18,0,124,67,103,163,173,208,146,138,84,25,18,0,125,162,58,217, +233,233,117,100,162,138,50,36,0,251,68,117,179,211,210,232,73,69,34,139, +137,0,62,33,179,211,210,234,201,69,38,139,137,0,62,33,179,211,210,232,73, +69,42,139,137,0,62,21,110,4,250,178,81,70,23,18,0,124,42,220,9,244,36,162, +145,134,68,128,31,6,234,5,100,234,201,69,28,100,72,1,240,110,160,86,78,132, +148,82,56,168,144,3,237,17,214,207,171,37,22,128,42,36,0,251,68,117,179, +232,73,69,164,9,137,0,62,33,179,234,201,69,168,9,137,0,62,33,179,232,73,69, +172,10,180,81,50,118,136,235,103,177,77,129,54,138,38,78,33,179,216,166, +210,198,218,40,153,59,68,117,179,209,214,234,201,77,144,109,162,137,147, +180,71,91,61,29,110,132,148,218,32,203,69,19,39,16,217,232,235,117,100,166, +211,6,90,40,153,56,134,207,71,91,161,37,54,168,54,209,68,201,218,35,173, +158,158,151,86,74,108,163,109,20,76,157,162,58,217,233,233,116,36,166,209, +70,90,40,153,56,134,207,79,75,171,37,54,154,50,209,68,201,196,54,122,122, +93,9,41,181,81,150,138,38,78,21,110,4,250,178,83,102,25,104,162,100,225,86, +224,79,161,37,54,140,54,209,68,201,193,186,129,89,58,178,83,103,27,104,162, +100,224,221,64,172,157,9,41,180,113,118,138,38,78,209,29,108,250,178,83, +136,2,237,20,76,157,162,58,217,244,36,167,18,5,90,40,153,56,134,207,171,37, +56,160,42,209,68,201,196,54,125,9,41,197,141,78,197,141,86,192,0,133,66, +215,173,96,49,33,64,46,84,8,14,39,49,224,137,40,18,4,19,159,141,100,1,100, +180,8,148,146,0,91,69,19,38,202,8,58,64,28,209,160,130,52,78,26,26,110,255, +80,64,196,104,156,50,125,4,144,116,192,57,165,97,4,104,156,52,52,221,254, +64,20,160,152,23,223,228,32,148,25,174,137,58,23,51,191,200,84,12,50,9,195, +39,196,80, }; #else #error invalid endianness defines diff -Nru duktape-2.0.0/src-separate/duk_builtins.h duktape-2.1.1/src-separate/duk_builtins.h --- duktape-2.0.0/src-separate/duk_builtins.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_builtins.h 2017-07-28 22:05:08.000000000 +0000 @@ -296,233 +296,224 @@ #define DUK_STRIDX_INT_PC2LINE 95 /* '\xffPc2line' */ #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_ARGS 96 /* '\xffArgs' */ +#define DUK_STRIDX_INT_THIS 96 /* '\xffThis' */ +#define DUK_HEAP_STRING_INT_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THIS) +#define DUK_HTHREAD_STRING_INT_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THIS) +#define DUK_STRIDX_INT_ARGS 97 /* '\xffArgs' */ #define DUK_HEAP_STRING_INT_ARGS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_ARGS) #define DUK_HTHREAD_STRING_INT_ARGS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_ARGS) -#define DUK_STRIDX_INT_MAP 97 /* '\xffMap' */ +#define DUK_STRIDX_INT_MAP 98 /* '\xffMap' */ #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 98 /* '\xffVarenv' */ +#define DUK_STRIDX_INT_VARENV 99 /* '\xffVarenv' */ #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 99 /* '\xffFinalizer' */ +#define DUK_STRIDX_INT_FINALIZER 100 /* '\xffFinalizer' */ #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_HANDLER 100 /* '\xffHandler' */ -#define DUK_HEAP_STRING_INT_HANDLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_HANDLER) -#define DUK_HTHREAD_STRING_INT_HANDLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_HANDLER) -#define DUK_STRIDX_INT_CALLEE 101 /* '\xffCallee' */ -#define DUK_HEAP_STRING_INT_CALLEE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_CALLEE) -#define DUK_HTHREAD_STRING_INT_CALLEE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_CALLEE) -#define DUK_STRIDX_INT_THREAD 102 /* '\xffThread' */ -#define DUK_HEAP_STRING_INT_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THREAD) -#define DUK_HTHREAD_STRING_INT_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THREAD) -#define DUK_STRIDX_INT_REGBASE 103 /* '\xffRegbase' */ -#define DUK_HEAP_STRING_INT_REGBASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_REGBASE) -#define DUK_HTHREAD_STRING_INT_REGBASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_REGBASE) -#define DUK_STRIDX_INT_TARGET 104 /* '\xffTarget' */ +#define DUK_STRIDX_INT_TARGET 101 /* '\xffTarget' */ #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_THIS 105 /* '\xffThis' */ -#define DUK_HEAP_STRING_INT_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THIS) -#define DUK_HTHREAD_STRING_INT_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THIS) -#define DUK_STRIDX_COMPILE 106 /* 'compile' */ +#define DUK_STRIDX_INT_HANDLER 102 /* '\xffHandler' */ +#define DUK_HEAP_STRING_INT_HANDLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_HANDLER) +#define DUK_HTHREAD_STRING_INT_HANDLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_HANDLER) +#define DUK_STRIDX_COMPILE 103 /* '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 107 /* 'input' */ +#define DUK_STRIDX_INPUT 104 /* '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 108 /* 'errCreate' */ +#define DUK_STRIDX_ERR_CREATE 105 /* '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 109 /* 'errThrow' */ +#define DUK_STRIDX_ERR_THROW 106 /* '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 110 /* 'env' */ +#define DUK_STRIDX_ENV 107 /* '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 111 /* 'hex' */ +#define DUK_STRIDX_HEX 108 /* '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 112 /* 'base64' */ +#define DUK_STRIDX_BASE64 109 /* '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 113 /* 'jx' */ +#define DUK_STRIDX_JX 110 /* '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 114 /* 'jc' */ +#define DUK_STRIDX_JC 111 /* '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_RESUME 115 /* 'resume' */ +#define DUK_STRIDX_RESUME 112 /* 'resume' */ #define DUK_HEAP_STRING_RESUME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RESUME) #define DUK_HTHREAD_STRING_RESUME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RESUME) -#define DUK_STRIDX_JSON_EXT_UNDEFINED 116 /* '{"_undef":true}' */ +#define DUK_STRIDX_JSON_EXT_UNDEFINED 113 /* '{"_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_STRIDX_JSON_EXT_NAN 114 /* '{"_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_STRIDX_JSON_EXT_POSINF 115 /* '{"_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_STRIDX_JSON_EXT_NEGINF 116 /* '{"_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_STRIDX_JSON_EXT_FUNCTION1 117 /* '{"_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_STRIDX_JSON_EXT_FUNCTION2 118 /* '{_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_STRIDX_BREAK 119 /* '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_STRIDX_CASE 120 /* '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_STRIDX_CATCH 121 /* '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_STRIDX_CONTINUE 122 /* '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_STRIDX_DEBUGGER 123 /* '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_STRIDX_DEFAULT 124 /* '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_STRIDX_DELETE 125 /* '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_STRIDX_DO 126 /* '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_STRIDX_ELSE 127 /* '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_STRIDX_FINALLY 128 /* '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_STRIDX_FOR 129 /* '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_STRIDX_LC_FUNCTION 130 /* '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_STRIDX_IF 131 /* '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_STRIDX_IN 132 /* '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_STRIDX_INSTANCEOF 133 /* '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_STRIDX_NEW 134 /* '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_STRIDX_RETURN 135 /* '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_STRIDX_SWITCH 136 /* '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_STRIDX_THIS 137 /* '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_STRIDX_THROW 138 /* '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_STRIDX_TRY 139 /* '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_STRIDX_TYPEOF 140 /* '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_STRIDX_VAR 141 /* '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_STRIDX_CONST 142 /* '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_STRIDX_VOID 143 /* '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_STRIDX_WHILE 144 /* '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_STRIDX_WITH 145 /* '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_STRIDX_CLASS 146 /* '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_STRIDX_ENUM 147 /* '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_STRIDX_EXPORT 148 /* '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_STRIDX_EXTENDS 149 /* '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_STRIDX_IMPORT 150 /* '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_STRIDX_SUPER 151 /* '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_STRIDX_LC_NULL 152 /* '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_STRIDX_TRUE 153 /* '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_STRIDX_FALSE 154 /* '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_STRIDX_IMPLEMENTS 155 /* '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_STRIDX_INTERFACE 156 /* '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_STRIDX_LET 157 /* '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_STRIDX_PACKAGE 158 /* '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_STRIDX_PRIVATE 159 /* '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_STRIDX_PROTECTED 160 /* '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_STRIDX_PUBLIC 161 /* '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_STRIDX_STATIC 162 /* '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_STRIDX_YIELD 163 /* '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 */ +#define DUK_HEAP_NUM_STRINGS 164 +#define DUK_STRIDX_START_RESERVED 119 +#define DUK_STRIDX_START_STRICT_RESERVED 155 +#define DUK_STRIDX_END_RESERVED 164 /* 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[921]; +DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[903]; #endif /* !DUK_SINGLE_FILE */ #define DUK_STRDATA_MAX_STRLEN 17 -#define DUK_STRDATA_DATA_LENGTH 921 +#define DUK_STRDATA_DATA_LENGTH 903 #endif /* DUK_USE_ROM_STRINGS */ #if defined(DUK_USE_ROM_OBJECTS) @@ -614,6 +605,8 @@ 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_prototype_to_string(duk_context *ctx); @@ -692,7 +685,7 @@ 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); #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[164]; +DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[166]; #endif /* !DUK_SINGLE_FILE */ #define DUK_BIDX_GLOBAL 0 #define DUK_BIDX_GLOBAL_ENV 1 @@ -773,19 +766,19 @@ #define DUK_NUM_ALL_BUILTINS 74 #if defined(DUK_USE_DOUBLE_LE) #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3790]; +DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3819]; #endif /* !DUK_SINGLE_FILE */ -#define DUK_BUILTINS_DATA_LENGTH 3790 +#define DUK_BUILTINS_DATA_LENGTH 3819 #elif defined(DUK_USE_DOUBLE_BE) #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3790]; +DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3819]; #endif /* !DUK_SINGLE_FILE */ -#define DUK_BUILTINS_DATA_LENGTH 3790 +#define DUK_BUILTINS_DATA_LENGTH 3819 #elif defined(DUK_USE_DOUBLE_ME) #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3790]; +DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3819]; #endif /* !DUK_SINGLE_FILE */ -#define DUK_BUILTINS_DATA_LENGTH 3790 +#define DUK_BUILTINS_DATA_LENGTH 3819 #else #error invalid endianness defines #endif diff -Nru duktape-2.0.0/src-separate/duk_config.h duktape-2.1.1/src-separate/duk_config.h --- duktape-2.0.0/src-separate/duk_config.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_config.h 2017-07-28 22:05:08.000000000 +0000 @@ -1,9 +1,9 @@ /* * duk_config.h configuration header generated by genconfig.py. * - * Git commit: 4180966c47d6d87106008dd4338de8d507c8072b - * Git describe: v2.0.0 - * Git branch: master + * Git commit: 9c8fba6392d1913cb5359be7b8f386fa3cdd8b4d + * Git describe: v2.1.1 + * Git branch: v2.1-maintenance * * Supported platforms: * - Mac OSX, iPhone, Darwin @@ -12,6 +12,7 @@ * - Generic BSD * - Atari ST TOS * - AmigaOS + * - Durango (XboxOne) * - Windows * - Flashplayer (Crossbridge) * - QNX @@ -19,6 +20,8 @@ * - Emscripten * - Linux * - Solaris + * - AIX + * - HPUX * - Generic POSIX * - Cygwin * - Generic UNIX @@ -126,6 +129,11 @@ #endif #endif +/* Durango (Xbox One) */ +#if defined(_DURANGO) || defined(_XBOX_ONE) +#define DUK_F_DURANGO +#endif + /* Windows, both 32-bit and 64-bit */ #if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || \ defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__) @@ -170,6 +178,28 @@ /* illumos / Solaris */ #if defined(__sun) && defined(__SVR4) #define DUK_F_SUN +#if defined(__SUNPRO_C) && (__SUNPRO_C < 0x550) +#define DUK_F_OLD_SOLARIS +/* Defines _ILP32 / _LP64 required by DUK_F_X86/DUK_F_X64. Platforms + * are processed before architectures, so this happens before the + * DUK_F_X86/DUK_F_X64 detection is emitted. + */ +#include +#endif +#endif + +/* AIX */ +#if defined(_AIX) +/* defined(__xlc__) || defined(__IBMC__): works but too wide */ +#define DUK_F_AIX +#endif + +/* HPUX */ +#if defined(__hpux) +#define DUK_F_HPUX +#if defined(__ia64) +#define DUK_F_HPUX_ITANIUM +#endif #endif /* POSIX */ @@ -188,17 +218,6 @@ #define DUK_F_UNIX #endif -/* stdint.h not available */ -#if defined(DUK_F_WINDOWS) && defined(_MSC_VER) -#if (_MSC_VER < 1700) -/* VS2012+ has stdint.h, < VS2012 does not (but it's available for download). */ -#define DUK_F_NO_STDINT_H -#endif -#endif -#if !defined(DUK_F_NO_STDINT_H) && (defined(DUK_F_TOS) || defined(DUK_F_BCC)) -#define DUK_F_NO_STDINT_H -#endif - /* C++ */ #undef DUK_F_CPP #if defined(__cplusplus) @@ -208,6 +227,9 @@ /* Intel x86 (32-bit), x64 (64-bit) or x32 (64-bit but 32-bit pointers), * define only one of DUK_F_X86, DUK_F_X64, DUK_F_X32. * https://sites.google.com/site/x32abi/ + * + * With DUK_F_OLD_SOLARIS the header must be included + * before this. */ #if defined(__amd64__) || defined(__amd64) || \ defined(__x86_64__) || defined(__x86_64) || \ @@ -334,6 +356,15 @@ #define DUK_F_VBCC #endif +#if defined(ANDROID) || defined(__ANDROID__) +#define DUK_F_ANDROID +#endif + +/* Atari Mint */ +#if defined(__MINT__) +#define DUK_F_MINT +#endif + /* * Platform autodetection */ @@ -458,6 +489,40 @@ #if !defined(DUK_USE_BYTEORDER) && (defined(DUK_F_M68K) || defined(DUK_F_PPC)) #define DUK_USE_BYTEORDER 3 #endif +#elif defined(DUK_F_DURANGO) +/* --- Durango (XboxOne) --- */ +/* Durango = XboxOne + * Configuration is nearly identical to Windows, except for + * DUK_USE_DATE_TZO_WINDOWS. + */ + +/* Initial fix: disable secure CRT related warnings when compiling Duktape + * itself (must be defined before including Windows headers). Don't define + * for user code including duktape.h. + */ +#if defined(DUK_COMPILING_DUKTAPE) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +/* MSVC does not have sys/param.h */ +#define DUK_USE_DATE_NOW_WINDOWS +#define DUK_USE_DATE_TZO_WINDOWS_NO_DST +/* Note: PRS and FMT are intentionally left undefined for now. This means + * there is no platform specific date parsing/formatting but there is still + * the ISO 8601 standard format. + */ +#if defined(DUK_COMPILING_DUKTAPE) +/* Only include when compiling Duktape to avoid polluting application build + * with a lot of unnecessary defines. + */ +#include +#endif + +#define DUK_USE_OS_STRING "durango" + +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif #elif defined(DUK_F_WINDOWS) /* --- Windows --- */ /* Initial fix: disable secure CRT related warnings when compiling Duktape @@ -527,6 +592,10 @@ #define DUK_USE_OS_STRING "qnx" #elif defined(DUK_F_TINSPIRE) /* --- TI-Nspire --- */ +#if defined(DUK_COMPILING_DUKTAPE) && !defined(_XOPEN_SOURCE) +#define _XOPEN_SOURCE /* e.g. strptime */ +#endif + #define DUK_USE_DATE_NOW_GETTIMEOFDAY #define DUK_USE_DATE_TZO_GMTIME_R #define DUK_USE_DATE_PRS_STRPTIME @@ -607,12 +676,50 @@ #define DUK_USE_DATE_FMT_STRFTIME #include +#if defined(DUK_F_OLD_SOLARIS) +/* Old Solaris with no endian.h, stdint.h */ +#define DUK_F_NO_STDINT_H +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#else /* DUK_F_OLD_SOLARIS */ #include +#endif /* DUK_F_OLD_SOLARIS */ + #include #include #include #define DUK_USE_OS_STRING "solaris" +#elif defined(DUK_F_AIX) +/* --- AIX --- */ +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include + +#define DUK_USE_OS_STRING "aix" +#elif defined(DUK_F_HPUX) +/* --- HPUX --- */ +#define DUK_F_NO_STDINT_H +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#define DUK_USE_DATE_NOW_GETTIMEOFDAY +#define DUK_USE_DATE_TZO_GMTIME_R +#define DUK_USE_DATE_PRS_STRPTIME +#define DUK_USE_DATE_FMT_STRFTIME +#include +#include +#include + +#define DUK_USE_OS_STRING "hpux" #elif defined(DUK_F_POSIX) /* --- Generic POSIX --- */ #define DUK_USE_DATE_NOW_GETTIMEOFDAY @@ -769,12 +876,8 @@ /* --- MIPS 32-bit --- */ #define DUK_USE_ARCH_STRING "mips32" /* MIPS byte order varies so rely on autodetection. */ -/* Based on 'make checkalign' there are no alignment requirements on - * Linux MIPS except for doubles, which need align by 4. Alignment - * requirements vary based on target though. - */ #if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 4 +#define DUK_USE_ALIGN_BY 8 #endif #define DUK_USE_PACKED_TVAL #define DUK_F_PACKED_TVAL_PROVIDED @@ -782,9 +885,6 @@ /* --- MIPS 64-bit --- */ #define DUK_USE_ARCH_STRING "mips64" /* MIPS byte order varies so rely on autodetection. */ -/* Good default is a bit arbitrary because alignment requirements - * depend on target. See https://github.com/svaarala/duktape/issues/102. - */ #if !defined(DUK_USE_ALIGN_BY) #define DUK_USE_ALIGN_BY 8 #endif @@ -908,6 +1008,9 @@ #define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) #endif +/* DUK_HOT */ +/* DUK_COLD */ + #if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) /* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're * compiling Duktape or the application. @@ -1018,6 +1121,12 @@ #define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) #endif +#if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && \ + defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40300) +#define DUK_HOT __attribute__((hot)) +#define DUK_COLD __attribute__((cold)) +#endif + #if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) /* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're * compiling Duktape or the application. @@ -1424,10 +1533,14 @@ #if defined(DUK_F_X86) || defined(DUK_F_X32) || \ defined(DUK_F_M68K) || defined(DUK_F_PPC32) || \ defined(DUK_F_BCC) || \ - (defined(__WORDSIZE) && (__WORDSIZE == 32)) + (defined(__WORDSIZE) && (__WORDSIZE == 32)) || \ + ((defined(DUK_F_OLD_SOLARIS) || defined(DUK_F_AIX) || \ + defined(DUK_F_HPUX)) && defined(_ILP32)) #define DUK_F_32BIT_PTRS #elif defined(DUK_F_X64) || \ - (defined(__WORDSIZE) && (__WORDSIZE == 64)) + (defined(__WORDSIZE) && (__WORDSIZE == 64)) || \ + ((defined(DUK_F_OLD_SOLARIS) || defined(DUK_F_AIX) || \ + defined(DUK_F_HPUX)) && defined(_LP64)) #define DUK_F_64BIT_PTRS #else /* not sure, not needed with C99 anyway */ @@ -2050,7 +2163,8 @@ #define DUK_DOUBLE_INFINITY (__builtin_inf()) #elif defined(INFINITY) #define DUK_DOUBLE_INFINITY ((double) INFINITY) -#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) +#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) && \ + !defined(DUK_F_OLD_SOLARIS) && !defined(DUK_F_AIX) #define DUK_DOUBLE_INFINITY (1.0 / 0.0) #else /* In VBCC (1.0 / 0.0) results in a warning and 0.0 instead of infinity. @@ -2066,7 +2180,8 @@ #undef DUK_USE_COMPUTED_NAN #if defined(NAN) #define DUK_DOUBLE_NAN NAN -#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) +#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) && \ + !defined(DUK_F_OLD_SOLARIS) && !defined(DUK_F_AIX) #define DUK_DOUBLE_NAN (0.0 / 0.0) #else /* In VBCC (0.0 / 0.0) results in a warning and 0.0 instead of NaN. @@ -2115,6 +2230,9 @@ * To be safe, use replacements. */ #define DUK_F_USE_REPL_ALL +#elif defined(DUK_F_AIX) +/* Older versions may be missing isnan(), etc. */ +#define DUK_F_USE_REPL_ALL #endif #if defined(DUK_F_USE_REPL_ALL) @@ -2203,9 +2321,10 @@ /* The functions below exist only in C99/C++11 or later and need a workaround * for platforms that don't include them. MSVC isn't detected as C99, but * these functions also exist in MSVC 2013 and later so include a clause for - * that too. + * that too. Android doesn't have log2; disable all of these for Android. */ -#if defined(DUK_F_C99) || defined(DUK_F_CPP11) || (defined(_MSC_VER) && (_MSC_VER >= 1800)) +#if (defined(DUK_F_C99) || defined(DUK_F_CPP11) || (defined(_MSC_VER) && (_MSC_VER >= 1800))) && \ + !defined(DUK_F_ANDROID) && !defined(DUK_F_MINT) #if !defined(DUK_CBRT) #define DUK_CBRT cbrt #endif @@ -2218,7 +2337,7 @@ #if !defined(DUK_TRUNC) #define DUK_TRUNC trunc #endif -#endif /* DUK_F_C99 */ +#endif /* DUK_F_C99 etc */ /* NetBSD 6.0 x86 (at least) has a few problems with pow() semantics, * see test-bug-netbsd-math-pow.js. MinGW has similar (but different) @@ -2431,7 +2550,8 @@ /* Macro for suppressing warnings for potentially unreferenced variables. * The variables can be actually unreferenced or unreferenced in some * specific cases only; for instance, if a variable is only debug printed, - * it is unreferenced when debug printing is disabled. + * it is unreferenced when debug printing is disabled. May cause warnings + * for volatile arguments. */ #define DUK_UNREF(x) do { (void) (x); } while (0) #endif @@ -2473,6 +2593,13 @@ #define DUK_ALWAYS_INLINE /*nop*/ #endif +#if !defined(DUK_HOT) +#define DUK_HOT /*nop*/ +#endif +#if !defined(DUK_COLD) +#define DUK_COLD /*nop*/ +#endif + #if !defined(DUK_EXTERNAL_DECL) #define DUK_EXTERNAL_DECL extern #endif @@ -2696,6 +2823,7 @@ #define DUK_USE_FAST_REFCOUNT_DEFAULT #undef DUK_USE_FATAL_HANDLER #define DUK_USE_FINALIZER_SUPPORT +#undef DUK_USE_FINALIZER_TORTURE #undef DUK_USE_FUNCPTR16 #undef DUK_USE_FUNCPTR_DEC16 #undef DUK_USE_FUNCPTR_ENC16 @@ -2704,16 +2832,26 @@ #define DUK_USE_FUNC_NAME_PROPERTY #undef DUK_USE_GC_TORTURE #undef DUK_USE_GET_RANDOM_DOUBLE +#undef DUK_USE_GLOBAL_BINDING #define DUK_USE_GLOBAL_BUILTIN #undef DUK_USE_HEAPPTR16 #undef DUK_USE_HEAPPTR_DEC16 #undef DUK_USE_HEAPPTR_ENC16 #define DUK_USE_HEX_FASTPATH +#define DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT 2 +#define DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT 9 +#define DUK_USE_HOBJECT_ARRAY_MINGROW_ADD 16 +#define DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR 8 +#define DUK_USE_HOBJECT_ENTRY_MINGROW_ADD 16 +#define DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR 8 #define DUK_USE_HOBJECT_HASH_PART +#define DUK_USE_HOBJECT_HASH_PROP_LIMIT 8 #define DUK_USE_HSTRING_ARRIDX #define DUK_USE_HSTRING_CLEN #undef DUK_USE_HSTRING_EXTDATA +#define DUK_USE_HTML_COMMENTS #define DUK_USE_IDCHAR_FASTPATH +#undef DUK_USE_INJECT_HEAP_ALLOC_ERROR #undef DUK_USE_INTERRUPT_COUNTER #undef DUK_USE_INTERRUPT_DEBUG_FIXUP #define DUK_USE_JC @@ -2729,10 +2867,8 @@ #define DUK_USE_JX #define DUK_USE_LEXER_SLIDING_WINDOW #undef DUK_USE_LIGHTFUNC_BUILTINS -#undef DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE #define DUK_USE_MARK_AND_SWEEP_RECLIMIT 256 #define DUK_USE_MATH_BUILTIN -#define DUK_USE_MS_STRINGTABLE_RESIZE #define DUK_USE_NATIVE_CALL_RECLIMIT 1000 #define DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER #define DUK_USE_NONSTD_ARRAY_MAP_TRAILER @@ -2752,9 +2888,9 @@ #undef DUK_USE_PREFER_SIZE #define DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS #undef DUK_USE_REFCOUNT16 +#define DUK_USE_REFCOUNT32 #define DUK_USE_REFERENCE_COUNTING #define DUK_USE_REFLECT_BUILTIN -#undef DUK_USE_REFZERO_FINALIZER_TORTURE #undef DUK_USE_REGEXP_CANON_WORKAROUND #define DUK_USE_REGEXP_COMPILER_RECLIMIT 10000 #define DUK_USE_REGEXP_EXECUTOR_RECLIMIT 10000 @@ -2766,6 +2902,7 @@ #undef DUK_USE_ROM_STRINGS #define DUK_USE_SECTION_B #undef DUK_USE_SELF_TESTS +#define DUK_USE_SHEBANG_COMMENTS #undef DUK_USE_SHUFFLE_TORTURE #define DUK_USE_SOURCE_NONBMP #undef DUK_USE_STRHASH16 @@ -2775,9 +2912,13 @@ #undef DUK_USE_STRICT_UTF8_SOURCE #define DUK_USE_STRING_BUILTIN #undef DUK_USE_STRLEN16 -#undef DUK_USE_STRTAB_CHAIN -#undef DUK_USE_STRTAB_CHAIN_SIZE -#define DUK_USE_STRTAB_PROBE +#define DUK_USE_STRTAB_GROW_LIMIT 17 +#define DUK_USE_STRTAB_MAXSIZE 268435456L +#define DUK_USE_STRTAB_MINSIZE 1024 +#undef DUK_USE_STRTAB_PTRCOMP +#define DUK_USE_STRTAB_RESIZE_CHECK_MASK 255 +#define DUK_USE_STRTAB_SHRINK_LIMIT 6 +#undef DUK_USE_STRTAB_TORTURE #undef DUK_USE_SYMBOL_BUILTIN #define DUK_USE_TAILCALL #define DUK_USE_TARGET_INFO "unknown" @@ -2822,10 +2963,12 @@ #if defined(DUK_USE_DATE_GET_LOCAL_TZOFFSET) /* External provider already defined. */ -#elif defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME) +#elif defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S) || defined(DUK_USE_DATE_TZO_GMTIME) #define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_gmtime((d)) #elif defined(DUK_USE_DATE_TZO_WINDOWS) #define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows((d)) +#elif defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST) +#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows_no_dst((d)) #else #error no provider for DUK_USE_DATE_GET_LOCAL_TZOFFSET() #endif @@ -3307,6 +3450,9 @@ #if defined(DUK_USE_INTEGER_ME) && defined(DUK_USE_INTEGER_BE) #error config option DUK_USE_INTEGER_ME conflicts with option DUK_USE_INTEGER_BE (which is also defined) #endif +#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE) +#error unsupported config option used (option has been removed): DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE +#endif #if defined(DUK_USE_MARK_AND_SWEEP) #error unsupported config option used (option has been removed): DUK_USE_MARK_AND_SWEEP #endif @@ -3319,6 +3465,9 @@ #if defined(DUK_USE_MATH_ROUND) #error unsupported config option used (option has been removed): DUK_USE_MATH_ROUND #endif +#if defined(DUK_USE_MS_STRINGTABLE_RESIZE) +#error unsupported config option used (option has been removed): DUK_USE_MS_STRINGTABLE_RESIZE +#endif #if defined(DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE) #error unsupported config option used (option has been removed): DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE #endif @@ -3349,6 +3498,9 @@ #if defined(DUK_USE_RDTSC) #error unsupported config option used (option has been removed): DUK_USE_RDTSC #endif +#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE) +#error unsupported config option used (option has been removed): DUK_USE_REFZERO_FINALIZER_TORTURE +#endif #if defined(DUK_USE_ROM_GLOBAL_CLONE) && !defined(DUK_USE_ROM_STRINGS) #error config option DUK_USE_ROM_GLOBAL_CLONE requires option DUK_USE_ROM_STRINGS (which is missing) #endif @@ -3379,9 +3531,21 @@ #if defined(DUK_USE_SIGSETJMP) #error unsupported config option used (option has been removed): DUK_USE_SIGSETJMP #endif +#if defined(DUK_USE_STRTAB_CHAIN) +#error unsupported config option used (option has been removed): DUK_USE_STRTAB_CHAIN +#endif +#if defined(DUK_USE_STRTAB_CHAIN_SIZE) +#error unsupported config option used (option has been removed): DUK_USE_STRTAB_CHAIN_SIZE +#endif #if defined(DUK_USE_STRTAB_CHAIN_SIZE) && !defined(DUK_USE_STRTAB_CHAIN) #error config option DUK_USE_STRTAB_CHAIN_SIZE requires option DUK_USE_STRTAB_CHAIN (which is missing) #endif +#if defined(DUK_USE_STRTAB_PROBE) +#error unsupported config option used (option has been removed): DUK_USE_STRTAB_PROBE +#endif +#if defined(DUK_USE_STRTAB_PTRCOMP) && !defined(DUK_USE_HEAPPTR16) +#error config option DUK_USE_STRTAB_PTRCOMP requires option DUK_USE_HEAPPTR16 (which is missing) +#endif #if defined(DUK_USE_TAILCALL) && defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) #error config option DUK_USE_TAILCALL conflicts with option DUK_USE_NONSTD_FUNC_CALLER_PROPERTY (which is also defined) #endif diff -Nru duktape-2.0.0/src-separate/duk_dblunion.h duktape-2.1.1/src-separate/duk_dblunion.h --- duktape-2.0.0/src-separate/duk_dblunion.h 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_dblunion.h 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,423 @@ +/* + * 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/cross endian (e.g. ARM) DUK_USE_DOUBLE_ME + * + * ARM is a special case: ARM double values are in mixed/cross 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. + * + * 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] = 0x000000007ff80000ULL; \ + } while (0) +#define DUK__DBLUNION_IS_NAN_FULL(u) \ + ((((u)->ull[DUK_DBL_IDX_ULL0] & 0x000000007ff00000ULL) == 0x000000007ff00000ULL) && \ + ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0xffffffff000fffffULL) != 0)) +#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x000000007ff80000ULL) +#define DUK__DBLUNION_IS_ANYINF(u) \ + (((u)->ull[DUK_DBL_IDX_ULL0] & 0xffffffff7fffffffULL) == 0x000000007ff00000ULL) +#define DUK__DBLUNION_IS_POSINF(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x000000007ff00000ULL) +#define DUK__DBLUNION_IS_NEGINF(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x00000000fff00000ULL) +#define DUK__DBLUNION_IS_ANYZERO(u) \ + (((u)->ull[DUK_DBL_IDX_ULL0] & 0xffffffff7fffffffULL) == 0x0000000000000000ULL) +#define DUK__DBLUNION_IS_POSZERO(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000000000000ULL) +#define DUK__DBLUNION_IS_NEGZERO(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000080000000ULL) +#else +/* Macros for 64-bit ops + big/little endian doubles. */ +#define DUK__DBLUNION_SET_NAN_FULL(u) do { \ + (u)->ull[DUK_DBL_IDX_ULL0] = 0x7ff8000000000000ULL; \ + } while (0) +#define DUK__DBLUNION_IS_NAN_FULL(u) \ + ((((u)->ull[DUK_DBL_IDX_ULL0] & 0x7ff0000000000000ULL) == 0x7ff0000000000000UL) && \ + ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0x000fffffffffffffULL) != 0)) +#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x7ff8000000000000ULL) +#define DUK__DBLUNION_IS_ANYINF(u) \ + (((u)->ull[DUK_DBL_IDX_ULL0] & 0x7fffffffffffffffULL) == 0x7ff0000000000000ULL) +#define DUK__DBLUNION_IS_POSINF(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x7ff0000000000000ULL) +#define DUK__DBLUNION_IS_NEGINF(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0xfff0000000000000ULL) +#define DUK__DBLUNION_IS_ANYZERO(u) \ + (((u)->ull[DUK_DBL_IDX_ULL0] & 0x7fffffffffffffffULL) == 0x0000000000000000ULL) +#define DUK__DBLUNION_IS_POSZERO(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000000000000ULL) +#define DUK__DBLUNION_IS_NEGZERO(u) \ + ((u)->ull[DUK_DBL_IDX_ULL0] == 0x8000000000000000ULL) +#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] & 0x8000000000000000ULL) != 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 */ diff -Nru duktape-2.0.0/src-separate/duk_debugger.c duktape-2.1.1/src-separate/duk_debugger.c --- duktape-2.0.0/src-separate/duk_debugger.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_debugger.c 2017-07-28 22:05:08.000000000 +0000 @@ -66,7 +66,6 @@ /* heap->dbg_detached_cb: keep */ /* heap->dbg_udata: keep */ /* heap->dbg_processing: keep on purpose to avoid debugger re-entry in detaching state */ - DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap); heap->dbg_state_dirty = 0; heap->dbg_force_restart = 0; heap->dbg_step_type = 0; @@ -74,6 +73,8 @@ heap->dbg_step_csindex = 0; heap->dbg_step_startline = 0; heap->dbg_have_next_byte = 0; + duk_debug_clear_paused(heap); /* XXX: some overlap with field inits above */ + heap->dbg_state_dirty = 0; /* XXX: clear_paused sets dirty; rework? */ /* Ensure there are no stale active breakpoint pointers. * Breakpoint list is currently kept - we could empty it @@ -92,7 +93,10 @@ duk_context *ctx; thr = heap->heap_thread; - DUK_ASSERT(thr != NULL); + if (thr == NULL) { + DUK_ASSERT(heap->dbg_detached_cb == NULL); + return; + } ctx = (duk_context *) thr; /* Safe to call multiple times. */ @@ -126,6 +130,9 @@ */ DUK_LOCAL void duk__debug_null_most_callbacks(duk_hthread *thr) { duk_heap *heap; + + DUK_ASSERT(thr != NULL); + heap = thr->heap; DUK_D(DUK_DPRINT("transport read/write error, NULL all callbacks expected detached")); heap->dbg_read_cb = NULL; @@ -973,7 +980,7 @@ duk_uint_fast32_t line; duk_uint_fast32_t pc; - act = duk_hthread_get_current_activation(thr); /* may be NULL */ + act = thr->callstack_curr; if (act == NULL) { return 0; } @@ -1004,13 +1011,13 @@ duk_debug_write_int(thr, (DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) ? 1 : 0)); DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* unsigned */ - if (thr->callstack_top == 0) { + act = thr->callstack_curr; + if (act == NULL) { duk_debug_write_undefined(thr); duk_debug_write_undefined(thr); duk_debug_write_int(thr, 0); duk_debug_write_int(thr, 0); } else { - act = thr->callstack + thr->callstack_top - 1; duk_push_tval(ctx, &act->tv_func); duk_get_prop_string(ctx, -1, "fileName"); duk__debug_write_hstring_safe_top(thr); @@ -1019,6 +1026,7 @@ duk_pop_3(ctx); /* Report next pc/line to be executed. */ duk_debug_write_uint(thr, (duk_uint32_t) duk_debug_curr_line(thr)); + act = thr->callstack_curr; duk_debug_write_uint(thr, (duk_uint32_t) duk_hthread_get_act_curr_pc(thr, act)); } @@ -1051,18 +1059,29 @@ duk__debug_write_hstring_safe_top(thr); duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_LINE_NUMBER); duk_debug_write_uint(thr, duk_get_uint(ctx, -1)); + duk_pop_2(ctx); } else { - /* For anything other than an Error instance, we calculate the error - * location directly from the current activation. + /* For anything other than an Error instance, we calculate the + * error location directly from the current activation if one + * exists. */ - act = thr->callstack + thr->callstack_top - 1; - duk_push_tval(ctx, &act->tv_func); - duk_get_prop_string(ctx, -1, "fileName"); - duk__debug_write_hstring_safe_top(thr); - pc = duk_hthread_get_act_prev_pc(thr, act); - duk_debug_write_uint(thr, (duk_uint32_t) duk_hobject_pc2line_query(ctx, -2, pc)); + act = thr->callstack_curr; + if (act != NULL) { + duk_push_tval(ctx, &act->tv_func); + duk_get_prop_string(ctx, -1, "fileName"); + duk__debug_write_hstring_safe_top(thr); + act = thr->callstack_curr; + pc = duk_hthread_get_act_prev_pc(thr, act); + duk_debug_write_uint(thr, (duk_uint32_t) duk_hobject_pc2line_query(ctx, -2, pc)); + duk_pop_2(ctx); + } else { + /* Can happen if duk_throw() is called on an empty + * callstack. + */ + duk_debug_write_cstring(thr, ""); + duk_debug_write_uint(thr, 0); + } } - duk_pop_2(ctx); /* shared pop */ duk_debug_write_eom(thr); } @@ -1202,7 +1221,11 @@ DUK_LOCAL void duk__debug_handle_pause(duk_hthread *thr, duk_heap *heap) { DUK_D(DUK_DPRINT("debug command Pause")); - DUK_HEAP_SET_PAUSED(heap); + if (duk_debug_is_paused(heap)) { + DUK_D(DUK_DPRINT("Pause requested when already paused, ignore")); + } else { + duk_debug_set_paused(heap); + } duk_debug_write_reply(thr); duk_debug_write_eom(thr); } @@ -1210,7 +1233,7 @@ DUK_LOCAL void duk__debug_handle_resume(duk_hthread *thr, duk_heap *heap) { DUK_D(DUK_DPRINT("debug command Resume")); - DUK_HEAP_CLEAR_PAUSED(heap); + duk_debug_clear_paused(heap); duk_debug_write_reply(thr); duk_debug_write_eom(thr); } @@ -1232,7 +1255,7 @@ line = duk_debug_curr_line(thr); if (line > 0) { - DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap); + duk_debug_clear_paused(heap); /* XXX: overlap with fields below; separate macro/helper? */ heap->dbg_step_type = step_type; heap->dbg_step_thread = thr; heap->dbg_step_csindex = thr->callstack_top - 1; @@ -1494,6 +1517,7 @@ /* Read callstack index, if non-null. */ if (duk_debug_peek_byte(thr) == DUK_DBG_IB_NULL) { direct_eval = 0; + level = -1; /* Not needed, but silences warning. */ (void) duk_debug_read_byte(thr); } else { direct_eval = 1; @@ -1736,82 +1760,29 @@ } } -#if defined(DUK_USE_STRTAB_CHAIN) -DUK_LOCAL void duk__debug_dump_strtab_chain(duk_hthread *thr, duk_heap *heap) { - duk_uint_fast32_t i, j; - duk_strtab_entry *e; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t *lst; -#else - duk_hstring **lst; -#endif - duk_hstring *h; - - for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { - e = heap->strtable + i; - if (e->listlen > 0) { -#if defined(DUK_USE_HEAPPTR16) - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); -#else - lst = e->u.strlist; -#endif - DUK_ASSERT(lst != NULL); - - for (j = 0; j < e->listlen; j++) { -#if defined(DUK_USE_HEAPPTR16) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[j]); -#else - h = lst[j]; -#endif - if (h != NULL) { - duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h); - } - } - } else { -#if defined(DUK_USE_HEAPPTR16) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16); -#else - h = e->u.str; -#endif - if (h != NULL) { - duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h); - } - } - } -} -#endif /* DUK_USE_STRTAB_CHAIN */ - -#if defined(DUK_USE_STRTAB_PROBE) -DUK_LOCAL void duk__debug_dump_strtab_probe(duk_hthread *thr, duk_heap *heap) { +DUK_LOCAL void duk__debug_dump_strtab(duk_hthread *thr, duk_heap *heap) { duk_uint32_t i; duk_hstring *h; for (i = 0; i < heap->st_size; i++) { -#if defined(DUK_USE_HEAPPTR16) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); +#if defined(DUK_USE_STRTAB_PTRCOMP) + h = DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, heap->strtable16[i]); #else h = heap->strtable[i]; #endif - if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) { - continue; + while (h != NULL) { + duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h); + h = h->hdr.h_next; } - - duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h); } } -#endif /* DUK_USE_STRTAB_PROBE */ DUK_LOCAL void duk__debug_handle_dump_heap(duk_hthread *thr, duk_heap *heap) { DUK_D(DUK_DPRINT("debug command DumpHeap")); duk_debug_write_reply(thr); duk__debug_dump_heap_allocated(thr, heap); -#if defined(DUK_USE_STRTAB_CHAIN) - duk__debug_dump_strtab_chain(thr, heap); -#endif -#if defined(DUK_USE_STRTAB_PROBE) - duk__debug_dump_strtab_probe(thr, heap); -#endif + duk__debug_dump_strtab(thr, heap); duk_debug_write_eom(thr); } #endif /* DUK_USE_DEBUGGER_DUMPHEAP */ @@ -1949,14 +1920,14 @@ "compfunc", "natfunc", "bufobj", - "thread", + "fastrefs", "array_part", "strict", "notail", "newenv", "namebinding", "createargs", - "envrecclosed", + "have_finalizer", "exotic_array", "exotic_stringobj", "exotic_arguments", @@ -1971,14 +1942,14 @@ DUK_HOBJECT_FLAG_COMPFUNC, DUK_HOBJECT_FLAG_NATFUNC, DUK_HOBJECT_FLAG_BUFOBJ, - DUK_HOBJECT_FLAG_THREAD, + DUK_HOBJECT_FLAG_FASTREFS, DUK_HOBJECT_FLAG_ARRAY_PART, DUK_HOBJECT_FLAG_STRICT, DUK_HOBJECT_FLAG_NOTAIL, DUK_HOBJECT_FLAG_NEWENV, DUK_HOBJECT_FLAG_NAMEBINDING, DUK_HOBJECT_FLAG_CREATEARGS, - DUK_HOBJECT_FLAG_ENVRECCLOSED, + DUK_HOBJECT_FLAG_HAVE_FINALIZER, DUK_HOBJECT_FLAG_EXOTIC_ARRAY, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS, @@ -2026,7 +1997,7 @@ for (;;) { mask = *masks++; - if (!mask) { + if (mask == 0) { break; } key = *keys++; @@ -2108,6 +2079,10 @@ DUK_D(DUK_DPRINT("debug command GetHeapObjInfo")); DUK_UNREF(heap); + DUK_ASSERT(sizeof(duk__debug_getinfo_hstring_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hstring_masks) / sizeof(duk_uint_t) - 1); + DUK_ASSERT(sizeof(duk__debug_getinfo_hobject_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hobject_masks) / sizeof(duk_uint_t) - 1); + DUK_ASSERT(sizeof(duk__debug_getinfo_hbuffer_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hbuffer_masks) / sizeof(duk_uint_t) - 1); + h = duk_debug_read_any_ptr(thr); if (!h) { duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid target"); @@ -2146,9 +2121,9 @@ duk__debug_getinfo_hstring_keys, duk__debug_getinfo_hstring_masks, DUK_HEAPHDR_GET_FLAGS_RAW(h)); - duk__debug_getinfo_prop_uint(thr, "bytelen", DUK_HSTRING_GET_BYTELEN(h_str)); - duk__debug_getinfo_prop_uint(thr, "charlen", DUK_HSTRING_GET_CHARLEN(h_str)); - duk__debug_getinfo_prop_uint(thr, "hash", DUK_HSTRING_GET_HASH(h_str)); + duk__debug_getinfo_prop_uint(thr, "bytelen", (duk_uint_t) DUK_HSTRING_GET_BYTELEN(h_str)); + duk__debug_getinfo_prop_uint(thr, "charlen", (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h_str)); + duk__debug_getinfo_prop_uint(thr, "hash", (duk_uint_t) DUK_HSTRING_GET_HASH(h_str)); duk__debug_getinfo_flags_key(thr, "data"); duk_debug_write_hstring(thr, h_str); break; @@ -2246,6 +2221,26 @@ DUK_UNREF(h_thr); } + if (DUK_HOBJECT_IS_DECENV(h_obj)) { + duk_hdecenv *h_env; + h_env = (duk_hdecenv *) h_obj; + + duk__debug_getinfo_flags_key(thr, "thread"); + duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->thread)); + duk__debug_getinfo_flags_key(thr, "varmap"); + duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->varmap)); + duk__debug_getinfo_prop_uint(thr, "regbase", (duk_uint_t) h_env->regbase); + } + + if (DUK_HOBJECT_IS_OBJENV(h_obj)) { + duk_hobjenv *h_env; + h_env = (duk_hobjenv *) h_obj; + + duk__debug_getinfo_flags_key(thr, "target"); + duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->target)); + duk__debug_getinfo_prop_bool(thr, "has_this", h_env->has_this); + } + #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) { duk_hbufobj *h_bufobj; @@ -2668,12 +2663,13 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)); + DUK_ASSERT(duk_debug_is_attached(thr->heap)); DUK_ASSERT(thr->heap->dbg_processing == 0); + DUK_ASSERT(!duk_debug_is_paused(thr->heap)); - DUK_HEAP_SET_PAUSED(thr->heap); + duk_debug_set_paused(thr->heap); - act = duk_hthread_get_current_activation(thr); + act = thr->callstack_curr; /* NOTE: act may be NULL if an error is thrown outside of any activation, * which may happen in the case of, e.g. syntax errors. @@ -2706,8 +2702,8 @@ thr->heap->dbg_state_dirty = 1; while (DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap)) { - DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)); - DUK_ASSERT(thr->heap->dbg_processing); + DUK_ASSERT(duk_debug_is_attached(thr->heap)); + DUK_ASSERT(thr->heap->dbg_processing == 0); duk_debug_process_messages(thr, 0 /*no_block*/); } @@ -2769,7 +2765,7 @@ DUK_ASSERT(thr != NULL); heap = thr->heap; DUK_ASSERT(heap != NULL); - DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)); + DUK_ASSERT(duk_debug_is_attached(thr->heap)); DUK_ASSERT_DISABLE(breakpoint_index >= 0); /* unsigned */ if (breakpoint_index >= heap->dbg_breakpoint_count) { @@ -2798,6 +2794,55 @@ return 1; } +/* + * Misc state management + */ + +DUK_INTERNAL duk_bool_t duk_debug_is_attached(duk_heap *heap) { + return (heap->dbg_read_cb != NULL); +} + +DUK_INTERNAL duk_bool_t duk_debug_is_paused(duk_heap *heap) { + return (DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) != 0); +} + +DUK_INTERNAL void duk_debug_set_paused(duk_heap *heap) { + if (duk_debug_is_paused(heap)) { + DUK_D(DUK_DPRINT("trying to set paused state when already paused, ignoring")); + } else { + DUK_HEAP_SET_DEBUGGER_PAUSED(heap); + heap->dbg_state_dirty = 1; + duk_debug_clear_step_state(heap); + DUK_ASSERT(heap->ms_running == 0); /* debugger can't be triggered within mark-and-sweep */ + heap->ms_running = 1; /* prevent mark-and-sweep, prevent refzero queueing */ + heap->ms_prevent_count++; + DUK_ASSERT(heap->ms_prevent_count != 0); /* Wrap. */ + DUK_ASSERT(heap->heap_thread != NULL); + } +} + +DUK_INTERNAL void duk_debug_clear_paused(duk_heap *heap) { + if (duk_debug_is_paused(heap)) { + DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap); + heap->dbg_state_dirty = 1; + duk_debug_clear_step_state(heap); + DUK_ASSERT(heap->ms_running == 1); + DUK_ASSERT(heap->ms_prevent_count > 0); + heap->ms_prevent_count--; + heap->ms_running = 0; + DUK_ASSERT(heap->heap_thread != NULL); + } else { + DUK_D(DUK_DPRINT("trying to clear paused state when not paused, ignoring")); + } +} + +DUK_INTERNAL void duk_debug_clear_step_state(duk_heap *heap) { + heap->dbg_step_type = DUK_STEP_TYPE_NONE; + heap->dbg_step_thread = NULL; + heap->dbg_step_csindex = 0; + heap->dbg_step_startline = 0; +} + #else /* DUK_USE_DEBUGGER_SUPPORT */ /* No debugger support. */ diff -Nru duktape-2.0.0/src-separate/duk_debugger.h duktape-2.1.1/src-separate/duk_debugger.h --- duktape-2.0.0/src-separate/duk_debugger.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_debugger.h 2017-07-28 22:05:08.000000000 +0000 @@ -140,6 +140,12 @@ 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); -#endif + +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_step_state(duk_heap *heap); +#endif /* DUK_USE_DEBUGGER_SUPPORT */ #endif /* DUK_DEBUGGER_H_INCLUDED */ diff -Nru duktape-2.0.0/src-separate/duk_debug_vsnprintf.c duktape-2.1.1/src-separate/duk_debug_vsnprintf.c --- duktape-2.0.0/src-separate/duk_debug_vsnprintf.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_debug_vsnprintf.c 2017-07-28 22:05:08.000000000 +0000 @@ -425,6 +425,9 @@ } } if (st->internal) { + if (DUK_HOBJECT_IS_ARRAY(h)) { + DUK__COMMA(); duk_fb_sprintf(fb, "__array:true"); + } if (DUK_HOBJECT_HAS_EXTENSIBLE(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__extensible:true"); } @@ -443,7 +446,7 @@ if (DUK_HOBJECT_HAS_BUFOBJ(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__bufobj:true"); } - if (DUK_HOBJECT_HAS_THREAD(h)) { + if (DUK_HOBJECT_IS_THREAD(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__thread:true"); } if (DUK_HOBJECT_HAS_ARRAY_PART(h)) { @@ -464,9 +467,6 @@ if (DUK_HOBJECT_HAS_CREATEARGS(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__createargs:true"); } - if (DUK_HOBJECT_HAS_ENVRECCLOSED(h)) { - DUK__COMMA(); duk_fb_sprintf(fb, "__envrecclosed:true"); - } if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_array:true"); } @@ -511,6 +511,15 @@ duk_fb_put_funcptr(fb, (duk_uint8_t *) &f->func, sizeof(f->func)); DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld", (long) f->nargs); DUK__COMMA(); duk_fb_sprintf(fb, "__magic:%ld", (long) f->magic); + } else if (st->internal && DUK_HOBJECT_IS_DECENV(h)) { + duk_hdecenv *e = (duk_hdecenv *) h; + DUK__COMMA(); duk_fb_sprintf(fb, "__thread:"); duk__print_hobject(st, (duk_hobject *) e->thread); + DUK__COMMA(); duk_fb_sprintf(fb, "__varmap:"); duk__print_hobject(st, (duk_hobject *) e->varmap); + DUK__COMMA(); duk_fb_sprintf(fb, "__regbase:%ld", (long) e->regbase); + } else if (st->internal && DUK_HOBJECT_IS_OBJENV(h)) { + duk_hobjenv *e = (duk_hobjenv *) h; + DUK__COMMA(); duk_fb_sprintf(fb, "__target:"); duk__print_hobject(st, (duk_hobject *) e->target); + DUK__COMMA(); duk_fb_sprintf(fb, "__has_this:%ld", (long) e->has_this); #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) } else if (st->internal && DUK_HOBJECT_IS_BUFOBJ(h)) { duk_hbufobj *b = (duk_hbufobj *) h; @@ -744,6 +753,10 @@ } #if defined(DUK_USE_FASTINT) case DUK_TAG_FASTINT: + DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); + DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + duk_fb_sprintf(fb, "%.18gF", (double) DUK_TVAL_GET_NUMBER(tv)); + break; #endif default: { /* IEEE double is approximately 16 decimal digits; print a couple extra */ @@ -837,7 +850,7 @@ if (ch == DUK_ASC_STAR) { /* unsupported: would consume multiple args */ - goto error; + goto format_error; } else if (ch == DUK_ASC_PERCENT) { duk_fb_put_byte(&fb, (duk_uint8_t) DUK_ASC_PERCENT); break; @@ -889,7 +902,7 @@ fmtlen = (duk_size_t) (p - p_begfmt); if (fmtlen >= sizeof(fmtbuf)) { /* format is too large, abort */ - goto error; + goto format_error; } DUK_MEMZERO(fmtbuf, sizeof(fmtbuf)); DUK_MEMCPY(fmtbuf, p_begfmt, fmtlen); @@ -964,7 +977,7 @@ } goto done; - error: + format_error: duk_fb_put_cstring(&fb, "FMTERR"); /* fall through */ diff -Nru duktape-2.0.0/src-separate/duk_error.h duktape-2.1.1/src-separate/duk_error.h --- duktape-2.0.0/src-separate/duk_error.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_error.h 2017-07-28 22:05:08.000000000 +0000 @@ -475,7 +475,10 @@ DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_fatal_handler(void *udata, const char *msg)); -DUK_INTERNAL_DECL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t lj_type); +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); diff -Nru duktape-2.0.0/src-separate/duk_error_longjmp.c duktape-2.1.1/src-separate/duk_error_longjmp.c --- duktape-2.0.0/src-separate/duk_error_longjmp.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_error_longjmp.c 2017-07-28 22:05:08.000000000 +0000 @@ -38,18 +38,37 @@ 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)); - /* Perform a refzero check before throwing: this catches cases where - * some internal code uses no-refzero (NORZ) macro variants but an - * error occurs before it has the chance to DUK_REFZERO_CHECK_xxx() - * explicitly. Refzero'ed objects would otherwise remain pending - * until the next refzero (which is not a big issue but still). + /* 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_REFZERO_CHECK_SLOW(thr); + + 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 !defined(DUK_USE_CPP_EXCEPTIONS) /* If we don't have a jmpbuf_ptr, there is little we can do except diff -Nru duktape-2.0.0/src-separate/duk_error_macros.c duktape-2.1.1/src-separate/duk_error_macros.c --- duktape-2.0.0/src-separate/duk_error_macros.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_error_macros.c 2017-07-28 22:05:08.000000000 +0000 @@ -8,7 +8,7 @@ #if defined(DUK_USE_VERBOSE_ERRORS) -DUK_INTERNAL void duk_err_handle_error_fmt(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *fmt, ...) { +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); @@ -18,13 +18,13 @@ va_end(ap); /* dead code, but ensures portability (see Linux man page notes) */ } -DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg) { +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 void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) { +DUK_INTERNAL DUK_COLD void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) { duk_err_create_and_throw(thr, code); } @@ -36,41 +36,41 @@ #if defined(DUK_USE_VERBOSE_ERRORS) #if defined(DUK_USE_PARANOID_ERRORS) -DUK_INTERNAL 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_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((duk_context *) thr, idx), (long) idx); } #else -DUK_INTERNAL 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_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((duk_context *) thr, idx), (long) idx); } #endif -DUK_INTERNAL void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 void duk_err_error_alloc_failed(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 void duk_err_error(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) { +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 void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *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 void duk_err_range_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx) { +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 void duk_err_range_push_beyond(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 void duk_err_type_invalid_args(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 void duk_err_type_invalid_state(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 void duk_err_type_invalid_trap_result(duk_hthread *thr, const char *filename, duk_int_t linenumber) { +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 @@ -82,25 +82,25 @@ DUK_LOCAL void duk__err_shared(duk_hthread *thr, duk_uint_t code) { DUK_ERROR_RAW(thr, NULL, 0, code, NULL); } -DUK_INTERNAL void duk_err_error(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_error(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_ERROR); } -DUK_INTERNAL void duk_err_range(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_range(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_RANGE_ERROR); } -DUK_INTERNAL void duk_err_eval(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_eval(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_EVAL_ERROR); } -DUK_INTERNAL void duk_err_reference(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_reference(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_REFERENCE_ERROR); } -DUK_INTERNAL void duk_err_syntax(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_syntax(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_SYNTAX_ERROR); } -DUK_INTERNAL void duk_err_type(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_type(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_TYPE_ERROR); } -DUK_INTERNAL void duk_err_uri(duk_hthread *thr) { +DUK_INTERNAL DUK_COLD void duk_err_uri(duk_hthread *thr) { duk__err_shared(thr, DUK_ERR_URI_ERROR); } #endif @@ -109,7 +109,7 @@ * Default fatal error handler */ -DUK_INTERNAL void duk_default_fatal_handler(void *udata, const char *msg) { +DUK_INTERNAL DUK_COLD void duk_default_fatal_handler(void *udata, const char *msg) { DUK_UNREF(udata); DUK_UNREF(msg); diff -Nru duktape-2.0.0/src-separate/duk_error_misc.c duktape-2.1.1/src-separate/duk_error_misc.c --- duktape-2.0.0/src-separate/duk_error_misc.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_error_misc.c 2017-07-28 22:05:08.000000000 +0000 @@ -61,11 +61,16 @@ } /* - * Exposed helper for setting up heap longjmp state. + * Helper for debugger throw notify and pause-on-uncaught integration. */ -DUK_INTERNAL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t lj_type) { #if defined(DUK_USE_DEBUGGER_SUPPORT) +#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) +DUK_INTERNAL void duk_err_check_debugger_integration(duk_hthread *thr) { + duk_context *ctx = (duk_context *) thr; + duk_bool_t fatal; + 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 @@ -73,53 +78,100 @@ * 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 defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap) && - !thr->heap->dbg_processing && - lj_type == DUK_LJ_TYPE_THROW) { - duk_context *ctx = (duk_context *) thr; - duk_bool_t fatal; - duk_hobject *h_obj; - - /* 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. - */ - h_obj = duk_get_hobject(ctx, -1); - if (h_obj == thr->builtins[DUK_BIDX_DOUBLE_ERROR]) { - DUK_D(DUK_DPRINT("built-in DoubleError instance thrown, not intercepting")); - goto skip_throw_intercept; - } - DUK_D(DUK_DPRINT("throw with debugger attached, report to client")); + 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; + } + + fatal = !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(ctx, tv_obj); - fatal = !duk__have_active_catcher(thr); + /* 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_debug_send_throw(thr, fatal); + /* Report it to the debug client */ + DUK_D(DUK_DPRINT("throw with debugger attached, report to client")); + duk_debug_send_throw(thr, fatal); #endif #if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) - if (fatal) { - DUK_D(DUK_DPRINT("throw will be fatal, halt before longjmp")); - duk_debug_halt_execution(thr, 1 /*use_prev_pc*/); - } -#endif + if (fatal) { + DUK_D(DUK_DPRINT("throw will be fatal, halt before longjmp")); + duk_debug_halt_execution(thr, 1 /*use_prev_pc*/); } +#endif + + /* Restore longjmp state. */ + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + thr->heap->lj.type = DUK_LJ_TYPE_THROW; + tv_obj = DUK_GET_TVAL_NEGIDX(ctx, -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); - skip_throw_intercept: + duk_pop(ctx); +} +#else /* DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT */ +DUK_INTERNAL void duk_err_check_debugger_integration(duk_hthread *thr) { + DUK_UNREF(thr); +} #endif /* DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT */ #endif /* DUK_USE_DEBUGGER_SUPPORT */ - thr->heap->lj.type = lj_type; +/* + * 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); - DUK_ASSERT(thr->valstack_top > thr->valstack); - DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, thr->valstack_top - 1); /* side effects */ + heap->lj.type = lj_type; + DUK_TVAL_SET_TVAL(&heap->lj.value1, tv_val); + DUK_TVAL_INCREF(thr, tv_val); - duk_pop((duk_context *) thr); + DUK_ASSERT_LJSTATE_SET(heap); } diff -Nru duktape-2.0.0/src-separate/duk_error_throw.c duktape-2.1.1/src-separate/duk_error_throw.c --- duktape-2.0.0/src-separate/duk_error_throw.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_error_throw.c 2017-07-28 22:05:08.000000000 +0000 @@ -16,7 +16,7 @@ * * 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->handling_error flag; the recursion + * "double fault" through the heap->creating_error flag; the recursion * then stops at the second level. */ @@ -26,7 +26,6 @@ DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code) { #endif duk_context *ctx = (duk_context *) thr; - duk_bool_t double_error = thr->heap->handling_error; #if defined(DUK_USE_VERBOSE_ERRORS) DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld, msg=%s, filename=%s, line=%ld", @@ -39,18 +38,11 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT(ctx != NULL); - thr->heap->handling_error = 1; - - if (!double_error) { - /* Allow headroom for calls during error handling (see GH-191). - * We allow space for 10 additional recursions, with one extra - * for, e.g. a print() call at the deepest level. - */ - DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX); - thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11; - } - - DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11); /* just making sure */ + /* 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 @@ -60,29 +52,50 @@ /* * 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. */ - /* XXX: if attempt to push beyond allocated valstack, this double fault - * handling fails miserably. We should really write the double error - * directly to thr->heap->lj.value1 and avoid valstack use entirely. - */ + if (thr->heap->creating_error) { + duk_tval tv_val; + duk_hobject *h_err; - if (double_error) { - if (thr->builtins[DUK_BIDX_DOUBLE_ERROR]) { - DUK_D(DUK_DPRINT("double fault detected -> push built-in fixed 'double error' instance")); - duk_push_hobject_bidx(ctx, DUK_BIDX_DOUBLE_ERROR); +#if 0 /* XXX: not always true because the second throw may come from a different coroutine */ + DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11); +#endif + thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX; + 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 " - "-> push the error code as a number")); - duk_push_int(ctx, (duk_int_t) code); + "-> 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 { - /* Error object is augmented at its creation here. */ + /* Allow headroom for calls during error handling (see GH-191). + * We allow space for 10 additional recursions, with one extra + * for, e.g. a print() call at the deepest level. + */ +#if 0 /* XXX: not always true, second throw may come from a different coroutine */ + DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX); +#endif + thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11; + thr->heap->creating_error = 1; + duk_require_stack(ctx, 1); - /* XXX: unnecessary '%s' formatting here, but cannot use - * 'msg' as a format string directly. + + /* 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(ctx, @@ -98,37 +111,38 @@ 0, NULL); #endif - } - - /* - * Augment error (throw time), unless double error - * - * 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 (double_error) { - DUK_D(DUK_DPRINT("double error: skip throw augmenting to avoid further trouble")); - } else { + /* 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(ctx, -1))); duk_err_augment_error_throw(thr); #endif + + duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(ctx, -1)); + thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX; + 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_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW); - - thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX; /* reset callstack limit */ - thr->heap->handling_error = 0; - DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT, %!iT (after throw augment)", (duk_tval *) &thr->heap->lj.value1, (duk_tval *) &thr->heap->lj.value2)); diff -Nru duktape-2.0.0/src-separate/duk_forwdecl.h duktape-2.1.1/src-separate/duk_forwdecl.h --- duktape-2.0.0/src-separate/duk_forwdecl.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_forwdecl.h 2017-07-28 22:05:08.000000000 +0000 @@ -26,6 +26,8 @@ struct duk_hnatfunc; struct duk_hthread; struct duk_hbufobj; +struct duk_hdecenv; +struct duk_hobjenv; struct duk_hbuffer; struct duk_hbuffer_fixed; struct duk_hbuffer_dynamic; @@ -80,8 +82,10 @@ typedef struct duk_hobject duk_hobject; typedef struct duk_hcompfunc duk_hcompfunc; typedef struct duk_hnatfunc duk_hnatfunc; -typedef struct duk_hbufobj duk_hbufobj; 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_hbuffer duk_hbuffer; typedef struct duk_hbuffer_fixed duk_hbuffer_fixed; typedef struct duk_hbuffer_dynamic duk_hbuffer_dynamic; diff -Nru duktape-2.0.0/src-separate/duk_hbuffer_alloc.c duktape-2.1.1/src-separate/duk_hbuffer_alloc.c --- duktape-2.0.0/src-separate/duk_hbuffer_alloc.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_hbuffer_alloc.c 2017-07-28 22:05:08.000000000 +0000 @@ -41,8 +41,8 @@ } res = (duk_hbuffer *) DUK_ALLOC(heap, alloc_size); - if (!res) { - goto error; + if (DUK_UNLIKELY(res == NULL)) { + goto alloc_error; } /* zero everything unless requested not to do so */ @@ -78,9 +78,9 @@ #else ptr = DUK_ALLOC(heap, size); #endif - if (!ptr) { + if (DUK_UNLIKELY(ptr == NULL)) { /* Because size > 0, NULL check is correct */ - goto error; + goto alloc_error; } *out_bufdata = ptr; @@ -116,7 +116,7 @@ DUK_DDD(DUK_DDDPRINT("allocated hbuffer: %p", (void *) res)); return res; - error: + alloc_error: DUK_DD(DUK_DDPRINT("hbuffer allocation failed")); DUK_FREE(heap, res); diff -Nru duktape-2.0.0/src-separate/duk_hbuffer_ops.c duktape-2.1.1/src-separate/duk_hbuffer_ops.c --- duktape-2.0.0/src-separate/duk_hbuffer_ops.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_hbuffer_ops.c 2017-07-28 22:05:08.000000000 +0000 @@ -39,7 +39,7 @@ */ res = DUK_REALLOC_INDIRECT(thr->heap, duk_hbuffer_get_dynalloc_ptr, (void *) buf, new_size); - if (res != NULL || new_size == 0) { + 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", diff -Nru duktape-2.0.0/src-separate/duk_heap_alloc.c duktape-2.1.1/src-separate/duk_heap_alloc.c --- duktape-2.0.0/src-separate/duk_heap_alloc.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_heap_alloc.c 2017-07-28 22:05:08.000000000 +0000 @@ -92,11 +92,9 @@ case DUK_HTYPE_OBJECT: duk_free_hobject(heap, (duk_hobject *) hdr); break; - case DUK_HTYPE_BUFFER: - duk_free_hbuffer(heap, (duk_hbuffer *) hdr); - break; default: - DUK_UNREACHABLE(); + DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) == DUK_HTYPE_BUFFER); + duk_free_hbuffer(heap, (duk_hbuffer *) hdr); } } @@ -132,23 +130,8 @@ } } -#if defined(DUK_USE_REFERENCE_COUNTING) -DUK_LOCAL void duk__free_refzero_list(duk_heap *heap) { - duk_heaphdr *curr; - duk_heaphdr *next; - - curr = heap->refzero_list; - while (curr) { - DUK_DDD(DUK_DDDPRINT("FINALFREE (refzero_list): %!iO", - (duk_heaphdr *) curr)); - next = DUK_HEAPHDR_GET_NEXT(heap, curr); - duk_heap_free_heaphdr_raw(heap, curr); - curr = next; - } -} -#endif - -DUK_LOCAL void duk__free_markandsweep_finalize_list(duk_heap *heap) { +#if defined(DUK_USE_FINALIZER_SUPPORT) +DUK_LOCAL void duk__free_finalize_list(duk_heap *heap) { duk_heaphdr *curr; duk_heaphdr *next; @@ -161,15 +144,15 @@ curr = next; } } +#endif /* DUK_USE_FINALIZER_SUPPORT */ DUK_LOCAL void duk__free_stringtable(duk_heap *heap) { /* strings are only tracked by stringtable */ - duk_heap_free_strtab(heap); + duk_heap_strtable_free(heap); } #if defined(DUK_USE_FINALIZER_SUPPORT) DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) { - duk_hthread *thr; duk_heaphdr *curr; duk_uint_t round_no; duk_size_t count_all; @@ -177,25 +160,31 @@ duk_size_t curr_limit; DUK_ASSERT(heap != NULL); - DUK_ASSERT(heap->heap_thread != NULL); #if defined(DUK_USE_REFERENCE_COUNTING) DUK_ASSERT(heap->refzero_list == NULL); /* refzero not running -> must be empty */ #endif - DUK_ASSERT(heap->finalize_list == NULL); /* mark-and-sweep not running -> must be empty */ + DUK_ASSERT(heap->finalize_list == NULL); /* mark-and-sweep last pass */ - /* XXX: here again finalizer thread is the heap_thread which needs - * to be coordinated with finalizer thread fixes. - */ - thr = heap->heap_thread; - DUK_ASSERT(thr != NULL); + if (heap->heap_thread == NULL) { + /* May happen when heap allocation fails right off. There + * cannot be any finalizable objects in this case. + */ + DUK_D(DUK_DPRINT("no heap_thread in heap destruct, assume no finalizable objects")); + return; + } - /* Prevent mark-and-sweep for the pending finalizers, also prevents - * refzero handling from moving objects away from the heap_allocated - * list. (The flag meaning is slightly abused here.) - */ - DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)); - DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap); + /* Prevent finalize_list processing and mark-and-sweep entirely. + * Setting ms_running = 1 also prevents refzero handling from moving + * objects away from the heap_allocated list (the flag name is a bit + * misleading here). + */ + DUK_ASSERT(heap->pf_prevent_count == 0); + heap->pf_prevent_count = 1; + DUK_ASSERT(heap->ms_running == 0); + heap->ms_running = 1; + DUK_ASSERT(heap->ms_prevent_count == 0); + heap->ms_prevent_count = 1; /* Bump, because mark-and-sweep assumes it's bumped when ms_running is set. */ curr_limit = 0; /* suppress warning, not used */ for (round_no = 0; ; round_no++) { @@ -204,18 +193,17 @@ count_finalized = 0; while (curr) { count_all++; - if (DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT) { + if (DUK_HEAPHDR_IS_OBJECT(curr)) { /* Only objects in heap_allocated may have finalizers. Check that * the object itself has a _Finalizer property (own or inherited) * so that we don't execute finalizers for e.g. Proxy objects. */ - DUK_ASSERT(thr != NULL); DUK_ASSERT(curr != NULL); - if (duk_hobject_hasprop_raw(thr, (duk_hobject *) curr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) { + if (DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) curr)) { if (!DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) curr)) { DUK_ASSERT(DUK_HEAP_HAS_FINALIZER_NORESCUE(heap)); /* maps to finalizer 2nd argument */ - duk_hobject_run_finalizer(thr, (duk_hobject *) curr); + duk_heap_run_finalizer(heap, (duk_hobject *) curr); count_finalized++; } } @@ -256,8 +244,10 @@ } } - DUK_ASSERT(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)); - DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap); + DUK_ASSERT(heap->ms_running == 1); + heap->ms_running = 0; + DUK_ASSERT(heap->pf_prevent_count == 1); + heap->pf_prevent_count = 0; } #endif /* DUK_USE_FINALIZER_SUPPORT */ @@ -265,7 +255,7 @@ DUK_D(DUK_DPRINT("free heap: %p", (void *) heap)); #if defined(DUK_USE_DEBUG) - duk_heap_dump_strtab(heap); + duk_heap_strtable_dump(heap); #endif #if defined(DUK_USE_DEBUGGER_SUPPORT) @@ -279,32 +269,47 @@ #endif /* Execute finalizers before freeing the heap, even for reachable - * objects, and regardless of whether or not mark-and-sweep is - * enabled. This gives finalizers the chance to free any native + * objects. This gives finalizers the chance to free any native * resources like file handles, allocations made outside Duktape, * etc. This is quite tricky to get right, so that all finalizer * guarantees are honored. * - * XXX: this perhaps requires an execution time limit. - */ - DUK_D(DUK_DPRINT("execute finalizers before freeing heap")); - /* Run mark-and-sweep a few times just in case (unreachable object + * Run mark-and-sweep a few times just in case (unreachable object * finalizers run already here). The last round must rescue objects * from the previous round without running any more finalizers. This * ensures rescued objects get their FINALIZED flag cleared so that * their finalizer is called once more in forced finalization to * satisfy finalizer guarantees. However, we don't want to run any - * more finalizer because that'd required one more loop, and so on. + * more finalizers because that'd required one more loop, and so on. + * + * XXX: this perhaps requires an execution time limit. */ + DUK_D(DUK_DPRINT("execute finalizers before freeing heap")); + DUK_ASSERT(heap->pf_skip_finalizers == 0); DUK_D(DUK_DPRINT("forced gc #1 in heap destruction")); duk_heap_mark_and_sweep(heap, 0); DUK_D(DUK_DPRINT("forced gc #2 in heap destruction")); duk_heap_mark_and_sweep(heap, 0); DUK_D(DUK_DPRINT("forced gc #3 in heap destruction (don't run finalizers)")); - duk_heap_mark_and_sweep(heap, DUK_MS_FLAG_SKIP_FINALIZERS); /* skip finalizers; queue finalizable objects to heap_allocated */ + heap->pf_skip_finalizers = 1; + duk_heap_mark_and_sweep(heap, 0); /* Skip finalizers; queue finalizable objects to heap_allocated. */ + /* There are never objects in refzero_list at this point, or at any + * point beyond a DECREF (even a DECREF_NORZ). Since Duktape 2.1 + * refzero_list processing is side effect free, so it is always + * processed to completion by a DECREF initially triggering a zero + * refcount. + */ +#if defined(DUK_USE_REFERENCE_COUNTING) + DUK_ASSERT(heap->refzero_list == NULL); /* Always processed to completion inline. */ +#endif #if defined(DUK_USE_FINALIZER_SUPPORT) - DUK_HEAP_SET_FINALIZER_NORESCUE(heap); /* rescue no longer supported */ + DUK_ASSERT(heap->finalize_list == NULL); /* Last mark-and-sweep with skip_finalizers. */ +#endif + +#if defined(DUK_USE_FINALIZER_SUPPORT) + DUK_D(DUK_DPRINT("run finalizers for remaining finalizable objects")); + DUK_HEAP_SET_FINALIZER_NORESCUE(heap); /* Rescue no longer supported. */ duk__free_run_finalizers(heap); #endif /* DUK_USE_FINALIZER_SUPPORT */ @@ -312,16 +317,17 @@ * are on the heap allocated list. */ - DUK_D(DUK_DPRINT("freeing heap objects of heap: %p", (void *) heap)); + DUK_D(DUK_DPRINT("freeing heap_allocated of heap: %p", (void *) heap)); duk__free_allocated(heap); #if defined(DUK_USE_REFERENCE_COUNTING) - DUK_D(DUK_DPRINT("freeing refzero list of heap: %p", (void *) heap)); - duk__free_refzero_list(heap); + DUK_ASSERT(heap->refzero_list == NULL); /* Always processed to completion inline. */ #endif - DUK_D(DUK_DPRINT("freeing mark-and-sweep finalize list of heap: %p", (void *) heap)); - duk__free_markandsweep_finalize_list(heap); +#if defined(DUK_USE_FINALIZER_SUPPORT) + DUK_D(DUK_DPRINT("freeing finalize_list of heap: %p", (void *) heap)); + duk__free_finalize_list(heap); +#endif DUK_D(DUK_DPRINT("freeing string table of heap: %p", (void *) heap)); duk__free_stringtable(heap); @@ -343,20 +349,26 @@ duk_small_uint_t i; #endif + DUK_UNREF(heap); + /* With ROM-based strings, heap->strs[] and thr->strs[] are omitted * so nothing to initialize for strs[]. */ #if defined(DUK_USE_ASSERTIONS) - for (i = 0; i < sizeof(duk_rom_strings) / sizeof(const duk_hstring *); i++) { - duk_uint32_t hash; + for (i = 0; i < sizeof(duk_rom_strings_lookup) / sizeof(const duk_hstring *); i++) { const duk_hstring *h; - h = duk_rom_strings[i]; - DUK_ASSERT(h != NULL); - hash = duk_heap_hashstring(heap, (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); - DUK_DD(DUK_DDPRINT("duk_rom_strings[%d] -> hash 0x%08lx, computed 0x%08lx", - (int) i, (unsigned long) DUK_HSTRING_GET_HASH(h), (unsigned long) hash)); - DUK_ASSERT(hash == (duk_uint32_t) DUK_HSTRING_GET_HASH(h)); + duk_uint32_t hash; + + h = duk_rom_strings_lookup[i]; + while (h != NULL) { + hash = duk_heap_hashstring(heap, (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); + DUK_DD(DUK_DDPRINT("duk_rom_strings_lookup[%d] -> hash 0x%08lx, computed 0x%08lx", + (int) i, (unsigned long) DUK_HSTRING_GET_HASH(h), (unsigned long) hash)); + DUK_ASSERT(hash == (duk_uint32_t) DUK_HSTRING_GET_HASH(h)); + + h = (const duk_hstring *) h->hdr.h_next; + } } #endif return 1; @@ -384,9 +396,9 @@ */ DUK_ASSERT(len <= 0xffffUL); DUK_DDD(DUK_DDDPRINT("intern built-in string %ld", (long) i)); - h = duk_heap_string_intern(heap, tmp, len); + h = duk_heap_strtable_intern(heap, tmp, len); if (!h) { - goto error; + goto failed; } DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)); @@ -421,7 +433,7 @@ return 1; - error: + failed: return 0; } #endif /* DUK_USE_ROM_STRINGS */ @@ -429,12 +441,11 @@ DUK_LOCAL duk_bool_t duk__init_heap_thread(duk_heap *heap) { duk_hthread *thr; - DUK_DD(DUK_DDPRINT("heap init: alloc heap thread")); - thr = duk_hthread_alloc(heap, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_FLAG_THREAD | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD)); - if (!thr) { + DUK_D(DUK_DPRINT("heap init: alloc heap thread")); + thr = duk_hthread_alloc_unchecked(heap, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD)); + if (thr == NULL) { DUK_D(DUK_DPRINT("failed to alloc heap_thread")); return 0; } @@ -454,6 +465,7 @@ /* 'thr' is now reachable */ + DUK_D(DUK_DPRINT("heap init: init heap thread stacks")); if (!duk_hthread_init_stacks(heap, thr)) { return 0; } @@ -572,6 +584,8 @@ DUK__DUMPSZ(duk_harray); DUK__DUMPSZ(duk_hcompfunc); DUK__DUMPSZ(duk_hnatfunc); + DUK__DUMPSZ(duk_hdecenv); + DUK__DUMPSZ(duk_hobjenv); DUK__DUMPSZ(duk_hthread); #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) DUK__DUMPSZ(duk_hbufobj); @@ -584,9 +598,6 @@ DUK__DUMPSZ(duk_propvalue); DUK__DUMPSZ(duk_propdesc); DUK__DUMPSZ(duk_heap); -#if defined(DUK_USE_STRTAB_CHAIN) - DUK__DUMPSZ(duk_strtab_entry); -#endif DUK__DUMPSZ(duk_activation); DUK__DUMPSZ(duk_catcher); DUK__DUMPSZ(duk_strcache); @@ -695,10 +706,21 @@ void *heap_udata, duk_fatal_function fatal_func) { duk_heap *res = NULL; + duk_uint32_t st_initsize; DUK_D(DUK_DPRINT("allocate heap")); /* + * Random config sanity asserts + */ + + DUK_ASSERT(DUK_USE_STRTAB_MINSIZE >= 64); + + DUK_ASSERT((DUK_HTYPE_STRING & 0x01U) == 0); + DUK_ASSERT((DUK_HTYPE_BUFFER & 0x01U) == 0); + DUK_ASSERT((DUK_HTYPE_OBJECT & 0x01U) == 1); /* DUK_HEAPHDR_IS_OBJECT() relies ont his. */ + + /* * Debug dump type sizes */ @@ -713,9 +735,11 @@ */ #if defined(DUK_USE_SELF_TESTS) + DUK_D(DUK_DPRINT("run self tests")); if (duk_selftest_run_tests(alloc_func, realloc_func, free_func, heap_udata) > 0) { fatal_func(heap_udata, "self test(s) failed"); } + DUK_D(DUK_DPRINT("self tests passed")); #endif /* @@ -772,9 +796,13 @@ * Use a raw call, all macros expect the heap to be initialized */ +#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 1) + goto failed; +#endif + DUK_D(DUK_DPRINT("alloc duk_heap object")); res = (duk_heap *) alloc_func(heap_udata, sizeof(duk_heap)); if (!res) { - goto error; + goto failed; } /* @@ -782,6 +810,9 @@ */ DUK_MEMZERO(res, sizeof(*res)); +#if defined(DUK_USE_ASSERTIONS) + res->heap_initializing = 1; +#endif /* explicit NULL inits */ #if defined(DUK_USE_EXPLICIT_NULL_INIT) @@ -789,20 +820,20 @@ res->heap_allocated = NULL; #if defined(DUK_USE_REFERENCE_COUNTING) res->refzero_list = NULL; - res->refzero_list_tail = NULL; #endif +#if defined(DUK_USE_FINALIZER_SUPPORT) res->finalize_list = NULL; +#if defined(DUK_USE_ASSERTIONS) + res->currently_finalizing = NULL; +#endif +#endif res->heap_thread = NULL; res->curr_thread = NULL; res->heap_object = NULL; -#if defined(DUK_USE_STRTAB_CHAIN) - /* nothing to NULL */ -#elif defined(DUK_USE_STRTAB_PROBE) -#if defined(DUK_USE_HEAPPTR16) - res->strtable16 = (duk_uint16_t *) NULL; +#if defined(DUK_USE_STRTAB_PTRCOMP) + res->strtable16 = NULL; #else - res->strtable = (duk_hstring **) NULL; -#endif + res->strtable = NULL; #endif #if defined(DUK_USE_ROM_STRINGS) /* no res->strs[] */ @@ -836,13 +867,21 @@ res->heap_udata = heap_udata; res->fatal_func = fatal_func; -#if defined(DUK_USE_HEAPPTR16) - /* XXX: zero assumption */ - res->heapptr_null16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) NULL); - res->heapptr_deleted16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) DUK_STRTAB_DELETED_MARKER(res)); -#endif + /* XXX: for now there's a pointer packing zero assumption, i.e. + * NULL <=> compressed pointer 0. If this is removed, may need + * to precompute e.g. null16 here. + */ + + /* res->ms_trigger_counter == 0 -> now causes immediate GC; which is OK */ - /* res->mark_and_sweep_trigger_counter == 0 -> now causes immediate GC; which is OK */ + /* Prevent mark-and-sweep and finalizer execution until heap is completely + * initialized. + */ + DUK_ASSERT(res->ms_prevent_count == 0); + DUK_ASSERT(res->pf_prevent_count == 0); + res->ms_prevent_count = 1; + res->pf_prevent_count = 1; + DUK_ASSERT(res->ms_running == 0); res->call_recursion_depth = 0; res->call_recursion_limit = DUK_USE_NATIVE_CALL_RECLIMIT; @@ -870,71 +909,49 @@ res->lj.jmpbuf_ptr = NULL; #endif DUK_ASSERT(res->lj.type == DUK_LJ_TYPE_UNKNOWN); /* zero */ - + DUK_ASSERT(res->lj.iserror == 0); DUK_TVAL_SET_UNDEFINED(&res->lj.value1); DUK_TVAL_SET_UNDEFINED(&res->lj.value2); -#if (DUK_STRTAB_INITIAL_SIZE < DUK_UTIL_MIN_HASH_PRIME) -#error initial heap stringtable size is defined incorrectly -#endif + DUK_ASSERT_LJSTATE_UNSET(res); /* * Init stringtable: fixed variant */ -#if defined(DUK_USE_STRTAB_CHAIN) - DUK_MEMZERO(res->strtable, sizeof(duk_strtab_entry) * DUK_STRTAB_CHAIN_SIZE); -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - { - duk_small_uint_t i; - for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { -#if defined(DUK_USE_HEAPPTR16) - res->strtable[i].u.str16 = res->heapptr_null16; + st_initsize = DUK_USE_STRTAB_MINSIZE; +#if defined(DUK_USE_STRTAB_PTRCOMP) + res->strtable16 = (duk_uint16_t *) alloc_func(heap_udata, sizeof(duk_uint16_t) * st_initsize); + if (res->strtable16 == NULL) { + goto failed; + } #else - res->strtable[i].u.str = NULL; -#endif - } + res->strtable = (duk_hstring **) alloc_func(heap_udata, sizeof(duk_hstring *) * st_initsize); + if (res->strtable == NULL) { + goto failed; } -#endif /* DUK_USE_EXPLICIT_NULL_INIT */ -#endif /* DUK_USE_STRTAB_CHAIN */ - - /* - * Init stringtable: probe variant - */ +#endif + res->st_size = st_initsize; + res->st_mask = st_initsize - 1; +#if (DUK_USE_STRTAB_MINSIZE != DUK_USE_STRTAB_MAXSIZE) + DUK_ASSERT(res->st_count == 0); +#endif -#if defined(DUK_USE_STRTAB_PROBE) -#if defined(DUK_USE_HEAPPTR16) - res->strtable16 = (duk_uint16_t *) alloc_func(heap_udata, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE); - if (!res->strtable16) { - goto error; - } -#else /* DUK_USE_HEAPPTR16 */ - res->strtable = (duk_hstring **) alloc_func(heap_udata, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE); - if (!res->strtable) { - goto error; - } -#endif /* DUK_USE_HEAPPTR16 */ - res->st_size = DUK_STRTAB_INITIAL_SIZE; +#if defined(DUK_USE_STRTAB_PTRCOMP) + /* zero assumption */ + DUK_MEMZERO(res->strtable16, sizeof(duk_uint16_t) * st_initsize); +#else #if defined(DUK_USE_EXPLICIT_NULL_INIT) { duk_small_uint_t i; - DUK_ASSERT(res->st_size == DUK_STRTAB_INITIAL_SIZE); - for (i = 0; i < DUK_STRTAB_INITIAL_SIZE; i++) { -#if defined(DUK_USE_HEAPPTR16) - res->strtable16[i] = res->heapptr_null16; -#else + for (i = 0; i < st_initsize; i++) { res->strtable[i] = NULL; -#endif } } -#else /* DUK_USE_EXPLICIT_NULL_INIT */ -#if defined(DUK_USE_HEAPPTR16) - DUK_MEMZERO(res->strtable16, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE); #else - DUK_MEMZERO(res->strtable, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE); -#endif + DUK_MEMZERO(res->strtable, sizeof(duk_hstring *) * st_initsize); #endif /* DUK_USE_EXPLICIT_NULL_INIT */ -#endif /* DUK_USE_STRTAB_PROBE */ +#endif /* DUK_USE_STRTAB_PTRCOMP */ /* * Init stringcache @@ -959,30 +976,40 @@ * Init built-in strings */ - DUK_DD(DUK_DDPRINT("HEAP: INIT STRINGS")); +#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 2) + goto failed; +#endif + DUK_D(DUK_DPRINT("heap init: initialize heap strings")); if (!duk__init_heap_strings(res)) { - goto error; + goto failed; } /* * Init the heap thread */ - DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP THREAD")); +#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 3) + goto failed; +#endif + DUK_D(DUK_DPRINT("heap init: initialize heap thread")); if (!duk__init_heap_thread(res)) { - goto error; + goto failed; } /* * Init the heap object */ - DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP OBJECT")); +#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 4) + goto failed; +#endif + DUK_D(DUK_DPRINT("heap init: initialize heap object")); DUK_ASSERT(res->heap_thread != NULL); - res->heap_object = duk_hobject_alloc(res, DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT)); - if (!res->heap_object) { - goto error; + res->heap_object = duk_hobject_alloc_unchecked(res, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT)); + if (res->heap_object == NULL) { + goto failed; } DUK_HOBJECT_INCREF(res->heap_thread, res->heap_object); @@ -1029,23 +1056,49 @@ #endif /* - * All done + * Allow finalizer and mark-and-sweep processing. + */ + + DUK_D(DUK_DPRINT("heap init: allow finalizer/mark-and-sweep processing")); + DUK_ASSERT(res->ms_prevent_count == 1); + DUK_ASSERT(res->pf_prevent_count == 1); + res->ms_prevent_count = 0; + res->pf_prevent_count = 0; + DUK_ASSERT(res->ms_running == 0); +#if defined(DUK_USE_ASSERTIONS) + res->heap_initializing = 0; +#endif + + /* + * All done. */ DUK_D(DUK_DPRINT("allocated heap: %p", (void *) res)); return res; - error: + failed: DUK_D(DUK_DPRINT("heap allocation failed")); - if (res) { - /* assumes that allocated pointers and alloc funcs are valid - * if res exists + if (res != NULL) { + /* Assumes that allocated pointers and alloc funcs are valid + * if res exists. */ + DUK_ASSERT(res->ms_prevent_count == 1); + DUK_ASSERT(res->pf_prevent_count == 1); + DUK_ASSERT(res->ms_running == 0); + if (res->heap_thread != NULL) { + res->ms_prevent_count = 0; + res->pf_prevent_count = 0; + } +#if defined(DUK_USE_ASSERTIONS) + res->heap_initializing = 0; +#endif + DUK_ASSERT(res->alloc_func != NULL); DUK_ASSERT(res->realloc_func != NULL); DUK_ASSERT(res->free_func != NULL); duk_heap_free(res); } + return NULL; } diff -Nru duktape-2.0.0/src-separate/duk_heap_finalize.c duktape-2.1.1/src-separate/duk_heap_finalize.c --- duktape-2.0.0/src-separate/duk_heap_finalize.c 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_heap_finalize.c 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,449 @@ +/* + * Finalizer handling. + */ + +#include "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_context *ctx) { + DUK_DD(DUK_DDPRINT("fake global torture finalizer executed")); + + /* Require a lot of stack to force a value stack grow/shrink. */ + duk_require_stack(ctx, 100000); + + /* Force a reallocation with pointer change for value, call, and + * catch stacks to maximize side effects. + */ + duk_hthread_valstack_torture_realloc((duk_hthread *) ctx); + duk_hthread_callstack_torture_realloc((duk_hthread *) ctx); + duk_hthread_catchstack_torture_realloc((duk_hthread *) ctx); + + /* Inner function call, error throw. */ + duk_eval_string_noresult(ctx, + "(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 has been reached. + * Otherwise a callstack limit error will be created, then refzero'ed. + */ + if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit || + thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) { + DUK_D(DUK_DPRINT("skip global torture finalizer because of call recursion or call stack size limit")); + return; + } + + /* Run fake finalizer. Avoid creating unnecessary garbage. */ + duk_push_c_function((duk_context *) thr, duk__fake_global_finalizer, 0 /*nargs*/); + (void) duk_pcall((duk_context *) thr, 0 /*nargs*/); + duk_pop((duk_context *) 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); + DUK_ASSERT(heap->heap_thread->callstack != NULL); + DUK_ASSERT(heap->heap_thread->catchstack != 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_context *ctx, void *udata) { + duk_hthread *thr; + + DUK_ASSERT(ctx != NULL); + thr = (duk_hthread *) ctx; + 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(ctx, -1, DUK_STRIDX_INT_FINALIZER); /* -> [... obj finalizer] */ + duk_dup_m2(ctx); + duk_push_boolean(ctx, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap)); + DUK_DDD(DUK_DDDPRINT("calling finalizer")); + duk_call(ctx, 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_context *ctx; + 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); + ctx = (duk_context *) 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(ctx); +#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 (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(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; + } + + duk_push_hobject(ctx, obj); /* this also increases refcount by one */ + rc = duk_safe_call(ctx, duk__finalize_helper, NULL /*udata*/, 0 /*nargs*/, 1 /*nrets*/); /* -> [... obj retval/error] */ + DUK_ASSERT_TOP(ctx, 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(ctx, -1))); + } + duk_pop_2(ctx); /* -> [...] */ + + DUK_ASSERT_TOP(ctx, entry_top); +} + +#else /* DUK_USE_FINALIZER_SUPPORT */ + +/* nothing */ + +#endif /* DUK_USE_FINALIZER_SUPPORT */ diff -Nru duktape-2.0.0/src-separate/duk_heap.h duktape-2.1.1/src-separate/duk_heap.h --- duktape-2.0.0/src-separate/duk_heap.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_heap.h 2017-07-28 22:05:08.000000000 +0000 @@ -14,13 +14,11 @@ * Heap flags */ -#define DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING (1 << 0) /* mark-and-sweep is currently running */ -#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1 << 1) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */ -#define DUK_HEAP_FLAG_REFZERO_FREE_RUNNING (1 << 2) /* refcount code is processing refzero list */ -#define DUK_HEAP_FLAG_ERRHANDLER_RUNNING (1 << 3) /* an error handler (user callback to augment/replace error) is running */ -#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1 << 4) /* executor interrupt running (used to avoid nested interrupts) */ -#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1 << 5) /* heap destruction ongoing, finalizer rescue no longer possible */ -#define DUK_HEAP_FLAG_DEBUGGER_PAUSED (1 << 6) /* debugger is paused: talk with debug client until step/resume */ +#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1 << 0) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */ +#define DUK_HEAP_FLAG_ERRHANDLER_RUNNING (1 << 1) /* an error handler (user callback to augment/replace error) is running */ +#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1 << 2) /* executor interrupt running (used to avoid nested interrupts) */ +#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1 << 3) /* heap destruction ongoing, finalizer rescue no longer possible */ +#define DUK_HEAP_FLAG_DEBUGGER_PAUSED (1 << 4) /* 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 { \ @@ -30,25 +28,19 @@ (heap)->flags &= ~(bits); \ } while (0) -#define DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) #define DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) -#define DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) #define DUK_HEAP_HAS_ERRHANDLER_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) #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_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) #define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) -#define DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) #define DUK_HEAP_SET_ERRHANDLER_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) #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_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) #define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) -#define DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) #define DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) #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) @@ -75,11 +67,25 @@ * field and the GC caller can impose further flags. */ -#define DUK_MS_FLAG_EMERGENCY (1 << 0) /* emergency mode: try extra hard */ -#define DUK_MS_FLAG_NO_STRINGTABLE_RESIZE (1 << 1) /* don't resize stringtable (but may sweep it); needed during stringtable resize */ -#define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1 << 2) /* don't compact objects; needed during object property allocation resize */ -#define DUK_MS_FLAG_NO_FINALIZERS (1 << 3) /* don't run finalizers; leave finalizable objects in finalize_list for next round */ -#define DUK_MS_FLAG_SKIP_FINALIZERS (1 << 4) /* don't run finalizers; queue finalizable objects back to heap_allocated */ +/* Emergency mark-and-sweep: try extra hard, even at the cost of + * performance. + */ +#define DUK_MS_FLAG_EMERGENCY (1 << 0) + +/* Voluntary mark-and-sweep: triggered periodically. */ +#define DUK_MS_FLAG_VOLUNTARY (1 << 1) + +/* 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 (1 << 2) + +/* 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 (1 << 2) /* * Thread switching @@ -121,39 +127,28 @@ #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 */ -/* helper to insert a (non-string) heap object into heap allocated list */ -#define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap,hdr) duk_heap_insert_into_heap_allocated((heap),(hdr)) - -/* - * Stringtable - */ - -/* initial stringtable size, must be prime and higher than DUK_UTIL_MIN_HASH_PRIME */ -#define DUK_STRTAB_INITIAL_SIZE 17 - -/* indicates a deleted string; any fixed non-NULL, non-hstring pointer works */ -#define DUK_STRTAB_DELETED_MARKER(heap) ((duk_hstring *) heap) - -/* resizing parameters */ -#define DUK_STRTAB_MIN_FREE_DIVISOR 4 /* load factor max 75% */ -#define DUK_STRTAB_MIN_USED_DIVISOR 4 /* load factor min 25% */ -#define DUK_STRTAB_GROW_ST_SIZE(n) ((n) + (n)) /* used entries + approx 100% -> reset load to 50% */ - -#define DUK_STRTAB_U32_MAX_STRLEN 10 /* 4'294'967'295 */ -#define DUK_STRTAB_HIGHEST_32BIT_PRIME 0xfffffffbUL - -/* probe sequence (open addressing) */ -#define DUK_STRTAB_HASH_INITIAL(hash,h_size) ((hash) % (h_size)) -#define DUK_STRTAB_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash)) - -/* fixed top level hashtable size (separate chaining) */ -#define DUK_STRTAB_CHAIN_SIZE DUK_USE_STRTAB_CHAIN_SIZE +/* 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 @@ -224,10 +219,17 @@ #define DUK_FREE(heap,ptr) duk_heap_mem_free((heap), (ptr)) /* + * Checked allocation, relative to a thread + */ + +#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)) + +/* * Memory constants */ -#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT 5 /* Retry allocation after mark-and-sweep for this +#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 @@ -268,27 +270,6 @@ duk_uint32_t line; }; -#if defined(DUK_USE_DEBUGGER_SUPPORT) -#define DUK_HEAP_IS_DEBUGGER_ATTACHED(heap) ((heap)->dbg_read_cb != NULL) -#define DUK_HEAP_CLEAR_STEP_STATE(heap) do { \ - (heap)->dbg_step_type = DUK_STEP_TYPE_NONE; \ - (heap)->dbg_step_thread = NULL; \ - (heap)->dbg_step_csindex = 0; \ - (heap)->dbg_step_startline = 0; \ - } while (0) -#define DUK_HEAP_SET_PAUSED(heap) do { \ - DUK_HEAP_SET_DEBUGGER_PAUSED(heap); \ - (heap)->dbg_state_dirty = 1; \ - DUK_HEAP_CLEAR_STEP_STATE((heap)); \ - } while (0) -#define DUK_HEAP_CLEAR_PAUSED(heap) do { \ - DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap); \ - (heap)->dbg_state_dirty = 1; \ - DUK_HEAP_CLEAR_STEP_STATE((heap)); \ - } while (0) -#define DUK_HEAP_IS_PAUSED(heap) (DUK_HEAP_HAS_DEBUGGER_PAUSED((heap))) -#endif /* DUK_USE_DEBUGGER_SUPPORT */ - /* * String cache should ideally be at duk_hthread level, but that would * cause string finalization to slow down relative to the number of @@ -317,28 +298,17 @@ duk_tval value2; /* 2nd related value (type specific) */ }; -/* - * Stringtable entry for fixed size stringtable - */ - -struct duk_strtab_entry { -#if defined(DUK_USE_HEAPPTR16) - /* A 16-bit listlen makes sense with 16-bit heap pointers: there - * won't be space for 64k strings anyway. - */ - duk_uint16_t listlen; /* if 0, 'str16' used, if > 0, 'strlist16' used */ - union { - duk_uint16_t strlist16; - duk_uint16_t str16; - } u; -#else - duk_size_t listlen; /* if 0, 'str' used, if > 0, 'strlist' used */ - union { - duk_hstring **strlist; - duk_hstring *str; - } u; -#endif -}; +#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) /* * Main heap structure @@ -357,12 +327,6 @@ */ void *heap_udata; - /* Precomputed pointers when using 16-bit heap pointer packing. */ -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t heapptr_null16; - duk_uint16_t heapptr_deleted16; -#endif - /* 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 @@ -370,53 +334,114 @@ */ duk_fatal_function fatal_func; - /* allocated heap objects */ + /* 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; - /* work list for objects whose refcounts are zero but which have not been - * "finalized"; avoids recursive C calls when refcounts go to zero in a - * chain of objects. + /* 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; - duk_heaphdr *refzero_list_tail; #endif - /* mark-and-sweep control */ +#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 + + /* 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 mark_and_sweep_trigger_counter; + duk_int_t ms_trigger_counter; #endif - duk_int_t mark_and_sweep_recursion_depth; - /* mark-and-sweep flags automatically active (used for critical sections) */ - duk_small_uint_t mark_and_sweep_base_flags; + /* 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; - /* work list for objects to be finalized (by mark-and-sweep) */ - duk_heaphdr *finalize_list; + /* Mark-and-sweep flags automatically active (used for critical sections). */ + duk_small_uint_t ms_base_flags; - /* longjmp state */ - duk_ljstate lj; + /* Mark-and-sweep running flag. Prevents re-entry, and also causes + * refzero events to be ignored (= objects won't be queued to refzero_list). + */ + 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 detecting internal "double faults", see duk_error_throw.c */ - duk_bool_t handling_error; + /* Longjmp state. */ + duk_ljstate lj; - /* heap thread, used internally and for finalization */ + /* Heap thread, used internally and for finalization. */ duk_hthread *heap_thread; - /* current thread */ - duk_hthread *curr_thread; /* currently running thread */ + /* Current running thread. */ + duk_hthread *curr_thread; - /* heap level "stash" object (e.g., various reachability roots) */ + /* 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 */ + /* Mix-in value for computing string hashes; should be reasonably unpredictable. */ duk_uint32_t hash_seed; - /* rnd_state for duk_util_tinyrandom.c */ + /* 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 */ @@ -425,7 +450,7 @@ #endif #endif - /* counter for unique local symbol creation */ + /* 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. @@ -441,10 +466,9 @@ duk_int_t inst_count_interrupt; #endif - /* debugger */ - + /* Debugger state. */ #if defined(DUK_USE_DEBUGGER_SUPPORT) - /* callbacks and udata; dbg_read_cb != NULL is used to indicate attached state */ + /* 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; @@ -454,7 +478,7 @@ duk_debug_detached_function dbg_detached_cb; void *dbg_udata; - /* debugger state, only relevant when attached */ + /* 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) */ @@ -478,30 +502,25 @@ duk_uint8_t dbg_next_byte; #endif - /* string intern table (weak refs) */ -#if defined(DUK_USE_STRTAB_PROBE) -#if defined(DUK_USE_HEAPPTR16) + /* String intern table (weak refs). */ +#if defined(DUK_USE_STRTAB_PTRCOMP) duk_uint16_t *strtable16; #else duk_hstring **strtable; #endif - duk_uint32_t st_size; /* alloc size in elements */ - duk_uint32_t st_used; /* used elements (includes DELETED) */ -#endif - - /* XXX: static alloc is OK until separate chaining stringtable - * resizing is implemented. - */ -#if defined(DUK_USE_STRTAB_CHAIN) - duk_strtab_entry strtable[DUK_STRTAB_CHAIN_SIZE]; + 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 + /* String access cache (codepoint offset -> byte offset) for fast string * character looping; 'weak' reference which needs special handling in GC. */ duk_strcache strcache[DUK_HEAP_STRCACHE_SIZE]; - /* built-in strings */ + /* Built-in strings. */ #if defined(DUK_USE_ROM_STRINGS) /* No field needed when strings are in ROM. */ #else @@ -530,32 +549,32 @@ 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_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING) -DUK_INTERNAL_DECL void duk_heap_remove_any_from_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 -#if 0 /*unused*/ -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen); -#endif -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen); -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t len); -#if 0 /*unused*/ -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val); -#endif -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val); -DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val); +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); +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_string_remove(duk_heap *heap, duk_hstring *h); -#endif -#if defined(DUK_USE_MS_STRINGTABLE_RESIZE) -DUK_INTERNAL_DECL void duk_heap_force_strtab_resize(duk_heap *heap); +DUK_INTERNAL_DECL void duk_heap_strtable_unlink(duk_heap *heap, duk_hstring *h); #endif -DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap); +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_dump_strtab(duk_heap *heap); +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); @@ -569,41 +588,18 @@ 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); -#if defined(DUK_USE_REFERENCE_COUNTING) -DUK_INTERNAL_DECL void duk_refzero_free_pending(duk_hthread *thr); -DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr); -#if 0 /* Not needed: fast path handles inline; slow path uses duk_heaphdr_decref() which is needed anyway. */ -DUK_INTERNAL_DECL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h); -DUK_INTERNAL_DECL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h); -DUK_INTERNAL_DECL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h); -DUK_INTERNAL_DECL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h); -DUK_INTERNAL_DECL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h); -DUK_INTERNAL_DECL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h); -#endif -DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h); -DUK_INTERNAL_DECL void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h); -#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) -DUK_INTERNAL_DECL void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h); /* no 'norz' variant */ -DUK_INTERNAL_DECL void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h); /* no 'norz' variant */ -DUK_INTERNAL_DECL void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h); -DUK_INTERNAL_DECL void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h); -#else -DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv); -DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv); -DUK_INTERNAL_DECL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv); -DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h); -DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h); -DUK_INTERNAL_DECL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h); -#endif -#else /* DUK_USE_REFERENCE_COUNTING */ -/* no refcounting */ -#endif /* DUK_USE_REFERENCE_COUNTING */ +#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 duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags); +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); diff -Nru duktape-2.0.0/src-separate/duk_heaphdr.h duktape-2.1.1/src-separate/duk_heaphdr.h --- duktape-2.0.0/src-separate/duk_heaphdr.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_heaphdr.h 2017-07-28 22:05:08.000000000 +0000 @@ -11,30 +11,45 @@ * * 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 are held in the - * heap-wide string table so they don't need link 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). This - * means essentially that the refcount field must be as wide as data pointers. - * On 64-bit platforms this means that the refcount needs to be 64 bits even - * if an 'int' is 32 bits. This is a bit unfortunate, and compromising on - * this might be reasonable in the future. + * 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_refcount16; + duk_uint16_t h_refcount; +#elif defined(DUK_USE_REFCOUNT32) + duk_uint32_t h_refcount; #else duk_size_t h_refcount; #endif -#endif +#endif /* DUK_USE_REFERENCE_COUNTING */ #if defined(DUK_USE_HEAPPTR16) duk_uint16_t h_next16; @@ -74,15 +89,26 @@ 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_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 +#endif /* DUK_USE_REFERENCE_COUNTING */ + + duk_hstring *h_next; + /* No 'h_prev' pointer for strings. */ }; #define DUK_HEAPHDR_FLAGS_TYPE_MASK 0x00000003UL @@ -138,21 +164,13 @@ #endif #if defined(DUK_USE_REFERENCE_COUNTING) -#if defined(DUK_USE_REFCOUNT16) -#define DUK_HEAPHDR_GET_REFCOUNT(h) ((h)->h_refcount16) -#define DUK_HEAPHDR_SET_REFCOUNT(h,val) do { \ - (h)->h_refcount16 = (val); \ - } while (0) -#define DUK_HEAPHDR_PREINC_REFCOUNT(h) (++(h)->h_refcount16) /* result: updated refcount */ -#define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount16) /* result: updated refcount */ -#else #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 */ -#endif #else /* refcount macros not defined without refcounting, caller must #if defined() now */ #endif /* DUK_USE_REFERENCE_COUNTING */ @@ -240,18 +258,23 @@ } while (0) #endif -#define DUK_HEAPHDR_STRING_INIT_NULLS(h) /* currently nop */ +#define DUK_HEAPHDR_STRING_INIT_NULLS(h) do { \ + (h)->h_next = NULL; \ + } while (0) /* * Type tests */ -#define DUK_HEAPHDR_IS_OBJECT(h) \ - (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_OBJECT) -#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) +/* 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 @@ -274,661 +297,9 @@ #define DUK_ASSERT_HEAPHDR_LINKS(heap,h) do {} while (0) #endif -/* - * Reference counting helper macros. The macros take a thread argument - * and must thus always be executed in a specific thread context. The - * thread argument is needed for features like finalization. Currently - * it is not required for INCREF, but it is included just in case. - * - * 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. - */ - -#if defined(DUK_USE_REFERENCE_COUNTING) - -#if defined(DUK_USE_ROM_OBJECTS) -/* With ROM objects "needs refcount update" is true when the value is - * heap allocated and is not a ROM object. - */ -/* XXX: double evaluation for 'tv' argument. */ -#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) \ - (DUK_TVAL_IS_HEAP_ALLOCATED((tv)) && !DUK_HEAPHDR_HAS_READONLY(DUK_TVAL_GET_HEAPHDR((tv)))) -#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) (!DUK_HEAPHDR_HAS_READONLY((h))) -#else /* DUK_USE_ROM_OBJECTS */ -/* Without ROM objects "needs refcount update" == is heap allocated. */ -#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) DUK_TVAL_IS_HEAP_ALLOCATED((tv)) -#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 1 -#endif /* DUK_USE_ROM_OBJECTS */ - -/* Fast variants, inline refcount operations except for refzero handling. - * Can be used explicitly when speed is always more important than size. - * For a good compiler and a single file build, these are basically the - * same as a forced inline. - */ -#define DUK_TVAL_INCREF_FAST(thr,tv) do { \ - duk_tval *duk__tv = (tv); \ - DUK_ASSERT(duk__tv != NULL); \ - if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \ - duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \ - DUK_ASSERT(duk__h != NULL); \ - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ - DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \ - } \ - } while (0) -#define DUK_TVAL_DECREF_FAST(thr,tv) do { \ - duk_tval *duk__tv = (tv); \ - DUK_ASSERT(duk__tv != NULL); \ - if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \ - duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \ - DUK_ASSERT(duk__h != NULL); \ - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \ - if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \ - duk_heaphdr_refzero((thr), duk__h); \ - } \ - } \ - } while (0) -#define DUK_TVAL_DECREF_NORZ_FAST(thr,tv) do { \ - duk_tval *duk__tv = (tv); \ - DUK_ASSERT(duk__tv != NULL); \ - if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \ - duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \ - DUK_ASSERT(duk__h != NULL); \ - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \ - if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \ - duk_heaphdr_refzero_norz((thr), duk__h); \ - } \ - } \ - } while (0) -#define DUK_HEAPHDR_INCREF_FAST(thr,h) do { \ - duk_heaphdr *duk__h = (duk_heaphdr *) (h); \ - DUK_ASSERT(duk__h != NULL); \ - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ - if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \ - DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \ - } \ - } while (0) -#define DUK_HEAPHDR_DECREF_FAST_RAW(thr,h,rzcall,rzcast) do { \ - duk_heaphdr *duk__h = (duk_heaphdr *) (h); \ - DUK_ASSERT(duk__h != NULL); \ - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \ - if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \ - if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \ - (rzcall)((thr), (rzcast) duk__h); \ - } \ - } \ - } while (0) -#define DUK_HEAPHDR_DECREF_FAST(thr,h) \ - DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *) -#define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) \ - DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *) - -/* Slow variants, call to a helper to reduce code size. - * Can be used explicitly when size is always more important than speed. - */ -#define DUK_TVAL_INCREF_SLOW(thr,tv) do { duk_tval_incref((tv)); } while (0) -#define DUK_TVAL_DECREF_SLOW(thr,tv) do { duk_tval_decref((thr), (tv)); } while (0) -#define DUK_TVAL_DECREF_NORZ_SLOW(thr,tv) do { duk_tval_decref_norz((thr), (tv)); } while (0) -#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) -#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) -#define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) -#define DUK_HSTRING_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) -#define DUK_HSTRING_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) -#define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) -#define DUK_HBUFFER_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) -#define DUK_HBUFFER_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) -#define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) -#define DUK_HOBJECT_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) -#define DUK_HOBJECT_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) -#define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) - -/* Default variants. Selection depends on speed/size preference. - * Concretely: with gcc 4.8.1 -Os x64 the difference in final binary - * is about +1kB for _FAST variants. - */ -#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) -/* XXX: It would be nice to specialize for specific duk_hobject subtypes - * but current refzero queue handling prevents that. - */ -#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_FAST((thr),(tv)) -#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_FAST((thr),(tv)) -#define DUK_TVAL_DECREF_NORZ(thr,tv) DUK_TVAL_DECREF_NORZ_FAST((thr),(tv)) -#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_FAST((thr),(h)) -#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *) -#define DUK_HEAPHDR_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *) -#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) -#define DUK_HSTRING_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *) -#define DUK_HSTRING_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *) /* no 'norz' variant */ -#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) -#define DUK_HOBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) -#define DUK_HOBJECT_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) -#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) -#define DUK_HBUFFER_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *) -#define DUK_HBUFFER_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *) /* no 'norz' variant */ -#define DUK_HCOMPFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HCOMPFUNC_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) -#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) -#define DUK_HNATFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HNATFUNC_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) -#define DUK_HNATFUNC_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) -#define DUK_HBUFOBJ_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HBUFOBJ_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) -#define DUK_HBUFOBJ_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) -#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HTHREAD_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) -#define DUK_HTHREAD_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) -#else -#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_SLOW((thr),(tv)) -#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_SLOW((thr),(tv)) -#define DUK_TVAL_DECREF_NORZ(thr,tv) DUK_TVAL_DECREF_NORZ_SLOW((thr),(tv)) -#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_SLOW((thr),(h)) -#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_SLOW((thr),(h)) -#define DUK_HEAPHDR_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_NORZ_SLOW((thr),(h)) -#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) -#define DUK_HSTRING_DECREF(thr,h) DUK_HSTRING_DECREF_SLOW((thr),(h)) -#define DUK_HSTRING_DECREF_NORZ(thr,h) DUK_HSTRING_DECREF_NORZ_SLOW((thr),(h)) -#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) -#define DUK_HOBJECT_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(h)) -#define DUK_HOBJECT_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(h)) -#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) -#define DUK_HBUFFER_DECREF(thr,h) DUK_HBUFFER_DECREF_SLOW((thr),(h)) -#define DUK_HBUFFER_DECREF_NORZ(thr,h) DUK_HBUFFER_DECREF_NORZ_SLOW((thr),(h)) -#define DUK_HCOMPFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HCOMPFUNC_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) -#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) -#define DUK_HNATFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HNATFUNC_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) -#define DUK_HNATFUNC_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) -#define DUK_HBUFOBJ_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HBUFOBJ_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) -#define DUK_HBUFOB_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) -#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) -#define DUK_HTHREAD_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) -#define DUK_HTHREAD_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) -#endif - -/* Convenience for some situations; the above macros don't allow NULLs - * for performance reasons. Macros cover only actually needed cases. - */ -#define DUK_HEAPHDR_INCREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HEAPHDR_INCREF((thr), (duk_heaphdr *) (h)); \ - } \ +#define DUK_ASSERT_HEAPHDR_VALID(h) do { \ + DUK_ASSERT((h) != NULL); \ + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID((h))); \ } while (0) -#define DUK_HEAPHDR_DECREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HEAPHDR_DECREF((thr), (duk_heaphdr *) (h)); \ - } \ - } while (0) -#define DUK_HEAPHDR_DECREF_NORZ_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HEAPHDR_DECREF_NORZ((thr), (duk_heaphdr *) (h)); \ - } \ - } while (0) -#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HOBJECT_INCREF((thr), (h)); \ - } \ - } while (0) -#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HOBJECT_DECREF((thr), (h)); \ - } \ - } while (0) -#define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HOBJECT_DECREF_NORZ((thr), (h)); \ - } \ - } while (0) -#define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HBUFFER_INCREF((thr), (h)); \ - } \ - } while (0) -#define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HBUFFER_DECREF((thr), (h)); \ - } \ - } while (0) -#define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HBUFFER_DECREF_NORZ((thr), (h)); \ - } \ - } while (0) -#define DUK_HTHREAD_INCREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HTHREAD_INCREF((thr), (h)); \ - } \ - } while (0) -#define DUK_HTHREAD_DECREF_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HTHREAD_DECREF((thr), (h)); \ - } \ - } while (0) -#define DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr,h) do { \ - if ((h) != NULL) { \ - DUK_HTHREAD_DECREF_NORZ((thr), (h)); \ - } \ - } while (0) - -/* Free pending refzero entries; quick check to avoid call because often - * the queue is empty. - */ -#define DUK_REFZERO_CHECK_FAST(thr) do { \ - if ((thr)->heap->refzero_list != NULL) { \ - duk_refzero_free_pending((thr)); \ - } \ - } while (0) -#define DUK_REFZERO_CHECK_SLOW(thr) do { \ - duk_refzero_free_pending((thr)); \ - } while (0) - -/* - * Macros to set a duk_tval and update refcount of the target (decref the - * old value and incref the new value if necessary). This is both performance - * and footprint critical; any changes made should be measured for size/speed. - */ - -#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_UNDEFINED(tv__dst); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_UNDEFINED(tv__dst); \ - DUK_TVAL_DECREF_NORZ((thr), &tv__tmp); \ - } while (0) - -#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_UNUSED(tv__dst); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_NULL(tv__dst); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) -#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) -#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) -#define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_NAN(tv__dst); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) -#if defined(DUK_USE_FASTINT) -#define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_I48(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) -#define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_I32(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) -#define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_U32(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) -#else -#define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \ - DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval)) -#endif /* DUK_USE_FASTINT */ - -#define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_STRING(tv__dst, (newval)); \ - DUK_HSTRING_INCREF((thr), (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \ - DUK_HOBJECT_INCREF((thr), (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \ - DUK_HBUFFER_INCREF((thr), (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -#define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_POINTER(tv__dst, (newval)); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -/* DUK_TVAL_SET_TVAL_UPDREF() is used a lot in executor, property lookups, - * etc, so it's very important for performance. Measure when changing. - * - * NOTE: the source and destination duk_tval pointers may be the same, and - * the macros MUST deal with that correctly. - */ - -/* Original idiom used, minimal code size. */ -#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \ - duk_tval *tv__dst, *tv__src; duk_tval tv__tmp; \ - tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ - DUK_TVAL_INCREF((thr), tv__src); \ - DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ - } while (0) - -/* Faster alternative: avoid making a temporary copy of tvptr_dst and use - * fast incref/decref macros. - */ -#define DUK_TVAL_SET_TVAL_UPDREF_ALT1(thr,tvptr_dst,tvptr_src) do { \ - duk_tval *tv__dst, *tv__src; duk_heaphdr *h__obj; \ - tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ - DUK_TVAL_INCREF_FAST((thr), tv__src); \ - if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv__dst)) { \ - h__obj = DUK_TVAL_GET_HEAPHDR(tv__dst); \ - DUK_ASSERT(h__obj != NULL); \ - DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ - DUK_HEAPHDR_DECREF_FAST((thr), h__obj); /* side effects */ \ - } else { \ - DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ - } \ - } while (0) - -/* XXX: no optimized variants yet */ -#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 -#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0 -#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0 -#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0 -#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0 -#define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0 -#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0 -#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0 -#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0 -#if defined(DUK_USE_FASTINT) -#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_I48_UPDREF_ALT0 -#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_I32_UPDREF_ALT0 -#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_U32_UPDREF_ALT0 -#else -#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast int-to-double */ -#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF -#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF -#endif /* DUK_USE_FASTINT */ -#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_I48_UPDREF /* convenience */ -#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0 -#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0 -#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0 -#define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0 -#define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0 - -#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) -/* Optimized for speed. */ -#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT1 -#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT1 -#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0 -#else -/* Optimized for size. */ -#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0 -#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0 -#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0 -#endif - -#else /* DUK_USE_REFERENCE_COUNTING */ - -#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) 0 -#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 0 - -#define DUK_TVAL_INCREF_FAST(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_DECREF_FAST(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_DECREF_NORZ_FAST(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_INCREF_SLOW(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_DECREF_SLOW(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_DECREF_NORZ_SLOW(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_INCREF(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_DECREF(thr,v) do {} while (0) /* nop */ -#define DUK_TVAL_DECREF_NORZ(thr,v) do {} while (0) /* nop */ -#define DUK_HEAPHDR_INCREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_DECREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HEAPHDR_DECREF_NORZ(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_INCREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_DECREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_INCREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_DECREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HSTRING_DECREF_NORZ(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_INCREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_INCREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF_NORZ(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_INCREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_INCREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF_NORZ(thr,h) do {} while (0) /* nop */ - -#define DUK_HCOMPFUNC_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HCOMPFUNC_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) do {} while (0) /* nop */ -#define DUK_HNATFUNC_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HNATFUNC_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HNATFUNC_DECREF_NORZ(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFOBJ_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFOBJ_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFOBJ_DECREF_NORZ(thr,h) do {} while (0) /* nop */ -#define DUK_HTHREAD_INCREF(thr,h) do {} while (0) /* nop */ -#define DUK_HTHREAD_DECREF(thr,h) do {} while (0) /* nop */ -#define DUK_HTHREAD_DECREF_NORZ(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ -#define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ -#define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do {} while (0) /* nop */ - -#define DUK_REFZERO_CHECK_FAST(thr) do {} while (0) /* nop */ -#define DUK_REFZERO_CHECK_SLOW(thr) do {} while (0) /* nop */ - -#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_UNDEFINED(tv__dst); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_UNUSED(tv__dst); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_NULL(tv__dst); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) -#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) -#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) -#define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_NAN(tv__dst); \ - DUK_UNREF((thr)); \ - } while (0) -#if defined(DUK_USE_FASTINT) -#define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_I48(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) -#define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_I32(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) -#define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_U32(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) -#else -#define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \ - DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval)) -#endif /* DUK_USE_FASTINT */ - -#define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_STRING(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ - duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_POINTER(tv__dst, (newval)); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \ - duk_tval *tv__dst, *tv__src; \ - tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ - DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ - DUK_UNREF((thr)); \ - } while (0) - -#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 -#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 -#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0 -#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0 -#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0 -#define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0 -#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0 -#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0 -#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0 -#if defined(DUK_USE_FASTINT) -#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_I48_UPDREF_ALT0 -#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_I32_UPDREF_ALT0 -#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_U32_UPDREF_ALT0 -#else -#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast-int-to-double */ -#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF -#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF -#endif /* DUK_USE_FASTINT */ -#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_I48_UPDREF /* convenience */ -#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0 -#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0 -#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0 -#define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0 -#define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0 - -#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0 -#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0 -#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0 - -#endif /* DUK_USE_REFERENCE_COUNTING */ #endif /* DUK_HEAPHDR_H_INCLUDED */ diff -Nru duktape-2.0.0/src-separate/duk_heap_markandsweep.c duktape-2.1.1/src-separate/duk_heap_markandsweep.c --- duktape-2.0.0/src-separate/duk_heap_markandsweep.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_heap_markandsweep.c 2017-07-28 22:05:08.000000000 +0000 @@ -8,22 +8,7 @@ DUK_LOCAL_DECL void duk__mark_tval(duk_heap *heap, duk_tval *tv); /* - * Misc - */ - -/* Select a thread for mark-and-sweep use. - * - * XXX: This needs to change later. - */ -DUK_LOCAL duk_hthread *duk__get_temp_hthread(duk_heap *heap) { - if (heap->curr_thread) { - return heap->curr_thread; - } - return heap->heap_thread; /* may be NULL, too */ -} - -/* - * Marking functions for heap types: mark children recursively + * Marking functions for heap types: mark children recursively. */ DUK_LOCAL void duk__mark_hstring(duk_heap *heap, duk_hstring *h) { @@ -47,7 +32,7 @@ for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) { duk_hstring *key = DUK_HOBJECT_E_GET_KEY(heap, h, i); - if (!key) { + if (key == NULL) { continue; } duk__mark_heaphdr(heap, (duk_heaphdr *) key); @@ -63,15 +48,19 @@ duk__mark_tval(heap, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i)); } - /* hash part is a 'weak reference' and does not contribute */ + /* Hash part is a 'weak reference' and does not contribute. */ duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h)); - /* XXX: rearrange bits to allow a switch case to be used here? */ - /* XXX: add a fast path for objects (and arrays)? */ - /* DUK_HOBJECT_IS_ARRAY(h): needs no special handling now as there are - * no extra fields in need of marking. + /* Fast path for objects which don't have a subclass struct, or have a + * subclass struct but nothing that needs marking in the subclass struct. */ + if (DUK_HOBJECT_HAS_FASTREFS(h)) { + DUK_ASSERT(DUK_HOBJECT_ALLOWS_FASTREFS(h)); + return; + } + DUK_ASSERT(DUK_HOBJECT_PROHIBITS_FASTREFS(h)); + if (DUK_HOBJECT_IS_COMPFUNC(h)) { duk_hcompfunc *f = (duk_hcompfunc *) h; duk_tval *tv, *tv_end; @@ -103,16 +92,21 @@ /* May happen in some out-of-memory corner cases. */ DUK_D(DUK_DPRINT("duk_hcompfunc 'data' is NULL, skipping marking")); } - } else if (DUK_HOBJECT_IS_NATFUNC(h)) { - duk_hnatfunc *f = (duk_hnatfunc *) h; - DUK_UNREF(f); - /* nothing to mark */ #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) } else if (DUK_HOBJECT_IS_BUFOBJ(h)) { duk_hbufobj *b = (duk_hbufobj *) h; duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf); duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf_prop); #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ + } else if (DUK_HOBJECT_IS_DECENV(h)) { + duk_hdecenv *e = (duk_hdecenv *) h; + DUK_ASSERT_HDECENV_VALID(e); + duk__mark_heaphdr(heap, (duk_heaphdr *) e->thread); + duk__mark_heaphdr(heap, (duk_heaphdr *) e->varmap); + } else if (DUK_HOBJECT_IS_OBJENV(h)) { + duk_hobjenv *e = (duk_hobjenv *) h; + DUK_ASSERT_HOBJENV_VALID(e); + duk__mark_heaphdr(heap, (duk_heaphdr *) e->target); } else if (DUK_HOBJECT_IS_THREAD(h)) { duk_hthread *t = (duk_hthread *) h; duk_tval *tv; @@ -141,19 +135,25 @@ duk__mark_heaphdr(heap, (duk_heaphdr *) t->resumer); - /* XXX: duk_small_uint_t would be enough for this loop */ for (i = 0; i < DUK_NUM_BUILTINS; i++) { duk__mark_heaphdr(heap, (duk_heaphdr *) t->builtins[i]); } + } 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); } } -/* recursion tracking happens here only */ +/* Mark any duk_heaphdr type. Recursion tracking happens only here. */ DUK_LOCAL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h) { DUK_DDD(DUK_DDDPRINT("duk__mark_heaphdr %p, type %ld", (void *) h, (h != NULL ? (long) DUK_HEAPHDR_GET_TYPE(h) : (long) -1))); - if (!h) { + if (h == NULL) { return; } #if defined(DUK_USE_ROM_OBJECTS) @@ -162,21 +162,24 @@ return; } #endif +#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) + h->h_assert_refcount++; /* Comparison refcount: bump even if already reachable. */ +#endif if (DUK_HEAPHDR_HAS_REACHABLE(h)) { DUK_DDD(DUK_DDDPRINT("already marked reachable, skip")); return; } DUK_HEAPHDR_SET_REACHABLE(h); - if (heap->mark_and_sweep_recursion_depth >= DUK_USE_MARK_AND_SWEEP_RECLIMIT) { - /* log this with a normal debug level because this should be relatively rare */ + if (heap->ms_recursion_depth >= DUK_USE_MARK_AND_SWEEP_RECLIMIT) { DUK_D(DUK_DPRINT("mark-and-sweep recursion limit reached, marking as temproot: %p", (void *) h)); DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap); DUK_HEAPHDR_SET_TEMPROOT(h); return; } - heap->mark_and_sweep_recursion_depth++; + heap->ms_recursion_depth++; + DUK_ASSERT(heap->ms_recursion_depth != 0); /* Wrap. */ switch (DUK_HEAPHDR_GET_TYPE(h)) { case DUK_HTYPE_STRING: @@ -193,12 +196,13 @@ DUK_UNREACHABLE(); } - heap->mark_and_sweep_recursion_depth--; + DUK_ASSERT(heap->ms_recursion_depth > 0); + heap->ms_recursion_depth--; } DUK_LOCAL void duk__mark_tval(duk_heap *heap, duk_tval *tv) { DUK_DDD(DUK_DDDPRINT("duk__mark_tval %p", (void *) tv)); - if (!tv) { + if (tv == NULL) { return; } if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { @@ -234,37 +238,12 @@ } /* - * Mark refzero_list objects. - * - * Objects on the refzero_list have no inbound references. They might have - * outbound references to objects that we might free, which would invalidate - * any references held by the refzero objects. A refzero object might also - * be rescued by refcount finalization. Refzero objects are treated as - * reachability roots to ensure they (or anything they point to) are not - * freed in mark-and-sweep. - */ - -#if defined(DUK_USE_REFERENCE_COUNTING) -DUK_LOCAL void duk__mark_refzero_list(duk_heap *heap) { - duk_heaphdr *hdr; - - DUK_DD(DUK_DDPRINT("duk__mark_refzero_list: %p", (void *) heap)); - - hdr = heap->refzero_list; - while (hdr) { - duk__mark_heaphdr(heap, hdr); - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -} -#endif - -/* * Mark unreachable, finalizable objects. * - * Such objects will be moved aside and their finalizers run later. They have - * to be treated as reachability roots for their properties etc to remain - * allocated. This marking is only done for unreachable values which would - * be swept later (refzero_list is thus excluded). + * Such objects will be moved aside and their finalizers run later. They + * have to be treated as reachability roots for their properties etc to + * remain allocated. This marking is only done for unreachable values which + * would be swept later. * * Objects are first marked FINALIZABLE and only then marked as reachability * roots; otherwise circular references might be handled inconsistently. @@ -272,32 +251,30 @@ #if defined(DUK_USE_FINALIZER_SUPPORT) DUK_LOCAL void duk__mark_finalizable(duk_heap *heap) { - duk_hthread *thr; duk_heaphdr *hdr; duk_size_t count_finalizable = 0; DUK_DD(DUK_DDPRINT("duk__mark_finalizable: %p", (void *) heap)); - thr = duk__get_temp_hthread(heap); - DUK_ASSERT(thr != NULL); + DUK_ASSERT(heap->heap_thread != NULL); hdr = heap->heap_allocated; - while (hdr) { - /* A finalizer is looked up from the object and up its prototype chain - * (which allows inherited finalizers). A prototype loop must not cause - * an error to be thrown here; duk_hobject_hasprop_raw() will ignore a - * prototype loop silently and indicate that the property doesn't exist. + while (hdr != NULL) { + /* A finalizer is looked up from the object and up its + * prototype chain (which allows inherited finalizers). + * The finalizer is checked for using a duk_hobject flag + * which is kept in sync with the presence and callability + * of a _Finalizer hidden symbol. */ if (!DUK_HEAPHDR_HAS_REACHABLE(hdr) && - DUK_HEAPHDR_GET_TYPE(hdr) == DUK_HTYPE_OBJECT && + DUK_HEAPHDR_IS_OBJECT(hdr) && !DUK_HEAPHDR_HAS_FINALIZED(hdr) && - duk_hobject_hasprop_raw(thr, (duk_hobject *) hdr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) { - + DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) hdr)) { /* heaphdr: * - is not reachable * - is an object - * - is not a finalized object + * - is not a finalized object waiting for rescue/keep decision * - has a finalizer */ @@ -307,7 +284,7 @@ (void *) hdr)); DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr)); DUK_HEAPHDR_SET_FINALIZABLE(hdr); - count_finalizable ++; + count_finalizable++; } hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); @@ -321,7 +298,7 @@ (long) count_finalizable)); hdr = heap->heap_allocated; - while (hdr) { + while (hdr != NULL) { if (DUK_HEAPHDR_HAS_FINALIZABLE(hdr)) { duk__mark_heaphdr(heap, hdr); } @@ -335,7 +312,6 @@ /* * Mark objects on finalize_list. - * */ #if defined(DUK_USE_FINALIZER_SUPPORT) @@ -348,7 +324,7 @@ DUK_DD(DUK_DDPRINT("duk__mark_finalize_list: %p", (void *) heap)); hdr = heap->finalize_list; - while (hdr) { + while (hdr != NULL) { duk__mark_heaphdr(heap, hdr); hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); #if defined(DUK_USE_DEBUG) @@ -368,15 +344,18 @@ /* * Fallback marking handler if recursion limit is reached. * - * Iterates 'temproots' until recursion limit is no longer hit. Note - * that temproots may reside either in heap allocated list or the - * refzero work list. This is a slow scan, but guarantees that we - * finish with a bounded C stack. + * Iterates 'temproots' until recursion limit is no longer hit. Temproots + * can be in heap_allocated or finalize_list; refzero_list is now always + * empty for mark-and-sweep. A temproot may occur in finalize_list now if + * there are objects on the finalize_list and user code creates a reference + * from an object in heap_allocated to the object in finalize_list (which is + * now allowed), and it happened to coincide with the recursion depth limit. + * + * This is a slow scan, but guarantees that we finish with a bounded C stack. * - * Note that nodes may have been marked as temproots before this - * scan begun, OR they may have been marked during the scan (as - * we process nodes recursively also during the scan). This is - * intended behavior. + * Note that nodes may have been marked as temproots before this scan begun, + * OR they may have been marked during the scan (as we process nodes + * recursively also during the scan). This is intended behavior. */ #if defined(DUK_USE_DEBUG) @@ -391,7 +370,10 @@ DUK_DDD(DUK_DDDPRINT("found a temp root: %p", (void *) hdr)); DUK_HEAPHDR_CLEAR_TEMPROOT(hdr); - DUK_HEAPHDR_CLEAR_REACHABLE(hdr); /* done so that duk__mark_heaphdr() works correctly */ + DUK_HEAPHDR_CLEAR_REACHABLE(hdr); /* Done so that duk__mark_heaphdr() works correctly. */ +#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) + hdr->h_assert_refcount--; /* Same node visited twice. */ +#endif duk__mark_heaphdr(heap, hdr); #if defined(DUK_USE_DEBUG) @@ -425,9 +407,8 @@ hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); } - /* must also check refzero_list */ -#if defined(DUK_USE_REFERENCE_COUNTING) - hdr = heap->refzero_list; +#if defined(DUK_USE_FINALIZER_SUPPORT) + hdr = heap->finalize_list; while (hdr) { #if defined(DUK_USE_DEBUG) duk__handle_temproot(heap, hdr, &count); @@ -436,7 +417,7 @@ #endif hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); } -#endif /* DUK_USE_REFERENCE_COUNTING */ +#endif #if defined(DUK_USE_DEBUG) DUK_DD(DUK_DDPRINT("temproot mark heap scan processed %ld temp roots", (long) count)); @@ -455,14 +436,11 @@ #if defined(DUK_USE_REFERENCE_COUNTING) DUK_LOCAL void duk__finalize_refcounts(duk_heap *heap) { - duk_hthread *thr; duk_heaphdr *hdr; - thr = duk__get_temp_hthread(heap); - DUK_ASSERT(thr != NULL); + DUK_ASSERT(heap->heap_thread != NULL); - DUK_DD(DUK_DDPRINT("duk__finalize_refcounts: heap=%p, hthread=%p", - (void *) heap, (void *) thr)); + DUK_DD(DUK_DDPRINT("duk__finalize_refcounts: heap=%p", (void *) heap)); hdr = heap->heap_allocated; while (hdr) { @@ -478,37 +456,21 @@ */ DUK_DDD(DUK_DDDPRINT("unreachable object, refcount finalize before sweeping: %p", (void *) hdr)); - duk_heaphdr_refcount_finalize(thr, hdr); - } - - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -} -#endif /* DUK_USE_REFERENCE_COUNTING */ -/* - * Clear (reachable) flags of refzero work list. - */ - -#if defined(DUK_USE_REFERENCE_COUNTING) -DUK_LOCAL void duk__clear_refzero_list_flags(duk_heap *heap) { - duk_heaphdr *hdr; - - DUK_DD(DUK_DDPRINT("duk__clear_refzero_list_flags: %p", (void *) heap)); + /* Finalize using heap->heap_thread; DECREF has a + * suppress check for mark-and-sweep which is based + * on heap->ms_running. + */ + duk_heaphdr_refcount_finalize_norz(heap, hdr); + } - hdr = heap->refzero_list; - while (hdr) { - DUK_HEAPHDR_CLEAR_REACHABLE(hdr); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr)); hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); } } #endif /* DUK_USE_REFERENCE_COUNTING */ /* - * Clear (reachable) flags of finalize_list + * Clear (reachable) flags of finalize_list. * * We could mostly do in the sweep phase when we move objects from the * heap into the finalize_list. However, if a finalizer run is skipped @@ -527,8 +489,11 @@ hdr = heap->finalize_list; while (hdr) { DUK_HEAPHDR_CLEAR_REACHABLE(hdr); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr)); +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(hdr) || \ + (heap->currently_finalizing == hdr)); +#endif + /* DUK_HEAPHDR_FLAG_FINALIZED may be set. */ DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr)); hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); } @@ -536,191 +501,85 @@ #endif /* DUK_USE_FINALIZER_SUPPORT */ /* - * Sweep stringtable + * Sweep stringtable. */ -#if defined(DUK_USE_STRTAB_CHAIN) - -/* XXX: skip count_free w/o debug? */ -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL void duk__sweep_string_chain16(duk_heap *heap, duk_uint16_t *slot, duk_size_t *count_keep, duk_size_t *count_free) { - duk_uint16_t h16 = *slot; +DUK_LOCAL void duk__sweep_stringtable(duk_heap *heap, duk_size_t *out_count_keep) { duk_hstring *h; - duk_uint16_t null16 = heap->heapptr_null16; - - if (h16 == null16) { - /* nop */ - return; - } - h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, h16); - DUK_ASSERT(h != NULL); - - if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) { - DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h); - (*count_keep)++; - } else { -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0); -#endif - /* deal with weak references first */ - duk_heap_strcache_string_remove(heap, (duk_hstring *) h); - *slot = null16; - - /* free inner references (these exist e.g. when external - * strings are enabled) - */ - duk_free_hstring(heap, h); - (*count_free)++; - } -} -#else /* DUK_USE_HEAPPTR16 */ -DUK_LOCAL void duk__sweep_string_chain(duk_heap *heap, duk_hstring **slot, duk_size_t *count_keep, duk_size_t *count_free) { - duk_hstring *h = *slot; - - if (h == NULL) { - /* nop */ - return; - } - - if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) { - DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h); - (*count_keep)++; - } else { -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0); -#endif - /* deal with weak references first */ - duk_heap_strcache_string_remove(heap, (duk_hstring *) h); - *slot = NULL; - - /* free inner references (these exist e.g. when external - * strings are enabled) - */ - duk_free_hstring(heap, h); - (*count_free)++; - } -} -#endif /* DUK_USE_HEAPPTR16 */ - -DUK_LOCAL void duk__sweep_stringtable_chain(duk_heap *heap, duk_size_t *out_count_keep) { - duk_strtab_entry *e; - duk_uint_fast32_t i; + duk_hstring *prev; + duk_uint32_t i; +#if defined(DUK_USE_DEBUG) duk_size_t count_free = 0; - duk_size_t count_keep = 0; - duk_size_t j, n; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t *lst; -#else - duk_hstring **lst; #endif + duk_size_t count_keep = 0; DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap)); - /* Non-zero refcounts should not happen for unreachable strings, - * because we refcount finalize all unreachable objects which - * should have decreased unreachable string refcounts to zero - * (even for cycles). - */ - - for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { - e = heap->strtable + i; - if (e->listlen == 0) { -#if defined(DUK_USE_HEAPPTR16) - duk__sweep_string_chain16(heap, &e->u.str16, &count_keep, &count_free); -#else - duk__sweep_string_chain(heap, &e->u.str, &count_keep, &count_free); -#endif - } else { -#if defined(DUK_USE_HEAPPTR16) - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); +#if defined(DUK_USE_STRTAB_PTRCOMP) + if (heap->strtable16 == NULL) { #else - lst = e->u.strlist; + if (heap->strtable == NULL) { #endif - for (j = 0, n = e->listlen; j < n; j++) { -#if defined(DUK_USE_HEAPPTR16) - duk__sweep_string_chain16(heap, lst + j, &count_keep, &count_free); -#else - duk__sweep_string_chain(heap, lst + j, &count_keep, &count_free); -#endif - } - } + goto done; } - DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept", - (long) count_free, (long) count_keep)); - *out_count_keep = count_keep; -} -#endif /* DUK_USE_STRTAB_CHAIN */ - -#if defined(DUK_USE_STRTAB_PROBE) -DUK_LOCAL void duk__sweep_stringtable_probe(duk_heap *heap, duk_size_t *out_count_keep) { - duk_hstring *h; - duk_uint_fast32_t i; -#if defined(DUK_USE_DEBUG) - duk_size_t count_free = 0; -#endif - duk_size_t count_keep = 0; - - DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap)); - for (i = 0; i < heap->st_size; i++) { -#if defined(DUK_USE_HEAPPTR16) - h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); +#if defined(DUK_USE_STRTAB_PTRCOMP) + h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); #else h = heap->strtable[i]; #endif - if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) { - continue; - } else if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) { - DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h); - count_keep++; - continue; - } - + prev = NULL; + while (h != NULL) { + duk_hstring *next; + next = h->hdr.h_next; + + if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) { + DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h); + count_keep++; + prev = h; + } else { #if defined(DUK_USE_DEBUG) - count_free++; + count_free++; #endif #if defined(DUK_USE_REFERENCE_COUNTING) - /* Non-zero refcounts should not happen for unreachable strings, - * because we refcount finalize all unreachable objects which - * should have decreased unreachable string refcounts to zero - * (even for cycles). - */ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0); + /* Non-zero refcounts should not happen for unreachable strings, + * because we refcount finalize all unreachable objects which + * should have decreased unreachable string refcounts to zero + * (even for cycles). + */ + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0); #endif - DUK_DDD(DUK_DDDPRINT("sweep string, not reachable: %p", (void *) h)); + /* Deal with weak references first. */ + duk_heap_strcache_string_remove(heap, (duk_hstring *) h); - /* deal with weak references first */ - duk_heap_strcache_string_remove(heap, (duk_hstring *) h); + /* Remove the string from the string table. */ + duk_heap_strtable_unlink_prev(heap, (duk_hstring *) h, (duk_hstring *) prev); - /* remove the string (mark DELETED), could also call - * duk_heap_string_remove() but that would be slow and - * pointless because we already know the slot. - */ -#if defined(DUK_USE_HEAPPTR16) - heap->strtable16[i] = heap->heapptr_deleted16; -#else - heap->strtable[i] = DUK_STRTAB_DELETED_MARKER(heap); -#endif + /* Free inner references (these exist e.g. when external + * strings are enabled) and the struct itself. + */ + duk_free_hstring(heap, (duk_hstring *) h); - /* free inner references (these exist e.g. when external - * strings are enabled) and the struct itself. - */ - duk_free_hstring(heap, (duk_hstring *) h); + /* Don't update 'prev'; it should be last string kept. */ + } + + h = next; + } } + done: #if defined(DUK_USE_DEBUG) DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept", (long) count_free, (long) count_keep)); #endif *out_count_keep = count_keep; } -#endif /* DUK_USE_STRTAB_PROBE */ /* - * Sweep heap + * Sweep heap. */ DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_count_keep) { @@ -749,65 +608,62 @@ if (DUK_HEAPHDR_HAS_REACHABLE(curr)) { /* - * Reachable object, keep + * Reachable object: + * - If FINALIZABLE -> actually unreachable (but marked + * artificially reachable), queue to finalize_list. + * - If !FINALIZABLE but FINALIZED -> rescued after + * finalizer execution. + * - Otherwise just a normal, reachable object. + * + * Objects which are kept are queued to heap_allocated + * tail (we're essentially filtering heap_allocated in + * practice). */ - DUK_DDD(DUK_DDDPRINT("sweep, reachable: %p", (void *) curr)); - - if (DUK_HEAPHDR_HAS_FINALIZABLE(curr)) { - /* - * If object has been marked finalizable, move it to the - * "to be finalized" work list. It will be collected on - * the next mark-and-sweep if it is still unreachable - * after running the finalizer. - */ - +#if defined(DUK_USE_FINALIZER_SUPPORT) + if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZABLE(curr))) { DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); - DUK_DDD(DUK_DDDPRINT("object has finalizer, move to finalization work list: %p", (void *) curr)); + DUK_DD(DUK_DDPRINT("sweep; reachable, finalizable --> move to finalize_list: %p", (void *) curr)); -#if defined(DUK_USE_DOUBLE_LINKED_HEAP) - if (heap->finalize_list) { - DUK_HEAPHDR_SET_PREV(heap, heap->finalize_list, curr); - } - DUK_HEAPHDR_SET_PREV(heap, curr, NULL); +#if defined(DUK_USE_REFERENCE_COUNTING) + DUK_HEAPHDR_PREINC_REFCOUNT(curr); /* Bump refcount so that refzero never occurs when pending a finalizer call. */ #endif - DUK_HEAPHDR_SET_NEXT(heap, curr, heap->finalize_list); - DUK_ASSERT_HEAPHDR_LINKS(heap, curr); - heap->finalize_list = curr; + DUK_HEAP_INSERT_INTO_FINALIZE_LIST(heap, curr); #if defined(DUK_USE_DEBUG) count_finalize++; #endif - } else { - /* - * Object will be kept; queue object back to heap_allocated (to tail) - */ - - if (DUK_HEAPHDR_HAS_FINALIZED(curr)) { - /* - * Object's finalizer was executed on last round, and - * object has been happily rescued. - */ - + } + else +#endif /* DUK_USE_FINALIZER_SUPPORT */ + { + if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZED(curr))) { DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); - DUK_DD(DUK_DDPRINT("object rescued during mark-and-sweep finalization: %p", (void *) curr)); + + if (flags & DUK_MS_FLAG_POSTPONE_RESCUE) { + DUK_DD(DUK_DDPRINT("sweep; reachable, finalized, but postponing rescue decisions --> keep object (with FINALIZED set): %!iO", curr)); + count_keep++; + } else { + DUK_DD(DUK_DDPRINT("sweep; reachable, finalized --> rescued after finalization: %p", (void *) curr)); +#if defined(DUK_USE_FINALIZER_SUPPORT) + DUK_HEAPHDR_CLEAR_FINALIZED(curr); +#endif #if defined(DUK_USE_DEBUG) - count_rescue++; + count_rescue++; #endif + } } else { - /* - * Plain, boring reachable object. - */ - DUK_DD(DUK_DDPRINT("keep object: %!iO", curr)); + DUK_DD(DUK_DDPRINT("sweep; reachable --> keep: %!iO", curr)); count_keep++; } - if (!heap->heap_allocated) { - heap->heap_allocated = curr; - } - if (prev) { + if (prev != NULL) { + DUK_ASSERT(heap->heap_allocated != NULL); DUK_HEAPHDR_SET_NEXT(heap, prev, curr); + } else { + DUK_ASSERT(heap->heap_allocated == NULL); + heap->heap_allocated = curr; } #if defined(DUK_USE_DOUBLE_LINKED_HEAP) DUK_HEAPHDR_SET_PREV(heap, curr, prev); @@ -818,21 +674,23 @@ } DUK_HEAPHDR_CLEAR_REACHABLE(curr); - DUK_HEAPHDR_CLEAR_FINALIZED(curr); - DUK_HEAPHDR_CLEAR_FINALIZABLE(curr); - + /* Keep FINALIZED if set, used if rescue decisions are postponed. */ + /* Keep FINALIZABLE for objects on finalize_list. */ DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); - - curr = next; } else { /* - * Unreachable object, free + * Unreachable object: + * - If FINALIZED, object was finalized but not + * rescued. This doesn't affect freeing. + * - Otherwise normal unreachable object. + * + * There's no guard preventing a FINALIZED object + * from being freed while finalizers execute: the + * artificial finalize_list reachability roots can't + * cause an incorrect free decision (but can cause + * an incorrect rescue decision). */ - DUK_DDD(DUK_DDDPRINT("sweep, not reachable: %p", (void *) curr)); - #if defined(DUK_USE_REFERENCE_COUNTING) /* Non-zero refcounts should not happen because we refcount * finalize all unreachable objects which should cancel out @@ -842,10 +700,15 @@ #endif DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); +#if defined(DUK_USE_DEBUG) if (DUK_HEAPHDR_HAS_FINALIZED(curr)) { - DUK_DDD(DUK_DDDPRINT("finalized object not rescued: %p", (void *) curr)); + DUK_DD(DUK_DDPRINT("sweep; unreachable, finalized --> finalized object not rescued: %p", (void *) curr)); + } else { + DUK_DD(DUK_DDPRINT("sweep; not reachable --> free: %p", (void *) curr)); } +#endif + /* Note: object cannot be a finalizable unreachable object, as * they have been marked temporarily reachable for this round, * and are handled above. @@ -855,17 +718,18 @@ count_free++; #endif - /* weak refs should be handled here, but no weak refs for + /* Weak refs should be handled here, but no weak refs for * any non-string objects exist right now. */ - /* free object and all auxiliary (non-heap) allocs */ + /* Free object and all auxiliary (non-heap) allocs. */ duk_heap_free_heaphdr_raw(heap, curr); - - curr = next; } + + curr = next; } - if (prev) { + + if (prev != NULL) { DUK_HEAPHDR_SET_NEXT(heap, prev, NULL); } DUK_ASSERT_HEAPHDR_LINKS(heap, prev); @@ -878,71 +742,6 @@ } /* - * Run (object) finalizers in the "to be finalized" work list. - */ - -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_LOCAL void duk__run_object_finalizers(duk_heap *heap, duk_small_uint_t flags) { - duk_heaphdr *curr; - duk_heaphdr *next; -#if defined(DUK_USE_DEBUG) - duk_size_t count = 0; -#endif - duk_hthread *thr; - - DUK_DD(DUK_DDPRINT("duk__run_object_finalizers: %p", (void *) heap)); - - thr = duk__get_temp_hthread(heap); - DUK_ASSERT(thr != NULL); - - curr = heap->finalize_list; - while (curr) { - DUK_DDD(DUK_DDDPRINT("mark-and-sweep finalize: %p", (void *) curr)); - - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* only objects have finalizers */ - DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr)); /* flags have been already cleared */ - DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr)); /* No finalizers for ROM objects */ - - if (DUK_LIKELY((flags & DUK_MS_FLAG_SKIP_FINALIZERS) == 0)) { - /* Run the finalizer, duk_hobject_run_finalizer() sets FINALIZED. - * Next mark-and-sweep will collect the object unless it has - * become reachable (i.e. rescued). FINALIZED prevents the - * finalizer from being executed again before that. - */ - duk_hobject_run_finalizer(thr, (duk_hobject *) curr); /* must never longjmp */ - DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(curr)); - } 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)); - } - - /* queue back to heap_allocated */ - next = DUK_HEAPHDR_GET_NEXT(heap, curr); - DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr); - - curr = next; -#if defined(DUK_USE_DEBUG) - count++; -#endif - } - - /* finalize_list will always be processed completely */ - heap->finalize_list = NULL; - -#if defined(DUK_USE_DEBUG) - DUK_D(DUK_DPRINT("mark-and-sweep finalize objects: %ld finalizers called", (long) count)); -#endif -} -#endif /* DUK_USE_FINALIZER_SUPPORT */ - -/* * Object compaction. * * Compaction is assumed to never throw an error. @@ -1017,26 +816,25 @@ duk_size_t count_compact = 0; duk_size_t count_bytes_saved = 0; #endif - duk_hthread *thr; DUK_DD(DUK_DDPRINT("duk__compact_objects: %p", (void *) heap)); - thr = duk__get_temp_hthread(heap); - DUK_ASSERT(thr != NULL); + DUK_ASSERT(heap->heap_thread != NULL); #if defined(DUK_USE_DEBUG) - duk__compact_object_list(heap, thr, heap->heap_allocated, &count_check, &count_compact, &count_bytes_saved); - duk__compact_object_list(heap, thr, heap->finalize_list, &count_check, &count_compact, &count_bytes_saved); -#if defined(DUK_USE_REFERENCE_COUNTING) - duk__compact_object_list(heap, thr, heap->refzero_list, &count_check, &count_compact, &count_bytes_saved); + duk__compact_object_list(heap, heap->heap_thread, heap->heap_allocated, &count_check, &count_compact, &count_bytes_saved); +#if defined(DUK_USE_FINALIZER_SUPPORT) + duk__compact_object_list(heap, heap->heap_thread, heap->finalize_list, &count_check, &count_compact, &count_bytes_saved); #endif #else - duk__compact_object_list(heap, thr, heap->heap_allocated); - duk__compact_object_list(heap, thr, heap->finalize_list); -#if defined(DUK_USE_REFERENCE_COUNTING) - duk__compact_object_list(heap, thr, heap->refzero_list); + duk__compact_object_list(heap, heap->heap_thread, heap->heap_allocated); +#if defined(DUK_USE_FINALIZER_SUPPORT) + duk__compact_object_list(heap, heap->heap_thread, heap->finalize_list); #endif #endif +#if defined(DUK_USE_REFERENCE_COUNTING) + DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ +#endif #if defined(DUK_USE_DEBUG) DUK_D(DUK_DPRINT("mark-and-sweep compact objects: %ld checked, %ld compaction attempts, %ld bytes saved by compaction", @@ -1062,166 +860,189 @@ } #if defined(DUK_USE_REFERENCE_COUNTING) - hdr = heap->refzero_list; - while (hdr) { - DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr)); - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -#endif /* DUK_USE_REFERENCE_COUNTING */ + DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ +#endif } #if defined(DUK_USE_REFERENCE_COUNTING) DUK_LOCAL void duk__assert_valid_refcounts(duk_heap *heap) { duk_heaphdr *hdr = heap->heap_allocated; while (hdr) { + /* Cannot really assert much w.r.t. refcounts now. */ + if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0 && DUK_HEAPHDR_HAS_FINALIZED(hdr)) { /* An object may be in heap_allocated list with a zero * refcount if it has just been finalized and is waiting * to be collected by the next cycle. + * (This doesn't currently happen however.) */ } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0) { /* An object may be in heap_allocated list with a zero - * refcount also if it is a temporary object created by - * a finalizer; because finalization now runs inside - * mark-and-sweep, such objects will not be queued to - * refzero_list and will thus appear here with refcount - * zero. + * refcount also if it is a temporary object created + * during debugger paused state. It will get collected + * by mark-and-sweep based on its reachability status + * (presumably not reachable because refcount is 0). */ -#if 0 /* this case can no longer occur because refcount is unsigned */ - } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) < 0) { - DUK_D(DUK_DPRINT("invalid refcount: %ld, %p -> %!O", - (hdr != NULL ? (long) DUK_HEAPHDR_GET_REFCOUNT(hdr) : (long) 0), - (void *) hdr, (duk_heaphdr *) hdr)); - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(hdr) > 0); -#endif } + DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(hdr) >= 0); /* Unsigned. */ hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); } } -#endif /* DUK_USE_REFERENCE_COUNTING */ -#endif /* DUK_USE_ASSERTIONS */ -/* - * Finalizer torture. Do one fake finalizer call which causes side effects - * similar to one or more finalizers on actual objects. - */ +DUK_LOCAL void duk__clear_assert_refcounts(duk_heap *heap) { + duk_heaphdr *curr; + duk_uint32_t i; + for (curr = heap->heap_allocated; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { + curr->h_assert_refcount = 0; + } #if defined(DUK_USE_FINALIZER_SUPPORT) -#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE) -DUK_LOCAL duk_ret_t duk__markandsweep_fake_finalizer(duk_context *ctx) { - DUK_D(DUK_DPRINT("fake mark-and-sweep torture finalizer executed")); - - /* Require a lot of stack to force a value stack grow/shrink. - * Recursive mark-and-sweep is prevented by allocation macros - * so this won't trigger another mark-and-sweep. - */ - duk_require_stack(ctx, 100000); + for (curr = heap->finalize_list; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { + curr->h_assert_refcount = 0; + } +#endif +#if defined(DUK_USE_REFERENCE_COUNTING) + for (curr = heap->refzero_list; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { + curr->h_assert_refcount = 0; + } +#endif - /* XXX: do something to force a callstack grow/shrink, perhaps - * just a manual forced resize or a forced relocating realloc? - */ + for (i = 0; i < heap->st_size; i++) { + duk_hstring *h; - return 0; +#if defined(DUK_USE_STRTAB_PTRCOMP) + h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); +#else + h = heap->strtable[i]; +#endif + while (h != NULL) { + ((duk_heaphdr *) h)->h_assert_refcount = 0; + h = h->hdr.h_next; + } + } } -DUK_LOCAL void duk__markandsweep_torture_finalizer(duk_hthread *thr) { - duk_context *ctx; - duk_int_t rc; +DUK_LOCAL void duk__check_refcount_heaphdr(duk_heaphdr *hdr) { + duk_bool_t count_ok; - DUK_ASSERT(thr != NULL); - ctx = (duk_context *) thr; + /* The refcount check only makes sense for reachable objects on + * heap_allocated or string table, after the sweep phase. Prior to + * sweep phase refcounts will include references that are not visible + * via reachability roots. + * + * Because we're called after the sweep phase, all heap objects on + * heap_allocated are reachable. REACHABLE flags have already been + * cleared so we can't check them. + */ - /* Avoid fake finalization when callstack limit has been reached. - * Otherwise a callstack limit error will be created, then refzero'ed. + /* ROM objects have intentionally incorrect refcount (1), but we won't + * check them. */ - if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit || - thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) { - DUK_D(DUK_DPRINT("call recursion depth reached, avoid fake mark-and-sweep torture finalizer")); - return; + DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr)); + + count_ok = ((duk_size_t) DUK_HEAPHDR_GET_REFCOUNT(hdr) == hdr->h_assert_refcount); + if (!count_ok) { + DUK_D(DUK_DPRINT("refcount mismatch for: %p: header=%ld counted=%ld --> %!iO", + (void *) hdr, (long) DUK_HEAPHDR_GET_REFCOUNT(hdr), + (long) hdr->h_assert_refcount, hdr)); + DUK_ASSERT(0); } +} + +DUK_LOCAL void duk__check_assert_refcounts(duk_heap *heap) { + duk_heaphdr *curr; + duk_uint32_t i; - /* Run fake finalizer. Avoid creating unnecessary garbage. */ - duk_push_c_function(ctx, duk__markandsweep_fake_finalizer, 0 /*nargs*/); - rc = duk_pcall(ctx, 0 /*nargs*/); - DUK_UNREF(rc); /* ignored */ - duk_pop(ctx); + for (curr = heap->heap_allocated; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { + duk__check_refcount_heaphdr(curr); + } +#if defined(DUK_USE_FINALIZER_SUPPORT) + for (curr = heap->finalize_list; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { + duk__check_refcount_heaphdr(curr); + } +#endif + + for (i = 0; i < heap->st_size; i++) { + duk_hstring *h; + +#if defined(DUK_USE_STRTAB_PTRCOMP) + h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); +#else + h = heap->strtable[i]; +#endif + while (h != NULL) { + duk__check_refcount_heaphdr((duk_heaphdr *) h); + h = h->hdr.h_next; + } + } } -#endif /* DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE */ -#endif /* DUK_USE_FINALIZER_SUPPORT */ +#endif /* DUK_USE_REFERENCE_COUNTING */ +#endif /* DUK_USE_ASSERTIONS */ /* * Main mark-and-sweep function. * * 'flags' represents the features requested by the caller. The current - * heap->mark_and_sweep_base_flags is ORed automatically into the flags; - * the base flags mask typically prevents certain mark-and-sweep operations - * to avoid trouble. + * heap->ms_base_flags is ORed automatically into the flags; the base flags + * mask typically prevents certain mark-and-sweep operation to avoid trouble. */ -DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags) { - duk_hthread *thr; +DUK_INTERNAL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags) { duk_size_t count_keep_obj; duk_size_t count_keep_str; #if defined(DUK_USE_VOLUNTARY_GC) duk_size_t tmp; #endif - /* XXX: thread selection for mark-and-sweep is currently a hack. - * If we don't have a thread, the entire mark-and-sweep is now - * skipped (although we could just skip finalizations). + /* If debugger is paused, garbage collection is disabled by default. + * This is achieved by bumping ms_prevent_count when becoming paused. */ + DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) || heap->ms_prevent_count > 0); - /* If thr != NULL, the thr may still be in the middle of - * initialization. - * XXX: Improve the thread viability test. + /* Prevention/recursion check as soon as possible because we may + * be called a number of times when voluntary mark-and-sweep is + * pending. */ - thr = duk__get_temp_hthread(heap); - if (thr == NULL) { - DUK_D(DUK_DPRINT("gc skipped because we don't have a temp thread")); - - /* reset voluntary gc trigger count */ -#if defined(DUK_USE_VOLUNTARY_GC) - heap->mark_and_sweep_trigger_counter = DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP; -#endif - return 0; /* OK */ + if (heap->ms_prevent_count != 0) { + DUK_DD(DUK_DDPRINT("reject recursive mark-and-sweep")); + return; } + DUK_ASSERT(heap->ms_running == 0); /* ms_prevent_count is bumped when ms_running is set */ - /* If debugger is paused, garbage collection is disabled by default. */ - /* XXX: will need a force flag if garbage collection is triggered - * explicitly during paused state. - */ -#if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_HEAP_IS_PAUSED(heap)) { - /* Checking this here rather that in memory alloc primitives - * reduces checking code there but means a failed allocation - * will go through a few retries before giving up. That's - * fine because this only happens during debugging. - */ - DUK_D(DUK_DPRINT("gc skipped because debugger is paused")); - return 0; - } -#endif + /* Heap_thread is used during mark-and-sweep for refcount finalization + * (it's also used for finalizer execution once mark-and-sweep is + * complete). Heap allocation code ensures heap_thread is set and + * properly initialized before setting ms_prevent_count to 0. + */ + DUK_ASSERT(heap->heap_thread != NULL); + DUK_ASSERT(heap->heap_thread->valstack != NULL); + DUK_ASSERT(heap->heap_thread->callstack != NULL); + DUK_ASSERT(heap->heap_thread->catchstack != NULL); DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) starting, requested flags: 0x%08lx, effective flags: 0x%08lx", - (unsigned long) flags, (unsigned long) (flags | heap->mark_and_sweep_base_flags))); + (unsigned long) flags, (unsigned long) (flags | heap->ms_base_flags))); - flags |= heap->mark_and_sweep_base_flags; + flags |= heap->ms_base_flags; +#if defined(DUK_USE_FINALIZER_SUPPORT) + if (heap->finalize_list != NULL) { + flags |= DUK_MS_FLAG_POSTPONE_RESCUE; + } +#endif /* * Assertions before */ #if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)); + DUK_ASSERT(heap->ms_prevent_count == 0); + DUK_ASSERT(heap->ms_running == 0); + DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(heap)); DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)); - DUK_ASSERT(heap->mark_and_sweep_recursion_depth == 0); + DUK_ASSERT(heap->ms_recursion_depth == 0); duk__assert_heaphdr_flags(heap); #if defined(DUK_USE_REFERENCE_COUNTING) - /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount + /* Note: heap->refzero_free_running may be true; a refcount * finalizer may trigger a mark-and-sweep. */ duk__assert_valid_refcounts(heap); @@ -1232,7 +1053,10 @@ * Begin */ - DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap); + DUK_ASSERT(heap->ms_prevent_count == 0); + DUK_ASSERT(heap->ms_running == 0); + heap->ms_prevent_count = 1; + heap->ms_running = 1; /* * Mark roots, hoping that recursion limit is not normally hit. @@ -1250,17 +1074,20 @@ * previous run had finalizer skip flag. */ - duk__mark_roots_heap(heap); /* main reachability roots */ +#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) + duk__clear_assert_refcounts(heap); +#endif + duk__mark_roots_heap(heap); /* Mark main reachability roots. */ #if defined(DUK_USE_REFERENCE_COUNTING) - duk__mark_refzero_list(heap); /* refzero_list treated as reachability roots */ + DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ #endif - duk__mark_temproots_by_heap_scan(heap); /* temproots */ + duk__mark_temproots_by_heap_scan(heap); /* Temproots. */ #if defined(DUK_USE_FINALIZER_SUPPORT) - duk__mark_finalizable(heap); /* mark finalizable as reachability roots */ - duk__mark_finalize_list(heap); /* mark finalizer work list as reachability roots */ + duk__mark_finalizable(heap); /* Mark finalizable as reachability roots. */ + duk__mark_finalize_list(heap); /* Mark finalizer work list as reachability roots. */ #endif - duk__mark_temproots_by_heap_scan(heap); /* temproots */ + duk__mark_temproots_by_heap_scan(heap); /* Temproots. */ /* * Sweep garbage and remove marking flags, and move objects with @@ -1282,15 +1109,12 @@ duk__finalize_refcounts(heap); #endif duk__sweep_heap(heap, flags, &count_keep_obj); -#if defined(DUK_USE_STRTAB_CHAIN) - duk__sweep_stringtable_chain(heap, &count_keep_str); -#elif defined(DUK_USE_STRTAB_PROBE) - duk__sweep_stringtable_probe(heap, &count_keep_str); -#else -#error internal error, invalid strtab options + duk__sweep_stringtable(heap, &count_keep_str); +#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) + duk__check_assert_refcounts(heap); #endif #if defined(DUK_USE_REFERENCE_COUNTING) - duk__clear_refzero_list_flags(heap); + DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ #endif #if defined(DUK_USE_FINALIZER_SUPPORT) duk__clear_finalize_list_flags(heap); @@ -1321,94 +1145,39 @@ /* * String table resize check. * - * Note: this may silently (and safely) fail if GC is caused by an - * allocation call in stringtable resize_hash(). Resize_hash() - * will prevent a recursive call to itself by setting the - * DUK_MS_FLAG_NO_STRINGTABLE_RESIZE in heap->mark_and_sweep_base_flags. - */ - - /* XXX: stringtable emergency compaction? */ - - /* XXX: remove this feature entirely? it would only matter for - * emergency GC. Disable for lowest memory builds. - */ -#if defined(DUK_USE_MS_STRINGTABLE_RESIZE) - if (!(flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE)) { - DUK_DD(DUK_DDPRINT("resize stringtable: %p", (void *) heap)); - duk_heap_force_strtab_resize(heap); - } else { - DUK_D(DUK_DPRINT("stringtable resize skipped because DUK_MS_FLAG_NO_STRINGTABLE_RESIZE is set")); - } -#endif - - /* - * Finalize objects in the finalization work list. Finalized - * objects are queued back to heap_allocated with FINALIZED set. - * - * Since finalizers may cause arbitrary side effects, they are - * prevented during string table and object property allocation - * resizing using the DUK_MS_FLAG_NO_FINALIZERS flag in - * heap->mark_and_sweep_base_flags. In this case the objects - * remain in the finalization work list after mark-and-sweep - * exits and they may be finalized on the next pass. - * - * Finalization currently happens inside "MARKANDSWEEP_RUNNING" - * protection (no mark-and-sweep may be triggered by the - * finalizers). As a side effect: - * - * 1) an out-of-memory error inside a finalizer will not - * cause a mark-and-sweep and may cause the finalizer - * to fail unnecessarily - * - * 2) any temporary objects whose refcount decreases to zero - * during finalization will not be put into refzero_list; - * they can only be collected by another mark-and-sweep - * - * This is not optimal, but since the sweep for this phase has - * already happened, this is probably good enough for now. - */ - -#if defined(DUK_USE_FINALIZER_SUPPORT) -#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE) - /* Cannot simulate individual finalizers because finalize_list only - * contains objects with actual finalizers. But simulate side effects - * from finalization by doing a bogus function call and resizing the - * stacks. + * This is mainly useful in emergency GC: if the string table load + * factor is really low for some reason, we can shrink the string + * table to a smaller size and free some memory in the process. + * Only execute in emergency GC. String table has internal flags + * to protect against recursive resizing if this mark-and-sweep pass + * was triggered by a string table resize. */ - if (flags & DUK_MS_FLAG_NO_FINALIZERS) { - DUK_D(DUK_DPRINT("skip mark-and-sweep torture finalizer, DUK_MS_FLAG_NO_FINALIZERS is set")); - } else if (!(thr->valstack != NULL && thr->callstack != NULL && thr->catchstack != NULL)) { - DUK_D(DUK_DPRINT("skip mark-and-sweep torture finalizer, thread not yet viable")); - } else { - DUK_D(DUK_DPRINT("run mark-and-sweep torture finalizer")); - duk__markandsweep_torture_finalizer(thr); - } -#endif /* DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE */ - if (flags & DUK_MS_FLAG_NO_FINALIZERS) { - DUK_D(DUK_DPRINT("finalizer run skipped because DUK_MS_FLAG_NO_FINALIZERS is set")); - } else { - duk__run_object_finalizers(heap, flags); + if (flags & DUK_MS_FLAG_EMERGENCY) { + DUK_D(DUK_DPRINT("stringtable resize check in emergency gc")); + duk_heap_strtable_force_resize(heap); } -#endif /* DUK_USE_FINALIZER_SUPPORT */ /* * Finish */ - DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap); + DUK_ASSERT(heap->ms_prevent_count == 1); + heap->ms_prevent_count = 0; + DUK_ASSERT(heap->ms_running == 1); + heap->ms_running = 0; /* * Assertions after */ #if defined(DUK_USE_ASSERTIONS) - DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)); + DUK_ASSERT(heap->ms_prevent_count == 0); DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)); - DUK_ASSERT(heap->mark_and_sweep_recursion_depth == 0); + DUK_ASSERT(heap->ms_recursion_depth == 0); duk__assert_heaphdr_flags(heap); #if defined(DUK_USE_REFERENCE_COUNTING) - /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount + /* Note: heap->refzero_free_running may be true; a refcount * finalizer may trigger a mark-and-sweep. */ duk__assert_valid_refcounts(heap); @@ -1421,15 +1190,47 @@ #if defined(DUK_USE_VOLUNTARY_GC) tmp = (count_keep_obj + count_keep_str) / 256; - heap->mark_and_sweep_trigger_counter = (duk_int_t) ( + heap->ms_trigger_counter = (duk_int_t) ( (tmp * DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT) + DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD); DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, trigger reset to %ld", - (long) count_keep_obj, (long) count_keep_str, (long) heap->mark_and_sweep_trigger_counter)); + (long) count_keep_obj, (long) count_keep_str, (long) heap->ms_trigger_counter)); #else DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, no voluntary trigger", (long) count_keep_obj, (long) count_keep_str)); #endif - return 0; /* OK */ + /* + * Finalize objects in the finalization work list. Finalized + * objects are queued back to heap_allocated with FINALIZED set. + * + * Since finalizers may cause arbitrary side effects, they are + * prevented e.g. during string table and object property allocation + * resizing using heap->pf_prevent_count. In this case the objects + * remain in the finalization work list after mark-and-sweep exits + * and they may be finalized on the next pass or any DECREF checking + * for finalize_list. + * + * As of Duktape 2.1 finalization happens outside mark-and-sweep + * protection. Mark-and-sweep is allowed while the finalize_list + * is being processed, but no rescue decisions are done while the + * process is on-going. This avoids incorrect rescue decisions + * if an object is considered reachable (and thus rescued) because + * of a reference via finalize_list (which is considered a reachability + * root). When finalize_list is being processed, reachable objects + * with FINALIZED set will just keep their FINALIZED flag for later + * mark-and-sweep processing. + * + * This could also be handled (a bit better) by having a more refined + * notion of reachability for rescue/free decisions. + * + * XXX: avoid finalizer execution when doing emergency GC? + */ + +#if defined(DUK_USE_FINALIZER_SUPPORT) + /* Attempt to process finalize_list, pf_prevent_count check + * is inside the target. + */ + duk_heap_process_finalize_list(heap); +#endif /* DUK_USE_FINALIZER_SUPPORT */ } diff -Nru duktape-2.0.0/src-separate/duk_heap_memory.c duktape-2.1.1/src-separate/duk_heap_memory.c --- duktape-2.0.0/src-separate/duk_heap_memory.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_heap_memory.c 2017-07-28 22:05:08.000000000 +0000 @@ -5,34 +5,28 @@ #include "duk_internal.h" /* - * Helpers - * - * The fast path checks are done within a macro to ensure "inlining" - * while the slow path actions use a helper (which won't typically be - * inlined in size optimized builds). + * Voluntary GC check */ #if defined(DUK_USE_VOLUNTARY_GC) -#define DUK__VOLUNTARY_PERIODIC_GC(heap) do { \ - (heap)->mark_and_sweep_trigger_counter--; \ - if ((heap)->mark_and_sweep_trigger_counter <= 0) { \ - duk__run_voluntary_gc(heap); \ - } \ - } while (0) - -DUK_LOCAL void duk__run_voluntary_gc(duk_heap *heap) { - if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { - DUK_DD(DUK_DDPRINT("mark-and-sweep in progress -> skip voluntary mark-and-sweep now")); - } else { - duk_small_uint_t flags; - duk_bool_t rc; +DUK_LOCAL DUK_INLINE void duk__check_voluntary_gc(duk_heap *heap) { + if (DUK_UNLIKELY(--(heap)->ms_trigger_counter < 0)) { +#if defined(DUK_USE_DEBUG) + if (heap->ms_prevent_count == 0) { + DUK_D(DUK_DPRINT("triggering voluntary mark-and-sweep")); + } else { + DUK_DD(DUK_DDPRINT("gc blocked -> skip voluntary mark-and-sweep now")); + } +#endif - DUK_D(DUK_DPRINT("triggering voluntary mark-and-sweep")); - flags = 0; - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); + /* Prevention checks in the call target handle cases where + * voluntary GC is not allowed. The voluntary GC trigger + * counter is only rewritten if mark-and-sweep actually runs. + */ + duk_heap_mark_and_sweep(heap, DUK_MS_FLAG_VOLUNTARY /*flags*/); } } +#define DUK__VOLUNTARY_PERIODIC_GC(heap) do { duk__check_voluntary_gc((heap)); } while (0) #else #define DUK__VOLUNTARY_PERIODIC_GC(heap) /* no voluntary gc */ #endif /* DUK_USE_VOLUNTARY_GC */ @@ -43,7 +37,6 @@ DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) { void *res; - duk_bool_t rc; duk_small_int_t i; DUK_ASSERT(heap != NULL); @@ -61,7 +54,7 @@ #if defined(DUK_USE_GC_TORTURE) /* simulate alloc failure on every alloc (except when mark-and-sweep is running) */ - if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + if (heap->ms_prevent_count == 0) { DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first alloc attempt fails")); res = NULL; DUK_UNREF(res); @@ -69,7 +62,7 @@ } #endif res = heap->alloc_func(heap->heap_udata, size); - if (res || size == 0) { + if (DUK_LIKELY(res || size == 0)) { /* for zero size allocations NULL is allowed */ return res; } @@ -79,16 +72,22 @@ DUK_D(DUK_DPRINT("first alloc attempt failed, attempt to gc and retry")); +#if 0 /* * Avoid a GC if GC is already running. This can happen at a late * stage in a GC when we try to e.g. resize the stringtable * or compact objects. + * + * NOTE: explicit handling isn't actually be needed: if the GC is + * not allowed, duk_heap_mark_and_sweep() will reject it for every + * attempt in the loop below, resulting in a NULL same as here. */ - if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + 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 @@ -104,8 +103,7 @@ flags |= DUK_MS_FLAG_EMERGENCY; } - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); + duk_heap_mark_and_sweep(heap, flags); res = heap->alloc_func(heap->heap_udata, size); if (res) { @@ -126,20 +124,43 @@ DUK_ASSERT_DISABLE(size >= 0); res = DUK_ALLOC(heap, size); - if (res) { + if (DUK_LIKELY(res != NULL)) { /* assume memset with zero size is OK */ DUK_MEMZERO(res, size); } return res; } +DUK_INTERNAL void *duk_heap_mem_alloc_checked(duk_hthread *thr, duk_size_t size) { + void *res; + + DUK_ASSERT(thr != NULL); + res = duk_heap_mem_alloc(thr->heap, size); + if (DUK_LIKELY(res != NULL || size == 0)) { + return res; + } + DUK_ERROR_ALLOC_FAILED(thr); + return NULL; +} + +DUK_INTERNAL void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, duk_size_t size) { + void *res; + + DUK_ASSERT(thr != NULL); + res = duk_heap_mem_alloc_zeroed(thr->heap, size); + if (DUK_LIKELY(res != NULL || size == 0)) { + return res; + } + DUK_ERROR_ALLOC_FAILED(thr); + return NULL; +} + /* * Reallocate memory with garbage collection */ DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize) { void *res; - duk_bool_t rc; duk_small_int_t i; DUK_ASSERT(heap != NULL); @@ -158,7 +179,7 @@ #if defined(DUK_USE_GC_TORTURE) /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */ - if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + if (heap->ms_prevent_count == 0) { DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first realloc attempt fails")); res = NULL; DUK_UNREF(res); @@ -166,7 +187,7 @@ } #endif res = heap->realloc_func(heap->heap_udata, ptr, newsize); - if (res || newsize == 0) { + if (DUK_LIKELY(res || newsize == 0)) { /* for zero size allocations NULL is allowed */ return res; } @@ -176,14 +197,16 @@ 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 (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + 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 @@ -199,8 +222,7 @@ flags |= DUK_MS_FLAG_EMERGENCY; } - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); + duk_heap_mark_and_sweep(heap, flags); res = heap->realloc_func(heap->heap_udata, ptr, newsize); if (res || newsize == 0) { @@ -222,7 +244,6 @@ DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize) { void *res; - duk_bool_t rc; duk_small_int_t i; DUK_ASSERT(heap != NULL); @@ -240,7 +261,7 @@ #if defined(DUK_USE_GC_TORTURE) /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */ - if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + 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); @@ -248,7 +269,7 @@ } #endif res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize); - if (res || newsize == 0) { + if (DUK_LIKELY(res || newsize == 0)) { /* for zero size allocations NULL is allowed */ return res; } @@ -258,14 +279,16 @@ 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 (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + 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 @@ -289,8 +312,7 @@ flags |= DUK_MS_FLAG_EMERGENCY; } - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); + duk_heap_mark_and_sweep(heap, flags); #if defined(DUK_USE_ASSERTIONS) ptr_post = cb(heap, ud); if (ptr_pre != ptr_post) { @@ -329,12 +351,8 @@ */ heap->free_func(heap->heap_udata, ptr); - /* Count free operations toward triggering a GC but never actually trigger - * a GC from a free. Otherwise code which frees internal structures would - * need to put in NULLs at every turn to ensure the object is always in - * consistent state for a mark-and-sweep. + /* 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. */ -#if defined(DUK_USE_VOLUNTARY_GC) - heap->mark_and_sweep_trigger_counter--; -#endif } diff -Nru duktape-2.0.0/src-separate/duk_heap_misc.c duktape-2.1.1/src-separate/duk_heap_misc.c --- duktape-2.0.0/src-separate/duk_heap_misc.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_heap_misc.c 2017-07-28 22:05:08.000000000 +0000 @@ -4,44 +4,146 @@ #include "duk_internal.h" -#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING) -/* arbitrary remove only works with double linked heap, and is only required by - * reference counting so far. - */ -DUK_INTERNAL void duk_heap_remove_any_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) { +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_ASSERT_HEAPHDR_LINKS(heap, hdr); + DUK_ASSERT_HEAPHDR_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); - if (DUK_HEAPHDR_GET_PREV(heap, hdr)) { - DUK_HEAPHDR_SET_NEXT(heap, DUK_HEAPHDR_GET_PREV(heap, hdr), DUK_HEAPHDR_GET_NEXT(heap, hdr)); + /* 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 { - heap->heap_allocated = DUK_HEAPHDR_GET_NEXT(heap, hdr); + DUK_ASSERT(heap->heap_allocated == hdr); + heap->heap_allocated = next; } - if (DUK_HEAPHDR_GET_NEXT(heap, hdr)) { - DUK_HEAPHDR_SET_PREV(heap, DUK_HEAPHDR_GET_NEXT(heap, hdr), DUK_HEAPHDR_GET_PREV(heap, hdr)); + if (next != NULL) { + DUK_HEAPHDR_SET_PREV(heap, next, prev); } else { ; } - - /* The prev/next pointers of the removed duk_heaphdr are left as garbage. - * It's up to the caller to ensure they're written before inserting the - * object back. - */ } -#endif +#endif /* DUK_USE_REFERENCE_COUNTING */ -DUK_INTERNAL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) { - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING); +#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) - if (heap->heap_allocated) { - DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, heap->heap_allocated) == NULL); - DUK_HEAPHDR_SET_PREV(heap, heap->heap_allocated, hdr); - } 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, heap->heap_allocated); - heap->heap_allocated = hdr; + DUK_HEAPHDR_SET_NEXT(heap, hdr, root); + DUK_ASSERT_HEAPHDR_LINKS(heap, hdr); + DUK_ASSERT_HEAPHDR_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) { diff -Nru duktape-2.0.0/src-separate/duk_heap_refcount.c duktape-2.1.1/src-separate/duk_heap_refcount.c --- duktape-2.0.0/src-separate/duk_heap_refcount.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_heap_refcount.c 2017-07-28 22:05:08.000000000 +0000 @@ -1,5 +1,9 @@ /* * 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 "duk_internal.h" @@ -11,36 +15,6 @@ #endif /* - * Misc - */ - -DUK_LOCAL void duk__queue_refzero(duk_heap *heap, duk_heaphdr *hdr) { - /* tail insert: don't disturb head in case refzero is running */ - - if (heap->refzero_list != NULL) { - duk_heaphdr *hdr_prev; - - hdr_prev = heap->refzero_list_tail; - DUK_ASSERT(hdr_prev != NULL); - DUK_ASSERT(DUK_HEAPHDR_GET_NEXT(heap, hdr_prev) == NULL); - - DUK_HEAPHDR_SET_NEXT(heap, hdr, NULL); - DUK_HEAPHDR_SET_PREV(heap, hdr, hdr_prev); - DUK_HEAPHDR_SET_NEXT(heap, hdr_prev, hdr); - DUK_ASSERT_HEAPHDR_LINKS(heap, hdr); - DUK_ASSERT_HEAPHDR_LINKS(heap, hdr_prev); - heap->refzero_list_tail = hdr; - } else { - DUK_ASSERT(heap->refzero_list_tail == NULL); - DUK_HEAPHDR_SET_NEXT(heap, hdr, NULL); - DUK_HEAPHDR_SET_PREV(heap, hdr, NULL); - DUK_ASSERT_HEAPHDR_LINKS(heap, hdr); - heap->refzero_list = hdr; - heap->refzero_list_tail = hdr; - } -} - -/* * Heap object refcount finalization. * * When an object is about to be freed, all other objects it refers to must @@ -48,41 +22,47 @@ * allocations (mark-and-sweep shares these helpers), it just manipulates * the refcounts. * - * Note that any of the decref's may cause a refcount to drop to zero, BUT - * it will not be processed inline. If refcount finalization is triggered - * by refzero processing, the objects will be just queued to the refzero - * list and processed later which eliminates C recursion. If refcount - * finalization is triggered by mark-and-sweep, any refzero situations are - * ignored because mark-and-sweep will deal with them. NORZ variants can - * be used here in both cases. + * 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__refcount_finalize_hobject(duk_hthread *thr, duk_hobject *h) { +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); - /* XXX: better to get base and walk forwards? */ + thr = heap->heap_thread; + DUK_ASSERT(thr != NULL); - p_key = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, h); - p_val = DUK_HOBJECT_E_GET_VALUE_BASE(thr->heap, h); - p_flag = DUK_HOBJECT_E_GET_FLAGS_BASE(thr->heap, h); + 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 (!key) { + if (DUK_UNLIKELY(key == NULL)) { continue; } DUK_HSTRING_DECREF_NORZ(thr, key); - if (p_flag[n] & DUK_PROPDESC_FLAG_ACCESSOR) { + 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)); @@ -97,7 +77,7 @@ } } - p_tv = DUK_HOBJECT_A_GET_BASE(thr->heap, h); + p_tv = DUK_HOBJECT_A_GET_BASE(heap, h); n = DUK_HOBJECT_GET_ASIZE(h); while (n-- > 0) { duk_tval *tv_val; @@ -105,39 +85,49 @@ DUK_TVAL_DECREF_NORZ(thr, tv_val); } - /* hash part is a 'weak reference' and does not contribute */ + /* Hash part is a 'weak reference' and doesn't contribute to refcounts. */ - { - duk_hobject *h_proto; - h_proto = (duk_hobject *) DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h); - DUK_ASSERT(h_proto == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_proto)); - DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_proto); + 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)); - /* XXX: rearrange bits to allow a switch case to be used here? */ - /* XXX: add a fast path for objects (and arrays)? */ + /* Slow path: special object, start bit checks from most likely. */ - /* DUK_HOBJECT_IS_ARRAY(h): needs no special handling now as there are - * no extra fields in need of decref. - */ if (DUK_HOBJECT_IS_COMPFUNC(h)) { duk_hcompfunc *f = (duk_hcompfunc *) h; duk_tval *tv, *tv_end; duk_hobject **funcs, **funcs_end; - if (DUK_HCOMPFUNC_GET_DATA(thr->heap, f) != NULL) { - tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, f); - tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, 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(thr->heap, f); - funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, f); + 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++; @@ -147,13 +137,19 @@ DUK_D(DUK_DPRINT("duk_hcompfunc 'data' is NULL, skipping decref")); } - DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_heaphdr *) DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f)); - DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_heaphdr *) DUK_HCOMPFUNC_GET_VARENV(thr->heap, f)); - DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(thr->heap, f)); - } else if (DUK_HOBJECT_IS_NATFUNC(h)) { - duk_hnatfunc *f = (duk_hnatfunc *) h; - DUK_UNREF(f); - /* nothing to finalize */ + 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_ASSERT_HDECENV_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_ASSERT_HOBJENV_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; @@ -191,264 +187,284 @@ } 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(duk_hthread *thr, duk_heaphdr *hdr) { - DUK_ASSERT(hdr); +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_GET_TYPE(hdr) == DUK_HTYPE_OBJECT) { - duk__refcount_finalize_hobject(thr, (duk_hobject *) hdr); + 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 */ } -#if defined(DUK_USE_FINALIZER_SUPPORT) -#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE) -DUK_LOCAL duk_ret_t duk__refcount_fake_finalizer(duk_context *ctx) { - DUK_UNREF(ctx); - DUK_D(DUK_DPRINT("fake refcount torture finalizer executed")); -#if 0 - DUK_DD(DUK_DDPRINT("fake torture finalizer for: %!T", duk_get_tval(ctx, 0))); -#endif - /* Require a lot of stack to force a value stack grow/shrink. */ - duk_require_stack(ctx, 100000); - - /* XXX: do something to force a callstack grow/shrink, perhaps - * just a manual forced resize? - */ - return 0; -} - -DUK_LOCAL void duk__refcount_run_torture_finalizer(duk_hthread *thr, duk_hobject *obj) { - duk_context *ctx; - duk_int_t rc; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(obj != NULL); - ctx = (duk_context *) thr; - - /* Avoid fake finalization for the duk__refcount_fake_finalizer function - * itself, otherwise we're in infinite recursion. - */ - if (DUK_HOBJECT_HAS_NATFUNC(obj)) { - if (((duk_hnatfunc *) obj)->func == duk__refcount_fake_finalizer) { - DUK_DD(DUK_DDPRINT("avoid fake torture finalizer for duk__refcount_fake_finalizer itself")); - return; - } - } - /* Avoid fake finalization when callstack limit has been reached. - * Otherwise a callstack limit error will be created, then refzero'ed, - * and we're in an infinite loop. - */ - if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit || - thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) { - DUK_D(DUK_DPRINT("call recursion depth reached, avoid fake torture finalizer")); - return; - } - - /* Run fake finalizer. Avoid creating new refzero queue entries - * so that we are not forced into a forever loop. - */ - duk_push_c_function(ctx, duk__refcount_fake_finalizer, 1 /*nargs*/); - duk_push_hobject(ctx, obj); - rc = duk_pcall(ctx, 1); - DUK_UNREF(rc); /* ignored */ - duk_pop(ctx); -} -#endif /* DUK_USE_REFZERO_FINALIZER_TORTURE */ -#endif /* DUK_USE_FINALIZER_SUPPORT */ - /* - * Refcount memory freeing loop. + * 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. * - * Frees objects in the refzero_pending list until the list becomes - * empty. When an object is freed, its references get decref'd and - * may cause further objects to be queued for freeing. + * - 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. + * 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_INTERNAL void duk_refzero_free_pending(duk_hthread *thr) { - duk_heaphdr *h1, *h2; - duk_heap *heap; +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(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - heap = thr->heap; DUK_ASSERT(heap != NULL); - /* - * Detect recursive invocation - */ + 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. */ - if (DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap)) { - DUK_DDD(DUK_DDDPRINT("refzero free running, skip run")); - return; - } + do { + duk_heaphdr *prev; - /* - * Churn refzero_list until empty - */ + DUK_DDD(DUK_DDDPRINT("refzero processing %p: %!O", (void *) curr, (duk_heaphdr *) curr)); - DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap); - while (heap->refzero_list) { - duk_hobject *obj; -#if defined(DUK_USE_FINALIZER_SUPPORT) - duk_bool_t rescued = 0; -#endif /* DUK_USE_FINALIZER_SUPPORT */ +#if defined(DUK_USE_DEBUG) + count++; +#endif - /* - * Pick an object from the head (don't remove yet). + 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); - h1 = heap->refzero_list; - obj = (duk_hobject *) h1; - DUK_DD(DUK_DDPRINT("refzero processing %p: %!O", (void *) h1, (duk_heaphdr *) h1)); - DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, h1) == NULL); - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(h1) == DUK_HTYPE_OBJECT); /* currently, always the case */ + 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. */ -#if defined(DUK_USE_FINALIZER_SUPPORT) -#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE) - /* Torture option to shake out finalizer side effect issues: - * make a bogus function call for every finalizable object, - * essentially simulating the case where everything has a - * finalizer. - */ - DUK_DD(DUK_DDPRINT("refzero torture enabled, fake finalizer")); - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h1) == 0); - DUK_HEAPHDR_PREINC_REFCOUNT(h1); /* bump refcount to prevent refzero during finalizer processing */ - duk__refcount_run_torture_finalizer(thr, obj); /* must never longjmp */ - DUK_HEAPHDR_PREDEC_REFCOUNT(h1); /* remove artificial bump */ - DUK_ASSERT_DISABLE(h1->h_refcount >= 0); /* refcount is unsigned, so always true */ -#endif /* DUK_USE_REFZERO_FINALIZER_TORTURE */ -#endif /* DUK_USE_FINALIZER_SUPPORT */ + duk_free_hobject(heap, (duk_hobject *) curr); /* Invalidates 'curr'. */ - /* - * Finalizer check. - * - * Note: running a finalizer may have arbitrary side effects, e.g. - * queue more objects on refzero_list (tail), or even trigger a - * mark-and-sweep. - * - * Note: quick reject check should match vast majority of - * objects and must be safe (not throw any errors, ever). - * - * An object may have FINALIZED here if it was finalized by mark-and-sweep - * on a previous run and refcount then decreased to zero. We won't run the - * finalizer again here. - * - * A finalizer is looked up from the object and up its prototype chain - * (which allows inherited finalizers). - */ + curr = prev; + } while (curr != NULL); -#if defined(DUK_USE_FINALIZER_SUPPORT) - if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) { - DUK_DDD(DUK_DDDPRINT("object has a finalizer, run it")); + heap->refzero_list = NULL; - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h1) == 0); - DUK_HEAPHDR_PREINC_REFCOUNT(h1); /* bump refcount to prevent refzero during finalizer processing */ + 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); - duk_hobject_run_finalizer(thr, obj); /* must never longjmp */ - DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1)); /* duk_hobject_run_finalizer() sets */ + hdr = (duk_heaphdr *) obj; - DUK_HEAPHDR_PREDEC_REFCOUNT(h1); /* remove artificial bump */ - DUK_ASSERT_DISABLE(h1->h_refcount >= 0); /* refcount is unsigned, so always true */ - - if (DUK_HEAPHDR_GET_REFCOUNT(h1) != 0) { - DUK_DDD(DUK_DDDPRINT("-> object refcount after finalization non-zero, object will be rescued")); - rescued = 1; - } else { - DUK_DDD(DUK_DDDPRINT("-> object refcount still zero after finalization, object will be freed")); + /* 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))) { + /* 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 */ - /* Refzero head is still the same. This is the case even if finalizer - * inserted more refzero objects; they are inserted to the tail. - */ - DUK_ASSERT(h1 == heap->refzero_list); + /* No need to finalize, free object via refzero_list. */ + + root = heap->refzero_list; - /* - * Remove the object from the refzero list. This cannot be done - * before a possible finalizer has been executed; the finalizer - * may trigger a mark-and-sweep, and mark-and-sweep must be able - * to traverse a complete 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); - h2 = DUK_HEAPHDR_GET_NEXT(heap, h1); - if (h2) { - DUK_HEAPHDR_SET_PREV(heap, h2, NULL); /* not strictly necessary */ - heap->refzero_list = h2; - } else { - heap->refzero_list = NULL; - heap->refzero_list_tail = 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); - /* - * Rescue or free. + /* 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) - if (rescued) { - /* yes -> move back to heap allocated */ - DUK_DD(DUK_DDPRINT("object rescued during refcount finalization: %p", (void *) h1)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(h1)); - DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1)); - DUK_HEAPHDR_CLEAR_FINALIZED(h1); - h2 = heap->heap_allocated; - DUK_HEAPHDR_SET_PREV(heap, h1, NULL); - if (h2) { - DUK_HEAPHDR_SET_PREV(heap, h2, h1); - } - DUK_HEAPHDR_SET_NEXT(heap, h1, h2); - DUK_ASSERT_HEAPHDR_LINKS(heap, h1); - DUK_ASSERT_HEAPHDR_LINKS(heap, h2); - heap->heap_allocated = h1; - } else -#endif /* DUK_USE_FINALIZER_SUPPORT */ - { - /* no -> decref members, then free */ - duk__refcount_finalize_hobject(thr, obj); - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(h1) == DUK_HTYPE_OBJECT); /* currently, always the case */ - duk_free_hobject(heap, (duk_hobject *) h1); - } +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. */ - count++; + if (DUK_UNLIKELY(thr->heap->finalize_list != NULL)) { + duk_heap_process_finalize_list(thr->heap); } - DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap); - - DUK_DDD(DUK_DDDPRINT("refzero processed %ld objects", (long) count)); +} - /* - * Once the whole refzero cascade has been freed, check for - * a voluntary mark-and-sweep. - */ +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 defined(DUK_USE_VOLUNTARY_GC) - /* 'count' is more or less comparable to normal trigger counter update - * which happens in memory block (re)allocation. - */ - heap->mark_and_sweep_trigger_counter -= count; - if (heap->mark_and_sweep_trigger_counter <= 0) { - duk_bool_t rc; - duk_small_uint_t flags = 0; /* not emergency */ - DUK_D(DUK_DPRINT("refcount triggering mark-and-sweep")); - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); - DUK_D(DUK_DPRINT("refcount triggered mark-and-sweep => rc %ld", (long) rc)); + if (DUK_UNLIKELY(thr->heap->finalize_list != NULL)) { + duk_heap_process_finalize_list(thr->heap); } -#endif /* DUK_USE_VOLUNTARY_GC */ +} +#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. + * 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, @@ -461,46 +477,67 @@ * mark-and-sweep also calls finalizers which would use the ordinary decref * macros anyway. * - * The DUK__RZ_SUPPRESS_CHECK() must be enabled also when mark-and-sweep - * support has been disabled: the flag is also used in heap destruction when - * running finalizers for remaining objects, and the flag prevents objects - * from being moved around in heap linked lists. + * 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. */ -/* The suppress condition is important to performance. The flags being tested - * are in the same duk_heap field so a single TEST instruction (on x86) tests - * for them. - */ +#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); \ + /* When mark-and-sweep runs, the 'thr' argument always matches heap_thread. \ + * This could be used to e.g. suppress check against 'thr' directly (and \ + * knowing it would be heap_thread); not really used now. \ + */ \ + DUK_ASSERT(thr->heap->ms_running == 0 || 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_COND() \ - (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) || DUK_HEAP_IS_PAUSED(heap)) +#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_COND() \ - (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) -#endif +#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 when mark-and-sweep running, object: %p", (void *) h)); \ + 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_heap_strcache_string_remove(thr->heap, (duk_hstring *) h); \ - duk_heap_string_remove(heap, (duk_hstring *) h); \ - duk_free_hstring(heap, (duk_hstring *) h); \ + duk__refcount_refzero_hstring(heap, (duk_hstring *) h); \ } while (0) #define DUK__RZ_BUFFER() do { \ - duk_heap_remove_any_from_heap_allocated(heap, (duk_heaphdr *) h); \ - duk_free_hbuffer(heap, (duk_hbuffer *) h); \ + duk__refcount_refzero_hbuffer(heap, (duk_hbuffer *) h); \ } while (0) #define DUK__RZ_OBJECT() do { \ - duk_heap_remove_any_from_heap_allocated(heap, (duk_heaphdr *) h); \ - duk__queue_refzero(heap, (duk_heaphdr *) h); \ - if (!skip_free_pending) { \ - duk_refzero_free_pending(thr); \ - } \ + 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 @@ -570,42 +607,39 @@ DUK__RZ_OBJECT(); break; - case DUK_HTYPE_BUFFER: + 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; - - default: - DUK_D(DUK_DPRINT("invalid heap type in decref: %ld", (long) DUK_HEAPHDR_GET_TYPE(h))); - DUK_UNREACHABLE(); } } -DUK_INTERNAL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h) { +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 void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h) { +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 void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h) { +DUK_INTERNAL DUK_NOINLINE void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h) { duk__hstring_refzero_helper(thr, h); } -DUK_INTERNAL void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h) { +DUK_INTERNAL DUK_NOINLINE void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h) { duk__hbuffer_refzero_helper(thr, h); } -DUK_INTERNAL void duk_hobject_refzero(duk_hthread *thr, duk_hobject *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 void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h) { +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*/); } @@ -619,6 +653,7 @@ 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. */ } } @@ -657,7 +692,7 @@ } duk_heaphdr_refzero_norz(thr, h); #else - duk_heaphdr_decref(thr, h); + duk_heaphdr_decref_norz(thr, h); #endif } } @@ -671,6 +706,13 @@ 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; \ @@ -680,6 +722,10 @@ } \ } 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; \ @@ -696,13 +742,18 @@ DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0); - DUK_HEAPHDR_PREINC_REFCOUNT(h); + 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(); diff -Nru duktape-2.0.0/src-separate/duk_heap_stringcache.c duktape-2.1.1/src-separate/duk_heap_stringcache.c --- duktape-2.0.0/src-separate/duk_heap_stringcache.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_heap_stringcache.c 2017-07-28 22:05:08.000000000 +0000 @@ -84,6 +84,10 @@ * * 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) { @@ -93,20 +97,27 @@ duk_small_int_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; - if (char_offset > DUK_HSTRING_GET_CHARLEN(h)) { - goto error; - } - /* * For ASCII strings, the answer is simple. */ - if (DUK_HSTRING_IS_ASCII(h)) { - /* clen == blen -> pure ascii */ + 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; } @@ -128,7 +139,7 @@ heap = thr->heap; sce = NULL; - use_cache = (DUK_HSTRING_GET_CHARLEN(h) > DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT); + use_cache = (char_length > DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT); if (use_cache) { #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) @@ -159,7 +170,7 @@ DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h) >= char_offset); dist_start = char_offset; - dist_end = DUK_HSTRING_GET_CHARLEN(h) - 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); @@ -232,12 +243,12 @@ scan_done: - if (!p_found) { + 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 error; + goto scan_error; } DUK_ASSERT(p_found >= p_start); @@ -292,7 +303,7 @@ return byte_offset; - error: + scan_error: DUK_ERROR_INTERNAL(thr); return 0; } diff -Nru duktape-2.0.0/src-separate/duk_heap_stringtable.c duktape-2.1.1/src-separate/duk_heap_stringtable.c --- duktape-2.0.0/src-separate/duk_heap_stringtable.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_heap_stringtable.c 2017-07-28 22:05:08.000000000 +0000 @@ -1,57 +1,169 @@ /* - * Heap stringtable handling, string interning. + * Heap string table handling, string interning. */ #include "duk_internal.h" -#if defined(DUK_USE_STRTAB_PROBE) -#define DUK__HASH_INITIAL(hash,h_size) DUK_STRTAB_HASH_INITIAL((hash),(h_size)) -#define DUK__HASH_PROBE_STEP(hash) DUK_STRTAB_HASH_PROBE_STEP((hash)) -#define DUK__DELETED_MARKER(heap) DUK_STRTAB_DELETED_MARKER((heap)) +/* Resize checks not needed if minsize == maxsize, typical for low memory + * targets. + */ +#define DUK__STRTAB_RESIZE_CHECK +#if (DUK_USE_STRTAB_MINSIZE == DUK_USE_STRTAB_MAXSIZE) +#undef DUK__STRTAB_RESIZE_CHECK +#endif + +#if defined(DUK_USE_STRTAB_PTRCOMP) +#define DUK__HEAPPTR_ENC16(heap,ptr) DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (ptr)) +#define DUK__HEAPPTR_DEC16(heap,val) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (val)) +#define DUK__GET_STRTABLE(heap) ((heap)->strtable16) +#else +#define DUK__HEAPPTR_ENC16(heap,ptr) (ptr) +#define DUK__HEAPPTR_DEC16(heap,val) (val) +#define DUK__GET_STRTABLE(heap) ((heap)->strtable) #endif -#define DUK__PREVENT_MS_SIDE_EFFECTS(heap) do { \ - (heap)->mark_and_sweep_base_flags |= \ - DUK_MS_FLAG_NO_STRINGTABLE_RESIZE | /* avoid recursive string table call */ \ - DUK_MS_FLAG_NO_FINALIZERS | /* avoid pressure to add/remove strings, invalidation of call data argument, etc. */ \ - DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid array abandoning which interns strings */ \ - } while (0) +#define DUK__STRTAB_U32_MAX_STRLEN 10 /* 4'294'967'295 */ /* - * Create a hstring and insert into the heap. The created object - * is directly garbage collectable with reference count zero. + * Debug dump stringtable. + */ + +#if defined(DUK_USE_DEBUG) +DUK_INTERNAL void duk_heap_strtable_dump(duk_heap *heap) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *strtable; +#else + duk_hstring **strtable; +#endif + duk_uint32_t i; + duk_hstring *h; + duk_size_t count_total = 0; + duk_size_t count_chain; + duk_size_t count_chain_min = DUK_SIZE_MAX; + duk_size_t count_chain_max = 0; + duk_size_t count_len[8]; /* chain lengths from 0 to 7 */ + + if (heap == NULL) { + DUK_D(DUK_DPRINT("string table, heap=NULL")); + return; + } + + strtable = DUK__GET_STRTABLE(heap); + if (strtable == NULL) { + DUK_D(DUK_DPRINT("string table, strtab=NULL")); + return; + } + + DUK_MEMZERO((void *) count_len, sizeof(count_len)); + for (i = 0; i < heap->st_size; i++) { + h = DUK__HEAPPTR_DEC16(heap, strtable[i]); + count_chain = 0; + while (h != NULL) { + count_chain++; + h = h->hdr.h_next; + } + if (count_chain < sizeof(count_len) / sizeof(duk_size_t)) { + count_len[count_chain]++; + } + count_chain_max = (count_chain > count_chain_max ? count_chain : count_chain_max); + count_chain_min = (count_chain < count_chain_min ? count_chain : count_chain_min); + count_total += count_chain; + } + + DUK_D(DUK_DPRINT("string table, strtab=%p, count=%lu, chain min=%lu max=%lu avg=%lf: " + "counts: %lu %lu %lu %lu %lu %lu %lu %lu ...", + (void *) heap->strtable, (unsigned long) count_total, + (unsigned long) count_chain_min, (unsigned long) count_chain_max, + (double) count_total / (double) heap->st_size, + (unsigned long) count_len[0], (unsigned long) count_len[1], + (unsigned long) count_len[2], (unsigned long) count_len[3], + (unsigned long) count_len[4], (unsigned long) count_len[5], + (unsigned long) count_len[6], (unsigned long) count_len[7])); +} +#endif /* DUK_USE_DEBUG */ + +/* + * Assertion helper to ensure strtable is populated correctly. + */ + +#if defined(DUK_USE_ASSERTIONS) +DUK_LOCAL void duk__strtable_assert_checks(duk_heap *heap) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *strtable; +#else + duk_hstring **strtable; +#endif + duk_uint32_t i; + duk_hstring *h; + duk_size_t count = 0; + + DUK_ASSERT(heap != NULL); + + strtable = DUK__GET_STRTABLE(heap); + if (strtable != NULL) { + DUK_ASSERT(heap->st_size != 0); + DUK_ASSERT(heap->st_mask == heap->st_size - 1); + + for (i = 0; i < heap->st_size; i++) { + h = DUK__HEAPPTR_DEC16(heap, strtable[i]); + while (h != NULL) { + DUK_ASSERT((DUK_HSTRING_GET_HASH(h) & heap->st_mask) == i); + count++; + h = h->hdr.h_next; + } + } + } else { + DUK_ASSERT(heap->st_size == 0); + DUK_ASSERT(heap->st_mask == 0); + } + +#if defined(DUK__STRTAB_RESIZE_CHECK) + DUK_ASSERT(count == (duk_size_t) heap->st_count); +#endif +} +#endif /* DUK_USE_ASSERTIONS */ + +/* + * Allocate and initialize a duk_hstring. + * + * Returns a NULL if allocation or initialization fails for some reason. * - * The caller must place the interned string into the stringtable - * immediately (without chance of a longjmp); otherwise the string - * is lost. + * The string won't be inserted into the string table and isn't tracked in + * any way (link pointers will be NULL). The caller must place the string + * into the string table without any risk of a longjmp, otherwise the string + * is leaked. */ -DUK_LOCAL -duk_hstring *duk__alloc_init_hstring(duk_heap *heap, - const duk_uint8_t *str, - duk_uint32_t blen, - duk_uint32_t strhash, - const duk_uint8_t *extdata) { - duk_hstring *res = NULL; - duk_uint8_t *data; - duk_size_t alloc_size; +DUK_LOCAL duk_hstring *duk__strtable_alloc_hstring(duk_heap *heap, + const duk_uint8_t *str, + duk_uint32_t blen, + duk_uint32_t strhash, + const duk_uint8_t *extdata) { + duk_hstring *res; + const duk_uint8_t *data; #if !defined(DUK_USE_HSTRING_ARRIDX) duk_uarridx_t dummy; #endif - duk_uint32_t clen; + + DUK_ASSERT(heap != NULL); + DUK_UNREF(extdata); #if defined(DUK_USE_STRLEN16) /* If blen <= 0xffffUL, clen is also guaranteed to be <= 0xffffUL. */ if (blen > 0xffffUL) { DUK_D(DUK_DPRINT("16-bit string blen/clen active and blen over 16 bits, reject intern")); - return NULL; + goto alloc_error; } #endif + /* XXX: Memzeroing the allocated structure is not really necessary + * because we could just initialize all fields explicitly (almost + * all fields are initialized explicitly anyway). + */ +#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) if (extdata) { - alloc_size = (duk_size_t) sizeof(duk_hstring_external); - res = (duk_hstring *) DUK_ALLOC(heap, alloc_size); - if (!res) { + res = (duk_hstring *) DUK_ALLOC(heap, sizeof(duk_hstring_external)); + if (DUK_UNLIKELY(res == NULL)) { goto alloc_error; } DUK_MEMZERO(res, sizeof(duk_hstring_external)); @@ -60,12 +172,18 @@ #endif DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, DUK_HSTRING_FLAG_EXTDATA); + DUK_ASSERT(extdata[blen] == 0); /* Application responsibility. */ + data = extdata; ((duk_hstring_external *) res)->extdata = extdata; - } else { + } else +#endif /* DUK_USE_HSTRING_EXTDATA && DUK_USE_EXTSTR_INTERN_CHECK */ + { + duk_uint8_t *data_tmp; + /* NUL terminate for convenient C access */ - alloc_size = (duk_size_t) (sizeof(duk_hstring) + blen + 1); - res = (duk_hstring *) DUK_ALLOC(heap, alloc_size); - if (!res) { + DUK_ASSERT(sizeof(duk_hstring) + blen + 1 > blen); /* No wrap, limits ensure. */ + res = (duk_hstring *) DUK_ALLOC(heap, sizeof(duk_hstring) + blen + 1); + if (DUK_UNLIKELY(res == NULL)) { goto alloc_error; } DUK_MEMZERO(res, sizeof(duk_hstring)); @@ -74,1081 +192,778 @@ #endif DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, 0); - data = (duk_uint8_t *) (res + 1); - DUK_MEMCPY(data, str, blen); - data[blen] = (duk_uint8_t) 0; + data_tmp = (duk_uint8_t *) (res + 1); + DUK_MEMCPY(data_tmp, str, blen); + data_tmp[blen] = (duk_uint8_t) 0; + data = (const duk_uint8_t *) data_tmp; } + DUK_HSTRING_SET_BYTELEN(res, blen); + DUK_HSTRING_SET_HASH(res, strhash); + DUK_ASSERT(!DUK_HSTRING_HAS_ARRIDX(res)); #if defined(DUK_USE_HSTRING_ARRIDX) - if (duk_js_to_arrayindex_raw_string(str, blen, &res->arridx)) { + res->arridx = duk_js_to_arrayindex_string(data, blen); + if (res->arridx != DUK_HSTRING_NO_ARRAY_INDEX) { #else - if (duk_js_to_arrayindex_raw_string(str, blen, &dummy)) { + dummy = duk_js_to_arrayindex_string(data, blen); + if (dummy != DUK_HSTRING_NO_ARRAY_INDEX) { #endif + /* Array index strings cannot be symbol strings, + * and they're always pure ASCII so blen == clen. + */ DUK_HSTRING_SET_ARRIDX(res); - } - - /* All strings beginning with specific (invalid UTF-8) byte prefixes - * are treated as symbols. - */ - DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(res)); - DUK_ASSERT(!DUK_HSTRING_HAS_HIDDEN(res)); - if (blen > 0) { - if (str[0] == 0xffU) { - DUK_HSTRING_SET_SYMBOL(res); - DUK_HSTRING_SET_HIDDEN(res); - } else if ((str[0] & 0xc0U) == 0x80U) { - DUK_HSTRING_SET_SYMBOL(res); + DUK_HSTRING_SET_ASCII(res); + DUK_ASSERT(duk_unicode_unvalidated_utf8_length(data, (duk_size_t) blen) == blen); + } else { + /* Because 'data' is NUL-terminated, we don't need a + * blen > 0 check here. For NUL (0x00) the symbol + * checks will be false. + */ + if (DUK_UNLIKELY(data[0] >= 0x80U)) { + if (data[0] == 0xffU) { + DUK_HSTRING_SET_SYMBOL(res); + DUK_HSTRING_SET_HIDDEN(res); + } else if (data[0] <= 0xbf) { + /* Check equivalent to: (data[0] & 0xc0U) == 0x80U. */ + DUK_HSTRING_SET_SYMBOL(res); + } } - } - - DUK_HSTRING_SET_HASH(res, strhash); - DUK_HSTRING_SET_BYTELEN(res, blen); - - clen = (duk_uint32_t) duk_unicode_unvalidated_utf8_length(str, (duk_size_t) blen); - DUK_ASSERT(clen <= blen); -#if defined(DUK_USE_HSTRING_CLEN) - DUK_HSTRING_SET_CHARLEN(res, clen); -#endif - /* Using an explicit 'ASCII' flag has larger footprint (one call site - * only) but is quite useful for the case when there's no explicit - * 'clen' in duk_hstring. - */ - DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(res)); - if (clen == blen) { - DUK_HSTRING_SET_ASCII(res); + /* Using an explicit 'ASCII' flag has larger footprint (one call site + * only) but is quite useful for the case when there's no explicit + * 'clen' in duk_hstring. + * + * The flag is set lazily for RAM strings. + */ + DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(res)); } - DUK_DDD(DUK_DDDPRINT("interned string, hash=0x%08lx, blen=%ld, clen=%ld, has_arridx=%ld, has_extdata=%ld", + DUK_DDD(DUK_DDDPRINT("interned string, hash=0x%08lx, blen=%ld, has_arridx=%ld, has_extdata=%ld", (unsigned long) DUK_HSTRING_GET_HASH(res), (long) DUK_HSTRING_GET_BYTELEN(res), - (long) DUK_HSTRING_GET_CHARLEN(res), (long) (DUK_HSTRING_HAS_ARRIDX(res) ? 1 : 0), (long) (DUK_HSTRING_HAS_EXTDATA(res) ? 1 : 0))); + DUK_ASSERT(res != NULL); return res; alloc_error: - DUK_FREE(heap, res); return NULL; } /* - * String table algorithm: fixed size string table with array chaining - * - * The top level string table has a fixed size, with each slot holding - * either NULL, string pointer, or pointer to a separately allocated - * string pointer list. - * - * This is good for low memory environments using a pool allocator: the - * top level allocation has a fixed size and the pointer lists have quite - * small allocation size, which further matches the typical pool sizes - * needed by objects, strings, property tables, etc. + * Grow strtable allocation in-place. */ -#if defined(DUK_USE_STRTAB_CHAIN) +#if defined(DUK__STRTAB_RESIZE_CHECK) +DUK_LOCAL void duk__strtable_grow_inplace(duk_heap *heap) { + duk_uint32_t new_st_size; + duk_uint32_t old_st_size; + duk_uint32_t i; + duk_hstring *h; + duk_hstring *next; + duk_hstring *prev; +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *new_ptr; + duk_uint16_t *new_ptr_high; +#else + duk_hstring **new_ptr; + duk_hstring **new_ptr_high; +#endif -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL duk_bool_t duk__insert_hstring_chain(duk_heap *heap, duk_hstring *h) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_uint16_t *lst; - duk_uint16_t *new_lst; - duk_size_t i, n; - duk_uint16_t null16 = heap->heapptr_null16; - duk_uint16_t h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h); + DUK_DD(DUK_DDPRINT("grow in-place: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size * 2)); DUK_ASSERT(heap != NULL); - DUK_ASSERT(h != NULL); - - slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); - - e = heap->strtable + slotidx; - if (e->listlen == 0) { - if (e->u.str16 == null16) { - e->u.str16 = h16; - } else { - /* Now two entries in the same slot, alloc list */ - lst = (duk_uint16_t *) DUK_ALLOC(heap, sizeof(duk_uint16_t) * 2); - if (lst == NULL) { - return 1; /* fail */ - } - lst[0] = e->u.str16; - lst[1] = h16; - e->u.strlist16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) lst); - e->listlen = 2; - } - } else { - DUK_ASSERT(e->u.strlist16 != null16); - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); - DUK_ASSERT(lst != NULL); - for (i = 0, n = e->listlen; i < n; i++) { - if (lst[i] == null16) { - lst[i] = h16; - return 0; - } - } - - if (e->listlen + 1 == 0) { - /* Overflow, relevant mainly when listlen is 16 bits. */ - return 1; /* fail */ - } + DUK_ASSERT(heap->st_resizing == 1); + DUK_ASSERT(heap->st_size >= 2); + DUK_ASSERT((heap->st_size & (heap->st_size - 1)) == 0); /* 2^N */ + DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL); + + new_st_size = heap->st_size << 1U; + DUK_ASSERT(new_st_size > heap->st_size); /* No overflow. */ + + /* Reallocate the strtable first and then work in-place to rehash + * strings. We don't need an indirect allocation here: even if GC + * is triggered to satisfy the allocation, recursive strtable resize + * is prevented by flags. This is also why we don't need to use + * DUK_REALLOC_INDIRECT(). + */ - new_lst = (duk_uint16_t *) DUK_REALLOC(heap, lst, sizeof(duk_uint16_t) * (e->listlen + 1)); - if (new_lst == NULL) { - return 1; /* fail */ - } - new_lst[e->listlen++] = h16; - e->u.strlist16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) new_lst); +#if defined(DUK_USE_STRTAB_PTRCOMP) + new_ptr = (duk_uint16_t *) DUK_REALLOC(heap, heap->strtable16, sizeof(duk_uint16_t) * new_st_size); +#else + new_ptr = (duk_hstring **) DUK_REALLOC(heap, heap->strtable, sizeof(duk_hstring *) * new_st_size); +#endif + if (DUK_UNLIKELY(new_ptr == NULL)) { + /* If realloc fails we can continue normally: the string table + * won't "fill up" although chains will gradually get longer. + * When string insertions continue, we'll quite soon try again + * with no special handling. + */ + DUK_D(DUK_DPRINT("string table grow failed, ignoring")); + return; } - return 0; -} -#else /* DUK_USE_HEAPPTR16 */ -DUK_LOCAL duk_bool_t duk__insert_hstring_chain(duk_heap *heap, duk_hstring *h) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_hstring **lst; - duk_hstring **new_lst; - duk_size_t i, n; +#if defined(DUK_USE_STRTAB_PTRCOMP) + heap->strtable16 = new_ptr; +#else + heap->strtable = new_ptr; +#endif - DUK_ASSERT(heap != NULL); - DUK_ASSERT(h != NULL); + /* Rehash a single bucket into two separate ones. When we grow + * by x2 the highest 'new' bit determines whether a string remains + * in its old position (bit is 0) or goes to a new one (bit is 1). + */ - slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); + old_st_size = heap->st_size; + new_ptr_high = new_ptr + old_st_size; + for (i = 0; i < old_st_size; i++) { + duk_hstring *new_root; + duk_hstring *new_root_high; + + h = DUK__HEAPPTR_DEC16(heap, new_ptr[i]); + new_root = h; + new_root_high = NULL; + + prev = NULL; + while (h != NULL) { + duk_uint32_t mask; + + DUK_ASSERT((DUK_HSTRING_GET_HASH(h) & heap->st_mask) == i); + next = h->hdr.h_next; + + /* Example: if previous size was 256, previous mask is 0xFF + * and size is 0x100 which corresponds to the new bit that + * comes into play. + */ + DUK_ASSERT(heap->st_mask == old_st_size - 1); + mask = old_st_size; + if (DUK_HSTRING_GET_HASH(h) & mask) { + if (prev != NULL) { + prev->hdr.h_next = h->hdr.h_next; + } else { + DUK_ASSERT(h == new_root); + new_root = h->hdr.h_next; + } - e = heap->strtable + slotidx; - if (e->listlen == 0) { - if (e->u.str == NULL) { - e->u.str = h; - } else { - /* Now two entries in the same slot, alloc list */ - lst = (duk_hstring **) DUK_ALLOC(heap, sizeof(duk_hstring *) * 2); - if (lst == NULL) { - return 1; /* fail */ - } - lst[0] = e->u.str; - lst[1] = h; - e->u.strlist = lst; - e->listlen = 2; - } - } else { - DUK_ASSERT(e->u.strlist != NULL); - lst = e->u.strlist; - for (i = 0, n = e->listlen; i < n; i++) { - if (lst[i] == NULL) { - lst[i] = h; - return 0; + h->hdr.h_next = new_root_high; + new_root_high = h; + } else { + prev = h; } + h = next; } - if (e->listlen + 1 == 0) { - /* Overflow, relevant mainly when listlen is 16 bits. */ - return 1; /* fail */ - } - - new_lst = (duk_hstring **) DUK_REALLOC(heap, e->u.strlist, sizeof(duk_hstring *) * (e->listlen + 1)); - if (new_lst == NULL) { - return 1; /* fail */ - } - new_lst[e->listlen++] = h; - e->u.strlist = new_lst; + new_ptr[i] = DUK__HEAPPTR_ENC16(heap, new_root); + new_ptr_high[i] = DUK__HEAPPTR_ENC16(heap, new_root_high); } - return 0; -} -#endif /* DUK_USE_HEAPPTR16 */ -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_uint16_t *lst; - duk_size_t i, n; - duk_uint16_t null16 = heap->heapptr_null16; - - DUK_ASSERT(heap != NULL); - - slotidx = strhash % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); - - e = heap->strtable + slotidx; - if (e->listlen == 0) { - if (e->u.str16 != null16) { - duk_hstring *h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16); - DUK_ASSERT(h != NULL); - if (DUK_HSTRING_GET_BYTELEN(h) == blen && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) { - return h; - } - } - } else { - DUK_ASSERT(e->u.strlist16 != null16); - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); - DUK_ASSERT(lst != NULL); - for (i = 0, n = e->listlen; i < n; i++) { - if (lst[i] != null16) { - duk_hstring *h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[i]); - DUK_ASSERT(h != NULL); - if (DUK_HSTRING_GET_BYTELEN(h) == blen && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) { - return h; - } - } - } - } + heap->st_size = new_st_size; + heap->st_mask = new_st_size - 1; - return NULL; +#if defined(DUK_USE_ASSERTIONS) + duk__strtable_assert_checks(heap); +#endif } -#else /* DUK_USE_HEAPPTR16 */ -DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_hstring **lst; - duk_size_t i, n; - - DUK_ASSERT(heap != NULL); +#endif /* DUK__STRTAB_RESIZE_CHECK */ - slotidx = strhash % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); - - e = heap->strtable + slotidx; - if (e->listlen == 0) { - if (e->u.str != NULL && - DUK_HSTRING_GET_BYTELEN(e->u.str) == blen && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(e->u.str), (size_t) blen) == 0) { - return e->u.str; - } - } else { - DUK_ASSERT(e->u.strlist != NULL); - lst = e->u.strlist; - for (i = 0, n = e->listlen; i < n; i++) { - if (lst[i] != NULL && - DUK_HSTRING_GET_BYTELEN(lst[i]) == blen && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(lst[i]), (size_t) blen) == 0) { - return lst[i]; - } - } - } +/* + * Shrink strtable allocation in-place. + */ - return NULL; -} -#endif /* DUK_USE_HEAPPTR16 */ +#if defined(DUK__STRTAB_RESIZE_CHECK) +DUK_LOCAL void duk__strtable_shrink_inplace(duk_heap *heap) { + duk_uint32_t new_st_size; + duk_uint32_t i; + duk_hstring *h; + duk_hstring *other; + duk_hstring *root; +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *old_ptr; + duk_uint16_t *old_ptr_high; + duk_uint16_t *new_ptr; +#else + duk_hstring **old_ptr; + duk_hstring **old_ptr_high; + duk_hstring **new_ptr; +#endif -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL void duk__remove_matching_hstring_chain(duk_heap *heap, duk_hstring *h) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_uint16_t *lst; - duk_size_t i, n; - duk_uint16_t h16; - duk_uint16_t null16 = heap->heapptr_null16; + DUK_DD(DUK_DDPRINT("shrink in-place: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size / 2)); DUK_ASSERT(heap != NULL); - DUK_ASSERT(h != NULL); - - slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); + DUK_ASSERT(heap->st_resizing == 1); + DUK_ASSERT(heap->st_size >= 2); + DUK_ASSERT((heap->st_size & (heap->st_size - 1)) == 0); /* 2^N */ + DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL); - DUK_ASSERT(h != NULL); - h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h); + new_st_size = heap->st_size >> 1U; - e = heap->strtable + slotidx; - if (e->listlen == 0) { - if (e->u.str16 == h16) { - e->u.str16 = null16; - return; - } - } else { - DUK_ASSERT(e->u.strlist16 != null16); - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); - DUK_ASSERT(lst != NULL); - for (i = 0, n = e->listlen; i < n; i++) { - if (lst[i] == h16) { - lst[i] = null16; - return; + /* Combine two buckets into a single one. When we shrink, one hash + * bit (highest) disappears. + */ + old_ptr = DUK__GET_STRTABLE(heap); + old_ptr_high = old_ptr + new_st_size; + for (i = 0; i < new_st_size; i++) { + h = DUK__HEAPPTR_DEC16(heap, old_ptr[i]); + other = DUK__HEAPPTR_DEC16(heap, old_ptr_high[i]); + + if (h == NULL) { + /* First chain is empty, so use second one as is. */ + root = other; + } else { + /* Find end of first chain, and link in the second. */ + root = h; + while (h->hdr.h_next != NULL) { + h = h->hdr.h_next; } + h->hdr.h_next = other; } - } - - DUK_D(DUK_DPRINT("failed to find string that should be in stringtable")); - DUK_UNREACHABLE(); - return; -} -#else /* DUK_USE_HEAPPTR16 */ -DUK_LOCAL void duk__remove_matching_hstring_chain(duk_heap *heap, duk_hstring *h) { - duk_small_uint_t slotidx; - duk_strtab_entry *e; - duk_hstring **lst; - duk_size_t i, n; - - DUK_ASSERT(heap != NULL); - DUK_ASSERT(h != NULL); - slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE; - DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE); - - e = heap->strtable + slotidx; - if (e->listlen == 0) { - DUK_ASSERT(h != NULL); - if (e->u.str == h) { - e->u.str = NULL; - return; - } - } else { - DUK_ASSERT(e->u.strlist != NULL); - lst = e->u.strlist; - for (i = 0, n = e->listlen; i < n; i++) { - DUK_ASSERT(h != NULL); - if (lst[i] == h) { - lst[i] = NULL; - return; - } - } + old_ptr[i] = DUK__HEAPPTR_ENC16(heap, root); } - DUK_D(DUK_DPRINT("failed to find string that should be in stringtable")); - DUK_UNREACHABLE(); - return; -} -#endif /* DUK_USE_HEAPPTR16 */ + heap->st_size = new_st_size; + heap->st_mask = new_st_size - 1; -#if defined(DUK_USE_DEBUG) -DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap) { - duk_strtab_entry *e; - duk_small_uint_t i; - duk_size_t j, n, used; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t *lst; - duk_uint16_t null16 = heap->heapptr_null16; + /* The strtable is now consistent and we can realloc safely. Even + * if side effects cause string interning or removal the strtable + * updates are safe. Recursive resize has been prevented by caller. + * This is also why we don't need to use DUK_REALLOC_INDIRECT(). + * + * We assume a realloc() to a smaller size is guaranteed to succeed. + * It would be relatively straightforward to handle the error by + * essentially performing a "grow" step to recover. + */ + +#if defined(DUK_USE_STRTAB_PTRCOMP) + new_ptr = (duk_uint16_t *) DUK_REALLOC(heap, heap->strtable16, sizeof(duk_uint16_t) * new_st_size); + DUK_ASSERT(new_ptr != NULL); + heap->strtable16 = new_ptr; #else - duk_hstring **lst; + new_ptr = (duk_hstring **) DUK_REALLOC(heap, heap->strtable, sizeof(duk_hstring *) * new_st_size); + DUK_ASSERT(new_ptr != NULL); + heap->strtable = new_ptr; #endif - DUK_ASSERT(heap != NULL); +#if defined(DUK_USE_ASSERTIONS) + duk__strtable_assert_checks(heap); +#endif +} +#endif /* DUK__STRTAB_RESIZE_CHECK */ - for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { - e = heap->strtable + i; +/* + * Grow/shrink check. + */ + +#if defined(DUK__STRTAB_RESIZE_CHECK) +DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__strtable_resize_check(duk_heap *heap) { + duk_uint32_t load_factor; /* fixed point */ - if (e->listlen == 0) { -#if defined(DUK_USE_HEAPPTR16) - DUK_DD(DUK_DDPRINT("[%03d] -> plain %d", (int) i, (int) (e->u.str16 != null16 ? 1 : 0))); + DUK_ASSERT(heap != NULL); +#if defined(DUK_USE_STRTAB_PTRCOMP) + DUK_ASSERT(heap->strtable16 != NULL); #else - DUK_DD(DUK_DDPRINT("[%03d] -> plain %d", (int) i, (int) (e->u.str ? 1 : 0))); + DUK_ASSERT(heap->strtable != NULL); #endif + + /* Prevent recursive resizing. */ + if (DUK_UNLIKELY(heap->st_resizing)) { + DUK_D(DUK_DPRINT("prevent recursive strtable resize")); + return; + } + + heap->st_resizing = 1; + + DUK_ASSERT(heap->st_size >= 16U); + DUK_ASSERT((heap->st_size >> 4U) >= 1); + load_factor = heap->st_count / (heap->st_size >> 4U); + + DUK_DD(DUK_DDPRINT("resize check string table: size=%lu, count=%lu, load_factor=%lu (fixed point .4; float %lf)", + (unsigned long) heap->st_size, (unsigned long) heap->st_count, + (unsigned long) load_factor, + (double) heap->st_count / (double) heap->st_size)); + + if (load_factor >= DUK_USE_STRTAB_GROW_LIMIT) { + if (heap->st_size >= DUK_USE_STRTAB_MAXSIZE) { + DUK_DD(DUK_DDPRINT("want to grow strtable (based on load factor) but already maximum size")); } else { - used = 0; -#if defined(DUK_USE_HEAPPTR16) - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); -#else - lst = e->u.strlist; + DUK_D(DUK_DPRINT("grow string table: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size * 2)); +#if defined(DUK_USE_DEBUG) + duk_heap_strtable_dump(heap); #endif - DUK_ASSERT(lst != NULL); - for (j = 0, n = e->listlen; j < n; j++) { -#if defined(DUK_USE_HEAPPTR16) - if (lst[j] != null16) { -#else - if (lst[j] != NULL) { + duk__strtable_grow_inplace(heap); + } + } else if (load_factor <= DUK_USE_STRTAB_SHRINK_LIMIT) { + if (heap->st_size <= DUK_USE_STRTAB_MINSIZE) { + DUK_DD(DUK_DDPRINT("want to shrink strtable (based on load factor) but already minimum size")); + } else { + DUK_D(DUK_DPRINT("shrink string table: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size / 2)); +#if defined(DUK_USE_DEBUG) + duk_heap_strtable_dump(heap); #endif - used++; - } - } - DUK_DD(DUK_DDPRINT("[%03d] -> array %d/%d", (int) i, (int) used, (int) e->listlen)); + duk__strtable_shrink_inplace(heap); } + } else { + DUK_DD(DUK_DDPRINT("no need for strtable resize")); } -} -#endif /* DUK_USE_DEBUG */ -#endif /* DUK_USE_STRTAB_CHAIN */ + heap->st_resizing = 0; +} +#endif /* DUK__STRTAB_RESIZE_CHECK */ /* - * String table algorithm: closed hashing with a probe sequence - * - * This is the default algorithm and works fine for environments with - * minimal memory constraints. + * Torture grow/shrink: unconditionally grow and shrink back. */ -#if defined(DUK_USE_STRTAB_PROBE) +#if defined(DUK_USE_STRTAB_TORTURE) && defined(DUK__STRTAB_RESIZE_CHECK) +DUK_LOCAL void duk__strtable_resize_torture(duk_heap *heap) { + duk_uint32_t old_st_size; -/* Count actually used (non-NULL, non-DELETED) entries. */ -DUK_LOCAL duk_int_t duk__count_used_probe(duk_heap *heap) { - duk_int_t res = 0; - duk_uint_fast32_t i, n; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t null16 = heap->heapptr_null16; - duk_uint16_t deleted16 = heap->heapptr_deleted16; -#endif + DUK_ASSERT(heap != NULL); - n = (duk_uint_fast32_t) heap->st_size; - for (i = 0; i < n; i++) { -#if defined(DUK_USE_HEAPPTR16) - if (heap->strtable16[i] != null16 && heap->strtable16[i] != deleted16) { -#else - if (heap->strtable[i] != NULL && heap->strtable[i] != DUK__DELETED_MARKER(heap)) { -#endif - res++; - } + old_st_size = heap->st_size; + if (old_st_size >= DUK_USE_STRTAB_MAXSIZE) { + return; } - return res; -} - -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL void duk__insert_hstring_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, duk_uint32_t *p_used, duk_hstring *h) { -#else -DUK_LOCAL void duk__insert_hstring_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, duk_uint32_t *p_used, duk_hstring *h) { -#endif - duk_uint32_t i; - duk_uint32_t step; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t null16 = heap->heapptr_null16; - duk_uint16_t deleted16 = heap->heapptr_deleted16; -#endif - - DUK_ASSERT(size > 0); - - i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(h), size); - step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(h)); - for (;;) { -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t e16 = entries16[i]; -#else - duk_hstring *e = entries[i]; -#endif - -#if defined(DUK_USE_HEAPPTR16) - /* XXX: could check for e16 == 0 because NULL is guaranteed to - * encode to zero. - */ - if (e16 == null16) { -#else - if (e == NULL) { -#endif - DUK_DDD(DUK_DDDPRINT("insert hit (null): %ld", (long) i)); -#if defined(DUK_USE_HEAPPTR16) - entries16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h); -#else - entries[i] = h; -#endif - (*p_used)++; - break; -#if defined(DUK_USE_HEAPPTR16) - } else if (e16 == deleted16) { -#else - } else if (e == DUK__DELETED_MARKER(heap)) { -#endif - /* st_used remains the same, DELETED is counted as used */ - DUK_DDD(DUK_DDDPRINT("insert hit (deleted): %ld", (long) i)); -#if defined(DUK_USE_HEAPPTR16) - entries16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h); -#else - entries[i] = h; -#endif - break; - } - DUK_DDD(DUK_DDDPRINT("insert miss: %ld", (long) i)); - i = (i + step) % size; - /* looping should never happen */ - DUK_ASSERT(i != DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(h), size)); + heap->st_resizing = 1; + duk__strtable_grow_inplace(heap); + if (heap->st_size > old_st_size) { + duk__strtable_shrink_inplace(heap); } + heap->st_resizing = 0; } +#endif /* DUK_USE_STRTAB_TORTURE && DUK__STRTAB_RESIZE_CHECK */ -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL duk_hstring *duk__find_matching_string_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { -#else -DUK_LOCAL duk_hstring *duk__find_matching_string_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { -#endif - duk_uint32_t i; - duk_uint32_t step; - - DUK_ASSERT(size > 0); +/* + * Raw intern; string already checked not to be present. + */ - i = DUK__HASH_INITIAL(strhash, size); - step = DUK__HASH_PROBE_STEP(strhash); - for (;;) { - duk_hstring *e; -#if defined(DUK_USE_HEAPPTR16) - e = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, entries16[i]); +DUK_LOCAL duk_hstring *duk__strtable_do_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { + duk_hstring *res; + const duk_uint8_t *extdata; +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *slot; #else - e = entries[i]; + duk_hstring **slot; #endif - if (!e) { - return NULL; - } - if (e != DUK__DELETED_MARKER(heap) && DUK_HSTRING_GET_BYTELEN(e) == blen) { - if (DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(e), (size_t) blen) == 0) { - DUK_DDD(DUK_DDDPRINT("find matching hit: %ld (step %ld, size %ld)", - (long) i, (long) step, (long) size)); - return e; - } - } - DUK_DDD(DUK_DDDPRINT("find matching miss: %ld (step %ld, size %ld)", - (long) i, (long) step, (long) size)); - i = (i + step) % size; + DUK_DDD(DUK_DDDPRINT("do_intern: heap=%p, str=%p, blen=%lu, strhash=%lx, st_size=%lu, st_count=%lu, load=%lf", + (void *) heap, (const void *) str, (unsigned long) blen, (unsigned long) strhash, + (unsigned long) heap->st_size, (unsigned long) heap->st_count, + (double) heap->st_count / (double) heap->st_size)); - /* looping should never happen */ - DUK_ASSERT(i != DUK__HASH_INITIAL(strhash, size)); - } - DUK_UNREACHABLE(); -} + DUK_ASSERT(heap != NULL); -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL void duk__remove_matching_hstring_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, duk_hstring *h) { -#else -DUK_LOCAL void duk__remove_matching_hstring_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, duk_hstring *h) { -#endif - duk_uint32_t i; - duk_uint32_t step; - duk_uint32_t hash; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t null16 = heap->heapptr_null16; - duk_uint16_t h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h); -#endif + /* Prevent any side effects on the string table and the caller provided + * str/blen arguments while interning is in progress. For example, if + * the caller provided str/blen from a dynamic buffer, a finalizer + * might resize or modify that dynamic buffer, invalidating the call + * arguments. + * + * While finalizers must be prevented, mark-and-sweep itself is fine. + * Recursive string table resize is prevented explicitly here. + */ - DUK_ASSERT(size > 0); - - hash = DUK_HSTRING_GET_HASH(h); - i = DUK__HASH_INITIAL(hash, size); - step = DUK__HASH_PROBE_STEP(hash); - for (;;) { -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t e16 = entries16[i]; -#else - duk_hstring *e = entries[i]; -#endif + heap->pf_prevent_count++; + DUK_ASSERT(heap->pf_prevent_count != 0); /* Wrap. */ -#if defined(DUK_USE_HEAPPTR16) - if (e16 == null16) { -#else - if (!e) { -#endif - DUK_UNREACHABLE(); - break; - } -#if defined(DUK_USE_HEAPPTR16) - if (e16 == h16) { -#else - if (e == h) { -#endif - /* st_used remains the same, DELETED is counted as used */ - DUK_DDD(DUK_DDDPRINT("free matching hit: %ld", (long) i)); -#if defined(DUK_USE_HEAPPTR16) - entries16[i] = heap->heapptr_deleted16; -#else - entries[i] = DUK__DELETED_MARKER(heap); +#if defined(DUK_USE_STRTAB_TORTURE) && defined(DUK__STRTAB_RESIZE_CHECK) + duk__strtable_resize_torture(heap); #endif - break; - } - DUK_DDD(DUK_DDDPRINT("free matching miss: %ld", (long) i)); - i = (i + step) % size; + /* String table grow/shrink check. Because of chaining (and no + * accumulation issues as with hash probe chains and DELETED + * markers) there's never a mandatory need to resize right now. + * Check for the resize only periodically, based on st_count + * bit pattern. Because string table removal doesn't do a shrink + * check, we do that also here. + * + * Do the resize and possible grow/shrink before the new duk_hstring + * has been allocated. Otherwise we may trigger a GC when the result + * duk_hstring is not yet strongly referenced. + */ - /* looping should never happen */ - DUK_ASSERT(i != DUK__HASH_INITIAL(hash, size)); +#if defined(DUK__STRTAB_RESIZE_CHECK) + if (DUK_UNLIKELY((heap->st_count & DUK_USE_STRTAB_RESIZE_CHECK_MASK) == 0)) { + duk__strtable_resize_check(heap); } -} - -DUK_LOCAL duk_bool_t duk__resize_strtab_raw_probe(duk_heap *heap, duk_uint32_t new_size) { -#if defined(DUK_USE_DEBUG) - duk_uint32_t old_used = heap->st_used; -#endif - duk_uint32_t old_size = heap->st_size; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t *old_entries = heap->strtable16; - duk_uint16_t *new_entries = NULL; -#else - duk_hstring **old_entries = heap->strtable; - duk_hstring **new_entries = NULL; #endif - duk_uint32_t new_used = 0; - duk_uint32_t i; -#if defined(DUK_USE_DEBUG) - DUK_UNREF(old_used); /* unused with some debug level combinations */ -#endif + /* External string check (low memory optimization). */ -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) - DUK_DDD(DUK_DDDPRINT("attempt to resize stringtable: %ld entries, %ld bytes, %ld used, %ld%% load -> %ld entries, %ld bytes, %ld used, %ld%% load", - (long) old_size, (long) (sizeof(duk_hstring *) * old_size), (long) old_used, - (long) (((double) old_used) / ((double) old_size) * 100.0), - (long) new_size, (long) (sizeof(duk_hstring *) * new_size), (long) duk__count_used_probe(heap), - (long) (((double) duk__count_used_probe(heap)) / ((double) new_size) * 100.0))); +#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) + extdata = (const duk_uint8_t *) DUK_USE_EXTSTR_INTERN_CHECK(heap->heap_udata, (void *) DUK_LOSE_CONST(str), (duk_size_t) blen); +#else + extdata = (const duk_uint8_t *) NULL; #endif - DUK_ASSERT(new_size > (duk_uint32_t) duk__count_used_probe(heap)); /* required for rehash to succeed, equality not that useful */ - DUK_ASSERT(old_entries); - - /* - * The attempt to allocate may cause a GC. Such a GC must not attempt to resize - * the stringtable (though it can be swept); finalizer execution and object - * compaction must also be postponed to avoid the pressure to add strings to the - * string table. Call site must prevent these. + /* Allocate and initialize string, not yet linked. This may cause a + * GC which may cause other strings to be interned and inserted into + * the string table before we insert our string. Finalizer execution + * is disabled intentionally to avoid a finalizer from e.g. resizing + * a buffer used as a data area for 'str'. */ - DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE); - DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_FINALIZERS); - DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_OBJECT_COMPACTION); + res = duk__strtable_alloc_hstring(heap, str, blen, strhash, extdata); -#if defined(DUK_USE_HEAPPTR16) - new_entries = (duk_uint16_t *) DUK_ALLOC(heap, sizeof(duk_uint16_t) * new_size); -#else - new_entries = (duk_hstring **) DUK_ALLOC(heap, sizeof(duk_hstring *) * new_size); -#endif + /* Allow side effects again: GC must be avoided until duk_hstring + * result (if successful) has been INCREF'd. + */ + DUK_ASSERT(heap->pf_prevent_count > 0); + heap->pf_prevent_count--; - if (!new_entries) { - goto resize_error; - } + /* Alloc error handling. */ -#if defined(DUK_USE_EXPLICIT_NULL_INIT) - for (i = 0; i < new_size; i++) { -#if defined(DUK_USE_HEAPPTR16) - new_entries[i] = heap->heapptr_null16; -#else - new_entries[i] = NULL; + if (DUK_UNLIKELY(res == NULL)) { +#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) + if (extdata != NULL) { + DUK_USE_EXTSTR_FREE(heap->heap_udata, (const void *) extdata); + } #endif + return NULL; } -#else -#if defined(DUK_USE_HEAPPTR16) - /* Relies on NULL encoding to zero. */ - DUK_MEMZERO(new_entries, sizeof(duk_uint16_t) * new_size); -#else - DUK_MEMZERO(new_entries, sizeof(duk_hstring *) * new_size); -#endif -#endif - /* Because new_size > duk__count_used_probe(heap), guaranteed to work */ - for (i = 0; i < old_size; i++) { - duk_hstring *e; + /* Insert into string table. */ -#if defined(DUK_USE_HEAPPTR16) - e = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, old_entries[i]); +#if defined(DUK_USE_STRTAB_PTRCOMP) + slot = heap->strtable16 + (strhash & heap->st_mask); #else - e = old_entries[i]; + slot = heap->strtable + (strhash & heap->st_mask); #endif - if (e == NULL || e == DUK__DELETED_MARKER(heap)) { - continue; - } - /* checking for DUK__DELETED_MARKER is not necessary here, but helper does it now */ - duk__insert_hstring_probe(heap, new_entries, new_size, &new_used, e); - } + DUK_ASSERT(res->hdr.h_next == NULL); /* This is the case now, but unnecessary zeroing/NULLing. */ + res->hdr.h_next = DUK__HEAPPTR_DEC16(heap, *slot); + *slot = DUK__HEAPPTR_ENC16(heap, res); -#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1) - DUK_DD(DUK_DDPRINT("resized stringtable: %ld entries, %ld bytes, %ld used, %ld%% load -> %ld entries, %ld bytes, %ld used, %ld%% load", - (long) old_size, (long) (sizeof(duk_hstring *) * old_size), (long) old_used, - (long) (((double) old_used) / ((double) old_size) * 100.0), - (long) new_size, (long) (sizeof(duk_hstring *) * new_size), (long) new_used, - (long) (((double) new_used) / ((double) new_size) * 100.0))); -#endif + /* Update string count only for successful inserts. */ -#if defined(DUK_USE_HEAPPTR16) - DUK_FREE(heap, heap->strtable16); - heap->strtable16 = new_entries; -#else - DUK_FREE(heap, heap->strtable); - heap->strtable = new_entries; +#if defined(DUK__STRTAB_RESIZE_CHECK) + heap->st_count++; #endif - heap->st_size = new_size; - heap->st_used = new_used; /* may be less, since DELETED entries are NULLed by rehash */ - return 0; /* OK */ + /* The duk_hstring is in the string table but is not yet strongly + * reachable. Calling code MUST NOT make any allocations or other + * side effects before the duk_hstring has been INCREF'd and made + * reachable. + */ - resize_error: - DUK_FREE(heap, new_entries); - return 1; /* FAIL */ + return res; } -DUK_LOCAL duk_bool_t duk__resize_strtab_probe(duk_heap *heap) { - duk_uint32_t new_size; - duk_bool_t ret; - - new_size = (duk_uint32_t) duk__count_used_probe(heap); - if (new_size >= 0x80000000UL) { - new_size = DUK_STRTAB_HIGHEST_32BIT_PRIME; - } else { - new_size = duk_util_get_hash_prime(DUK_STRTAB_GROW_ST_SIZE(new_size)); - new_size = duk_util_get_hash_prime(new_size); - } - DUK_ASSERT(new_size > 0); +/* + * Intern a string from str/blen, returning either an existing duk_hstring + * or adding a new one into the string table. The input string does -not- + * need to be NUL terminated. + * + * The input 'str' argument may point to a Duktape managed data area such as + * the data area of a dynamic buffer. It's crucial to avoid any side effects + * that might affect the data area (e.g. resize the dynamic buffer, or write + * to the buffer) before the string is fully interned. + */ - /* rehash even if old and new sizes are the same to get rid of - * DELETED entries. - */ +#if defined(DUK_USE_ROM_STRINGS) +DUK_LOCAL duk_hstring *duk__strtab_romstring_lookup(duk_heap *heap, const duk_uint8_t *str, duk_size_t blen, duk_uint32_t strhash) { + duk_size_t lookup_hash; + duk_hstring *curr; - ret = duk__resize_strtab_raw_probe(heap, new_size); + DUK_ASSERT(heap != NULL); + DUK_UNREF(heap); - return ret; -} + lookup_hash = (blen << 4); + if (blen > 0) { + lookup_hash += str[0]; + } + lookup_hash &= 0xff; -DUK_LOCAL duk_bool_t duk__recheck_strtab_size_probe(duk_heap *heap, duk_uint32_t new_used) { - duk_uint32_t new_free; - duk_uint32_t tmp1; - duk_uint32_t tmp2; - - DUK_ASSERT(new_used <= heap->st_size); /* grow by at most one */ - new_free = heap->st_size - new_used; /* unsigned intentionally */ - - /* new_free / size <= 1 / DIV <=> new_free <= size / DIV */ - /* new_used / size <= 1 / DIV <=> new_used <= size / DIV */ - - tmp1 = heap->st_size / DUK_STRTAB_MIN_FREE_DIVISOR; - tmp2 = heap->st_size / DUK_STRTAB_MIN_USED_DIVISOR; - - if (new_free <= tmp1 || new_used <= tmp2) { - /* load factor too low or high, count actually used entries and resize */ - return duk__resize_strtab_probe(heap); - } else { - return 0; /* OK */ + curr = DUK_LOSE_CONST(duk_rom_strings_lookup[lookup_hash]); + while (curr != NULL) { + if (strhash == DUK_HSTRING_GET_HASH(curr) && + blen == DUK_HSTRING_GET_BYTELEN(curr) && + DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(curr), blen) == 0) { + DUK_DDD(DUK_DDDPRINT("intern check: rom string: %!O, computed hash 0x%08lx, rom hash 0x%08lx", + curr, (unsigned long) strhash, (unsigned long) DUK_HSTRING_GET_HASH(curr))); + return curr; + } + curr = curr->hdr.h_next; } + + return NULL; } +#endif /* DUK_USE_ROM_STRINGS */ -#if defined(DUK_USE_DEBUG) -DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap) { - duk_uint32_t i; +DUK_INTERNAL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) { + duk_uint32_t strhash; duk_hstring *h; + DUK_DDD(DUK_DDDPRINT("intern check: heap=%p, str=%p, blen=%lu", (void *) heap, (const void *) str, (unsigned long) blen)); + + /* Preliminaries. */ + DUK_ASSERT(heap != NULL); -#if defined(DUK_USE_HEAPPTR16) - DUK_ASSERT(heap->strtable16 != NULL); -#else - DUK_ASSERT(heap->strtable != NULL); -#endif - DUK_UNREF(h); + DUK_ASSERT(blen == 0 || str != NULL); + DUK_ASSERT(blen <= DUK_HSTRING_MAX_BYTELEN); /* Caller is responsible for ensuring this. */ + strhash = duk_heap_hashstring(heap, str, (duk_size_t) blen); - for (i = 0; i < heap->st_size; i++) { -#if defined(DUK_USE_HEAPPTR16) - h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->strtable16[i]); + /* String table lookup. */ + + DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL); + DUK_ASSERT(heap->st_size > 0); + DUK_ASSERT(heap->st_size == heap->st_mask + 1); +#if defined(DUK_USE_STRTAB_PTRCOMP) + h = DUK__HEAPPTR_DEC16(heap, heap->strtable16[strhash & heap->st_mask]); #else - h = heap->strtable[i]; + h = heap->strtable[strhash & heap->st_mask]; #endif - - DUK_DD(DUK_DDPRINT("[%03d] -> %p", (int) i, (void *) h)); + while (h != NULL) { + if (DUK_HSTRING_GET_HASH(h) == strhash && + DUK_HSTRING_GET_BYTELEN(h) == blen && + DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) { + /* Found existing entry. */ + return h; + } + h = h->hdr.h_next; } -} -#endif /* DUK_USE_DEBUG */ -#endif /* DUK_USE_STRTAB_PROBE */ - -/* - * Raw intern and lookup - */ - -DUK_LOCAL duk_hstring *duk__do_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { - duk_hstring *res; - const duk_uint8_t *extdata; - duk_small_uint_t prev_mark_and_sweep_base_flags; - - /* Prevent any side effects on the string table and the caller provided - * str/blen arguments while interning is in progress. For example, if - * the caller provided str/blen from a dynamic buffer, a finalizer might - * resize that dynamic buffer, invalidating the call arguments. + /* ROM table lookup. Because this lookup is slower, do it only after + * RAM lookup. This works because no ROM string is ever interned into + * the RAM string table. */ - DUK_ASSERT((heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE) == 0); - prev_mark_and_sweep_base_flags = heap->mark_and_sweep_base_flags; - DUK__PREVENT_MS_SIDE_EFFECTS(heap); - -#if defined(DUK_USE_STRTAB_PROBE) - if (duk__recheck_strtab_size_probe(heap, heap->st_used + 1)) { - goto failed; - } -#endif -#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) - extdata = (const duk_uint8_t *) DUK_USE_EXTSTR_INTERN_CHECK(heap->heap_udata, (void *) DUK_LOSE_CONST(str), (duk_size_t) blen); -#else - extdata = (const duk_uint8_t *) NULL; -#endif - res = duk__alloc_init_hstring(heap, str, blen, strhash, extdata); - if (!res) { - goto failed; - } - -#if defined(DUK_USE_STRTAB_CHAIN) - if (duk__insert_hstring_chain(heap, res)) { - /* failed */ - DUK_FREE(heap, res); - goto failed; - } -#elif defined(DUK_USE_STRTAB_PROBE) - /* guaranteed to succeed */ - duk__insert_hstring_probe(heap, -#if defined(DUK_USE_HEAPPTR16) - heap->strtable16, -#else - heap->strtable, -#endif - heap->st_size, - &heap->st_used, - res); -#else -#error internal error, invalid strtab options +#if defined(DUK_USE_ROM_STRINGS) + h = duk__strtab_romstring_lookup(heap, str, blen, strhash); + if (h != NULL) { + return h; + } #endif - /* Note: hstring is in heap but has refcount zero and is not strongly reachable. - * Caller should increase refcount and make the hstring reachable before any - * operations which require allocation (and possible gc). - */ - - done: - heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; - return res; + /* Not found in string table; insert. */ - failed: - res = NULL; - goto done; + h = duk__strtable_do_intern(heap, str, blen, strhash); + return h; /* may be NULL */ } -DUK_LOCAL duk_hstring *duk__do_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t *out_strhash) { - duk_hstring *res; +/* + * Intern a string from u32. + */ - DUK_ASSERT(out_strhash); +/* XXX: Could arrange some special handling because we know that the result + * will have an arridx flag and an ASCII flag, won't need a clen check, etc. + */ - *out_strhash = duk_heap_hashstring(heap, str, (duk_size_t) blen); +DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32(duk_heap *heap, duk_uint32_t val) { + char buf[DUK__STRTAB_U32_MAX_STRLEN]; + char *p; -#if defined(DUK_USE_ROM_STRINGS) - { - duk_small_uint_t i; - /* XXX: This is VERY inefficient now, and should be e.g. a - * binary search or perfect hash, to be fixed. - */ - for (i = 0; i < (duk_small_uint_t) (sizeof(duk_rom_strings) / sizeof(duk_hstring *)); i++) { - duk_hstring *romstr; - romstr = (duk_hstring *) DUK_LOSE_CONST(duk_rom_strings[i]); - if (blen == DUK_HSTRING_GET_BYTELEN(romstr) && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(romstr), blen) == 0) { - DUK_DD(DUK_DDPRINT("intern check: rom string: %!O, computed hash 0x%08lx, rom hash 0x%08lx", - romstr, (unsigned long) *out_strhash, (unsigned long) DUK_HSTRING_GET_HASH(romstr))); - DUK_ASSERT(*out_strhash == DUK_HSTRING_GET_HASH(romstr)); - *out_strhash = DUK_HSTRING_GET_HASH(romstr); - return romstr; - } - } - } -#endif /* DUK_USE_ROM_STRINGS */ + DUK_ASSERT(heap != NULL); -#if defined(DUK_USE_STRTAB_CHAIN) - res = duk__find_matching_string_chain(heap, str, blen, *out_strhash); -#elif defined(DUK_USE_STRTAB_PROBE) - res = duk__find_matching_string_probe(heap, -#if defined(DUK_USE_HEAPPTR16) - heap->strtable16, -#else - heap->strtable, -#endif - heap->st_size, - str, - blen, - *out_strhash); -#else -#error internal error, invalid strtab options -#endif + /* This is smaller and faster than a %lu sprintf. */ + p = buf + sizeof(buf); + do { + p--; + *p = duk_lc_digits[val % 10]; + val = val / 10; + } while (val != 0); /* For val == 0, emit exactly one '0'. */ + DUK_ASSERT(p >= buf); - return res; + return duk_heap_strtable_intern(heap, (const duk_uint8_t *) p, (duk_uint32_t) ((buf + sizeof(buf)) - p)); } /* - * Exposed calls + * Checked convenience variants. + * + * XXX: Because the main use case is for the checked variants, make them the + * main functionality and provide a safe variant separately (it is only needed + * during heap init). The problem with that is that longjmp state and error + * creation must already be possible to throw. */ -#if 0 /*unused*/ -DUK_INTERNAL duk_hstring *duk_heap_string_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) { - duk_uint32_t strhash; /* dummy */ - return duk__do_lookup(heap, str, blen, &strhash); -} -#endif - -DUK_INTERNAL duk_hstring *duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) { +DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) { duk_hstring *res; - duk_uint32_t strhash; - /* caller is responsible for ensuring this */ - DUK_ASSERT(blen <= DUK_HSTRING_MAX_BYTELEN); + DUK_ASSERT(thr != NULL); + DUK_ASSERT(thr->heap != NULL); + DUK_ASSERT(blen == 0 || str != NULL); - res = duk__do_lookup(heap, str, blen, &strhash); - if (res) { - return res; - } - - res = duk__do_intern(heap, str, blen, strhash); - return res; /* may be NULL */ -} - -DUK_INTERNAL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) { - duk_hstring *res = duk_heap_string_intern(thr->heap, str, blen); - if (!res) { + res = duk_heap_strtable_intern(thr->heap, str, blen); + if (DUK_UNLIKELY(res == NULL)) { DUK_ERROR_ALLOC_FAILED(thr); } return res; } -#if 0 /*unused*/ -DUK_INTERNAL duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val) { - char buf[DUK_STRTAB_U32_MAX_STRLEN+1]; - DUK_SNPRINTF(buf, sizeof(buf), "%lu", (unsigned long) val); - buf[sizeof(buf) - 1] = (char) 0; - DUK_ASSERT(DUK_STRLEN(buf) <= DUK_UINT32_MAX); /* formatted result limited */ - return duk_heap_string_lookup(heap, (const duk_uint8_t *) buf, (duk_uint32_t) DUK_STRLEN(buf)); -} -#endif +DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32_checked(duk_hthread *thr, duk_uint32_t val) { + duk_hstring *res; -DUK_INTERNAL duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val) { - char buf[DUK_STRTAB_U32_MAX_STRLEN+1]; - DUK_SNPRINTF(buf, sizeof(buf), "%lu", (unsigned long) val); - buf[sizeof(buf) - 1] = (char) 0; - DUK_ASSERT(DUK_STRLEN(buf) <= DUK_UINT32_MAX); /* formatted result limited */ - return duk_heap_string_intern(heap, (const duk_uint8_t *) buf, (duk_uint32_t) DUK_STRLEN(buf)); -} + DUK_ASSERT(thr != NULL); + DUK_ASSERT(thr->heap != NULL); -DUK_INTERNAL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val) { - duk_hstring *res = duk_heap_string_intern_u32(thr->heap, val); - if (!res) { + res = duk_heap_strtable_intern_u32(thr->heap, val); + if (DUK_UNLIKELY(res == NULL)) { DUK_ERROR_ALLOC_FAILED(thr); } return res; } -/* find and remove string from stringtable; caller must free the string itself */ +/* + * Remove (unlink) a string from the string table. + * + * Just unlinks the duk_hstring, leaving link pointers as garbage. + * Caller must free the string itself. + */ + #if defined(DUK_USE_REFERENCE_COUNTING) -DUK_INTERNAL void duk_heap_string_remove(duk_heap *heap, duk_hstring *h) { - DUK_DDD(DUK_DDDPRINT("remove string from stringtable: %!O", (duk_heaphdr *) h)); +/* Unlink without a 'prev' pointer. */ +DUK_INTERNAL void duk_heap_strtable_unlink(duk_heap *heap, duk_hstring *h) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *slot; +#else + duk_hstring **slot; +#endif + duk_hstring *other; + duk_hstring *prev; + + DUK_DDD(DUK_DDDPRINT("remove: heap=%p, h=%p, blen=%lu, strhash=%lx", + (void *) heap, (void *) h, + (unsigned long) (h != NULL ? DUK_HSTRING_GET_BYTELEN(h) : 0), + (unsigned long) (h != NULL ? DUK_HSTRING_GET_HASH(h) : 0))); -#if defined(DUK_USE_STRTAB_CHAIN) - duk__remove_matching_hstring_chain(heap, h); -#elif defined(DUK_USE_STRTAB_PROBE) - duk__remove_matching_hstring_probe(heap, -#if defined(DUK_USE_HEAPPTR16) - heap->strtable16, -#else - heap->strtable, + DUK_ASSERT(heap != NULL); + DUK_ASSERT(h != NULL); + +#if defined(DUK__STRTAB_RESIZE_CHECK) + DUK_ASSERT(heap->st_count > 0); + heap->st_count--; #endif - heap->st_size, - h); + +#if defined(DUK_USE_STRTAB_PTRCOMP) + slot = heap->strtable16 + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); #else -#error internal error, invalid strtab options + slot = heap->strtable + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); #endif + other = DUK__HEAPPTR_DEC16(heap, *slot); + DUK_ASSERT(other != NULL); /* At least argument string is in the chain. */ + + prev = NULL; + while (other != h) { + prev = other; + other = other->hdr.h_next; + DUK_ASSERT(other != NULL); /* We'll eventually find 'h'. */ + } + if (prev != NULL) { + /* Middle of list. */ + prev->hdr.h_next = h->hdr.h_next; + } else { + /* Head of list. */ + *slot = DUK__HEAPPTR_ENC16(heap, h->hdr.h_next); + } + + /* There's no resize check on a string free. The next string + * intern will do one. + */ } +#endif /* DUK_USE_REFERENCE_COUNTING */ + +/* Unlink with a 'prev' pointer. */ +DUK_INTERNAL void duk_heap_strtable_unlink_prev(duk_heap *heap, duk_hstring *h, duk_hstring *prev) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *slot; +#else + duk_hstring **slot; #endif -#if defined(DUK_USE_MS_STRINGTABLE_RESIZE) -DUK_INTERNAL void duk_heap_force_strtab_resize(duk_heap *heap) { - duk_small_uint_t prev_mark_and_sweep_base_flags; - /* Force a resize so that DELETED entries are eliminated. - * Another option would be duk__recheck_strtab_size_probe(); - * but since that happens on every intern anyway, this whole - * check can now be disabled. - */ + DUK_DDD(DUK_DDDPRINT("remove: heap=%p, prev=%p, h=%p, blen=%lu, strhash=%lx", + (void *) heap, (void *) prev, (void *) h, + (unsigned long) (h != NULL ? DUK_HSTRING_GET_BYTELEN(h) : 0), + (unsigned long) (h != NULL ? DUK_HSTRING_GET_HASH(h) : 0))); - DUK_ASSERT((heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE) == 0); - prev_mark_and_sweep_base_flags = heap->mark_and_sweep_base_flags; - DUK__PREVENT_MS_SIDE_EFFECTS(heap); + DUK_ASSERT(heap != NULL); + DUK_ASSERT(h != NULL); + DUK_ASSERT(prev == NULL || prev->hdr.h_next == h); -#if defined(DUK_USE_STRTAB_CHAIN) - DUK_UNREF(heap); -#elif defined(DUK_USE_STRTAB_PROBE) - (void) duk__resize_strtab_probe(heap); +#if defined(DUK__STRTAB_RESIZE_CHECK) + DUK_ASSERT(heap->st_count > 0); + heap->st_count--; #endif - heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; -} + if (prev != NULL) { + /* Middle of list. */ + prev->hdr.h_next = h->hdr.h_next; + } else { + /* Head of list. */ +#if defined(DUK_USE_STRTAB_PTRCOMP) + slot = heap->strtable16 + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); +#else + slot = heap->strtable + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); #endif + DUK_ASSERT(DUK__HEAPPTR_DEC16(heap, *slot) == h); + *slot = DUK__HEAPPTR_ENC16(heap, h->hdr.h_next); + } +} -#if defined(DUK_USE_STRTAB_CHAIN) -DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap) { - /* Free strings in the stringtable and any allocations needed - * by the stringtable itself. +/* + * Force string table resize check in mark-and-sweep. + */ + +DUK_INTERNAL void duk_heap_strtable_force_resize(duk_heap *heap) { + /* Does only one grow/shrink step if needed. The heap->st_resizing + * flag protects against recursive resizing. */ - duk_uint_fast32_t i, j; - duk_strtab_entry *e; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t *lst; - duk_uint16_t null16 = heap->heapptr_null16; -#else - duk_hstring **lst; -#endif - duk_hstring *h; - for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { - e = heap->strtable + i; - if (e->listlen > 0) { -#if defined(DUK_USE_HEAPPTR16) - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); -#else - lst = e->u.strlist; -#endif - DUK_ASSERT(lst != NULL); + DUK_ASSERT(heap != NULL); + DUK_UNREF(heap); - for (j = 0; j < e->listlen; j++) { -#if defined(DUK_USE_HEAPPTR16) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[j]); - lst[j] = null16; -#else - h = lst[j]; - lst[j] = NULL; -#endif - /* strings may have inner refs (extdata) in some cases */ - if (h != NULL) { - duk_free_hstring(heap, h); - } - } -#if defined(DUK_USE_HEAPPTR16) - e->u.strlist16 = null16; +#if defined(DUK__STRTAB_RESIZE_CHECK) +#if defined(DUK_USE_STRTAB_PTRCOMP) + if (heap->strtable16 != NULL) { #else - e->u.strlist = NULL; + if (heap->strtable != NULL) { #endif - DUK_FREE(heap, lst); - } else { -#if defined(DUK_USE_HEAPPTR16) - h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16); - e->u.str16 = null16; -#else - h = e->u.str; - e->u.str = NULL; -#endif - if (h != NULL) { - duk_free_hstring(heap, h); - } - } - e->listlen = 0; + duk__strtable_resize_check(heap); } +#endif } -#endif /* DUK_USE_STRTAB_CHAIN */ -#if defined(DUK_USE_STRTAB_PROBE) -DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap) { - duk_uint_fast32_t i; - duk_hstring *h; +/* + * Free strings in the string table and the string table itself. + */ -#if defined(DUK_USE_HEAPPTR16) - if (heap->strtable16) { +DUK_INTERNAL void duk_heap_strtable_free(duk_heap *heap) { +#if defined(DUK_USE_STRTAB_PTRCOMP) + duk_uint16_t *strtable; + duk_uint16_t *st; #else - if (heap->strtable) { + duk_hstring **strtable; + duk_hstring **st; #endif - for (i = 0; i < (duk_uint_fast32_t) heap->st_size; i++) { -#if defined(DUK_USE_HEAPPTR16) - h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); -#else - h = heap->strtable[i]; + duk_hstring *h; + + DUK_ASSERT(heap != NULL); + +#if defined(DUK_USE_ASSERTIONS) + duk__strtable_assert_checks(heap); #endif - if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) { - continue; - } - DUK_ASSERT(h != NULL); - /* strings may have inner refs (extdata) in some cases */ + /* Strtable can be NULL if heap init fails. However, in that case + * heap->st_size is 0, so strtable == strtable_end and we skip the + * loop without a special check. + */ + strtable = DUK__GET_STRTABLE(heap); + st = strtable + heap->st_size; + DUK_ASSERT(strtable != NULL || heap->st_size == 0); + + while (strtable != st) { + --st; + h = DUK__HEAPPTR_DEC16(heap, *st); + while (h) { + duk_hstring *h_next; + h_next = h->hdr.h_next; + + /* Strings may have inner refs (extdata) in some cases. */ duk_free_hstring(heap, h); -#if 0 /* not strictly necessary */ - heap->strtable[i] = NULL; -#endif + + h = h_next; } -#if defined(DUK_USE_HEAPPTR16) - DUK_FREE(heap, heap->strtable16); -#else - DUK_FREE(heap, heap->strtable); -#endif -#if 0 /* not strictly necessary */ - heap->strtable = NULL; -#endif } + + DUK_FREE(heap, strtable); } -#endif /* DUK_USE_STRTAB_PROBE */ diff -Nru duktape-2.0.0/src-separate/duk_henv.h duktape-2.1.1/src-separate/duk_henv.h --- duktape-2.0.0/src-separate/duk_henv.h 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_henv.h 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,48 @@ +/* + * Environment object representation. + */ + +#if !defined(DUK_HENV_H_INCLUDED) +#define DUK_HENV_H_INCLUDED + +#define DUK_ASSERT_HDECENV_VALID(h) do { \ + DUK_ASSERT((h) != NULL); \ + DUK_ASSERT(DUK_HOBJECT_IS_DECENV((duk_hobject *) (h))); \ + DUK_ASSERT((h)->thread == NULL || (h)->varmap != NULL); \ + } while (0) + +#define DUK_ASSERT_HOBJENV_VALID(h) do { \ + 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); \ + } while (0) + +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; +}; + +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 */ diff -Nru duktape-2.0.0/src-separate/duk_hobject_alloc.c duktape-2.1.1/src-separate/duk_hobject_alloc.c --- duktape-2.0.0/src-separate/duk_hobject_alloc.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_hobject_alloc.c 2017-07-28 22:05:08.000000000 +0000 @@ -6,19 +6,29 @@ * 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 "duk_internal.h" -DUK_LOCAL void duk__init_object_parts(duk_heap *heap, duk_hobject *obj, duk_uint_t hobject_flags) { +/* + * 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 - - /* XXX: macro? sets both heaphdr and object flags */ - obj->hdr.h_flags = hobject_flags; - DUK_HEAPHDR_SET_TYPE(&obj->hdr, DUK_HTYPE_OBJECT); /* also goes into flags */ - #if defined(DUK_USE_HEAPPTR16) - /* Zero encoded pointer is required to match NULL */ + /* 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); @@ -27,14 +37,22 @@ DUK_ASSERT_HEAPHDR_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. + /* 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. * @@ -46,7 +64,7 @@ * count before invoking any operation that might require memory allocation. */ -DUK_INTERNAL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags) { +DUK_INTERNAL duk_hobject *duk_hobject_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags) { duk_hobject *res; DUK_ASSERT(heap != NULL); @@ -54,30 +72,30 @@ /* 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_THREAD) == 0); - res = (duk_hobject *) DUK_ALLOC(heap, sizeof(duk_hobject)); - if (!res) { + res = (duk_hobject *) DUK_ALLOC_ZEROED(heap, sizeof(duk_hobject)); + if (DUK_UNLIKELY(res == NULL)) { return NULL; } - DUK_MEMZERO(res, sizeof(duk_hobject)); + DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(res)); - duk__init_object_parts(heap, res, hobject_flags); + duk__init_object_parts(heap, hobject_flags, res); + DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(res)); return res; } -DUK_INTERNAL duk_hcompfunc *duk_hcompfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags) { - duk_hcompfunc *res; +DUK_INTERNAL duk_hobject *duk_hobject_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { + duk_hobject *res; - res = (duk_hcompfunc *) DUK_ALLOC(heap, sizeof(duk_hcompfunc)); - if (!res) { - return NULL; - } - DUK_MEMZERO(res, sizeof(duk_hcompfunc)); + res = (duk_hobject *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hobject)); + return res; +} - duk__init_object_parts(heap, &res->obj, hobject_flags); +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. */ @@ -93,17 +111,10 @@ return res; } -DUK_INTERNAL duk_hnatfunc *duk_hnatfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags) { +DUK_INTERNAL duk_hnatfunc *duk_hnatfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { duk_hnatfunc *res; - res = (duk_hnatfunc *) DUK_ALLOC(heap, sizeof(duk_hnatfunc)); - if (!res) { - return NULL; - } - DUK_MEMZERO(res, sizeof(duk_hnatfunc)); - - duk__init_object_parts(heap, &res->obj, hobject_flags); - + res = (duk_hnatfunc *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hnatfunc)); #if defined(DUK_USE_EXPLICIT_NULL_INIT) res->func = NULL; #endif @@ -112,17 +123,10 @@ } #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL duk_hbufobj *duk_hbufobj_alloc(duk_heap *heap, duk_uint_t hobject_flags) { +DUK_INTERNAL duk_hbufobj *duk_hbufobj_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { duk_hbufobj *res; - res = (duk_hbufobj *) DUK_ALLOC(heap, sizeof(duk_hbufobj)); - if (!res) { - return NULL; - } - DUK_MEMZERO(res, sizeof(duk_hbufobj)); - - duk__init_object_parts(heap, &res->obj, hobject_flags); - + 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; @@ -133,24 +137,22 @@ } #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ -/* - * Allocate a new thread. +/* 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. + * 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(duk_heap *heap, duk_uint_t hobject_flags) { +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 (!res) { + if (DUK_UNLIKELY(res == NULL)) { return NULL; } DUK_MEMZERO(res, sizeof(duk_hthread)); - duk__init_object_parts(heap, &res->obj, hobject_flags); + duk__init_object_parts(heap, hobject_flags, &res->obj); #if defined(DUK_USE_EXPLICIT_NULL_INIT) res->ptr_curr_pc = NULL; @@ -160,6 +162,7 @@ res->valstack_bottom = NULL; res->valstack_top = NULL; res->callstack = NULL; + res->callstack_curr = NULL; res->catchstack = NULL; res->resumer = NULL; res->compile_ctx = NULL, @@ -169,7 +172,7 @@ res->strs = NULL; #endif { - int i; + duk_small_uint_t i; for (i = 0; i < DUK_NUM_BUILTINS; i++) { res->builtins[i] = NULL; } @@ -186,32 +189,51 @@ return res; } -#if 0 /* unused now */ -DUK_INTERNAL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags) { - duk_hobject *res = duk_hobject_alloc(thr->heap, hobject_flags); - if (!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); } 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 -/* - * Allocate a new array. - */ + DUK_ASSERT(res->thread == NULL); + DUK_ASSERT(res->varmap == NULL); + DUK_ASSERT(res->regbase == 0); -DUK_INTERNAL duk_harray *duk_harray_alloc(duk_heap *heap, duk_uint_t hobject_flags) { - duk_harray *res; + return res; +} - res = (duk_harray *) DUK_ALLOC(heap, sizeof(duk_harray)); - if (!res) { - return NULL; - } - DUK_MEMZERO(res, sizeof(duk_harray)); +DUK_INTERNAL duk_hobjenv *duk_hobjenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { + duk_hobjenv *res; - duk__init_object_parts(heap, &res->obj, hobject_flags); + 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->length == 0); + DUK_ASSERT(res->target == NULL); return res; } diff -Nru duktape-2.0.0/src-separate/duk_hobject_enum.c duktape-2.1.1/src-separate/duk_hobject_enum.c --- duktape-2.0.0/src-separate/duk_hobject_enum.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_hobject_enum.c 2017-07-28 22:05:08.000000000 +0000 @@ -242,6 +242,9 @@ */ DUK_LOCAL void duk__add_enum_key(duk_context *ctx, duk_hstring *k) { + /* 'k' may be unreachable on entry so must push without any + * potential for GC. + */ duk_push_hstring(ctx, k); duk_push_true(ctx); duk_put_prop(ctx, -3); @@ -442,7 +445,7 @@ /* This is a bit fragile: the string is not * reachable until it is pushed by the helper. */ - k = duk_heap_string_intern_u32_checked(thr, i); + k = duk_heap_strtable_intern_u32_checked(thr, i); DUK_ASSERT(k); duk__add_enum_key(ctx, k); @@ -476,7 +479,7 @@ if (DUK_TVAL_IS_UNUSED(tv)) { continue; } - k = duk_heap_string_intern_u32_checked(thr, i); /* Fragile reachability. */ + k = duk_heap_strtable_intern_u32_checked(thr, i); /* Fragile reachability. */ DUK_ASSERT(k); duk__add_enum_key(ctx, k); @@ -506,7 +509,7 @@ !DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(thr->heap, curr, i)) { continue; } - if (DUK_HSTRING_HAS_SYMBOL(k)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(k))) { if (!(enum_flags & DUK_ENUM_INCLUDE_HIDDEN) && DUK_HSTRING_HAS_HIDDEN(k)) { continue; diff -Nru duktape-2.0.0/src-separate/duk_hobject_finalizer.c duktape-2.1.1/src-separate/duk_hobject_finalizer.c --- duktape-2.0.0/src-separate/duk_hobject_finalizer.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_hobject_finalizer.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,113 +0,0 @@ -/* - * Run an duk_hobject finalizer. Used for both reference counting - * and mark-and-sweep algorithms. Must never throw an error. - * - * There is no return value. Any return value or error thrown by - * the finalizer is ignored (although errors are debug logged). - * - * Notes: - * - * - The thread used for calling the finalizer is the same as the - * 'thr' argument. This may need to change later. - * - * - 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). - */ - -#include "duk_internal.h" - -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_LOCAL duk_ret_t duk__finalize_helper(duk_context *ctx, void *udata) { - duk_hthread *thr; - - DUK_ASSERT(ctx != NULL); - thr = (duk_hthread *) ctx; - DUK_UNREF(udata); - - DUK_DDD(DUK_DDDPRINT("protected finalization helper running")); - - /* [... obj] */ - - /* 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(ctx, -1, DUK_STRIDX_INT_FINALIZER); /* -> [... obj finalizer] */ - if (!duk_is_callable(ctx, -1)) { - DUK_DDD(DUK_DDDPRINT("-> no finalizer or finalizer not callable")); - return 0; - } - duk_dup_m2(ctx); - duk_push_boolean(ctx, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap)); - DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling finalizer")); - duk_call(ctx, 2); /* [ ... obj finalizer obj heapDestruct ] -> [ ... obj retval ] */ - DUK_DDD(DUK_DDDPRINT("finalizer finished 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_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj) { - duk_context *ctx = (duk_context *) thr; - duk_ret_t rc; -#if defined(DUK_USE_ASSERTIONS) - duk_idx_t entry_top; -#endif - - DUK_DDD(DUK_DDDPRINT("running object finalizer for object: %p", (void *) obj)); - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(ctx != NULL); - DUK_ASSERT(obj != NULL); - DUK_ASSERT_VALSTACK_SPACE(thr, 1); - -#if defined(DUK_USE_ASSERTIONS) - entry_top = duk_get_top(ctx); -#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). - */ - - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); - if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj)) { - DUK_D(DUK_DPRINT("object already finalized, avoid running finalizer twice: %!O", obj)); - return; - } - DUK_HEAPHDR_SET_FINALIZED((duk_heaphdr *) obj); /* ensure never re-entered until rescue cycle complete */ - if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj)) { - /* This shouldn't happen; call sites should avoid looking up - * _Finalizer "through" a Proxy, but ignore if we come here - * with a Proxy to avoid finalizer re-entry. - */ - DUK_D(DUK_DPRINT("object is a proxy, skip finalizer call")); - return; - } - - /* XXX: use a NULL error handler for the finalizer call? */ - - DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling wrapped finalize helper")); - duk_push_hobject(ctx, obj); /* this also increases refcount by one */ - rc = duk_safe_call(ctx, duk__finalize_helper, NULL /*udata*/, 0 /*nargs*/, 1 /*nrets*/); /* -> [... obj retval/error] */ - DUK_ASSERT_TOP(ctx, 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(ctx, -1))); - } - duk_pop_2(ctx); /* -> [...] */ - - DUK_ASSERT_TOP(ctx, entry_top); -} -#endif /* DUK_USE_FINALIZER_SUPPORT */ diff -Nru duktape-2.0.0/src-separate/duk_hobject.h duktape-2.1.1/src-separate/duk_hobject.h --- duktape-2.0.0/src-separate/duk_hobject.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_hobject.h 2017-07-28 22:05:08.000000000 +0000 @@ -32,8 +32,8 @@ #if !defined(DUK_HOBJECT_H_INCLUDED) #define DUK_HOBJECT_H_INCLUDED -/* Object flag. There are currently 25 flag bits available. Make sure - * this stays in sync with debugger object inspection code. +/* 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 @@ -45,14 +45,14 @@ #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_THREAD DUK_HEAPHDR_USER_FLAG(7) /* object is a thread (duk_hthread) */ +#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_ENVRECCLOSED DUK_HEAPHDR_USER_FLAG(14) /* envrec: (declarative) record is closed */ +#define DUK_HOBJECT_FLAG_HAVE_FINALIZER DUK_HEAPHDR_USER_FLAG(14) /* object has a callable 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) */ @@ -132,7 +132,6 @@ #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_THREAD (1UL << DUK_HOBJECT_CLASS_THREAD) #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) @@ -166,7 +165,7 @@ #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) #define DUK_HOBJECT_IS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) -#define DUK_HOBJECT_IS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) +#define DUK_HOBJECT_IS_THREAD(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_THREAD) #define DUK_HOBJECT_IS_NONBOUND_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \ DUK_HOBJECT_FLAG_COMPFUNC | \ @@ -204,14 +203,14 @@ #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) #define DUK_HOBJECT_HAS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) -#define DUK_HOBJECT_HAS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) +#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_ENVRECCLOSED(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED) +#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) @@ -224,14 +223,14 @@ #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) #define DUK_HOBJECT_SET_BUFOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) -#define DUK_HOBJECT_SET_THREAD(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) +#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_ENVRECCLOSED(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED) +#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) @@ -244,20 +243,28 @@ #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) #define DUK_HOBJECT_CLEAR_BUFOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) -#define DUK_HOBJECT_CLEAR_THREAD(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) +#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_ENVRECCLOSED(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED) +#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) #define DUK_HOBJECT_CLEAR_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC) #define DUK_HOBJECT_CLEAR_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ) +/* Object can/cannot use FASTREFS, i.e. has no strong reference fields beyond + * duk_hobject base header. + */ +#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))) +#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. */ @@ -639,6 +646,16 @@ #define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr,h,p) duk_hobject_set_prototype_updref((thr), (h), (p)) /* + * 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 */ @@ -651,22 +668,9 @@ #if defined(DUK_USE_OBJSIZES16) #define DUK_HOBJECT_MAX_PROPERTIES 0x0000ffffUL #else -#define DUK_HOBJECT_MAX_PROPERTIES 0x7fffffffUL /* 2**31-1 ~= 2G properties */ +#define DUK_HOBJECT_MAX_PROPERTIES 0x3fffffffUL /* 2**30-1 ~= 1G properties */ #endif -/* higher value conserves memory; also note that linear scan is cache friendly */ -#define DUK_HOBJECT_E_USE_HASH_LIMIT 32 - -/* hash size relative to entries size: for value X, approx. hash_prime(e_size + e_size / X) */ -#define DUK_HOBJECT_H_SIZE_DIVISOR 4 /* hash size approx. 1.25 times entries size */ - -/* if new_size < L * old_size, resize without abandon check; L = 3-bit fixed point, e.g. 9 -> 9/8 = 112.5% */ -#define DUK_HOBJECT_A_FAST_RESIZE_LIMIT 9 /* 112.5%, i.e. new size less than 12.5% higher -> fast resize */ - -/* if density < L, abandon array part, L = 3-bit fixed point, e.g. 2 -> 2/8 = 25% */ -/* limit is quite low: one array entry is 8 bytes, one normal entry is 4+1+8+4 = 17 bytes (with hash entry) */ -#define DUK_HOBJECT_A_ABANDON_LIMIT 2 /* 25%, i.e. less than 25% used -> abandon */ - /* 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 @@ -678,18 +682,6 @@ #error invalid DUK_USE_ALIGN_BY #endif -/* controls for minimum entry part growth */ -#define DUK_HOBJECT_E_MIN_GROW_ADD 16 -#define DUK_HOBJECT_E_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */ - -/* controls for minimum array part growth */ -#define DUK_HOBJECT_A_MIN_GROW_ADD 16 -#define DUK_HOBJECT_A_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */ - -/* probe sequence */ -#define DUK_HOBJECT_HASH_INITIAL(hash,h_size) ((hash) % (h_size)) -#define DUK_HOBJECT_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash)) - /* * PC-to-line constants */ @@ -719,7 +711,7 @@ struct duk_propdesc { /* read-only values 'lifted' for ease of use */ - duk_small_int_t flags; + duk_small_uint_t flags; duk_hobject *get; duk_hobject *set; @@ -843,17 +835,18 @@ */ /* alloc and init */ -DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags); -#if 0 /* unused */ -DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags); -#endif -DUK_INTERNAL_DECL duk_harray *duk_harray_alloc(duk_heap *heap, duk_uint_t hobject_flags); -DUK_INTERNAL_DECL duk_hcompfunc *duk_hcompfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags); -DUK_INTERNAL_DECL duk_hnatfunc *duk_hnatfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags); +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); #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) -DUK_INTERNAL_DECL duk_hbufobj *duk_hbufobj_alloc(duk_heap *heap, duk_uint_t hobject_flags); +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(duk_heap *heap, duk_uint_t hobject_flags); +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); /* resize */ DUK_INTERNAL_DECL void duk_hobject_realloc_props(duk_hthread *thr, @@ -890,6 +883,11 @@ 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 @@ -936,11 +934,6 @@ /* macros */ DUK_INTERNAL_DECL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p); -/* finalization */ -#if defined(DUK_USE_FINALIZER_SUPPORT) -DUK_INTERNAL_DECL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj); -#endif - /* 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); diff -Nru duktape-2.0.0/src-separate/duk_hobject_pc2line.c duktape-2.1.1/src-separate/duk_hobject_pc2line.c --- duktape-2.0.0/src-separate/duk_hobject_pc2line.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_hobject_pc2line.c 2017-07-28 22:05:08.000000000 +0000 @@ -150,7 +150,7 @@ 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 error; + goto pc2line_error; } hdr = (duk_uint32_t *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, buf); @@ -159,7 +159,7 @@ /* 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 error; + goto pc2line_error; } curr_line = hdr[1 + hdr_index * 2]; @@ -167,7 +167,7 @@ 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 error; + goto pc2line_error; } /* @@ -218,7 +218,7 @@ DUK_DDD(DUK_DDDPRINT("pc2line lookup result: pc %ld -> line %ld", (long) pc, (long) curr_line)); return curr_line; - error: + pc2line_error: DUK_D(DUK_DPRINT("pc2line conversion failed for pc=%ld", (long) pc)); return 0; } diff -Nru duktape-2.0.0/src-separate/duk_hobject_props.c duktape-2.1.1/src-separate/duk_hobject_props.c --- duktape-2.0.0/src-separate/duk_hobject_props.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_hobject_props.c 2017-07-28 22:05:08.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Hobject property set/get functionality. + * duk_hobject property access functionality. * * This is very central functionality for size, performance, and compliance. * It is also rather intricate; see hobject-algorithms.rst for discussion on @@ -40,10 +40,6 @@ * might be more appropriate. */ -/* - * XXX: duk_uint_fast32_t should probably be used in many places here. - */ - #include "duk_internal.h" /* @@ -52,10 +48,6 @@ #define DUK__NO_ARRAY_INDEX DUK_HSTRING_NO_ARRAY_INDEX -/* hash probe sequence */ -#define DUK__HASH_INITIAL(hash,h_size) DUK_HOBJECT_HASH_INITIAL((hash),(h_size)) -#define DUK__HASH_PROBE_STEP(hash) DUK_HOBJECT_HASH_PROBE_STEP((hash)) - /* marker values for hash part */ #define DUK__HASH_UNUSED DUK_HOBJECT_HASHIDX_UNUSED #define DUK__HASH_DELETED DUK_HOBJECT_HASHIDX_DELETED @@ -218,14 +210,26 @@ DUK_LOCAL duk_uint32_t duk__get_default_h_size(duk_uint32_t e_size) { DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES); - if (e_size >= DUK_HOBJECT_E_USE_HASH_LIMIT) { + if (e_size >= DUK_USE_HOBJECT_HASH_PROP_LIMIT) { duk_uint32_t res; + duk_uint32_t tmp; - /* result: hash_prime(floor(1.2 * e_size)) */ - res = duk_util_get_hash_prime(e_size + e_size / DUK_HOBJECT_H_SIZE_DIVISOR); - - /* if fails, e_size will be zero = not an issue, except performance-wise */ - DUK_ASSERT(res == 0 || res > e_size); + /* Hash size should be 2^N where N is chosen so that 2^N is + * larger than e_size. Extra shifting is used to ensure hash + * is relatively sparse. + */ + tmp = e_size; + res = 2; /* Result will be 2 ** (N + 1). */ + while (tmp >= 0x40) { + tmp >>= 6; + res <<= 6; + } + while (tmp != 0) { + tmp >>= 1; + res <<= 1; + } + DUK_ASSERT((DUK_HOBJECT_MAX_PROPERTIES << 2U) > DUK_HOBJECT_MAX_PROPERTIES); /* Won't wrap, even shifted by 2. */ + DUK_ASSERT(res > e_size); return res; } else { return 0; @@ -239,7 +243,7 @@ DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES); - res = (e_size + DUK_HOBJECT_E_MIN_GROW_ADD) / DUK_HOBJECT_E_MIN_GROW_DIVISOR; + res = (e_size + DUK_USE_HOBJECT_ENTRY_MINGROW_ADD) / DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR; DUK_ASSERT(res >= 1); /* important for callers */ return res; } @@ -250,7 +254,7 @@ DUK_ASSERT((duk_size_t) a_size <= DUK_HOBJECT_MAX_PROPERTIES); - res = (a_size + DUK_HOBJECT_A_MIN_GROW_ADD) / DUK_HOBJECT_A_MIN_GROW_DIVISOR; + res = (a_size + DUK_USE_HOBJECT_ARRAY_MINGROW_ADD) / DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR; DUK_ASSERT(res >= 1); /* important for callers */ return res; } @@ -325,7 +329,7 @@ * of the check, but may confuse debugging. */ - return (a_used < DUK_HOBJECT_A_ABANDON_LIMIT * (a_size >> 3)); + return (a_used < DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT * (a_size >> 3)); } /* Fast check for extending array: check whether or not a slow density check is required. */ @@ -351,7 +355,7 @@ * arr_idx > limit'' * ((old_size + 7) / 8) */ - return (arr_idx > DUK_HOBJECT_A_FAST_RESIZE_LIMIT * ((old_size + 7) >> 3)); + return (arr_idx > DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT * ((old_size + 7) >> 3)); } /* @@ -503,29 +507,26 @@ /* * Reallocate property allocation, moving properties to the new allocation. * - * Includes key compaction, rehashing, and can also optionally abandoning + * Includes key compaction, rehashing, and can also optionally abandon * the array part, 'migrating' array entries into the beginning of the - * new entry part. Arguments are not validated here, so e.g. new_h_size - * MUST be a valid prime. + * new entry part. * * There is no support for in-place reallocation or just compacting keys * without resizing the property allocation. This is intentional to keep - * code size minimal. + * code size minimal, but would be useful future work. * * The implementation is relatively straightforward, except for the array * abandonment process. Array abandonment requires that new string keys * are interned, which may trigger GC. All keys interned so far must be - * reachable for GC at all times; valstack is used for that now. + * reachable for GC at all times and correctly refcounted for; valstack is + * used for that now. * * Also, a GC triggered during this reallocation process must not interfere - * with the object being resized. This is currently controlled by using - * heap->mark_and_sweep_base_flags to indicate that no finalizers will be - * executed (as they can affect ANY object) and no objects are compacted - * (it would suffice to protect this particular object only, though). - * - * Note: a non-checked variant would be nice but is a bit tricky to - * implement for the array abandonment process. It's easy for - * everything else. + * with the object being resized. This is currently controlled by preventing + * finalizers (as they may affect ANY object) and object compaction in + * mark-and-sweep. It would suffice to protect only this particular object + * from compaction, however. DECREF refzero cascades are side effect free + * and OK. * * Note: because we need to potentially resize the valstack (as part * of abandoning the array part), any tval pointers to the valstack @@ -539,7 +540,7 @@ duk_uint32_t new_h_size, duk_bool_t abandon_array) { duk_context *ctx = (duk_context *) thr; - duk_small_uint_t prev_mark_and_sweep_base_flags; + duk_small_uint_t prev_ms_base_flags; duk_uint32_t new_alloc_size; duk_uint32_t new_e_size_adjusted; duk_uint8_t *new_p; @@ -550,6 +551,10 @@ duk_uint32_t *new_h; duk_uint32_t new_e_next; duk_uint_fast32_t i; + duk_size_t array_copy_size; +#if defined(DUK_USE_ASSERTIONS) + duk_bool_t prev_error_not_allowed; +#endif DUK_ASSERT(thr != NULL); DUK_ASSERT(ctx != NULL); @@ -619,9 +624,8 @@ /* * Property count check. This is the only point where we ensure that * we don't get more (allocated) property space that we can handle. - * There aren't hard limits as such, but some algorithms fail (e.g. - * finding next higher prime, selecting hash part size) if we get too - * close to the 4G property limit. + * There aren't hard limits as such, but some algorithms may fail + * if we get too close to the 4G property limit. * * Since this works based on allocation size (not actually used size), * the limit is a bit approximate but good enough in practice. @@ -634,43 +638,46 @@ /* * Compute new alloc size and alloc new area. * - * The new area is allocated as a dynamic buffer and placed into the - * valstack for reachability. The actual buffer is then detached at - * the end. - * - * Note: heap_mark_and_sweep_base_flags are altered here to ensure - * no-one touches this object while we're resizing and rehashing it. - * The flags must be reset on every exit path after it. Finalizers - * and compaction is prevented currently for all objects while it - * would be enough to restrict it only for the current object. + * The new area is not tracked in the heap at all, so it's critical + * we get to free/keep it in a controlled manner. */ - prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags; - thr->heap->mark_and_sweep_base_flags |= - DUK_MS_FLAG_NO_FINALIZERS | /* avoid attempts to add/remove object keys */ - DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid attempt to compact the current object */ +#if defined(DUK_USE_ASSERTIONS) + /* Whole path must be error throw free, but we may be called from + * within error handling so can't assert for error_not_allowed == 0. + */ + prev_error_not_allowed = thr->heap->error_not_allowed; + thr->heap->error_not_allowed = 1; +#endif + prev_ms_base_flags = thr->heap->ms_base_flags; + thr->heap->ms_base_flags |= + DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* Avoid attempt to compact the current object (all objects really). */ + thr->heap->pf_prevent_count++; /* Avoid finalizers. */ + DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */ new_alloc_size = DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size); DUK_DDD(DUK_DDDPRINT("new hobject allocation size is %ld", (long) new_alloc_size)); if (new_alloc_size == 0) { - /* for zero size, don't push anything on valstack */ DUK_ASSERT(new_e_size_adjusted == 0); DUK_ASSERT(new_a_size == 0); DUK_ASSERT(new_h_size == 0); new_p = NULL; } else { - /* This may trigger mark-and-sweep with arbitrary side effects, - * including an attempted resize of the object we're resizing, - * executing a finalizer which may add or remove properties of - * the object we're resizing etc. - */ - - /* Note: buffer is dynamic so that we can 'steal' the actual - * allocation later. + /* Alloc may trigger mark-and-sweep but no compaction, and + * cannot throw. */ - - new_p = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, new_alloc_size); /* errors out if out of memory */ - DUK_ASSERT(new_p != NULL); /* since new_alloc_size > 0 */ +#if 0 /* XXX: inject test */ + if (1) { + goto alloc_failed; + } +#endif + new_p = (duk_uint8_t *) DUK_ALLOC(thr->heap, new_alloc_size); + if (new_p == NULL) { + /* NULL always indicates alloc failure because + * new_alloc_size > 0. + */ + goto alloc_failed; + } } /* Set up pointers to the new property area: this is hidden behind a macro @@ -691,27 +698,27 @@ (void *) new_a, (void *) new_h)); /* - * Migrate array to start of entries if requested. + * Migrate array part to start of entries if requested. * * Note: from an enumeration perspective the order of entry keys matters. * Array keys should appear wherever they appeared before the array abandon - * operation. + * operation. (This no longer matters much because keys are ES2015 sorted.) */ if (abandon_array) { - /* - * Note: assuming new_a_size == 0, and that entry part contains - * no conflicting keys, refcounts do not need to be adjusted for - * the values, as they remain exactly the same. + /* Assuming new_a_size == 0, and that entry part contains + * no conflicting keys, refcounts do not need to be adjusted for + * the values, as they remain exactly the same. * - * The keys, however, need to be interned, incref'd, and be - * reachable for GC. Any intern attempt may trigger a GC and - * claim any non-reachable strings, so every key must be reachable - * at all times. + * The keys, however, need to be interned, incref'd, and be + * reachable for GC. Any intern attempt may trigger a GC and + * claim any non-reachable strings, so every key must be reachable + * at all times. Refcounts must be correct to satisfy refcount + * assertions. * - * A longjmp must not occur here, as the new_p allocation would - * be freed without these keys being decref'd, hence the messy - * decref handling if intern fails. + * A longjmp must not occur here, as the new_p allocation would + * leak. Refcounts would come out correctly as the interned + * strings are valstack tracked. */ DUK_ASSERT(new_a_size == 0); @@ -740,20 +747,29 @@ * must be careful. */ - /* never shrinks; auto-adds DUK_VALSTACK_INTERNAL_EXTRA, which is generous */ +#if 0 /* XXX: inject test */ + if (1) { + goto abandon_error; + } +#endif + /* Never shrinks; auto-adds DUK_VALSTACK_INTERNAL_EXTRA, which + * is generous. + */ if (!duk_check_stack(ctx, 1)) { goto abandon_error; } DUK_ASSERT_VALSTACK_SPACE(thr, 1); - key = duk_heap_string_intern_u32(thr->heap, i); - if (!key) { + key = duk_heap_strtable_intern_u32(thr->heap, i); + if (key == NULL) { goto abandon_error; } duk_push_hstring(ctx, key); /* keep key reachable for GC etc; guaranteed not to fail */ - /* key is now reachable in the valstack */ + /* Key is now reachable in the valstack, don't INCREF + * the new allocation yet (we'll steal the refcounts + * from the value stack once all keys are done). + */ - DUK_HSTRING_INCREF(thr, key); /* second incref for the entry reference */ new_e_k[new_e_next] = key; tv2 = &new_e_pv[new_e_next].v; /* array entries are all plain values */ DUK_TVAL_SET_TVAL(tv2, tv1); @@ -767,8 +783,9 @@ */ } + /* Steal refcounts from value stack. */ DUK_DDD(DUK_DDDPRINT("abandon array: pop %ld key temps from valstack", (long) new_e_next)); - duk_pop_n(ctx, new_e_next); + duk_pop_n_nodecref_unsafe(ctx, new_e_next); } /* @@ -781,7 +798,7 @@ DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL); key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i); - if (!key) { + if (key == NULL) { continue; } @@ -796,53 +813,46 @@ /* the entries [new_e_next, new_e_size_adjusted[ are left uninitialized on purpose (ok, not gc reachable) */ /* - * Copy array elements to new array part. + * Copy array elements to new array part. If the new array part is + * larger, initialize the unused entries as UNUSED because they are + * GC reachable. */ - if (new_a_size > DUK_HOBJECT_GET_ASIZE(obj)) { - /* copy existing entries as is */ - DUK_ASSERT(new_p != NULL && new_a != NULL); - if (DUK_HOBJECT_GET_ASIZE(obj) > 0) { - /* Avoid zero copy with an invalid pointer. If obj->p is NULL, - * the 'new_a' pointer will be invalid which is not allowed even - * when copy size is zero. - */ - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL); - DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0); - DUK_MEMCPY((void *) new_a, (void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), sizeof(duk_tval) * DUK_HOBJECT_GET_ASIZE(obj)); - } - - /* fill new entries with -unused- (required, gc reachable) */ - for (i = DUK_HOBJECT_GET_ASIZE(obj); i < new_a_size; i++) { - duk_tval *tv = &new_a[i]; - DUK_TVAL_SET_UNUSED(tv); - } - } else { #if defined(DUK_USE_ASSERTIONS) - /* caller must have decref'd values above new_a_size (if that is necessary) */ - if (!abandon_array) { - for (i = new_a_size; i < DUK_HOBJECT_GET_ASIZE(obj); i++) { - duk_tval *tv; - tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i); - - /* current assertion is quite strong: decref's and set to unused */ - DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv)); - } + /* Caller must have decref'd values above new_a_size (if that is necessary). */ + if (!abandon_array) { + for (i = new_a_size; i < DUK_HOBJECT_GET_ASIZE(obj); i++) { + duk_tval *tv; + tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i); + DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv)); } + } #endif - if (new_a_size > 0) { - /* Avoid zero copy with an invalid pointer. If obj->p is NULL, - * the 'new_a' pointer will be invalid which is not allowed even - * when copy size is zero. - */ - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL); - DUK_ASSERT(new_a_size > 0); - DUK_MEMCPY((void *) new_a, (void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), sizeof(duk_tval) * new_a_size); - } + if (new_a_size > DUK_HOBJECT_GET_ASIZE(obj)) { + array_copy_size = sizeof(duk_tval) * DUK_HOBJECT_GET_ASIZE(obj); + } else { + array_copy_size = sizeof(duk_tval) * new_a_size; + } + if (array_copy_size > 0) { + /* Avoid zero copy with an invalid pointer. If obj->p is NULL, + * the 'new_a' pointer will be invalid which is not allowed even + * when copy size is zero. + */ + DUK_ASSERT(new_a != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0); + DUK_MEMCPY((void *) new_a, + (const void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), + array_copy_size); + } + for (i = DUK_HOBJECT_GET_ASIZE(obj); i < new_a_size; i++) { + duk_tval *tv = &new_a[i]; + DUK_TVAL_SET_UNUSED(tv); } /* - * Rebuild the hash part always from scratch (guaranteed to finish). + * Rebuild the hash part always from scratch (guaranteed to finish + * as long as caller gave consistent parameters). * * Any resize of hash part requires rehashing. In addition, by rehashing * get rid of any elements marked deleted (DUK__HASH_DELETED) which is critical @@ -850,7 +860,11 @@ */ #if defined(DUK_USE_HOBJECT_HASH_PART) - if (DUK_UNLIKELY(new_h_size > 0)) { + if (new_h_size == 0) { + DUK_DDD(DUK_DDDPRINT("no hash part, no rehash")); + } else { + duk_uint32_t mask; + DUK_ASSERT(new_h != NULL); /* fill new_h with u32 0xff = UNUSED */ @@ -859,13 +873,15 @@ DUK_MEMSET(new_h, 0xff, sizeof(duk_uint32_t) * new_h_size); DUK_ASSERT(new_e_next <= new_h_size); /* equality not actually possible */ + + mask = new_h_size - 1; for (i = 0; i < new_e_next; i++) { duk_hstring *key = new_e_k[i]; duk_uint32_t j, step; DUK_ASSERT(key != NULL); - j = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), new_h_size); - step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key)); + j = DUK_HSTRING_GET_HASH(key) & mask; + step = 1; /* Cache friendly but clustering prone. */ for (;;) { DUK_ASSERT(new_h[j] != DUK__HASH_DELETED); /* should never happen */ @@ -875,14 +891,11 @@ break; } DUK_DDD(DUK_DDDPRINT("rebuild miss %ld, step %ld", (long) j, (long) step)); - j = (j + step) % new_h_size; + j = (j + step) & mask; - /* guaranteed to finish */ - DUK_ASSERT(j != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), new_h_size)); + /* Guaranteed to finish (hash is larger than #props). */ } } - } else { - DUK_DDD(DUK_DDDPRINT("no hash part, no rehash")); } #endif /* DUK_USE_HOBJECT_HASH_PART */ @@ -921,30 +934,20 @@ DUK_HOBJECT_SET_ASIZE(obj, new_a_size); DUK_HOBJECT_SET_HSIZE(obj, new_h_size); - if (new_p) { - /* - * Detach actual buffer from dynamic buffer in valstack, and - * pop it from the stack. - * - * XXX: the buffer object is certainly not reachable at this point, - * so it would be nice to free it forcibly even with only - * mark-and-sweep enabled. Not a big issue though. - */ - (void) duk_steal_buffer(ctx, -1, NULL); - duk_pop(ctx); - } else { - DUK_ASSERT(new_alloc_size == 0); - /* no need to pop, nothing was pushed */ - } - - /* clear array part flag only after switching */ + /* Clear array part flag only after switching. */ if (abandon_array) { DUK_HOBJECT_CLEAR_ARRAY_PART(obj); } DUK_DDD(DUK_DDDPRINT("resize result: %!O", (duk_heaphdr *) obj)); - thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; + DUK_ASSERT(thr->heap->pf_prevent_count > 0); + thr->heap->pf_prevent_count--; + thr->heap->ms_base_flags = prev_ms_base_flags; +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(thr->heap->error_not_allowed == 1); + thr->heap->error_not_allowed = prev_error_not_allowed; +#endif /* * Post resize assertions. @@ -956,21 +959,25 @@ return; /* - * Abandon array failed, need to decref keys already inserted - * into the beginning of new_e_k before unwinding valstack. + * Abandon array failed. We don't need to DECREF anything + * because the references in the new allocation are not + * INCREF'd until abandon is complete. The string interned + * keys are on the value stack and are handled normally by + * unwind. */ abandon_error: - DUK_D(DUK_DPRINT("hobject resize failed during abandon array, decref keys")); - i = new_e_next; - while (i > 0) { - i--; - DUK_ASSERT(new_e_k != NULL); - DUK_ASSERT(new_e_k[i] != NULL); - DUK_HSTRING_DECREF(thr, new_e_k[i]); /* side effects */ - } + alloc_failed: + DUK_D(DUK_DPRINT("object property table resize failed")); - thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; + DUK_FREE(thr->heap, new_p); /* OK for NULL. */ + + thr->heap->pf_prevent_count--; + thr->heap->ms_base_flags = prev_ms_base_flags; +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(thr->heap->error_not_allowed == 1); + thr->heap->error_not_allowed = prev_error_not_allowed; +#endif DUK_ERROR_ALLOC_FAILED(thr); } @@ -1122,7 +1129,7 @@ } #if defined(DUK_USE_HOBJECT_HASH_PART) - if (e_size >= DUK_HOBJECT_E_USE_HASH_LIMIT) { + if (e_size >= DUK_USE_HOBJECT_HASH_PROP_LIMIT) { h_size = duk__get_default_h_size(e_size); } else { h_size = 0; @@ -1183,13 +1190,15 @@ duk_uint32_t n; duk_uint32_t i, step; duk_uint32_t *h_base; + duk_uint32_t mask; DUK_DDD(DUK_DDDPRINT("duk_hobject_find_existing_entry() using hash part for lookup")); h_base = DUK_HOBJECT_H_GET_BASE(heap, obj); n = DUK_HOBJECT_GET_HSIZE(obj); - i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n); - step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key)); + mask = n - 1; + i = DUK_HSTRING_GET_HASH(key) & mask; + step = 1; /* Cache friendly but clustering prone. */ for (;;) { duk_uint32_t t; @@ -1217,10 +1226,9 @@ DUK_DDD(DUK_DDDPRINT("lookup miss i=%ld, t=%ld", (long) i, (long) t)); } - i = (i + step) % n; + i = (i + step) & mask; - /* guaranteed to finish, as hash is never full */ - DUK_ASSERT(i != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n)); + /* Guaranteed to finish (hash is larger than #props). */ } } #endif /* DUK_USE_HOBJECT_HASH_PART */ @@ -1325,13 +1333,14 @@ #if defined(DUK_USE_HOBJECT_HASH_PART) if (DUK_UNLIKELY(DUK_HOBJECT_GET_HSIZE(obj) > 0)) { - duk_uint32_t n; + duk_uint32_t n, mask; duk_uint32_t i, step; duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(thr->heap, obj); n = DUK_HOBJECT_GET_HSIZE(obj); - i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n); - step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key)); + mask = n - 1; + i = DUK_HSTRING_GET_HASH(key) & mask; + step = 1; /* Cache friendly but clustering prone. */ for (;;) { duk_uint32_t t = h_base[i]; @@ -1346,10 +1355,9 @@ break; } DUK_DDD(DUK_DDDPRINT("duk__alloc_entry_checked() miss %ld", (long) i)); - i = (i + step) % n; + i = (i + step) & mask; - /* guaranteed to find an empty slot */ - DUK_ASSERT(i != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), DUK_HOBJECT_GET_HSIZE(obj))); + /* Guaranteed to finish (hash is larger than #props). */ } } #endif /* DUK_USE_HOBJECT_HASH_PART */ @@ -1749,6 +1757,8 @@ DUK_DDD(DUK_DDDPRINT("string object exotic property get for key: %!O, arr_idx: %ld", (duk_heaphdr *) key, (long) arr_idx)); + /* XXX: charlen; avoid multiple lookups? */ + if (arr_idx != DUK__NO_ARRAY_INDEX) { duk_hstring *h_val; @@ -1989,7 +1999,7 @@ } /* not found in 'curr', next in prototype chain; impose max depth */ - if (sanity-- == 0) { + if (DUK_UNLIKELY(sanity-- == 0)) { if (flags & DUK_GETDESC_FLAG_IGNORE_PROTOLOOP) { /* treat like property not found */ break; @@ -1998,7 +2008,7 @@ } } curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); - } while (curr); + } while (curr != NULL); /* out_desc is left untouched (possibly garbage), caller must use return * value to determine whether out_desc can be looked up @@ -2348,7 +2358,7 @@ duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj); duk_int_t pop_count; - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { /* Symbols (ES2015 or hidden) don't have virtual properties. */ DUK_DDD(DUK_DDDPRINT("base object is a symbol, start lookup from symbol prototype")); curr = thr->builtins[DUK_BIDX_SYMBOL_PROTOTYPE]; @@ -2689,11 +2699,11 @@ /* XXX: option to pretend property doesn't exist if sanity limit is * hit might be useful. */ - if (sanity-- == 0) { + if (DUK_UNLIKELY(sanity-- == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); } curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); - } while (curr); + } while (curr != NULL); /* * Not found @@ -3373,7 +3383,7 @@ arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key); DUK_ASSERT(key != NULL); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { /* Symbols (ES2015 or hidden) don't have virtual properties. */ curr = thr->builtins[DUK_BIDX_SYMBOL_PROTOTYPE]; goto lookup; @@ -3789,11 +3799,11 @@ /* XXX: option to pretend property doesn't exist if sanity limit is * hit might be useful. */ - if (sanity-- == 0) { + if (DUK_UNLIKELY(sanity-- == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); } curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); - } while (curr); + } while (curr != NULL); /* * Property not found in prototype chain. @@ -4420,10 +4430,10 @@ /* Note: proxy handling must happen before key is string coerced. */ if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_DELETE_PROPERTY, tv_key, &h_target)) { - /* -> [ ... trap handler ] */ + /* -> [ ... obj key trap handler ] */ DUK_DDD(DUK_DDDPRINT("-> proxy object 'deleteProperty' for key %!T", (duk_tval *) tv_key)); duk_push_hobject(ctx, h_target); /* target */ - duk_push_tval(ctx, tv_key); /* P */ + duk_dup_m4(ctx); /* P */ duk_call_method(ctx, 2 /*nargs*/); tmp_bool = duk_to_boolean(ctx, -1); duk_pop(ctx); @@ -4434,6 +4444,7 @@ /* Target object must be checked for a conflicting * non-configurable property. */ + tv_key = DUK_GET_TVAL_NEGIDX(ctx, -1); arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key); DUK_ASSERT(key != NULL); @@ -4781,6 +4792,41 @@ return 0; } +/* + * Fast finalizer check for an object. Walks the prototype chain, checking + * for finalizer presence using DUK_HOBJECT_FLAG_HAVE_FINALIZER which is kept + * in sync with the actual property when setting/removing the finalizer. + */ + +#if defined(DUK_USE_HEAPPTR16) +DUK_INTERNAL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_heap *heap, duk_hobject *obj) { +#else +DUK_INTERNAL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_hobject *obj) { +#endif + duk_uint_t sanity; + + DUK_ASSERT(obj != NULL); + + sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; + do { + if (DUK_UNLIKELY(DUK_HOBJECT_HAS_HAVE_FINALIZER(obj))) { + return 1; + } + if (DUK_UNLIKELY(sanity-- == 0)) { + DUK_D(DUK_DPRINT("prototype loop when checking for finalizer existence; returning false")); + return 0; + } +#if defined(DUK_USE_HEAPPTR16) + DUK_ASSERT(heap != NULL); + obj = DUK_HOBJECT_GET_PROTOTYPE(heap, obj); +#else + obj = DUK_HOBJECT_GET_PROTOTYPE(NULL, obj); /* 'heap' arg ignored */ +#endif + } while (obj != NULL); + + return 0; +} + /* * Object.getOwnPropertyDescriptor() (E5 Sections 15.2.3.3, 8.10.4) * diff -Nru duktape-2.0.0/src-separate/duk_hstring.h duktape-2.1.1/src-separate/duk_hstring.h --- duktape-2.0.0/src-separate/duk_hstring.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_hstring.h 2017-07-28 22:05:08.000000000 +0000 @@ -79,7 +79,7 @@ */ #define DUK_HSTRING_IS_ASCII(x) (DUK_HSTRING_GET_BYTELEN((x)) == DUK_HSTRING_GET_CHARLEN((x))) #endif -#define DUK_HSTRING_IS_ASCII(x) DUK_HSTRING_HAS_ASCII((x)) +#define DUK_HSTRING_IS_ASCII(x) DUK_HSTRING_HAS_ASCII((x)) /* lazily set! */ #define DUK_HSTRING_IS_EMPTY(x) (DUK_HSTRING_GET_BYTELEN((x)) == 0) #if defined(DUK_USE_STRHASH16) @@ -100,7 +100,7 @@ (x)->hdr.h_strextra16 = (v); \ } while (0) #if defined(DUK_USE_HSTRING_CLEN) -#define DUK_HSTRING_GET_CHARLEN(x) ((x)->clen16) +#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x)) #define DUK_HSTRING_SET_CHARLEN(x,v) do { \ (x)->clen16 = (v); \ } while (0) @@ -115,7 +115,7 @@ #define DUK_HSTRING_SET_BYTELEN(x,v) do { \ (x)->blen = (v); \ } while (0) -#define DUK_HSTRING_GET_CHARLEN(x) ((x)->clen) +#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x)) #define DUK_HSTRING_SET_CHARLEN(x,v) do { \ (x)->clen = (v); \ } while (0) @@ -146,11 +146,11 @@ * avoids helper call if string has no array index value. */ #define DUK_HSTRING_GET_ARRIDX_FAST(h) \ - (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_string_helper((h)) : DUK_HSTRING_NO_ARRAY_INDEX) + (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_hstring_fast_known((h)) : DUK_HSTRING_NO_ARRAY_INDEX) /* Slower but more compact variant. */ #define DUK_HSTRING_GET_ARRIDX_SLOW(h) \ - (duk_js_to_arrayindex_string_helper((h))) + (duk_js_to_arrayindex_hstring_fast((h))) #endif /* @@ -165,30 +165,26 @@ */ duk_heaphdr_string hdr; - /* Note: we could try to stuff a partial hash (e.g. 16 bits) into the - * shared heap header. Good hashing needs more hash bits though. - */ - - /* string hash */ + /* String hash. */ #if defined(DUK_USE_STRHASH16) /* If 16-bit hash is in use, stuff it into duk_heaphdr_string flags. */ #else duk_uint32_t hash; #endif - /* precomputed array index (or DUK_HSTRING_NO_ARRAY_INDEX) */ + /* Precomputed array index (or DUK_HSTRING_NO_ARRAY_INDEX). */ #if defined(DUK_USE_HSTRING_ARRIDX) duk_uarridx_t arridx; #endif - /* length in bytes (not counting NUL term) */ + /* Length in bytes (not counting NUL term). */ #if defined(DUK_USE_STRLEN16) /* placed in duk_heaphdr_string */ #else duk_uint32_t blen; #endif - /* length in codepoints (must be E5 compatible) */ + /* Length in codepoints (must be E5 compatible). */ #if defined(DUK_USE_STRLEN16) #if defined(DUK_USE_HSTRING_CLEN) duk_uint16_t clen16; @@ -200,7 +196,7 @@ #endif /* - * String value of 'blen+1' bytes follows (+1 for NUL termination + * String data of 'blen+1' bytes follows (+1 for NUL termination * convenience for C API). No alignment needs to be guaranteed * for strings, but fields above should guarantee alignment-by-4 * (but not alignment-by-8). @@ -225,9 +221,6 @@ */ DUK_INTERNAL_DECL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos, duk_bool_t surrogate_aware); - -#if !defined(DUK_USE_HSTRING_CLEN) DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h); -#endif #endif /* DUK_HSTRING_H_INCLUDED */ diff -Nru duktape-2.0.0/src-separate/duk_hstring_misc.c duktape-2.1.1/src-separate/duk_hstring_misc.c --- duktape-2.0.0/src-separate/duk_hstring_misc.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_hstring_misc.c 2017-07-28 22:05:08.000000000 +0000 @@ -4,6 +4,10 @@ #include "duk_internal.h" +/* + * duk_hstring charCodeAt, with and without surrogate awareness + */ + DUK_INTERNAL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos, duk_bool_t surrogate_aware) { duk_uint32_t boff; const duk_uint8_t *p, *p_start, *p_end; @@ -51,13 +55,84 @@ return cp1; } -#if !defined(DUK_USE_HSTRING_CLEN) -DUK_INTERNAL duk_size_t duk_hstring_get_charlen(duk_hstring *h) { - if (DUK_HSTRING_HAS_ASCII(h)) { +/* + * duk_hstring charlen access + */ + +#if defined(DUK_USE_HSTRING_CLEN) +DUK_LOCAL DUK_COLD duk_size_t duk__hstring_get_charlen_slowpath(duk_hstring *h) { + duk_size_t res; + + DUK_ASSERT(h->clen == 0); /* Checked by caller. */ + +#if defined(DUK_USE_ROM_STRINGS) + /* ROM strings have precomputed clen, but if the computed clen is zero + * we can still come here and can't write anything. + */ + if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { + return 0; + } +#endif + + res = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); +#if defined(DUK_USE_STRLEN16) + DUK_ASSERT(res <= 0xffffUL); /* Bytelength checked during interning. */ + h->clen16 = (duk_uint16_t) res; +#else + h->clen = (duk_uint32_t) res; +#endif + if (DUK_LIKELY(res == DUK_HSTRING_GET_BYTELEN(h))) { + DUK_HSTRING_SET_ASCII(h); + } + return res; +} +#else /* DUK_USE_HSTRING_CLEN */ +DUK_LOCAL duk_size_t duk__hstring_get_charlen_slowpath(duk_hstring *h) { + if (DUK_LIKELY(DUK_HSTRING_HAS_ASCII(h))) { /* Most practical strings will go here. */ return DUK_HSTRING_GET_BYTELEN(h); } else { - return duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); + /* ASCII flag is lazy, so set it here. */ + duk_size_t res; + + /* XXX: here we could use the strcache to speed up the + * computation (matters for 'i < str.length' loops). + */ + + res = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); + +#if defined(DUK_USE_ROM_STRINGS) + if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { + /* For ROM strings, can't write anything; ASCII flag + * is preset so we don't need to update it. + */ + return res; + } +#endif + if (DUK_LIKELY(res == DUK_HSTRING_GET_BYTELEN(h))) { + DUK_HSTRING_SET_ASCII(h); + } + return res; } } -#endif /* !DUK_USE_HSTRING_CLEN */ +#endif /* DUK_USE_HSTRING_CLEN */ + +#if defined(DUK_USE_HSTRING_CLEN) +DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) { +#if defined(DUK_USE_STRLEN16) + if (DUK_LIKELY(h->clen16 != 0)) { + return h->clen16; + } +#else + if (DUK_LIKELY(h->clen != 0)) { + return h->clen; + } +#endif + return duk__hstring_get_charlen_slowpath(h); +} +#else /* DUK_USE_HSTRING_CLEN */ +DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) { + /* Always use slow path. */ + return duk__hstring_get_charlen_slowpath(h); +} +#endif /* DUK_USE_HSTRING_CLEN */ diff -Nru duktape-2.0.0/src-separate/duk_hthread_alloc.c duktape-2.1.1/src-separate/duk_hthread_alloc.c --- duktape-2.0.0/src-separate/duk_hthread_alloc.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_hthread_alloc.c 2017-07-28 22:05:08.000000000 +0000 @@ -21,6 +21,7 @@ DUK_ASSERT(thr->valstack_bottom == NULL); DUK_ASSERT(thr->valstack_top == NULL); DUK_ASSERT(thr->callstack == NULL); + DUK_ASSERT(thr->callstack_curr == NULL); DUK_ASSERT(thr->catchstack == NULL); /* valstack */ @@ -50,6 +51,7 @@ DUK_MEMZERO(thr->callstack, alloc_size); thr->callstack_size = DUK_CALLSTACK_INITIAL_SIZE; DUK_ASSERT(thr->callstack_top == 0); + DUK_ASSERT(thr->callstack_curr == NULL); /* catchstack */ alloc_size = sizeof(duk_catcher) * DUK_CATCHSTACK_INITIAL_SIZE; diff -Nru duktape-2.0.0/src-separate/duk_hthread_builtins.c duktape-2.1.1/src-separate/duk_hthread_builtins.c --- duktape-2.0.0/src-separate/duk_hthread_builtins.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_hthread_builtins.c 2017-07-28 22:05:08.000000000 +0000 @@ -35,12 +35,13 @@ #if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT) DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) { duk_context *ctx; - duk_hobject *h1; + duk_hobject *h_global; #if defined(DUK_USE_ROM_GLOBAL_CLONE) - duk_hobject *h2; + duk_hobject *h_oldglobal; duk_uint8_t *props; duk_size_t alloc_size; #endif + duk_hobject *h_objenv; ctx = (duk_context *) thr; @@ -48,83 +49,84 @@ #if defined(DUK_USE_ROM_GLOBAL_INHERIT) /* Inherit from ROM-based global object: less RAM usage, less transparent. */ - h1 = duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL), - DUK_BIDX_GLOBAL); - DUK_ASSERT(h1 != NULL); + h_global = duk_push_object_helper(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL), + DUK_BIDX_GLOBAL); + DUK_ASSERT(h_global != NULL); #elif defined(DUK_USE_ROM_GLOBAL_CLONE) /* Clone the properties of the ROM-based global object to create a * fully RAM-based global object. Uses more memory than the inherit * model but more compliant. */ - h1 = duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL), - DUK_BIDX_OBJECT_PROTOTYPE); - DUK_ASSERT(h1 != NULL); - h2 = thr->builtins[DUK_BIDX_GLOBAL]; - DUK_ASSERT(h2 != NULL); + h_global = duk_push_object_helper(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL), + DUK_BIDX_OBJECT_PROTOTYPE); + DUK_ASSERT(h_global != NULL); + h_oldglobal = thr->builtins[DUK_BIDX_GLOBAL]; + DUK_ASSERT(h_oldglobal != NULL); /* Copy the property table verbatim; this handles attributes etc. * For ROM objects it's not necessary (or possible) to update * refcounts so leave them as is. */ - alloc_size = DUK_HOBJECT_P_ALLOC_SIZE(h2); + alloc_size = DUK_HOBJECT_P_ALLOC_SIZE(h_oldglobal); DUK_ASSERT(alloc_size > 0); - props = DUK_ALLOC(thr->heap, alloc_size); - if (!props) { - DUK_ERROR_ALLOC_FAILED(thr); - return; - } - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h2) != NULL); - DUK_MEMCPY((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h2), alloc_size); + props = DUK_ALLOC_CHECKED(thr, alloc_size); + DUK_ASSERT(props != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal) != NULL); + DUK_MEMCPY((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal), alloc_size); /* XXX: keep property attributes or tweak them here? * Properties will now be non-configurable even when they're * normally configurable for the global object. */ - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h1) == NULL); - DUK_HOBJECT_SET_PROPS(thr->heap, h1, props); - DUK_HOBJECT_SET_ESIZE(h1, DUK_HOBJECT_GET_ESIZE(h2)); - DUK_HOBJECT_SET_ENEXT(h1, DUK_HOBJECT_GET_ENEXT(h2)); - DUK_HOBJECT_SET_ASIZE(h1, DUK_HOBJECT_GET_ASIZE(h2)); - DUK_HOBJECT_SET_HSIZE(h1, DUK_HOBJECT_GET_HSIZE(h2)); + DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h_global) == NULL); + DUK_HOBJECT_SET_PROPS(thr->heap, h_global, props); + DUK_HOBJECT_SET_ESIZE(h_global, DUK_HOBJECT_GET_ESIZE(h_oldglobal)); + DUK_HOBJECT_SET_ENEXT(h_global, DUK_HOBJECT_GET_ENEXT(h_oldglobal)); + DUK_HOBJECT_SET_ASIZE(h_global, DUK_HOBJECT_GET_ASIZE(h_oldglobal)); + DUK_HOBJECT_SET_HSIZE(h_global, DUK_HOBJECT_GET_HSIZE(h_oldglobal)); #else -#error internal error in defines +#error internal error in config defines #endif - duk_hobject_compact_props(thr, h1); + duk_hobject_compact_props(thr, h_global); DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); - DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL])); /* no need to decref */ - thr->builtins[DUK_BIDX_GLOBAL] = h1; - DUK_HOBJECT_INCREF(thr, h1); - DUK_D(DUK_DPRINT("duplicated global object: %!O", h1)); - + DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL])); /* no need to decref: ROM object */ + thr->builtins[DUK_BIDX_GLOBAL] = h_global; + DUK_HOBJECT_INCREF(thr, h_global); + DUK_D(DUK_DPRINT("duplicated global object: %!O", h_global)); /* Create a fresh object environment for the global scope. This is * needed so that the global scope points to the newly created RAM-based * global object. */ - h1 = duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV), - -1); /* no prototype */ - DUK_ASSERT(h1 != NULL); - duk_dup_m2(ctx); - duk_dup_top(ctx); /* -> [ ... new_global new_globalenv new_global new_global ] */ - duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); /* always provideThis=true */ + h_objenv = (duk_hobject *) duk_hobjenv_alloc(thr, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV)); + DUK_ASSERT(h_objenv != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_objenv) == NULL); + duk_push_hobject(ctx, h_objenv); + + DUK_ASSERT(h_global != NULL); + ((duk_hobjenv *) h_objenv)->target = h_global; + DUK_HOBJECT_INCREF(thr, h_global); + DUK_ASSERT(((duk_hobjenv *) h_objenv)->has_this == 0); - duk_hobject_compact_props(thr, h1); DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL); - DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL_ENV])); /* no need to decref */ - thr->builtins[DUK_BIDX_GLOBAL_ENV] = h1; - DUK_HOBJECT_INCREF(thr, h1); - DUK_D(DUK_DPRINT("duplicated global env: %!O", h1)); + DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL_ENV])); /* no need to decref: ROM object */ + thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_objenv; + DUK_HOBJECT_INCREF(thr, h_objenv); + DUK_D(DUK_DPRINT("duplicated global env: %!O", h_objenv)); - duk_pop_2(ctx); + DUK_ASSERT_HOBJENV_VALID((duk_hobjenv *) h_objenv); + + duk_pop_2(ctx); /* Pop global object and global env. */ } #endif /* DUK_USE_ROM_GLOBAL_CLONE || DUK_USE_ROM_GLOBAL_INHERIT */ @@ -230,11 +232,11 @@ duk_small_int_t len = -1; /* must be signed */ class_num = (duk_small_uint_t) duk_bd_decode_varuint(bd); - len = (duk_small_int_t) duk_bd_decode_flagged(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/); + len = (duk_small_int_t) duk_bd_decode_flagged_signed(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/); if (class_num == DUK_HOBJECT_CLASS_FUNCTION) { duk_small_uint_t natidx; - duk_int_t c_nargs; /* must hold DUK_VARARGS */ + duk_small_int_t c_nargs; /* must hold DUK_VARARGS */ duk_c_function c_func; duk_int16_t magic; @@ -246,7 +248,7 @@ c_func = duk_bi_native_functions[natidx]; DUK_ASSERT(c_func != NULL); - c_nargs = (duk_small_uint_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, len /*def_value*/); + c_nargs = (duk_small_int_t) duk_bd_decode_flagged_signed(bd, DUK__NARGS_BITS, len /*def_value*/); if (c_nargs == DUK__NARGS_VARARGS_MARKER) { c_nargs = DUK_VARARGS; } @@ -289,8 +291,31 @@ ((duk_hnatfunc *) h)->magic = magic; } else if (class_num == DUK_HOBJECT_CLASS_ARRAY) { duk_push_array(ctx); + } else if (class_num == DUK_HOBJECT_CLASS_OBJENV) { + duk_hobjenv *env; + duk_hobject *global; + + DUK_ASSERT(i == DUK_BIDX_GLOBAL_ENV); + DUK_ASSERT(DUK_BIDX_GLOBAL_ENV > DUK_BIDX_GLOBAL); + + env = duk_hobjenv_alloc(thr, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV)); + DUK_ASSERT(env->target == NULL); + duk_push_hobject(ctx, (duk_hobject *) env); + + global = duk_known_hobject(ctx, DUK_BIDX_GLOBAL); + DUK_ASSERT(global != NULL); + env->target = global; + DUK_HOBJECT_INCREF(thr, global); + DUK_ASSERT(env->has_this == 0); + + DUK_ASSERT_HOBJENV_VALID(env); } else { + DUK_ASSERT(class_num != DUK_HOBJECT_CLASS_DECENV); + (void) duk_push_object_helper(ctx, + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_EXTENSIBLE, -1); /* no prototype or class yet */ @@ -339,14 +364,13 @@ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_COMPFUNC(h)); /* DUK_HOBJECT_FLAG_NATFUNC varies */ - DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(h)); + DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(h) || class_num == DUK_HOBJECT_CLASS_ARRAY); /* DUK_HOBJECT_FLAG_STRICT varies */ DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(h) || /* all native functions have NEWENV */ DUK_HOBJECT_HAS_NEWENV(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(h)); - DUK_ASSERT(!DUK_HOBJECT_HAS_ENVRECCLOSED(h)); /* DUK_HOBJECT_FLAG_EXOTIC_ARRAY varies */ /* DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ varies */ DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h)); @@ -695,12 +719,8 @@ #endif " " /* Low memory options */ -#if defined(DUK_USE_STRTAB_CHAIN) - "c" /* chain */ -#elif defined(DUK_USE_STRTAB_PROBE) - "p" /* probe */ -#else - "?" +#if defined(DUK_USE_STRTAB_PTRCOMP) + "s" #endif #if !defined(DUK_USE_HEAPPTR16) && !defined(DUK_DATAPTR16) && !defined(DUK_FUNCPTR16) "n" diff -Nru duktape-2.0.0/src-separate/duk_hthread.h duktape-2.1.1/src-separate/duk_hthread.h --- duktape-2.0.0/src-separate/duk_hthread.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_hthread.h 2017-07-28 22:05:08.000000000 +0000 @@ -134,8 +134,6 @@ #endif #endif /* DUK_USE_ROM_STRINGS */ -#define DUK_HTHREAD_GET_CURRENT_ACTIVATION(thr) (&(thr)->callstack[(thr)->callstack_top - 1]) - /* values for the state field */ #define DUK_HTHREAD_STATE_INACTIVE 1 /* thread not currently running */ #define DUK_HTHREAD_STATE_RUNNING 2 /* thread currently running (only one at a time) */ @@ -317,8 +315,9 @@ /* Call stack. [0,callstack_top[ is GC reachable. */ duk_activation *callstack; + duk_activation *callstack_curr; /* current activation (or NULL if none) */ duk_size_t callstack_size; /* allocation size */ - duk_size_t callstack_top; /* next to use, highest used is top - 1 */ + duk_size_t callstack_top; /* next to use, highest used is top - 1 (or none if top == 0) */ duk_size_t callstack_preventcount; /* number of activation records in callstack preventing a yield */ /* Catch stack. [0,catchstack_top[ is GC reachable. */ @@ -380,12 +379,19 @@ DUK_INTERNAL_DECL void duk_hthread_callstack_grow(duk_hthread *thr); DUK_INTERNAL_DECL void duk_hthread_callstack_shrink_check(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_hthread_callstack_unwind_norz(duk_hthread *thr, duk_size_t new_top); DUK_INTERNAL_DECL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top); DUK_INTERNAL_DECL void duk_hthread_catchstack_grow(duk_hthread *thr); DUK_INTERNAL_DECL void duk_hthread_catchstack_shrink_check(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_hthread_catchstack_unwind_norz(duk_hthread *thr, duk_size_t new_top); DUK_INTERNAL_DECL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top); -DUK_INTERNAL_DECL duk_activation *duk_hthread_get_current_activation(duk_hthread *thr); +#if defined(DUK_USE_FINALIZER_TORTURE) +DUK_INTERNAL_DECL void duk_hthread_valstack_torture_realloc(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_hthread_callstack_torture_realloc(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_hthread_catchstack_torture_realloc(duk_hthread *thr); +#endif + DUK_INTERNAL_DECL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */ DUK_INTERNAL_DECL void *duk_hthread_get_callstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */ DUK_INTERNAL_DECL void *duk_hthread_get_catchstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */ diff -Nru duktape-2.0.0/src-separate/duk_hthread_misc.c duktape-2.1.1/src-separate/duk_hthread_misc.c --- duktape-2.0.0/src-separate/duk_hthread_misc.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_hthread_misc.c 2017-07-28 22:05:08.000000000 +0000 @@ -10,7 +10,6 @@ /* Order of unwinding is important */ duk_hthread_catchstack_unwind(thr, 0); - duk_hthread_callstack_unwind(thr, 0); /* side effects, possibly errors */ thr->valstack_bottom = thr->valstack; @@ -33,16 +32,6 @@ */ } -DUK_INTERNAL duk_activation *duk_hthread_get_current_activation(duk_hthread *thr) { - DUK_ASSERT(thr != NULL); - - if (thr->callstack_top > 0) { - return thr->callstack + thr->callstack_top - 1; - } else { - return NULL; - } -} - #if defined(DUK_USE_DEBUGGER_SUPPORT) DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act) { duk_instr_t *bcode; @@ -88,7 +77,9 @@ if (thr->ptr_curr_pc != NULL) { /* ptr_curr_pc != NULL only when bytecode executor is active. */ DUK_ASSERT(thr->callstack_top > 0); - act = thr->callstack + thr->callstack_top - 1; + DUK_ASSERT(thr->callstack_curr != NULL); + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); act->curr_pc = *thr->ptr_curr_pc; } } @@ -101,7 +92,9 @@ if (thr->ptr_curr_pc != NULL) { /* ptr_curr_pc != NULL only when bytecode executor is active. */ DUK_ASSERT(thr->callstack_top > 0); - act = thr->callstack + thr->callstack_top - 1; + DUK_ASSERT(thr->callstack_curr != NULL); + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); act->curr_pc = *thr->ptr_curr_pc; thr->ptr_curr_pc = NULL; } diff -Nru duktape-2.0.0/src-separate/duk_hthread_stacks.c duktape-2.1.1/src-separate/duk_hthread_stacks.c --- duktape-2.0.0/src-separate/duk_hthread_stacks.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_hthread_stacks.c 2017-07-28 22:05:08.000000000 +0000 @@ -22,8 +22,7 @@ #include "duk_internal.h" -/* check that there is space for at least one new entry */ -DUK_INTERNAL void duk_hthread_callstack_grow(duk_hthread *thr) { +DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__hthread_do_callstack_grow(duk_hthread *thr) { duk_activation *new_ptr; duk_size_t old_size; duk_size_t new_size; @@ -32,10 +31,6 @@ DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */ DUK_ASSERT(thr->callstack_size >= thr->callstack_top); - if (thr->callstack_top < thr->callstack_size) { - return; - } - old_size = thr->callstack_size; new_size = old_size + DUK_CALLSTACK_GROW_STEP; @@ -60,10 +55,28 @@ thr->callstack = new_ptr; thr->callstack_size = new_size; + if (thr->callstack_top > 0) { + thr->callstack_curr = thr->callstack + thr->callstack_top - 1; + } else { + thr->callstack_curr = NULL; + } + /* note: any entries above the callstack top are garbage and not zeroed */ } -DUK_INTERNAL void duk_hthread_callstack_shrink_check(duk_hthread *thr) { +/* check that there is space for at least one new entry */ +DUK_INTERNAL void duk_hthread_callstack_grow(duk_hthread *thr) { + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */ + DUK_ASSERT(thr->callstack_size >= thr->callstack_top); + + if (DUK_LIKELY(thr->callstack_top < thr->callstack_size)) { + return; + } + duk__hthread_do_callstack_grow(thr); +} + +DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__hthread_do_callstack_shrink(duk_hthread *thr) { duk_size_t new_size; duk_activation *p; @@ -71,10 +84,6 @@ DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */ DUK_ASSERT(thr->callstack_size >= thr->callstack_top); - if (thr->callstack_size - thr->callstack_top < DUK_CALLSTACK_SHRINK_THRESHOLD) { - return; - } - new_size = thr->callstack_top + DUK_CALLSTACK_SHRINK_SPARE; DUK_ASSERT(new_size >= thr->callstack_top); @@ -90,6 +99,12 @@ if (p) { thr->callstack = p; thr->callstack_size = new_size; + + if (thr->callstack_top > 0) { + thr->callstack_curr = thr->callstack + thr->callstack_top - 1; + } else { + thr->callstack_curr = NULL; + } } else { /* Because new_size != 0, if condition doesn't need to be * (p != NULL || new_size == 0). @@ -101,7 +116,19 @@ /* note: any entries above the callstack top are garbage and not zeroed */ } -DUK_INTERNAL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top) { +DUK_INTERNAL void duk_hthread_callstack_shrink_check(duk_hthread *thr) { + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */ + DUK_ASSERT(thr->callstack_size >= thr->callstack_top); + + if (DUK_LIKELY(thr->callstack_size - thr->callstack_top < DUK_CALLSTACK_SHRINK_THRESHOLD)) { + return; + } + + duk__hthread_do_callstack_shrink(thr); +} + +DUK_INTERNAL void duk_hthread_callstack_unwind_norz(duk_hthread *thr, duk_size_t new_top) { duk_size_t idx; DUK_DDD(DUK_DDDPRINT("unwind callstack top of thread %p from %ld to %ld", @@ -130,9 +157,7 @@ while (idx > new_top) { duk_activation *act; duk_hobject *func; -#if defined(DUK_USE_REFERENCE_COUNTING) duk_hobject *tmp; -#endif #if defined(DUK_USE_DEBUGGER_SUPPORT) duk_heap *heap; #endif @@ -174,12 +199,12 @@ DUK_TVAL_SET_NULL(tv_caller); /* no incref needed */ DUK_ASSERT(act->prev_caller == NULL); } - DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */ + DUK_TVAL_DECREF_NORZ(thr, &tv_tmp); } else { h_tmp = act->prev_caller; if (h_tmp) { act->prev_caller = NULL; - DUK_HOBJECT_DECREF(thr, h_tmp); /* side effects */ + DUK_HOBJECT_DECREF_NORZ(thr, h_tmp); } } act = thr->callstack + idx; /* avoid side effects */ @@ -199,8 +224,12 @@ /* Pause for all step types: step into, step over, step out. * This is the only place explicitly handling a step out. */ - DUK_HEAP_SET_PAUSED(heap); - DUK_ASSERT(heap->dbg_step_thread == NULL); + if (duk_debug_is_paused(heap)) { + DUK_D(DUK_DPRINT("step pause trigger but already paused, ignoring")); + } else { + duk_debug_set_paused(heap); + DUK_ASSERT(heap->dbg_step_thread == NULL); + } } #endif @@ -221,42 +250,19 @@ } /* func is NULL for lightfunc */ + /* Catch sites are required to clean up their environments + * in FINALLY part before propagating, so this should + * always hold here. + */ DUK_ASSERT(act->lex_env == act->var_env); + if (act->var_env != NULL) { DUK_DDD(DUK_DDDPRINT("closing var_env record %p -> %!O", (void *) act->var_env, (duk_heaphdr *) act->var_env)); - duk_js_close_environment_record(thr, act->var_env, func, act->idx_bottom); + duk_js_close_environment_record(thr, act->var_env); act = thr->callstack + idx; /* avoid side effect issues */ } -#if 0 - if (act->lex_env != NULL) { - if (act->lex_env == act->var_env) { - /* common case, already closed, so skip */ - DUK_DD(DUK_DDPRINT("lex_env and var_env are the same and lex_env " - "already closed -> skip closing lex_env")); - ; - } else { - DUK_DD(DUK_DDPRINT("closing lex_env record %p -> %!O", - (void *) act->lex_env, (duk_heaphdr *) act->lex_env)); - duk_js_close_environment_record(thr, act->lex_env, DUK_ACT_GET_FUNC(act), act->idx_bottom); - act = thr->callstack + idx; /* avoid side effect issues */ - } - } -#endif - - DUK_ASSERT((act->lex_env == NULL) || - ((duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_VARMAP(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL))); - - DUK_ASSERT((act->var_env == NULL) || - ((duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_VARMAP(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL) && - (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL))); - skip_env_close: /* @@ -269,55 +275,38 @@ } /* - * Reference count updates - * - * Note: careful manipulation of refcounts. The top is - * not updated yet, so all the activations are reachable - * for mark-and-sweep (which may be triggered by decref). - * However, the pointers are NULL so this is not an issue. + * Reference count updates, using NORZ macros so we don't + * need to handle side effects. */ -#if defined(DUK_USE_REFERENCE_COUNTING) - tmp = act->var_env; -#endif + DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, act->var_env); act->var_env = NULL; -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); - act = thr->callstack + idx; /* avoid side effect issues */ -#endif - -#if defined(DUK_USE_REFERENCE_COUNTING) - tmp = act->lex_env; -#endif + DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, act->lex_env); act->lex_env = NULL; -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); - act = thr->callstack + idx; /* avoid side effect issues */ -#endif /* Note: this may cause a corner case situation where a finalizer * may see a currently reachable activation whose 'func' is NULL. */ -#if defined(DUK_USE_REFERENCE_COUNTING) tmp = DUK_ACT_GET_FUNC(act); -#endif + DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp); + DUK_UNREF(tmp); act->func = NULL; -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); - act = thr->callstack + idx; /* avoid side effect issues */ - DUK_UNREF(act); -#endif } thr->callstack_top = new_top; + if (new_top > 0) { + thr->callstack_curr = thr->callstack + new_top - 1; + } else { + thr->callstack_curr = NULL; + } /* * We could clear the book-keeping variables for the topmost activation, * but don't do so now. */ #if 0 - if (thr->callstack_top > 0) { - duk_activation *act = thr->callstack + thr->callstack_top - 1; + if (thr->callstack_curr != NULL) { + duk_activation *act = thr->callstack_curr; act->idx_retval = 0; } #endif @@ -328,7 +317,12 @@ */ } -DUK_INTERNAL void duk_hthread_catchstack_grow(duk_hthread *thr) { +DUK_INTERNAL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top) { + duk_hthread_callstack_unwind_norz(thr, new_top); + DUK_REFZERO_CHECK_FAST(thr); +} + +DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__hthread_do_catchstack_grow(duk_hthread *thr) { duk_catcher *new_ptr; duk_size_t old_size; duk_size_t new_size; @@ -337,10 +331,6 @@ DUK_ASSERT_DISABLE(thr->catchstack_top); /* avoid warning (unsigned) */ DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top); - if (thr->catchstack_top < thr->catchstack_size) { - return; - } - old_size = thr->catchstack_size; new_size = old_size + DUK_CATCHSTACK_GROW_STEP; @@ -368,7 +358,19 @@ /* note: any entries above the catchstack top are garbage and not zeroed */ } -DUK_INTERNAL void duk_hthread_catchstack_shrink_check(duk_hthread *thr) { +DUK_INTERNAL void duk_hthread_catchstack_grow(duk_hthread *thr) { + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->catchstack_top); /* avoid warning (unsigned) */ + DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top); + + if (DUK_LIKELY(thr->catchstack_top < thr->catchstack_size)) { + return; + } + + duk__hthread_do_catchstack_grow(thr); +} + +DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__hthread_do_catchstack_shrink(duk_hthread *thr) { duk_size_t new_size; duk_catcher *p; @@ -376,10 +378,6 @@ DUK_ASSERT_DISABLE(thr->catchstack_top >= 0); /* avoid warning (unsigned) */ DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top); - if (thr->catchstack_size - thr->catchstack_top < DUK_CATCHSTACK_SHRINK_THRESHOLD) { - return; - } - new_size = thr->catchstack_top + DUK_CATCHSTACK_SHRINK_SPARE; DUK_ASSERT(new_size >= thr->catchstack_top); @@ -406,7 +404,19 @@ /* note: any entries above the catchstack top are garbage and not zeroed */ } -DUK_INTERNAL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top) { +DUK_INTERNAL void duk_hthread_catchstack_shrink_check(duk_hthread *thr) { + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->catchstack_top >= 0); /* avoid warning (unsigned) */ + DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top); + + if (DUK_LIKELY(thr->catchstack_size - thr->catchstack_top < DUK_CATCHSTACK_SHRINK_THRESHOLD)) { + return; + } + + duk__hthread_do_catchstack_shrink(thr); +} + +DUK_INTERNAL void duk_hthread_catchstack_unwind_norz(duk_hthread *thr, duk_size_t new_top) { duk_size_t idx; DUK_DDD(DUK_DDDPRINT("unwind catchstack top of thread %p from %ld to %ld", @@ -462,7 +472,8 @@ env = act->lex_env; /* current lex_env of the activation (created for catcher) */ DUK_ASSERT(env != NULL); /* must be, since env was created when catcher was created */ act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env); /* prototype is lex_env before catcher created */ - DUK_HOBJECT_DECREF(thr, env); + DUK_HOBJECT_INCREF(thr, act->lex_env); + DUK_HOBJECT_DECREF_NORZ(thr, env); /* There is no need to decref anything else than 'env': if 'env' * becomes unreachable, refzero will handle decref'ing its prototype. @@ -474,3 +485,97 @@ /* note: any entries above the catchstack top are garbage and not zeroed */ } + +DUK_INTERNAL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top) { + duk_hthread_catchstack_unwind_norz(thr, new_top); + DUK_REFZERO_CHECK_FAST(thr); +} + +#if defined(DUK_USE_FINALIZER_TORTURE) +DUK_INTERNAL void duk_hthread_valstack_torture_realloc(duk_hthread *thr) { + duk_size_t alloc_size; + duk_tval *new_ptr; + duk_ptrdiff_t end_off; + duk_ptrdiff_t bottom_off; + duk_ptrdiff_t top_off; + + if (thr->valstack == NULL) { + return; + } + + end_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack); + bottom_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack); + top_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack); + alloc_size = (duk_size_t) end_off; + if (alloc_size == 0) { + return; + } + + new_ptr = (duk_tval *) DUK_ALLOC(thr->heap, alloc_size); + if (new_ptr != NULL) { + DUK_MEMCPY((void *) new_ptr, (const void *) thr->valstack, alloc_size); + DUK_MEMSET((void *) thr->valstack, 0x55, alloc_size); + DUK_FREE(thr->heap, (void *) thr->valstack); + thr->valstack = new_ptr; + thr->valstack_end = (duk_tval *) ((duk_uint8_t *) new_ptr + end_off); + thr->valstack_bottom = (duk_tval *) ((duk_uint8_t *) new_ptr + bottom_off); + thr->valstack_top = (duk_tval *) ((duk_uint8_t *) new_ptr + top_off); + /* No change in size. */ + } else { + DUK_D(DUK_DPRINT("failed to realloc valstack for torture, ignore")); + } +} + +DUK_INTERNAL void duk_hthread_callstack_torture_realloc(duk_hthread *thr) { + duk_size_t alloc_size; + duk_activation *new_ptr; + duk_ptrdiff_t curr_off; + + if (thr->callstack == NULL) { + return; + } + + curr_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->callstack_curr - (duk_uint8_t *) thr->callstack); + alloc_size = sizeof(duk_activation) * thr->callstack_size; + if (alloc_size == 0) { + return; + } + + new_ptr = (duk_activation *) DUK_ALLOC(thr->heap, alloc_size); + if (new_ptr != NULL) { + DUK_MEMCPY((void *) new_ptr, (const void *) thr->callstack, alloc_size); + DUK_MEMSET((void *) thr->callstack, 0x55, alloc_size); + DUK_FREE(thr->heap, (void *) thr->callstack); + thr->callstack = new_ptr; + thr->callstack_curr = (duk_activation *) ((duk_uint8_t *) new_ptr + curr_off); + /* No change in size. */ + } else { + DUK_D(DUK_DPRINT("failed to realloc callstack for torture, ignore")); + } +} + +DUK_INTERNAL void duk_hthread_catchstack_torture_realloc(duk_hthread *thr) { + duk_size_t alloc_size; + duk_catcher *new_ptr; + + if (thr->catchstack == NULL) { + return; + } + + alloc_size = sizeof(duk_catcher) * thr->catchstack_size; + if (alloc_size == 0) { + return; + } + + new_ptr = (duk_catcher *) DUK_ALLOC(thr->heap, alloc_size); + if (new_ptr != NULL) { + DUK_MEMCPY((void *) new_ptr, (const void *) thr->catchstack, alloc_size); + DUK_MEMSET((void *) thr->catchstack, 0x55, alloc_size); + DUK_FREE(thr->heap, (void *) thr->catchstack); + thr->catchstack = new_ptr; + /* No change in size. */ + } else { + DUK_D(DUK_DPRINT("failed to realloc catchstack for torture, ignore")); + } +} +#endif /* DUK_USE_FINALIZER_TORTURE */ diff -Nru duktape-2.0.0/src-separate/duk_internal.h duktape-2.1.1/src-separate/duk_internal.h --- duktape-2.0.0/src-separate/duk_internal.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_internal.h 2017-07-28 22:05:08.000000000 +0000 @@ -41,6 +41,7 @@ * dependencies. */ +#include "duk_dblunion.h" #include "duk_replacements.h" #include "duk_jmpbuf.h" #include "duk_exception.h" @@ -55,6 +56,7 @@ #include "duk_js_compiler.h" #include "duk_regexp.h" #include "duk_heaphdr.h" +#include "duk_refcount.h" #include "duk_api_internal.h" #include "duk_hstring.h" #include "duk_hobject.h" @@ -63,6 +65,7 @@ #include "duk_hbufobj.h" #include "duk_hthread.h" #include "duk_harray.h" +#include "duk_henv.h" #include "duk_hbuffer.h" #include "duk_heap.h" #include "duk_debugger.h" diff -Nru duktape-2.0.0/src-separate/duk_js_bytecode.h duktape-2.1.1/src-separate/duk_js_bytecode.h --- duktape-2.0.0/src-separate/duk_js_bytecode.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_js_bytecode.h 2017-07-28 22:05:08.000000000 +0000 @@ -461,8 +461,7 @@ #define DUK_BC_TRYCATCH_FLAG_WITH_BINDING (1 << 3) /* DUK_OP_DECLVAR flags in A; bottom bits are reserved for propdesc flags (DUK_PROPDESC_FLAG_XXX) */ -#define DUK_BC_DECLVAR_FLAG_UNDEF_VALUE (1 << 4) /* use 'undefined' for value automatically */ -#define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1 << 5) /* function declaration */ +#define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1 << 4) /* function declaration */ /* Misc constants and helper macros. */ #define DUK_BC_LDINT_BIAS (1L << 15) diff -Nru duktape-2.0.0/src-separate/duk_js_call.c duktape-2.1.1/src-separate/duk_js_call.c --- duktape-2.0.0/src-separate/duk_js_call.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_js_call.c 2017-07-28 22:05:08.000000000 +0000 @@ -21,6 +21,8 @@ #include "duk_internal.h" +/* XXX: heap->error_not_allowed for success path too? */ + /* * Forward declarations. */ @@ -176,16 +178,19 @@ arg = duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_ARRAY_PART | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARGUMENTS), DUK_BIDX_OBJECT_PROTOTYPE); DUK_ASSERT(arg != NULL); (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), -1); /* no prototype */ (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), -1); /* no prototype */ i_arg = duk_get_top(ctx) - 3; @@ -473,6 +478,8 @@ duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_LENGTH); /* -> [ ... func this arg1 ... argN _Args length ] */ len = (duk_idx_t) duk_require_int(ctx, -1); duk_pop(ctx); + + duk_require_stack(ctx, len); for (i = 0; i < len; i++) { /* XXX: very slow - better to bulk allocate a gap, and copy * from args_array directly (we know it has a compact array @@ -495,7 +502,7 @@ (long) num_stack_args, (long) idx_func, duk_get_tval(ctx, idx_func))); } while (--sanity > 0); - if (sanity == 0) { + if (DUK_UNLIKELY(sanity == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_BOUND_CHAIN_LIMIT); } @@ -569,7 +576,9 @@ return; } - act_callee = thr->callstack + thr->callstack_top - 1; + DUK_ASSERT(thr->callstack_top > 0); + act_callee = thr->callstack_curr; + DUK_ASSERT(act_callee != NULL); act_caller = (thr->callstack_top >= 2 ? act_callee - 1 : NULL); /* XXX: check .caller writability? */ @@ -1050,16 +1059,6 @@ */ duk__handle_call_inner(thr, num_stack_args, call_flags, idx_func); - /* Success path handles */ - DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth); - DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc); - - /* Longjmp state is kept clean in success path */ - DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN); - DUK_ASSERT(thr->heap->lj.iserror == 0); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1)); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); - thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr; return DUK_EXEC_SUCCESS; @@ -1086,11 +1085,6 @@ idx_func, old_jmpbuf_ptr); - /* Longjmp state is cleaned up by error handling */ - DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN); - DUK_ASSERT(thr->heap->lj.iserror == 0); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1)); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); return DUK_EXEC_ERROR; } #if defined(DUK_USE_CPP_EXCEPTIONS) @@ -1116,6 +1110,7 @@ entry_ptr_curr_pc, idx_func, old_jmpbuf_ptr); + return DUK_EXEC_ERROR; } } catch (...) { @@ -1136,6 +1131,7 @@ entry_ptr_curr_pc, idx_func, old_jmpbuf_ptr); + return DUK_EXEC_ERROR; } } @@ -1326,7 +1322,8 @@ duk_hthread_callstack_grow(thr); - if (thr->callstack_top > 0) { + act = thr->callstack_curr; + if (act != NULL) { /* * Update idx_retval of current activation. * @@ -1337,12 +1334,13 @@ * the Ecmascript call's idx_retval must be set for things to work. */ - (thr->callstack + thr->callstack_top - 1)->idx_retval = entry_valstack_bottom_index + idx_func; + act->idx_retval = entry_valstack_bottom_index + idx_func; } DUK_ASSERT(thr->callstack_top < thr->callstack_size); act = thr->callstack + thr->callstack_top; thr->callstack_top++; + thr->callstack_curr = act; DUK_ASSERT(thr->callstack_top <= thr->callstack_size); DUK_ASSERT(thr->valstack_top > thr->valstack_bottom); /* at least effective 'this' */ DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func)); @@ -1433,8 +1431,8 @@ #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) if (func) { duk__update_func_caller_prop(thr, func); + act = thr->callstack_curr; } - act = thr->callstack + thr->callstack_top - 1; #endif /* [ ... func this arg1 ... argN ] */ @@ -1479,7 +1477,7 @@ /* [ ... func this arg1 ... argN envobj ] */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; act->lex_env = env; act->var_env = env; DUK_HOBJECT_INCREF(thr, env); @@ -1494,6 +1492,7 @@ DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func)); duk__handle_oldenv_for_call(thr, func, act); + /* No need to re-lookup 'act' at present: no side effects. */ DUK_ASSERT(act->lex_env != NULL); DUK_ASSERT(act->var_env != NULL); @@ -1530,6 +1529,7 @@ * new value stack bottom, and call the target. */ + act = thr->callstack_curr; if (func != NULL && DUK_HOBJECT_IS_COMPFUNC(func)) { /* * Ecmascript call @@ -1572,10 +1572,9 @@ DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); /* may need unwind */ DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1); - DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1); - duk_hthread_catchstack_unwind(thr, entry_catchstack_top); + duk_hthread_catchstack_unwind_norz(thr, entry_catchstack_top); duk_hthread_catchstack_shrink_check(thr); - duk_hthread_callstack_unwind(thr, entry_callstack_top); + duk_hthread_callstack_unwind_norz(thr, entry_callstack_top); /* XXX: may now fail */ duk_hthread_callstack_shrink_check(thr); thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index; @@ -1637,7 +1636,7 @@ DUK_ASSERT(thr->catchstack_top == entry_catchstack_top); /* no need to unwind */ DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1); - duk_hthread_callstack_unwind(thr, entry_callstack_top); + duk_hthread_callstack_unwind_norz(thr, entry_callstack_top); duk_hthread_callstack_shrink_check(thr); thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index; @@ -1692,9 +1691,12 @@ DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */ thr->state = (duk_uint8_t) entry_thread_state; + /* Disabled assert: triggered with some torture tests. */ +#if 0 DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */ (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */ (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */ +#endif thr->heap->call_recursion_depth = entry_call_recursion_depth; @@ -1707,7 +1709,7 @@ * on every return should have no ill effect. */ #if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + if (duk_debug_is_attached(thr->heap)) { DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt")); DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init); thr->interrupt_init -= thr->interrupt_counter; @@ -1720,6 +1722,14 @@ duk__interrupt_fixup(thr, entry_curr_thread); #endif + /* Restored by success path. */ + DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth); + DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc); + + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + + DUK_REFZERO_CHECK_FAST(thr); + return; thread_state_error: @@ -1751,6 +1761,7 @@ * the error here. */ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW); + DUK_ASSERT_LJSTATE_SET(thr->heap); DUK_ASSERT(thr->callstack_top >= entry_callstack_top); DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); @@ -1772,9 +1783,9 @@ * scopes; this is a sandboxing issue, described in: * https://github.com/svaarala/duktape/issues/476 */ - duk_hthread_catchstack_unwind(thr, entry_catchstack_top); + duk_hthread_catchstack_unwind_norz(thr, entry_catchstack_top); duk_hthread_catchstack_shrink_check(thr); - duk_hthread_callstack_unwind(thr, entry_callstack_top); + duk_hthread_callstack_unwind_norz(thr, entry_callstack_top); duk_hthread_callstack_shrink_check(thr); thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index; @@ -1825,9 +1836,12 @@ DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */ thr->state = (duk_uint8_t) entry_thread_state; + /* Disabled assert: triggered with some torture tests. */ +#if 0 DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */ (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */ (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */ +#endif thr->heap->call_recursion_depth = entry_call_recursion_depth; @@ -1840,7 +1854,7 @@ * on every return should have no ill effect. */ #if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + if (duk_debug_is_attached(thr->heap)) { DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt")); DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init); thr->interrupt_init -= thr->interrupt_counter; @@ -1852,6 +1866,21 @@ #if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG) duk__interrupt_fixup(thr, entry_curr_thread); #endif + + /* Error handling complete, remove side effect protections and + * process pending finalizers. + */ +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(thr->heap->error_not_allowed == 1); + thr->heap->error_not_allowed = 0; +#endif + DUK_ASSERT(thr->heap->pf_prevent_count > 0); + thr->heap->pf_prevent_count--; + DUK_DD(DUK_DDPRINT("call error handled, pf_prevent_count updated to %ld", (long) thr->heap->pf_prevent_count)); + + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + + DUK_REFZERO_CHECK_SLOW(thr); } /* @@ -1949,12 +1978,6 @@ entry_callstack_top, entry_catchstack_top); - /* Longjmp state is kept clean in success path */ - DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN); - DUK_ASSERT(thr->heap->lj.iserror == 0); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1)); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); - /* Note: either pointer may be NULL (at entry), so don't assert */ thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr; @@ -1974,12 +1997,6 @@ entry_catchstack_top, old_jmpbuf_ptr); - /* Longjmp state is cleaned up by error handling */ - DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN); - DUK_ASSERT(thr->heap->lj.iserror == 0); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1)); - DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); - retval = DUK_EXEC_ERROR; } #if defined(DUK_USE_CPP_EXCEPTIONS) @@ -2024,6 +2041,8 @@ DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == old_jmpbuf_ptr); /* success/error path both do this */ + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + duk__handle_safe_call_shared(thr, idx_retbase, num_stack_rets, @@ -2138,6 +2157,10 @@ DUK_ASSERT(thr->callstack_top == entry_callstack_top); duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, rc); + + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + + DUK_REFZERO_CHECK_FAST(thr); return; thread_state_error: @@ -2172,6 +2195,7 @@ * the error here. */ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW); + DUK_ASSERT_LJSTATE_SET(thr->heap); DUK_ASSERT(thr->callstack_top >= entry_callstack_top); DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); @@ -2180,9 +2204,9 @@ DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); DUK_ASSERT(thr->callstack_top >= entry_callstack_top); - duk_hthread_catchstack_unwind(thr, entry_catchstack_top); + duk_hthread_catchstack_unwind_norz(thr, entry_catchstack_top); duk_hthread_catchstack_shrink_check(thr); - duk_hthread_callstack_unwind(thr, entry_callstack_top); + duk_hthread_callstack_unwind_norz(thr, entry_callstack_top); duk_hthread_callstack_shrink_check(thr); thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index; @@ -2214,6 +2238,21 @@ thr->heap->lj.iserror = 0; DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */ + + /* Error handling complete, remove side effect protections and + * process pending finalizers. + */ +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(thr->heap->error_not_allowed == 1); + thr->heap->error_not_allowed = 0; +#endif + DUK_ASSERT(thr->heap->pf_prevent_count > 0); + thr->heap->pf_prevent_count--; + DUK_DD(DUK_DDPRINT("safe call error handled, pf_prevent_count updated to %ld", (long) thr->heap->pf_prevent_count)); + + DUK_ASSERT_LJSTATE_UNSET(thr->heap); + + DUK_REFZERO_CHECK_SLOW(thr); } DUK_LOCAL void duk__handle_safe_call_shared(duk_hthread *thr, @@ -2260,6 +2299,8 @@ #if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG) duk__interrupt_fixup(thr, entry_curr_thread); #endif + + DUK_ASSERT_LJSTATE_UNSET(thr->heap); } /* @@ -2447,7 +2488,8 @@ DUK_ASSERT(thr->callstack_top >= 1); DUK_ASSERT((call_flags & DUK_CALL_FLAG_IS_RESUME) == 0); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) { /* See: test-bug-tailcall-preventyield-assert.c. */ DUK_DDD(DUK_DDDPRINT("tail call prevented by current activation having DUK_ACT_FLAG_PREVENTYIELD")); @@ -2494,16 +2536,17 @@ break; } } - duk_hthread_catchstack_unwind(thr, i_stk + 1); + duk_hthread_catchstack_unwind_norz(thr, i_stk + 1); /* Unwind the topmost callstack entry before reusing it */ DUK_ASSERT(thr->callstack_top > 0); - duk_hthread_callstack_unwind(thr, thr->callstack_top - 1); + duk_hthread_callstack_unwind_norz(thr, thr->callstack_top - 1); /* Then reuse the unwound activation; callstack was not shrunk so there is always space */ + DUK_ASSERT(thr->callstack_top < thr->callstack_size); + act = thr->callstack + thr->callstack_top; thr->callstack_top++; - DUK_ASSERT(thr->callstack_top <= thr->callstack_size); - act = thr->callstack + thr->callstack_top - 1; + thr->callstack_curr = act; /* Start filling in the activation */ act->func = func; /* don't want an intermediate exposed state with func == NULL */ @@ -2520,7 +2563,7 @@ DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */ #if defined(DUK_USE_REFERENCE_COUNTING) DUK_HOBJECT_INCREF(thr, func); - act = thr->callstack + thr->callstack_top - 1; /* side effects (currently none though) */ + act = thr->callstack_curr; /* side effects (currently none though) */ #endif #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) @@ -2532,7 +2575,7 @@ * is in use. */ duk__update_func_caller_prop(thr, func); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; #endif act->flags = (DUK_HOBJECT_HAS_STRICT(func) ? @@ -2589,7 +2632,7 @@ DUK_DDD(DUK_DDDPRINT("update to current activation idx_retval")); DUK_ASSERT(thr->callstack_top < thr->callstack_size); DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL); DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act))); act->idx_retval = entry_valstack_bottom_index + idx_func; @@ -2598,6 +2641,7 @@ DUK_ASSERT(thr->callstack_top < thr->callstack_size); act = thr->callstack + thr->callstack_top; thr->callstack_top++; + thr->callstack_curr = act; DUK_ASSERT(thr->callstack_top <= thr->callstack_size); DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); @@ -2630,7 +2674,7 @@ #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) duk__update_func_caller_prop(thr, func); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; #endif } @@ -2659,6 +2703,7 @@ */ duk__handle_oldenv_for_call(thr, func, act); + /* No need to re-lookup 'act' at present: no side effects. */ DUK_ASSERT(act->lex_env != NULL); DUK_ASSERT(act->var_env != NULL); @@ -2688,7 +2733,7 @@ /* [ ... arg1 ... argN envobj ] */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; act->lex_env = env; act->var_env = env; DUK_HOBJECT_INCREF(thr, act->lex_env); @@ -2724,5 +2769,6 @@ * the topmost activation. */ + DUK_REFZERO_CHECK_FAST(thr); return 1; } diff -Nru duktape-2.0.0/src-separate/duk_js_compiler.c duktape-2.1.1/src-separate/duk_js_compiler.c --- duktape-2.0.0/src-separate/duk_js_compiler.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_js_compiler.c 2017-07-28 22:05:08.000000000 +0000 @@ -1998,6 +1998,8 @@ duk_pop(ctx); return ret; #else + DUK_UNREF(comp_ctx); + DUK_UNREF(rc); DUK_ASSERT((rc & DUK__CONST_MARKER) == 0); /* caller removes const marker */ return 0; #endif @@ -2249,15 +2251,31 @@ DUK_DDD(DUK_DDDPRINT("arith inline check: d1=%lf, d2=%lf, op=%ld", (double) d1, (double) d2, (long) x->op)); switch (x->op) { - case DUK_OP_ADD: d3 = d1 + d2; break; - case DUK_OP_SUB: d3 = d1 - d2; break; - case DUK_OP_MUL: d3 = d1 * d2; break; - case DUK_OP_DIV: d3 = d1 / d2; break; + case DUK_OP_ADD: { + d3 = d1 + d2; + break; + } + case DUK_OP_SUB: { + d3 = d1 - d2; + break; + } + case DUK_OP_MUL: { + d3 = d1 * d2; + break; + } + case DUK_OP_DIV: { + d3 = d1 / d2; + break; + } case DUK_OP_EXP: { d3 = (duk_double_t) duk_js_arith_pow((double) d1, (double) d2); break; } - default: accept_fold = 0; break; + default: { + d3 = 0.0; /* Won't be used, but silence MSVC /W4 warning. */ + accept_fold = 0; + break; + } } if (accept_fold) { @@ -6171,6 +6189,7 @@ duk_small_uint_t stmt_flags = 0; duk_int_t label_id = -1; duk_small_uint_t tok; + duk_bool_t test_func_decl; DUK__RECURSION_INCREASE(comp_ctx, thr); @@ -6236,17 +6255,15 @@ * for function statements are modelled after V8, see * test-dev-func-decl-outside-top.js. */ - + test_func_decl = allow_source_elem; #if defined(DUK_USE_NONSTD_FUNC_STMT) /* Lenient: allow function declarations outside top level in * non-strict mode but reject them in strict mode. */ - if (allow_source_elem || !comp_ctx->curr_func.is_strict) -#else /* DUK_USE_NONSTD_FUNC_STMT */ - /* Strict: never allow function declarations outside top level. */ - if (allow_source_elem) + test_func_decl = test_func_decl || !comp_ctx->curr_func.is_strict; #endif /* DUK_USE_NONSTD_FUNC_STMT */ - { + /* Strict: never allow function declarations outside top level. */ + if (test_func_decl) { /* FunctionDeclaration: not strictly a statement but handled as such. * * O(depth^2) parse count for inner functions is handled by recording a @@ -6958,6 +6975,9 @@ (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1))); +#if defined(DUK_USE_FASTINT) + DUK_ASSERT(DUK_TVAL_IS_NULL(duk_get_tval(ctx, -1)) || DUK_TVAL_IS_FASTINT(duk_get_tval(ctx, -1))); +#endif duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */ } @@ -7023,8 +7043,7 @@ duk_push_null(ctx); declvar_flags = DUK_PROPDESC_FLAG_WRITABLE | - DUK_PROPDESC_FLAG_ENUMERABLE | - DUK_BC_DECLVAR_FLAG_UNDEF_VALUE; + DUK_PROPDESC_FLAG_ENUMERABLE; if (configurable_bindings) { declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE; } @@ -7701,9 +7720,9 @@ DUK_ASSERT(lex_pt != NULL); flags = comp_stk->flags; - is_eval = (flags & DUK_JS_COMPILE_FLAG_EVAL ? 1 : 0); - is_strict = (flags & DUK_JS_COMPILE_FLAG_STRICT ? 1 : 0); - is_funcexpr = (flags & DUK_JS_COMPILE_FLAG_FUNCEXPR ? 1 : 0); + is_eval = (flags & DUK_COMPILE_EVAL ? 1 : 0); + is_strict = (flags & DUK_COMPILE_STRICT ? 1 : 0); + is_funcexpr = (flags & DUK_COMPILE_FUNCEXPR ? 1 : 0); h_filename = duk_get_hstring(ctx, -1); /* may be undefined */ @@ -7779,7 +7798,7 @@ */ DUK_ASSERT(func->is_setget == 0); - func->is_strict = is_strict; + func->is_strict = (duk_uint8_t) is_strict; DUK_ASSERT(func->is_notail == 0); if (is_funcexpr) { @@ -7794,8 +7813,9 @@ (void) duk__parse_func_like_raw(comp_ctx, 0 /*flags*/); } else { DUK_ASSERT(func->is_function == 0); - func->is_eval = is_eval; - func->is_global = !is_eval; + DUK_ASSERT(is_eval == 0 || is_eval == 1); + func->is_eval = (duk_uint8_t) is_eval; + func->is_global = (duk_uint8_t) !is_eval; DUK_ASSERT(func->is_namebinding == 0); DUK_ASSERT(func->is_constructable == 0); @@ -7835,6 +7855,7 @@ DUK_LEXER_INITCTX(&comp_stk.comp_ctx_alloc.lex); comp_stk.comp_ctx_alloc.lex.input = src_buffer; comp_stk.comp_ctx_alloc.lex.input_length = src_length; + comp_stk.comp_ctx_alloc.lex.flags = flags; /* Forward flags directly for now. */ /* [ ... filename ] */ diff -Nru duktape-2.0.0/src-separate/duk_js_compiler.h duktape-2.1.1/src-separate/duk_js_compiler.h --- duktape-2.0.0/src-separate/duk_js_compiler.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_js_compiler.h 2017-07-28 22:05:08.000000000 +0000 @@ -222,10 +222,6 @@ * Prototypes */ -#define DUK_JS_COMPILE_FLAG_EVAL (1 << 0) /* source is eval code (not global) */ -#define DUK_JS_COMPILE_FLAG_STRICT (1 << 1) /* strict outer context */ -#define DUK_JS_COMPILE_FLAG_FUNCEXPR (1 << 2) /* source is a function expression (used for Function constructor) */ - DUK_INTERNAL_DECL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer, duk_size_t src_length, duk_small_uint_t flags); #endif /* DUK_JS_COMPILER_H_INCLUDED */ diff -Nru duktape-2.0.0/src-separate/duk_js_executor.c duktape-2.1.1/src-separate/duk_js_executor.c --- duktape-2.0.0/src-separate/duk_js_executor.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_js_executor.c 2017-07-28 22:05:08.000000000 +0000 @@ -276,7 +276,7 @@ break; } default: { - DUK_UNREACHABLE(); + /* Possible with DUK_OP_EXP. */ goto skip_fastint; } } @@ -533,8 +533,7 @@ if (DUK_TVAL_IS_NUMBER(tv)) { d1 = DUK_TVAL_GET_NUMBER(tv); } else { - d1 = duk_to_number(ctx, idx_src); /* side effects, perform in-place */ - DUK_ASSERT(DUK_TVAL_IS_NUMBER(DUK_GET_TVAL_POSIDX(ctx, idx_src))); + d1 = duk_to_number_tval(ctx, tv); /* side effects */ } if (opcode == DUK_OP_UNP) { @@ -586,7 +585,9 @@ else #endif /* DUK_USE_FASTINT */ { - i1 = duk_to_int32(ctx, idx_src); /* side effects */ + duk_push_tval(ctx, tv); + i1 = duk_to_int32(ctx, -1); /* side effects */ + duk_pop_unsafe(ctx); } /* Result is always fastint compatible. */ @@ -729,7 +730,7 @@ DUK_ASSERT(DUK_TVAL_IS_STRING(tv_id)); name = DUK_TVAL_GET_STRING(tv_id); DUK_ASSERT(name != NULL); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [ ... val this ] */ /* XXX: Fastint fast path would be useful here. Also fastints @@ -748,11 +749,13 @@ if (op & 0x02) { duk_push_number(ctx, y); /* -> [ ... x this y ] */ + act = thr->callstack_curr; duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(ctx, -1), is_strict); duk_pop_2(ctx); /* -> [ ... x ] */ } else { duk_pop_2(ctx); /* -> [ ... ] */ duk_push_number(ctx, y); /* -> [ ... y ] */ + act = thr->callstack_curr; duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(ctx, -1), is_strict); } @@ -882,17 +885,19 @@ duk__set_catcher_regs(thr, cat_idx, tv_val_unstable, lj_type); - duk_hthread_catchstack_unwind(thr, cat_idx + 1); - duk_hthread_callstack_unwind(thr, thr->catchstack[cat_idx].callstack_index + 1); + duk_hthread_catchstack_unwind_norz(thr, cat_idx + 1); + duk_hthread_callstack_unwind_norz(thr, thr->catchstack[cat_idx].callstack_index + 1); DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))); + DUK_ASSERT(thr->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); duk__reconfig_valstack_ecma_catcher(thr, thr->callstack_top - 1, cat_idx); DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); act->curr_pc = thr->catchstack[cat_idx].pc_base + 0; /* +0 = catch */ act = NULL; @@ -907,8 +912,7 @@ */ if (DUK_CAT_HAS_CATCH_BINDING_ENABLED(&thr->catchstack[cat_idx])) { - duk_hobject *new_env; - duk_hobject *act_lex_env; + duk_hdecenv *new_env; DUK_DDD(DUK_DDDPRINT("catcher has an automatic catch binding")); @@ -916,7 +920,8 @@ * points, so we re-lookup it multiple times. */ DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); if (act->lex_env == NULL) { DUK_ASSERT(act->var_env == NULL); @@ -924,22 +929,26 @@ /* this may have side effects, so re-lookup act */ duk_js_init_activation_environment_records_delayed(thr, act); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); } DUK_ASSERT(act->lex_env != NULL); DUK_ASSERT(act->var_env != NULL); DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL); DUK_UNREF(act); /* unreferenced without assertions */ - act = thr->callstack + thr->callstack_top - 1; - act_lex_env = act->lex_env; - act = NULL; /* invalidated */ - - new_env = duk_push_object_helper_proto(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), - act_lex_env); + /* XXX: If an out-of-memory happens here, longjmp state asserts + * will be triggered at present and a try-catch fails to catch. + * That's not sandboxing fatal (C API protected calls are what + * matters), and script catch code can immediately throw anyway + * for almost any operation. + */ + 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(ctx, (duk_hobject *) new_env); + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL); DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", (duk_heaphdr *) new_env)); /* Note: currently the catch binding is handled without a register @@ -948,14 +957,20 @@ * record regbases etc. */ + /* XXX: duk_xdef_prop() may cause an out-of-memory, see above. */ DUK_ASSERT(thr->catchstack[cat_idx].h_varname != NULL); duk_push_hstring(ctx, thr->catchstack[cat_idx].h_varname); duk_push_tval(ctx, thr->valstack + thr->catchstack[cat_idx].idx_base); duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_W); /* writable, not configurable */ - act = thr->callstack + thr->callstack_top - 1; - act->lex_env = new_env; - DUK_HOBJECT_INCREF(thr, new_env); /* reachable through activation */ + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); + DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, act->lex_env); + act->lex_env = (duk_hobject *) new_env; + DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env); /* reachable through activation */ + /* Net refcount change to act->lex_env is 0: incref for new_env's + * prototype, decref for act->lex_env overwrite. + */ DUK_CAT_SET_LEXENV_ACTIVE(&thr->catchstack[cat_idx]); @@ -975,17 +990,19 @@ duk__set_catcher_regs(thr, cat_idx, tv_val_unstable, lj_type); - duk_hthread_catchstack_unwind(thr, cat_idx + 1); /* cat_idx catcher is kept, even for finally */ - duk_hthread_callstack_unwind(thr, thr->catchstack[cat_idx].callstack_index + 1); + duk_hthread_catchstack_unwind_norz(thr, cat_idx + 1); /* cat_idx catcher is kept, even for finally */ + duk_hthread_callstack_unwind_norz(thr, thr->catchstack[cat_idx].callstack_index + 1); DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))); + DUK_ASSERT(thr->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); duk__reconfig_valstack_ecma_catcher(thr, thr->callstack_top - 1, cat_idx); DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); act->curr_pc = thr->catchstack[cat_idx].pc_base + 1; /* +1 = finally */ act = NULL; @@ -998,7 +1015,8 @@ DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL); DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(DUK_ACT_GET_FUNC(act))); @@ -1007,13 +1025,14 @@ act->curr_pc = thr->catchstack[cat_idx].pc_base + (lj_type == DUK_LJ_TYPE_CONTINUE ? 1 : 0); act = NULL; /* invalidated */ - duk_hthread_catchstack_unwind(thr, cat_idx + 1); /* keep label catcher */ + duk_hthread_catchstack_unwind_norz(thr, cat_idx + 1); /* keep label catcher */ /* no need to unwind callstack */ /* valstack should not need changes */ #if defined(DUK_USE_ASSERTIONS) DUK_ASSERT(thr->callstack_top >= 1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) == (duk_size_t) ((duk_hcompfunc *) DUK_ACT_GET_FUNC(act))->nregs); #endif @@ -1035,7 +1054,7 @@ tv1 = resumer->valstack + resumer->callstack[act_idx].idx_retval; /* return value from Duktape.Thread.resume() */ DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable); /* side effects */ - duk_hthread_callstack_unwind(resumer, act_idx + 1); /* unwind to 'resume' caller */ + duk_hthread_callstack_unwind_norz(resumer, act_idx + 1); /* unwind to 'resume' caller */ /* no need to unwind catchstack */ duk__reconfig_valstack_ecma_return(resumer, act_idx); @@ -1098,10 +1117,11 @@ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged by Duktape.Thread.resume() */ DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))->func == duk_bi_thread_resume); - DUK_ASSERT_DISABLE((thr->callstack + thr->callstack_top - 2)->idx_retval >= 0); /* unsigned */ + DUK_ASSERT(thr->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack_curr))->func == duk_bi_thread_resume); + DUK_ASSERT_DISABLE((thr->callstack_curr - 1)->idx_retval >= 0); /* unsigned */ tv = &thr->heap->lj.value2; /* resumee */ DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); @@ -1116,11 +1136,11 @@ DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED || resumee->callstack_top >= 2); /* YIELDED: Ecmascript activation + Duktape.Thread.yield() activation */ DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED || - (DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1))->func == duk_bi_thread_yield)); + (DUK_ACT_GET_FUNC(resumee->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumee->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumee->callstack_curr))->func == duk_bi_thread_yield)); DUK_ASSERT_DISABLE(resumee->state != DUK_HTHREAD_STATE_YIELDED || - (resumee->callstack + resumee->callstack_top - 2)->idx_retval >= 0); /* idx_retval unsigned */ + (resumee->callstack_curr - 1)->idx_retval >= 0); /* idx_retval unsigned */ DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_INACTIVE || resumee->callstack_top == 0); /* INACTIVE: no activation, single function value on valstack */ @@ -1135,7 +1155,9 @@ * which we simply ignore. */ + DUK_ASSERT(resumee->resumer == NULL); resumee->resumer = thr; + DUK_HTHREAD_INCREF(thr, thr); resumee->state = DUK_HTHREAD_STATE_RUNNING; thr->state = DUK_HTHREAD_STATE_RESUMED; DUK_HEAP_SWITCH_THREAD(thr->heap, resumee); @@ -1159,13 +1181,15 @@ tv2 = &thr->heap->lj.value1; DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv2); /* side effects */ - duk_hthread_callstack_unwind(resumee, act_idx + 1); /* unwind to 'yield' caller */ + duk_hthread_callstack_unwind_norz(resumee, act_idx + 1); /* unwind to 'yield' caller */ /* no need to unwind catchstack */ duk__reconfig_valstack_ecma_return(resumee, act_idx); + DUK_ASSERT(resumee->resumer == NULL); resumee->resumer = thr; + DUK_HTHREAD_INCREF(thr, thr); resumee->state = DUK_HTHREAD_STATE_RUNNING; thr->state = DUK_HTHREAD_STATE_RESUMED; DUK_HEAP_SWITCH_THREAD(thr->heap, resumee); @@ -1201,7 +1225,9 @@ DUK_ERROR_INTERNAL(thr); } + DUK_ASSERT(resumee->resumer == NULL); resumee->resumer = thr; + DUK_HTHREAD_INCREF(thr, thr); resumee->state = DUK_HTHREAD_STATE_RUNNING; thr->state = DUK_HTHREAD_STATE_RESUMED; DUK_HEAP_SWITCH_THREAD(thr->heap, resumee); @@ -1234,28 +1260,31 @@ DUK_ASSERT(thr != entry_thread); /* Duktape.Thread.yield() should prevent */ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged from Duktape.Thread.yield() */ DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.yield() activation */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))->func == duk_bi_thread_yield); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2))); /* an Ecmascript function */ - DUK_ASSERT_DISABLE((thr->callstack + thr->callstack_top - 2)->idx_retval >= 0); /* unsigned */ + DUK_ASSERT(thr->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack_curr))->func == duk_bi_thread_yield); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr - 1) != NULL && + DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr - 1))); /* an Ecmascript function */ + DUK_ASSERT_DISABLE((thr->callstack_curr - 1)->idx_retval >= 0); /* unsigned */ resumer = thr->resumer; DUK_ASSERT(resumer != NULL); DUK_ASSERT(resumer->state == DUK_HTHREAD_STATE_RESUMED); /* written by a previous RESUME handling */ DUK_ASSERT(resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ - DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1))->func == duk_bi_thread_resume); - DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 2) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 2))); /* an Ecmascript function */ - DUK_ASSERT_DISABLE((resumer->callstack + resumer->callstack_top - 2)->idx_retval >= 0); /* unsigned */ + DUK_ASSERT(resumer->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumer->callstack_curr))->func == duk_bi_thread_resume); + DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr - 1) != NULL && + DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr - 1))); /* an Ecmascript function */ + DUK_ASSERT_DISABLE((resumer->callstack_curr - 1)->idx_retval >= 0); /* unsigned */ if (thr->heap->lj.iserror) { thr->state = DUK_HTHREAD_STATE_YIELDED; thr->resumer = NULL; + DUK_HTHREAD_DECREF_NORZ(thr, resumer); resumer->state = DUK_HTHREAD_STATE_RUNNING; DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); thr = resumer; @@ -1271,6 +1300,7 @@ thr->state = DUK_HTHREAD_STATE_YIELDED; thr->resumer = NULL; + DUK_HTHREAD_DECREF_NORZ(thr, resumer); resumer->state = DUK_HTHREAD_STATE_RUNNING; DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); #if 0 @@ -1351,9 +1381,9 @@ * final catcher unwind everything */ #if 0 - duk_hthread_catchstack_unwind(thr, (cat - thr->catchstack) + 1); /* leave 'cat' as top catcher (also works if catchstack exhausted) */ - duk_hthread_callstack_unwind(thr, entry_callstack_index + 1); - + duk_hthread_catchstack_unwind_norz(thr, (cat - thr->catchstack) + 1); /* leave 'cat' as top catcher (also works if catchstack exhausted) */ + duk_hthread_callstack_unwind_norz(thr, entry_callstack_index + 1); + DUK_REFZERO_CHECK_SLOW(thr); #endif DUK_D(DUK_DPRINT("-> throw propagated up to entry level, rethrow and exit bytecode executor")); retval = DUK__LONGJMP_RETHROW; @@ -1370,11 +1400,12 @@ DUK_ASSERT(thr->resumer != NULL); DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2))); /* an Ecmascript function */ + DUK_ASSERT(thr->resumer->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack_curr))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */ + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr - 1) != NULL && + DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr - 1))); /* an Ecmascript function */ resumer = thr->resumer; @@ -1387,6 +1418,7 @@ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED); thr->resumer = NULL; + DUK_HTHREAD_DECREF_NORZ(thr, resumer); resumer->state = DUK_HTHREAD_STATE_RUNNING; DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); thr = resumer; @@ -1415,6 +1447,8 @@ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */ + DUK_GC_TORTURE(thr->heap); + just_return: return retval; @@ -1555,6 +1589,7 @@ cat = thr->catchstack + thr->catchstack_top - 1; /* may be < thr->catchstack initially */ DUK_ASSERT(thr->callstack_top > 0); /* ensures callstack_top - 1 >= 0 */ + DUK_ASSERT(thr->callstack_curr != NULL); orig_callstack_index = thr->callstack_top - 1; while (cat >= thr->catchstack) { @@ -1602,22 +1637,22 @@ */ DUK_DDD(DUK_DDDPRINT("return to Ecmascript caller, idx_retval=%ld, lj_value1=%!T", - (long) (thr->callstack + thr->callstack_top - 2)->idx_retval, + (long) (thr->callstack_curr - 1)->idx_retval, (duk_tval *) &thr->heap->lj.value1)); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2))); /* must be ecmascript */ + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr - 1))); /* must be ecmascript */ - tv1 = thr->valstack + (thr->callstack + thr->callstack_top - 2)->idx_retval; + tv1 = thr->valstack + (thr->callstack_curr - 1)->idx_retval; DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom); tv2 = thr->valstack_top - 1; DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */ DUK_DDD(DUK_DDDPRINT("return value at idx_retval=%ld is %!T", - (long) (thr->callstack + thr->callstack_top - 2)->idx_retval, - (duk_tval *) (thr->valstack + (thr->callstack + thr->callstack_top - 2)->idx_retval))); + (long) (thr->callstack_curr - 1)->idx_retval, + (duk_tval *) (thr->valstack + (thr->callstack_curr - 1)->idx_retval))); - duk_hthread_catchstack_unwind(thr, new_cat_top); /* leave 'cat' as top catcher (also works if catchstack exhausted) */ - duk_hthread_callstack_unwind(thr, thr->callstack_top - 1); + duk_hthread_catchstack_unwind_norz(thr, new_cat_top); /* leave 'cat' as top catcher (also works if catchstack exhausted) */ + duk_hthread_callstack_unwind_norz(thr, thr->callstack_top - 1); duk__reconfig_valstack_ecma_return(thr, thr->callstack_top - 1); DUK_DD(DUK_DDPRINT("-> return not intercepted, restart execution in caller")); @@ -1629,12 +1664,13 @@ DUK_ASSERT(thr->resumer != NULL); DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1) != NULL && - DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1)) && - ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */ - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2))); /* an Ecmascript function */ - DUK_ASSERT_DISABLE((thr->resumer->callstack + thr->resumer->callstack_top - 2)->idx_retval >= 0); /* unsigned */ + DUK_ASSERT(thr->resumer->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr) != NULL && + DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr)) && + ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack_curr))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */ + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr - 1) != NULL && + DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr - 1))); /* an Ecmascript function */ + DUK_ASSERT_DISABLE((thr->resumer->callstack_curr - 1)->idx_retval >= 0); /* unsigned */ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED); @@ -1648,6 +1684,7 @@ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED); thr->resumer = NULL; + DUK_HTHREAD_DECREF(thr, resumer); resumer->state = DUK_HTHREAD_STATE_RUNNING; DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); #if 0 @@ -1706,7 +1743,8 @@ DUK_ASSERT(thr->heap->dbg_processing == 0); /* don't re-enter e.g. during Eval */ ctx = (duk_context *) thr; - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); /* It might seem that replacing 'thr->heap' with just 'heap' below * might be a good idea, but it increases code size slightly @@ -1731,8 +1769,7 @@ (line != thr->heap->dbg_step_startline)) { DUK_D(DUK_DPRINT("STEP STATE TRIGGERED PAUSE at line %ld", (long) line)); - - DUK_HEAP_SET_PAUSED(thr->heap); + duk_debug_set_paused(thr->heap); } /* Check for breakpoints only on line transition. @@ -1758,8 +1795,7 @@ if (act->prev_line != bp->line && line == bp->line) { DUK_D(DUK_DPRINT("BREAKPOINT TRIGGERED at %!O:%ld", (duk_heaphdr *) bp->filename, (long) bp->line)); - - DUK_HEAP_SET_PAUSED(thr->heap); + duk_debug_set_paused(thr->heap); } } } else { @@ -1846,8 +1882,9 @@ * above, so we must recheck attach status. */ - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { - act = thr->callstack + thr->callstack_top - 1; /* relookup, may have changed */ + if (duk_debug_is_attached(thr->heap)) { + act = thr->callstack_curr; /* relookup, may have changed */ + DUK_ASSERT(act != NULL); if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE || ((thr->heap->dbg_step_type == DUK_STEP_TYPE_INTO || thr->heap->dbg_step_type == DUK_STEP_TYPE_OVER) && @@ -1870,7 +1907,7 @@ } #endif /* DUK_USE_DEBUGGER_SUPPORT */ -DUK_LOCAL duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) { +DUK_LOCAL DUK_NOINLINE DUK_COLD duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) { duk_int_t ctr; duk_activation *act; duk_hcompfunc *fun; @@ -1920,7 +1957,8 @@ } DUK_HEAP_SET_INTERRUPT_RUNNING(thr->heap); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC((duk_hobject *) fun)); @@ -1956,7 +1994,7 @@ * detaching (to finish off the pending detach). */ duk__interrupt_handle_debugger(thr, &immediate, &retval); - act = thr->callstack + thr->callstack_top - 1; /* relookup if changed */ + act = thr->callstack_curr; /* relookup if changed */ DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */ } #endif /* DUK_USE_DEBUGGER_SUPPORT */ @@ -2098,7 +2136,7 @@ (thr->heap->dbg_step_thread != thr || thr->heap->dbg_step_csindex != thr->callstack_top - 1)) { DUK_D(DUK_DPRINT("STEP INTO ACTIVE, FORCE PAUSED")); - DUK_HEAP_SET_PAUSED(thr->heap); + duk_debug_set_paused(thr->heap); } /* Force interrupt right away if we're paused or in "checked mode". @@ -2153,7 +2191,7 @@ #if defined(DUK_USE_EXEC_FUN_LOCAL) #define DUK__FUN() fun #else -#define DUK__FUN() ((duk_hcompfunc *) DUK_ACT_GET_FUNC((thr)->callstack + (thr)->callstack_top - 1)) +#define DUK__FUN() ((duk_hcompfunc *) DUK_ACT_GET_FUNC((thr)->callstack_curr)) #endif #define DUK__STRICT() (DUK_HOBJECT_HAS_STRICT((duk_hobject *) DUK__FUN())) @@ -2230,12 +2268,12 @@ #define DUK__SYNC_CURR_PC() do { \ duk_activation *act; \ - act = thr->callstack + thr->callstack_top - 1; \ + act = thr->callstack_curr; \ act->curr_pc = curr_pc; \ } while (0) #define DUK__SYNC_AND_NULL_CURR_PC() do { \ duk_activation *act; \ - act = thr->callstack + thr->callstack_top - 1; \ + act = thr->callstack_curr; \ act->curr_pc = curr_pc; \ thr->ptr_curr_pc = NULL; \ } while (0) @@ -2287,15 +2325,27 @@ lj_ret = duk__handle_longjmp(heap->curr_thread, entry_thread, entry_callstack_top); + /* Error handling complete, remove side effect protections. + */ +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(heap->error_not_allowed == 1); + heap->error_not_allowed = 0; +#endif + DUK_ASSERT(heap->pf_prevent_count > 0); + heap->pf_prevent_count--; + DUK_DD(DUK_DDPRINT("executor error handled, pf_prevent_count updated to %ld", (long) heap->pf_prevent_count)); + if (lj_ret == DUK__LONGJMP_RESTART) { /* Restart bytecode execution, possibly with a changed thread. */ - ; + DUK_REFZERO_CHECK_SLOW(heap->curr_thread); } else { - /* Rethrow error to calling state. */ - DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW); + /* If an error is propagated, don't run refzero checks here. + * The next catcher will deal with that. Pf_prevent_count + * will be re-bumped by the longjmp. + */ - /* Longjmp handling has restored jmpbuf_ptr. */ - DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr); + DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW); /* Rethrow error to calling state. */ + DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr); /* Longjmp handling has restored jmpbuf_ptr. */ /* Thread may have changed, e.g. YIELD converted to THROW. */ duk_err_longjmp(heap->curr_thread); @@ -2318,8 +2368,10 @@ DUK_ASSERT(exec_thr->heap->curr_thread != NULL); DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR((duk_heaphdr *) exec_thr); DUK_ASSERT(exec_thr->callstack_top >= 1); /* at least one activation, ours */ - DUK_ASSERT(DUK_ACT_GET_FUNC(exec_thr->callstack + exec_thr->callstack_top - 1) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(exec_thr->callstack + exec_thr->callstack_top - 1))); + DUK_ASSERT(DUK_ACT_GET_FUNC(exec_thr->callstack_curr) != NULL); + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(exec_thr->callstack_curr))); + + DUK_GC_TORTURE(exec_thr->heap); entry_thread = exec_thr; heap = entry_thread->heap; @@ -2410,7 +2462,7 @@ } /* Inner executor, performance critical. */ -DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_size_t entry_callstack_top) { +DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_size_t entry_callstack_top) { /* Current PC, accessed by other functions through thr->ptr_to_curr_pc. * Critical for performance. It would be safest to make this volatile, * but that eliminates performance benefits; aliasing guarantees @@ -2451,6 +2503,8 @@ #endif #endif + DUK_GC_TORTURE(entry_thread->heap); + /* * Restart execution by reloading thread state. * @@ -2500,8 +2554,11 @@ thr = entry_thread->heap->curr_thread; DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->callstack_top >= 1); - DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))); + DUK_ASSERT(thr->callstack_curr != NULL); + DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); + + DUK_GC_TORTURE(thr->heap); thr->ptr_curr_pc = &curr_pc; @@ -2515,7 +2572,8 @@ /* Assume interrupt init/counter are properly initialized here. */ /* Assume that thr->valstack_bottom has been set-up before getting here. */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); DUK_ASSERT(fun != NULL); DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == fun->nregs); @@ -2523,9 +2581,10 @@ DUK_ASSERT(consts != NULL); #if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap) && !thr->heap->dbg_processing) { + if (duk_debug_is_attached(thr->heap) && !thr->heap->dbg_processing) { duk__executor_recheck_debugger(thr, act, fun); - act = thr->callstack + thr->callstack_top - 1; /* relookup after side effects (no side effects currently however) */ + act = thr->callstack_curr; /* relookup after side effects (no side effects currently however) */ + DUK_ASSERT(act != NULL); } #endif /* DUK_USE_DEBUGGER_SUPPORT */ @@ -2575,10 +2634,11 @@ duk_small_uint_t exec_int_ret; /* Write curr_pc back for the debugger. */ - DUK_ASSERT(thr->callstack_top > 0); { duk_activation *act; - act = thr->callstack + thr->callstack_top - 1; + DUK_ASSERT(thr->callstack_top > 0); + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); act->curr_pc = (duk_instr_t *) curr_pc; } @@ -2612,7 +2672,7 @@ #if defined(DUK_USE_ASSERTIONS) || defined(DUK_USE_DEBUG) { duk_activation *act; - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; DUK_ASSERT(curr_pc >= DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, DUK__FUN())); DUK_ASSERT(curr_pc < DUK_HCOMPFUNC_GET_CODE_END(thr->heap, DUK__FUN())); DUK_UNREF(act); /* if debugging disabled */ @@ -2904,7 +2964,7 @@ DUK_ASSERT(DUK_TVAL_IS_STRING(tv)); name = DUK_TVAL_GET_STRING(tv); tv = NULL; /* lookup has side effects */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; if (duk_js_getvar_activation(thr, act, name, 0 /*throw*/)) { /* -> [... val this] */ tv = DUK_GET_TVAL_NEGIDX(ctx, -2); @@ -3632,14 +3692,12 @@ duk_hstring *name; duk_small_uint_t prop_flags; duk_bool_t is_func_decl; - duk_bool_t is_undef_value; tv1 = DUK__REGCONSTP_B(ins); DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); name = DUK_TVAL_GET_STRING(tv1); DUK_ASSERT(name != NULL); - is_undef_value = ((a & DUK_BC_DECLVAR_FLAG_UNDEF_VALUE) != 0); is_func_decl = ((a & DUK_BC_DECLVAR_FLAG_FUNC_DECL) != 0); /* XXX: declvar takes an duk_tval pointer, which is awkward and @@ -3651,19 +3709,25 @@ */ prop_flags = a & DUK_PROPDESC_FLAGS_MASK; - if (is_undef_value) { + if (is_func_decl) { + duk_push_tval(ctx, DUK__REGCONSTP_C(ins)); + } else { DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */ thr->valstack_top++; - } else { - duk_push_tval(ctx, DUK__REGCONSTP_C(ins)); } tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; if (duk_js_declvar_activation(thr, act, name, tv1, prop_flags, is_func_decl)) { - /* already declared, must update binding value */ - tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1); - duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT()); + if (is_func_decl) { + /* Already declared, update value. */ + tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1); + duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT()); + } else { + /* Already declared but no initializer value + * (e.g. 'var xyz;'), no-op. + */ + } } duk_pop(ctx); @@ -3717,7 +3781,7 @@ DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); name = DUK_TVAL_GET_STRING(tv1); DUK_ASSERT(name != NULL); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */ idx = (duk_uint_fast_t) DUK_DEC_A(ins); @@ -3744,7 +3808,7 @@ DUK_ASSERT_DISABLE(bc >= 0); /* unsigned */ DUK_ASSERT((duk_uint_t) bc < (duk_uint_t) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, DUK__FUN())); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; fun_act = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); fun_temp = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, fun_act)[bc]; DUK_ASSERT(fun_temp != NULL); @@ -3756,6 +3820,7 @@ if (act->lex_env == NULL) { DUK_ASSERT(act->var_env == NULL); duk_js_init_activation_environment_records_delayed(thr, act); + act = thr->callstack_curr; } DUK_ASSERT(act->lex_env != NULL); DUK_ASSERT(act->var_env != NULL); @@ -3782,7 +3847,7 @@ DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); name = DUK_TVAL_GET_STRING(tv1); DUK_ASSERT(name != NULL); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */ duk_pop(ctx); /* 'this' binding is not needed here */ DUK__REPLACE_TOP_A_BREAK(); @@ -3803,7 +3868,7 @@ */ tv1 = DUK__REGP_A(ins); /* val */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT()); break; } @@ -3818,7 +3883,7 @@ DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); name = DUK_TVAL_GET_STRING(tv1); DUK_ASSERT(name != NULL); - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; rc = duk_js_delvar_activation(thr, act, name); DUK__REPLACE_BOOL_A_BREAK(rc); } @@ -3879,6 +3944,7 @@ thr->valstack_top++; DUK__RETURN_SHARED(); } + /* This will be unused without refcounting. */ case DUK_OP_RETCONST: { duk_tval *tv; @@ -3895,7 +3961,10 @@ DUK__SYNC_AND_NULL_CURR_PC(); tv = DUK__CONSTP_BC(ins); DUK_TVAL_SET_TVAL(thr->valstack_top, tv); +#if defined(DUK_USE_REFERENCE_COUNTING) + /* Without refcounting only RETCONSTN is used. */ DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv)); /* no INCREF for this constant */ +#endif thr->valstack_top++; DUK__RETURN_SHARED(); } @@ -4019,57 +4088,44 @@ a = DUK_DEC_A(ins); bc = DUK_DEC_BC(ins); - act = thr->callstack + thr->callstack_top - 1; - DUK_ASSERT(thr->callstack_top >= 1); - - /* 'with' target must be created first, in case we run out of memory */ - /* XXX: refactor out? */ - - if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) { - DUK_DDD(DUK_DDDPRINT("need to initialize a with binding object")); - - if (act->lex_env == NULL) { - DUK_ASSERT(act->var_env == NULL); - DUK_DDD(DUK_DDDPRINT("delayed environment initialization")); - - /* must relookup act in case of side effects */ - duk_js_init_activation_environment_records_delayed(thr, act); - act = thr->callstack + thr->callstack_top - 1; - DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */ - } - DUK_ASSERT(act->lex_env != NULL); - DUK_ASSERT(act->var_env != NULL); - - (void) duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV), - -1); /* no prototype, updated below */ - - duk_push_tval(ctx, DUK__REGP(bc)); - duk_to_object(ctx, -1); - duk_dup_top(ctx); - - /* [ ... env target ] */ - /* [ ... env target target ] */ - - duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); - duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); /* always provideThis=true */ - - /* [ ... env ] */ + /* Registers 'bc' and 'bc + 1' are written in longjmp handling + * and if their previous values (which are temporaries) become + * unreachable -and- have a finalizer, there'll be a function + * call during error handling which is not supported now (GH-287). + * Ensure that both 'bc' and 'bc + 1' have primitive values to + * guarantee no finalizer calls in error handling. Scrubbing also + * ensures finalizers for the previous values run here rather than + * later. Error handling related values are also written to 'bc' + * and 'bc + 1' but those values never become unreachable during + * error handling, so there's no side effect problem even if the + * error value has a finalizer. + */ + duk_dup(ctx, bc); /* Stabilize value. */ + duk_to_undefined(ctx, bc); + duk_to_undefined(ctx, bc + 1); - DUK_DDD(DUK_DDDPRINT("environment for with binding: %!iT", - (duk_tval *) duk_get_tval(ctx, -1))); - } + /* Ensure a catchstack entry is available. One entry + * is guaranteed even if side effects cause function + * calls and the catchstack is shrunk because some + * spare room is left behind by a shrink operation. + */ + duk_hthread_catchstack_grow(thr); - /* allocate catcher and populate it (should be atomic) */ + /* Allocate catcher and populate it. Doesn't have to + * be fully atomic, but the catcher must be in a + * consistent state if side effects (such as finalizer + * calls) occur. + */ - duk_hthread_catchstack_grow(thr); - cat = thr->catchstack + thr->catchstack_top; DUK_ASSERT(thr->catchstack_top + 1 <= thr->catchstack_size); + cat = thr->catchstack + thr->catchstack_top; thr->catchstack_top++; cat->flags = DUK_CAT_TYPE_TCF; cat->h_varname = NULL; + cat->callstack_index = thr->callstack_top - 1; + cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */ + cat->idx_base = (duk_size_t) (thr->valstack_bottom - thr->valstack) + bc; if (a & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) { cat->flags |= DUK_CAT_FLAG_CATCH_ENABLED; @@ -4080,7 +4136,7 @@ if (a & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING) { DUK_DDD(DUK_DDDPRINT("catch binding flag set to catcher")); cat->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED; - tv1 = DUK__REGP(bc); + tv1 = DUK_GET_TVAL_NEGIDX(thr, -1); DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); /* borrowed reference; although 'tv1' comes from a register, @@ -4089,54 +4145,69 @@ */ cat->h_varname = DUK_TVAL_GET_STRING(tv1); } else if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) { - /* env created above to stack top */ - duk_hobject *new_env; + duk_hobjenv *env; + duk_hobject *target; - DUK_DDD(DUK_DDDPRINT("lexenv active flag set to catcher")); - cat->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE; + /* Delayed env initialization for activation (if needed). */ + DUK_ASSERT(thr->callstack_top >= 1); + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); + if (act->lex_env == NULL) { + DUK_DDD(DUK_DDDPRINT("delayed environment initialization")); + DUK_ASSERT(act->var_env == NULL); - DUK_DDD(DUK_DDDPRINT("activating object env: %!iT", - (duk_tval *) duk_get_tval(ctx, -1))); + duk_js_init_activation_environment_records_delayed(thr, act); + act = thr->callstack_curr; /* relookup, side effects */ + DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */ + } DUK_ASSERT(act->lex_env != NULL); - new_env = DUK_GET_HOBJECT_NEGIDX(ctx, -1); - DUK_ASSERT(new_env != NULL); + DUK_ASSERT(act->var_env != NULL); - act = thr->callstack + thr->callstack_top - 1; /* relookup (side effects) */ - DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, new_env, act->lex_env); /* side effects */ + /* Coerce 'with' target. */ + target = duk_to_hobject(ctx, -1); + DUK_ASSERT(target != NULL); + + /* Create an object environment; it is not pushed + * so avoid side effects very carefully until it is + * referenced. + */ + env = duk_hobjenv_alloc(thr, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV)); + DUK_ASSERT(env != NULL); + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL); + env->target = target; /* always provideThis=true */ + DUK_HOBJECT_INCREF(thr, target); + env->has_this = 1; + DUK_ASSERT_HOBJENV_VALID(env); + DUK_DDD(DUK_DDDPRINT("environment for with binding: %!iO", env)); - act = thr->callstack + thr->callstack_top - 1; /* relookup (side effects) */ - act->lex_env = new_env; - DUK_HOBJECT_INCREF(thr, new_env); - duk_pop(ctx); + act = thr->callstack_curr; /* relookup (side effects) */ + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL); + DUK_ASSERT(act->lex_env != NULL); + DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) env, act->lex_env); + act->lex_env = (duk_hobject *) env; /* Now reachable. */ + DUK_HOBJECT_INCREF(thr, (duk_hobject *) env); + /* Net refcount change to act->lex_env is 0: incref for env's + * prototype, decref for act->lex_env overwrite. + */ + + /* Set catcher lex_env active (affects unwind) + * only when the whole setup is complete. + */ + cat = thr->catchstack + thr->catchstack_top - 1; + cat->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE; } else { ; } - /* Registers 'bc' and 'bc + 1' are written in longjmp handling - * and if their previous values (which are temporaries) become - * unreachable -and- have a finalizer, there'll be a function - * call during error handling which is not supported now (GH-287). - * Ensure that both 'bc' and 'bc + 1' have primitive values to - * guarantee no finalizer calls in error handling. Scrubbing also - * ensures finalizers for the previous values run here rather than - * later. Error handling related values are also written to 'bc' - * and 'bc + 1' but those values never become unreachable during - * error handling, so there's no side effect problem even if the - * error value has a finalizer. - */ - duk_to_undefined(ctx, bc); - duk_to_undefined(ctx, bc + 1); - - cat = thr->catchstack + thr->catchstack_top - 1; /* relookup (side effects) */ - cat->callstack_index = thr->callstack_top - 1; - cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */ - cat->idx_base = (duk_size_t) (thr->valstack_bottom - thr->valstack) + bc; - DUK_DDD(DUK_DDDPRINT("TRYCATCH catcher: flags=0x%08lx, callstack_index=%ld, pc_base=%ld, " "idx_base=%ld, h_varname=%!O", (unsigned long) cat->flags, (long) cat->callstack_index, (long) cat->pc_base, (long) cat->idx_base, (duk_heaphdr *) cat->h_varname)); + duk_pop(ctx); + curr_pc += 2; /* skip jump slots */ break; } @@ -4190,7 +4261,8 @@ cat = thr->catchstack + thr->catchstack_top - 1; DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat)); /* cleared before entering catch part */ - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack_curr; + DUK_ASSERT(act != NULL); if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) { duk_hobject *prev_env; @@ -4205,6 +4277,7 @@ DUK_ASSERT(prev_env != NULL); act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, prev_env); DUK_CAT_CLEAR_LEXENV_ACTIVE(cat); + DUK_HOBJECT_INCREF(thr, act->lex_env); DUK_HOBJECT_DECREF(thr, prev_env); /* side effects */ } @@ -4329,7 +4402,8 @@ duk_push_tval(ctx, thr->valstack + cat->idx_base); - duk_err_setup_heap_ljstate(thr, (duk_small_int_t) cont_type); + duk_err_setup_ljstate1(thr, (duk_small_int_t) cont_type, thr->valstack + cat->idx_base); + /* No debugger Throw notify check on purpose (rethrow). */ DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */ duk_err_longjmp(thr); @@ -4366,7 +4440,10 @@ (duk_tval *) duk_get_tval(ctx, -1))); #endif - duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW); + duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(ctx, -1)); +#if defined(DUK_USE_DEBUGGER_SUPPORT) + duk_err_check_debugger_integration(thr); +#endif DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */ duk_err_longjmp(thr); @@ -4903,7 +4980,7 @@ * from precompiled bytecode. */ #if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { + if (duk_debug_is_attached(thr->heap)) { DUK_D(DUK_DPRINT("DEBUGGER statement encountered, halt execution")); DUK__SYNC_AND_NULL_CURR_PC(); duk_debug_halt_execution(thr, 1 /*use_prev_pc*/); @@ -4996,22 +5073,18 @@ case DUK_OP_UNUSED252: case DUK_OP_UNUSED253: case DUK_OP_UNUSED254: - case DUK_OP_UNUSED255: { - /* Force all case clauses to map to an actual handler - * so that the compiler can emit a jump without a bounds - * check: the switch argument is a duk_uint8_t so that - * the compiler may be able to figure it out. This is - * a small detail and obviously compiler dependent. - */ - volatile duk_small_int_t dummy_volatile; - dummy_volatile = 0; - DUK_UNREF(dummy_volatile); - DUK_D(DUK_DPRINT("invalid opcode: %ld - %!I", (long) op, ins)); - DUK__INTERNAL_ERROR("invalid opcode"); - break; - } + case DUK_OP_UNUSED255: + /* Force all case clauses to map to an actual handler + * so that the compiler can emit a jump without a bounds + * check: the switch argument is a duk_uint8_t so that + * the compiler may be able to figure it out. This is + * a small detail and obviously compiler dependent. + */ + /* default: clause omitted on purpose */ +#else + default: #endif /* DUK_USE_EXEC_PREFER_SIZE */ - default: { + { /* Default case catches invalid/unsupported opcodes. */ DUK_D(DUK_DPRINT("invalid opcode: %ld - %!I", (long) op, ins)); DUK__INTERNAL_ERROR("invalid opcode"); diff -Nru duktape-2.0.0/src-separate/duk_js.h duktape-2.1.1/src-separate/duk_js.h --- duktape-2.0.0/src-separate/duk_js.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_js.h 2017-07-28 22:05:08.000000000 +0000 @@ -28,8 +28,11 @@ DUK_INTERNAL_DECL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv); DUK_INTERNAL_DECL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv); DUK_INTERNAL_DECL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv); -DUK_INTERNAL_DECL duk_small_int_t duk_js_to_arrayindex_raw_string(const duk_uint8_t *str, duk_uint32_t blen, duk_uarridx_t *out_idx); -DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h); +DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string(const duk_uint8_t *str, duk_uint32_t blen); +#if !defined(DUK_USE_HSTRING_ARRIDX) +DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_hstring_fast_known(duk_hstring *h); +DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_hstring_fast(duk_hstring *h); +#endif DUK_INTERNAL_DECL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags); DUK_INTERNAL_DECL duk_small_int_t duk_js_data_compare(const duk_uint8_t *buf1, const duk_uint8_t *buf2, duk_size_t len1, duk_size_t len2); DUK_INTERNAL_DECL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2); @@ -82,7 +85,7 @@ DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name); DUK_INTERNAL_DECL duk_bool_t duk_js_declvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_small_int_t prop_flags, duk_bool_t is_func_decl); DUK_INTERNAL_DECL void duk_js_init_activation_environment_records_delayed(duk_hthread *thr, duk_activation *act); -DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env, duk_hobject *func, duk_size_t regbase); +DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env); DUK_INTERNAL_DECL duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_size_t idx_bottom); DUK_INTERNAL_DECL void duk_js_push_closure(duk_hthread *thr, diff -Nru duktape-2.0.0/src-separate/duk_js_ops.c duktape-2.1.1/src-separate/duk_js_ops.c --- duktape-2.0.0/src-separate/duk_js_ops.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_js_ops.c 2017-07-28 22:05:08.000000000 +0000 @@ -218,7 +218,7 @@ case DUK_TAG_STRING: { /* For Symbols ToNumber() is always a TypeError. */ duk_hstring *h = DUK_TVAL_GET_STRING(tv); - if (DUK_HSTRING_HAS_SYMBOL(h)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { DUK_ERROR_TYPE(thr, DUK_STR_CANNOT_NUMBER_COERCE_SYMBOL); } duk_push_hstring(ctx, h); @@ -950,7 +950,7 @@ DUK_ASSERT(h1 != NULL); DUK_ASSERT(h2 != NULL); - if (!DUK_HSTRING_HAS_SYMBOL(h1) && !DUK_HSTRING_HAS_SYMBOL(h2)) { + if (DUK_LIKELY(!DUK_HSTRING_HAS_SYMBOL(h1) && !DUK_HSTRING_HAS_SYMBOL(h2))) { rc = duk_js_string_compare(h1, h2); duk_pop_2(ctx); if (rc < 0) { @@ -1080,7 +1080,7 @@ /* func support for [[HasInstance]] checked in the beginning of the loop */ } while (--sanity > 0); - if (sanity == 0) { + if (DUK_UNLIKELY(sanity == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_BOUND_CHAIN_LIMIT); } @@ -1166,7 +1166,7 @@ val = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, val); } while (--sanity > 0); - if (sanity == 0) { + if (DUK_UNLIKELY(sanity == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); } DUK_UNREACHABLE(); @@ -1267,7 +1267,7 @@ /* All internal keys are identified as Symbols. */ str = DUK_TVAL_GET_STRING(tv_x); DUK_ASSERT(str != NULL); - if (DUK_HSTRING_HAS_SYMBOL(str)) { + if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(str))) { stridx = DUK_STRIDX_LC_SYMBOL; } else { stridx = DUK_STRIDX_LC_STRING; @@ -1317,64 +1317,109 @@ * * Array index: E5 Section 15.4 * Array length: E5 Section 15.4.5.1 steps 3.c - 3.d (array length write) - * - * duk_js_to_arrayindex_string_helper() computes the array index from - * string contents alone. Depending on options it's only called during - * string intern (and value stored to duk_hstring) or it's called also - * at runtime. */ -DUK_INTERNAL duk_small_int_t duk_js_to_arrayindex_raw_string(const duk_uint8_t *str, duk_uint32_t blen, duk_uarridx_t *out_idx) { - duk_uarridx_t res, new_res; - - if (blen == 0 || blen > 10) { - goto parse_fail; - } - if (str[0] == (duk_uint8_t) '0' && blen > 1) { - goto parse_fail; - } +/* Compure array index from string context, or return a "not array index" + * indicator. + */ +DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_string(const duk_uint8_t *str, duk_uint32_t blen) { + duk_uarridx_t res; - /* Accept 32-bit decimal integers, no leading zeroes, signs, etc. - * Leading zeroes are not accepted (zero index "0" is an exception - * handled above). + /* Only strings with byte length 1-10 can be 32-bit array indices. + * Leading zeroes (except '0' alone), plus/minus signs are not allowed. + * We could do a lot of prechecks here, but since most strings won't + * start with any digits, it's simpler to just parse the number and + * fail quickly. */ res = 0; - while (blen-- > 0) { - duk_uint8_t c = *str++; - if (c >= (duk_uint8_t) '0' && c <= (duk_uint8_t) '9') { - new_res = res * 10 + (duk_uint32_t) (c - (duk_uint8_t) '0'); - if (new_res < res) { - /* overflow, more than 32 bits -> not an array index */ - goto parse_fail; + if (blen == 0) { + goto parse_fail; + } + do { + duk_uarridx_t dig; + dig = (duk_uarridx_t) (*str++) - DUK_ASC_0; + + if (dig <= 9U) { + /* Careful overflow handling. When multiplying by 10: + * - 0x19999998 x 10 = 0xfffffff0: no overflow, and adding + * 0...9 is safe. + * - 0x19999999 x 10 = 0xfffffffa: no overflow, adding + * 0...5 is safe, 6...9 overflows. + * - 0x1999999a x 10 = 0x100000004: always overflow. + */ + if (DUK_UNLIKELY(res >= 0x19999999UL)) { + if (res >= 0x1999999aUL) { + /* Always overflow. */ + goto parse_fail; + } + DUK_ASSERT(res == 0x19999999UL); + if (dig >= 6U) { + goto parse_fail; + } + res = 0xfffffffaUL + dig; + DUK_ASSERT(res >= 0xfffffffaUL); + DUK_ASSERT_DISABLE(res <= 0xffffffffUL); /* range */ + } else { + res = res * 10U + dig; + if (DUK_UNLIKELY(res == 0)) { + /* If 'res' is 0, previous 'res' must + * have been 0 and we scanned in a zero. + * This is only allowed if blen == 1, + * i.e. the exact string '0'. + */ + if (blen == (duk_uint32_t) 1) { + return 0; + } + goto parse_fail; + } } - res = new_res; } else { + /* Because 'dig' is unsigned, catches both values + * above '9' and below '0'. + */ goto parse_fail; } - } + } while (--blen > 0); - *out_idx = res; - return 1; + return res; parse_fail: - *out_idx = DUK_HSTRING_NO_ARRAY_INDEX; - return 0; + return DUK_HSTRING_NO_ARRAY_INDEX; } -/* Called by duk_hstring.h macros */ -DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h) { +#if !defined(DUK_USE_HSTRING_ARRIDX) +/* Get array index for a string which is known to be an array index. This helper + * is needed when duk_hstring doesn't concretely store the array index, but strings + * are flagged as array indices at intern time. + */ +DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_hstring_fast_known(duk_hstring *h) { + const duk_uint8_t *p; duk_uarridx_t res; - duk_small_int_t rc; + duk_uint8_t t; + + DUK_ASSERT(h != NULL); + DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(h)); + p = DUK_HSTRING_GET_DATA(h); + res = 0; + for (;;) { + t = *p++; + if (DUK_UNLIKELY(t == 0)) { + /* Scanning to NUL is always safe for interned strings. */ + break; + } + DUK_ASSERT(t >= DUK_ASC_0 && t <= DUK_ASC_9); + res = res * 10U + (t - DUK_ASC_0); + } + return res; +} + +DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_hstring_fast(duk_hstring *h) { + DUK_ASSERT(h != NULL); if (!DUK_HSTRING_HAS_ARRIDX(h)) { return DUK_HSTRING_NO_ARRAY_INDEX; } - - rc = duk_js_to_arrayindex_raw_string(DUK_HSTRING_GET_DATA(h), - DUK_HSTRING_GET_BYTELEN(h), - &res); - DUK_UNREF(rc); - DUK_ASSERT(rc != 0); - return res; + return duk_js_to_arrayindex_hstring_fast_known(h); } +#endif /* DUK_USE_HSTRING_ARRIDX */ diff -Nru duktape-2.0.0/src-separate/duk_js_var.c duktape-2.1.1/src-separate/duk_js_var.c --- duktape-2.0.0/src-separate/duk_js_var.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_js_var.c 2017-07-28 22:05:08.000000000 +0000 @@ -37,11 +37,11 @@ */ typedef struct { + duk_hobject *env; duk_hobject *holder; /* for object-bound identifiers */ duk_tval *value; /* for register-bound and declarative env identifiers */ duk_int_t attrs; /* property attributes for identifier (relevant if value != NULL) */ - duk_tval *this_binding; - duk_hobject *env; + duk_bool_t has_this; /* for object-bound identifiers: provide 'this' binding */ } duk__id_lookup_result; /* @@ -194,7 +194,7 @@ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&fun_clos->obj)); DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(&fun_clos->obj)); DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(&fun_clos->obj)); - DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(&fun_clos->obj)); + DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(&fun_clos->obj)); /* DUK_HOBJECT_FLAG_ARRAY_PART: don't care */ /* DUK_HOBJECT_FLAG_NEWENV: handled below */ DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&fun_clos->obj)); @@ -229,7 +229,7 @@ #if defined(DUK_USE_FUNC_NAME_PROPERTY) if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_clos->obj)) { duk_hobject *proto; - duk_hobject *new_env; + duk_hdecenv *new_env; /* * Named function expression, name needs to be bound @@ -247,11 +247,18 @@ } /* -> [ ... closure template env ] */ - new_env = duk_push_object_helper_proto(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), - proto); + 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(ctx, (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, proto); + DUK_HOBJECT_INCREF_ALLOWNULL(thr, proto); + + DUK_ASSERT(new_env->thread == NULL); /* Closed. */ + DUK_ASSERT(new_env->varmap == NULL); /* It's important that duk_xdef_prop() is a 'raw define' so that any * properties in an ancestor are never an issue (they should never be @@ -270,10 +277,10 @@ /* [ ... closure template env ] */ - DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, new_env); - DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, new_env); - DUK_HOBJECT_INCREF(thr, new_env); - DUK_HOBJECT_INCREF(thr, new_env); + DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, (duk_hobject *) new_env); + DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, (duk_hobject *) new_env); + DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env); + DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env); duk_pop(ctx); /* [ ... closure template ] */ @@ -495,10 +502,11 @@ duk_hobject *func, duk_size_t idx_bottom) { duk_context *ctx = (duk_context *) thr; - duk_hobject *env; + duk_hdecenv *env; duk_hobject *parent; duk_hcompfunc *f; + DUK_ASSERT(ctx != NULL); DUK_ASSERT(thr != NULL); DUK_ASSERT(func != NULL); @@ -508,25 +516,44 @@ parent = thr->builtins[DUK_BIDX_GLOBAL_ENV]; } - (void) duk_push_object_helper(ctx, - DUK_HOBJECT_FLAG_EXTENSIBLE | - DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), - -1); /* no prototype, updated below */ - env = duk_known_hobject(ctx, -1); - DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, env, parent); /* parent env is the prototype */ + env = duk_hdecenv_alloc(thr, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV)); + DUK_ASSERT(env != NULL); + duk_push_hobject(ctx, (duk_hobject *) env); + + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL); + DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) env, parent); + DUK_HOBJECT_INCREF_ALLOWNULL(thr, parent); /* parent env is the prototype */ /* open scope information, for compiled functions only */ + DUK_ASSERT(env->thread == NULL); + DUK_ASSERT(env->varmap == NULL); + DUK_ASSERT(env->regbase == 0); if (DUK_HOBJECT_IS_COMPFUNC(func)) { - duk_push_hthread(ctx, thr); - duk_xdef_prop_stridx_short_wec(ctx, -2, DUK_STRIDX_INT_THREAD); - duk_push_hobject(ctx, func); - duk_xdef_prop_stridx_short_wec(ctx, -2, DUK_STRIDX_INT_CALLEE); - duk_push_size_t(ctx, idx_bottom); - duk_xdef_prop_stridx_short_wec(ctx, -2, DUK_STRIDX_INT_REGBASE); + duk_hobject *varmap; + duk_tval *tv; + + tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARMAP(thr)); + if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) { + DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); + varmap = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(varmap != NULL); + env->varmap = varmap; + DUK_HOBJECT_INCREF(thr, varmap); + env->thread = thr; + DUK_HTHREAD_INCREF(thr, thr); + env->regbase = idx_bottom; + } else { + /* If function has no _Varmap, leave the environment closed. */ + DUK_ASSERT(env->thread == NULL); + DUK_ASSERT(env->varmap == NULL); + DUK_ASSERT(env->regbase == 0); + } } - return env; + return (duk_hobject *) env; } DUK_INTERNAL @@ -535,7 +562,10 @@ duk_context *ctx = (duk_context *) thr; duk_hobject *func; duk_hobject *env; + duk_size_t act_off; + DUK_ASSERT(act != NULL); + act_off = (duk_size_t) ((duk_uint8_t *) act - (duk_uint8_t *) thr->callstack); func = DUK_ACT_GET_FUNC(act); DUK_ASSERT(func != NULL); DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound functions are never in act 'func' */ @@ -550,6 +580,7 @@ env = duk_create_activation_environment_record(thr, func, act->idx_bottom); DUK_ASSERT(env != NULL); + act = (duk_activation *) (void *) ((duk_uint8_t *) thr->callstack + act_off); DUK_DDD(DUK_DDDPRINT("created delayed fresh env: %!ipO", (duk_heaphdr *) env)); #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) @@ -574,156 +605,103 @@ * Closing environment records. * * The environment record MUST be closed with the thread where its activation - * is. In other words (if 'env' is open): - * - * - 'thr' must match _env.thread - * - 'func' must match _env.callee - * - 'regbase' must match _env.regbase - * - * These are not looked up from the env to minimize code size. - * - * XXX: should access the own properties directly instead of using the API + * is; i.e. if 'env' is open, 'thr' must match env->thread, and the regbase + * and varmap must still be valid. On entry, 'env' must be reachable. */ -DUK_INTERNAL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env, duk_hobject *func, duk_size_t regbase) { +DUK_INTERNAL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env) { duk_context *ctx = (duk_context *) thr; duk_uint_fast32_t i; + duk_hobject *varmap; + duk_hstring *key; + duk_tval *tv; + duk_uint_t regnum; DUK_ASSERT(thr != NULL); DUK_ASSERT(env != NULL); - /* func is NULL for lightfuncs */ - if (!DUK_HOBJECT_IS_DECENV(env) || DUK_HOBJECT_HAS_ENVRECCLOSED(env)) { - DUK_DDD(DUK_DDDPRINT("environment record not a declarative record, " - "or already closed: %!iO", - (duk_heaphdr *) env)); + if (DUK_UNLIKELY(!DUK_HOBJECT_IS_DECENV(env))) { + DUK_DDD(DUK_DDDPRINT("env not a declarative record: %!iO", (duk_heaphdr *) env)); return; } - DUK_DDD(DUK_DDDPRINT("closing environment record: %!iO, func: %!iO, regbase: %ld", - (duk_heaphdr *) env, (duk_heaphdr *) func, (long) regbase)); - - duk_push_hobject(ctx, env); + varmap = ((duk_hdecenv *) env)->varmap; + if (varmap == NULL) { + DUK_DDD(DUK_DDDPRINT("env already closed: %!iO", (duk_heaphdr *) env)); - /* assertions: env must be closed in the same thread as where it runs */ -#if defined(DUK_USE_ASSERTIONS) - { - /* [... env] */ - - if (duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_CALLEE)) { - DUK_ASSERT(duk_is_object(ctx, -1)); - DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) func); - } - duk_pop(ctx); - - if (duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_THREAD)) { - DUK_ASSERT(duk_is_object(ctx, -1)); - DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) thr); - } - duk_pop(ctx); - - if (duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_REGBASE)) { - DUK_ASSERT(duk_is_number(ctx, -1)); - DUK_ASSERT(duk_get_number(ctx, -1) == (double) regbase); - } - duk_pop(ctx); - - /* [... env] */ + return; } -#endif + DUK_ASSERT(((duk_hdecenv *) env)->thread != NULL); + DUK_ASSERT_HDECENV_VALID((duk_hdecenv *) env); - if (func != NULL && DUK_HOBJECT_IS_COMPFUNC(func)) { - duk_hobject *varmap; - duk_hstring *key; - duk_tval *tv; - duk_uint_t regnum; - - /* XXX: additional conditions when to close variables? we don't want to do it - * unless the environment may have "escaped" (referenced in a function closure). - * With delayed environments, the existence is probably good enough of a check. - */ + DUK_DDD(DUK_DDDPRINT("closing env: %!iO", (duk_heaphdr *) env)); + DUK_DDD(DUK_DDDPRINT("varmap: %!O", (duk_heaphdr *) varmap)); - /* XXX: any way to detect faster whether something needs to be closed? - * We now look up _Callee and then skip the rest. - */ + /* Env must be closed in the same thread as where it runs. */ + DUK_ASSERT(((duk_hdecenv *) env)->thread == thr); - /* Note: we rely on the _Varmap having a bunch of nice properties, like: - * - being compacted and unmodified during this process - * - not containing an array part - * - having correct value types - */ - - /* [... env] */ - - if (!duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_CALLEE)) { - DUK_DDD(DUK_DDDPRINT("env has no callee property, nothing to close; re-delete the control properties just in case")); - duk_pop(ctx); - goto skip_varmap; - } - - /* [... env callee] */ - - if (!duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VARMAP)) { - DUK_DDD(DUK_DDDPRINT("callee has no varmap property, nothing to close; delete the control properties")); - duk_pop_2(ctx); - goto skip_varmap; - } - varmap = duk_require_hobject(ctx, -1); - DUK_ASSERT(varmap != NULL); - - DUK_DDD(DUK_DDDPRINT("varmap: %!O", (duk_heaphdr *) varmap)); - - /* [... env callee varmap] */ - - DUK_DDD(DUK_DDDPRINT("copying bound register values, %ld bound regs", (long) DUK_HOBJECT_GET_ENEXT(varmap))); - - for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) { - key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i); - DUK_ASSERT(key != NULL); /* assume keys are compacted */ + /* XXX: additional conditions when to close variables? we don't want to do it + * unless the environment may have "escaped" (referenced in a function closure). + * With delayed environments, the existence is probably good enough of a check. + */ - DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, varmap, i)); /* assume plain values */ + /* Note: we rely on the _Varmap having a bunch of nice properties, like: + * - being compacted and unmodified during this process + * - not containing an array part + * - having correct value types + */ - tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, varmap, i); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); /* assume value is a number */ - regnum = (duk_uint_t) DUK_TVAL_GET_NUMBER(tv); - DUK_ASSERT_DISABLE(regnum >= 0); /* unsigned */ - DUK_ASSERT(regnum < ((duk_hcompfunc *) func)->nregs); /* regnum is sane */ - DUK_ASSERT(thr->valstack + regbase + regnum >= thr->valstack); - DUK_ASSERT(thr->valstack + regbase + regnum < thr->valstack_top); + DUK_DDD(DUK_DDDPRINT("copying bound register values, %ld bound regs", (long) DUK_HOBJECT_GET_ENEXT(varmap))); - /* XXX: slightly awkward */ - duk_push_hstring(ctx, key); - duk_push_tval(ctx, thr->valstack + regbase + regnum); - DUK_DDD(DUK_DDDPRINT("closing identifier '%s' -> reg %ld, value %!T", - (const char *) duk_require_string(ctx, -2), - (long) regnum, - (duk_tval *) duk_get_tval(ctx, -1))); + /* Copy over current variable values from value stack to the + * environment record. The scope object is empty but may + * inherit from another scope which has conflicting names. + */ - /* [... env callee varmap key val] */ + /* XXX: Do this using a once allocated entry area, no side effects. + * Hash part would need special treatment however (maybe copy, and + * then realloc with hash part if large enough). + */ + for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) { + duk_size_t regbase; - /* if property already exists, overwrites silently */ - duk_xdef_prop(ctx, -5, DUK_PROPDESC_FLAGS_WE); /* writable but not deletable */ - } + key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i); + DUK_ASSERT(key != NULL); /* assume keys are compact in _Varmap */ + DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, varmap, i)); /* assume plain values */ - duk_pop_2(ctx); + tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, varmap, i); + DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (duk_double_t) DUK_UINT32_MAX); /* limits */ +#if defined(DUK_USE_FASTINT) + DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv)); + regnum = (duk_uint_t) DUK_TVAL_GET_FASTINT_U32(tv); +#else + regnum = (duk_uint_t) DUK_TVAL_GET_NUMBER(tv); +#endif - /* [... env] */ + regbase = ((duk_hdecenv *) env)->regbase; + DUK_ASSERT(thr->valstack + regbase + regnum >= thr->valstack); + DUK_ASSERT(thr->valstack + regbase + regnum < thr->valstack_top); + + /* If property already exists, overwrites silently. + * Property is writable, but not deletable (not configurable + * in terms of property attributes). + */ + duk_push_tval(ctx, thr->valstack + regbase + regnum); + DUK_DDD(DUK_DDDPRINT("closing identifier %!O -> reg %ld, value %!T", + (duk_heaphdr *) key, + (long) regnum, + (duk_tval *) duk_get_tval(ctx, -1))); + duk_hobject_define_property_internal(thr, env, key, DUK_PROPDESC_FLAGS_WE); } - skip_varmap: + /* NULL atomically to avoid inconsistent state + side effects. */ + DUK_HOBJECT_DECREF_NORZ(thr, ((duk_hdecenv *) env)->thread); + DUK_HOBJECT_DECREF_NORZ(thr, ((duk_hdecenv *) env)->varmap); + ((duk_hdecenv *) env)->thread = NULL; + ((duk_hdecenv *) env)->varmap = NULL; - /* [... env] */ - - duk_del_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_CALLEE); - duk_del_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_THREAD); - duk_del_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_REGBASE); - - duk_pop(ctx); - - DUK_HOBJECT_SET_ENVRECCLOSED(env); - - DUK_DDD(DUK_DDDPRINT("environment record after being closed: %!O", - (duk_heaphdr *) env)); + DUK_DDD(DUK_DDDPRINT("env after closing: %!O", (duk_heaphdr *) env)); } /* @@ -753,12 +731,8 @@ DUK_LOCAL duk_bool_t duk__getid_open_decl_env_regs(duk_hthread *thr, duk_hstring *name, - duk_hobject *env, + duk_hdecenv *env, duk__id_lookup_result *out) { - duk_hthread *env_thr; - duk_hobject *env_func; - duk_size_t env_regbase; - duk_hobject *varmap; duk_tval *tv; duk_size_t reg_rel; duk_size_t idx; @@ -768,69 +742,39 @@ DUK_ASSERT(env != NULL); DUK_ASSERT(out != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_DECENV(env)); + DUK_ASSERT(DUK_HOBJECT_IS_DECENV((duk_hobject *) env)); + DUK_ASSERT_HDECENV_VALID(env); - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_CALLEE(thr)); - if (!tv) { - /* env is closed, should be missing _Callee, _Thread, _Regbase */ - DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL); - DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL); - DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL); + if (env->thread == NULL) { + /* already closed */ return 0; } + DUK_ASSERT(env->varmap != NULL); - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); - DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_TVAL_GET_OBJECT(tv))); - env_func = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(env_func != NULL); - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env_func, DUK_HTHREAD_STRING_INT_VARMAP(thr)); - if (!tv) { + tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env->varmap, name); + if (DUK_UNLIKELY(tv == NULL)) { return 0; } - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); - varmap = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(varmap != NULL); - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, varmap, name); - if (!tv) { - return 0; - } DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (duk_double_t) DUK_UINT32_MAX); /* limits */ +#if defined(DUK_USE_FASTINT) + DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv)); + reg_rel = (duk_size_t) DUK_TVAL_GET_FASTINT_U32(tv); +#else reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv); +#endif DUK_ASSERT_DISABLE(reg_rel >= 0); /* unsigned */ - DUK_ASSERT(reg_rel < ((duk_hcompfunc *) env_func)->nregs); - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THREAD(thr)); - DUK_ASSERT(tv != NULL); - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); - DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_THREAD(DUK_TVAL_GET_OBJECT(tv))); - env_thr = (duk_hthread *) DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(env_thr != NULL); - /* Note: env_thr != thr is quite possible and normal, so careful - * with what thread is used for valstack lookup. - */ - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_REGBASE(thr)); - DUK_ASSERT(tv != NULL); - DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); - env_regbase = (duk_size_t) DUK_TVAL_GET_NUMBER(tv); - - idx = env_regbase + reg_rel; - tv = env_thr->valstack + idx; - DUK_ASSERT(tv >= env_thr->valstack && tv < env_thr->valstack_end); /* XXX: more accurate? */ + idx = env->regbase + reg_rel; + tv = env->thread->valstack + idx; + DUK_ASSERT(tv >= env->thread->valstack && tv < env->thread->valstack_end); /* XXX: more accurate? */ out->value = tv; out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */ - out->this_binding = NULL; /* implicit this value always undefined for - * declarative environment records. - */ - out->env = env; + out->env = (duk_hobject *) env; out->holder = NULL; - + out->has_this = 0; return 1; } @@ -859,6 +803,7 @@ return 0; } + /* XXX: move varmap to duk_hcompfunc struct field. */ tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARMAP(thr)); if (!tv) { return 0; @@ -882,12 +827,9 @@ out->value = tv; out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */ - out->this_binding = NULL; /* implicit this value always undefined for - * declarative environment records. - */ out->env = NULL; out->holder = NULL; - + out->has_this = 0; return 1; } @@ -899,7 +841,6 @@ duk_bool_t parents, duk__id_lookup_result *out) { duk_tval *tv; - duk_tval *tv_target; duk_tval tv_name; duk_uint_t sanity; @@ -940,10 +881,10 @@ if (duk__getid_activation_regs(thr, name, act, out)) { DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " - "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O " + "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " "(found from register bindings when env=NULL)", (duk_heaphdr *) name, (duk_tval *) out->value, - (long) out->attrs, (duk_tval *) out->this_binding, + (long) out->attrs, (long) out->has_this, (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); return 1; } @@ -1020,37 +961,30 @@ * register-bound variables. */ - if (DUK_HOBJECT_HAS_ENVRECCLOSED(env)) { - /* already closed */ - goto skip_regs; - } - - if (duk__getid_open_decl_env_regs(thr, name, env, out)) { + DUK_ASSERT_HDECENV_VALID((duk_hdecenv *) env); + if (duk__getid_open_decl_env_regs(thr, name, (duk_hdecenv *) env, out)) { DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " - "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O " + "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " "(declarative environment record, scope open, found in regs)", (duk_heaphdr *) name, (duk_tval *) out->value, - (long) out->attrs, (duk_tval *) out->this_binding, + (long) out->attrs, (long) out->has_this, (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); return 1; } - skip_regs: tv = duk_hobject_find_existing_entry_tval_ptr_and_attrs(thr->heap, env, name, &attrs); if (tv) { out->value = tv; out->attrs = attrs; - out->this_binding = NULL; /* implicit this value always undefined for - * declarative environment records. - */ out->env = env; out->holder = env; + out->has_this = 0; DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " - "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O " + "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " "(declarative environment record, found in properties)", (duk_heaphdr *) name, (duk_tval *) out->value, - (long) out->attrs, (duk_tval *) out->this_binding, + (long) out->attrs, (long) out->has_this, (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); return 1; } @@ -1073,11 +1007,9 @@ duk_bool_t found; DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV); + DUK_ASSERT_HOBJENV_VALID((duk_hobjenv *) env); - tv_target = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_TARGET(thr)); - DUK_ASSERT(tv_target != NULL); - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_target)); - target = DUK_TVAL_GET_OBJECT(tv_target); + target = ((duk_hobjenv *) env)->target; DUK_ASSERT(target != NULL); /* Target may be a Proxy or property may be an accessor, so we must @@ -1088,10 +1020,13 @@ */ if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(target)) { + duk_tval tv_target_tmp; + DUK_ASSERT(name != NULL); DUK_TVAL_SET_STRING(&tv_name, name); + DUK_TVAL_SET_OBJECT(&tv_target_tmp, target); - found = duk_hobject_hasprop(thr, tv_target, &tv_name); + found = duk_hobject_hasprop(thr, &tv_target_tmp, &tv_name); } else { /* XXX: duk_hobject_hasprop() would be correct for * non-Proxy objects too, but it is about ~20-25% @@ -1104,16 +1039,15 @@ if (found) { out->value = NULL; /* can't get value, may be accessor */ out->attrs = 0; /* irrelevant when out->value == NULL */ - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THIS(thr)); - out->this_binding = tv; /* may be NULL */ out->env = env; out->holder = target; + out->has_this = ((duk_hobjenv *) env)->has_this; DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " - "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O " + "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " "(object environment record)", (duk_heaphdr *) name, (duk_tval *) out->value, - (long) out->attrs, (duk_tval *) out->this_binding, + (long) out->attrs, (long) out->has_this, (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); return 1; } @@ -1125,11 +1059,11 @@ goto fail_not_found; } - if (sanity-- == 0) { + if (DUK_UNLIKELY(sanity-- == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); } env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env); - }; + } /* * Not found (even in global object) @@ -1236,29 +1170,27 @@ parents = 1; /* follow parent chain */ if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) { if (ref.value) { - DUK_ASSERT(ref.this_binding == NULL); /* always for register bindings */ duk_push_tval(ctx, ref.value); duk_push_undefined(ctx); } else { DUK_ASSERT(ref.holder != NULL); - /* Note: getprop may invoke any getter and invalidate any - * duk_tval pointers, so this must be done first. + /* ref.holder is safe across the getprop call (even + * with side effects) because 'env' is reachable and + * ref.holder is a direct heap pointer. */ - if (ref.this_binding) { - duk_push_tval(ctx, ref.this_binding); - } else { - duk_push_undefined(ctx); - } - DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder); DUK_TVAL_SET_STRING(&tv_tmp_key, name); - (void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key); /* [this value] */ + (void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key); /* [value] */ - /* ref.value, ref.this.binding invalidated here by getprop call */ + if (ref.has_this) { + duk_push_hobject(ctx, ref.holder); + } else { + duk_push_undefined(ctx); + } - duk_insert(ctx, -2); /* [this value] -> [value this] */ + /* [value this] */ } return 1; @@ -1361,13 +1293,11 @@ */ duk_tval *tv_val; - DUK_ASSERT(ref.this_binding == NULL); /* always for register bindings */ - tv_val = ref.value; DUK_ASSERT(tv_val != NULL); DUK_TVAL_SET_TVAL_UPDREF(thr, tv_val, val); /* side effects */ - /* ref.value and ref.this_binding invalidated here */ + /* ref.value invalidated here */ } else { DUK_ASSERT(ref.holder != NULL); @@ -1375,7 +1305,7 @@ DUK_TVAL_SET_STRING(&tv_tmp_key, name); (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, strict); - /* ref.value and ref.this_binding invalidated here */ + /* ref.value invalidated here */ } return; @@ -1748,14 +1678,11 @@ */ if (DUK_HOBJECT_IS_DECENV(env)) { + DUK_ASSERT_HDECENV_VALID((duk_hdecenv *) env); holder = env; } else { - DUK_ASSERT(DUK_HOBJECT_IS_OBJENV(env)); - - tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_TARGET(thr)); - DUK_ASSERT(tv != NULL); - DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); - holder = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT_HOBJENV_VALID((duk_hobjenv *) env); + holder = ((duk_hobjenv *) env)->target; DUK_ASSERT(holder != NULL); } @@ -1797,6 +1724,10 @@ duk_bool_t is_func_decl) { duk_hobject *env; duk_tval tv_val_copy; + duk_size_t act_off; + + DUK_ASSERT(act != NULL); + act_off = (duk_size_t) ((duk_uint8_t *) act - (duk_uint8_t *) thr->callstack); /* * Make a value copy of the input val. This ensures that @@ -1813,6 +1744,7 @@ if (!act->var_env) { DUK_ASSERT(act->lex_env == NULL); duk_js_init_activation_environment_records_delayed(thr, act); + act = (duk_activation *) (void *) ((duk_uint8_t *) thr->callstack + act_off); } DUK_ASSERT(act->lex_env != NULL); DUK_ASSERT(act->var_env != NULL); diff -Nru duktape-2.0.0/src-separate/duk_lexer.c duktape-2.1.1/src-separate/duk_lexer.c --- duktape-2.0.0/src-separate/duk_lexer.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_lexer.c 2017-07-28 22:05:08.000000000 +0000 @@ -744,6 +744,68 @@ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE); } +/* Parse legacy octal escape of the form \N{1,3}, e.g. \0, \5, \0377. Maximum + * allowed value is \0377 (U+00FF), longest match is used. Used for both string + * RegExp octal escape parsing. Window[0] must be the slash '\' and the first + * digit must already be validated to be in [0-9] by the caller. + */ +DUK_LOCAL duk_codepoint_t duk__lexer_parse_legacy_octal(duk_lexer_ctx *lex_ctx, duk_small_int_t *out_adv, duk_bool_t reject_annex_b) { + duk_codepoint_t cp; + duk_small_uint_t lookup_idx; + duk_small_int_t adv; + duk_codepoint_t tmp; + + DUK_ASSERT(out_adv != NULL); + DUK_ASSERT(DUK__LOOKUP(lex_ctx, 0) == DUK_ASC_BACKSLASH); + DUK_ASSERT(DUK__LOOKUP(lex_ctx, 1) >= DUK_ASC_0 && DUK__LOOKUP(lex_ctx, 1) <= DUK_ASC_9); + + cp = 0; + for (lookup_idx = 1; lookup_idx <= 3; lookup_idx++) { + DUK_DDD(DUK_DDDPRINT("lookup_idx=%ld, cp=%ld", (long) lookup_idx, (long) cp)); + tmp = DUK__LOOKUP(lex_ctx, lookup_idx); + if (tmp < DUK_ASC_0 || tmp > DUK_ASC_7) { + /* No more valid digits. */ + break; + } + tmp = (cp << 3) + (tmp - DUK_ASC_0); + if (tmp > 0xff) { + /* Three digit octal escapes above \377 (= 0xff) + * are not allowed. + */ + break; + } + cp = tmp; + } + DUK_DDD(DUK_DDDPRINT("final lookup_idx=%ld, cp=%ld", (long) lookup_idx, (long) cp)); + + adv = lookup_idx; + if (lookup_idx == 1) { + DUK_DDD(DUK_DDDPRINT("\\8 or \\9 -> treat as literal, accept in strict mode too")); + DUK_ASSERT(tmp == DUK_ASC_8 || tmp == DUK_ASC_9); + cp = tmp; + adv++; /* correction to above, eat offending character */ + } else if (lookup_idx == 2 && cp == 0) { + /* Note: 'foo\0bar' is OK in strict mode, but 'foo\00bar' is not. + * It won't be interpreted as 'foo\u{0}0bar' but as a SyntaxError. + */ + DUK_DDD(DUK_DDDPRINT("\\0 -> accept in strict mode too")); + } else { + /* This clause also handles non-shortest zero, e.g. \00. */ + if (reject_annex_b) { + DUK_DDD(DUK_DDDPRINT("non-zero octal literal %ld -> reject in strict-mode", (long) cp)); + cp = -1; + } else { + DUK_DDD(DUK_DDDPRINT("non-zero octal literal %ld -> accepted", (long) cp)); + DUK_ASSERT(cp >= 0 && cp <= 0xff); + } + } + + *out_adv = adv; + + DUK_ASSERT((cp >= 0 && cp <= 0xff) || (cp == -1 && reject_annex_b)); + return cp; +} + /* XXX: move strict mode to lex_ctx? */ DUK_LOCAL void duk__lexer_parse_string_literal(duk_lexer_ctx *lex_ctx, duk_token *out_token, duk_small_int_t quote, duk_bool_t strict_mode) { duk_small_int_t adv; @@ -829,46 +891,9 @@ * Parse octal (up to 3 digits) from the lookup window. */ - duk_codepoint_t tmp; - duk_small_uint_t lookup_idx; - - emitcp = 0; - for (lookup_idx = 1; lookup_idx <= 3; lookup_idx++) { - DUK_DDD(DUK_DDDPRINT("lookup_idx=%ld, emitcp=%ld", (long) lookup_idx, (long) emitcp)); - tmp = DUK__LOOKUP(lex_ctx, lookup_idx); - if (tmp < DUK_ASC_0 || tmp > DUK_ASC_7) { - /* No more valid digits. */ - break; - } - tmp = (emitcp << 3) + (tmp - DUK_ASC_0); - if (tmp > 0xff) { - /* Three digit octal escapes above \377 (= 0xff) - * are not allowed. - */ - break; - } - emitcp = tmp; - } - DUK_DDD(DUK_DDDPRINT("final lookup_idx=%ld, emitcp=%ld", (long) lookup_idx, (long) emitcp)); - - adv = lookup_idx; - if (lookup_idx == 1) { - /* \8 or \9 -> treat as literal, accept also - * in strict mode. - */ - DUK_DDD(DUK_DDDPRINT("\\8 or \\9 -> treat as literal, accept in strict mode too")); - emitcp = x; - adv++; /* correction to above, eat offending character */ - } else if (lookup_idx == 2 && emitcp == 0) { - /* Zero escape, also allowed in non-strict mode. */ - DUK_DDD(DUK_DDDPRINT("\\0 -> accept in strict mode too")); - } else { - /* Valid octal, only accept in non-strict mode. */ - DUK_DDD(DUK_DDDPRINT("octal literal %ld -> accept only in non-strict-mode", (long) emitcp)); - DUK_ASSERT(emitcp >= 0 && emitcp <= 0xff); - if (strict_mode) { - goto fail_escape; - } + emitcp = duk__lexer_parse_legacy_octal(lex_ctx, &adv, strict_mode /*reject_annex_b*/); + if (emitcp < 0) { + goto fail_escape; } } else if (x < 0) { goto fail_unterminated; @@ -919,6 +944,19 @@ return; } +/* Skip to end-of-line (or end-of-file), used for single line comments. */ +DUK_LOCAL void duk__lexer_skip_to_endofline(duk_lexer_ctx *lex_ctx) { + for (;;) { + duk_codepoint_t x; + + x = DUK__L0(); + if (x < 0 || duk_unicode_is_line_terminator(x)) { + break; + } + DUK__ADVANCECHARS(lex_ctx, 1); + } +} + /* * Parse Ecmascript source InputElementDiv or InputElementRegExp * (E5 Section 7), skipping whitespace, comments, and line terminators. @@ -1057,6 +1095,17 @@ DUK__ADVANCECHARS(lex_ctx, 1); got_lineterm = 1; goto restart_lineupdate; +#if defined(DUK_USE_SHEBANG_COMMENTS) + case DUK_ASC_HASH: /* '#' */ + if (DUK__L1() == DUK_ASC_EXCLAMATION && lex_ctx->window[0].offset == 0 && + (lex_ctx->flags & DUK_COMPILE_SHEBANG)) { + /* "Shebang" comment ('#! ...') on first line. */ + /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but not necessary */ + duk__lexer_skip_to_endofline(lex_ctx); + goto restart; /* line terminator will be handled on next round */ + } + goto fail_token; +#endif /* DUK_USE_SHEBANG_COMMENTS */ case DUK_ASC_SLASH: /* '/' */ if (DUK__L1() == DUK_ASC_SLASH) { /* @@ -1064,14 +1113,8 @@ * code point). */ - /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but it unnecessary */ - for (;;) { - x = DUK__L0(); - if (x < 0 || duk_unicode_is_line_terminator(x)) { - break; - } - DUK__ADVANCECHARS(lex_ctx, 1); - } + /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but not necessary */ + duk__lexer_skip_to_endofline(lex_ctx); goto restart; /* line terminator will be handled on next round */ } else if (DUK__L1() == DUK_ASC_STAR) { /* @@ -1256,6 +1299,18 @@ advtok = DUK__ADVTOK(1, DUK_TOK_COMMA); break; case DUK_ASC_LANGLE: /* '<' */ +#if defined(DUK_USE_HTML_COMMENTS) + if (DUK__L1() == DUK_ASC_EXCLAMATION && DUK__L2() == DUK_ASC_MINUS && DUK__L3() == DUK_ASC_MINUS) { + /* + * ES6: B.1.3, handle "" SingleLineHTMLCloseComment + * Only allowed: + * - on new line + * - preceded only by whitespace + * - preceded by end of multiline comment and optional whitespace + * + * Since whitespace generates no tokens, and multiline comments + * are treated as a line ending, consulting `got_lineterm` is + * sufficient to test for these three options. + */ + + /* DUK__ADVANCECHARS(lex_ctx, 3) would be correct here, but not necessary */ + duk__lexer_skip_to_endofline(lex_ctx); + goto restart; /* line terminator will be handled on next round */ + } else +#endif /* DUK_USE_HTML_COMMENTS */ if (DUK__L1() == DUK_ASC_MINUS) { advtok = DUK__ADVTOK(2, DUK_TOK_DECREMENT); } else if (DUK__L1() == DUK_ASC_EQUALS) { @@ -2020,6 +2094,8 @@ } else if (DUK__L2() == DUK_ASC_COLON) { /* (?: */ advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_START_NONCAPTURE_GROUP); + } else { + goto fail_group; } } else { /* ( */ @@ -2087,6 +2163,10 @@ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_ESCAPE); return; + fail_group: + DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_GROUP); + return; + #if !defined(DUK_USE_ES6_REGEXP_SYNTAX) fail_invalid_char: DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_CHARACTER); @@ -2163,7 +2243,7 @@ DUK__ADVANCECHARS(lex_ctx, 1); /* eat ']' before finishing */ break; } else if (x == DUK_ASC_MINUS) { - if (start >= 0 && !dash && DUK__L0() != DUK_ASC_RBRACKET) { + if (start >= 0 && !dash && DUK__L1() != DUK_ASC_RBRACKET) { /* '-' as a range indicator */ dash = 1; continue; @@ -2260,12 +2340,24 @@ sizeof(duk_unicode_re_ranges_not_wordchar) / sizeof(duk_uint16_t)); ch = -1; } else if (DUK__ISDIGIT(x)) { - /* DecimalEscape, only \0 is allowed, no leading zeroes are allowed */ + /* DecimalEscape, only \0 is allowed, no leading + * zeroes are allowed. + * + * ES2015 Annex B also allows (maximal match) legacy + * octal escapes up to \377 and \8 and \9 are + * accepted as literal '8' and '9', also in strict mode. + */ + +#if defined(DUK_USE_ES6_REGEXP_SYNTAX) + ch = duk__lexer_parse_legacy_octal(lex_ctx, &adv, 0 /*reject_annex_b*/); + DUK_ASSERT(ch >= 0); /* no rejections */ +#else if (x == DUK_ASC_0 && !DUK__ISDIGIT(DUK__L2())) { ch = 0x0000; } else { goto fail_escape; } +#endif #if defined(DUK_USE_ES6_REGEXP_SYNTAX) } else if (x >= 0) { /* IdentityEscape: ES2015 Annex B allows almost all diff -Nru duktape-2.0.0/src-separate/duk_lexer.h duktape-2.1.1/src-separate/duk_lexer.h --- duktape-2.0.0/src-separate/duk_lexer.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_lexer.h 2017-07-28 22:05:08.000000000 +0000 @@ -32,7 +32,7 @@ #define DUK_LEXER_GETPOINT(ctx,pt) duk_lexer_getpoint((ctx), (pt)) -/* currently 6 characters of lookup are actually needed (duk_lexer.c) */ +/* Currently 6 characters of lookup are actually needed (duk_lexer.c). */ #define DUK_LEXER_WINDOW_SIZE 6 #if defined(DUK_USE_LEXER_SLIDING_WINDOW) #define DUK_LEXER_BUFFER_SIZE 64 @@ -410,6 +410,8 @@ duk_int_t token_count; /* number of tokens parsed */ duk_int_t token_limit; /* maximum token count before error (sanity backstop) */ + + duk_small_uint_t flags; /* lexer flags, use compiler flag defines for now */ }; /* diff -Nru duktape-2.0.0/src-separate/duk_refcount.h duktape-2.1.1/src-separate/duk_refcount.h --- duktape-2.0.0/src-separate/duk_refcount.h 1970-01-01 00:00:00.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_refcount.h 2017-07-28 22:05:08.000000000 +0000 @@ -0,0 +1,698 @@ +/* + * Reference counting helper macros. The macros take a thread argument + * and must thus always be executed in a specific thread context. The + * thread argument is not really needed anymore: DECREF can operate with + * a heap pointer only, and INCREF needs neither. + */ + +#if !defined(DUK_REFCOUNT_H_INCLUDED) +#define DUK_REFCOUNT_H_INCLUDED + +#if defined(DUK_USE_REFERENCE_COUNTING) + +#if defined(DUK_USE_ROM_OBJECTS) +/* With ROM objects "needs refcount update" is true when the value is + * heap allocated and is not a ROM object. + */ +/* XXX: double evaluation for 'tv' argument. */ +#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) \ + (DUK_TVAL_IS_HEAP_ALLOCATED((tv)) && !DUK_HEAPHDR_HAS_READONLY(DUK_TVAL_GET_HEAPHDR((tv)))) +#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) (!DUK_HEAPHDR_HAS_READONLY((h))) +#else /* DUK_USE_ROM_OBJECTS */ +/* Without ROM objects "needs refcount update" == is heap allocated. */ +#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) DUK_TVAL_IS_HEAP_ALLOCATED((tv)) +#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 1 +#endif /* DUK_USE_ROM_OBJECTS */ + +/* Fast variants, inline refcount operations except for refzero handling. + * Can be used explicitly when speed is always more important than size. + * For a good compiler and a single file build, these are basically the + * same as a forced inline. + */ +#define DUK_TVAL_INCREF_FAST(thr,tv) do { \ + duk_tval *duk__tv = (tv); \ + DUK_ASSERT(duk__tv != NULL); \ + if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \ + duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \ + DUK_ASSERT(duk__h != NULL); \ + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ + DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \ + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) != 0); /* No wrapping. */ \ + } \ + } while (0) +#define DUK_TVAL_DECREF_FAST(thr,tv) do { \ + duk_tval *duk__tv = (tv); \ + DUK_ASSERT(duk__tv != NULL); \ + if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \ + duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \ + DUK_ASSERT(duk__h != NULL); \ + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \ + if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \ + duk_heaphdr_refzero((thr), duk__h); \ + } \ + } \ + } while (0) +#define DUK_TVAL_DECREF_NORZ_FAST(thr,tv) do { \ + duk_tval *duk__tv = (tv); \ + DUK_ASSERT(duk__tv != NULL); \ + if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \ + duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \ + DUK_ASSERT(duk__h != NULL); \ + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \ + if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \ + duk_heaphdr_refzero_norz((thr), duk__h); \ + } \ + } \ + } while (0) +#define DUK_HEAPHDR_INCREF_FAST(thr,h) do { \ + duk_heaphdr *duk__h = (duk_heaphdr *) (h); \ + DUK_ASSERT(duk__h != NULL); \ + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ + if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \ + DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \ + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) != 0); /* No wrapping. */ \ + } \ + } while (0) +#define DUK_HEAPHDR_DECREF_FAST_RAW(thr,h,rzcall,rzcast) do { \ + duk_heaphdr *duk__h = (duk_heaphdr *) (h); \ + DUK_ASSERT(duk__h != NULL); \ + DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \ + if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \ + if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \ + (rzcall)((thr), (rzcast) duk__h); \ + } \ + } \ + } while (0) +#define DUK_HEAPHDR_DECREF_FAST(thr,h) \ + DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *) +#define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) \ + DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *) + +/* Slow variants, call to a helper to reduce code size. + * Can be used explicitly when size is always more important than speed. + */ +#define DUK_TVAL_INCREF_SLOW(thr,tv) do { duk_tval_incref((tv)); } while (0) +#define DUK_TVAL_DECREF_SLOW(thr,tv) do { duk_tval_decref((thr), (tv)); } while (0) +#define DUK_TVAL_DECREF_NORZ_SLOW(thr,tv) do { duk_tval_decref_norz((thr), (tv)); } while (0) +#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) +#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) +#define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) +#define DUK_HSTRING_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) +#define DUK_HSTRING_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) +#define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) +#define DUK_HBUFFER_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) +#define DUK_HBUFFER_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) +#define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) +#define DUK_HOBJECT_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) +#define DUK_HOBJECT_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) +#define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) + +/* Default variants. Selection depends on speed/size preference. + * Concretely: with gcc 4.8.1 -Os x64 the difference in final binary + * is about +1kB for _FAST variants. + */ +#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) +/* XXX: It would be nice to specialize for specific duk_hobject subtypes + * but current refzero queue handling prevents that. + */ +#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_FAST((thr),(tv)) +#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_FAST((thr),(tv)) +#define DUK_TVAL_DECREF_NORZ(thr,tv) DUK_TVAL_DECREF_NORZ_FAST((thr),(tv)) +#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_FAST((thr),(h)) +#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *) +#define DUK_HEAPHDR_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *) +#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) +#define DUK_HSTRING_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *) +#define DUK_HSTRING_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *) /* no 'norz' variant */ +#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) +#define DUK_HOBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) +#define DUK_HOBJECT_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) +#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) +#define DUK_HBUFFER_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *) +#define DUK_HBUFFER_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *) /* no 'norz' variant */ +#define DUK_HCOMPFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HCOMPFUNC_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) +#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) +#define DUK_HNATFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HNATFUNC_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) +#define DUK_HNATFUNC_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) +#define DUK_HBUFOBJ_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HBUFOBJ_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) +#define DUK_HBUFOBJ_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) +#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HTHREAD_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) +#define DUK_HTHREAD_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) +#else +#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_SLOW((thr),(tv)) +#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_SLOW((thr),(tv)) +#define DUK_TVAL_DECREF_NORZ(thr,tv) DUK_TVAL_DECREF_NORZ_SLOW((thr),(tv)) +#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_SLOW((thr),(h)) +#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_SLOW((thr),(h)) +#define DUK_HEAPHDR_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_NORZ_SLOW((thr),(h)) +#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) +#define DUK_HSTRING_DECREF(thr,h) DUK_HSTRING_DECREF_SLOW((thr),(h)) +#define DUK_HSTRING_DECREF_NORZ(thr,h) DUK_HSTRING_DECREF_NORZ_SLOW((thr),(h)) +#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) +#define DUK_HOBJECT_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(h)) +#define DUK_HOBJECT_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(h)) +#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) +#define DUK_HBUFFER_DECREF(thr,h) DUK_HBUFFER_DECREF_SLOW((thr),(h)) +#define DUK_HBUFFER_DECREF_NORZ(thr,h) DUK_HBUFFER_DECREF_NORZ_SLOW((thr),(h)) +#define DUK_HCOMPFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HCOMPFUNC_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) +#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) +#define DUK_HNATFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HNATFUNC_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) +#define DUK_HNATFUNC_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) +#define DUK_HBUFOBJ_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HBUFOBJ_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) +#define DUK_HBUFOB_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) +#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) +#define DUK_HTHREAD_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) +#define DUK_HTHREAD_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) +#endif + +/* Convenience for some situations; the above macros don't allow NULLs + * for performance reasons. Macros cover only actually needed cases. + */ +#define DUK_HEAPHDR_INCREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HEAPHDR_INCREF((thr), (duk_heaphdr *) (h)); \ + } \ + } while (0) +#define DUK_HEAPHDR_DECREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HEAPHDR_DECREF((thr), (duk_heaphdr *) (h)); \ + } \ + } while (0) +#define DUK_HEAPHDR_DECREF_NORZ_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HEAPHDR_DECREF_NORZ((thr), (duk_heaphdr *) (h)); \ + } \ + } while (0) +#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HOBJECT_INCREF((thr), (h)); \ + } \ + } while (0) +#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HOBJECT_DECREF((thr), (h)); \ + } \ + } while (0) +#define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HOBJECT_DECREF_NORZ((thr), (h)); \ + } \ + } while (0) +#define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HBUFFER_INCREF((thr), (h)); \ + } \ + } while (0) +#define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HBUFFER_DECREF((thr), (h)); \ + } \ + } while (0) +#define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HBUFFER_DECREF_NORZ((thr), (h)); \ + } \ + } while (0) +#define DUK_HTHREAD_INCREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HTHREAD_INCREF((thr), (h)); \ + } \ + } while (0) +#define DUK_HTHREAD_DECREF_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HTHREAD_DECREF((thr), (h)); \ + } \ + } while (0) +#define DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr,h) do { \ + if ((h) != NULL) { \ + DUK_HTHREAD_DECREF_NORZ((thr), (h)); \ + } \ + } while (0) + +/* Called after one or more DECREF NORZ calls to handle pending side effects. + * At present DECREF NORZ does freeing inline but doesn't execute finalizers, + * so these macros check for pending finalizers and execute them. The FAST + * variant is performance critical. + */ +#if defined(DUK_USE_FINALIZER_SUPPORT) +#define DUK_REFZERO_CHECK_FAST(thr) do { \ + duk_refzero_check_fast((thr)); \ + } while (0) +#define DUK_REFZERO_CHECK_SLOW(thr) do { \ + duk_refzero_check_slow((thr)); \ + } while (0) +#else /* DUK_USE_FINALIZER_SUPPORT */ +#define DUK_REFZERO_CHECK_FAST(thr) do { } while (0) +#define DUK_REFZERO_CHECK_SLOW(thr) do { } while (0) +#endif /* DUK_USE_FINALIZER_SUPPORT */ + +/* + * Macros to set a duk_tval and update refcount of the target (decref the + * old value and incref the new value if necessary). This is both performance + * and footprint critical; any changes made should be measured for size/speed. + */ + +#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_UNDEFINED(tv__dst); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_UNDEFINED(tv__dst); \ + DUK_TVAL_DECREF_NORZ((thr), &tv__tmp); \ + } while (0) + +#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_UNUSED(tv__dst); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_NULL(tv__dst); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) +#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) +#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) +#define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_NAN(tv__dst); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) +#if defined(DUK_USE_FASTINT) +#define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_I48(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) +#define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_I32(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) +#define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_U32(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) +#else +#define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \ + DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval)) +#endif /* DUK_USE_FASTINT */ + +#define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_STRING(tv__dst, (newval)); \ + DUK_HSTRING_INCREF((thr), (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \ + DUK_HOBJECT_INCREF((thr), (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \ + DUK_HBUFFER_INCREF((thr), (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +#define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_POINTER(tv__dst, (newval)); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +/* DUK_TVAL_SET_TVAL_UPDREF() is used a lot in executor, property lookups, + * etc, so it's very important for performance. Measure when changing. + * + * NOTE: the source and destination duk_tval pointers may be the same, and + * the macros MUST deal with that correctly. + */ + +/* Original idiom used, minimal code size. */ +#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \ + duk_tval *tv__dst, *tv__src; duk_tval tv__tmp; \ + tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ + DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ + DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ + DUK_TVAL_INCREF((thr), tv__src); \ + DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ + } while (0) + +/* Faster alternative: avoid making a temporary copy of tvptr_dst and use + * fast incref/decref macros. + */ +#define DUK_TVAL_SET_TVAL_UPDREF_ALT1(thr,tvptr_dst,tvptr_src) do { \ + duk_tval *tv__dst, *tv__src; duk_heaphdr *h__obj; \ + tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ + DUK_TVAL_INCREF_FAST((thr), tv__src); \ + if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv__dst)) { \ + h__obj = DUK_TVAL_GET_HEAPHDR(tv__dst); \ + DUK_ASSERT(h__obj != NULL); \ + DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ + DUK_HEAPHDR_DECREF_FAST((thr), h__obj); /* side effects */ \ + } else { \ + DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ + } \ + } while (0) + +/* XXX: no optimized variants yet */ +#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 +#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0 +#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0 +#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0 +#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0 +#define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0 +#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0 +#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0 +#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0 +#if defined(DUK_USE_FASTINT) +#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_I48_UPDREF_ALT0 +#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_I32_UPDREF_ALT0 +#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_U32_UPDREF_ALT0 +#else +#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast int-to-double */ +#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF +#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF +#endif /* DUK_USE_FASTINT */ +#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_I48_UPDREF /* convenience */ +#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0 +#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0 +#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0 +#define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0 +#define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0 + +#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) +/* Optimized for speed. */ +#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT1 +#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT1 +#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0 +#else +/* Optimized for size. */ +#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0 +#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0 +#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0 +#endif + +#else /* DUK_USE_REFERENCE_COUNTING */ + +#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) 0 +#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 0 + +#define DUK_TVAL_INCREF_FAST(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_DECREF_FAST(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_DECREF_NORZ_FAST(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_INCREF_SLOW(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_DECREF_SLOW(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_DECREF_NORZ_SLOW(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_INCREF(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_DECREF(thr,v) do {} while (0) /* nop */ +#define DUK_TVAL_DECREF_NORZ(thr,v) do {} while (0) /* nop */ +#define DUK_HEAPHDR_INCREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_DECREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HEAPHDR_DECREF_NORZ(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_INCREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_DECREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_INCREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_DECREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HSTRING_DECREF_NORZ(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_INCREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_INCREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF_NORZ(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_INCREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_INCREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF_NORZ(thr,h) do {} while (0) /* nop */ + +#define DUK_HCOMPFUNC_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HCOMPFUNC_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) do {} while (0) /* nop */ +#define DUK_HNATFUNC_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HNATFUNC_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HNATFUNC_DECREF_NORZ(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFOBJ_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFOBJ_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFOBJ_DECREF_NORZ(thr,h) do {} while (0) /* nop */ +#define DUK_HTHREAD_INCREF(thr,h) do {} while (0) /* nop */ +#define DUK_HTHREAD_DECREF(thr,h) do {} while (0) /* nop */ +#define DUK_HTHREAD_DECREF_NORZ(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ +#define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ +#define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do {} while (0) /* nop */ + +#define DUK_REFZERO_CHECK_FAST(thr) do {} while (0) /* nop */ +#define DUK_REFZERO_CHECK_SLOW(thr) do {} while (0) /* nop */ + +#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_UNDEFINED(tv__dst); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_UNUSED(tv__dst); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_NULL(tv__dst); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) +#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) +#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) +#define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_NAN(tv__dst); \ + DUK_UNREF((thr)); \ + } while (0) +#if defined(DUK_USE_FASTINT) +#define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_I48(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) +#define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_I32(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) +#define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_U32(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) +#else +#define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \ + DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval)) +#endif /* DUK_USE_FASTINT */ + +#define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_STRING(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ + duk_tval *tv__dst; tv__dst = (tvptr_dst); \ + DUK_TVAL_SET_POINTER(tv__dst, (newval)); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \ + duk_tval *tv__dst, *tv__src; \ + tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ + DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ + DUK_UNREF((thr)); \ + } while (0) + +#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 +#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 +#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0 +#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0 +#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0 +#define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0 +#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0 +#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0 +#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0 +#if defined(DUK_USE_FASTINT) +#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_I48_UPDREF_ALT0 +#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_I32_UPDREF_ALT0 +#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_U32_UPDREF_ALT0 +#else +#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast-int-to-double */ +#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF +#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF +#endif /* DUK_USE_FASTINT */ +#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_I48_UPDREF /* convenience */ +#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0 +#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0 +#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0 +#define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0 +#define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0 + +#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0 +#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0 +#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0 + +#endif /* DUK_USE_REFERENCE_COUNTING */ + +#if defined(DUK_USE_REFERENCE_COUNTING) +#if defined(DUK_USE_FINALIZER_SUPPORT) +DUK_INTERNAL_DECL void duk_refzero_check_slow(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_refzero_check_fast(duk_hthread *thr); +#endif +DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize_norz(duk_heap *heap, duk_heaphdr *hdr); +DUK_INTERNAL_DECL void duk_hobject_refcount_finalize_norz(duk_heap *heap, duk_hobject *h); +#if 0 /* Not needed: fast path handles inline; slow path uses duk_heaphdr_decref() which is needed anyway. */ +DUK_INTERNAL_DECL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h); +DUK_INTERNAL_DECL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h); +DUK_INTERNAL_DECL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h); +DUK_INTERNAL_DECL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h); +DUK_INTERNAL_DECL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h); +DUK_INTERNAL_DECL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h); +#endif +DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h); +DUK_INTERNAL_DECL void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h); +#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) +DUK_INTERNAL_DECL void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h); /* no 'norz' variant */ +DUK_INTERNAL_DECL void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h); /* no 'norz' variant */ +DUK_INTERNAL_DECL void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h); +DUK_INTERNAL_DECL void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h); +#else +DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv); +DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv); +DUK_INTERNAL_DECL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv); +DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h); +DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h); +DUK_INTERNAL_DECL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h); +#endif +#else /* DUK_USE_REFERENCE_COUNTING */ +/* no refcounting */ +#endif /* DUK_USE_REFERENCE_COUNTING */ + +#endif /* DUK_REFCOUNT_H_INCLUDED */ diff -Nru duktape-2.0.0/src-separate/duk_regexp_compiler.c duktape-2.1.1/src-separate/duk_regexp_compiler.c --- duktape-2.0.0/src-separate/duk_regexp_compiler.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_regexp_compiler.c 2017-07-28 22:05:08.000000000 +0000 @@ -864,34 +864,34 @@ switch (c) { case (duk_uint8_t) 'g': { if (flags & DUK_RE_FLAG_GLOBAL) { - goto error; + goto flags_error; } flags |= DUK_RE_FLAG_GLOBAL; break; } case (duk_uint8_t) 'i': { if (flags & DUK_RE_FLAG_IGNORE_CASE) { - goto error; + goto flags_error; } flags |= DUK_RE_FLAG_IGNORE_CASE; break; } case (duk_uint8_t) 'm': { if (flags & DUK_RE_FLAG_MULTILINE) { - goto error; + goto flags_error; } flags |= DUK_RE_FLAG_MULTILINE; break; } default: { - goto error; + goto flags_error; } } } return flags; - error: + flags_error: DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_REGEXP_FLAGS); return 0; /* never here */ } diff -Nru duktape-2.0.0/src-separate/duk_regexp_executor.c duktape-2.1.1/src-separate/duk_regexp_executor.c --- duktape-2.0.0/src-separate/duk_regexp_executor.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_regexp_executor.c 2017-07-28 22:05:08.000000000 +0000 @@ -818,6 +818,7 @@ char_offset = (duk_uint32_t) 0; } + DUK_ASSERT(char_offset <= DUK_HSTRING_GET_CHARLEN(h_input)); sp = re_ctx.input + duk_heap_strcache_offset_char2byte(thr, h_input, char_offset); /* diff -Nru duktape-2.0.0/src-separate/duk_source_meta.json duktape-2.1.1/src-separate/duk_source_meta.json --- duktape-2.0.0/src-separate/duk_source_meta.json 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_source_meta.json 2017-07-28 22:05:08.000000000 +0000 @@ -1,10 +1,10 @@ { - "comment": "Metadata for Duktape build", - "duk_version_string": "2.0.0", + "comment": "Metadata for Duktape sources", + "duk_version_string": "2.1.1", "type": "duk_source_meta", - "duk_version": 20000, - "git_branch": "master", - "git_commit": "4180966c47d6d87106008dd4338de8d507c8072b", + "duk_version": 20101, + "git_branch": "v2.1-maintenance", + "git_commit": "9c8fba6392d1913cb5359be7b8f386fa3cdd8b4d", "builtin_strings_info": [ { "plain": "Undefined", @@ -487,6 +487,11 @@ "define": "DUK_STRIDX_INT_PC2LINE" }, { + "plain": "\u00ffThis", + "base64": "/1RoaXM=", + "define": "DUK_STRIDX_INT_THIS" + }, + { "plain": "\u00ffArgs", "base64": "/0FyZ3M=", "define": "DUK_STRIDX_INT_ARGS" @@ -507,34 +512,14 @@ "define": "DUK_STRIDX_INT_FINALIZER" }, { - "plain": "\u00ffHandler", - "base64": "/0hhbmRsZXI=", - "define": "DUK_STRIDX_INT_HANDLER" - }, - { - "plain": "\u00ffCallee", - "base64": "/0NhbGxlZQ==", - "define": "DUK_STRIDX_INT_CALLEE" - }, - { - "plain": "\u00ffThread", - "base64": "/1RocmVhZA==", - "define": "DUK_STRIDX_INT_THREAD" - }, - { - "plain": "\u00ffRegbase", - "base64": "/1JlZ2Jhc2U=", - "define": "DUK_STRIDX_INT_REGBASE" - }, - { "plain": "\u00ffTarget", "base64": "/1RhcmdldA==", "define": "DUK_STRIDX_INT_TARGET" }, { - "plain": "\u00ffThis", - "base64": "/1RoaXM=", - "define": "DUK_STRIDX_INT_THIS" + "plain": "\u00ffHandler", + "base64": "/0hhbmRsZXI=", + "define": "DUK_STRIDX_INT_HANDLER" }, { "plain": "compile", @@ -939,16 +924,13 @@ "/1Zhcm1hcA==", "/1NvdXJjZQ==", "/1BjMmxpbmU=", + "/1RoaXM=", "/0FyZ3M=", "/01hcA==", "/1ZhcmVudg==", "/0ZpbmFsaXplcg==", - "/0hhbmRsZXI=", - "/0NhbGxlZQ==", - "/1RocmVhZA==", - "/1JlZ2Jhc2U=", "/1RhcmdldA==", - "/1RoaXM=", + "/0hhbmRsZXI=", "Y29tcGlsZQ==", "aW5wdXQ=", "ZXJyQ3JlYXRl", @@ -1011,7 +993,7 @@ "c3RhdGlj", "eWllbGQ=" ], - "git_describe": "v2.0.0", + "git_describe": "v2.1.1", "builtin_strings": [ "Undefined", "Null", @@ -1109,16 +1091,13 @@ "\u00ffVarmap", "\u00ffSource", "\u00ffPc2line", + "\u00ffThis", "\u00ffArgs", "\u00ffMap", "\u00ffVarenv", "\u00ffFinalizer", - "\u00ffHandler", - "\u00ffCallee", - "\u00ffThread", - "\u00ffRegbase", "\u00ffTarget", - "\u00ffThis", + "\u00ffHandler", "compile", "input", "errCreate", diff -Nru duktape-2.0.0/src-separate/duk_strings.h duktape-2.1.1/src-separate/duk_strings.h --- duktape-2.0.0/src-separate/duk_strings.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_strings.h 2017-07-28 22:05:08.000000000 +0000 @@ -136,6 +136,7 @@ #define DUK_STR_INVALID_REGEXP_ESCAPE "invalid regexp escape" #define DUK_STR_INVALID_BACKREFS "invalid backreference(s)" #define DUK_STR_INVALID_REGEXP_CHARACTER "invalid regexp character" +#define DUK_STR_INVALID_REGEXP_GROUP "invalid regexp group" #define DUK_STR_UNTERMINATED_CHARCLASS "unterminated character class" #define DUK_STR_INVALID_RANGE "invalid range" diff -Nru duktape-2.0.0/src-separate/duktape.h duktape-2.1.1/src-separate/duktape.h --- duktape-2.0.0/src-separate/duktape.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duktape.h 2017-07-28 22:05:08.000000000 +0000 @@ -1,13 +1,13 @@ /* - * Duktape public API for Duktape 2.0.0. + * Duktape public API for Duktape 2.1.1. * - * See the API reference for documentation on call semantics. - * The exposed API is inside the DUK_API_PUBLIC_H_INCLUDED - * include guard. Other parts of the header are Duktape - * internal and related to platform/compiler/feature detection. + * See the API reference for documentation on call semantics. The exposed, + * supported API is between the "BEGIN PUBLIC API" and "END PUBLIC API" + * comments. Other parts of the header are Duktape internal and related to + * e.g. platform/compiler/feature detection. * - * Git commit 4180966c47d6d87106008dd4338de8d507c8072b (v2.0.0). - * Git branch master. + * Git commit 9c8fba6392d1913cb5359be7b8f386fa3cdd8b4d (v2.1.1). + * Git branch v2.1-maintenance. * * See Duktape AUTHORS.rst and LICENSE.txt for copyright and * licensing information. @@ -87,6 +87,8 @@ * * Brett Vickers (https://github.com/beevik) * * Dominik Okwieka (https://github.com/okitec) * * Remko Tron\u00e7on (https://el-tramo.be) + * * Romero Malaquias (rbsm@ic.ufal.br) + * * Michael Drake * * Other contributions * =================== @@ -135,18 +137,38 @@ #undef DUK_SINGLE_FILE -/* External duk_config.h provides platform/compiler/OS dependent - * typedefs and macros, and DUK_USE_xxx config options so that - * the rest of Duktape doesn't need to do any feature detection. +/* + * BEGIN PUBLIC API */ -#include "duk_config.h" /* - * BEGIN PUBLIC API + * Version and Git commit identification + */ + +/* Duktape version, (major * 10000) + (minor * 100) + patch. Allows C code + * to #if (DUK_VERSION >= NNN) against Duktape API version. The same value + * is also available to Ecmascript code in Duktape.version. Unofficial + * development snapshots have 99 for patch level (e.g. 0.10.99 would be a + * development version after 0.10.0 but before the next official release). */ +#define DUK_VERSION 20101L -#if !defined(DUK_API_PUBLIC_H_INCLUDED) -#define DUK_API_PUBLIC_H_INCLUDED +/* Git commit, describe, and branch for Duktape build. Useful for + * non-official snapshot builds so that application code can easily log + * which Duktape snapshot was used. Not available in the Ecmascript + * environment. + */ +#define DUK_GIT_COMMIT "9c8fba6392d1913cb5359be7b8f386fa3cdd8b4d" +#define DUK_GIT_DESCRIBE "v2.1.1" +#define DUK_GIT_BRANCH "v2.1-maintenance" + +/* External duk_config.h provides platform/compiler/OS dependent + * typedefs and macros, and DUK_USE_xxx config options so that + * the rest of Duktape doesn't need to do any feature detection. + * DUK_VERSION is defined before including so that configuration + * snippets can react to it. + */ +#include "duk_config.h" /* * Avoid C++ name mangling @@ -247,23 +269,6 @@ * Constants */ -/* Duktape version, (major * 10000) + (minor * 100) + patch. Allows C code - * to #if (DUK_VERSION >= NNN) against Duktape API version. The same value - * is also available to Ecmascript code in Duktape.version. Unofficial - * development snapshots have 99 for patch level (e.g. 0.10.99 would be a - * development version after 0.10.0 but before the next official release). - */ -#define DUK_VERSION 20000L - -/* Git commit, describe, and branch for Duktape build. Useful for - * non-official snapshot builds so that application code can easily log - * which Duktape snapshot was used. Not available in the Ecmascript - * environment. - */ -#define DUK_GIT_COMMIT "4180966c47d6d87106008dd4338de8d507c8072b" -#define DUK_GIT_DESCRIBE "v2.0.0" -#define DUK_GIT_BRANCH "master" - /* Duktape debug protocol version used by this build. */ #define DUK_DEBUG_PROTOCOL_VERSION 2 @@ -334,11 +339,13 @@ #define DUK_COMPILE_EVAL (1 << 3) /* compile eval code (instead of global code) */ #define DUK_COMPILE_FUNCTION (1 << 4) /* compile function code (instead of global code) */ #define DUK_COMPILE_STRICT (1 << 5) /* use strict (outer) context for global, eval, or function code */ -#define DUK_COMPILE_SAFE (1 << 6) /* (internal) catch compilation errors */ -#define DUK_COMPILE_NORESULT (1 << 7) /* (internal) omit eval result */ -#define DUK_COMPILE_NOSOURCE (1 << 8) /* (internal) no source string on stack */ -#define DUK_COMPILE_STRLEN (1 << 9) /* (internal) take strlen() of src_buffer (avoids double evaluation in macro) */ -#define DUK_COMPILE_NOFILENAME (1 << 10) /* (internal) no filename on stack */ +#define DUK_COMPILE_SHEBANG (1 << 6) /* allow shebang ('#! ...') comment on first line of source */ +#define DUK_COMPILE_SAFE (1 << 7) /* (internal) catch compilation errors */ +#define DUK_COMPILE_NORESULT (1 << 8) /* (internal) omit eval result */ +#define DUK_COMPILE_NOSOURCE (1 << 9) /* (internal) no source string on stack */ +#define DUK_COMPILE_STRLEN (1 << 10) /* (internal) take strlen() of src_buffer (avoids double evaluation in macro) */ +#define DUK_COMPILE_NOFILENAME (1 << 11) /* (internal) no filename on stack */ +#define DUK_COMPILE_FUNCEXPR (1 << 12) /* (internal) source is a function expression (used for Function constructor) */ /* Flags for duk_def_prop() and its variants */ #define DUK_DEFPROP_WRITABLE (1 << 0) /* set writable (effective if DUK_DEFPROP_HAVE_WRITABLE set) */ @@ -445,9 +452,9 @@ DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_fatal_raw(duk_context *ctx, const char *err_msg)); #define duk_fatal(ctx,err_msg) \ (duk_fatal_raw((ctx), (err_msg)), (duk_ret_t) 0) +DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...)); #if defined(DUK_API_VARIADIC_MACROS) -DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...)); #define duk_error(ctx,err_code,...) \ (duk_error_raw((ctx), (duk_errcode_t) (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0) #define duk_generic_error(ctx,...) \ @@ -516,6 +523,7 @@ #endif /* DUK_API_VARIADIC_MACROS */ DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap)); + #define duk_error_va(ctx,err_code,fmt,ap) \ (duk_error_va_raw((ctx), (duk_errcode_t) (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0) #define duk_generic_error_va(ctx,fmt,ap) \ @@ -663,19 +671,18 @@ #define duk_push_external_buffer(ctx) \ ((void) duk_push_buffer_raw((ctx), 0, DUK_BUF_FLAG_DYNAMIC | DUK_BUF_FLAG_EXTERNAL)) -#define DUK_BUFOBJ_CREATE_ARRBUF (1 << 4) /* internal flag: create backing ArrayBuffer; keep in one byte */ #define DUK_BUFOBJ_ARRAYBUFFER 0 -#define DUK_BUFOBJ_NODEJS_BUFFER (1 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_DATAVIEW (2 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_INT8ARRAY (3 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_UINT8ARRAY (4 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_UINT8CLAMPEDARRAY (5 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_INT16ARRAY (6 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_UINT16ARRAY (7 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_INT32ARRAY (8 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_UINT32ARRAY (9 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_FLOAT32ARRAY (10 | DUK_BUFOBJ_CREATE_ARRBUF) -#define DUK_BUFOBJ_FLOAT64ARRAY (11 | DUK_BUFOBJ_CREATE_ARRBUF) +#define DUK_BUFOBJ_NODEJS_BUFFER 1 +#define DUK_BUFOBJ_DATAVIEW 2 +#define DUK_BUFOBJ_INT8ARRAY 3 +#define DUK_BUFOBJ_UINT8ARRAY 4 +#define DUK_BUFOBJ_UINT8CLAMPEDARRAY 5 +#define DUK_BUFOBJ_INT16ARRAY 6 +#define DUK_BUFOBJ_UINT16ARRAY 7 +#define DUK_BUFOBJ_INT32ARRAY 8 +#define DUK_BUFOBJ_UINT32ARRAY 9 +#define DUK_BUFOBJ_FLOAT32ARRAY 10 +#define DUK_BUFOBJ_FLOAT64ARRAY 11 DUK_EXTERNAL_DECL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags); @@ -789,8 +796,43 @@ DUK_EXTERNAL_DECL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t idx); DUK_EXTERNAL_DECL duk_context *duk_get_context(duk_context *ctx, duk_idx_t idx); DUK_EXTERNAL_DECL void *duk_get_heapptr(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t idx, duk_size_t len); + +/* + * Get-with-explicit default operations: like get operations but with an + * explicit default value. + */ + +DUK_EXTERNAL_DECL duk_bool_t duk_get_boolean_default(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value); +DUK_EXTERNAL_DECL duk_double_t duk_get_number_default(duk_context *ctx, duk_idx_t idx, duk_double_t def_value); +DUK_EXTERNAL_DECL duk_int_t duk_get_int_default(duk_context *ctx, duk_idx_t idx, duk_int_t def_value); +DUK_EXTERNAL_DECL duk_uint_t duk_get_uint_default(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value); +DUK_EXTERNAL_DECL const char *duk_get_string_default(duk_context *ctx, duk_idx_t idx, const char *def_value); +DUK_EXTERNAL_DECL const char *duk_get_lstring_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len); +DUK_EXTERNAL_DECL void *duk_get_buffer_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len); +DUK_EXTERNAL_DECL void *duk_get_buffer_data_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len); +DUK_EXTERNAL_DECL void *duk_get_pointer_default(duk_context *ctx, duk_idx_t idx, void *def_value); +DUK_EXTERNAL_DECL duk_c_function duk_get_c_function_default(duk_context *ctx, duk_idx_t idx, duk_c_function def_value); +DUK_EXTERNAL_DECL duk_context *duk_get_context_default(duk_context *ctx, duk_idx_t idx, duk_context *def_value); +DUK_EXTERNAL_DECL void *duk_get_heapptr_default(duk_context *ctx, duk_idx_t idx, void *def_value); + +/* + * Opt operations: like require operations but with an explicit default value + * when value is undefined or index is invalid, null and non-matching types + * cause a TypeError. + */ + +DUK_EXTERNAL_DECL duk_bool_t duk_opt_boolean(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value); +DUK_EXTERNAL_DECL duk_double_t duk_opt_number(duk_context *ctx, duk_idx_t idx, duk_double_t def_value); +DUK_EXTERNAL_DECL duk_int_t duk_opt_int(duk_context *ctx, duk_idx_t idx, duk_int_t def_value); +DUK_EXTERNAL_DECL duk_uint_t duk_opt_uint(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value); +DUK_EXTERNAL_DECL const char *duk_opt_string(duk_context *ctx, duk_idx_t idx, const char *def_ptr); +DUK_EXTERNAL_DECL const char *duk_opt_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len); +DUK_EXTERNAL_DECL void *duk_opt_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size); +DUK_EXTERNAL_DECL void *duk_opt_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size); +DUK_EXTERNAL_DECL void *duk_opt_pointer(duk_context *ctx, duk_idx_t idx, void *def_value); +DUK_EXTERNAL_DECL duk_c_function duk_opt_c_function(duk_context *ctx, duk_idx_t idx, duk_c_function def_value); +DUK_EXTERNAL_DECL duk_context *duk_opt_context(duk_context *ctx, duk_idx_t idx, duk_context *def_value); +DUK_EXTERNAL_DECL void *duk_opt_heapptr(duk_context *ctx, duk_idx_t idx, void *def_value); /* * Require operations: no coercion, throw error if index or type @@ -869,6 +911,17 @@ duk_safe_to_lstring((ctx), (idx), NULL) /* + * Value length + */ + +DUK_EXTERNAL_DECL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t idx, duk_size_t len); +#if 0 +/* duk_require_length()? */ +/* duk_opt_length()? */ +#endif + +/* * Misc conversion */ @@ -1228,434 +1281,8 @@ } #endif -#endif /* DUK_API_PUBLIC_H_INCLUDED */ - /* * END PUBLIC API */ -/* - * 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/cross endian (e.g. ARM) DUK_USE_DOUBLE_ME - * - * ARM is a special case: ARM double values are in mixed/cross 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. - * - * 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] = 0x000000007ff80000ULL; \ - } while (0) -#define DUK__DBLUNION_IS_NAN_FULL(u) \ - ((((u)->ull[DUK_DBL_IDX_ULL0] & 0x000000007ff00000ULL) == 0x000000007ff00000ULL) && \ - ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0xffffffff000fffffULL) != 0)) -#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x000000007ff80000ULL) -#define DUK__DBLUNION_IS_ANYINF(u) \ - (((u)->ull[DUK_DBL_IDX_ULL0] & 0xffffffff7fffffffULL) == 0x000000007ff00000ULL) -#define DUK__DBLUNION_IS_POSINF(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x000000007ff00000ULL) -#define DUK__DBLUNION_IS_NEGINF(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x00000000fff00000ULL) -#define DUK__DBLUNION_IS_ANYZERO(u) \ - (((u)->ull[DUK_DBL_IDX_ULL0] & 0xffffffff7fffffffULL) == 0x0000000000000000ULL) -#define DUK__DBLUNION_IS_POSZERO(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000000000000ULL) -#define DUK__DBLUNION_IS_NEGZERO(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000080000000ULL) -#else -/* Macros for 64-bit ops + big/little endian doubles. */ -#define DUK__DBLUNION_SET_NAN_FULL(u) do { \ - (u)->ull[DUK_DBL_IDX_ULL0] = 0x7ff8000000000000ULL; \ - } while (0) -#define DUK__DBLUNION_IS_NAN_FULL(u) \ - ((((u)->ull[DUK_DBL_IDX_ULL0] & 0x7ff0000000000000ULL) == 0x7ff0000000000000UL) && \ - ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0x000fffffffffffffULL) != 0)) -#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x7ff8000000000000ULL) -#define DUK__DBLUNION_IS_ANYINF(u) \ - (((u)->ull[DUK_DBL_IDX_ULL0] & 0x7fffffffffffffffULL) == 0x7ff0000000000000ULL) -#define DUK__DBLUNION_IS_POSINF(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x7ff0000000000000ULL) -#define DUK__DBLUNION_IS_NEGINF(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0xfff0000000000000ULL) -#define DUK__DBLUNION_IS_ANYZERO(u) \ - (((u)->ull[DUK_DBL_IDX_ULL0] & 0x7fffffffffffffffULL) == 0x0000000000000000ULL) -#define DUK__DBLUNION_IS_POSZERO(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000000000000ULL) -#define DUK__DBLUNION_IS_NEGZERO(u) \ - ((u)->ull[DUK_DBL_IDX_ULL0] == 0x8000000000000000ULL) -#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] & 0x8000000000000000ULL) != 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 */ - #endif /* DUKTAPE_H_INCLUDED */ diff -Nru duktape-2.0.0/src-separate/duk_util_bitdecoder.c duktape-2.1.1/src-separate/duk_util_bitdecoder.c --- duktape-2.0.0/src-separate/duk_util_bitdecoder.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_util_bitdecoder.c 2017-07-28 22:05:08.000000000 +0000 @@ -58,8 +58,7 @@ } /* Decode a one-bit flag, and if set, decode a value of 'bits', otherwise return - * default value. Return value is signed so that negative marker value can be - * used by caller as a "not present" value. + * default value. */ DUK_INTERNAL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value) { if (duk_bd_decode_flag(ctx)) { @@ -69,6 +68,11 @@ } } +/* Signed variant, allows negative marker value. */ +DUK_INTERNAL duk_int32_t duk_bd_decode_flagged_signed(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value) { + return (duk_int32_t) duk_bd_decode_flagged(ctx, bits, (duk_uint32_t) def_value); +} + /* Shared varint encoding. Match dukutil.py BitEncode.varuint(). */ DUK_INTERNAL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx) { duk_small_uint_t t; diff -Nru duktape-2.0.0/src-separate/duk_util_bufwriter.c duktape-2.1.1/src-separate/duk_util_bufwriter.c --- duktape-2.0.0/src-separate/duk_util_bufwriter.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_util_bufwriter.c 2017-07-28 22:05:08.000000000 +0000 @@ -63,7 +63,7 @@ curr_off = (duk_size_t) (bw_ctx->p - bw_ctx->p_base); add_sz = (curr_off >> DUK_BW_SPARE_SHIFT) + DUK_BW_SPARE_ADD; new_sz = curr_off + sz + add_sz; - if (new_sz < curr_off) { + if (DUK_UNLIKELY(new_sz < curr_off)) { /* overflow */ DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG); return NULL; /* not reachable */ diff -Nru duktape-2.0.0/src-separate/duk_util.h duktape-2.1.1/src-separate/duk_util.h --- duktape-2.0.0/src-separate/duk_util.h 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_util.h 2017-07-28 22:05:08.000000000 +0000 @@ -5,10 +5,6 @@ #if !defined(DUK_UTIL_H_INCLUDED) #define DUK_UTIL_H_INCLUDED -#define DUK_UTIL_MIN_HASH_PRIME 17 /* must match genhashsizes.py */ - -#define DUK_UTIL_GET_HASH_PROBE_STEP(hash) (duk_util_probe_steps[(hash) & 0x1f]) - #if defined(DUK_USE_GET_RANDOM_DOUBLE) #define DUK_UTIL_GET_RANDOM_DOUBLE(thr) DUK_USE_GET_RANDOM_DOUBLE((thr)->heap_udata) #else @@ -494,7 +490,7 @@ #endif /* !DUK_SINGLE_FILE */ /* Note: assumes that duk_util_probe_steps size is 32 */ -#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE) +#if defined(DUK_USE_HOBJECT_HASH_PART) #if !defined(DUK_SINGLE_FILE) DUK_INTERNAL_DECL duk_uint8_t duk_util_probe_steps[32]; #endif /* !DUK_SINGLE_FILE */ @@ -504,13 +500,10 @@ DUK_INTERNAL_DECL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed); #endif -#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE) -DUK_INTERNAL_DECL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size); -#endif - DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits); DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx); DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value); +DUK_INTERNAL_DECL duk_int32_t duk_bd_decode_flagged_signed(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value); DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx); DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_bitpacked_string(duk_bitdecoder_ctx *bd, duk_uint8_t *out); diff -Nru duktape-2.0.0/src-separate/duk_util_hashprime.c duktape-2.1.1/src-separate/duk_util_hashprime.c --- duktape-2.0.0/src-separate/duk_util_hashprime.c 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/src-separate/duk_util_hashprime.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,77 +0,0 @@ -/* - * Round a number upwards to a prime (not usually the nearest one). - * - * Uses a table of successive 32-bit primes whose ratio is roughly - * constant. This keeps the relative upwards 'rounding error' bounded - * and the data size small. A simple 'predict-correct' compression is - * used to compress primes to one byte per prime. See genhashsizes.py - * for details. - * - * The minimum prime returned here must be coordinated with the possible - * probe sequence steps in duk_hobject and duk_heap stringtable. - */ - -#include "duk_internal.h" - -/* Awkward inclusion condition: drop out of compilation if not needed by any - * call site: object hash part or probing stringtable. - */ -#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE) - -/* hash size ratio goal, must match genhashsizes.py */ -#define DUK__HASH_SIZE_RATIO 1177 /* floor(1.15 * (1 << 10)) */ - -/* prediction corrections for prime list (see genhashsizes.py) */ -DUK_LOCAL const duk_int8_t duk__hash_size_corrections[] = { - 17, /* minimum prime */ - 4, 3, 4, 1, 4, 1, 1, 2, 2, 2, 2, 1, 6, 6, 9, 5, 1, 2, 2, 5, 1, 3, 3, 3, - 5, 4, 4, 2, 4, 8, 3, 4, 23, 2, 4, 7, 8, 11, 2, 12, 15, 10, 1, 1, 5, 1, 5, - 8, 9, 17, 14, 10, 7, 5, 2, 46, 21, 1, 9, 9, 4, 4, 10, 23, 36, 6, 20, 29, - 18, 6, 19, 21, 16, 11, 5, 5, 48, 9, 1, 39, 14, 8, 4, 29, 9, 1, 15, 48, 12, - 22, 6, 15, 27, 4, 2, 17, 28, 8, 9, 4, 5, 8, 3, 3, 8, 37, 11, 15, 8, 30, - 43, 6, 33, 41, 5, 20, 32, 41, 38, 24, 77, 14, 19, 11, 4, 35, 18, 19, 41, - 10, 23, 16, 9, 2, - -1 -}; - -/* probe steps (see genhashsizes.py), currently assumed to be 32 entries long - * (DUK_UTIL_GET_HASH_PROBE_STEP macro). - */ -DUK_INTERNAL duk_uint8_t duk_util_probe_steps[32] = { - 2, 3, 5, 7, 11, 13, 19, 31, 41, 47, 59, 67, 73, 79, 89, 101, 103, 107, - 109, 127, 137, 139, 149, 157, 163, 167, 173, 181, 191, 193, 197, 199 -}; - -DUK_INTERNAL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size) { - const duk_int8_t *p = duk__hash_size_corrections; - duk_uint32_t curr; - - curr = (duk_uint32_t) *p++; - for (;;) { - duk_small_int_t t = (duk_small_int_t) *p++; - if (t < 0) { - /* may happen if size is very close to 2^32-1 */ - break; - } - - /* prediction: portable variant using doubles if 64-bit values not available */ -#if defined(DUK_USE_64BIT_OPS) - curr = (duk_uint32_t) ((((duk_uint64_t) curr) * ((duk_uint64_t) DUK__HASH_SIZE_RATIO)) >> 10); -#else - /* 32-bit x 11-bit = 43-bit, fits accurately into a double */ - curr = (duk_uint32_t) DUK_FLOOR(((double) curr) * ((double) DUK__HASH_SIZE_RATIO) / 1024.0); -#endif - - /* correction */ - curr += t; - - DUK_DDD(DUK_DDDPRINT("size=%ld, curr=%ld", (long) size, (long) curr)); - - if (curr >= size) { - return curr; - } - } - return 0; -} - -#endif /* DUK_USE_HOBJECT_HASH_PART || DUK_USE_STRTAB_PROBE */ diff -Nru duktape-2.0.0/tools/configure.py duktape-2.1.1/tools/configure.py --- duktape-2.0.0/tools/configure.py 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/tools/configure.py 2017-07-28 22:05:08.000000000 +0000 @@ -130,7 +130,7 @@ def cstring(x): return '"' + x + '"' # good enough for now -# DUK_VERSION is grepped from duk_api_public.h.in: it is needed for the +# DUK_VERSION is grepped from duktape.h.in: it is needed for the # public API and we want to avoid defining it in two places. def get_duk_version(apiheader_filename): r = re.compile(r'^#define\s+DUK_VERSION\s+(.*?)L?\s*$') @@ -255,6 +255,8 @@ parser.add_option('--verbose', dest='verbose', action='store_true', default=False, help='Show verbose debug messages') (opts, args) = parser.parse_args() + if len(args) > 0: + raise Exception('unexpected arguments: %r' % args) if opts.obsolete_builtin_metadata is not None: raise Exception('--user-builtin-metadata has been removed, use --builtin-file instead') @@ -310,7 +312,7 @@ duk_dist_meta = json.loads(f.read()) duk_version, duk_major, duk_minor, duk_patch, duk_version_formatted = \ - get_duk_version(os.path.join(srcdir, 'duk_api_public.h.in')) + get_duk_version(os.path.join(srcdir, 'duktape.h.in')) git_commit = None git_branch = None @@ -430,10 +432,13 @@ 'duk_bi_symbol.c', 'duk_bi_thread.c', 'duk_bi_thrower.c', + 'duk_dblunion.h', 'duk_debug_fixedbuffer.c', 'duk_debug.h', 'duk_debug_macros.c', 'duk_debug_vsnprintf.c', + 'duk_debugger.c', + 'duk_debugger.h', 'duk_error_augment.c', 'duk_error.h', 'duk_error_longjmp.c', @@ -445,11 +450,14 @@ 'duk_hbuffer_alloc.c', 'duk_hbuffer.h', 'duk_hbuffer_ops.c', + 'duk_hbufobj.h', + 'duk_hbufobj_misc.c', 'duk_hcompfunc.h', 'duk_heap_alloc.c', 'duk_heap.h', 'duk_heap_hashstring.c', 'duk_heaphdr.h', + 'duk_heap_finalize.c', 'duk_heap_markandsweep.c', 'duk_heap_memory.c', 'duk_heap_misc.c', @@ -460,7 +468,6 @@ 'duk_hobject_alloc.c', 'duk_hobject_class.c', 'duk_hobject_enum.c', - 'duk_hobject_finalizer.c', 'duk_hobject.h', 'duk_hobject_misc.c', 'duk_hobject_pc2line.c', @@ -472,10 +479,7 @@ 'duk_hthread.h', 'duk_hthread_misc.c', 'duk_hthread_stacks.c', - 'duk_hbufobj.h', - 'duk_hbufobj_misc.c', - 'duk_debugger.c', - 'duk_debugger.h', + 'duk_henv.h', 'duk_internal.h', 'duk_jmpbuf.h', 'duk_exception.h', @@ -493,6 +497,7 @@ 'duk_lexer.h', 'duk_numconv.c', 'duk_numconv.h', + 'duk_refcount.h', 'duk_regexp_compiler.c', 'duk_regexp_executor.c', 'duk_regexp.h', @@ -505,7 +510,6 @@ 'duk_util_bitencoder.c', 'duk_util.h', 'duk_util_hashbytes.c', - 'duk_util_hashprime.c', 'duk_util_misc.c', 'duk_util_tinyrandom.c', 'duk_util_bufwriter.c', @@ -608,8 +612,6 @@ '@DUK_SINGLE_FILE@': '#define DUK_SINGLE_FILE', '@LICENSE_TXT@': read_file(os.path.join(tempdir, 'LICENSE.txt.tmp'), strip_last_nl=True), '@AUTHORS_RST@': read_file(os.path.join(tempdir, 'AUTHORS.rst.tmp'), strip_last_nl=True), - '@DUK_API_PUBLIC_H@': read_file(os.path.join(srcdir, 'duk_api_public.h.in'), strip_last_nl=True), - '@DUK_DBLUNION_H@': read_file(os.path.join(srcdir, 'duk_dblunion.h.in'), strip_last_nl=True), '@DUK_VERSION_FORMATTED@': duk_version_formatted, '@GIT_COMMIT@': git_commit, '@GIT_COMMIT_CSTRING@': git_commit_cstring, @@ -896,7 +898,6 @@ 'duk_error_macros.c', 'duk_unicode_support.c', 'duk_util_misc.c', - 'duk_util_hashprime.c', 'duk_hobject_class.c' ] diff -Nru duktape-2.0.0/tools/genbuiltins.py duktape-2.1.1/tools/genbuiltins.py --- duktape-2.0.0/tools/genbuiltins.py 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/tools/genbuiltins.py 2017-07-28 22:05:08.000000000 +0000 @@ -44,6 +44,9 @@ # Must match DUK_USE_ROM_PTRCOMP_FIRST (generated header checks). ROMPTR_FIRST = 0xf800 # 2048 should be enough; now around ~1000 used +# ROM string table size +ROMSTR_LOOKUP_SIZE = 256 + # # Miscellaneous helpers # @@ -1422,7 +1425,6 @@ 'Symbol', 'ObjEnv', 'DecEnv', - 'Buffer', 'Pointer', 'Thread' # Remaining class names are not currently needed. @@ -2256,87 +2258,118 @@ genc.emitLine('#error currently assumes DUK_USE_HEAPPTR16 and DUK_USE_REFCOUNT16 are both defined') genc.emitLine('#endif') genc.emitLine('#if defined(DUK_USE_HSTRING_CLEN)') - genc.emitLine('#define DUK__STRINIT(heaphdr_flags,refcount,hash32,hash16,blen,clen) \\') - genc.emitLine('\t{ { (heaphdr_flags) | ((hash16) << 16), (refcount), (blen) }, (clen) }') + genc.emitLine('#define DUK__STRINIT(heaphdr_flags,refcount,hash32,hash16,blen,clen,next) \\') + genc.emitLine('\t{ { (heaphdr_flags) | ((hash16) << 16), DUK__REFCINIT((refcount)), (blen), (duk_hstring *) DUK_LOSE_CONST((next)) }, (clen) }') genc.emitLine('#else /* DUK_USE_HSTRING_CLEN */') - genc.emitLine('#define DUK__STRINIT(heaphdr_flags,refcount,hash32,hash16,blen,clen) \\') - genc.emitLine('\t{ { (heaphdr_flags) | ((hash16) << 16), (refcount), (blen) } }') + genc.emitLine('#define DUK__STRINIT(heaphdr_flags,refcount,hash32,hash16,blen,clen,next) \\') + genc.emitLine('\t{ { (heaphdr_flags) | ((hash16) << 16), DUK__REFCINIT((refcount)), (blen), (duk_hstring *) DUK_LOSE_CONST((next)) } }') genc.emitLine('#endif /* DUK_USE_HSTRING_CLEN */') genc.emitLine('#else /* DUK_USE_HEAPPTR16 */') - genc.emitLine('#define DUK__STRINIT(heaphdr_flags,refcount,hash32,hash16,blen,clen) \\') - genc.emitLine('\t{ { (heaphdr_flags), (refcount) }, (hash32), (blen), (clen) }') + genc.emitLine('#define DUK__STRINIT(heaphdr_flags,refcount,hash32,hash16,blen,clen,next) \\') + genc.emitLine('\t{ { (heaphdr_flags), DUK__REFCINIT((refcount)), DUK_LOSE_CONST((next)) }, (hash32), (blen), (clen) }') genc.emitLine('#endif /* DUK_USE_HEAPPTR16 */') - # Emit string initializers. - genc.emitLine('') + # Organize ROM strings into a chained ROM string table. The ROM string + # h_next link pointer is used for chaining just like for RAM strings but + # in a separate string table. + # + # To avoid dealing with the different possible string hash algorithms, + # use a much more trivial lookup key for ROM strings for now. + romstr_hash = [] + while len(romstr_hash) < ROMSTR_LOOKUP_SIZE: + romstr_hash.append([]) + for str_index,v in enumerate(strs): + if len(v) > 0: + rom_lookup_hash = ord(v[0]) + (len(v) << 4) + else: + rom_lookup_hash = 0 + (len(v) << 4) + rom_lookup_hash = rom_lookup_hash & 0xff + romstr_hash[rom_lookup_hash].append(v) + + romstr_next = {} # string -> the string's 'next' link + for lst in romstr_hash: + prev = None + #print(repr(lst)) + for v in lst: + if prev is not None: + romstr_next[prev] = v + prev = v + + chain_lens = {} + for lst in romstr_hash: + chainlen = len(lst) + if not chain_lens.has_key(chainlen): + chain_lens[chainlen] = 0 + chain_lens[chainlen] += 1 + tmp = [] + for k in sorted(chain_lens.keys()): + tmp.append('%d: %d' % (k, chain_lens[k])) + logger.info('ROM string table chain lengths: %s' % ', '.join(tmp)) + bi_str_map = {} # string -> initializer variable name for str_index,v in enumerate(strs): bi_str_map[v] = 'duk_str_%d' % str_index - tmp = 'DUK_INTERNAL const duk_romstr_%d duk_str_%d = {' % (len(v), str_index) - flags = [ 'DUK_HTYPE_STRING', 'DUK_HEAPHDR_FLAG_READONLY' ] - is_arridx = string_is_arridx(v) - - blen = len(v) - clen = rom_charlen(v) - - if blen == clen: - flags.append('DUK_HSTRING_FLAG_ASCII') - if is_arridx: - flags.append('DUK_HSTRING_FLAG_ARRIDX') - if len(v) >= 1 and v[0] in [ '\x80', '\x81', '\xff' ]: - flags.append('DUK_HSTRING_FLAG_SYMBOL') - if len(v) >= 1 and v[0] in [ '\xff' ]: - flags.append('DUK_HSTRING_FLAG_HIDDEN') - if v in [ 'eval', 'arguments' ]: - flags.append('DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS') - if reserved_words.has_key(v): - flags.append('DUK_HSTRING_FLAG_RESERVED_WORD') - if strict_reserved_words.has_key(v): - flags.append('DUK_HSTRING_FLAG_STRICT_RESERVED_WORD') - - tmp += 'DUK__STRINIT(%s,%d,%s,%s,%d,%d),' % \ - ('|'.join(flags), 1, rom_get_strhash32_macro(v), \ - rom_get_strhash16_macro(v), blen, clen) - - tmpbytes = [] - for c in v: - if ord(c) < 128: - tmpbytes.append('%d' % ord(c)) - else: - tmpbytes.append('%dU' % ord(c)) - tmpbytes.append('%d' % 0) # NUL term - tmp += '{' + ','.join(tmpbytes) + '}' - tmp += '};' - genc.emitLine(tmp) + # Emit string initializers. Emit the strings in an order which avoids + # forward declarations for the h_next link pointers; const forward + # declarations are a problem in C++. + genc.emitLine('') + for lst in romstr_hash: + for v in reversed(lst): + tmp = 'DUK_INTERNAL const duk_romstr_%d %s = {' % (len(v), bi_str_map[v]) + flags = [ 'DUK_HTYPE_STRING', 'DUK_HEAPHDR_FLAG_READONLY' ] + is_arridx = string_is_arridx(v) + + blen = len(v) + clen = rom_charlen(v) + + if blen == clen: + flags.append('DUK_HSTRING_FLAG_ASCII') + if is_arridx: + flags.append('DUK_HSTRING_FLAG_ARRIDX') + if len(v) >= 1 and v[0] in [ '\x80', '\x81', '\xff' ]: + flags.append('DUK_HSTRING_FLAG_SYMBOL') + if len(v) >= 1 and v[0] in [ '\xff' ]: + flags.append('DUK_HSTRING_FLAG_HIDDEN') + if v in [ 'eval', 'arguments' ]: + flags.append('DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS') + if reserved_words.has_key(v): + flags.append('DUK_HSTRING_FLAG_RESERVED_WORD') + if strict_reserved_words.has_key(v): + flags.append('DUK_HSTRING_FLAG_STRICT_RESERVED_WORD') + + h_next = 'NULL' + if romstr_next.has_key(v): + h_next = '&' + bi_str_map[romstr_next[v]] + + tmp += 'DUK__STRINIT(%s,%d,%s,%s,%d,%d,%s),' % \ + ('|'.join(flags), 1, rom_get_strhash32_macro(v), \ + rom_get_strhash16_macro(v), blen, clen, h_next) + + tmpbytes = [] + for c in v: + if ord(c) < 128: + tmpbytes.append('%d' % ord(c)) + else: + tmpbytes.append('%dU' % ord(c)) + tmpbytes.append('%d' % 0) # NUL term + tmp += '{' + ','.join(tmpbytes) + '}' + tmp += '};' + genc.emitLine(tmp) - # Emit an array of ROM strings, used for string interning. - # - # XXX: String interning now simply walks through the list checking if - # an incoming string is present in ROM. It would be better to use - # binary search (or perhaps even a perfect hash) for this lookup. - # To support binary search we could emit the list in string hash - # order, but because there are multiple different hash variants - # there would need to be multiple lists. We could also order the - # strings based on the string data which is independent of the string - # hash and still possible to binary search relatively efficiently. + # Emit the ROM string lookup table used by string interning. # # cdecl> explain const int * const foo; # declare foo as const pointer to const int genc.emitLine('') - genc.emitLine('DUK_INTERNAL const duk_hstring * const duk_rom_strings[%d] = {'% len(strs)) + genc.emitLine('DUK_INTERNAL const duk_hstring * const duk_rom_strings_lookup[%d] = {'% len(romstr_hash)) tmp = [] linecount = 0 - for str_index,v in enumerate(strs): - if str_index > 0: - tmp.append(', ') - if linecount >= 6: - linecount = 0 - tmp.append('\n') - tmp.append('(const duk_hstring *) &duk_str_%d' % str_index) - linecount += 1 - for line in ''.join(tmp).split('\n'): - genc.emitLine(line) + for lst in romstr_hash: + if len(lst) == 0: + genc.emitLine('\tNULL,') + else: + genc.emitLine('\t(const duk_hstring *) &%s,' % bi_str_map[lst[0]]) genc.emitLine('};') # Emit an array of duk_hstring pointers indexed using DUK_STRIDX_xxx. @@ -2356,7 +2389,7 @@ # Emit ROM strings header. def rom_emit_strings_header(genc, meta): genc.emitLine('#if !defined(DUK_SINGLE_FILE)') # C++ static const workaround - genc.emitLine('DUK_INTERNAL_DECL const duk_hstring * const duk_rom_strings[%d];'% len(meta['strings'])) + genc.emitLine('DUK_INTERNAL_DECL const duk_hstring * const duk_rom_strings_lookup[%d];' % ROMSTR_LOOKUP_SIZE) genc.emitLine('DUK_INTERNAL_DECL const duk_hstring * const duk_rom_strings_stridx[%d];' % len(meta['strings_stridx'])) genc.emitLine('#endif') @@ -2370,6 +2403,8 @@ 'struct duk_romarr { duk_harray hdr; };') genc.emitLine('typedef struct duk_romfun duk_romfun; ' + \ 'struct duk_romfun { duk_hnatfunc hdr; };') + genc.emitLine('typedef struct duk_romobjenv duk_romobjenv; ' + \ + 'struct duk_romobjenv { duk_hobjenv hdr; };') # For ROM pointer compression we'd need a -compile time- variant. # The current portable solution is to just assign running numbers @@ -2387,18 +2422,22 @@ #genc.emitLine('#error need DUK_USE_HEAPPTR_ENC16_STATIC which provides compile-time pointer compression') #genc.emitLine('#endif') genc.emitLine('#define DUK__ROMOBJ_INIT(heaphdr_flags,refcount,props,props_enc16,iproto,iproto_enc16,esize,enext,asize,hsize) \\') - genc.emitLine('\t{ { { (heaphdr_flags), (refcount), 0, 0, (props_enc16) }, (iproto_enc16), (esize), (enext), (asize) } }') + genc.emitLine('\t{ { { (heaphdr_flags), DUK__REFCINIT((refcount)), 0, 0, (props_enc16) }, (iproto_enc16), (esize), (enext), (asize) } }') genc.emitLine('#define DUK__ROMARR_INIT(heaphdr_flags,refcount,props,props_enc16,iproto,iproto_enc16,esize,enext,asize,hsize,length) \\') - genc.emitLine('\t{ { { { (heaphdr_flags), (refcount), 0, 0, (props_enc16) }, (iproto_enc16), (esize), (enext), (asize) }, (length), 0 /*length_nonwritable*/ } }') + genc.emitLine('\t{ { { { (heaphdr_flags), DUK__REFCINIT((refcount)), 0, 0, (props_enc16) }, (iproto_enc16), (esize), (enext), (asize) }, (length), 0 /*length_nonwritable*/ } }') genc.emitLine('#define DUK__ROMFUN_INIT(heaphdr_flags,refcount,props,props_enc16,iproto,iproto_enc16,esize,enext,asize,hsize,nativefunc,nargs,magic) \\') - genc.emitLine('\t{ { { { (heaphdr_flags), (refcount), 0, 0, (props_enc16) }, (iproto_enc16), (esize), (enext), (asize) }, (nativefunc), (duk_int16_t) (nargs), (duk_int16_t) (magic) } }') + genc.emitLine('\t{ { { { (heaphdr_flags), DUK__REFCINIT((refcount)), 0, 0, (props_enc16) }, (iproto_enc16), (esize), (enext), (asize) }, (nativefunc), (duk_int16_t) (nargs), (duk_int16_t) (magic) } }') + genc.emitLine('#define DUK__ROMOBJENV_INIT(heaphdr_flags,refcount,props,props_enc16,iproto,iproto_enc16,esize,enext,asize,hsize,target,has_this) \\') + genc.emitLine('\t{ { { { (heaphdr_flags), DUK__REFCINIT((refcount)), 0, 0, (props_enc16) }, (iproto_enc16), (esize), (enext), (asize) }, (duk_hobject *) DUK_LOSE_CONST(target), (has_this) } }') genc.emitLine('#else /* DUK_USE_HEAPPTR16 */') genc.emitLine('#define DUK__ROMOBJ_INIT(heaphdr_flags,refcount,props,props_enc16,iproto,iproto_enc16,esize,enext,asize,hsize) \\') - genc.emitLine('\t{ { { (heaphdr_flags), (refcount), NULL, NULL }, (duk_uint8_t *) DUK_LOSE_CONST(props), (duk_hobject *) DUK_LOSE_CONST(iproto), (esize), (enext), (asize), (hsize) } }') + genc.emitLine('\t{ { { (heaphdr_flags), DUK__REFCINIT((refcount)), NULL, NULL }, (duk_uint8_t *) DUK_LOSE_CONST(props), (duk_hobject *) DUK_LOSE_CONST(iproto), (esize), (enext), (asize), (hsize) } }') genc.emitLine('#define DUK__ROMARR_INIT(heaphdr_flags,refcount,props,props_enc16,iproto,iproto_enc16,esize,enext,asize,hsize,length) \\') - genc.emitLine('\t{ { { { (heaphdr_flags), (refcount), NULL, NULL }, (duk_uint8_t *) DUK_LOSE_CONST(props), (duk_hobject *) DUK_LOSE_CONST(iproto), (esize), (enext), (asize), (hsize) }, (length), 0 /*length_nonwritable*/ } }') + genc.emitLine('\t{ { { { (heaphdr_flags), DUK__REFCINIT((refcount)), NULL, NULL }, (duk_uint8_t *) DUK_LOSE_CONST(props), (duk_hobject *) DUK_LOSE_CONST(iproto), (esize), (enext), (asize), (hsize) }, (length), 0 /*length_nonwritable*/ } }') genc.emitLine('#define DUK__ROMFUN_INIT(heaphdr_flags,refcount,props,props_enc16,iproto,iproto_enc16,esize,enext,asize,hsize,nativefunc,nargs,magic) \\') - genc.emitLine('\t{ { { { (heaphdr_flags), (refcount), NULL, NULL }, (duk_uint8_t *) DUK_LOSE_CONST(props), (duk_hobject *) DUK_LOSE_CONST(iproto), (esize), (enext), (asize), (hsize) }, (nativefunc), (duk_int16_t) (nargs), (duk_int16_t) (magic) } }') + genc.emitLine('\t{ { { { (heaphdr_flags), DUK__REFCINIT((refcount)), NULL, NULL }, (duk_uint8_t *) DUK_LOSE_CONST(props), (duk_hobject *) DUK_LOSE_CONST(iproto), (esize), (enext), (asize), (hsize) }, (nativefunc), (duk_int16_t) (nargs), (duk_int16_t) (magic) } }') + genc.emitLine('#define DUK__ROMOBJENV_INIT(heaphdr_flags,refcount,props,props_enc16,iproto,iproto_enc16,esize,enext,asize,hsize,target,has_this) \\') + genc.emitLine('\t{ { { { (heaphdr_flags), DUK__REFCINIT((refcount)), NULL, NULL }, (duk_uint8_t *) DUK_LOSE_CONST(props), (duk_hobject *) DUK_LOSE_CONST(iproto), (esize), (enext), (asize), (hsize) }, (duk_hobject *) DUK_LOSE_CONST(target), (has_this) } }') genc.emitLine('#endif /* DUK_USE_HEAPPTR16 */') # Initializer typedef for a dummy function pointer. ROM support assumes @@ -2678,6 +2717,8 @@ genc.emitLine('DUK_EXTERNAL_DECL const duk_romfun duk_obj_%d;' % idx) elif obj.get('class') == 'Array': genc.emitLine('DUK_EXTERNAL_DECL const duk_romarr duk_obj_%d;' % idx) + elif obj.get('class') == 'ObjEnv': + genc.emitLine('DUK_EXTERNAL_DECL const duk_romobjenv duk_obj_%d;' % idx) else: genc.emitLine('DUK_EXTERNAL_DECL const duk_romobj duk_obj_%d;' % idx) genc.emitLine('') @@ -2695,6 +2736,8 @@ tmp = 'DUK_EXTERNAL const duk_romfun duk_obj_%d = ' % idx elif obj.get('class') == 'Array': tmp = 'DUK_EXTERNAL const duk_romarr duk_obj_%d = ' % idx + elif obj.get('class') == 'ObjEnv': + tmp = 'DUK_EXTERNAL const duk_romobjenv duk_obj_%d = ' % idx else: tmp = 'DUK_EXTERNAL const duk_romobj duk_obj_%d = ' % idx @@ -2753,6 +2796,12 @@ tmp += 'DUK__ROMARR_INIT(%s,%d,%s,%d,%s,%d,%d,%d,%d,%d,%d);' % \ ('|'.join(flags), refcount, props, props_enc16, \ iproto, iproto_enc16, e_size, e_next, a_size, h_size, arrlen) + elif obj.get('class') == 'ObjEnv': + objenv_target = '&%s' % bi_obj_map[obj['objenv_target']] + objenv_has_this = obj['objenv_has_this'] + tmp += 'DUK__ROMOBJENV_INIT(%s,%d,%s,%d,%s,%d,%d,%d,%d,%d,%s,%d);' % \ + ('|'.join(flags), refcount, props, props_enc16, \ + iproto, iproto_enc16, e_size, e_next, a_size, h_size, objenv_target, objenv_has_this) else: tmp += 'DUK__ROMOBJ_INIT(%s,%d,%s,%d,%s,%d,%d,%d,%d,%d);' % \ ('|'.join(flags), refcount, props, props_enc16, \ @@ -3003,6 +3052,12 @@ gc_src.emitHeader('genbuiltins.py') gc_src.emitLine('#include "duk_internal.h"') gc_src.emitLine('') + gc_src.emitLine('#if defined(DUK_USE_ASSERTIONS)') + gc_src.emitLine('#define DUK__REFCINIT(refc) 0 /*h_assert_refcount*/, (refc) /*actual*/') + gc_src.emitLine('#else') + gc_src.emitLine('#define DUK__REFCINIT(refc) (refc) /*actual*/') + gc_src.emitLine('#endif') + gc_src.emitLine('') gc_src.emitLine('#if defined(DUK_USE_ROM_STRINGS)') if opts.rom_support: rom_bi_str_map = rom_emit_strings_source(gc_src, rom_meta) @@ -3116,7 +3171,7 @@ 'plain': t1, 'base64': t2, 'define': s['define'] }) meta = { - 'comment': 'Metadata for Duktape build', + 'comment': 'Metadata for Duktape sources', 'duk_version': ver, 'duk_version_string': '%d.%d.%d' % (ver / 10000, (ver / 100) % 100, ver % 100), 'git_commit': build_info['git_commit'], diff -Nru duktape-2.0.0/tools/genconfig.py duktape-2.1.1/tools/genconfig.py --- duktape-2.0.0/tools/genconfig.py 2017-01-02 03:09:51.000000000 +0000 +++ duktape-2.1.1/tools/genconfig.py 2017-07-28 22:05:08.000000000 +0000 @@ -1338,6 +1338,10 @@ meta = use_defs.get(opt) if meta is None: raise Exception('unknown config option in source code: %r' % opt) + if meta.get('removed', None) is not None: + #logger.info('removed config option in source code: %r' % opt) + #raise Exception('removed config option in source code: %r' % opt) + pass for meta in use_defs_list: if not defs_used.has_key(meta['define']):