summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbellard <6490144+bellard@users.noreply.github.com>2020-11-08 14:30:56 +0100
committerbellard <6490144+bellard@users.noreply.github.com>2020-11-08 14:30:56 +0100
commitb1f67dfc1a7372dd665246cf1c203528e5057e42 (patch)
treeb68346b1d20aa2e709c44a4f7ea902dd3ba6336f
parent7c312df422572cf867f29a1d80693e8a77f7fb2a (diff)
downloadquickjs-b1f67dfc1a7372dd665246cf1c203528e5057e42.tar.gz
quickjs-b1f67dfc1a7372dd665246cf1c203528e5057e42.zip
2020-11-08 release
-rw-r--r--Changelog7
-rw-r--r--Makefile15
-rw-r--r--TODO68
-rw-r--r--VERSION2
-rw-r--r--doc/jsbignum.html734
-rw-r--r--doc/jsbignum.pdfbin153057 -> 0 bytes
-rw-r--r--doc/quickjs.html1369
-rw-r--r--doc/quickjs.pdfbin165855 -> 0 bytes
-rw-r--r--doc/quickjs.texi12
-rw-r--r--jscompress.c918
-rw-r--r--libbf.h2
-rw-r--r--libregexp.c26
-rw-r--r--qjscalc.js11
-rw-r--r--quickjs-atom.h1
-rw-r--r--quickjs-libc.c95
-rw-r--r--quickjs-opcode.h13
-rw-r--r--quickjs.c2541
-rw-r--r--quickjs.h9
-rwxr-xr-xrelease.sh79
-rw-r--r--test262.conf17
-rw-r--r--test262_errors.txt65
-rw-r--r--tests/test_builtin.js25
-rw-r--r--tests/test_language.js155
23 files changed, 1870 insertions, 4294 deletions
diff --git a/Changelog b/Changelog
index 1a7533b..0c25b96 100644
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,10 @@
+2020-11-08:
+
+- improved function parameter initializers
+- added std.setenv(), std.unsetenv() and std.getenviron()
+- added JS_EvalThis()
+- misc bug fixes
+
2020-09-06:
- added logical assignment operators
diff --git a/Makefile b/Makefile
index 94c8e31..766a7e1 100644
--- a/Makefile
+++ b/Makefile
@@ -28,9 +28,9 @@ endif
# Windows cross compilation from Linux
#CONFIG_WIN32=y
# use link time optimization (smaller and faster executables but slower build)
-CONFIG_LTO=y
+#CONFIG_LTO=y
# consider warnings as errors (for development)
-#CONFIG_WERROR=y
+CONFIG_WERROR=y
# force 32 bit build for some utilities
#CONFIG_M32=y
@@ -53,7 +53,11 @@ CONFIG_BIGNUM=y
OBJDIR=.obj
ifdef CONFIG_WIN32
- CROSS_PREFIX=i686-w64-mingw32-
+ ifdef CONFIG_M32
+ CROSS_PREFIX=i686-w64-mingw32-
+ else
+ CROSS_PREFIX=x86_64-w64-mingw32-
+ endif
EXE=.exe
else
CROSS_PREFIX=
@@ -281,15 +285,12 @@ $(OBJDIR)/%.check.o: %.c | $(OBJDIR)
regexp_test: libregexp.c libunicode.c cutils.c
$(CC) $(LDFLAGS) $(CFLAGS) -DTEST -o $@ libregexp.c libunicode.c cutils.c $(LIBS)
-jscompress: jscompress.c
- $(CC) $(LDFLAGS) $(CFLAGS) -o $@ jscompress.c
-
unicode_gen: $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o libunicode.c unicode_gen_def.h
$(HOST_CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o
clean:
rm -f repl.c qjscalc.c out.c
- rm -f *.a *.o *.d *~ jscompress unicode_gen regexp_test $(PROGS)
+ rm -f *.a *.o *.d *~ unicode_gen regexp_test $(PROGS)
rm -f hello.c test_fib.c
rm -f examples/*.so tests/*.so
rm -rf $(OBJDIR)/ *.dSYM/ qjs-debug
diff --git a/TODO b/TODO
index 0eec6d3..b5500c9 100644
--- a/TODO
+++ b/TODO
@@ -1,13 +1,11 @@
-Misc:
-- use realpath in module name normalizer and put it in quickjs-libc
-- use custom printf to avoid C library compatibility issues
-- rename CONFIG_ALL_UNICODE, CONFIG_BIGNUM, CONFIG_ATOMICS, CONFIG_CHECK_JSVALUE ?
+Bugs:
+- modules: better error handling with cyclic module references
+
+Misc ideas:
+- use custom printf to avoid compatibility issues with floating point numbers
+- consistent naming for preprocessor defines
- unify coding style and naming conventions
- use names from the ECMA spec in library implementation
-- modules: if no ".", use a well known module loading path ?
-- use JSHoistedDef only for global variables (JSHoistedDef.var_name != JS_ATOM_NULL)
-- add index in JSVarDef and is_arg flag to merge args and vars in JSFunctionDef
-- replace most JSVarDef flags with var_type enumeration
- use byte code emitters with typed arguments (for clarity)
- use 2 bytecode DynBufs in JSFunctionDef, one for reading, one for writing
and use the same wrappers in all phases
@@ -15,19 +13,36 @@ Misc:
- use custom timezone support to avoid C library compatibility issues
Memory:
+- use memory pools for objects, etc?
- test border cases for max number of atoms, object properties, string length
- add emergency malloc mode for out of memory exceptions.
- test all DynBuf memory errors
- test all js_realloc memory errors
-- bignum: handle memory errors
-- use memory pools for objects, etc?
- improve JS_ComputeMemoryUsage() with more info
-Optimizations:
+Built-in standard library:
+- BSD sockets
+- modules: use realpath in module name normalizer and put it in quickjs-libc
+- modules: if no ".", use a well known module loading path ?
+- get rid of __loadScript, use more common name
+
+REPL:
+- debugger
+- readline: support MS Windows terminal
+- readline: handle dynamic terminal resizing
+- readline: handle double width unicode characters
+- multiline editing
+- runtime object and function inspectors
+- interactive object browser
+- use more generic approach to display evaluation results
+- improve directive handling: dispatch, colorize, completion...
+- save history
+- close all predefined methods in repl.js and jscalc.js
+
+Optimization ideas:
- 64-bit atoms in 64-bit mode ?
-- use auto-init properties for more global objects
+- 64-bit small bigint in 64-bit mode ?
- reuse stack slots for disjoint scopes, if strip
-- optimize `for of` iterator for built-in array objects
- add heuristic to avoid some cycles in closures
- small String (0-2 charcodes) with immediate storage
- perform static string concatenation at compile time
@@ -36,43 +51,20 @@ Optimizations:
- optimize `s += a + b`, `s += a.b` and similar simple expressions
- ensure string canonical representation and optimise comparisons and hashes?
- remove JSObject.first_weak_ref, use bit+context based hashed array for weak references
-- optimize function storage with length and name accessors?
- property access optimization on the global object, functions,
prototypes and special non extensible objects.
- create object literals with the correct length by backpatching length argument
- remove redundant set_loc_uninitialized/check_uninitialized opcodes
- peephole optim: push_atom_value, to_propkey -> push_atom_value
- peephole optim: put_loc x, get_loc_check x -> set_loc x
-- comparative performance benchmark
-- use variable name when throwing uninitialized exception if available
- convert slow array to fast array when all properties != length are numeric
- optimize destructuring assignments for global and local variables
- implement some form of tail-call-optimization
- optimize OP_apply
- optimize f(...b)
-Extensions:
-- support more features in [features] section
-- add built-in preprocessor in compiler, get rid of jscompress
- handle #if, #ifdef, #line, limited support for #define
-- get rid of __loadScript, use more common name
-- BSD sockets
-
-REPL:
-- debugger
-- readline: support MS Windows terminal
-- readline: handle dynamic terminal resizing
-- readline: handle double width unicode characters
-- multiline editing
-- runtime object and function inspectors
-- interactive object browser
-- use more generic approach to display evaluation results
-- improve directive handling: dispatch, colorize, completion...
-- save history
-- close all predefined methods in repl.js and jscalc.js
-
Test262o: 0/11262 errors, 463 excluded
Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
-Test262: 30/71748 errors, 868 excluded, 474 skipped
-Test262 commit: 24c67328062383079ada85f4d253eb0526fd209b
+Result: 51/75119 errors, 899 excluded, 570 skipped
+Test262 commit: 1c33fdb0ca60fb9d7392403be769ed0d26209132
diff --git a/VERSION b/VERSION
index c67790a..78749b0 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2020-09-06
+2020-11-08
diff --git a/doc/jsbignum.html b/doc/jsbignum.html
deleted file mode 100644
index ab31612..0000000
--- a/doc/jsbignum.html
+++ /dev/null
@@ -1,734 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<!-- Created by GNU Texinfo 6.1, http://www.gnu.org/software/texinfo/ -->
-<head>
-<title>Javascript Bignum Extensions</title>
-
-<meta name="description" content="Javascript Bignum Extensions">
-<meta name="keywords" content="Javascript Bignum Extensions">
-<meta name="resource-type" content="document">
-<meta name="distribution" content="global">
-<meta name="Generator" content="makeinfo">
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-<link href="#SEC_Contents" rel="contents" title="Table of Contents">
-<style type="text/css">
-<!--
-a.summary-letter {text-decoration: none}
-blockquote.indentedblock {margin-right: 0em}
-blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
-blockquote.smallquotation {font-size: smaller}
-div.display {margin-left: 3.2em}
-div.example {margin-left: 3.2em}
-div.lisp {margin-left: 3.2em}
-div.smalldisplay {margin-left: 3.2em}
-div.smallexample {margin-left: 3.2em}
-div.smalllisp {margin-left: 3.2em}
-kbd {font-style: oblique}
-pre.display {font-family: inherit}
-pre.format {font-family: inherit}
-pre.menu-comment {font-family: serif}
-pre.menu-preformatted {font-family: serif}
-pre.smalldisplay {font-family: inherit; font-size: smaller}
-pre.smallexample {font-size: smaller}
-pre.smallformat {font-family: inherit; font-size: smaller}
-pre.smalllisp {font-size: smaller}
-span.nolinebreak {white-space: nowrap}
-span.roman {font-family: initial; font-weight: normal}
-span.sansserif {font-family: sans-serif; font-weight: normal}
-ul.no-bullet {list-style: none}
--->
-</style>
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
-
-
-</head>
-
-<body lang="en">
-<h1 class="settitle" align="center">Javascript Bignum Extensions</h1>
-
-<a name="SEC_Contents"></a>
-<h2 class="contents-heading">Table of Contents</h2>
-
-<div class="contents">
-<ul class="no-bullet">
-<li><a name="toc-Introduction" href="#Introduction">1 Introduction</a></li>
-<li><a name="toc-Operator-overloading" href="#Operator-overloading">2 Operator overloading</a></li>
-<li><a name="toc-BigInt-extensions" href="#BigInt-extensions">3 BigInt extensions</a></li>
-<li><a name="toc-BigFloat" href="#BigFloat">4 BigFloat</a>
-<ul class="no-bullet">
- <li><a name="toc-Introduction-1" href="#Introduction-1">4.1 Introduction</a></li>
- <li><a name="toc-Floating-point-rounding" href="#Floating-point-rounding">4.2 Floating point rounding</a></li>
- <li><a name="toc-Operators" href="#Operators">4.3 Operators</a></li>
- <li><a name="toc-BigFloat-literals" href="#BigFloat-literals">4.4 BigFloat literals</a></li>
- <li><a name="toc-Builtin-Object-changes" href="#Builtin-Object-changes">4.5 Builtin Object changes</a>
- <ul class="no-bullet">
- <li><a name="toc-BigFloat-function" href="#BigFloat-function">4.5.1 <code>BigFloat</code> function</a></li>
- <li><a name="toc-BigFloat_002eprototype" href="#BigFloat_002eprototype">4.5.2 <code>BigFloat.prototype</code></a></li>
- <li><a name="toc-BigFloatEnv-constructor" href="#BigFloatEnv-constructor">4.5.3 <code>BigFloatEnv</code> constructor</a></li>
- </ul></li>
-</ul></li>
-<li><a name="toc-BigDecimal" href="#BigDecimal">5 BigDecimal</a>
-<ul class="no-bullet">
- <li><a name="toc-Operators-1" href="#Operators-1">5.1 Operators</a></li>
- <li><a name="toc-BigDecimal-literals" href="#BigDecimal-literals">5.2 BigDecimal literals</a></li>
- <li><a name="toc-Builtin-Object-changes-1" href="#Builtin-Object-changes-1">5.3 Builtin Object changes</a>
- <ul class="no-bullet">
- <li><a name="toc-The-BigDecimal-function_002e" href="#The-BigDecimal-function_002e">5.3.1 The <code>BigDecimal</code> function.</a></li>
- <li><a name="toc-Properties-of-the-BigDecimal-object" href="#Properties-of-the-BigDecimal-object">5.3.2 Properties of the <code>BigDecimal</code> object</a></li>
- <li><a name="toc-Properties-of-the-BigDecimal_002eprototype-object" href="#Properties-of-the-BigDecimal_002eprototype-object">5.3.3 Properties of the <code>BigDecimal.prototype</code> object</a></li>
- </ul></li>
-</ul></li>
-<li><a name="toc-Math-mode" href="#Math-mode">6 Math mode</a></li>
-
-</ul>
-</div>
-
-
-<a name="Introduction"></a>
-<h2 class="chapter">1 Introduction</h2>
-
-<p>The Bignum extensions add the following features to the Javascript
-language while being 100% backward compatible:
-</p>
-<ul>
-<li> Operator overloading with a dispatch logic inspired from the proposal available at <a href="https://github.com/tc39/proposal-operator-overloading/">https://github.com/tc39/proposal-operator-overloading/</a>.
-
-</li><li> Arbitrarily large floating point numbers (<code>BigFloat</code>) in base 2 using the IEEE 754 semantics.
-
-</li><li> Arbitrarily large floating point numbers (<code>BigDecimal</code>) in base 10 based on the proposal available at
-<a href="https://github.com/littledan/proposal-bigdecimal">https://github.com/littledan/proposal-bigdecimal</a>.
-
-</li><li> <code>math</code> mode: arbitrarily large integers and floating point numbers are available by default. The integer division and power can be overloaded for example to return a fraction. The modulo operator (<code>%</code>) is defined as the Euclidian
-remainder. <code>^</code> is an alias to the power operator
-(<code>**</code>). <code>^^</code> is used as the exclusive or operator.
-
-</li></ul>
-
-<p>The extensions are independent from each other except the <code>math</code>
-mode which relies on BigFloat and operator overloading.
-</p>
-<a name="Operator-overloading"></a>
-<h2 class="chapter">2 Operator overloading</h2>
-
-<p>Operator overloading is inspired from the proposal available at
-<a href="https://github.com/tc39/proposal-operator-overloading/">https://github.com/tc39/proposal-operator-overloading/</a>. It
-implements the same dispatch logic but finds the operator sets by
-looking at the <code>Symbol.operatorSet</code> property in the objects. The
-changes were done in order to simplify the implementation.
-</p>
-<p>More precisely, the following modifications were made:
-</p>
-<ul>
-<li> <code>with operators from</code> is not supported. Operator overloading is always enabled.
-
-</li><li> The dispatch is not based on a static <code>[[OperatorSet]]</code> field in all instances. Instead, a dynamic lookup of the <code>Symbol.operatorSet</code> property is done. This property is typically added in the prototype of each object.
-
-</li><li> <code>Operators.create(...dictionaries)</code> is used to create a new OperatorSet object. The <code>Operators</code> function is supported as an helper to be closer to the TC39 proposal.
-
-</li><li> <code>[]</code> cannot be overloaded.
-
-</li><li> In math mode, the BigInt division and power operators can be overloaded with <code>Operators.updateBigIntOperators(dictionary)</code>.
-
-</li></ul>
-
-<a name="BigInt-extensions"></a>
-<h2 class="chapter">3 BigInt extensions</h2>
-
-<p>A few properties are added to the BigInt object:
-</p>
-<dl compact="compact">
-<dt><code>tdiv(a, b)</code></dt>
-<dd><p>Return <em>trunc(a/b)</em>. <code>b = 0</code> raises a RangeError
-exception.
-</p>
-</dd>
-<dt><code>fdiv(a, b)</code></dt>
-<dd><p>Return <em>\lfloor a/b \rfloor</em>. <code>b = 0</code> raises a RangeError
-exception.
-</p>
-</dd>
-<dt><code>cdiv(a, b)</code></dt>
-<dd><p>Return <em>\lceil a/b \rceil</em>. <code>b = 0</code> raises a RangeError
-exception.
-</p>
-</dd>
-<dt><code>ediv(a, b)</code></dt>
-<dd><p>Return <em>sgn(b) \lfloor a/{|b|} \rfloor</em> (Euclidian
-division). <code>b = 0</code> raises a RangeError exception.
-</p>
-</dd>
-<dt><code>tdivrem(a, b)</code></dt>
-<dt><code>fdivrem(a, b)</code></dt>
-<dt><code>cdivrem(a, b)</code></dt>
-<dt><code>edivrem(a, b)</code></dt>
-<dd><p>Return an array of two elements. The first element is the quotient,
-the second is the remainder. The same rounding is done as the
-corresponding division operation.
-</p>
-</dd>
-<dt><code>sqrt(a)</code></dt>
-<dd><p>Return <em>\lfloor \sqrt(a) \rfloor</em>. A RangeError exception is
-raised if <em>a &lt; 0</em>.
-</p>
-</dd>
-<dt><code>sqrtrem(a)</code></dt>
-<dd><p>Return an array of two elements. The first element is <em>\lfloor
-\sqrt{a} \rfloor</em>. The second element is <em>a-\lfloor \sqrt{a}
-\rfloor^2</em>. A RangeError exception is raised if <em>a &lt; 0</em>.
-</p>
-</dd>
-<dt><code>floorLog2(a)</code></dt>
-<dd><p>Return -1 if <em>a \leq 0</em> otherwise return <em>\lfloor \log2(a) \rfloor</em>.
-</p>
-</dd>
-<dt><code>ctz(a)</code></dt>
-<dd><p>Return the number of trailing zeros in the two&rsquo;s complement binary representation of a. Return -1 if <em>a=0</em>.
-</p>
-</dd>
-</dl>
-
-<a name="BigFloat"></a>
-<h2 class="chapter">4 BigFloat</h2>
-
-<a name="Introduction-1"></a>
-<h3 class="section">4.1 Introduction</h3>
-
-<p>This extension adds the <code>BigFloat</code> primitive type. The
-<code>BigFloat</code> type represents floating point numbers in base 2
-with the IEEE 754 semantics. A floating
-point number is represented as a sign, mantissa and exponent. The
-special values <code>NaN</code>, <code>+/-Infinity</code>, <code>+0</code> and <code>-0</code>
-are supported. The mantissa and exponent can have any bit length with
-an implementation specific minimum and maximum.
-</p>
-<a name="Floating-point-rounding"></a>
-<h3 class="section">4.2 Floating point rounding</h3>
-
-<p>Each floating point operation operates with infinite precision and
-then rounds the result according to the specified floating point
-environment (<code>BigFloatEnv</code> object). The status flags of the
-environment are also set according to the result of the operation.
-</p>
-<p>If no floating point environment is provided, the global floating
-point environment is used.
-</p>
-<p>The rounding mode of the global floating point environment is always
-<code>RNDN</code> (&ldquo;round to nearest with ties to even&rdquo;)<a name="DOCF1" href="#FOOT1"><sup>1</sup></a>. The status flags of the global environment cannot be
-read<a name="DOCF2" href="#FOOT2"><sup>2</sup></a>. The precision of the global environment is
-<code>BigFloatEnv.prec</code>. The number of exponent bits of the global
-environment is <code>BigFloatEnv.expBits</code>. The global environment
-subnormal flag is set to <code>true</code>.
-</p>
-<p>For example, <code>prec = 53</code> and <code> expBits = 11</code> exactly give
-the same precision as the IEEE 754 64 bit floating point format. The
-default precision is <code>prec = 113</code> and <code> expBits = 15</code> (IEEE
-754 128 bit floating point format).
-</p>
-<p>The global floating point environment can only be modified temporarily
-when calling a function (see <code>BigFloatEnv.setPrec</code>). Hence a
-function can change the global floating point environment for its
-callees but not for its caller.
-</p>
-<a name="Operators"></a>
-<h3 class="section">4.3 Operators</h3>
-
-<p>The builtin operators are extended so that a BigFloat is returned if
-at least one operand is a BigFloat. The computations are always done
-with infinite precision and rounded according to the global floating
-point environment.
-</p>
-<p><code>typeof</code> applied on a <code>BigFloat</code> returns <code>bigfloat</code>.
-</p>
-<p>BigFloat can be compared with all the other numeric types and the
-result follows the expected mathematical relations.
-</p>
-<p>However, since BigFloat and Number are different types they are never
-equal when using the strict comparison operators (e.g. <code>0.0 ===
-0.0l</code> is false).
-</p>
-<a name="BigFloat-literals"></a>
-<h3 class="section">4.4 BigFloat literals</h3>
-
-<p>BigFloat literals are floating point numbers with a trailing <code>l</code>
-suffix. BigFloat literals have an infinite precision. They are rounded
-according to the global floating point environment when they are
-evaluated.<a name="DOCF3" href="#FOOT3"><sup>3</sup></a>
-</p>
-<a name="Builtin-Object-changes"></a>
-<h3 class="section">4.5 Builtin Object changes</h3>
-
-<a name="BigFloat-function"></a>
-<h4 class="subsection">4.5.1 <code>BigFloat</code> function</h4>
-
-<p>The <code>BigFloat</code> function cannot be invoked as a constructor. When
-invoked as a function: the parameter is converted to a primitive
-type. If the result is a numeric type, it is converted to BigFloat
-without rounding. If the result is a string, it is converted to
-BigFloat using the precision of the global floating point environment.
-</p>
-<p><code>BigFloat</code> properties:
-</p>
-<dl compact="compact">
-<dt><code>LN2</code></dt>
-<dt><code>PI</code></dt>
-<dd><p>Getter. Return the value of the corresponding mathematical constant
-rounded to nearest, ties to even with the current global
-precision. The constant values are cached for small precisions.
-</p>
-</dd>
-<dt><code>MIN_VALUE</code></dt>
-<dt><code>MAX_VALUE</code></dt>
-<dt><code>EPSILON</code></dt>
-<dd><p>Getter. Return the minimum, maximum and epsilon <code>BigFloat</code> values
-(same definition as the corresponding <code>Number</code> constants).
-</p>
-</dd>
-<dt><code>fpRound(a[, e])</code></dt>
-<dd><p>Round the floating point number <code>a</code> according to the floating
-point environment <code>e</code> or the global environment if <code>e</code> is
-undefined.
-</p>
-</dd>
-<dt><code>parseFloat(a[, radix[, e]])</code></dt>
-<dd><p>Parse the string <code>a</code> as a floating point number in radix
-<code>radix</code>. The radix is 0 (default) or from 2 to 36. The radix 0
-means radix 10 unless there is a hexadecimal or binary prefix. The
-result is rounded according to the floating point environment <code>e</code>
-or the global environment if <code>e</code> is undefined.
-</p>
-</dd>
-<dt><code>isFinite(a)</code></dt>
-<dd><p>Return true if <code>a</code> is a finite bigfloat.
-</p>
-</dd>
-<dt><code>isNaN(a)</code></dt>
-<dd><p>Return true if <code>a</code> is a NaN bigfloat.
-</p>
-</dd>
-<dt><code>add(a, b[, e])</code></dt>
-<dt><code>sub(a, b[, e])</code></dt>
-<dt><code>mul(a, b[, e])</code></dt>
-<dt><code>div(a, b[, e])</code></dt>
-<dd><p>Perform the specified floating point operation and round the floating
-point number <code>a</code> according to the floating point environment
-<code>e</code> or the global environment if <code>e</code> is undefined. If
-<code>e</code> is specified, the floating point status flags are updated.
-</p>
-</dd>
-<dt><code>floor(x)</code></dt>
-<dt><code>ceil(x)</code></dt>
-<dt><code>round(x)</code></dt>
-<dt><code>trunc(x)</code></dt>
-<dd><p>Round to an integer. No additional rounding is performed.
-</p>
-</dd>
-<dt><code>abs(x)</code></dt>
-<dd><p>Return the absolute value of x. No additional rounding is performed.
-</p>
-</dd>
-<dt><code>fmod(x, y[, e])</code></dt>
-<dt><code>remainder(x, y[, e])</code></dt>
-<dd><p>Floating point remainder. The quotient is truncated to zero (fmod) or
-to the nearest integer with ties to even (remainder). <code>e</code> is an
-optional floating point environment.
-</p>
-</dd>
-<dt><code>sqrt(x[, e])</code></dt>
-<dd><p>Square root. Return a rounded floating point number. <code>e</code> is an
-optional floating point environment.
-</p>
-</dd>
-<dt><code>sin(x[, e])</code></dt>
-<dt><code>cos(x[, e])</code></dt>
-<dt><code>tan(x[, e])</code></dt>
-<dt><code>asin(x[, e])</code></dt>
-<dt><code>acos(x[, e])</code></dt>
-<dt><code>atan(x[, e])</code></dt>
-<dt><code>atan2(x, y[, e])</code></dt>
-<dt><code>exp(x[, e])</code></dt>
-<dt><code>log(x[, e])</code></dt>
-<dt><code>pow(x, y[, e])</code></dt>
-<dd><p>Transcendental operations. Return a rounded floating point
-number. <code>e</code> is an optional floating point environment.
-</p>
-</dd>
-</dl>
-
-<a name="BigFloat_002eprototype"></a>
-<h4 class="subsection">4.5.2 <code>BigFloat.prototype</code></h4>
-
-<p>The following properties are modified:
-</p>
-<dl compact="compact">
-<dt><code>valueOf()</code></dt>
-<dd><p>Return the bigfloat primitive value corresponding to <code>this</code>.
-</p>
-</dd>
-<dt><code>toString(radix)</code></dt>
-<dd>
-<p>For floating point numbers:
-</p>
-<ul>
-<li> If the radix is a power of two, the conversion is done with infinite
-precision.
-</li><li> Otherwise, the number is rounded to nearest with ties to even using
-the global precision. It is then converted to string using the minimum
-number of digits so that its conversion back to a floating point using
-the global precision and round to nearest gives the same number.
-
-</li></ul>
-
-<p>The exponent letter is <code>e</code> for base 10, <code>p</code> for bases 2, 8,
-16 with a binary exponent and <code>@</code> for the other bases.
-</p>
-</dd>
-<dt><code>toPrecision(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)</code></dt>
-<dt><code>toFixed(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)</code></dt>
-<dt><code>toExponential(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)</code></dt>
-<dd><p>Same semantics as the corresponding <code>Number</code> functions with
-BigFloats. There is no limit on the accepted precision <code>p</code>. The
-rounding mode and radix can be optionally specified. The radix must be
-between 2 and 36.
-</p>
-</dd>
-</dl>
-
-<a name="BigFloatEnv-constructor"></a>
-<h4 class="subsection">4.5.3 <code>BigFloatEnv</code> constructor</h4>
-
-<p>The <code>BigFloatEnv([p, [,rndMode]]</code> constructor cannot be invoked as a
-function. The floating point environment contains:
-</p>
-<ul>
-<li> the mantissa precision in bits
-
-</li><li> the exponent size in bits assuming an IEEE 754 representation;
-
-</li><li> the subnormal flag (if true, subnormal floating point numbers can
-be generated by the floating point operations).
-
-</li><li> the rounding mode
-
-</li><li> the floating point status. The status flags can only be set by the floating point operations. They can be reset with <code>BigFloatEnv.prototype.clearStatus()</code> or with the various status flag setters.
-
-</li></ul>
-
-<p><code>new BigFloatEnv([p, [,rndMode]]</code> creates a new floating point
-environment. The status flags are reset. If no parameter is given the
-precision, exponent bits and subnormal flags are copied from the
-global floating point environment. Otherwise, the precision is set to
-<code>p</code>, the number of exponent bits is set to <code>expBitsMax</code> and the
-subnormal flags is set to <code>false</code>. If <code>rndMode</code> is
-<code>undefined</code>, the rounding mode is set to <code>RNDN</code>.
-</p>
-<p><code>BigFloatEnv</code> properties:
-</p>
-<dl compact="compact">
-<dt><code>prec</code></dt>
-<dd><p>Getter. Return the precision in bits of the global floating point
-environment. The initial value is <code>113</code>.
-</p>
-</dd>
-<dt><code>expBits</code></dt>
-<dd><p>Getter. Return the exponent size in bits of the global floating point
-environment assuming an IEEE 754 representation. The initial value is
-<code>15</code>.
-</p>
-</dd>
-<dt><code>setPrec(f, p[, e])</code></dt>
-<dd><p>Set the precision of the global floating point environment to <code>p</code>
-and the exponent size to <code>e</code> then call the function
-<code>f</code>. Then the Float precision and exponent size are reset to
-their precious value and the return value of <code>f</code> is returned (or
-an exception is raised if <code>f</code> raised an exception). If <code>e</code>
-is <code>undefined</code> it is set to <code>BigFloatEnv.expBitsMax</code>.
-</p>
-</dd>
-<dt><code>precMin</code></dt>
-<dd><p>Read-only integer. Return the minimum allowed precision. Must be at least 2.
-</p>
-</dd>
-<dt><code>precMax</code></dt>
-<dd><p>Read-only integer. Return the maximum allowed precision. Must be at least 113.
-</p>
-</dd>
-<dt><code>expBitsMin</code></dt>
-<dd><p>Read-only integer. Return the minimum allowed exponent size in
-bits. Must be at least 3.
-</p>
-</dd>
-<dt><code>expBitsMax</code></dt>
-<dd><p>Read-only integer. Return the maximum allowed exponent size in
-bits. Must be at least 15.
-</p>
-</dd>
-<dt><code>RNDN</code></dt>
-<dd><p>Read-only integer. Round to nearest, with ties to even rounding mode.
-</p>
-</dd>
-<dt><code>RNDZ</code></dt>
-<dd><p>Read-only integer. Round to zero rounding mode.
-</p>
-</dd>
-<dt><code>RNDD</code></dt>
-<dd><p>Read-only integer. Round to -Infinity rounding mode.
-</p>
-</dd>
-<dt><code>RNDU</code></dt>
-<dd><p>Read-only integer. Round to +Infinity rounding mode.
-</p>
-</dd>
-<dt><code>RNDNA</code></dt>
-<dd><p>Read-only integer. Round to nearest, with ties away from zero rounding mode.
-</p>
-</dd>
-<dt><code>RNDA</code></dt>
-<dd><p>Read-only integer. Round away from zero rounding mode.
-</p>
-</dd>
-<dt><code>RNDF<a name="DOCF4" href="#FOOT4"><sup>4</sup></a></code></dt>
-<dd><p>Read-only integer. Faithful rounding mode. The result is
-non-deterministically rounded to -Infinity or +Infinity. This rounding
-mode usually gives a faster and deterministic running time for the
-floating point operations.
-</p>
-</dd>
-</dl>
-
-<p><code>BigFloatEnv.prototype</code> properties:
-</p>
-<dl compact="compact">
-<dt><code>prec</code></dt>
-<dd><p>Getter and setter (Integer). Return or set the precision in bits.
-</p>
-</dd>
-<dt><code>expBits</code></dt>
-<dd><p>Getter and setter (Integer). Return or set the exponent size in bits
-assuming an IEEE 754 representation.
-</p>
-</dd>
-<dt><code>rndMode</code></dt>
-<dd><p>Getter and setter (Integer). Return or set the rounding mode.
-</p>
-</dd>
-<dt><code>subnormal</code></dt>
-<dd><p>Getter and setter (Boolean). subnormal flag. It is false when
-<code>expBits = expBitsMax</code>.
-</p>
-</dd>
-<dt><code>clearStatus()</code></dt>
-<dd><p>Clear the status flags.
-</p>
-</dd>
-<dt><code>invalidOperation</code></dt>
-<dt><code>divideByZero</code></dt>
-<dt><code>overflow</code></dt>
-<dt><code>underflow</code></dt>
-<dt><code>inexact</code></dt>
-<dd><p>Getter and setter (Boolean). Status flags.
-</p>
-</dd>
-</dl>
-
-<a name="BigDecimal"></a>
-<h2 class="chapter">5 BigDecimal</h2>
-
-<p>This extension adds the <code>BigDecimal</code> primitive type. The
-<code>BigDecimal</code> type represents floating point numbers in base
-10. It is inspired from the proposal available at
-<a href="https://github.com/littledan/proposal-bigdecimal">https://github.com/littledan/proposal-bigdecimal</a>.
-</p>
-<p>The <code>BigDecimal</code> floating point numbers are always normalized and
-finite. There is no concept of <code>-0</code>, <code>Infinity</code> or
-<code>NaN</code>. By default, all the computations are done with infinite
-precision.
-</p>
-<a name="Operators-1"></a>
-<h3 class="section">5.1 Operators</h3>
-
-<p>The following builtin operators support BigDecimal:
-</p>
-<dl compact="compact">
-<dt><code>+</code></dt>
-<dt><code>-</code></dt>
-<dt><code>*</code></dt>
-<dd><p>Both operands must be BigDecimal. The result is computed with infinite
-precision.
-</p></dd>
-<dt><code>%</code></dt>
-<dd><p>Both operands must be BigDecimal. The result is computed with infinite
-precision. A range error is throws in case of division by zero.
-</p>
-</dd>
-<dt><code>/</code></dt>
-<dd><p>Both operands must be BigDecimal. A range error is throws in case of
-division by zero or if the result cannot be represented with infinite
-precision (use <code>BigDecimal.div</code> to specify the rounding).
-</p>
-</dd>
-<dt><code>**</code></dt>
-<dd><p>Both operands must be BigDecimal. The exponent must be a positive
-integer. The result is computed with infinite precision.
-</p>
-</dd>
-<dt><code>===</code></dt>
-<dd><p>When one of the operand is a BigDecimal, return true if both operands
-are a BigDecimal and if they are equal.
-</p>
-</dd>
-<dt><code>==</code></dt>
-<dt><code>!=</code></dt>
-<dt><code>&lt;=</code></dt>
-<dt><code>&gt;=</code></dt>
-<dt><code>&lt;</code></dt>
-<dt><code>&gt;</code></dt>
-<dd>
-<p>Numerical comparison. When one of the operand is not a BigDecimal, it is
-converted to BigDecimal by using ToString(). Hence comparisons between
-Number and BigDecimal do not use the exact mathematical value of the
-Number value.
-</p>
-</dd>
-</dl>
-
-<a name="BigDecimal-literals"></a>
-<h3 class="section">5.2 BigDecimal literals</h3>
-
-<p>BigDecimal literals are decimal floating point numbers with a trailing
-<code>m</code> suffix.
-</p>
-<a name="Builtin-Object-changes-1"></a>
-<h3 class="section">5.3 Builtin Object changes</h3>
-
-<a name="The-BigDecimal-function_002e"></a>
-<h4 class="subsection">5.3.1 The <code>BigDecimal</code> function.</h4>
-
-<p>It returns <code>0m</code> if no parameter is provided. Otherwise the first
-parameter is converted to a bigdecimal by using ToString(). Hence
-Number values are not converted to their exact numerical value as
-BigDecimal.
-</p>
-<a name="Properties-of-the-BigDecimal-object"></a>
-<h4 class="subsection">5.3.2 Properties of the <code>BigDecimal</code> object</h4>
-
-<dl compact="compact">
-<dt><code>add(a, b[, e])</code></dt>
-<dt><code>sub(a, b[, e])</code></dt>
-<dt><code>mul(a, b[, e])</code></dt>
-<dt><code>div(a, b[, e])</code></dt>
-<dt><code>mod(a, b[, e])</code></dt>
-<dt><code>sqrt(a, e)</code></dt>
-<dt><code>round(a, e)</code></dt>
-<dd><p>Perform the specified floating point operation and round the floating
-point result according to the rounding object <code>e</code>. If the
-rounding object is not present, the operation is executed with
-infinite precision.
-</p>
-<p>For <code>div</code>, a <code>RangeError</code> exception is thrown in case of
-division by zero or if the result cannot be represented with infinite
-precision if no rounding object is present.
-</p>
-<p>For <code>sqrt</code>, a range error is thrown if <code>a</code> is less than
-zero.
-</p>
-<p>The rounding object must contain the following properties:
-<code>roundingMode</code> is a string specifying the rounding mode
-(<code>&quot;floor&quot;</code>, <code>&quot;ceiling&quot;</code>, <code>&quot;down&quot;</code>, <code>&quot;up&quot;</code>,
-<code>&quot;half-even&quot;</code>, <code>&quot;half-up&quot;</code>). Either
-<code>maximumSignificantDigits</code> or <code>maximumFractionDigits</code> must
-be present to specify respectively the number of significant digits
-(must be &gt;= 1) or the number of digits after the decimal point (must
-be &gt;= 0).
-</p>
-</dd>
-</dl>
-
-<a name="Properties-of-the-BigDecimal_002eprototype-object"></a>
-<h4 class="subsection">5.3.3 Properties of the <code>BigDecimal.prototype</code> object</h4>
-
-<dl compact="compact">
-<dt><code>valueOf()</code></dt>
-<dd><p>Return the bigdecimal primitive value corresponding to <code>this</code>.
-</p>
-</dd>
-<dt><code>toString()</code></dt>
-<dd><p>Convert <code>this</code> to a string with infinite precision in base 10.
-</p>
-</dd>
-<dt><code>toPrecision(p, rnd_mode = &quot;half-up&quot;)</code></dt>
-<dt><code>toFixed(p, rnd_mode = &quot;half-up&quot;)</code></dt>
-<dt><code>toExponential(p, rnd_mode = &quot;half-up&quot;)</code></dt>
-<dd><p>Convert the BigDecimal <code>this</code> to string with the specified
-precision <code>p</code>. There is no limit on the accepted precision
-<code>p</code>. The rounding mode can be optionally
-specified. <code>toPrecision</code> outputs either in decimal fixed notation
-or in decimal exponential notation with a <code>p</code> digits of
-precision. <code>toExponential</code> outputs in decimal exponential
-notation with <code>p</code> digits after the decimal point. <code>toFixed</code>
-outputs in decimal notation with <code>p</code> digits after the decimal
-point.
-</p>
-</dd>
-</dl>
-
-<a name="Math-mode"></a>
-<h2 class="chapter">6 Math mode</h2>
-
-<p>A new <em>math mode</em> is enabled with the <code>&quot;use math&quot;</code>
-directive. It propagates the same way as the <em>strict mode</em>. It is
-designed so that arbitrarily large integers and floating point numbers
-are available by default. In order to minimize the number of changes
-in the Javascript semantics, integers are represented either as Number
-or BigInt depending on their magnitude. Floating point numbers are
-always represented as BigFloat.
-</p>
-<p>The following changes are made to the Javascript semantics:
-</p>
-<ul>
-<li> Floating point literals (i.e. number with a decimal point or an exponent) are <code>BigFloat</code> by default (i.e. a <code>l</code> suffix is implied). Hence <code>typeof 1.0 === &quot;bigfloat&quot;</code>.
-
-</li><li> Integer literals (i.e. numbers without a decimal point or an exponent) with or without the <code>n</code> suffix are <code>BigInt</code> if their value cannot be represented as a safe integer. A safe integer is defined as a integer whose absolute value is smaller or equal to <code>2**53-1</code>. Hence <code>typeof 1 === &quot;number &quot;</code>, <code>typeof 1n === &quot;number&quot;</code> but <code>typeof 9007199254740992 === &quot;bigint&quot; </code>.
-
-</li><li> All the bigint builtin operators and functions are modified so that their result is returned as a Number if it is a safe integer. Otherwise the result stays a BigInt.
-
-</li><li> The builtin operators are modified so that they return an exact result (which can be a BigInt) if their operands are safe integers. Operands between Number and BigInt are accepted provided the Number operand is a safe integer. The integer power with a negative exponent returns a BigFloat as result. The integer division returns a BigFloat as result.
-
-</li><li> The <code>^</code> operator is an alias to the power operator (<code>**</code>).
-
-</li><li> The power operator (both <code>^</code> and <code>**</code>) grammar is modified so that <code>-2^2</code> is allowed and yields <code>-4</code>.
-
-</li><li> The logical xor operator is still available with the <code>^^</code> operator.
-
-</li><li> The modulo operator (<code>%</code>) returns the Euclidian remainder (always positive) instead of the truncated remainder.
-
-</li><li> The integer division operator can be overloaded with <code>Operators.updateBigIntOperators(dictionary)</code>.
-
-</li><li> The integer power operator with a non zero negative exponent can be overloaded with <code>Operators.updateBigIntOperators(dictionary)</code>.
-
-</li></ul>
-
-<div class="footnote">
-<hr>
-<h4 class="footnotes-heading">Footnotes</h4>
-
-<h3><a name="FOOT1" href="#DOCF1">(1)</a></h3>
-<p>The
-rationale is that the rounding mode changes must always be
-explicit.</p>
-<h3><a name="FOOT2" href="#DOCF2">(2)</a></h3>
-<p>The rationale is to avoid side effects for the built-in
-operators.</p>
-<h3><a name="FOOT3" href="#DOCF3">(3)</a></h3>
-<p>Base 10 floating point literals cannot usually be
-exactly represented as base 2 floating point number. In order to
-ensure that the literal is represented accurately with the current
-precision, it must be evaluated at runtime.</p>
-<h3><a name="FOOT4" href="#DOCF4">(4)</a></h3>
-<p>Could be removed in case a deterministic behavior for floating point operations is required.</p>
-</div>
-<hr>
-
-
-
-</body>
-</html>
diff --git a/doc/jsbignum.pdf b/doc/jsbignum.pdf
deleted file mode 100644
index 442a8c0..0000000
--- a/doc/jsbignum.pdf
+++ /dev/null
Binary files differ
diff --git a/doc/quickjs.html b/doc/quickjs.html
deleted file mode 100644
index e8b3369..0000000
--- a/doc/quickjs.html
+++ /dev/null
@@ -1,1369 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<!-- Created by GNU Texinfo 6.1, http://www.gnu.org/software/texinfo/ -->
-<head>
-<title>QuickJS Javascript Engine</title>
-
-<meta name="description" content="QuickJS Javascript Engine">
-<meta name="keywords" content="QuickJS Javascript Engine">
-<meta name="resource-type" content="document">
-<meta name="distribution" content="global">
-<meta name="Generator" content="makeinfo">
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-<link href="#SEC_Contents" rel="contents" title="Table of Contents">
-<style type="text/css">
-<!--
-a.summary-letter {text-decoration: none}
-blockquote.indentedblock {margin-right: 0em}
-blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
-blockquote.smallquotation {font-size: smaller}
-div.display {margin-left: 3.2em}
-div.example {margin-left: 3.2em}
-div.lisp {margin-left: 3.2em}
-div.smalldisplay {margin-left: 3.2em}
-div.smallexample {margin-left: 3.2em}
-div.smalllisp {margin-left: 3.2em}
-kbd {font-style: oblique}
-pre.display {font-family: inherit}
-pre.format {font-family: inherit}
-pre.menu-comment {font-family: serif}
-pre.menu-preformatted {font-family: serif}
-pre.smalldisplay {font-family: inherit; font-size: smaller}
-pre.smallexample {font-size: smaller}
-pre.smallformat {font-family: inherit; font-size: smaller}
-pre.smalllisp {font-size: smaller}
-span.nolinebreak {white-space: nowrap}
-span.roman {font-family: initial; font-weight: normal}
-span.sansserif {font-family: sans-serif; font-weight: normal}
-ul.no-bullet {list-style: none}
--->
-</style>
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
-
-
-</head>
-
-<body lang="en">
-<h1 class="settitle" align="center">QuickJS Javascript Engine</h1>
-
-<a name="SEC_Contents"></a>
-<h2 class="contents-heading">Table of Contents</h2>
-
-<div class="contents">
-<ul class="no-bullet">
-<li><a name="toc-Introduction" href="#Introduction">1 Introduction</a>
-<ul class="no-bullet">
- <li><a name="toc-Main-Features" href="#Main-Features">1.1 Main Features</a></li>
-</ul></li>
-<li><a name="toc-Usage" href="#Usage">2 Usage</a>
-<ul class="no-bullet">
- <li><a name="toc-Installation" href="#Installation">2.1 Installation</a></li>
- <li><a name="toc-Quick-start" href="#Quick-start">2.2 Quick start</a></li>
- <li><a name="toc-Command-line-options" href="#Command-line-options">2.3 Command line options</a>
- <ul class="no-bullet">
- <li><a name="toc-qjs-interpreter" href="#qjs-interpreter">2.3.1 <code>qjs</code> interpreter</a></li>
- <li><a name="toc-qjsc-compiler" href="#qjsc-compiler">2.3.2 <code>qjsc</code> compiler</a></li>
- </ul></li>
- <li><a name="toc-qjscalc-application" href="#qjscalc-application">2.4 <code>qjscalc</code> application</a></li>
- <li><a name="toc-Built_002din-tests" href="#Built_002din-tests">2.5 Built-in tests</a></li>
- <li><a name="toc-Test262-_0028ECMAScript-Test-Suite_0029" href="#Test262-_0028ECMAScript-Test-Suite_0029">2.6 Test262 (ECMAScript Test Suite)</a></li>
-</ul></li>
-<li><a name="toc-Specifications" href="#Specifications">3 Specifications</a>
-<ul class="no-bullet">
- <li><a name="toc-Language-support" href="#Language-support">3.1 Language support</a>
- <ul class="no-bullet">
- <li><a name="toc-ES2020-support" href="#ES2020-support">3.1.1 ES2020 support</a></li>
- <li><a name="toc-ECMA402" href="#ECMA402">3.1.2 ECMA402</a></li>
- <li><a name="toc-Extensions" href="#Extensions">3.1.3 Extensions</a></li>
- <li><a name="toc-Mathematical-extensions" href="#Mathematical-extensions">3.1.4 Mathematical extensions</a></li>
- </ul></li>
- <li><a name="toc-Modules" href="#Modules">3.2 Modules</a></li>
- <li><a name="toc-Standard-library" href="#Standard-library">3.3 Standard library</a>
- <ul class="no-bullet">
- <li><a name="toc-Global-objects" href="#Global-objects">3.3.1 Global objects</a></li>
- <li><a name="toc-std-module" href="#std-module">3.3.2 <code>std</code> module</a></li>
- <li><a name="toc-os-module" href="#os-module">3.3.3 <code>os</code> module</a></li>
- </ul></li>
- <li><a name="toc-QuickJS-C-API" href="#QuickJS-C-API">3.4 QuickJS C API</a>
- <ul class="no-bullet">
- <li><a name="toc-Runtime-and-contexts" href="#Runtime-and-contexts">3.4.1 Runtime and contexts</a></li>
- <li><a name="toc-JSValue" href="#JSValue">3.4.2 JSValue</a></li>
- <li><a name="toc-C-functions" href="#C-functions">3.4.3 C functions</a></li>
- <li><a name="toc-Exceptions" href="#Exceptions">3.4.4 Exceptions</a></li>
- <li><a name="toc-Script-evaluation" href="#Script-evaluation">3.4.5 Script evaluation</a></li>
- <li><a name="toc-JS-Classes" href="#JS-Classes">3.4.6 JS Classes</a></li>
- <li><a name="toc-C-Modules" href="#C-Modules">3.4.7 C Modules</a></li>
- <li><a name="toc-Memory-handling" href="#Memory-handling">3.4.8 Memory handling</a></li>
- <li><a name="toc-Execution-timeout-and-interrupts" href="#Execution-timeout-and-interrupts">3.4.9 Execution timeout and interrupts</a></li>
- </ul></li>
-</ul></li>
-<li><a name="toc-Internals" href="#Internals">4 Internals</a>
-<ul class="no-bullet">
- <li><a name="toc-Bytecode" href="#Bytecode">4.1 Bytecode</a></li>
- <li><a name="toc-Executable-generation" href="#Executable-generation">4.2 Executable generation</a>
- <ul class="no-bullet">
- <li><a name="toc-qjsc-compiler-1" href="#qjsc-compiler-1">4.2.1 <code>qjsc</code> compiler</a></li>
- <li><a name="toc-Binary-JSON" href="#Binary-JSON">4.2.2 Binary JSON</a></li>
- </ul></li>
- <li><a name="toc-Runtime" href="#Runtime">4.3 Runtime</a>
- <ul class="no-bullet">
- <li><a name="toc-Strings" href="#Strings">4.3.1 Strings</a></li>
- <li><a name="toc-Objects" href="#Objects">4.3.2 Objects</a></li>
- <li><a name="toc-Atoms" href="#Atoms">4.3.3 Atoms</a></li>
- <li><a name="toc-Numbers" href="#Numbers">4.3.4 Numbers</a></li>
- <li><a name="toc-Garbage-collection" href="#Garbage-collection">4.3.5 Garbage collection</a></li>
- <li><a name="toc-JSValue-1" href="#JSValue-1">4.3.6 JSValue</a></li>
- <li><a name="toc-Function-call" href="#Function-call">4.3.7 Function call</a></li>
- </ul></li>
- <li><a name="toc-RegExp" href="#RegExp">4.4 RegExp</a></li>
- <li><a name="toc-Unicode" href="#Unicode">4.5 Unicode</a></li>
- <li><a name="toc-BigInt_002c-BigFloat_002c-BigDecimal" href="#BigInt_002c-BigFloat_002c-BigDecimal">4.6 BigInt, BigFloat, BigDecimal</a></li>
-</ul></li>
-<li><a name="toc-License" href="#License">5 License</a></li>
-
-</ul>
-</div>
-
-
-<a name="Introduction"></a>
-<h2 class="chapter">1 Introduction</h2>
-
-<p>QuickJS is a small and embeddable Javascript engine. It supports the
-ES2020 specification
-<a name="DOCF1" href="#FOOT1"><sup>1</sup></a>
-including modules, asynchronous generators, proxies and BigInt.
-</p>
-<p>It supports mathematical extensions such as big decimal float float
-numbers (BigDecimal), big binary floating point numbers (BigFloat),
-and operator overloading.
-</p>
-<a name="Main-Features"></a>
-<h3 class="section">1.1 Main Features</h3>
-
-<ul>
-<li> Small and easily embeddable: just a few C files, no external dependency, 210 KiB of x86 code for a simple &ldquo;hello world&rdquo; program.
-
-</li><li> Fast interpreter with very low startup time: runs the 69000 tests of the ECMAScript Test Suite<a name="DOCF2" href="#FOOT2"><sup>2</sup></a> in about 95 seconds on a single core of a desktop PC. The complete life cycle of a runtime instance completes in less than 300 microseconds.
-
-</li><li> Almost complete ES2020 support including modules, asynchronous
-generators and full Annex B support (legacy web compatibility). Many
-features from the upcoming ES2021 specification
-<a name="DOCF3" href="#FOOT3"><sup>3</sup></a> are also supported.
-
-</li><li> Passes nearly 100% of the ECMAScript Test Suite tests when selecting the ES2020 features.
-
-</li><li> Compile Javascript sources to executables with no external dependency.
-
-</li><li> Garbage collection using reference counting (to reduce memory usage and have deterministic behavior) with cycle removal.
-
-</li><li> Mathematical extensions: BigDecimal, BigFloat, operator overloading, bigint mode, math mode.
-
-</li><li> Command line interpreter with contextual colorization and completion implemented in Javascript.
-
-</li><li> Small built-in standard library with C library wrappers.
-
-</li></ul>
-
-<a name="Usage"></a>
-<h2 class="chapter">2 Usage</h2>
-
-<a name="Installation"></a>
-<h3 class="section">2.1 Installation</h3>
-
-<p>A Makefile is provided to compile the engine on Linux or MacOS/X. A
-preliminary Windows support is available thru cross compilation on a
-Linux host with the MingGW tools.
-</p>
-<p>Edit the top of the <code>Makefile</code> if you wish to select specific
-options then run <code>make</code>.
-</p>
-<p>You can type <code>make install</code> as root if you wish to install the binaries and support files to
-<code>/usr/local</code> (this is not necessary to use QuickJS).
-</p>
-<a name="Quick-start"></a>
-<h3 class="section">2.2 Quick start</h3>
-
-<p><code>qjs</code> is the command line interpreter (Read-Eval-Print Loop). You can pass
-Javascript files and/or expressions as arguments to execute them:
-</p>
-<div class="example">
-<pre class="example">./qjs examples/hello.js
-</pre></div>
-
-<p><code>qjsc</code> is the command line compiler:
-</p>
-<div class="example">
-<pre class="example">./qjsc -o hello examples/hello.js
-./hello
-</pre></div>
-
-<p>generates a <code>hello</code> executable with no external dependency.
-</p>
-<a name="Command-line-options"></a>
-<h3 class="section">2.3 Command line options</h3>
-
-<a name="qjs-interpreter"></a>
-<h4 class="subsection">2.3.1 <code>qjs</code> interpreter</h4>
-
-<pre class="verbatim">usage: qjs [options] [file [args]]
-</pre>
-<p>Options are:
-</p><dl compact="compact">
-<dt><code>-h</code></dt>
-<dt><code>--help</code></dt>
-<dd><p>List options.
-</p>
-</dd>
-<dt><code>-e <code>EXPR</code></code></dt>
-<dt><code>--eval <code>EXPR</code></code></dt>
-<dd><p>Evaluate EXPR.
-</p>
-</dd>
-<dt><code>-i</code></dt>
-<dt><code>--interactive</code></dt>
-<dd><p>Go to interactive mode (it is not the default when files are provided on the command line).
-</p>
-</dd>
-<dt><code>-m</code></dt>
-<dt><code>--module</code></dt>
-<dd><p>Load as ES6 module (default=autodetect). A module is autodetected if
-the filename extension is <code>.mjs</code> or if the first keyword of the
-source is <code>import</code>.
-</p>
-</dd>
-<dt><code>--script</code></dt>
-<dd><p>Load as ES6 script (default=autodetect).
-</p>
-</dd>
-<dt><code>--bignum</code></dt>
-<dd><p>Enable the bignum extensions: BigDecimal object, BigFloat object and
-the <code>&quot;use math&quot;</code> directive.
-</p>
-</dd>
-<dt><code>-I file</code></dt>
-<dt><code>--include file</code></dt>
-<dd><p>Include an additional file.
-</p>
-</dd>
-</dl>
-
-<p>Advanced options are:
-</p>
-<dl compact="compact">
-<dt><code>--std</code></dt>
-<dd><p>Make the <code>std</code> and <code>os</code> modules available to the loaded
-script even if it is not a module.
-</p>
-</dd>
-<dt><code>-d</code></dt>
-<dt><code>--dump</code></dt>
-<dd><p>Dump the memory usage stats.
-</p>
-</dd>
-<dt><code>-q</code></dt>
-<dt><code>--quit</code></dt>
-<dd><p>just instantiate the interpreter and quit.
-</p>
-</dd>
-</dl>
-
-<a name="qjsc-compiler"></a>
-<h4 class="subsection">2.3.2 <code>qjsc</code> compiler</h4>
-
-<pre class="verbatim">usage: qjsc [options] [files]
-</pre>
-<p>Options are:
-</p><dl compact="compact">
-<dt><code>-c</code></dt>
-<dd><p>Only output bytecode in a C file. The default is to output an executable file.
-</p></dd>
-<dt><code>-e</code></dt>
-<dd><p>Output <code>main()</code> and bytecode in a C file. The default is to output an
-executable file.
-</p></dd>
-<dt><code>-o output</code></dt>
-<dd><p>Set the output filename (default = <samp>out.c</samp> or <samp>a.out</samp>).
-</p>
-</dd>
-<dt><code>-N cname</code></dt>
-<dd><p>Set the C name of the generated data.
-</p>
-</dd>
-<dt><code>-m</code></dt>
-<dd><p>Compile as Javascript module (default=autodetect).
-</p>
-</dd>
-<dt><code>-D module_name</code></dt>
-<dd><p>Compile a dynamically loaded module and its dependencies. This option
-is needed when your code uses the <code>import</code> keyword or the
-<code>os.Worker</code> constructor because the compiler cannot statically
-find the name of the dynamically loaded modules.
-</p>
-</dd>
-<dt><code>-M module_name[,cname]</code></dt>
-<dd><p>Add initialization code for an external C module. See the
-<code>c_module</code> example.
-</p>
-</dd>
-<dt><code>-x</code></dt>
-<dd><p>Byte swapped output (only used for cross compilation).
-</p>
-</dd>
-<dt><code>-flto</code></dt>
-<dd><p>Use link time optimization. The compilation is slower but the
-executable is smaller and faster. This option is automatically set
-when the <code>-fno-x</code> options are used.
-</p>
-</dd>
-<dt><code>-fno-[eval|string-normalize|regexp|json|proxy|map|typedarray|promise|bigint]</code></dt>
-<dd><p>Disable selected language features to produce a smaller executable file.
-</p>
-</dd>
-<dt><code>-fbignum</code></dt>
-<dd><p>Enable the bignum extensions: BigDecimal object, BigFloat object and
-the <code>&quot;use math&quot;</code> directive.
-</p>
-</dd>
-</dl>
-
-<a name="qjscalc-application"></a>
-<h3 class="section">2.4 <code>qjscalc</code> application</h3>
-
-<p>The <code>qjscalc</code> application is a superset of the <code>qjs</code>
-command line interpreter implementing a Javascript calculator with
-arbitrarily large integer and floating point numbers, fractions,
-complex numbers, polynomials and matrices. The source code is in
-<samp>qjscalc.js</samp>. More documentation and a web version are available at
-<a href="http://numcalc.com">http://numcalc.com</a>.
-</p>
-<a name="Built_002din-tests"></a>
-<h3 class="section">2.5 Built-in tests</h3>
-
-<p>Run <code>make test</code> to run the few built-in tests included in the
-QuickJS archive.
-</p>
-<a name="Test262-_0028ECMAScript-Test-Suite_0029"></a>
-<h3 class="section">2.6 Test262 (ECMAScript Test Suite)</h3>
-
-<p>A test262 runner is included in the QuickJS archive. The test262 tests
-can be installed in the QuickJS source directory with:
-</p>
-<div class="example">
-<pre class="example">git clone https://github.com/tc39/test262.git test262
-cd test262
-patch -p1 &lt; ../tests/test262.patch
-cd ..
-</pre></div>
-
-<p>The patch adds the implementation specific <code>harness</code> functions
-and optimizes the inefficient RegExp character classes and Unicode
-property escapes tests (the tests themselves are not modified, only a
-slow string initialization function is optimized).
-</p>
-<p>The tests can be run with
-</p><div class="example">
-<pre class="example">make test2
-</pre></div>
-
-<p>The configuration files <code>test262.conf</code>
-(resp. <code>test262o.conf</code> for the old ES5.1 tests<a name="DOCF4" href="#FOOT4"><sup>4</sup></a>))
-contain the options to run the various tests. Tests can be excluded
-based on features or filename.
-</p>
-<p>The file <code>test262_errors.txt</code> contains the current list of
-errors. The runner displays a message when a new error appears or when
-an existing error is corrected or modified. Use the <code>-u</code> option
-to update the current list of errors (or <code>make test2-update</code>).
-</p>
-<p>The file <code>test262_report.txt</code> contains the logs of all the
-tests. It is useful to have a clearer analysis of a particular
-error. In case of crash, the last line corresponds to the failing
-test.
-</p>
-<p>Use the syntax <code>./run-test262 -c test262.conf -f filename.js</code> to
-run a single test. Use the syntax <code>./run-test262 -c test262.conf
-N</code> to start testing at test number <code>N</code>.
-</p>
-<p>For more information, run <code>./run-test262</code> to see the command line
-options of the test262 runner.
-</p>
-<p><code>run-test262</code> accepts the <code>-N</code> option to be invoked from
-<code>test262-harness</code><a name="DOCF5" href="#FOOT5"><sup>5</sup></a>
-thru <code>eshost</code>. Unless you want to compare QuickJS with other
-engines under the same conditions, we do not recommend to run the
-tests this way as it is much slower (typically half an hour instead of
-about 100 seconds).
-</p>
-<a name="Specifications"></a>
-<h2 class="chapter">3 Specifications</h2>
-
-<a name="Language-support"></a>
-<h3 class="section">3.1 Language support</h3>
-
-<a name="ES2020-support"></a>
-<h4 class="subsection">3.1.1 ES2020 support</h4>
-
-<p>The ES2020 specification is almost fully supported including the Annex
-B (legacy web compatibility) and the Unicode related features.
-</p>
-<p>The following features are not supported yet:
-</p>
-<ul>
-<li> Tail calls<a name="DOCF6" href="#FOOT6"><sup>6</sup></a>
-
-</li></ul>
-
-<a name="ECMA402"></a>
-<h4 class="subsection">3.1.2 ECMA402</h4>
-
-<p>ECMA402 (Internationalization API) is not supported.
-</p>
-<a name="Extensions"></a>
-<h4 class="subsection">3.1.3 Extensions</h4>
-
-<ul>
-<li> The directive <code>&quot;use strip&quot;</code> indicates that the debug information (including the source code of the functions) should not be retained to save memory. As <code>&quot;use strict&quot;</code>, the directive can be global to a script or local to a function.
-
-</li><li> The first line of a script beginning with <code>#!</code> is ignored.
-
-</li></ul>
-
-<a name="Mathematical-extensions"></a>
-<h4 class="subsection">3.1.4 Mathematical extensions</h4>
-
-<p>The mathematical extensions are fully backward compatible with
-standard Javascript. See <code>jsbignum.pdf</code> for more information.
-</p>
-<ul>
-<li> <code>BigDecimal</code> support: arbitrary large floating point numbers in base 10.
-
-</li><li> <code>BigFloat</code> support: arbitrary large floating point numbers in base 2.
-
-</li><li> Operator overloading.
-
-</li><li> The directive <code>&quot;use bigint&quot;</code> enables the bigint mode where integers are <code>BigInt</code> by default.
-
-</li><li> The directive <code>&quot;use math&quot;</code> enables the math mode where the division and power operators on integers produce fractions. Floating point literals are <code>BigFloat</code> by default and integers are <code>BigInt</code> by default.
-
-</li></ul>
-
-<a name="Modules"></a>
-<h3 class="section">3.2 Modules</h3>
-
-<p>ES6 modules are fully supported. The default name resolution is the
-following:
-</p>
-<ul>
-<li> Module names with a leading <code>.</code> or <code>..</code> are relative
-to the current module path.
-
-</li><li> Module names without a leading <code>.</code> or <code>..</code> are system
-modules, such as <code>std</code> or <code>os</code>.
-
-</li><li> Module names ending with <code>.so</code> are native modules using the
-QuickJS C API.
-
-</li></ul>
-
-<a name="Standard-library"></a>
-<h3 class="section">3.3 Standard library</h3>
-
-<p>The standard library is included by default in the command line
-interpreter. It contains the two modules <code>std</code> and <code>os</code> and
-a few global objects.
-</p>
-<a name="Global-objects"></a>
-<h4 class="subsection">3.3.1 Global objects</h4>
-
-<dl compact="compact">
-<dt><code>scriptArgs</code></dt>
-<dd><p>Provides the command line arguments. The first argument is the script name.
-</p></dd>
-<dt><code>print(...args)</code></dt>
-<dd><p>Print the arguments separated by spaces and a trailing newline.
-</p></dd>
-<dt><code>console.log(...args)</code></dt>
-<dd><p>Same as print().
-</p>
-</dd>
-</dl>
-
-<a name="std-module"></a>
-<h4 class="subsection">3.3.2 <code>std</code> module</h4>
-
-<p>The <code>std</code> module provides wrappers to the libc <samp>stdlib.h</samp>
-and <samp>stdio.h</samp> and a few other utilities.
-</p>
-<p>Available exports:
-</p>
-<dl compact="compact">
-<dt><code>exit(n)</code></dt>
-<dd><p>Exit the process.
-</p>
-</dd>
-<dt><code>evalScript(str, options = undefined)</code></dt>
-<dd><p>Evaluate the string <code>str</code> as a script (global
-eval). <code>options</code> is an optional object containing the following
-optional properties:
-</p>
-<dl compact="compact">
-<dt><code>backtrace_barrier</code></dt>
-<dd><p>Boolean (default = false). If true, error backtraces do not list the
- stack frames below the evalScript.
- </p></dd>
-</dl>
-
-</dd>
-<dt><code>loadScript(filename)</code></dt>
-<dd><p>Evaluate the file <code>filename</code> as a script (global eval).
-</p>
-</dd>
-<dt><code>loadFile(filename)</code></dt>
-<dd><p>Load the file <code>filename</code> and return it as a string assuming UTF-8
-encoding. Return <code>null</code> in case of I/O error.
-</p>
-</dd>
-<dt><code>open(filename, flags, errorObj = undefined)</code></dt>
-<dd><p>Open a file (wrapper to the libc <code>fopen()</code>). Return the FILE
-object or <code>null</code> in case of I/O error. If <code>errorObj</code> is not
-undefined, set its <code>errno</code> property to the error code or to 0 if
-no error occured.
-</p>
-</dd>
-<dt><code>popen(command, flags, errorObj = undefined)</code></dt>
-<dd><p>Open a process by creating a pipe (wrapper to the libc
-<code>popen()</code>). Return the FILE
-object or <code>null</code> in case of I/O error. If <code>errorObj</code> is not
-undefined, set its <code>errno</code> property to the error code or to 0 if
-no error occured.
-</p>
-</dd>
-<dt><code>fdopen(fd, flags, errorObj = undefined)</code></dt>
-<dd><p>Open a file from a file handle (wrapper to the libc
-<code>fdopen()</code>). Return the FILE
-object or <code>null</code> in case of I/O error. If <code>errorObj</code> is not
-undefined, set its <code>errno</code> property to the error code or to 0 if
-no error occured.
-</p>
-</dd>
-<dt><code>tmpfile(errorObj = undefined)</code></dt>
-<dd><p>Open a temporary file. Return the FILE
-object or <code>null</code> in case of I/O error. If <code>errorObj</code> is not
-undefined, set its <code>errno</code> property to the error code or to 0 if
-no error occured.
-</p>
-</dd>
-<dt><code>puts(str)</code></dt>
-<dd><p>Equivalent to <code>std.out.puts(str)</code>.
-</p>
-</dd>
-<dt><code>printf(fmt, ...args)</code></dt>
-<dd><p>Equivalent to <code>std.out.printf(fmt, ...args)</code>.
-</p>
-</dd>
-<dt><code>sprintf(fmt, ...args)</code></dt>
-<dd><p>Equivalent to the libc sprintf().
-</p>
-</dd>
-<dt><code>in</code></dt>
-<dt><code>out</code></dt>
-<dt><code>err</code></dt>
-<dd><p>Wrappers to the libc file <code>stdin</code>, <code>stdout</code>, <code>stderr</code>.
-</p>
-</dd>
-<dt><code>SEEK_SET</code></dt>
-<dt><code>SEEK_CUR</code></dt>
-<dt><code>SEEK_END</code></dt>
-<dd><p>Constants for seek().
-</p>
-</dd>
-<dt><code>Error</code></dt>
-<dd>
-<p>Enumeration object containing the integer value of common errors
-(additional error codes may be defined):
-</p>
-<dl compact="compact">
-<dt><code>EINVAL</code></dt>
-<dt><code>EIO</code></dt>
-<dt><code>EACCES</code></dt>
-<dt><code>EEXIST</code></dt>
-<dt><code>ENOSPC</code></dt>
-<dt><code>ENOSYS</code></dt>
-<dt><code>EBUSY</code></dt>
-<dt><code>ENOENT</code></dt>
-<dt><code>EPERM</code></dt>
-<dt><code>EPIPE</code></dt>
-</dl>
-
-</dd>
-<dt><code>strerror(errno)</code></dt>
-<dd><p>Return a string that describes the error <code>errno</code>.
-</p>
-</dd>
-<dt><code>gc()</code></dt>
-<dd><p>Manually invoke the cycle removal algorithm. The cycle removal
-algorithm is automatically started when needed, so this function is
-useful in case of specific memory constraints or for testing.
-</p>
-</dd>
-<dt><code>getenv(name)</code></dt>
-<dd><p>Return the value of the environment variable <code>name</code> or
-<code>undefined</code> if it is not defined.
-</p>
-</dd>
-<dt><code>urlGet(url, options = undefined)</code></dt>
-<dd>
-<p>Download <code>url</code> using the <samp>curl</samp> command line
-utility. <code>options</code> is an optional object containing the following
-optional properties:
-</p>
-<dl compact="compact">
-<dt><code>binary</code></dt>
-<dd><p>Boolean (default = false). If true, the response is an ArrayBuffer
- instead of a string. When a string is returned, the data is assumed
- to be UTF-8 encoded.
-</p>
-</dd>
-<dt><code>full</code></dt>
-<dd>
-<p>Boolean (default = false). If true, return the an object contains
- the properties <code>response</code> (response content),
- <code>responseHeaders</code> (headers separated by CRLF), <code>status</code>
- (status code). <code>response</code> is <code>null</code> is case of protocol or
- network error. If <code>full</code> is false, only the response is
- returned if the status is between 200 and 299. Otherwise <code>null</code>
- is returned.
-</p>
-</dd>
-</dl>
-
-</dd>
-<dt><code>parseExtJSON(str)</code></dt>
-<dd>
-<p>Parse <code>str</code> using a superset of <code>JSON.parse</code>. The
- following extensions are accepted:
-</p>
-<ul>
-<li> Single line and multiline comments
- </li><li> unquoted properties (ASCII-only Javascript identifiers)
- </li><li> trailing comma in array and object definitions
- </li><li> single quoted strings
- </li><li> <code>\f</code> and <code>\v</code> are accepted as space characters
- </li><li> leading plus in numbers
- </li><li> octal (<code>0o</code> prefix) and hexadecimal (<code>0x</code> prefix) numbers
- </li></ul>
-</dd>
-</dl>
-
-<p>FILE prototype:
-</p>
-<dl compact="compact">
-<dt><code>close()</code></dt>
-<dd><p>Close the file. Return 0 if OK or <code>-errno</code> in case of I/O error.
-</p></dd>
-<dt><code>puts(str)</code></dt>
-<dd><p>Outputs the string with the UTF-8 encoding.
-</p></dd>
-<dt><code>printf(fmt, ...args)</code></dt>
-<dd><p>Formatted printf.
-</p>
-<p>The same formats as the standard C library <code>printf</code> are
-supported. Integer format types (e.g. <code>%d</code>) truncate the Numbers
-or BigInts to 32 bits. Use the <code>l</code> modifier (e.g. <code>%ld</code>) to
-truncate to 64 bits.
-</p>
-</dd>
-<dt><code>flush()</code></dt>
-<dd><p>Flush the buffered file.
-</p></dd>
-<dt><code>seek(offset, whence)</code></dt>
-<dd><p>Seek to a give file position (whence is
-<code>std.SEEK_*</code>). <code>offset</code> can be a number or a bigint. Return
-0 if OK or <code>-errno</code> in case of I/O error.
-</p></dd>
-<dt><code>tell()</code></dt>
-<dd><p>Return the current file position.
-</p></dd>
-<dt><code>tello()</code></dt>
-<dd><p>Return the current file position as a bigint.
-</p></dd>
-<dt><code>eof()</code></dt>
-<dd><p>Return true if end of file.
-</p></dd>
-<dt><code>fileno()</code></dt>
-<dd><p>Return the associated OS handle.
-</p></dd>
-<dt><code>error()</code></dt>
-<dd><p>Return true if there was an error.
-</p></dd>
-<dt><code>clearerr()</code></dt>
-<dd><p>Clear the error indication.
-</p>
-</dd>
-<dt><code>read(buffer, position, length)</code></dt>
-<dd><p>Read <code>length</code> bytes from the file to the ArrayBuffer <code>buffer</code> at byte
-position <code>position</code> (wrapper to the libc <code>fread</code>).
-</p>
-</dd>
-<dt><code>write(buffer, position, length)</code></dt>
-<dd><p>Write <code>length</code> bytes to the file from the ArrayBuffer <code>buffer</code> at byte
-position <code>position</code> (wrapper to the libc <code>fread</code>).
-</p>
-</dd>
-<dt><code>getline()</code></dt>
-<dd><p>Return the next line from the file, assuming UTF-8 encoding, excluding
-the trailing line feed.
-</p>
-</dd>
-<dt><code>readAsString(max_size = undefined)</code></dt>
-<dd><p>Read <code>max_size</code> bytes from the file and return them as a string
-assuming UTF-8 encoding. If <code>max_size</code> is not present, the file
-is read up its end.
-</p>
-</dd>
-<dt><code>getByte()</code></dt>
-<dd><p>Return the next byte from the file. Return -1 if the end of file is reached.
-</p>
-</dd>
-<dt><code>putByte(c)</code></dt>
-<dd><p>Write one byte to the file.
-</p></dd>
-</dl>
-
-<a name="os-module"></a>
-<h4 class="subsection">3.3.3 <code>os</code> module</h4>
-
-<p>The <code>os</code> module provides Operating System specific functions:
-</p>
-<ul>
-<li> low level file access
-</li><li> signals
-</li><li> timers
-</li><li> asynchronous I/O
-</li><li> workers (threads)
-</li></ul>
-
-<p>The OS functions usually return 0 if OK or an OS specific negative
-error code.
-</p>
-<p>Available exports:
-</p>
-<dl compact="compact">
-<dt><code>open(filename, flags, mode = 0o666)</code></dt>
-<dd><p>Open a file. Return a handle or &lt; 0 if error.
-</p>
-</dd>
-<dt><code>O_RDONLY</code></dt>
-<dt><code>O_WRONLY</code></dt>
-<dt><code>O_RDWR</code></dt>
-<dt><code>O_APPEND</code></dt>
-<dt><code>O_CREAT</code></dt>
-<dt><code>O_EXCL</code></dt>
-<dt><code>O_TRUNC</code></dt>
-<dd><p>POSIX open flags.
-</p>
-</dd>
-<dt><code>O_TEXT</code></dt>
-<dd><p>(Windows specific). Open the file in text mode. The default is binary mode.
-</p>
-</dd>
-<dt><code>close(fd)</code></dt>
-<dd><p>Close the file handle <code>fd</code>.
-</p>
-</dd>
-<dt><code>seek(fd, offset, whence)</code></dt>
-<dd><p>Seek in the file. Use <code>std.SEEK_*</code> for
-<code>whence</code>. <code>offset</code> is either a number or a bigint. If
-<code>offset</code> is a bigint, a bigint is returned too.
-</p>
-</dd>
-<dt><code>read(fd, buffer, offset, length)</code></dt>
-<dd><p>Read <code>length</code> bytes from the file handle <code>fd</code> to the
-ArrayBuffer <code>buffer</code> at byte position <code>offset</code>.
-Return the number of read bytes or &lt; 0 if error.
-</p>
-</dd>
-<dt><code>write(fd, buffer, offset, length)</code></dt>
-<dd><p>Write <code>length</code> bytes to the file handle <code>fd</code> from the
-ArrayBuffer <code>buffer</code> at byte position <code>offset</code>.
-Return the number of written bytes or &lt; 0 if error.
-</p>
-</dd>
-<dt><code>isatty(fd)</code></dt>
-<dd><p>Return <code>true</code> is <code>fd</code> is a TTY (terminal) handle.
-</p>
-</dd>
-<dt><code>ttyGetWinSize(fd)</code></dt>
-<dd><p>Return the TTY size as <code>[width, height]</code> or <code>null</code> if not available.
-</p>
-</dd>
-<dt><code>ttySetRaw(fd)</code></dt>
-<dd><p>Set the TTY in raw mode.
-</p>
-</dd>
-<dt><code>remove(filename)</code></dt>
-<dd><p>Remove a file. Return 0 if OK or <code>-errno</code>.
-</p>
-</dd>
-<dt><code>rename(oldname, newname)</code></dt>
-<dd><p>Rename a file. Return 0 if OK or <code>-errno</code>.
-</p>
-</dd>
-<dt><code>realpath(path)</code></dt>
-<dd><p>Return <code>[str, err]</code> where <code>str</code> is the canonicalized absolute
-pathname of <code>path</code> and <code>err</code> the error code.
-</p>
-</dd>
-<dt><code>getcwd()</code></dt>
-<dd><p>Return <code>[str, err]</code> where <code>str</code> is the current working directory
-and <code>err</code> the error code.
-</p>
-</dd>
-<dt><code>chdir(path)</code></dt>
-<dd><p>Change the current directory. Return 0 if OK or <code>-errno</code>.
-</p>
-</dd>
-<dt><code>mkdir(path, mode = 0o777)</code></dt>
-<dd><p>Create a directory at <code>path</code>. Return 0 if OK or <code>-errno</code>.
-</p>
-</dd>
-<dt><code>stat(path)</code></dt>
-<dt><code>lstat(path)</code></dt>
-<dd>
-<p>Return <code>[obj, err]</code> where <code>obj</code> is an object containing the
-file status of <code>path</code>. <code>err</code> is the error code. The
-following fields are defined in <code>obj</code>: dev, ino, mode, nlink,
-uid, gid, rdev, size, blocks, atime, mtime, ctime. The times are
-specified in milliseconds since 1970. <code>lstat()</code> is the same as
-<code>stat()</code> excepts that it returns information about the link
-itself.
-</p>
-</dd>
-<dt><code>S_IFMT</code></dt>
-<dt><code>S_IFIFO</code></dt>
-<dt><code>S_IFCHR</code></dt>
-<dt><code>S_IFDIR</code></dt>
-<dt><code>S_IFBLK</code></dt>
-<dt><code>S_IFREG</code></dt>
-<dt><code>S_IFSOCK</code></dt>
-<dt><code>S_IFLNK</code></dt>
-<dt><code>S_ISGID</code></dt>
-<dt><code>S_ISUID</code></dt>
-<dd><p>Constants to interpret the <code>mode</code> property returned by
-<code>stat()</code>. They have the same value as in the C system header
-<samp>sys/stat.h</samp>.
-</p>
-</dd>
-<dt><code>utimes(path, atime, mtime)</code></dt>
-<dd><p>Change the access and modification times of the file <code>path</code>. The
-times are specified in milliseconds since 1970. Return 0 if OK or <code>-errno</code>.
-</p>
-</dd>
-<dt><code>symlink(target, linkpath)</code></dt>
-<dd><p>Create a link at <code>linkpath</code> containing the string <code>target</code>. Return 0 if OK or <code>-errno</code>.
-</p>
-</dd>
-<dt><code>readlink(path)</code></dt>
-<dd><p>Return <code>[str, err]</code> where <code>str</code> is the link target and <code>err</code>
-the error code.
-</p>
-</dd>
-<dt><code>readdir(path)</code></dt>
-<dd><p>Return <code>[array, err]</code> where <code>array</code> is an array of strings
-containing the filenames of the directory <code>path</code>. <code>err</code> is
-the error code.
-</p>
-</dd>
-<dt><code>setReadHandler(fd, func)</code></dt>
-<dd><p>Add a read handler to the file handle <code>fd</code>. <code>func</code> is called
-each time there is data pending for <code>fd</code>. A single read handler
-per file handle is supported. Use <code>func = null</code> to remove the
-handler.
-</p>
-</dd>
-<dt><code>setWriteHandler(fd, func)</code></dt>
-<dd><p>Add a write handler to the file handle <code>fd</code>. <code>func</code> is
-called each time data can be written to <code>fd</code>. A single write
-handler per file handle is supported. Use <code>func = null</code> to remove
-the handler.
-</p>
-</dd>
-<dt><code>signal(signal, func)</code></dt>
-<dd><p>Call the function <code>func</code> when the signal <code>signal</code>
-happens. Only a single handler per signal number is supported. Use
-<code>null</code> to set the default handler or <code>undefined</code> to ignore
-the signal. Signal handlers can only be defined in the main thread.
-</p>
-</dd>
-<dt><code>SIGINT</code></dt>
-<dt><code>SIGABRT</code></dt>
-<dt><code>SIGFPE</code></dt>
-<dt><code>SIGILL</code></dt>
-<dt><code>SIGSEGV</code></dt>
-<dt><code>SIGTERM</code></dt>
-<dd><p>POSIX signal numbers.
-</p>
-</dd>
-<dt><code>kill(pid, sig)</code></dt>
-<dd><p>Send the signal <code>sig</code> to the process <code>pid</code>.
-</p>
-</dd>
-<dt><code>exec(args[, options])</code></dt>
-<dd><p>Execute a process with the arguments <code>args</code>. <code>options</code> is an
-object containing optional parameters:
-</p>
-<dl compact="compact">
-<dt><code>block</code></dt>
-<dd><p>Boolean (default = true). If true, wait until the process is
- terminated. In this case, <code>exec</code> return the exit code if positive
- or the negated signal number if the process was interrupted by a
- signal. If false, do not block and return the process id of the child.
-</p>
-</dd>
-<dt><code>usePath</code></dt>
-<dd><p>Boolean (default = true). If true, the file is searched in the
- <code>PATH</code> environment variable.
-</p>
-</dd>
-<dt><code>file</code></dt>
-<dd><p>String (default = <code>args[0]</code>). Set the file to be executed.
-</p>
-</dd>
-<dt><code>cwd</code></dt>
-<dd><p>String. If present, set the working directory of the new process.
-</p>
-</dd>
-<dt><code>stdin</code></dt>
-<dt><code>stdout</code></dt>
-<dt><code>stderr</code></dt>
-<dd><p>If present, set the handle in the child for stdin, stdout or stderr.
-</p>
-</dd>
-<dt><code>env</code></dt>
-<dd><p>Object. If present, set the process environment from the object
- key-value pairs. Otherwise use the same environment as the current
- process.
-</p>
-</dd>
-<dt><code>uid</code></dt>
-<dd><p>Integer. If present, the process uid with <code>setuid</code>.
-</p>
-</dd>
-<dt><code>gid</code></dt>
-<dd><p>Integer. If present, the process gid with <code>setgid</code>.
-</p>
-</dd>
-</dl>
-
-</dd>
-<dt><code>waitpid(pid, options)</code></dt>
-<dd><p><code>waitpid</code> Unix system call. Return the array <code>[ret,
-status]</code>. <code>ret</code> contains <code>-errno</code> in case of error.
-</p>
-</dd>
-<dt><code>WNOHANG</code></dt>
-<dd><p>Constant for the <code>options</code> argument of <code>waitpid</code>.
-</p>
-</dd>
-<dt><code>dup(fd)</code></dt>
-<dd><p><code>dup</code> Unix system call.
-</p>
-</dd>
-<dt><code>dup2(oldfd, newfd)</code></dt>
-<dd><p><code>dup2</code> Unix system call.
-</p>
-</dd>
-<dt><code>pipe()</code></dt>
-<dd><p><code>pipe</code> Unix system call. Return two handles as <code>[read_fd,
-write_fd]</code> or null in case of error.
-</p>
-</dd>
-<dt><code>sleep(delay_ms)</code></dt>
-<dd><p>Sleep during <code>delay_ms</code> milliseconds.
-</p>
-</dd>
-<dt><code>setTimeout(func, delay)</code></dt>
-<dd><p>Call the function <code>func</code> after <code>delay</code> ms. Return a handle
-to the timer.
-</p>
-</dd>
-<dt><code>clearTimeout(handle)</code></dt>
-<dd><p>Cancel a timer.
-</p>
-</dd>
-<dt><code>platform</code></dt>
-<dd><p>Return a string representing the platform: <code>&quot;linux&quot;</code>, <code>&quot;darwin&quot;</code>,
-<code>&quot;win32&quot;</code> or <code>&quot;js&quot;</code>.
-</p>
-</dd>
-<dt><code>Worker(module_filename)</code></dt>
-<dd><p>Constructor to create a new thread (worker) with an API close to the
-<code>WebWorkers</code>. <code>module_filename</code> is a string specifying the
-module filename which is executed in the newly created thread. As for
-dynamically imported module, it is relative to the current script or
-module path. Threads normally don&rsquo;t share any data and communicate
-between each other with messages. Nested workers are not supported. An
-example is available in <samp>tests/test_worker.js</samp>.
-</p>
-<p>The worker class has the following static properties:
-</p>
-<dl compact="compact">
-<dt><code>parent</code></dt>
-<dd><p>In the created worker, <code>Worker.parent</code> represents the parent
- worker and is used to send or receive messages.
- </p></dd>
-</dl>
-
-<p>The worker instances have the following properties:
-</p>
-<dl compact="compact">
-<dt><code>postMessage(msg)</code></dt>
-<dd>
-<p>Send a message to the corresponding worker. <code>msg</code> is cloned in
- the destination worker using an algorithm similar to the <code>HTML</code>
- structured clone algorithm. <code>SharedArrayBuffer</code> are shared
- between workers.
-</p>
-<p>Current limitations: <code>Map</code> and <code>Set</code> are not supported
- yet.
-</p>
-</dd>
-<dt><code>onmessage</code></dt>
-<dd>
-<p>Getter and setter. Set a function which is called each time a
- message is received. The function is called with a single
- argument. It is an object with a <code>data</code> property containing the
- received message. The thread is not terminated if there is at least
- one non <code>null</code> <code>onmessage</code> handler.
-</p>
-</dd>
-</dl>
-
-</dd>
-</dl>
-
-<a name="QuickJS-C-API"></a>
-<h3 class="section">3.4 QuickJS C API</h3>
-
-<p>The C API was designed to be simple and efficient. The C API is
-defined in the header <code>quickjs.h</code>.
-</p>
-<a name="Runtime-and-contexts"></a>
-<h4 class="subsection">3.4.1 Runtime and contexts</h4>
-
-<p><code>JSRuntime</code> represents a Javascript runtime corresponding to an
-object heap. Several runtimes can exist at the same time but they
-cannot exchange objects. Inside a given runtime, no multi-threading is
-supported.
-</p>
-<p><code>JSContext</code> represents a Javascript context (or Realm). Each
-JSContext has its own global objects and system objects. There can be
-several JSContexts per JSRuntime and they can share objects, similar
-to frames of the same origin sharing Javascript objects in a
-web browser.
-</p>
-<a name="JSValue"></a>
-<h4 class="subsection">3.4.2 JSValue</h4>
-
-<p><code>JSValue</code> represents a Javascript value which can be a primitive
-type or an object. Reference counting is used, so it is important to
-explicitly duplicate (<code>JS_DupValue()</code>, increment the reference
-count) or free (<code>JS_FreeValue()</code>, decrement the reference count)
-JSValues.
-</p>
-<a name="C-functions"></a>
-<h4 class="subsection">3.4.3 C functions</h4>
-
-<p>C functions can be created with
-<code>JS_NewCFunction()</code>. <code>JS_SetPropertyFunctionList()</code> is a
-shortcut to easily add functions, setters and getters properties to a
-given object.
-</p>
-<p>Unlike other embedded Javascript engines, there is no implicit stack,
-so C functions get their parameters as normal C parameters. As a
-general rule, C functions take constant <code>JSValue</code>s as parameters
-(so they don&rsquo;t need to free them) and return a newly allocated (=live)
-<code>JSValue</code>.
-</p>
-<a name="Exceptions"></a>
-<h4 class="subsection">3.4.4 Exceptions</h4>
-
-<p>Exceptions: most C functions can return a Javascript exception. It
-must be explicitly tested and handled by the C code. The specific
-<code>JSValue</code> <code>JS_EXCEPTION</code> indicates that an exception
-occurred. The actual exception object is stored in the
-<code>JSContext</code> and can be retrieved with <code>JS_GetException()</code>.
-</p>
-<a name="Script-evaluation"></a>
-<h4 class="subsection">3.4.5 Script evaluation</h4>
-
-<p>Use <code>JS_Eval()</code> to evaluate a script or module source.
-</p>
-<p>If the script or module was compiled to bytecode with <code>qjsc</code>, it
-can be evaluated by calling <code>js_std_eval_binary()</code>. The advantage
-is that no compilation is needed so it is faster and smaller because
-the compiler can be removed from the executable if no <code>eval</code> is
-required.
-</p>
-<p>Note: the bytecode format is linked to a given QuickJS
-version. Moreover, no security check is done before its
-execution. Hence the bytecode should not be loaded from untrusted
-sources. That&rsquo;s why there is no option to output the bytecode to a
-binary file in <code>qjsc</code>.
-</p>
-<a name="JS-Classes"></a>
-<h4 class="subsection">3.4.6 JS Classes</h4>
-
-<p>C opaque data can be attached to a Javascript object. The type of the
-C opaque data is determined with the class ID (<code>JSClassID</code>) of
-the object. Hence the first step is to register a new class ID and JS
-class (<code>JS_NewClassID()</code>, <code>JS_NewClass()</code>). Then you can
-create objects of this class with <code>JS_NewObjectClass()</code> and get or
-set the C opaque point with
-<code>JS_GetOpaque()</code>/<code>JS_SetOpaque()</code>.
-</p>
-<p>When defining a new JS class, it is possible to declare a finalizer
-which is called when the object is destroyed. A <code>gc_mark</code> method
-can be provided so that the cycle removal algorithm can find the other
-objects referenced by this object. Other methods are available to
-define exotic object behaviors.
-</p>
-<p>The Class ID are globally allocated (i.e. for all runtimes). The
-JSClass are allocated per <code>JSRuntime</code>. <code>JS_SetClassProto()</code>
-is used to define a prototype for a given class in a given
-JSContext. <code>JS_NewObjectClass()</code> sets this prototype in the
-created object.
-</p>
-<p>Examples are available in <samp>quickjs-libc.c</samp>.
-</p>
-<a name="C-Modules"></a>
-<h4 class="subsection">3.4.7 C Modules</h4>
-
-<p>Native ES6 modules are supported and can be dynamically or statically
-linked. Look at the <samp>test_bjson</samp> and <samp>bjson.so</samp>
-examples. The standard library <samp>quickjs-libc.c</samp> is also a good example
-of a native module.
-</p>
-<a name="Memory-handling"></a>
-<h4 class="subsection">3.4.8 Memory handling</h4>
-
-<p>Use <code>JS_SetMemoryLimit()</code> to set a global memory allocation limit
-to a given JSRuntime.
-</p>
-<p>Custom memory allocation functions can be provided with
-<code>JS_NewRuntime2()</code>.
-</p>
-<p>The maximum system stack size can be set with <code>JS_SetMaxStackSize()</code>.
-</p>
-<a name="Execution-timeout-and-interrupts"></a>
-<h4 class="subsection">3.4.9 Execution timeout and interrupts</h4>
-
-<p>Use <code>JS_SetInterruptHandler()</code> to set a callback which is
-regularly called by the engine when it is executing code. This
-callback can be used to implement an execution timeout.
-</p>
-<p>It is used by the command line interpreter to implement a
-<code>Ctrl-C</code> handler.
-</p>
-<a name="Internals"></a>
-<h2 class="chapter">4 Internals</h2>
-
-<a name="Bytecode"></a>
-<h3 class="section">4.1 Bytecode</h3>
-
-<p>The compiler generates bytecode directly with no intermediate
-representation such as a parse tree, hence it is very fast. Several
-optimizations passes are done over the generated bytecode.
-</p>
-<p>A stack-based bytecode was chosen because it is simple and generates
-compact code.
-</p>
-<p>For each function, the maximum stack size is computed at compile time so that
-no runtime stack overflow tests are needed.
-</p>
-<p>A separate compressed line number table is maintained for the debug
-information.
-</p>
-<p>Access to closure variables is optimized and is almost as fast as local
-variables.
-</p>
-<p>Direct <code>eval</code> in strict mode is optimized.
-</p>
-<a name="Executable-generation"></a>
-<h3 class="section">4.2 Executable generation</h3>
-
-<a name="qjsc-compiler-1"></a>
-<h4 class="subsection">4.2.1 <code>qjsc</code> compiler</h4>
-
-<p>The <code>qjsc</code> compiler generates C sources from Javascript files. By
-default the C sources are compiled with the system compiler
-(<code>gcc</code> or <code>clang</code>).
-</p>
-<p>The generated C source contains the bytecode of the compiled functions
-or modules. If a full complete executable is needed, it also
-contains a <code>main()</code> function with the necessary C code to initialize the
-Javascript engine and to load and execute the compiled functions and
-modules.
-</p>
-<p>Javascript code can be mixed with C modules.
-</p>
-<p>In order to have smaller executables, specific Javascript features can
-be disabled, in particular <code>eval</code> or the regular expressions. The
-code removal relies on the Link Time Optimization of the system
-compiler.
-</p>
-<a name="Binary-JSON"></a>
-<h4 class="subsection">4.2.2 Binary JSON</h4>
-
-<p><code>qjsc</code> works by compiling scripts or modules and then serializing
-them to a binary format. A subset of this format (without functions or
-modules) can be used as binary JSON. The example <samp>test_bjson.js</samp>
-shows how to use it.
-</p>
-<p>Warning: the binary JSON format may change without notice, so it
-should not be used to store persistent data. The <samp>test_bjson.js</samp>
-example is only used to test the binary object format functions.
-</p>
-<a name="Runtime"></a>
-<h3 class="section">4.3 Runtime</h3>
-
-<a name="Strings"></a>
-<h4 class="subsection">4.3.1 Strings</h4>
-
-<p>Strings are stored either as an 8 bit or a 16 bit array of
-characters. Hence random access to characters is always fast.
-</p>
-<p>The C API provides functions to convert Javascript Strings to C UTF-8 encoded
-strings. The most common case where the Javascript string contains
-only ASCII characters involves no copying.
-</p>
-<a name="Objects"></a>
-<h4 class="subsection">4.3.2 Objects</h4>
-
-<p>The object shapes (object prototype, property names and flags) are shared
-between objects to save memory.
-</p>
-<p>Arrays with no holes (except at the end of the array) are optimized.
-</p>
-<p>TypedArray accesses are optimized.
-</p>
-<a name="Atoms"></a>
-<h4 class="subsection">4.3.3 Atoms</h4>
-
-<p>Object property names and some strings are stored as Atoms (unique
-strings) to save memory and allow fast comparison. Atoms are
-represented as a 32 bit integer. Half of the atom range is reserved for
-immediate integer literals from <em>0</em> to <em>2^{31}-1</em>.
-</p>
-<a name="Numbers"></a>
-<h4 class="subsection">4.3.4 Numbers</h4>
-
-<p>Numbers are represented either as 32-bit signed integers or 64-bit IEEE-754
-floating point values. Most operations have fast paths for the 32-bit
-integer case.
-</p>
-<a name="Garbage-collection"></a>
-<h4 class="subsection">4.3.5 Garbage collection</h4>
-
-<p>Reference counting is used to free objects automatically and
-deterministically. A separate cycle removal pass is done when the allocated
-memory becomes too large. The cycle removal algorithm only uses the
-reference counts and the object content, so no explicit garbage
-collection roots need to be manipulated in the C code.
-</p>
-<a name="JSValue-1"></a>
-<h4 class="subsection">4.3.6 JSValue</h4>
-
-<p>It is a Javascript value which can be a primitive type (such as
-Number, String, ...) or an Object. NaN boxing is used in the 32-bit version
-to store 64-bit floating point numbers. The representation is
-optimized so that 32-bit integers and reference counted values can be
-efficiently tested.
-</p>
-<p>In 64-bit code, JSValue are 128-bit large and no NaN boxing is used. The
-rationale is that in 64-bit code memory usage is less critical.
-</p>
-<p>In both cases (32 or 64 bits), JSValue exactly fits two CPU registers,
-so it can be efficiently returned by C functions.
-</p>
-<a name="Function-call"></a>
-<h4 class="subsection">4.3.7 Function call</h4>
-
-<p>The engine is optimized so that function calls are fast. The system
-stack holds the Javascript parameters and local variables.
-</p>
-<a name="RegExp"></a>
-<h3 class="section">4.4 RegExp</h3>
-
-<p>A specific regular expression engine was developed. It is both small
-and efficient and supports all the ES2020 features including the
-Unicode properties. As the Javascript compiler, it directly generates
-bytecode without a parse tree.
-</p>
-<p>Backtracking with an explicit stack is used so that there is no
-recursion on the system stack. Simple quantifiers are specifically
-optimized to avoid recursions.
-</p>
-<p>Infinite recursions coming from quantifiers with empty terms are
-avoided.
-</p>
-<p>The full regexp library weights about 15 KiB (x86 code), excluding the
-Unicode library.
-</p>
-<a name="Unicode"></a>
-<h3 class="section">4.5 Unicode</h3>
-
-<p>A specific Unicode library was developed so that there is no
-dependency on an external large Unicode library such as ICU. All the
-Unicode tables are compressed while keeping a reasonable access
-speed.
-</p>
-<p>The library supports case conversion, Unicode normalization, Unicode
-script queries, Unicode general category queries and all Unicode
-binary properties.
-</p>
-<p>The full Unicode library weights about 45 KiB (x86 code).
-</p>
-<a name="BigInt_002c-BigFloat_002c-BigDecimal"></a>
-<h3 class="section">4.6 BigInt, BigFloat, BigDecimal</h3>
-
-<p>BigInt, BigFloat and BigDecimal are implemented with the <code>libbf</code>
-library<a name="DOCF7" href="#FOOT7"><sup>7</sup></a>. It weights about 90
-KiB (x86 code) and provides arbitrary precision IEEE 754 floating
-point operations and transcendental functions with exact rounding.
-</p>
-<a name="License"></a>
-<h2 class="chapter">5 License</h2>
-
-<p>QuickJS is released under the MIT license.
-</p>
-<p>Unless otherwise specified, the QuickJS sources are copyright Fabrice
-Bellard and Charlie Gordon.
-</p>
-<div class="footnote">
-<hr>
-<h4 class="footnotes-heading">Footnotes</h4>
-
-<h3><a name="FOOT1" href="#DOCF1">(1)</a></h3>
-<p><a href="https://tc39.es/ecma262/">https://tc39.es/ecma262/</a></p>
-<h3><a name="FOOT2" href="#DOCF2">(2)</a></h3>
-<p><a href="https://github.com/tc39/test262">https://github.com/tc39/test262</a></p>
-<h3><a name="FOOT3" href="#DOCF3">(3)</a></h3>
-<p><a href="https://tc39.github.io/ecma262/">https://tc39.github.io/ecma262/</a></p>
-<h3><a name="FOOT4" href="#DOCF4">(4)</a></h3>
-<p>The old
-ES5.1 tests can be extracted with <code>git clone --single-branch
---branch es5-tests https://github.com/tc39/test262.git test262o</code></p>
-<h3><a name="FOOT5" href="#DOCF5">(5)</a></h3>
-<p><a href="https://github.com/bterlson/test262-harness">https://github.com/bterlson/test262-harness</a></p>
-<h3><a name="FOOT6" href="#DOCF6">(6)</a></h3>
-<p>We believe the current specification of tails calls is too complicated and presents limited practical interests.</p>
-<h3><a name="FOOT7" href="#DOCF7">(7)</a></h3>
-<p><a href="https://bellard.org/libbf">https://bellard.org/libbf</a></p>
-</div>
-<hr>
-
-
-
-</body>
-</html>
diff --git a/doc/quickjs.pdf b/doc/quickjs.pdf
deleted file mode 100644
index 497964b..0000000
--- a/doc/quickjs.pdf
+++ /dev/null
Binary files differ
diff --git a/doc/quickjs.texi b/doc/quickjs.texi
index 57d13e6..40c0bb5 100644
--- a/doc/quickjs.texi
+++ b/doc/quickjs.texi
@@ -452,6 +452,16 @@ useful in case of specific memory constraints or for testing.
Return the value of the environment variable @code{name} or
@code{undefined} if it is not defined.
+@item setenv(name, value)
+Set the value of the environment variable @code{name} to the string
+@code{value}.
+
+@item unsetenv(name)
+Delete the environment variable @code{name}.
+
+@item getenviron()
+Return an object containing the environment variables as key-value pairs.
+
@item urlGet(url, options = undefined)
Download @code{url} using the @file{curl} command line
@@ -532,7 +542,7 @@ position @code{position} (wrapper to the libc @code{fread}).
@item write(buffer, position, length)
Write @code{length} bytes to the file from the ArrayBuffer @code{buffer} at byte
-position @code{position} (wrapper to the libc @code{fread}).
+position @code{position} (wrapper to the libc @code{fwrite}).
@item getline()
Return the next line from the file, assuming UTF-8 encoding, excluding
diff --git a/jscompress.c b/jscompress.c
deleted file mode 100644
index a68c0e8..0000000
--- a/jscompress.c
+++ /dev/null
@@ -1,918 +0,0 @@
-/*
- * Javascript Compressor
- *
- * Copyright (c) 2008-2018 Fabrice Bellard
- * Copyright (c) 2017-2018 Charlie Gordon
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include <stdlib.h>
-#include <stdio.h>
-#include <getopt.h>
-#include <stdarg.h>
-#include <string.h>
-#include <inttypes.h>
-#include <unistd.h>
-
-#include "cutils.h"
-
-typedef struct JSToken {
- int tok;
- char buf[20];
- char *str;
- int len;
- int size;
- int line_num; /* line number for start of token */
- int lines; /* number of embedded linefeeds in token */
-} JSToken;
-
-enum {
- TOK_EOF = 256,
- TOK_IDENT,
- TOK_STR1,
- TOK_STR2,
- TOK_STR3,
- TOK_NUM,
- TOK_COM,
- TOK_LCOM,
-};
-
-void tok_reset(JSToken *tt)
-{
- if (tt->str != tt->buf) {
- free(tt->str);
- tt->str = tt->buf;
- tt->size = sizeof(tt->buf);
- }
- tt->len = 0;
-}
-
-void tok_add_ch(JSToken *tt, int c)
-{
- if (tt->len + 1 > tt->size) {
- tt->size *= 2;
- if (tt->str == tt->buf) {
- tt->str = malloc(tt->size);
- memcpy(tt->str, tt->buf, tt->len);
- } else {
- tt->str = realloc(tt->str, tt->size);
- }
- }
- tt->str[tt->len++] = c;
-}
-
-FILE *infile;
-const char *filename;
-int output_line_num;
-int line_num;
-int ch;
-JSToken tokc;
-
-int skip_mask;
-#define DEFINE_MAX 20
-char *define_tab[DEFINE_MAX];
-int define_len;
-
-void error(const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- if (filename) {
- fprintf(stderr, "%s:%d: ", filename, line_num);
- } else {
- fprintf(stderr, "jscompress: ");
- }
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n");
- va_end(ap);
- exit(1);
-}
-
-void define_symbol(const char *def)
-{
- int i;
- for (i = 0; i < define_len; i++) {
- if (!strcmp(tokc.str, define_tab[i]))
- return;
- }
- if (define_len >= DEFINE_MAX)
- error("too many defines");
- define_tab[define_len++] = strdup(def);
-}
-
-void undefine_symbol(const char *def)
-{
- int i, j;
- for (i = j = 0; i < define_len; i++) {
- if (!strcmp(tokc.str, define_tab[i])) {
- free(define_tab[i]);
- } else {
- define_tab[j++] = define_tab[i];
- }
- }
- define_len = j;
-}
-
-const char *find_symbol(const char *def)
-{
- int i;
- for (i = 0; i < define_len; i++) {
- if (!strcmp(tokc.str, define_tab[i]))
- return "1";
- }
- return NULL;
-}
-
-void next(void);
-
-void nextch(void)
-{
- ch = fgetc(infile);
- if (ch == '\n')
- line_num++;
-}
-
-int skip_blanks(void)
-{
- for (;;) {
- next();
- if (tokc.tok != ' ' && tokc.tok != '\t' &&
- tokc.tok != TOK_COM && tokc.tok != TOK_LCOM)
- return tokc.tok;
- }
-}
-
-void parse_directive(void)
-{
- int ifdef, mask = skip_mask;
- /* simplistic preprocessor:
- #define / #undef / #ifdef / #ifndef / #else / #endif
- no symbol substitution.
- */
- skip_mask = 0; /* disable skipping to parse preprocessor line */
- nextch();
- if (skip_blanks() != TOK_IDENT)
- error("expected preprocessing directive after #");
-
- if (!strcmp(tokc.str, "define")) {
- if (skip_blanks() != TOK_IDENT)
- error("expected identifier after #define");
- define_symbol(tokc.str);
- } else if (!strcmp(tokc.str, "undef")) {
- if (skip_blanks() != TOK_IDENT)
- error("expected identifier after #undef");
- undefine_symbol(tokc.str);
- } else if ((ifdef = 1, !strcmp(tokc.str, "ifdef")) ||
- (ifdef = 0, !strcmp(tokc.str, "ifndef"))) {
- if (skip_blanks() != TOK_IDENT)
- error("expected identifier after #ifdef/#ifndef");
- mask = (mask << 2) | 2 | ifdef;
- if (find_symbol(tokc.str))
- mask ^= 1;
- } else if (!strcmp(tokc.str, "else")) {
- if (!(mask & 2))
- error("#else without a #if");
- mask ^= 1;
- } else if (!strcmp(tokc.str, "endif")) {
- if (!(mask & 2))
- error("#endif without a #if");
- mask >>= 2;
- } else {
- error("unsupported preprocessing directive");
- }
- if (skip_blanks() != '\n')
- error("extra characters on preprocessing line");
- skip_mask = mask;
-}
-
-/* return -1 if invalid char */
-static int hex_to_num(int ch)
-{
- if (ch >= 'a' && ch <= 'f')
- return ch - 'a' + 10;
- else if (ch >= 'A' && ch <= 'F')
- return ch - 'A' + 10;
- else if (ch >= '0' && ch <= '9')
- return ch - '0';
- else
- return -1;
-}
-
-void next(void)
-{
-again:
- tok_reset(&tokc);
- tokc.line_num = line_num;
- tokc.lines = 0;
- switch(ch) {
- case EOF:
- tokc.tok = TOK_EOF;
- if (skip_mask)
- error("missing #endif");
- break;
- case 'a' ... 'z':
- case 'A' ... 'Z':
- case '_':
- case '$':
- tok_add_ch(&tokc, ch);
- nextch();
- while ((ch >= 'a' && ch <= 'z') ||
- (ch >= 'A' && ch <= 'Z') ||
- (ch >= '0' && ch <= '9') ||
- (ch == '_' || ch == '$')) {
- tok_add_ch(&tokc, ch);
- nextch();
- }
- tok_add_ch(&tokc, '\0');
- tokc.tok = TOK_IDENT;
- break;
- case '.':
- nextch();
- if (ch >= '0' && ch <= '9') {
- tok_add_ch(&tokc, '.');
- goto has_dot;
- }
- tokc.tok = '.';
- break;
- case '0':
- tok_add_ch(&tokc, ch);
- nextch();
- if (ch == 'x' || ch == 'X') {
- /* hexa */
- tok_add_ch(&tokc, ch);
- nextch();
- while ((ch >= 'a' && ch <= 'f') ||
- (ch >= 'A' && ch <= 'F') ||
- (ch >= '0' && ch <= '9')) {
- tok_add_ch(&tokc, ch);
- nextch();
- }
- tok_add_ch(&tokc, '\0');
- tokc.tok = TOK_NUM;
- break;
- }
- goto has_digit;
-
- case '1' ... '9':
- tok_add_ch(&tokc, ch);
- nextch();
- has_digit:
- /* decimal */
- while (ch >= '0' && ch <= '9') {
- tok_add_ch(&tokc, ch);
- nextch();
- }
- if (ch == '.') {
- tok_add_ch(&tokc, ch);
- nextch();
- has_dot:
- while (ch >= '0' && ch <= '9') {
- tok_add_ch(&tokc, ch);
- nextch();
- }
- }
- if (ch == 'e' || ch == 'E') {
- tok_add_ch(&tokc, ch);
- nextch();
- if (ch == '+' || ch == '-') {
- tok_add_ch(&tokc, ch);
- nextch();
- }
- while (ch >= '0' && ch <= '9') {
- tok_add_ch(&tokc, ch);
- nextch();
- }
- }
- tok_add_ch(&tokc, '\0');
- tokc.tok = TOK_NUM;
- break;
- case '`':
- {
- nextch();
- while (ch != '`' && ch != EOF) {
- if (ch == '\\') {
- tok_add_ch(&tokc, ch);
- nextch();
- if (ch == EOF) {
- error("unexpected char after '\\'");
- }
- tok_add_ch(&tokc, ch);
- } else {
- tok_add_ch(&tokc, ch);
- nextch();
- }
- }
- nextch();
- tok_add_ch(&tokc, 0);
- tokc.tok = TOK_STR3;
- }
- break;
- case '\"':
- case '\'':
- {
- int n, i, c, hex_digit_count;
- int quote_ch;
- quote_ch = ch;
- nextch();
- while (ch != quote_ch && ch != EOF) {
- if (ch == '\\') {
- nextch();
- switch(ch) {
- case 'n':
- tok_add_ch(&tokc, '\n');
- nextch();
- break;
- case 'r':
- tok_add_ch(&tokc, '\r');
- nextch();
- break;
- case 't':
- tok_add_ch(&tokc, '\t');
- nextch();
- break;
- case 'v':
- tok_add_ch(&tokc, '\v');
- nextch();
- break;
- case '\"':
- case '\'':
- case '\\':
- tok_add_ch(&tokc, ch);
- nextch();
- break;
- case '0' ... '7':
- n = 0;
- while (ch >= '0' && ch <= '7') {
- n = n * 8 + (ch - '0');
- nextch();
- }
- tok_add_ch(&tokc, n);
- break;
- case 'x':
- case 'u':
- if (ch == 'x')
- hex_digit_count = 2;
- else
- hex_digit_count = 4;
- nextch();
- n = 0;
- for(i = 0; i < hex_digit_count; i++) {
- c = hex_to_num(ch);
- if (c < 0)
- error("unexpected char after '\\x'");
- n = n * 16 + c;
- nextch();
- }
- if (n >= 256)
- error("unicode is currently unsupported");
- tok_add_ch(&tokc, n);
- break;
-
- default:
- error("unexpected char after '\\'");
- }
- } else {
- /* XXX: should refuse embedded newlines */
- tok_add_ch(&tokc, ch);
- nextch();
- }
- }
- nextch();
- tok_add_ch(&tokc, 0);
- if (quote_ch == '\'')
- tokc.tok = TOK_STR1;
- else
- tokc.tok = TOK_STR2;
- }
- break;
- case '/':
- nextch();
- if (ch == '/') {
- tok_add_ch(&tokc, '/');
- tok_add_ch(&tokc, ch);
- nextch();
- while (ch != '\n' && ch != EOF) {
- tok_add_ch(&tokc, ch);
- nextch();
- }
- tok_add_ch(&tokc, '\0');
- tokc.tok = TOK_LCOM;
- } else if (ch == '*') {
- int last;
- tok_add_ch(&tokc, '/');
- tok_add_ch(&tokc, ch);
- last = 0;
- for(;;) {
- nextch();
- if (ch == EOF)
- error("unterminated comment");
- if (ch == '\n')
- tokc.lines++;
- tok_add_ch(&tokc, ch);
- if (last == '*' && ch == '/')
- break;
- last = ch;
- }
- nextch();
- tok_add_ch(&tokc, '\0');
- tokc.tok = TOK_COM;
- } else {
- tokc.tok = '/';
- }
- break;
- case '#':
- parse_directive();
- goto again;
- case '\n':
- /* adjust line number */
- tokc.line_num--;
- tokc.lines++;
- /* fall thru */
- default:
- tokc.tok = ch;
- nextch();
- break;
- }
- if (skip_mask & 1)
- goto again;
-}
-
-void print_tok(FILE *f, JSToken *tt)
-{
- /* keep output lines in sync with input lines */
- while (output_line_num < tt->line_num) {
- putc('\n', f);
- output_line_num++;
- }
-
- switch(tt->tok) {
- case TOK_IDENT:
- case TOK_COM:
- case TOK_LCOM:
- fprintf(f, "%s", tt->str);
- break;
- case TOK_NUM:
- {
- unsigned long a;
- char *p;
- a = strtoul(tt->str, &p, 0);
- if (*p == '\0' && a <= 0x7fffffff) {
- /* must be an integer */
- fprintf(f, "%d", (int)a);
- } else {
- fprintf(f, "%s", tt->str);
- }
- }
- break;
- case TOK_STR3:
- fprintf(f, "`%s`", tt->str);
- break;
- case TOK_STR1:
- case TOK_STR2:
- {
- int i, c, quote_ch;
- if (tt->tok == TOK_STR1)
- quote_ch = '\'';
- else
- quote_ch = '\"';
- fprintf(f, "%c", quote_ch);
- for(i = 0; i < tt->len - 1; i++) {
- c = (uint8_t)tt->str[i];
- switch(c) {
- case '\r':
- fprintf(f, "\\r");
- break;
- case '\n':
- fprintf(f, "\\n");
- break;
- case '\t':
- fprintf(f, "\\t");
- break;
- case '\v':
- fprintf(f, "\\v");
- break;
- case '\"':
- case '\'':
- if (c == quote_ch)
- fprintf(f, "\\%c", c);
- else
- fprintf(f, "%c", c);
- break;
- case '\\':
- fprintf(f, "\\\\");
- break;
- default:
- /* XXX: no utf-8 support! */
- if (c >= 32 && c <= 255) {
- fprintf(f, "%c", c);
- } else if (c <= 255)
- fprintf(f, "\\x%02x", c);
- else
- fprintf(f, "\\u%04x", c);
- break;
- }
- }
- fprintf(f, "%c", quote_ch);
- }
- break;
- default:
- if (tokc.tok >= 256)
- error("unsupported token in print_tok: %d", tt->tok);
- fprintf(f, "%c", tt->tok);
- break;
- }
- output_line_num += tt->lines;
-}
-
-/* check if token pasting could occur */
-static BOOL compat_token(int c1, int c2)
-{
- if ((c1 == TOK_IDENT || c1 == TOK_NUM) &&
- (c2 == TOK_IDENT || c2 == TOK_NUM))
- return FALSE;
-
- if ((c1 == c2 && strchr("+-<>&|=*/.", c1))
- || (c2 == '=' && strchr("+-<>&|!*/^%", c1))
- || (c1 == '=' && c2 == '>')
- || (c1 == '/' && c2 == '*')
- || (c1 == '.' && c2 == TOK_NUM)
- || (c1 == TOK_NUM && c2 == '.'))
- return FALSE;
-
- return TRUE;
-}
-
-void js_compress(const char *filename, const char *outfilename,
- BOOL do_strip, BOOL keep_header)
-{
- FILE *outfile;
- int ltok, seen_space;
-
- line_num = 1;
- infile = fopen(filename, "rb");
- if (!infile) {
- perror(filename);
- exit(1);
- }
-
- output_line_num = 1;
- outfile = fopen(outfilename, "wb");
- if (!outfile) {
- perror(outfilename);
- exit(1);
- }
-
- nextch();
- next();
- ltok = 0;
- seen_space = 0;
- if (do_strip) {
- if (keep_header) {
- while (tokc.tok == ' ' ||
- tokc.tok == '\n' ||
- tokc.tok == '\t' ||
- tokc.tok == '\v' ||
- tokc.tok == '\b' ||
- tokc.tok == '\f') {
- seen_space = 1;
- next();
- }
- if (tokc.tok == TOK_COM) {
- print_tok(outfile, &tokc);
- //fprintf(outfile, "\n");
- ltok = tokc.tok;
- seen_space = 0;
- next();
- }
- }
-
- for(;;) {
- if (tokc.tok == TOK_EOF)
- break;
- if (tokc.tok == ' ' ||
- tokc.tok == '\r' ||
- tokc.tok == '\t' ||
- tokc.tok == '\v' ||
- tokc.tok == '\b' ||
- tokc.tok == '\f' ||
- tokc.tok == TOK_LCOM ||
- tokc.tok == TOK_COM) {
- /* don't print spaces or comments */
- seen_space = 1;
- } else if (tokc.tok == TOK_STR3) {
- print_tok(outfile, &tokc);
- ltok = tokc.tok;
- seen_space = 0;
- } else if (tokc.tok == TOK_STR1 || tokc.tok == TOK_STR2) {
- int count, i;
- /* find the optimal quote char */
- count = 0;
- for(i = 0; i < tokc.len; i++) {
- if (tokc.str[i] == '\'')
- count++;
- else if (tokc.str[i] == '\"')
- count--;
- }
- if (count > 0)
- tokc.tok = TOK_STR2;
- else if (count < 0)
- tokc.tok = TOK_STR1;
- print_tok(outfile, &tokc);
- ltok = tokc.tok;
- seen_space = 0;
- } else {
- if (seen_space && !compat_token(ltok, tokc.tok)) {
- fprintf(outfile, " ");
- }
- print_tok(outfile, &tokc);
- ltok = tokc.tok;
- seen_space = 0;
- }
- next();
- }
- } else {
- /* just handle preprocessing */
- while (tokc.tok != TOK_EOF) {
- print_tok(outfile, &tokc);
- next();
- }
- }
-
- fclose(outfile);
- fclose(infile);
-}
-
-#define HASH_SIZE 30011
-#define MATCH_LEN_MIN 3
-#define MATCH_LEN_MAX (4 + 63)
-#define DIST_MAX 65535
-
-static int find_longest_match(int *pdist, const uint8_t *src, int src_len,
- const int *hash_next, int cur_pos)
-{
- int pos, i, match_len, match_pos, pos_min, len_max;
-
- len_max = min_int(src_len - cur_pos, MATCH_LEN_MAX);
- match_len = 0;
- match_pos = 0;
- pos_min = max_int(cur_pos - DIST_MAX - 1, 0);
- pos = hash_next[cur_pos];
- while (pos >= pos_min) {
- for(i = 0; i < len_max; i++) {
- if (src[cur_pos + i] != src[pos + i])
- break;
- }
- if (i > match_len) {
- match_len = i;
- match_pos = pos;
- }
- pos = hash_next[pos];
- }
- *pdist = cur_pos - match_pos - 1;
- return match_len;
-}
-
-int lz_compress(uint8_t **pdst, const uint8_t *src, int src_len)
-{
- int *hash_table, *hash_next;
- uint32_t h, v;
- int i, dist, len, len1, dist1;
- uint8_t *dst, *q;
-
- /* build the hash table */
-
- hash_table = malloc(sizeof(hash_table[0]) * HASH_SIZE);
- for(i = 0; i < HASH_SIZE; i++)
- hash_table[i] = -1;
- hash_next = malloc(sizeof(hash_next[0]) * src_len);
- for(i = 0; i < src_len; i++)
- hash_next[i] = -1;
-
- for(i = 0; i < src_len - MATCH_LEN_MIN + 1; i++) {
- h = ((src[i] << 16) | (src[i + 1] << 8) | src[i + 2]) % HASH_SIZE;
- hash_next[i] = hash_table[h];
- hash_table[h] = i;
- }
- for(;i < src_len; i++) {
- hash_next[i] = -1;
- }
- free(hash_table);
-
- dst = malloc(src_len + 4); /* never larger than the source */
- q = dst;
- *q++ = src_len >> 24;
- *q++ = src_len >> 16;
- *q++ = src_len >> 8;
- *q++ = src_len >> 0;
- /* compress */
- i = 0;
- while (i < src_len) {
- if (src[i] >= 128)
- return -1;
- len = find_longest_match(&dist, src, src_len, hash_next, i);
- if (len >= MATCH_LEN_MIN) {
- /* heuristic: see if better length just after */
- len1 = find_longest_match(&dist1, src, src_len, hash_next, i + 1);
- if (len1 > len)
- goto no_match;
- }
- if (len < MATCH_LEN_MIN) {
- no_match:
- *q++ = src[i];
- i++;
- } else if (len <= (3 + 15) && dist < (1 << 10)) {
- v = 0x8000 | ((len - 3) << 10) | dist;
- *q++ = v >> 8;
- *q++ = v;
- i += len;
- } else if (len >= 4 && len <= (4 + 63) && dist < (1 << 16)) {
- v = 0xc00000 | ((len - 4) << 16) | dist;
- *q++ = v >> 16;
- *q++ = v >> 8;
- *q++ = v;
- i += len;
- } else {
- goto no_match;
- }
- }
- free(hash_next);
- *pdst = dst;
- return q - dst;
-}
-
-static int load_file(uint8_t **pbuf, const char *filename)
-{
- FILE *f;
- uint8_t *buf;
- int buf_len;
-
- f = fopen(filename, "rb");
- if (!f) {
- perror(filename);
- exit(1);
- }
- fseek(f, 0, SEEK_END);
- buf_len = ftell(f);
- fseek(f, 0, SEEK_SET);
- buf = malloc(buf_len + 1);
- fread(buf, 1, buf_len, f);
- buf[buf_len] = '\0';
- fclose(f);
- *pbuf = buf;
- return buf_len;
-}
-
-static void save_file(const char *filename, const uint8_t *buf, int buf_len)
-{
- FILE *f;
-
- f = fopen(filename, "wb");
- if (!f) {
- perror(filename);
- exit(1);
- }
- fwrite(buf, 1, buf_len, f);
- fclose(f);
-}
-
-static void save_c_source(const char *filename, const uint8_t *buf, int buf_len,
- const char *var_name)
-{
- FILE *f;
- int i;
-
- f = fopen(filename, "wb");
- if (!f) {
- perror(filename);
- exit(1);
- }
- fprintf(f, "/* This file is automatically generated - do not edit */\n\n");
- fprintf(f, "const uint8_t %s[] = {\n", var_name);
- for(i = 0; i < buf_len; i++) {
- fprintf(f, " 0x%02x,", buf[i]);
- if ((i % 8) == 7 || (i == buf_len - 1))
- fprintf(f, "\n");
- }
- fprintf(f, "};\n");
- fclose(f);
-}
-
-#define DEFAULT_OUTPUT_FILENAME "out.js"
-
-void help(void)
-{
- printf("jscompress version 1.0 Copyright (c) 2008-2018 Fabrice Bellard\n"
- "usage: jscompress [options] filename\n"
- "Javascript compressor\n"
- "\n"
- "-h print this help\n"
- "-n do not compress spaces\n"
- "-H keep the first comment\n"
- "-c compress to file\n"
- "-C name compress to C source ('name' is the variable name)\n"
- "-D symbol define preprocessor symbol\n"
- "-U symbol undefine preprocessor symbol\n"
- "-o outfile set the output filename (default=%s)\n",
- DEFAULT_OUTPUT_FILENAME);
- exit(1);
-}
-
-int main(int argc, char **argv)
-{
- int c, do_strip, keep_header, compress;
- const char *out_filename, *c_var, *fname;
- char tmpfilename[1024];
-
- do_strip = 1;
- keep_header = 0;
- out_filename = DEFAULT_OUTPUT_FILENAME;
- compress = 0;
- c_var = NULL;
- for(;;) {
- c = getopt(argc, argv, "hno:HcC:D:U:");
- if (c == -1)
- break;
- switch(c) {
- case 'h':
- help();
- break;
- case 'n':
- do_strip = 0;
- break;
- case 'o':
- out_filename = optarg;
- break;
- case 'H':
- keep_header = 1;
- break;
- case 'c':
- compress = 1;
- break;
- case 'C':
- c_var = optarg;
- compress = 1;
- break;
- case 'D':
- define_symbol(optarg);
- break;
- case 'U':
- undefine_symbol(optarg);
- break;
- }
- }
- if (optind >= argc)
- help();
-
- filename = argv[optind++];
-
- if (compress) {
-#if defined(__ANDROID__)
- /* XXX: use another directory ? */
- snprintf(tmpfilename, sizeof(tmpfilename), "out.%d", getpid());
-#else
- snprintf(tmpfilename, sizeof(tmpfilename), "/tmp/out.%d", getpid());
-#endif
- fname = tmpfilename;
- } else {
- fname = out_filename;
- }
- js_compress(filename, fname, do_strip, keep_header);
-
- if (compress) {
- uint8_t *buf1, *buf2;
- int buf1_len, buf2_len;
-
- buf1_len = load_file(&buf1, fname);
- unlink(fname);
- buf2_len = lz_compress(&buf2, buf1, buf1_len);
- if (buf2_len < 0) {
- fprintf(stderr, "Could not compress file (UTF8 chars are forbidden)\n");
- exit(1);
- }
-
- if (c_var) {
- save_c_source(out_filename, buf2, buf2_len, c_var);
- } else {
- save_file(out_filename, buf2, buf2_len);
- }
- free(buf1);
- free(buf2);
- }
- return 0;
-}
diff --git a/libbf.h b/libbf.h
index 6749b35..4576bf8 100644
--- a/libbf.h
+++ b/libbf.h
@@ -27,7 +27,7 @@
#include <stddef.h>
#include <stdint.h>
-#if defined(__x86_64__)
+#if INTPTR_MAX >= INT64_MAX
#define LIMB_LOG2_BITS 6
#else
#define LIMB_LOG2_BITS 5
diff --git a/libregexp.c b/libregexp.c
index bbb5e9d..379bfc7 100644
--- a/libregexp.c
+++ b/libregexp.c
@@ -75,7 +75,7 @@ typedef struct {
int capture_count;
int total_capture_count; /* -1 = not computed yet */
int has_named_captures; /* -1 = don't know, 0 = no, 1 = yes */
- void *mem_opaque;
+ void *opaque;
DynBuf group_names;
union {
char error_msg[TMP_BUF_SIZE];
@@ -230,7 +230,7 @@ static int cr_init_char_range(REParseState *s, CharRange *cr, uint32_t c)
invert = c & 1;
c_pt = char_range_table[c >> 1];
len = *c_pt++;
- cr_init(cr, s->mem_opaque, lre_realloc);
+ cr_init(cr, s->opaque, lre_realloc);
for(i = 0; i < len * 2; i++) {
if (cr_add_point(cr, c_pt[i]))
goto fail;
@@ -625,7 +625,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr,
p++;
q = name;
while (is_unicode_char(*p)) {
- if ((q - name) > sizeof(name) - 1)
+ if ((q - name) >= sizeof(name) - 1)
goto unknown_property_name;
*q++ = *p++;
}
@@ -634,7 +634,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr,
if (*p == '=') {
p++;
while (is_unicode_char(*p)) {
- if ((q - value) > sizeof(value) - 1)
+ if ((q - value) >= sizeof(value) - 1)
return re_parse_error(s, "unknown unicode property value");
*q++ = *p++;
}
@@ -651,7 +651,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr,
} else if (!strcmp(name, "Script_Extensions") || !strcmp(name, "scx")) {
script_ext = TRUE;
do_script:
- cr_init(cr, s->mem_opaque, lre_realloc);
+ cr_init(cr, s->opaque, lre_realloc);
ret = unicode_script(cr, value, script_ext);
if (ret) {
cr_free(cr);
@@ -661,7 +661,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr,
goto out_of_memory;
}
} else if (!strcmp(name, "General_Category") || !strcmp(name, "gc")) {
- cr_init(cr, s->mem_opaque, lre_realloc);
+ cr_init(cr, s->opaque, lre_realloc);
ret = unicode_general_category(cr, value);
if (ret) {
cr_free(cr);
@@ -671,7 +671,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr,
goto out_of_memory;
}
} else if (value[0] == '\0') {
- cr_init(cr, s->mem_opaque, lre_realloc);
+ cr_init(cr, s->opaque, lre_realloc);
ret = unicode_general_category(cr, name);
if (ret == -1) {
cr_free(cr);
@@ -864,7 +864,7 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp)
CharRange cr1_s, *cr1 = &cr1_s;
BOOL invert;
- cr_init(cr, s->mem_opaque, lre_realloc);
+ cr_init(cr, s->opaque, lre_realloc);
p = *pp;
p++; /* skip '[' */
invert = FALSE;
@@ -1147,9 +1147,13 @@ static int re_parse_captures(REParseState *s, int *phas_named_captures,
}
}
capture_index++;
+ if (capture_index >= CAPTURE_COUNT_MAX)
+ goto done;
}
} else {
capture_index++;
+ if (capture_index >= CAPTURE_COUNT_MAX)
+ goto done;
}
break;
case '\\':
@@ -1163,6 +1167,7 @@ static int re_parse_captures(REParseState *s, int *phas_named_captures,
break;
}
}
+ done:
if (capture_name)
return -1;
else
@@ -1734,6 +1739,9 @@ static int re_parse_disjunction(REParseState *s, BOOL is_backward_dir)
{
int start, len, pos;
+ if (lre_check_stack_overflow(s->opaque, 0))
+ return re_parse_error(s, "stack overflow");
+
start = s->byte_code.size;
if (re_parse_alternative(s, is_backward_dir))
return -1;
@@ -1819,7 +1827,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
BOOL is_sticky;
memset(s, 0, sizeof(*s));
- s->mem_opaque = opaque;
+ s->opaque = opaque;
s->buf_ptr = (const uint8_t *)buf;
s->buf_end = s->buf_ptr + buf_len;
s->buf_start = s->buf_ptr;
diff --git a/qjscalc.js b/qjscalc.js
index 493869e..b7c5001 100644
--- a/qjscalc.js
+++ b/qjscalc.js
@@ -2625,6 +2625,17 @@ function atanh(a)
return 0.5 * log((1 + x) / (1 - x));
}
+function sigmoid(x)
+{
+ x = Float(x);
+ return 1 / (1 + exp(-x));
+}
+
+function lerp(a, b, t)
+{
+ return a + (b - a) * t;
+}
+
var idn = Matrix.idn;
var diag = Matrix.diag;
var trans = Matrix.trans;
diff --git a/quickjs-atom.h b/quickjs-atom.h
index a353ad4..4c22794 100644
--- a/quickjs-atom.h
+++ b/quickjs-atom.h
@@ -113,6 +113,7 @@ DEF(caller, "caller")
DEF(_eval_, "<eval>")
DEF(_ret_, "<ret>")
DEF(_var_, "<var>")
+DEF(_arg_var_, "<arg_var>")
DEF(_with_, "<with>")
DEF(lastIndex, "lastIndex")
DEF(target, "target")
diff --git a/quickjs-libc.c b/quickjs-libc.c
index 00a7536..e8b81e9 100644
--- a/quickjs-libc.c
+++ b/quickjs-libc.c
@@ -623,6 +623,97 @@ static JSValue js_std_getenv(JSContext *ctx, JSValueConst this_val,
return JS_NewString(ctx, str);
}
+#if defined(_WIN32)
+static void setenv(const char *name, const char *value, int overwrite)
+{
+ char *str;
+ size_t name_len, value_len;
+ name_len = strlen(name);
+ value_len = strlen(value);
+ str = malloc(name_len + 1 + value_len + 1);
+ memcpy(str, name, name_len);
+ str[name_len] = '=';
+ memcpy(str + name_len + 1, value, value_len);
+ str[name_len + 1 + value_len] = '\0';
+ _putenv(str);
+ free(str);
+}
+
+static void unsetenv(const char *name)
+{
+ setenv(name, "", TRUE);
+}
+#endif /* _WIN32 */
+
+static JSValue js_std_setenv(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ const char *name, *value;
+ name = JS_ToCString(ctx, argv[0]);
+ if (!name)
+ return JS_EXCEPTION;
+ value = JS_ToCString(ctx, argv[1]);
+ if (!value) {
+ JS_FreeCString(ctx, name);
+ return JS_EXCEPTION;
+ }
+ setenv(name, value, TRUE);
+ JS_FreeCString(ctx, name);
+ JS_FreeCString(ctx, value);
+ return JS_UNDEFINED;
+}
+
+static JSValue js_std_unsetenv(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ const char *name;
+ name = JS_ToCString(ctx, argv[0]);
+ if (!name)
+ return JS_EXCEPTION;
+ unsetenv(name);
+ JS_FreeCString(ctx, name);
+ return JS_UNDEFINED;
+}
+
+/* return an object containing the list of the available environment
+ variables. */
+static JSValue js_std_getenviron(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ char **envp;
+ const char *name, *p, *value;
+ JSValue obj;
+ uint32_t idx;
+ size_t name_len;
+ JSAtom atom;
+ int ret;
+
+ obj = JS_NewObject(ctx);
+ if (JS_IsException(obj))
+ return JS_EXCEPTION;
+ envp = environ;
+ for(idx = 0; envp[idx] != NULL; idx++) {
+ name = envp[idx];
+ p = strchr(name, '=');
+ name_len = p - name;
+ if (!p)
+ continue;
+ value = p + 1;
+ atom = JS_NewAtomLen(ctx, name, name_len);
+ if (atom == JS_ATOM_NULL)
+ goto fail;
+ ret = JS_DefinePropertyValue(ctx, obj, atom, JS_NewString(ctx, value),
+ JS_PROP_C_W_E);
+ JS_FreeAtom(ctx, atom);
+ if (ret < 0)
+ goto fail;
+ }
+ return obj;
+ fail:
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+}
+
static JSValue js_std_gc(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
@@ -1395,6 +1486,9 @@ static const JSCFunctionListEntry js_std_funcs[] = {
JS_CFUNC_DEF("evalScript", 1, js_evalScript ),
JS_CFUNC_DEF("loadScript", 1, js_loadScript ),
JS_CFUNC_DEF("getenv", 1, js_std_getenv ),
+ JS_CFUNC_DEF("setenv", 1, js_std_setenv ),
+ JS_CFUNC_DEF("unsetenv", 1, js_std_unsetenv ),
+ JS_CFUNC_DEF("getenviron", 1, js_std_getenviron ),
JS_CFUNC_DEF("urlGet", 1, js_std_urlGet ),
JS_CFUNC_DEF("loadFile", 1, js_std_loadFile ),
JS_CFUNC_DEF("strerror", 1, js_std_strerror ),
@@ -1412,7 +1506,6 @@ static const JSCFunctionListEntry js_std_funcs[] = {
JS_PROP_INT32_DEF("SEEK_CUR", SEEK_CUR, JS_PROP_CONFIGURABLE ),
JS_PROP_INT32_DEF("SEEK_END", SEEK_END, JS_PROP_CONFIGURABLE ),
JS_OBJECT_DEF("Error", js_std_error_props, countof(js_std_error_props), JS_PROP_CONFIGURABLE),
- /* setenv, ... */
};
static const JSCFunctionListEntry js_std_file_proto_funcs[] = {
diff --git a/quickjs-opcode.h b/quickjs-opcode.h
index 387363c..c731a14 100644
--- a/quickjs-opcode.h
+++ b/quickjs-opcode.h
@@ -114,7 +114,7 @@ DEF( check_brand, 1, 2, 2, none) /* this_obj func -> this_obj func */
DEF( add_brand, 1, 2, 0, none) /* this_obj home_obj -> */
DEF( return_async, 1, 1, 0, none)
DEF( throw, 1, 1, 0, none)
-DEF( throw_var, 6, 0, 0, atom_u8)
+DEF( throw_error, 6, 0, 0, atom_u8)
DEF( eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */
DEF( apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */
DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a
@@ -205,16 +205,15 @@ DEF( for_of_start, 1, 1, 3, none)
DEF(for_await_of_start, 1, 1, 3, none)
DEF( for_in_next, 1, 1, 3, none)
DEF( for_of_next, 2, 3, 5, u8)
-DEF(for_await_of_next, 1, 3, 4, none)
+DEF(iterator_check_object, 1, 1, 1, none)
DEF(iterator_get_value_done, 1, 1, 2, none)
DEF( iterator_close, 1, 3, 0, none)
DEF(iterator_close_return, 1, 4, 4, none)
-DEF(async_iterator_close, 1, 3, 2, none)
-DEF(async_iterator_next, 1, 4, 4, none)
-DEF(async_iterator_get, 2, 4, 5, u8)
+DEF( iterator_next, 1, 4, 4, none)
+DEF( iterator_call, 2, 4, 5, u8)
DEF( initial_yield, 1, 0, 0, none)
DEF( yield, 1, 1, 2, none)
-DEF( yield_star, 1, 2, 2, none)
+DEF( yield_star, 1, 1, 2, none)
DEF(async_yield_star, 1, 1, 2, none)
DEF( await, 1, 1, 1, none)
@@ -266,8 +265,6 @@ DEF( nop, 1, 0, 0, none)
/* temporary opcodes: never emitted in the final bytecode */
-def(set_arg_valid_upto, 3, 0, 0, arg) /* emitted in phase 1, removed in phase 2 */
-
def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
diff --git a/quickjs.c b/quickjs.c
index efc1d54..a39ff8f 100644
--- a/quickjs.c
+++ b/quickjs.c
@@ -199,7 +199,7 @@ typedef enum JSErrorEnum {
} JSErrorEnum;
#define JS_MAX_LOCAL_VARS 65536
-#define JS_STACK_SIZE_MAX 65536
+#define JS_STACK_SIZE_MAX 65534
#define JS_STRING_LEN_MAX ((1 << 30) - 1)
#define __exception __attribute__((warn_unused_result))
@@ -506,14 +506,17 @@ typedef struct JSClosureVar {
uint8_t is_arg : 1;
uint8_t is_const : 1;
uint8_t is_lexical : 1;
- uint8_t var_kind : 3; /* see JSVarKindEnum */
- /* 9 bits available */
+ uint8_t var_kind : 4; /* see JSVarKindEnum */
+ /* 8 bits available */
uint16_t var_idx; /* is_local = TRUE: index to a normal variable of the
parent function. otherwise: index to a closure
variable of the parent function */
JSAtom var_name;
} JSClosureVar;
+#define ARG_SCOPE_INDEX 1
+#define ARG_SCOPE_END (-2)
+
typedef struct JSVarScope {
int parent; /* index into fd->scopes of the enclosing scope */
int first; /* index into fd->vars of the last variable in this scope */
@@ -526,6 +529,7 @@ typedef enum {
JS_VAR_NEW_FUNCTION_DECL, /* lexical var with async/generator
function declaration */
JS_VAR_CATCH,
+ JS_VAR_FUNCTION_NAME, /* function expression name */
JS_VAR_PRIVATE_FIELD,
JS_VAR_PRIVATE_METHOD,
JS_VAR_PRIVATE_GETTER,
@@ -533,12 +537,21 @@ typedef enum {
JS_VAR_PRIVATE_GETTER_SETTER, /* must come after JS_VAR_PRIVATE_SETTER */
} JSVarKindEnum;
+/* XXX: could use a different structure in bytecode functions to save
+ memory */
typedef struct JSVarDef {
JSAtom var_name;
- int scope_level; /* index into fd->scopes of this variable lexical scope */
- int scope_next; /* index into fd->vars of the next variable in the
- * same or enclosing lexical scope */
- uint8_t is_func_var : 1; /* used for the function self reference */
+ /* index into fd->scopes of this variable lexical scope */
+ int scope_level;
+ /* during compilation:
+ - if scope_level = 0: scope in which the variable is defined
+ - if scope_level != 0: index into fd->vars of the next
+ variable in the same or enclosing lexical scope
+ in a bytecode function:
+ index into fd->vars of the next
+ variable in the same or enclosing lexical scope
+ */
+ int scope_next;
uint8_t is_const : 1;
uint8_t is_lexical : 1;
uint8_t is_captured : 1;
@@ -548,7 +561,9 @@ typedef struct JSVarDef {
JS_VAR_FUNCTION_DECL/JS_VAR_NEW_FUNCTION_DECL or scope level of
the definition of the 'var' variables (they have scope_level =
0) */
- int func_pool_or_scope_idx : 24; /* only used during compilation */
+ int func_pool_idx : 24; /* only used during compilation : index in
+ the constant pool for hoisted function
+ definition */
} JSVarDef;
/* for the encoding of the pc2line table */
@@ -855,7 +870,7 @@ struct JSObject {
uint8_t extensible : 1;
uint8_t free_mark : 1; /* only used when freeing objects with cycles */
uint8_t is_exotic : 1; /* TRUE if object has exotic property handlers */
- uint8_t fast_array : 1; /* TRUE if u.array is used for get/put */
+ uint8_t fast_array : 1; /* TRUE if u.array is used for get/put (for JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS and typed arrays) */
uint8_t is_constructor : 1; /* TRUE if object is a constructor function */
uint8_t is_uncatchable_error : 1; /* if TRUE, error is not catchable */
uint8_t tmp_mark : 1; /* used in JS_WriteObjectRec() */
@@ -1000,7 +1015,7 @@ static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_o
static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,
int argc, JSValueConst *argv);
static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
- JSValue val);
+ JSValue val, BOOL is_array_ctor);
static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
JSValueConst val, int flags, int scope_idx);
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...);
@@ -1226,11 +1241,11 @@ static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,
JSGCObjectTypeEnum type);
static void remove_gc_object(JSGCObjectHeader *h);
static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s);
-static int js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
-static int js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
+static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
+static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
void *opaque);
-static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p,
- JSAtom atom, void *opaque);
+static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p,
+ JSAtom atom, void *opaque);
void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag);
static const JSClassExoticMethods js_arguments_exotic_methods;
@@ -6710,6 +6725,21 @@ static JSValue JS_ThrowReferenceErrorUninitialized(JSContext *ctx, JSAtom name)
JS_AtomGetStr(ctx, buf, sizeof(buf), name));
}
+static JSValue JS_ThrowReferenceErrorUninitialized2(JSContext *ctx,
+ JSFunctionBytecode *b,
+ int idx, BOOL is_ref)
+{
+ JSAtom atom = JS_ATOM_NULL;
+ if (is_ref) {
+ atom = b->closure_var[idx].var_name;
+ } else {
+ /* not present if the function is stripped and contains no eval() */
+ if (b->vardefs)
+ atom = b->vardefs[b->arg_count + idx].var_name;
+ }
+ return JS_ThrowReferenceErrorUninitialized(ctx, atom);
+}
+
static JSValue JS_ThrowTypeErrorInvalidClass(JSContext *ctx, int class_id)
{
JSRuntime *rt = ctx->rt;
@@ -6986,25 +7016,37 @@ int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj)
return JS_OrdinaryIsInstanceOf(ctx, val, obj);
}
-typedef int JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
+/* return the value associated to the autoinit property or an exception */
+typedef JSValue JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
static JSAutoInitFunc *js_autoinit_func_table[] = {
js_instantiate_prototype, /* JS_AUTOINIT_ID_PROTOTYPE */
js_module_ns_autoinit, /* JS_AUTOINIT_ID_MODULE_NS */
- JS_InstantiateFunctionListItem, /* JS_AUTOINIT_ID_PROP */
+ JS_InstantiateFunctionListItem2, /* JS_AUTOINIT_ID_PROP */
};
+/* warning: 'prs' is reallocated after it */
static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop,
- JSProperty *pr)
+ JSProperty *pr, JSShapeProperty *prs)
{
- int ret;
+ JSValue val;
JSContext *realm;
JSAutoInitFunc *func;
-
+
+ if (js_shape_prepare_update(ctx, p, &prs))
+ return -1;
+
realm = js_autoinit_get_realm(pr);
func = js_autoinit_func_table[js_autoinit_get_id(pr)];
- ret = func(realm, p, prop, pr->u.init.opaque);
- return ret;
+ /* 'func' shall not modify the object properties 'pr' */
+ val = func(realm, p, prop, pr->u.init.opaque);
+ js_autoinit_free(ctx->rt, pr);
+ prs->flags &= ~JS_PROP_TMASK;
+ pr->u.value = JS_UNDEFINED;
+ if (JS_IsException(val))
+ return -1;
+ pr->u.value = val;
+ return 0;
}
JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
@@ -7075,7 +7117,7 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
return JS_DupValue(ctx, val);
} else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
/* Instantiate property and retry */
- if (JS_AutoInitProperty(ctx, p, prop, pr))
+ if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
return JS_EXCEPTION;
continue;
}
@@ -7093,7 +7135,7 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
return JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);
} else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
- goto typed_array_oob;
+ return JS_UNDEFINED;
}
} else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
@@ -7102,9 +7144,6 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
if (ret != 0) {
if (ret < 0)
return JS_EXCEPTION;
- typed_array_oob:
- if (typed_array_is_detached(ctx, p))
- return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
return JS_UNDEFINED;
}
}
@@ -7337,6 +7376,22 @@ static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func)
return 0;
}
+static uint32_t js_string_obj_get_length(JSContext *ctx,
+ JSValueConst obj)
+{
+ JSObject *p;
+ JSString *p1;
+ uint32_t len = 0;
+
+ /* This is a class exotic method: obj class_id is JS_CLASS_STRING */
+ p = JS_VALUE_GET_OBJ(obj);
+ if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {
+ p1 = JS_VALUE_GET_STRING(p->u.object_data);
+ len = p1->len;
+ }
+ return len;
+}
+
static int num_keys_cmp(const void *p1, const void *p2, void *opaque)
{
JSContext *ctx = opaque;
@@ -7379,7 +7434,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
JSPropertyEnum *tab_atom, *tab_exotic;
JSAtom atom;
uint32_t num_keys_count, str_keys_count, sym_keys_count, atom_count;
- uint32_t num_index, str_index, sym_index, exotic_count;
+ uint32_t num_index, str_index, sym_index, exotic_count, exotic_keys_count;
BOOL is_enumerable, num_sorted;
uint32_t num_key;
JSAtomKindEnum kind;
@@ -7392,6 +7447,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
num_keys_count = 0;
str_keys_count = 0;
sym_keys_count = 0;
+ exotic_keys_count = 0;
exotic_count = 0;
tab_exotic = NULL;
sh = p->shape;
@@ -7425,19 +7481,13 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
if (p->is_exotic) {
if (p->fast_array) {
- /* the implicit GetOwnProperty raises an exception if the
- typed array is detached */
- if ((flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY)) &&
- (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
- p->class_id <= JS_CLASS_FLOAT64_ARRAY) &&
- typed_array_is_detached(ctx, p) &&
- typed_array_get_length(ctx, p) != 0) {
- JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- return -1;
- }
if (flags & JS_GPN_STRING_MASK) {
num_keys_count += p->u.array.count;
}
+ } else if (p->class_id == JS_CLASS_STRING) {
+ if (flags & JS_GPN_STRING_MASK) {
+ num_keys_count += js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+ }
} else {
const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
if (em && em->get_own_property_names) {
@@ -7466,13 +7516,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
tab_exotic[i].is_enumerable = is_enumerable;
}
if (!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) {
- if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {
- num_keys_count++;
- } else if (kind == JS_ATOM_KIND_STRING) {
- str_keys_count++;
- } else {
- sym_keys_count++;
- }
+ exotic_keys_count++;
}
}
}
@@ -7482,7 +7526,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
/* fill them */
- atom_count = num_keys_count + str_keys_count + sym_keys_count;
+ atom_count = num_keys_count + str_keys_count + sym_keys_count + exotic_keys_count;
/* avoid allocating 0 bytes */
tab_atom = js_malloc(ctx, sizeof(tab_atom[0]) * max_int(atom_count, 1));
if (!tab_atom) {
@@ -7518,12 +7562,19 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
}
if (p->is_exotic) {
+ int len;
if (p->fast_array) {
if (flags & JS_GPN_STRING_MASK) {
- for(i = 0; i < p->u.array.count; i++) {
+ len = p->u.array.count;
+ goto add_array_keys;
+ }
+ } else if (p->class_id == JS_CLASS_STRING) {
+ if (flags & JS_GPN_STRING_MASK) {
+ len = js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+ add_array_keys:
+ for(i = 0; i < len; i++) {
tab_atom[num_index].atom = __JS_AtomFromUInt32(i);
if (tab_atom[num_index].atom == JS_ATOM_NULL) {
- js_free_prop_enum(ctx, tab_exotic, exotic_count);
js_free_prop_enum(ctx, tab_atom, num_index);
return -1;
}
@@ -7531,30 +7582,23 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
num_index++;
}
}
- }
- if (exotic_count > 0) {
+ } else {
+ /* Note: exotic keys are not reordered and comes after the object own properties. */
for(i = 0; i < exotic_count; i++) {
atom = tab_exotic[i].atom;
is_enumerable = tab_exotic[i].is_enumerable;
kind = JS_AtomGetKind(ctx, atom);
if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
((flags >> kind) & 1) != 0) {
- if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {
- j = num_index++;
- num_sorted = FALSE;
- } else if (kind == JS_ATOM_KIND_STRING) {
- j = str_index++;
- } else {
- j = sym_index++;
- }
- tab_atom[j].atom = atom;
- tab_atom[j].is_enumerable = is_enumerable;
+ tab_atom[sym_index].atom = atom;
+ tab_atom[sym_index].is_enumerable = is_enumerable;
+ sym_index++;
} else {
JS_FreeAtom(ctx, atom);
}
}
+ js_free(ctx, tab_exotic);
}
- js_free(ctx, tab_exotic);
}
assert(num_index == num_keys_count);
@@ -7614,7 +7658,7 @@ retry:
desc->value = JS_DupValue(ctx, val);
} else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
/* Instantiate property and retry */
- if (JS_AutoInitProperty(ctx, p, prop, pr))
+ if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
return -1;
goto retry;
}
@@ -7642,10 +7686,8 @@ retry:
idx = __JS_AtomToUInt32(prop);
if (idx < p->u.array.count) {
if (desc) {
- desc->flags = JS_PROP_WRITABLE | JS_PROP_ENUMERABLE;
- if (p->class_id == JS_CLASS_ARRAY ||
- p->class_id == JS_CLASS_ARGUMENTS)
- desc->flags |= JS_PROP_CONFIGURABLE;
+ desc->flags = JS_PROP_WRITABLE | JS_PROP_ENUMERABLE |
+ JS_PROP_CONFIGURABLE;
desc->getter = JS_UNDEFINED;
desc->setter = JS_UNDEFINED;
desc->value = JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);
@@ -7653,19 +7695,6 @@ retry:
return TRUE;
}
}
- if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
- p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
- int ret;
- ret = JS_AtomIsNumericIndex(ctx, prop);
- if (ret != 0) {
- if (ret < 0)
- return -1;
- if (typed_array_is_detached(ctx, p)) {
- JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- return -1;
- }
- }
- }
} else {
const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
if (em && em->get_own_property) {
@@ -7748,8 +7777,6 @@ int JS_HasProperty(JSContext *ctx, JSValueConst obj, JSAtom prop)
if (ret != 0) {
if (ret < 0)
return -1;
- /* the detached array test was done in
- JS_GetOwnPropertyInternal() */
return FALSE;
}
}
@@ -8074,7 +8101,7 @@ static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom)
return -1;
goto redo;
} else {
- return FALSE; /* not configurable */
+ return FALSE;
}
}
} else {
@@ -8114,15 +8141,19 @@ static int call_setter(JSContext *ctx, JSObject *setter,
}
/* set the array length and remove the array elements if necessary. */
-static int set_array_length(JSContext *ctx, JSObject *p, JSValue val, int flags)
+static int set_array_length(JSContext *ctx, JSObject *p, JSValue val,
+ int flags)
{
uint32_t len, idx, cur_len;
int i, ret;
/* Note: this call can reallocate the properties of 'p' */
- ret = JS_ToArrayLengthFree(ctx, &len, val);
+ ret = JS_ToArrayLengthFree(ctx, &len, val, FALSE);
if (ret)
return -1;
+ /* JS_ToArrayLengthFree() must be done before the read-only test */
+ if (unlikely(!(p->shape->prop[0].flags & JS_PROP_WRITABLE)))
+ return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
if (likely(p->fast_array)) {
uint32_t old_len = p->u.array.count;
@@ -8382,8 +8413,7 @@ retry:
/* fast case */
set_value(ctx, &pr->u.value, val);
return TRUE;
- } else if ((prs->flags & (JS_PROP_LENGTH | JS_PROP_WRITABLE)) ==
- (JS_PROP_LENGTH | JS_PROP_WRITABLE)) {
+ } else if (prs->flags & JS_PROP_LENGTH) {
assert(p->class_id == JS_CLASS_ARRAY);
assert(prop == JS_ATOM_length);
return set_array_length(ctx, p, val, flags);
@@ -8399,7 +8429,7 @@ retry:
return TRUE;
} else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
/* Instantiate property and retry (potentially useless) */
- if (JS_AutoInitProperty(ctx, p, prop, pr)) {
+ if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) {
JS_FreeValue(ctx, val);
return -1;
}
@@ -8437,10 +8467,6 @@ retry:
JS_FreeValue(ctx, val);
if (JS_IsException(val))
return -1;
- if (typed_array_is_detached(ctx, p1)) {
- JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- return -1;
- }
return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index");
}
}
@@ -8509,7 +8535,7 @@ retry:
return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags);
} else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
/* Instantiate property and retry (potentially useless) */
- if (JS_AutoInitProperty(ctx, p1, prop, pr))
+ if (JS_AutoInitProperty(ctx, p1, prop, pr, prs))
return -1;
goto retry2;
} else if (!(prs->flags & JS_PROP_WRITABLE)) {
@@ -8677,12 +8703,7 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
return -1;
if (unlikely(idx >= (uint32_t)p->u.array.count)) {
ta_out_of_bound:
- if (typed_array_is_detached(ctx, p)) {
- JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- return -1;
- } else {
- return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index");
- }
+ return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index");
}
p->u.array.u.double_ptr[idx] = d;
break;
@@ -8967,13 +8988,32 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
redo_prop_update:
prs = find_own_property(&pr, p, prop);
if (prs) {
+ /* the range of the Array length property is always tested before */
+ if ((prs->flags & JS_PROP_LENGTH) && (flags & JS_PROP_HAS_VALUE)) {
+ uint32_t array_length;
+ if (JS_ToArrayLengthFree(ctx, &array_length,
+ JS_DupValue(ctx, val), FALSE)) {
+ return -1;
+ }
+ /* this code relies on the fact that Uint32 are never allocated */
+ val = (JSValueConst)JS_NewUint32(ctx, array_length);
+ /* prs may have been modified */
+ prs = find_own_property(&pr, p, prop);
+ assert(prs != NULL);
+ }
/* property already exists */
if (!check_define_prop_flags(prs->flags, flags)) {
not_configurable:
return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable");
}
- retry:
+ if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
+ /* Instantiate property and retry */
+ if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
+ return -1;
+ goto redo_prop_update;
+ }
+
if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE |
JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
@@ -8996,14 +9036,6 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
/* convert to getset */
if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
free_var_ref(ctx->rt, pr->u.var_ref);
- } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
- /* clear property and update */
- if (js_shape_prepare_update(ctx, p, &prs))
- return -1;
- js_autoinit_free(ctx->rt, pr);
- prs->flags &= ~JS_PROP_TMASK;
- pr->u.value = JS_UNDEFINED;
- goto retry;
} else {
JS_FreeValue(ctx, pr->u.value);
}
@@ -9051,39 +9083,17 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
pr->u.value = JS_UNDEFINED;
} else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
/* Note: JS_PROP_VARREF is always writable */
- } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
- /* clear property and update */
- if (js_shape_prepare_update(ctx, p, &prs))
- return -1;
- js_autoinit_free(ctx->rt, pr);
- prs->flags &= ~JS_PROP_TMASK;
- pr->u.value = JS_UNDEFINED;
} else {
if ((prs->flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 &&
- (flags & JS_PROP_HAS_VALUE) &&
- !js_same_value(ctx, val, pr->u.value)) {
- goto not_configurable;
+ (flags & JS_PROP_HAS_VALUE)) {
+ if (!js_same_value(ctx, val, pr->u.value)) {
+ goto not_configurable;
+ } else {
+ return TRUE;
+ }
}
}
- if (prs->flags & JS_PROP_LENGTH) {
- if (flags & JS_PROP_HAS_VALUE) {
- res = set_array_length(ctx, p, JS_DupValue(ctx, val),
- flags);
- } else {
- res = TRUE;
- }
- /* still need to reset the writable flag if needed.
- The JS_PROP_LENGTH is reset to have the correct
- read-only behavior in JS_SetProperty(). */
- if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==
- JS_PROP_HAS_WRITABLE) {
- prs = get_shape_prop(p->shape);
- if (js_update_property_flags(ctx, p, &prs,
- prs->flags & ~(JS_PROP_WRITABLE | JS_PROP_LENGTH)))
- return -1;
- }
- return res;
- } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
+ if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
if (flags & JS_PROP_HAS_VALUE) {
if (p->class_id == JS_CLASS_MODULE_NS) {
/* JS_PROP_WRITABLE is always true for variable
@@ -9107,9 +9117,27 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
pr->u.value = val1;
prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
}
- } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
- /* XXX: should never happen, type was reset above */
- abort();
+ } else if (prs->flags & JS_PROP_LENGTH) {
+ if (flags & JS_PROP_HAS_VALUE) {
+ /* Note: no JS code is executable because
+ 'val' is guaranted to be a Uint32 */
+ res = set_array_length(ctx, p, JS_DupValue(ctx, val),
+ flags);
+ } else {
+ res = TRUE;
+ }
+ /* still need to reset the writable flag if
+ needed. The JS_PROP_LENGTH is kept because the
+ Uint32 test is still done if the length
+ property is read-only. */
+ if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==
+ JS_PROP_HAS_WRITABLE) {
+ prs = get_shape_prop(p->shape);
+ if (js_update_property_flags(ctx, p, &prs,
+ prs->flags & ~JS_PROP_WRITABLE))
+ return -1;
+ }
+ return res;
} else {
if (flags & JS_PROP_HAS_VALUE) {
JS_FreeValue(ctx, pr->u.value);
@@ -9194,9 +9222,9 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
typed_array_oob:
return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound index in typed array");
}
- prop_flags = get_prop_flags(flags, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE);
+ prop_flags = get_prop_flags(flags, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET) ||
- prop_flags != (JS_PROP_ENUMERABLE | JS_PROP_WRITABLE)) {
+ prop_flags != (JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE)) {
return JS_ThrowTypeErrorOrFalse(ctx, flags, "invalid descriptor flags");
}
if (flags & JS_PROP_HAS_VALUE) {
@@ -9581,9 +9609,8 @@ static int JS_SetGlobalVar(JSContext *ctx, JSAtom prop, JSValue val,
set_value(ctx, &pr->u.value, val);
return 0;
}
-
flags = JS_PROP_THROW_STRICT;
- if (flag != 2 && is_strict_mode(ctx))
+ if (is_strict_mode(ctx))
flags |= JS_PROP_NO_ADD;
return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, flags);
}
@@ -10918,11 +10945,10 @@ static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val)
}
static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
- JSValue val)
+ JSValue val, BOOL is_array_ctor)
{
uint32_t tag, len;
- redo:
tag = JS_VALUE_GET_TAG(val);
switch(tag) {
case JS_TAG_INT:
@@ -10959,16 +10985,36 @@ static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
double d;
d = JS_VALUE_GET_FLOAT64(val);
len = (uint32_t)d;
- if (len != d) {
- fail:
- JS_ThrowRangeError(ctx, "invalid array length");
- return -1;
- }
+ if (len != d)
+ goto fail;
} else {
- val = JS_ToNumberFree(ctx, val);
- if (JS_IsException(val))
- return -1;
- goto redo;
+ uint32_t len1;
+
+ if (is_array_ctor) {
+ val = JS_ToNumberFree(ctx, val);
+ if (JS_IsException(val))
+ return -1;
+ /* cannot recurse because val is a number */
+ if (JS_ToArrayLengthFree(ctx, &len, val, TRUE))
+ return -1;
+ } else {
+ /* legacy behavior: must do the conversion twice and compare */
+ if (JS_ToUint32(ctx, &len, val)) {
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
+ val = JS_ToNumberFree(ctx, val);
+ if (JS_IsException(val))
+ return -1;
+ /* cannot recurse because val is a number */
+ if (JS_ToArrayLengthFree(ctx, &len1, val, FALSE))
+ return -1;
+ if (len1 != len) {
+ fail:
+ JS_ThrowRangeError(ctx, "invalid array length");
+ return -1;
+ }
+ }
}
break;
}
@@ -15031,15 +15077,6 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
if (prs->flags & JS_PROP_ENUMERABLE)
goto normal_case;
}
- /* the implicit GetOwnProperty raises an exception if the
- typed array is detached */
- if ((p->class_id >= JS_CLASS_UINT8C_ARRAY &&
- p->class_id <= JS_CLASS_FLOAT64_ARRAY) &&
- typed_array_is_detached(ctx, p) &&
- typed_array_get_length(ctx, p) != 0) {
- JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- goto fail;
- }
/* for fast arrays, we only store the number of elements */
it->is_array = TRUE;
it->array_length = p->u.array.count;
@@ -15349,16 +15386,6 @@ static __exception int js_for_of_next(JSContext *ctx, JSValue *sp, int offset)
return 0;
}
-static __exception int js_for_await_of_next(JSContext *ctx, JSValue *sp)
-{
- JSValue result;
- result = JS_Call(ctx, sp[-2], sp[-3], 0, NULL);
- if (JS_IsException(result))
- return -1;
- sp[0] = result;
- return 0;
-}
-
static JSValue JS_IteratorGetCompleteValue(JSContext *ctx, JSValueConst obj,
BOOL *pdone)
{
@@ -15663,7 +15690,7 @@ static JSValue js_closure2(JSContext *ctx, JSValue func_obj,
return JS_EXCEPTION;
}
-static int js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque)
+static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque)
{
JSValue obj, this_val;
int ret;
@@ -15671,15 +15698,17 @@ static int js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, vo
this_val = JS_MKPTR(JS_TAG_OBJECT, p);
obj = JS_NewObject(ctx);
if (JS_IsException(obj))
- return -1;
+ return JS_EXCEPTION;
set_cycle_flag(ctx, obj);
set_cycle_flag(ctx, this_val);
ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_constructor,
JS_DupValue(ctx, this_val),
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- if (JS_DefinePropertyValue(ctx, this_val, atom, obj, JS_PROP_WRITABLE) < 0 || ret < 0)
- return -1;
- return 0;
+ if (ret < 0) {
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+ }
+ return obj;
}
static const uint16_t func_kind_to_class_id[] = {
@@ -16645,11 +16674,12 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JS_Throw(ctx, *--sp);
goto exception;
- CASE(OP_throw_var):
+ CASE(OP_throw_error):
#define JS_THROW_VAR_RO 0
#define JS_THROW_VAR_REDECL 1
#define JS_THROW_VAR_UNINITIALIZED 2
-#define JS_THROW_VAR_DELETE_SUPER 3
+#define JS_THROW_ERROR_DELETE_SUPER 3
+#define JS_THROW_ERROR_ITERATOR_THROW 4
{
JSAtom atom;
int type;
@@ -16665,9 +16695,12 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
if (type == JS_THROW_VAR_UNINITIALIZED)
JS_ThrowReferenceErrorUninitialized(ctx, atom);
else
- if (type == JS_THROW_VAR_DELETE_SUPER)
+ if (type == JS_THROW_ERROR_DELETE_SUPER)
JS_ThrowReferenceError(ctx, "unsupported reference to 'super'");
else
+ if (type == JS_THROW_ERROR_ITERATOR_THROW)
+ JS_ThrowTypeError(ctx, "iterator does not have a throw method");
+ else
JS_ThrowInternalError(ctx, "invalid throw var type %d", type);
}
goto exception;
@@ -16995,7 +17028,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
pc += 2;
val = *var_refs[idx]->pvalue;
if (unlikely(JS_IsUninitialized(val))) {
- JS_ThrowReferenceErrorUninitialized(ctx, JS_ATOM_NULL);
+ JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
goto exception;
}
sp[0] = JS_DupValue(ctx, val);
@@ -17008,7 +17041,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
idx = get_u16(pc);
pc += 2;
if (unlikely(JS_IsUninitialized(*var_refs[idx]->pvalue))) {
- JS_ThrowReferenceErrorUninitialized(ctx, JS_ATOM_NULL);
+ JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
goto exception;
}
set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
@@ -17021,7 +17054,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
idx = get_u16(pc);
pc += 2;
if (unlikely(!JS_IsUninitialized(*var_refs[idx]->pvalue))) {
- JS_ThrowReferenceErrorUninitialized(ctx, JS_ATOM_NULL);
+ JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
goto exception;
}
set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
@@ -17042,7 +17075,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
idx = get_u16(pc);
pc += 2;
if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
- JS_ThrowReferenceErrorUninitialized(ctx, JS_ATOM_NULL);
+ JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE);
goto exception;
}
sp[0] = JS_DupValue(ctx, var_buf[idx]);
@@ -17055,7 +17088,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
idx = get_u16(pc);
pc += 2;
if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
- JS_ThrowReferenceErrorUninitialized(ctx, JS_ATOM_NULL);
+ JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE);
goto exception;
}
set_value(ctx, &var_buf[idx], sp[-1]);
@@ -17294,16 +17327,17 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
sp += 1;
*sp++ = JS_NewCatchOffset(ctx, 0);
BREAK;
- CASE(OP_for_await_of_next):
- if (js_for_await_of_next(ctx, sp))
- goto exception;
- sp += 1;
- BREAK;
CASE(OP_iterator_get_value_done):
if (js_iterator_get_value_done(ctx, sp))
goto exception;
sp += 1;
BREAK;
+ CASE(OP_iterator_check_object):
+ if (unlikely(!JS_IsObject(sp[-1]))) {
+ JS_ThrowTypeError(ctx, "iterator must return an object");
+ goto exception;
+ }
+ BREAK;
CASE(OP_iterator_close):
/* iter_obj next catch_offset -> */
@@ -17340,37 +17374,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
}
BREAK;
- CASE(OP_async_iterator_close):
- /* iter_obj next catch_offset -> value flag */
- {
- JSValue ret, method;
- int ret_flag;
- sp--; /* remove the catch offset */
- method = JS_GetProperty(ctx, sp[-2], JS_ATOM_return);
- if (JS_IsException(method))
- goto exception;
- if (JS_IsUndefined(method) || JS_IsNull(method)) {
- ret = JS_UNDEFINED;
- ret_flag = TRUE;
- } else {
- ret = JS_CallFree(ctx, method, sp[-2], 0, NULL);
- if (JS_IsException(ret))
- goto exception;
- if (!JS_IsObject(ret)) {
- JS_FreeValue(ctx, ret);
- JS_ThrowTypeErrorNotAnObject(ctx);
- goto exception;
- }
- ret_flag = FALSE;
- }
- JS_FreeValue(ctx, sp[-2]);
- JS_FreeValue(ctx, sp[-1]);
- sp[-2] = ret;
- sp[-1] = JS_NewBool(ctx, ret_flag);
- }
- BREAK;
-
- CASE(OP_async_iterator_next):
+ CASE(OP_iterator_next):
/* stack: iter_obj next catch_offset val */
{
JSValue ret;
@@ -17383,26 +17387,28 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
}
BREAK;
- CASE(OP_async_iterator_get):
+ CASE(OP_iterator_call):
/* stack: iter_obj next catch_offset val */
{
JSValue method, ret;
BOOL ret_flag;
int flags;
flags = *pc++;
- /* XXX: use another opcode such as OP_throw_var */
- if (flags == 2) {
- JS_ThrowTypeError(ctx, "iterator does not have a throw method");
- goto exception;
- }
- method = JS_GetProperty(ctx, sp[-4], flags ? JS_ATOM_throw : JS_ATOM_return);
+ method = JS_GetProperty(ctx, sp[-4], (flags & 1) ?
+ JS_ATOM_throw : JS_ATOM_return);
if (JS_IsException(method))
goto exception;
if (JS_IsUndefined(method) || JS_IsNull(method)) {
ret_flag = TRUE;
} else {
- ret = JS_CallFree(ctx, method, sp[-4],
- 1, (JSValueConst *)(sp - 1));
+ if (flags & 2) {
+ /* no argument */
+ ret = JS_CallFree(ctx, method, sp[-4],
+ 0, NULL);
+ } else {
+ ret = JS_CallFree(ctx, method, sp[-4],
+ 1, (JSValueConst *)(sp - 1));
+ }
if (JS_IsException(ret))
goto exception;
JS_FreeValue(ctx, sp[-1]);
@@ -17728,7 +17734,8 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
CASE(OP_put_ref_value):
{
- int ret;
+ int ret, flags;
+ flags = JS_PROP_THROW_STRICT;
if (unlikely(JS_IsUndefined(sp[-3]))) {
if (is_strict_mode(ctx)) {
JSAtom atom = JS_ValueToAtom(ctx, sp[-2]);
@@ -17740,8 +17747,11 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
} else {
sp[-3] = JS_DupValue(ctx, ctx->global_obj);
}
+ } else {
+ if (is_strict_mode(ctx))
+ flags |= JS_PROP_NO_ADD;
}
- ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], JS_PROP_THROW_STRICT);
+ ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], flags);
JS_FreeValue(ctx, sp[-3]);
sp -= 3;
if (unlikely(ret < 0))
@@ -18084,8 +18094,12 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
var_buf[idx] = JS_NewInt32(ctx, val + 1);
} else {
inc_loc_slow:
- if (js_unary_arith_slow(ctx, var_buf + idx + 1, OP_inc))
+ /* must duplicate otherwise the variable value may
+ be destroyed before JS code accesses it */
+ op1 = JS_DupValue(ctx, op1);
+ if (js_unary_arith_slow(ctx, &op1 + 1, OP_inc))
goto exception;
+ set_value(ctx, &var_buf[idx], op1);
}
}
BREAK;
@@ -18105,8 +18119,12 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
var_buf[idx] = JS_NewInt32(ctx, val - 1);
} else {
dec_loc_slow:
- if (js_unary_arith_slow(ctx, var_buf + idx + 1, OP_dec))
+ /* must duplicate otherwise the variable value may
+ be destroyed before JS code accesses it */
+ op1 = JS_DupValue(ctx, op1);
+ if (js_unary_arith_slow(ctx, &op1 + 1, OP_dec))
goto exception;
+ set_value(ctx, &var_buf[idx], op1);
}
}
BREAK;
@@ -18432,6 +18450,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
set_value(ctx, &sp[-1], val);
break;
case OP_with_put_var:
+ /* XXX: check if strict mode */
ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2],
JS_PROP_THROW_STRICT);
JS_FreeValue(ctx, sp[-1]);
@@ -18922,13 +18941,11 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,
JSGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_GENERATOR);
JSStackFrame *sf;
JSValue ret, func_ret;
- JSValueConst iter_args[1];
*pdone = TRUE;
if (!s)
return JS_ThrowTypeError(ctx, "not a generator");
sf = &s->func_state.frame;
- redo:
switch(s->state) {
default:
case JS_GENERATOR_STATE_SUSPENDED_START:
@@ -18940,85 +18957,16 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,
}
break;
case JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR:
- {
- int done;
- JSValue method, iter_obj;
-
- iter_obj = sf->cur_sp[-2];
- if (magic == GEN_MAGIC_NEXT) {
- method = JS_DupValue(ctx, sf->cur_sp[-1]);
- } else {
- method = JS_GetProperty(ctx, iter_obj,
- magic == GEN_MAGIC_RETURN ?
- JS_ATOM_return : JS_ATOM_throw);
- if (JS_IsException(method))
- goto iter_exception;
- }
- if (magic != GEN_MAGIC_NEXT &&
- (JS_IsUndefined(method) || JS_IsNull(method))) {
- /* default action */
- if (magic == GEN_MAGIC_RETURN) {
- ret = JS_DupValue(ctx, argv[0]);
- goto iter_done;
- } else {
- if (JS_IteratorClose(ctx, iter_obj, FALSE))
- goto iter_exception;
- JS_ThrowTypeError(ctx, "iterator does not have a throw method");
- goto iter_exception;
- }
- }
- ret = JS_IteratorNext2(ctx, iter_obj, method, argc, argv, &done);
- JS_FreeValue(ctx, method);
- if (JS_IsException(ret)) {
- iter_exception:
- goto exec_throw;
- }
- /* if not done, the iterator returns the exact object
- returned by 'method' */
- if (done == 2) {
- JSValue done_val, value;
- done_val = JS_GetProperty(ctx, ret, JS_ATOM_done);
- if (JS_IsException(done_val)) {
- JS_FreeValue(ctx, ret);
- goto iter_exception;
- }
- done = JS_ToBoolFree(ctx, done_val);
- if (done) {
- value = JS_GetProperty(ctx, ret, JS_ATOM_value);
- JS_FreeValue(ctx, ret);
- if (JS_IsException(value))
- goto iter_exception;
- ret = value;
- goto iter_done;
- } else {
- *pdone = 2;
- }
- } else {
- if (done) {
- /* 'yield *' returns the value associated to done = true */
- iter_done:
- JS_FreeValue(ctx, sf->cur_sp[-2]);
- JS_FreeValue(ctx, sf->cur_sp[-1]);
- sf->cur_sp--;
- goto exec_arg;
- } else {
- *pdone = FALSE;
- }
- }
- break;
- }
- break;
case JS_GENERATOR_STATE_SUSPENDED_YIELD:
/* cur_sp[-1] was set to JS_UNDEFINED in the previous call */
ret = JS_DupValue(ctx, argv[0]);
- if (magic == GEN_MAGIC_THROW) {
+ if (magic == GEN_MAGIC_THROW &&
+ s->state == JS_GENERATOR_STATE_SUSPENDED_YIELD) {
JS_Throw(ctx, ret);
- exec_throw:
s->func_state.throw_flag = TRUE;
} else {
- exec_arg:
sf->cur_sp[-1] = ret;
- sf->cur_sp[0] = JS_NewBool(ctx, (magic == GEN_MAGIC_RETURN));
+ sf->cur_sp[0] = JS_NewInt32(ctx, magic);
sf->cur_sp++;
exec_no_arg:
s->func_state.throw_flag = FALSE;
@@ -19032,17 +18980,14 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,
return func_ret;
}
if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) {
+ /* get the returned yield value at the top of the stack */
+ ret = sf->cur_sp[-1];
+ sf->cur_sp[-1] = JS_UNDEFINED;
if (JS_VALUE_GET_INT(func_ret) == FUNC_RET_YIELD_STAR) {
- /* 'yield *' */
s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR;
- iter_args[0] = JS_UNDEFINED;
- argc = 1;
- argv = iter_args;
- goto redo;
+ /* return (value, done) object */
+ *pdone = 2;
} else {
- /* get the return the yield value at the top of the stack */
- ret = sf->cur_sp[-1];
- sf->cur_sp[-1] = JS_UNDEFINED;
*pdone = FALSE;
}
} else {
@@ -19853,15 +19798,15 @@ typedef struct BlockEnv {
int has_iterator;
} BlockEnv;
-typedef struct JSHoistedDef {
- int cpool_idx; /* -1 means variable global definition */
- uint8_t force_init : 1; /* initialize to undefined */
+typedef struct JSGlobalVar {
+ int cpool_idx; /* if >= 0, index in the constant pool for hoisted
+ function defintion*/
+ uint8_t force_init : 1; /* force initialization to undefined */
uint8_t is_lexical : 1; /* global let/const definition */
uint8_t is_const : 1; /* const definition */
- int var_idx; /* function object index if cpool_idx >= 0 */
int scope_level; /* scope of definition */
- JSAtom var_name; /* variable name if cpool_idx < 0 */
-} JSHoistedDef;
+ JSAtom var_name; /* variable name */
+} JSGlobalVar;
typedef struct RelocEntry {
struct RelocEntry *next;
@@ -19924,6 +19869,7 @@ typedef struct JSFunctionDef {
BOOL has_home_object; /* TRUE if the home object is available */
BOOL has_prototype; /* true if a prototype field is necessary */
BOOL has_simple_parameter_list;
+ BOOL has_parameter_expressions; /* if true, an argument scope is created */
BOOL has_use_strict; /* to reject directive in special cases */
BOOL has_eval_call; /* true if the function contains a call to eval() */
BOOL has_arguments_binding; /* true if the 'arguments' binding is
@@ -19951,7 +19897,10 @@ typedef struct JSFunctionDef {
int arg_count; /* number of arguments */
int defined_arg_count;
int var_object_idx; /* -1 if none */
+ int arg_var_object_idx; /* -1 if none (var object for the argument scope) */
int arguments_var_idx; /* -1 if none */
+ int arguments_arg_idx; /* argument variable definition in argument scope,
+ -1 if none */
int func_var_idx; /* variable containing the current function (-1
if none, only used if is_func_expr is true) */
int eval_ret_idx; /* variable containing the return value of the eval, -1 if none */
@@ -19967,10 +19916,11 @@ typedef struct JSFunctionDef {
int scope_count; /* number of entries used in the fd->scopes array */
JSVarScope *scopes;
JSVarScope def_scope_array[4];
+ int body_scope; /* scope of the body of the function or eval */
- int hoisted_def_count;
- int hoisted_def_size;
- JSHoistedDef *hoisted_def;
+ int global_var_count;
+ int global_var_size;
+ JSGlobalVar *global_vars;
DynBuf byte_code;
int last_opcode_pos; /* -1 if no last opcode */
@@ -21475,7 +21425,7 @@ static BOOL js_is_live_code(JSParseState *s) {
case OP_return_undef:
case OP_return_async:
case OP_throw:
- case OP_throw_var:
+ case OP_throw_error:
case OP_goto:
#if SHORT_OPCODES
case OP_goto8:
@@ -21647,6 +21597,21 @@ static int find_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
return find_arg(ctx, fd, name);
}
+/* find a variable declaration in a given scope */
+static int find_var_in_scope(JSContext *ctx, JSFunctionDef *fd,
+ JSAtom name, int scope_level)
+{
+ int scope_idx;
+ for(scope_idx = fd->scopes[scope_level].first; scope_idx >= 0;
+ scope_idx = fd->vars[scope_idx].scope_next) {
+ if (fd->vars[scope_idx].scope_level != scope_level)
+ break;
+ if (fd->vars[scope_idx].var_name == name)
+ return scope_idx;
+ }
+ return -1;
+}
+
/* return true if scope == parent_scope or if scope is a child of
parent_scope */
static BOOL is_child_scope(JSContext *ctx, JSFunctionDef *fd,
@@ -21668,7 +21633,7 @@ static int find_var_in_child_scope(JSContext *ctx, JSFunctionDef *fd,
for(i = 0; i < fd->var_count; i++) {
JSVarDef *vd = &fd->vars[i];
if (vd->var_name == name && vd->scope_level == 0) {
- if (is_child_scope(ctx, fd, vd->func_pool_or_scope_idx,
+ if (is_child_scope(ctx, fd, vd->scope_next,
scope_level))
return i;
}
@@ -21677,11 +21642,11 @@ static int find_var_in_child_scope(JSContext *ctx, JSFunctionDef *fd,
}
-static JSHoistedDef *find_hoisted_def(JSFunctionDef *fd, JSAtom name)
+static JSGlobalVar *find_global_var(JSFunctionDef *fd, JSAtom name)
{
int i;
- for(i = 0; i < fd->hoisted_def_count; i++) {
- JSHoistedDef *hf = &fd->hoisted_def[i];
+ for(i = 0; i < fd->global_var_count; i++) {
+ JSGlobalVar *hf = &fd->global_vars[i];
if (hf->var_name == name)
return hf;
}
@@ -21689,9 +21654,9 @@ static JSHoistedDef *find_hoisted_def(JSFunctionDef *fd, JSAtom name)
}
-static JSHoistedDef *find_lexical_hoisted_def(JSFunctionDef *fd, JSAtom name)
+static JSGlobalVar *find_lexical_global_var(JSFunctionDef *fd, JSAtom name)
{
- JSHoistedDef *hf = find_hoisted_def(fd, name);
+ JSGlobalVar *hf = find_global_var(fd, name);
if (hf && hf->is_lexical)
return hf;
else
@@ -21711,7 +21676,7 @@ static int find_lexical_decl(JSContext *ctx, JSFunctionDef *fd, JSAtom name,
}
if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_GLOBAL) {
- if (find_lexical_hoisted_def(fd, name))
+ if (find_lexical_global_var(fd, name))
return GLOBAL_VAR_OFFSET;
}
return -1;
@@ -21800,6 +21765,7 @@ static int add_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
vd = &fd->vars[fd->var_count++];
memset(vd, 0, sizeof(*vd));
vd->var_name = JS_DupAtom(ctx, name);
+ vd->func_pool_idx = -1;
return fd->var_count - 1;
}
@@ -21823,22 +21789,47 @@ static int add_func_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
int idx = fd->func_var_idx;
if (idx < 0 && (idx = add_var(ctx, fd, name)) >= 0) {
fd->func_var_idx = idx;
- fd->vars[idx].is_func_var = TRUE;
+ fd->vars[idx].var_kind = JS_VAR_FUNCTION_NAME;
if (fd->js_mode & JS_MODE_STRICT)
fd->vars[idx].is_const = TRUE;
}
return idx;
}
-static int add_arguments_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
+static int add_arguments_var(JSContext *ctx, JSFunctionDef *fd)
{
int idx = fd->arguments_var_idx;
- if (idx < 0 && (idx = add_var(ctx, fd, name)) >= 0) {
+ if (idx < 0 && (idx = add_var(ctx, fd, JS_ATOM_arguments)) >= 0) {
fd->arguments_var_idx = idx;
}
return idx;
}
+/* add an argument definition in the argument scope. Only needed when
+ "eval()" may be called in the argument scope. Return 0 if OK. */
+static int add_arguments_arg(JSContext *ctx, JSFunctionDef *fd)
+{
+ int idx;
+ if (fd->arguments_arg_idx < 0) {
+ idx = find_var_in_scope(ctx, fd, JS_ATOM_arguments, ARG_SCOPE_INDEX);
+ if (idx < 0) {
+ /* XXX: the scope links are not fully updated. May be an
+ issue if there are child scopes of the argument
+ scope */
+ idx = add_var(ctx, fd, JS_ATOM_arguments);
+ if (idx < 0)
+ return -1;
+ fd->vars[idx].scope_next = fd->scopes[ARG_SCOPE_INDEX].first;
+ fd->scopes[ARG_SCOPE_INDEX].first = idx;
+ fd->vars[idx].scope_level = ARG_SCOPE_INDEX;
+ fd->vars[idx].is_lexical = TRUE;
+
+ fd->arguments_arg_idx = idx;
+ }
+ }
+ return 0;
+}
+
static int add_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
{
JSVarDef *vd;
@@ -21854,32 +21845,27 @@ static int add_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
vd = &fd->args[fd->arg_count++];
memset(vd, 0, sizeof(*vd));
vd->var_name = JS_DupAtom(ctx, name);
+ vd->func_pool_idx = -1;
return fd->arg_count - 1;
}
-/* add a Hoisted definition for a function (cpool_idx >= 0) or a
- global variable (cpool_idx = -1) */
-static JSHoistedDef *add_hoisted_def(JSContext *ctx,
- JSFunctionDef *s, int cpool_idx,
- JSAtom name, int var_idx, BOOL is_lexical)
+/* add a global variable definition */
+static JSGlobalVar *add_global_var(JSContext *ctx, JSFunctionDef *s,
+ JSAtom name)
{
- JSHoistedDef *hf;
+ JSGlobalVar *hf;
- if (js_resize_array(ctx, (void **)&s->hoisted_def,
- sizeof(s->hoisted_def[0]),
- &s->hoisted_def_size, s->hoisted_def_count + 1))
+ if (js_resize_array(ctx, (void **)&s->global_vars,
+ sizeof(s->global_vars[0]),
+ &s->global_var_size, s->global_var_count + 1))
return NULL;
- hf = &s->hoisted_def[s->hoisted_def_count++];
- hf->cpool_idx = cpool_idx;
- hf->force_init = 0;
- hf->is_lexical = is_lexical;
+ hf = &s->global_vars[s->global_var_count++];
+ hf->cpool_idx = -1;
+ hf->force_init = FALSE;
+ hf->is_lexical = FALSE;
hf->is_const = FALSE;
- hf->var_idx = var_idx;
hf->scope_level = s->scope_level;
- hf->var_name = JS_ATOM_NULL;
- if (name != JS_ATOM_NULL) {
- hf->var_name = JS_DupAtom(ctx, name);
- }
+ hf->var_name = JS_DupAtom(ctx, name);
return hf;
}
@@ -21924,7 +21910,7 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
goto redef_lex_error;
}
} else {
- if (fd->scope_level == 1) {
+ if (fd->scope_level == fd->body_scope) {
redef_lex_error:
/* redefining a scoped var in the same scope: error */
return js_parse_error(s, "invalid redefinition of lexical identifier");
@@ -21933,7 +21919,7 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
}
if (var_def_type != JS_VAR_DEF_FUNCTION_DECL &&
var_def_type != JS_VAR_DEF_NEW_FUNCTION_DECL &&
- fd->scope_level == 1 &&
+ fd->scope_level == fd->body_scope &&
find_arg(ctx, fd, name) >= 0) {
/* lexical variable redefines a parameter name */
return js_parse_error(s, "invalid redefinition of parameter name");
@@ -21944,8 +21930,8 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
}
if (fd->is_global_var) {
- JSHoistedDef *hf;
- hf = find_hoisted_def(fd, name);
+ JSGlobalVar *hf;
+ hf = find_global_var(fd, name);
if (hf && is_child_scope(ctx, fd, hf->scope_level,
fd->scope_level)) {
return js_parse_error(s, "invalid redefinition of global identifier");
@@ -21955,11 +21941,12 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
if (fd->is_eval &&
(fd->eval_type == JS_EVAL_TYPE_GLOBAL ||
fd->eval_type == JS_EVAL_TYPE_MODULE) &&
- fd->scope_level == 1) {
- JSHoistedDef *hf;
- hf = add_hoisted_def(s->ctx, fd, -1, name, -1, TRUE);
+ fd->scope_level == fd->body_scope) {
+ JSGlobalVar *hf;
+ hf = add_global_var(s->ctx, fd, name);
if (!hf)
return -1;
+ hf->is_lexical = TRUE;
hf->is_const = (var_def_type == JS_VAR_DEF_CONST);
idx = GLOBAL_VAR_OFFSET;
} else {
@@ -21991,13 +21978,13 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
return js_parse_error(s, "invalid redefinition of lexical identifier");
}
if (fd->is_global_var) {
- JSHoistedDef *hf;
- hf = find_hoisted_def(fd, name);
+ JSGlobalVar *hf;
+ hf = find_global_var(fd, name);
if (hf && hf->is_lexical && hf->scope_level == fd->scope_level &&
fd->eval_type == JS_EVAL_TYPE_MODULE) {
goto invalid_lexical_redefinition;
}
- hf = add_hoisted_def(s->ctx, fd, -1, name, -1, FALSE);
+ hf = add_global_var(s->ctx, fd, name);
if (!hf)
return -1;
idx = GLOBAL_VAR_OFFSET;
@@ -22010,7 +21997,7 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
if (idx >= 0) {
if (name == JS_ATOM_arguments && fd->has_arguments_binding)
fd->arguments_var_idx = idx;
- fd->vars[idx].func_pool_or_scope_idx = fd->scope_level;
+ fd->vars[idx].scope_next = fd->scope_level;
}
}
break;
@@ -22052,8 +22039,9 @@ static __exception int js_parse_function_decl2(JSParseState *s,
int function_line_num,
JSParseExportEnum export_flag,
JSFunctionDef **pfd);
-static __exception int js_parse_assign_expr(JSParseState *s, int in_accepted);
-static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag);
+static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags);
+static __exception int js_parse_assign_expr(JSParseState *s);
+static __exception int js_parse_unary(JSParseState *s, int parse_flags);
static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
JSAtom label_name,
int label_break, int label_cont,
@@ -22385,8 +22373,9 @@ static BOOL is_regexp_allowed(int tok)
}
}
-#define SKIP_HAS_SEMI (1 << 0)
-#define SKIP_HAS_ELLIPSIS (1 << 1)
+#define SKIP_HAS_SEMI (1 << 0)
+#define SKIP_HAS_ELLIPSIS (1 << 1)
+#define SKIP_HAS_ASSIGNMENT (1 << 2)
/* XXX: improve speed with early bailout */
/* XXX: no longer works if regexps are present. Could use previous
@@ -22459,7 +22448,10 @@ static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_
bits |= SKIP_HAS_ELLIPSIS;
}
break;
-
+ case '=':
+ bits |= SKIP_HAS_ASSIGNMENT;
+ break;
+
case TOK_DIV_ASSIGN:
tok_len = 2;
goto parse_regexp;
@@ -22574,7 +22566,7 @@ static __exception int js_parse_object_literal(JSParseState *s)
if (s->token.val == TOK_ELLIPSIS) {
if (next_token(s))
return -1;
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
emit_op(s, OP_null); /* dummy excludeList */
emit_op(s, OP_copy_data_properties);
@@ -22633,7 +22625,7 @@ static __exception int js_parse_object_literal(JSParseState *s)
} else {
if (js_parse_expect(s, ':'))
goto fail;
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
goto fail;
if (name == JS_ATOM_NULL) {
set_object_name_computed(s);
@@ -22668,8 +22660,23 @@ static __exception int js_parse_object_literal(JSParseState *s)
return -1;
}
-static __exception int js_parse_postfix_expr(JSParseState *s,
- BOOL accept_lparen);
+/* allow the 'in' binary operator */
+#define PF_IN_ACCEPTED (1 << 0)
+/* allow function calls parsing in js_parse_postfix_expr() */
+#define PF_POSTFIX_CALL (1 << 1)
+/* allow arrow functions parsing in js_parse_postfix_expr() */
+#define PF_ARROW_FUNC (1 << 2)
+/* allow the exponentiation operator in js_parse_unary() */
+#define PF_POW_ALLOWED (1 << 3)
+/* forbid the exponentiation operator in js_parse_unary() */
+#define PF_POW_FORBIDDEN (1 << 4)
+
+static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags);
+
+static __exception int js_parse_left_hand_side_expr(JSParseState *s)
+{
+ return js_parse_postfix_expr(s, PF_POSTFIX_CALL);
+}
/* XXX: is there is nicer solution ? */
static __exception int js_parse_class_default_ctor(JSParseState *s,
@@ -22873,8 +22880,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
class_flags = JS_DEFINE_CLASS_HAS_HERITAGE;
if (next_token(s))
goto fail;
- /* XXX: the grammar only allows LeftHandSideExpression */
- if (js_parse_postfix_expr(s, TRUE))
+ if (js_parse_left_hand_side_expr(s))
goto fail;
} else {
emit_op(s, OP_undefined);
@@ -23081,7 +23087,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
if (s->token.val == '=') {
if (next_token(s))
goto fail;
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
goto fail;
} else {
emit_op(s, OP_undefined);
@@ -23285,7 +23291,7 @@ static __exception int js_parse_array_literal(JSParseState *s)
while (s->token.val != ']' && idx < 32) {
if (s->token.val == ',' || s->token.val == TOK_ELLIPSIS)
break;
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
idx++;
/* accept trailing comma */
@@ -23306,7 +23312,7 @@ static __exception int js_parse_array_literal(JSParseState *s)
break;
need_length = TRUE;
if (s->token.val != ',') {
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
emit_op(s, OP_define_field);
emit_u32(s, __JS_AtomFromUInt32(idx));
@@ -23341,7 +23347,7 @@ static __exception int js_parse_array_literal(JSParseState *s)
if (s->token.val == TOK_ELLIPSIS) {
if (next_token(s))
return -1;
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
#if 1
emit_op(s, OP_append);
@@ -23373,7 +23379,7 @@ static __exception int js_parse_array_literal(JSParseState *s)
} else {
need_length = TRUE;
if (s->token.val != ',') {
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
/* a idx val */
emit_op(s, OP_define_array_el);
@@ -23781,6 +23787,8 @@ fail:
return JS_ATOM_NULL;
}
+/* Return -1 if error, 0 if no initializer, 1 if an initializer is
+ present at the top level. */
static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
int hasval, int has_ellipsis,
BOOL allow_initializer)
@@ -23789,7 +23797,8 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
int start_addr, assign_addr;
JSAtom prop_name, var_name;
int opcode, scope, tok1, skip_bits;
-
+ BOOL has_initializer;
+
if (has_ellipsis < 0) {
/* pre-parse destructuration target for spread detection */
js_parse_skip_parens_token(s, &skip_bits, FALSE);
@@ -23842,7 +23851,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
label_lvalue = -1;
depth_lvalue = 0;
} else {
- if (js_parse_postfix_expr(s, TRUE))
+ if (js_parse_left_hand_side_expr(s))
return -1;
if (get_lvalue(s, &opcode, &scope, &var_name,
@@ -23898,7 +23907,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
emit_op(s, OP_get_field2);
emit_u32(s, prop_name);
}
- if (js_parse_destructuring_element(s, tok, is_arg, TRUE, -1, TRUE))
+ if (js_parse_destructuring_element(s, tok, is_arg, TRUE, -1, TRUE) < 0)
return -1;
if (s->token.val == '}')
break;
@@ -23935,7 +23944,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
if (var_name == JS_ATOM_NULL)
goto prop_error;
} else {
- if (js_parse_postfix_expr(s, TRUE))
+ if (js_parse_left_hand_side_expr(s))
goto prop_error;
lvalue:
if (get_lvalue(s, &opcode, &scope, &var_name,
@@ -24033,7 +24042,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
if (next_token(s))
goto var_error;
emit_op(s, OP_drop);
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
goto var_error;
if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)
set_object_name(s, var_name);
@@ -24097,7 +24106,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
emit_u8(s, 0);
emit_op(s, OP_drop);
}
- if (js_parse_destructuring_element(s, tok, is_arg, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE))
+ if (js_parse_destructuring_element(s, tok, is_arg, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
return -1;
} else {
var_name = JS_ATOM_NULL;
@@ -24111,7 +24120,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
opcode = OP_scope_get_var;
scope = s->cur_func->scope_level;
} else {
- if (js_parse_postfix_expr(s, TRUE))
+ if (js_parse_left_hand_side_expr(s))
return -1;
if (get_lvalue(s, &opcode, &scope, &var_name,
&label_lvalue, &enum_depth, FALSE, '[')) {
@@ -24135,7 +24144,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
if (next_token(s))
goto var_error;
emit_op(s, OP_drop);
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
goto var_error;
if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)
set_object_name(s, var_name);
@@ -24170,10 +24179,11 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
emit_label(s, label_parse);
if (hasval)
emit_op(s, OP_drop);
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
emit_goto(s, OP_goto, label_assign);
emit_label(s, label_done);
+ has_initializer = TRUE;
} else {
/* normally hasval is true except if
js_parse_skip_parens_token() was wrong in the parsing */
@@ -24186,8 +24196,9 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
memset(s->cur_func->byte_code.buf + start_addr, OP_nop,
assign_addr - start_addr);
s->cur_func->label_slots[label_parse].ref_count--;
+ has_initializer = FALSE;
}
- return 0;
+ return has_initializer;
prop_error:
JS_FreeAtom(s->ctx, prop_name);
@@ -24220,10 +24231,12 @@ static void optional_chain_test(JSParseState *s, int *poptional_chaining_label,
emit_label(s, label_next);
}
-static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen)
+/* allowed parse_flags: PF_POSTFIX_CALL, PF_ARROW_FUNC */
+static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
{
FuncCallType call_type;
int optional_chaining_label;
+ BOOL accept_lparen = (parse_flags & PF_POSTFIX_CALL) != 0;
call_type = FUNC_CALL_NORMAL;
switch(s->token.val) {
@@ -24321,7 +24334,8 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
}
break;
case '(':
- if (js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) {
+ if ((parse_flags & PF_ARROW_FUNC) &&
+ js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) {
if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
JS_FUNC_NORMAL, JS_ATOM_NULL,
s->token.ptr, s->token.line_num))
@@ -24369,7 +24383,8 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
if (s->token.u.ident.is_reserved) {
return js_parse_error_reserved_identifier(s);
}
- if (peek_token(s, TRUE) == TOK_ARROW) {
+ if ((parse_flags & PF_ARROW_FUNC) &&
+ peek_token(s, TRUE) == TOK_ARROW) {
if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
JS_FUNC_NORMAL, JS_ATOM_NULL,
s->token.ptr, s->token.line_num))
@@ -24388,10 +24403,11 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
JS_FUNC_ASYNC, JS_ATOM_NULL,
source_ptr, source_line_num))
return -1;
- } else if ((s->token.val == '(' &&
- js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) ||
- (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&
- peek_token(s, TRUE) == TOK_ARROW)) {
+ } else if ((parse_flags & PF_ARROW_FUNC) &&
+ ((s->token.val == '(' &&
+ js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) ||
+ (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&
+ peek_token(s, TRUE) == TOK_ARROW))) {
if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
JS_FUNC_ASYNC, JS_ATOM_NULL,
source_ptr, source_line_num))
@@ -24421,7 +24437,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
{
int skip_bits;
if (js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {
- if (js_parse_destructuring_element(s, 0, 0, FALSE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE))
+ if (js_parse_destructuring_element(s, 0, 0, FALSE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
return -1;
} else {
if (s->token.val == '{') {
@@ -24450,7 +24466,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
emit_atom(s, JS_ATOM_new_target);
emit_u16(s, 0);
} else {
- if (js_parse_postfix_expr(s, FALSE))
+ if (js_parse_postfix_expr(s, 0))
return -1;
accept_lparen = TRUE;
if (s->token.val != '(') {
@@ -24503,7 +24519,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
return -1;
if (!accept_lparen)
return js_parse_error(s, "invalid use of 'import()'");
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
if (js_parse_expect(s, ')'))
return -1;
@@ -24636,7 +24652,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
}
if (s->token.val == TOK_ELLIPSIS)
break;
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
arg_count++;
if (s->token.val == ')')
@@ -24656,7 +24672,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
if (s->token.val == TOK_ELLIPSIS) {
if (next_token(s))
return -1;
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
#if 1
/* XXX: could pass is_last indicator? */
@@ -24687,7 +24703,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
emit_op(s, OP_nip1);
#endif
} else {
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
/* array idx val */
emit_op(s, OP_define_array_el);
@@ -24789,16 +24805,19 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
} else if (s->token.val == '.') {
if (next_token(s))
return -1;
+ parse_property:
if (s->token.val == TOK_PRIVATE_NAME) {
/* private class field */
if (get_prev_opcode(fd) == OP_get_super) {
return js_parse_error(s, "private class field forbidden after super");
}
+ if (has_optional_chain) {
+ optional_chain_test(s, &optional_chaining_label, 1);
+ }
emit_op(s, OP_scope_get_private_field);
emit_atom(s, s->token.u.ident.atom);
emit_u16(s, s->cur_func->scope_level);
} else {
- parse_property:
if (!token_is_ident(s->token.val)) {
return js_parse_error(s, "expecting field name");
}
@@ -24857,7 +24876,7 @@ static __exception int js_parse_delete(JSParseState *s)
if (next_token(s))
return -1;
- if (js_parse_unary(s, -1))
+ if (js_parse_unary(s, PF_POW_FORBIDDEN))
return -1;
switch(opcode = get_prev_opcode(fd)) {
case OP_get_field:
@@ -24896,9 +24915,9 @@ static __exception int js_parse_delete(JSParseState *s)
case OP_scope_get_private_field:
return js_parse_error(s, "cannot delete a private class field");
case OP_get_super_value:
- emit_op(s, OP_throw_var);
+ emit_op(s, OP_throw_error);
emit_atom(s, JS_ATOM_NULL);
- emit_u8(s, JS_THROW_VAR_DELETE_SUPER);
+ emit_u8(s, JS_THROW_ERROR_DELETE_SUPER);
break;
default:
ret_true:
@@ -24909,7 +24928,8 @@ static __exception int js_parse_delete(JSParseState *s)
return 0;
}
-static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag)
+/* allowed parse_flags: PF_ARROW_FUNC, PF_POW_ALLOWED, PF_POW_FORBIDDEN */
+static __exception int js_parse_unary(JSParseState *s, int parse_flags)
{
int op;
@@ -24922,7 +24942,7 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag)
op = s->token.val;
if (next_token(s))
return -1;
- if (js_parse_unary(s, -1))
+ if (js_parse_unary(s, PF_POW_FORBIDDEN))
return -1;
switch(op) {
case '-':
@@ -24944,7 +24964,7 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag)
default:
abort();
}
- exponentiation_flag = 0;
+ parse_flags = 0;
break;
case TOK_DEC:
case TOK_INC:
@@ -24954,7 +24974,6 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag)
op = s->token.val;
if (next_token(s))
return -1;
- /* XXX: should parse LeftHandSideExpression */
if (js_parse_unary(s, 0))
return -1;
if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op))
@@ -24969,7 +24988,7 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag)
JSFunctionDef *fd;
if (next_token(s))
return -1;
- if (js_parse_unary(s, -1))
+ if (js_parse_unary(s, PF_POW_FORBIDDEN))
return -1;
/* reference access should not return an exception, so we
patch the get_var */
@@ -24978,13 +24997,13 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag)
fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_var_undef;
}
emit_op(s, OP_typeof);
- exponentiation_flag = 0;
+ parse_flags = 0;
}
break;
case TOK_DELETE:
if (js_parse_delete(s))
return -1;
- exponentiation_flag = 0;
+ parse_flags = 0;
break;
case TOK_AWAIT:
if (!(s->cur_func->func_kind & JS_FUNC_ASYNC))
@@ -24993,13 +25012,14 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag)
return js_parse_error(s, "await in default expression");
if (next_token(s))
return -1;
- if (js_parse_unary(s, -1))
+ if (js_parse_unary(s, PF_POW_FORBIDDEN))
return -1;
emit_op(s, OP_await);
- exponentiation_flag = 0;
+ parse_flags = 0;
break;
default:
- if (js_parse_postfix_expr(s, TRUE))
+ if (js_parse_postfix_expr(s, (parse_flags & PF_ARROW_FUNC) |
+ PF_POSTFIX_CALL))
return -1;
if (!s->got_lf &&
(s->token.val == TOK_DEC || s->token.val == TOK_INC)) {
@@ -25016,21 +25036,21 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag)
}
break;
}
- if (exponentiation_flag) {
+ if (parse_flags & (PF_POW_ALLOWED | PF_POW_FORBIDDEN)) {
#ifdef CONFIG_BIGNUM
if (s->token.val == TOK_POW || s->token.val == TOK_MATH_POW) {
/* Extended exponentiation syntax rules: we extend the ES7
grammar in order to have more intuitive semantics:
-2**2 evaluates to -4. */
if (!(s->cur_func->js_mode & JS_MODE_MATH)) {
- if (exponentiation_flag < 0) {
+ if (parse_flags & PF_POW_FORBIDDEN) {
JS_ThrowSyntaxError(s->ctx, "unparenthesized unary expression can't appear on the left-hand side of '**'");
return -1;
}
}
if (next_token(s))
return -1;
- if (js_parse_unary(s, 1))
+ if (js_parse_unary(s, PF_POW_ALLOWED))
return -1;
emit_op(s, OP_pow);
}
@@ -25041,13 +25061,13 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag)
regarding the precedence of prefix operators and the
postifx exponential, ES7 specifies that -2**2 is a
syntax error. */
- if (exponentiation_flag < 0) {
+ if (parse_flags & PF_POW_FORBIDDEN) {
JS_ThrowSyntaxError(s->ctx, "unparenthesized unary expression can't appear on the left-hand side of '**'");
return -1;
}
if (next_token(s))
return -1;
- if (js_parse_unary(s, 1))
+ if (js_parse_unary(s, PF_POW_ALLOWED))
return -1;
emit_op(s, OP_pow);
}
@@ -25056,15 +25076,17 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag)
return 0;
}
+/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
static __exception int js_parse_expr_binary(JSParseState *s, int level,
- BOOL in_accepted)
+ int parse_flags)
{
int op, opcode;
if (level == 0) {
- return js_parse_unary(s, 1);
+ return js_parse_unary(s, (parse_flags & PF_ARROW_FUNC) |
+ PF_POW_ALLOWED);
}
- if (js_parse_expr_binary(s, level - 1, in_accepted))
+ if (js_parse_expr_binary(s, level - 1, parse_flags))
return -1;
for(;;) {
op = s->token.val;
@@ -25134,7 +25156,7 @@ static __exception int js_parse_expr_binary(JSParseState *s, int level,
opcode = OP_instanceof;
break;
case TOK_IN:
- if (in_accepted) {
+ if (parse_flags & PF_IN_ACCEPTED) {
opcode = OP_in;
} else {
return 0;
@@ -25194,23 +25216,24 @@ static __exception int js_parse_expr_binary(JSParseState *s, int level,
}
if (next_token(s))
return -1;
- if (js_parse_expr_binary(s, level - 1, in_accepted))
+ if (js_parse_expr_binary(s, level - 1, parse_flags & ~PF_ARROW_FUNC))
return -1;
emit_op(s, opcode);
}
return 0;
}
+/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
static __exception int js_parse_logical_and_or(JSParseState *s, int op,
- BOOL in_accepted)
+ int parse_flags)
{
int label1;
if (op == TOK_LAND) {
- if (js_parse_expr_binary(s, 8, in_accepted))
+ if (js_parse_expr_binary(s, 8, parse_flags))
return -1;
} else {
- if (js_parse_logical_and_or(s, TOK_LAND, in_accepted))
+ if (js_parse_logical_and_or(s, TOK_LAND, parse_flags))
return -1;
}
if (s->token.val == op) {
@@ -25224,10 +25247,11 @@ static __exception int js_parse_logical_and_or(JSParseState *s, int op,
emit_op(s, OP_drop);
if (op == TOK_LAND) {
- if (js_parse_expr_binary(s, 8, in_accepted))
+ if (js_parse_expr_binary(s, 8, parse_flags & ~PF_ARROW_FUNC))
return -1;
} else {
- if (js_parse_logical_and_or(s, TOK_LAND, in_accepted))
+ if (js_parse_logical_and_or(s, TOK_LAND,
+ parse_flags & ~PF_ARROW_FUNC))
return -1;
}
if (s->token.val != op) {
@@ -25242,11 +25266,11 @@ static __exception int js_parse_logical_and_or(JSParseState *s, int op,
return 0;
}
-static __exception int js_parse_coalesce_expr(JSParseState *s, BOOL in_accepted)
+static __exception int js_parse_coalesce_expr(JSParseState *s, int parse_flags)
{
int label1;
- if (js_parse_logical_and_or(s, TOK_LOR, in_accepted))
+ if (js_parse_logical_and_or(s, TOK_LOR, parse_flags))
return -1;
if (s->token.val == TOK_DOUBLE_QUESTION_MARK) {
label1 = new_label(s);
@@ -25259,7 +25283,7 @@ static __exception int js_parse_coalesce_expr(JSParseState *s, BOOL in_accepted)
emit_goto(s, OP_if_false, label1);
emit_op(s, OP_drop);
- if (js_parse_expr_binary(s, 8, in_accepted))
+ if (js_parse_expr_binary(s, 8, parse_flags & ~PF_ARROW_FUNC))
return -1;
if (s->token.val != TOK_DOUBLE_QUESTION_MARK)
break;
@@ -25269,18 +25293,19 @@ static __exception int js_parse_coalesce_expr(JSParseState *s, BOOL in_accepted)
return 0;
}
-static __exception int js_parse_cond_expr(JSParseState *s, BOOL in_accepted)
+/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
+static __exception int js_parse_cond_expr(JSParseState *s, int parse_flags)
{
int label1, label2;
- if (js_parse_coalesce_expr(s, in_accepted))
+ if (js_parse_coalesce_expr(s, parse_flags))
return -1;
if (s->token.val == '?') {
if (next_token(s))
return -1;
label1 = emit_goto(s, OP_if_false, -1);
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
if (js_parse_expect(s, ':'))
return -1;
@@ -25289,7 +25314,7 @@ static __exception int js_parse_cond_expr(JSParseState *s, BOOL in_accepted)
emit_label(s, label1);
- if (js_parse_assign_expr(s, in_accepted))
+ if (js_parse_assign_expr2(s, parse_flags & PF_IN_ACCEPTED))
return -1;
emit_label(s, label2);
@@ -25299,14 +25324,16 @@ static __exception int js_parse_cond_expr(JSParseState *s, BOOL in_accepted)
static void emit_return(JSParseState *s, BOOL hasval);
-static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted)
+/* allowed parse_flags: PF_IN_ACCEPTED */
+static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
{
int opcode, op, scope;
JSAtom name0 = JS_ATOM_NULL;
JSAtom name;
if (s->token.val == TOK_YIELD) {
- BOOL is_star = FALSE;
+ BOOL is_star = FALSE, is_async;
+
if (!(s->cur_func->func_kind & JS_FUNC_GENERATOR))
return js_parse_error(s, "unexpected 'yield' keyword");
if (!s->cur_func->in_function_body)
@@ -25323,109 +25350,120 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted)
if (next_token(s))
return -1;
}
- if (js_parse_assign_expr(s, in_accepted))
+ if (js_parse_assign_expr2(s, parse_flags))
return -1;
} else {
emit_op(s, OP_undefined);
}
- if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
+ is_async = (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR);
+
+ if (is_star) {
int label_loop, label_return, label_next;
int label_return1, label_yield, label_throw, label_throw1;
int label_throw2;
- if (is_star) {
- label_loop = new_label(s);
- label_yield = new_label(s);
-
- emit_op(s, OP_for_await_of_start);
+ label_loop = new_label(s);
+ label_yield = new_label(s);
- /* remove the catch offset (XXX: could avoid pushing back
- undefined) */
- emit_op(s, OP_drop);
- emit_op(s, OP_undefined);
-
- emit_op(s, OP_undefined); /* initial value */
+ emit_op(s, is_async ? OP_for_await_of_start : OP_for_of_start);
- emit_label(s, label_loop);
- emit_op(s, OP_async_iterator_next);
+ /* remove the catch offset (XXX: could avoid pushing back
+ undefined) */
+ emit_op(s, OP_drop);
+ emit_op(s, OP_undefined);
+
+ emit_op(s, OP_undefined); /* initial value */
+
+ emit_label(s, label_loop);
+ emit_op(s, OP_iterator_next);
+ if (is_async)
emit_op(s, OP_await);
- emit_op(s, OP_iterator_get_value_done);
- label_next = emit_goto(s, OP_if_true, -1); /* end of loop */
+ emit_op(s, OP_iterator_check_object);
+ emit_op(s, OP_get_field2);
+ emit_atom(s, JS_ATOM_done);
+ label_next = emit_goto(s, OP_if_true, -1); /* end of loop */
+ emit_label(s, label_yield);
+ if (is_async) {
+ /* OP_async_yield_star takes the value as parameter */
+ emit_op(s, OP_get_field);
+ emit_atom(s, JS_ATOM_value);
emit_op(s, OP_await);
- emit_label(s, label_yield);
emit_op(s, OP_async_yield_star);
- emit_op(s, OP_dup);
- label_return = emit_goto(s, OP_if_true, -1);
- emit_op(s, OP_drop);
- emit_goto(s, OP_goto, label_loop);
-
- emit_label(s, label_return);
- emit_op(s, OP_push_i32);
- emit_u32(s, 2);
- emit_op(s, OP_strict_eq);
- label_throw = emit_goto(s, OP_if_true, -1);
-
- /* return handling */
- emit_op(s, OP_await);
- emit_op(s, OP_async_iterator_get);
- emit_u8(s, 0);
- label_return1 = emit_goto(s, OP_if_true, -1);
+ } else {
+ /* OP_yield_star takes (value, done) as parameter */
+ emit_op(s, OP_yield_star);
+ }
+ emit_op(s, OP_dup);
+ label_return = emit_goto(s, OP_if_true, -1);
+ emit_op(s, OP_drop);
+ emit_goto(s, OP_goto, label_loop);
+
+ emit_label(s, label_return);
+ emit_op(s, OP_push_i32);
+ emit_u32(s, 2);
+ emit_op(s, OP_strict_eq);
+ label_throw = emit_goto(s, OP_if_true, -1);
+
+ /* return handling */
+ if (is_async)
emit_op(s, OP_await);
- emit_op(s, OP_iterator_get_value_done);
- /* XXX: the spec does not indicate that an await should be
- performed in case done = true, but the tests assume it */
- emit_goto(s, OP_if_false, label_yield);
-
- emit_label(s, label_return1);
- emit_op(s, OP_nip);
- emit_op(s, OP_nip);
- emit_op(s, OP_nip);
- emit_return(s, TRUE);
-
- /* throw handling */
- emit_label(s, label_throw);
- emit_op(s, OP_async_iterator_get);
- emit_u8(s, 1);
- label_throw1 = emit_goto(s, OP_if_true, -1);
+ emit_op(s, OP_iterator_call);
+ emit_u8(s, 0);
+ label_return1 = emit_goto(s, OP_if_true, -1);
+ if (is_async)
emit_op(s, OP_await);
- emit_op(s, OP_iterator_get_value_done);
- emit_goto(s, OP_if_false, label_yield);
- /* XXX: the spec does not indicate that an await should be
- performed in case done = true, but the tests assume it */
+ emit_op(s, OP_iterator_check_object);
+ emit_op(s, OP_get_field2);
+ emit_atom(s, JS_ATOM_done);
+ emit_goto(s, OP_if_false, label_yield);
+
+ emit_op(s, OP_get_field);
+ emit_atom(s, JS_ATOM_value);
+
+ emit_label(s, label_return1);
+ emit_op(s, OP_nip);
+ emit_op(s, OP_nip);
+ emit_op(s, OP_nip);
+ emit_return(s, TRUE);
+
+ /* throw handling */
+ emit_label(s, label_throw);
+ emit_op(s, OP_iterator_call);
+ emit_u8(s, 1);
+ label_throw1 = emit_goto(s, OP_if_true, -1);
+ if (is_async)
emit_op(s, OP_await);
- emit_goto(s, OP_goto, label_next);
- /* close the iterator and throw a type error exception */
- emit_label(s, label_throw1);
- emit_op(s, OP_async_iterator_get);
- emit_u8(s, 0);
- label_throw2 = emit_goto(s, OP_if_true, -1);
+ emit_op(s, OP_iterator_check_object);
+ emit_op(s, OP_get_field2);
+ emit_atom(s, JS_ATOM_done);
+ emit_goto(s, OP_if_false, label_yield);
+ emit_goto(s, OP_goto, label_next);
+ /* close the iterator and throw a type error exception */
+ emit_label(s, label_throw1);
+ emit_op(s, OP_iterator_call);
+ emit_u8(s, 2);
+ label_throw2 = emit_goto(s, OP_if_true, -1);
+ if (is_async)
emit_op(s, OP_await);
- emit_label(s, label_throw2);
- emit_op(s, OP_async_iterator_get);
- emit_u8(s, 2); /* throw the type error exception */
- emit_op(s, OP_drop); /* never reached */
+ emit_label(s, label_throw2);
- emit_label(s, label_next);
- emit_op(s, OP_nip); /* keep the value associated with
- done = true */
- emit_op(s, OP_nip);
- emit_op(s, OP_nip);
- } else {
- emit_op(s, OP_await);
- emit_op(s, OP_yield);
- label_next = emit_goto(s, OP_if_false, -1);
- emit_return(s, TRUE);
- emit_label(s, label_next);
- }
+ emit_op(s, OP_throw_error);
+ emit_atom(s, JS_ATOM_NULL);
+ emit_u8(s, JS_THROW_ERROR_ITERATOR_THROW);
+
+ emit_label(s, label_next);
+ emit_op(s, OP_get_field);
+ emit_atom(s, JS_ATOM_value);
+ emit_op(s, OP_nip); /* keep the value associated with
+ done = true */
+ emit_op(s, OP_nip);
+ emit_op(s, OP_nip);
} else {
int label_next;
- if (is_star) {
- emit_op(s, OP_for_of_start);
- emit_op(s, OP_drop); /* drop the catch offset */
- emit_op(s, OP_yield_star);
- } else {
- emit_op(s, OP_yield);
- }
+
+ if (is_async)
+ emit_op(s, OP_await);
+ emit_op(s, OP_yield);
label_next = emit_goto(s, OP_if_false, -1);
emit_return(s, TRUE);
emit_label(s, label_next);
@@ -25436,7 +25474,7 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted)
/* name0 is used to check for OP_set_name pattern, not duplicated */
name0 = s->token.u.ident.atom;
}
- if (js_parse_cond_expr(s, in_accepted))
+ if (js_parse_cond_expr(s, parse_flags | PF_ARROW_FUNC))
return -1;
op = s->token.val;
@@ -25447,7 +25485,7 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted)
if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, (op != '='), op) < 0)
return -1;
- if (js_parse_assign_expr(s, in_accepted)) {
+ if (js_parse_assign_expr2(s, parse_flags)) {
JS_FreeAtom(s->ctx, name);
return -1;
}
@@ -25491,7 +25529,7 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted)
-1);
emit_op(s, OP_drop);
- if (js_parse_assign_expr(s, in_accepted)) {
+ if (js_parse_assign_expr2(s, parse_flags)) {
JS_FreeAtom(s->ctx, name);
return -1;
}
@@ -25533,11 +25571,17 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted)
return 0;
}
-static __exception int js_parse_expr2(JSParseState *s, BOOL in_accepted)
+static __exception int js_parse_assign_expr(JSParseState *s)
+{
+ return js_parse_assign_expr2(s, PF_IN_ACCEPTED);
+}
+
+/* allowed parse_flags: PF_IN_ACCEPTED */
+static __exception int js_parse_expr2(JSParseState *s, int parse_flags)
{
BOOL comma = FALSE;
for(;;) {
- if (js_parse_assign_expr(s, in_accepted))
+ if (js_parse_assign_expr2(s, parse_flags))
return -1;
if (comma) {
/* prevent get_lvalue from using the last expression
@@ -25559,7 +25603,7 @@ static __exception int js_parse_expr2(JSParseState *s, BOOL in_accepted)
static __exception int js_parse_expr(JSParseState *s)
{
- return js_parse_expr2(s, TRUE);
+ return js_parse_expr2(s, PF_IN_ACCEPTED);
}
static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
@@ -25655,12 +25699,25 @@ static void emit_return(JSParseState *s, BOOL hasval)
}
emit_op(s, OP_iterator_close_return);
if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
- int label_next;
- emit_op(s, OP_async_iterator_close);
+ int label_next, label_next2;
+
+ emit_op(s, OP_drop); /* catch offset */
+ emit_op(s, OP_drop); /* next */
+ emit_op(s, OP_get_field2);
+ emit_atom(s, JS_ATOM_return);
+ /* stack: iter_obj return_func */
+ emit_op(s, OP_dup);
+ emit_op(s, OP_is_undefined_or_null);
label_next = emit_goto(s, OP_if_true, -1);
+ emit_op(s, OP_call_method);
+ emit_u16(s, 0);
+ emit_op(s, OP_iterator_check_object);
emit_op(s, OP_await);
+ label_next2 = emit_goto(s, OP_goto, -1);
emit_label(s, label_next);
emit_op(s, OP_drop);
+ emit_label(s, label_next2);
+ emit_op(s, OP_drop);
} else {
emit_op(s, OP_iterator_close);
}
@@ -25748,7 +25805,8 @@ static __exception int js_parse_block(JSParseState *s)
return 0;
}
-static __exception int js_parse_var(JSParseState *s, BOOL in_accepted, int tok,
+/* allowed parse_flags: PF_IN_ACCEPTED */
+static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok,
BOOL export_flag)
{
JSContext *ctx = s->ctx;
@@ -25788,7 +25846,7 @@ static __exception int js_parse_var(JSParseState *s, BOOL in_accepted, int tok,
emit_u16(s, fd->scope_level);
if (get_lvalue(s, &opcode, &scope, &name1, &label, NULL, FALSE, '=') < 0)
goto var_error;
- if (js_parse_assign_expr(s, in_accepted)) {
+ if (js_parse_assign_expr2(s, parse_flags)) {
JS_FreeAtom(ctx, name1);
goto var_error;
}
@@ -25796,7 +25854,7 @@ static __exception int js_parse_var(JSParseState *s, BOOL in_accepted, int tok,
put_lvalue(s, opcode, scope, name1, label,
PUT_LVALUE_NOKEEP, FALSE);
} else {
- if (js_parse_assign_expr(s, in_accepted))
+ if (js_parse_assign_expr2(s, parse_flags))
goto var_error;
set_object_name(s, name);
emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ?
@@ -25823,7 +25881,7 @@ static __exception int js_parse_var(JSParseState *s, BOOL in_accepted, int tok,
if ((s->token.val == '[' || s->token.val == '{')
&& js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {
emit_op(s, OP_undefined);
- if (js_parse_destructuring_element(s, tok, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE))
+ if (js_parse_destructuring_element(s, tok, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
return -1;
} else {
return js_parse_error(s, "variable name expected");
@@ -25952,7 +26010,7 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
if (s->token.val == '[' || s->token.val == '{') {
- if (js_parse_destructuring_element(s, tok, 0, TRUE, -1, FALSE))
+ if (js_parse_destructuring_element(s, tok, 0, TRUE, -1, FALSE) < 0)
return -1;
has_destructuring = TRUE;
} else {
@@ -25978,11 +26036,11 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
int skip_bits;
if ((s->token.val == '[' || s->token.val == '{')
&& ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == TOK_IN || tok1 == TOK_OF)) {
- if (js_parse_destructuring_element(s, 0, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE))
+ if (js_parse_destructuring_element(s, 0, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
return -1;
} else {
int lvalue_label;
- if (js_parse_postfix_expr(s, TRUE))
+ if (js_parse_left_hand_side_expr(s))
return -1;
if (get_lvalue(s, &opcode, &scope, &var_name, &lvalue_label,
NULL, FALSE, TOK_FOR))
@@ -26002,7 +26060,7 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
/* parse and evaluate initializer prior to evaluating the
object (only used with "for in" with a non lexical variable
in non strict mode */
- if (next_token(s) || js_parse_assign_expr(s, FALSE)) {
+ if (next_token(s) || js_parse_assign_expr2(s, 0)) {
JS_FreeAtom(ctx, var_name);
return -1;
}
@@ -26035,7 +26093,7 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
if (next_token(s))
return -1;
if (is_for_of) {
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
} else {
if (js_parse_expr(s))
@@ -26088,7 +26146,11 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
if (is_for_of) {
if (is_async) {
/* call the next method */
- emit_op(s, OP_for_await_of_next);
+ /* stack: iter_obj next catch_offset */
+ emit_op(s, OP_dup3);
+ emit_op(s, OP_drop);
+ emit_op(s, OP_call_method);
+ emit_u16(s, 0);
/* get the result of the promise */
emit_op(s, OP_await);
/* unwrap the value and done values */
@@ -26646,7 +26708,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
if (s->token.val == '[' || s->token.val == '{') {
/* XXX: TOK_LET is not completely correct */
- if (js_parse_destructuring_element(s, TOK_LET, 0, TRUE, -1, TRUE))
+ if (js_parse_destructuring_element(s, TOK_LET, 0, TRUE, -1, TRUE) < 0)
goto fail;
} else {
js_parse_error(s, "identifier expected");
@@ -26712,18 +26774,37 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
}
emit_label(s, label_finally);
if (s->token.val == TOK_FINALLY) {
- int saved_eval_ret_idx;
+ int saved_eval_ret_idx = 0; /* avoid warning */
+
if (next_token(s))
goto fail;
/* on the stack: ret_value gosub_ret_value */
push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL,
-1, -1, 2);
- saved_eval_ret_idx = s->cur_func->eval_ret_idx;
- s->cur_func->eval_ret_idx = -1;
- /* 'finally' does not update eval_ret */
+
+ if (s->cur_func->eval_ret_idx >= 0) {
+ /* 'finally' updates eval_ret only if not a normal
+ termination */
+ saved_eval_ret_idx =
+ add_var(s->ctx, s->cur_func, JS_ATOM__ret_);
+ if (saved_eval_ret_idx < 0)
+ goto fail;
+ emit_op(s, OP_get_loc);
+ emit_u16(s, s->cur_func->eval_ret_idx);
+ emit_op(s, OP_put_loc);
+ emit_u16(s, saved_eval_ret_idx);
+ set_eval_ret_undefined(s);
+ }
+
if (js_parse_block(s))
goto fail;
- s->cur_func->eval_ret_idx = saved_eval_ret_idx;
+
+ if (s->cur_func->eval_ret_idx >= 0) {
+ emit_op(s, OP_get_loc);
+ emit_u16(s, saved_eval_ret_idx);
+ emit_op(s, OP_put_loc);
+ emit_u16(s, s->cur_func->eval_ret_idx);
+ }
pop_break_entry(s->cur_func);
}
emit_op(s, OP_ret);
@@ -27511,19 +27592,11 @@ static int exported_names_cmp(const void *p1, const void *p2, void *opaque)
static JSValue js_get_module_ns(JSContext *ctx, JSModuleDef *m);
-static int js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
- void *opaque)
+static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
+ void *opaque)
{
JSModuleDef *m = opaque;
- JSValue val, this_val = JS_MKPTR(JS_TAG_OBJECT, p);
-
- val = js_get_module_ns(ctx, m);
- if (JS_IsException(val))
- return -1;
- if (JS_DefinePropertyValue(ctx, this_val, atom, val,
- JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)
- return -1;
- return 0;
+ return js_get_module_ns(ctx, m);
}
static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m)
@@ -27741,7 +27814,7 @@ static int js_create_module_bytecode_function(JSContext *ctx, JSModuleDef *m)
return -1;
}
-/* must be done before js_instantiate_module() because of cyclic references */
+/* must be done before js_link_module() because of cyclic references */
static int js_create_module_function(JSContext *ctx, JSModuleDef *m)
{
BOOL is_c_module;
@@ -27784,7 +27857,7 @@ static int js_create_module_function(JSContext *ctx, JSModuleDef *m)
/* Prepare a module to be executed by resolving all the imported
variables. */
-static int js_instantiate_module(JSContext *ctx, JSModuleDef *m)
+static int js_link_module(JSContext *ctx, JSModuleDef *m)
{
int i;
JSImportEntry *mi;
@@ -27792,7 +27865,8 @@ static int js_instantiate_module(JSContext *ctx, JSModuleDef *m)
JSVarRef **var_refs, *var_ref;
JSObject *p;
BOOL is_c_module;
-
+ JSValue ret_val;
+
if (m->instantiated)
return 0;
m->instantiated = TRUE;
@@ -27806,7 +27880,7 @@ static int js_instantiate_module(JSContext *ctx, JSModuleDef *m)
for(i = 0; i < m->req_module_entries_count; i++) {
JSReqModuleEntry *rme = &m->req_module_entries[i];
- if (js_instantiate_module(ctx, rme->module) < 0)
+ if (js_link_module(ctx, rme->module) < 0)
goto fail;
}
@@ -27925,6 +27999,12 @@ static int js_instantiate_module(JSContext *ctx, JSModuleDef *m)
me->u.local.var_ref = var_ref;
}
}
+
+ /* initialize the global variables */
+ ret_val = JS_Call(ctx, m->func_obj, JS_TRUE, 0, NULL);
+ if (JS_IsException(ret_val))
+ goto fail;
+ JS_FreeValue(ctx, ret_val);
}
#ifdef DUMP_MODULE_RESOLVE
@@ -28324,7 +28404,7 @@ static __exception int js_parse_export(JSParseState *s)
s->token.ptr, s->token.line_num,
JS_PARSE_EXPORT_DEFAULT, NULL);
} else {
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
}
/* set the name of anonymous functions */
@@ -28567,7 +28647,9 @@ static JSFunctionDef *js_new_function_def(JSContext *ctx,
fd->last_opcode_pos = -1;
fd->func_name = JS_ATOM_NULL;
fd->var_object_idx = -1;
+ fd->arg_var_object_idx = -1;
fd->arguments_var_idx = -1;
+ fd->arguments_arg_idx = -1;
fd->func_var_idx = -1;
fd->eval_ret_idx = -1;
fd->this_var_idx = -1;
@@ -28576,13 +28658,14 @@ static JSFunctionDef *js_new_function_def(JSContext *ctx,
fd->home_object_var_idx = -1;
/* XXX: should distinguish arg, var and var object and body scopes */
- fd->scope_level = 0; /* 0: var/arg scope, 1:body scope */
- fd->scope_first = -1;
fd->scopes = fd->def_scope_array;
fd->scope_size = countof(fd->def_scope_array);
fd->scope_count = 1;
fd->scopes[0].first = -1;
fd->scopes[0].parent = -1;
+ fd->scope_level = 0; /* 0: var/arg scope */
+ fd->scope_first = -1;
+ fd->body_scope = -1;
fd->filename = JS_NewAtom(ctx, filename);
fd->line_num = line_num;
@@ -28663,10 +28746,10 @@ static void js_free_function_def(JSContext *ctx, JSFunctionDef *fd)
}
js_free(ctx, fd->args);
- for(i = 0; i < fd->hoisted_def_count; i++) {
- JS_FreeAtom(ctx, fd->hoisted_def[i].var_name);
+ for(i = 0; i < fd->global_var_count; i++) {
+ JS_FreeAtom(ctx, fd->global_vars[i].var_name);
}
- js_free(ctx, fd->hoisted_def);
+ js_free(ctx, fd->global_vars);
for(i = 0; i < fd->closure_var_count; i++) {
JSClosureVar *cv = &fd->closure_var[i];
@@ -29350,19 +29433,27 @@ static int resolve_pseudo_var(JSContext *ctx, JSFunctionDef *s,
switch(var_name) {
case JS_ATOM_home_object:
/* 'home_object' pseudo variable */
- var_idx = s->home_object_var_idx = add_var(ctx, s, var_name);
+ if (s->home_object_var_idx < 0)
+ s->home_object_var_idx = add_var(ctx, s, var_name);
+ var_idx = s->home_object_var_idx;
break;
case JS_ATOM_this_active_func:
/* 'this.active_func' pseudo variable */
- var_idx = s->this_active_func_var_idx = add_var(ctx, s, var_name);
+ if (s->this_active_func_var_idx < 0)
+ s->this_active_func_var_idx = add_var(ctx, s, var_name);
+ var_idx = s->this_active_func_var_idx;
break;
case JS_ATOM_new_target:
/* 'new.target' pseudo variable */
- var_idx = s->new_target_var_idx = add_var(ctx, s, var_name);
+ if (s->new_target_var_idx < 0)
+ s->new_target_var_idx = add_var(ctx, s, var_name);
+ var_idx = s->new_target_var_idx;
break;
case JS_ATOM_this:
/* 'this' pseudo variable */
- var_idx = s->this_var_idx = add_var_this(ctx, s);
+ if (s->this_var_idx < 0)
+ s->this_var_idx = add_var_this(ctx, s);
+ var_idx = s->this_var_idx;
break;
default:
var_idx = -1;
@@ -29371,18 +29462,32 @@ static int resolve_pseudo_var(JSContext *ctx, JSFunctionDef *s,
return var_idx;
}
+/* test if 'var_name' is in the variable object on the stack. If is it
+ the case, handle it and jump to 'label_done' */
+static void var_object_test(JSContext *ctx, JSFunctionDef *s,
+ JSAtom var_name, int op, DynBuf *bc,
+ int *plabel_done, BOOL is_with)
+{
+ dbuf_putc(bc, get_with_scope_opcode(op));
+ dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+ *plabel_done = new_label_fd(s, *plabel_done);
+ dbuf_put_u32(bc, *plabel_done);
+ dbuf_putc(bc, is_with);
+ update_label(s, *plabel_done, 1);
+ s->jump_size++;
+}
+
/* return the position of the next opcode */
static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
JSAtom var_name, int scope_level, int op,
DynBuf *bc, uint8_t *bc_buf,
- LabelSlot *ls, int pos_next, int arg_valid)
+ LabelSlot *ls, int pos_next)
{
int idx, var_idx, is_put;
int label_done;
- BOOL is_func_var = FALSE;
JSFunctionDef *fd;
JSVarDef *vd;
- BOOL is_pseudo_var;
+ BOOL is_pseudo_var, is_arg_scope;
label_done = -1;
@@ -29400,12 +29505,11 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
if (vd->var_name == var_name) {
if (op == OP_scope_put_var || op == OP_scope_make_ref) {
if (vd->is_const) {
- dbuf_putc(bc, OP_throw_var);
+ dbuf_putc(bc, OP_throw_error);
dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
dbuf_putc(bc, JS_THROW_VAR_RO);
goto done;
}
- is_func_var = vd->is_func_var;
}
var_idx = idx;
break;
@@ -29413,33 +29517,16 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
dbuf_putc(bc, OP_get_loc);
dbuf_put_u16(bc, idx);
- dbuf_putc(bc, get_with_scope_opcode(op));
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- label_done = new_label_fd(s, label_done);
- dbuf_put_u32(bc, label_done);
- dbuf_putc(bc, 1);
- update_label(s, label_done, 1);
- s->jump_size++;
+ var_object_test(ctx, s, var_name, op, bc, &label_done, 1);
}
idx = vd->scope_next;
}
+ is_arg_scope = (idx == ARG_SCOPE_END);
if (var_idx < 0) {
- /* XXX: scoping issues:
- should not resolve vars from the function body during argument parse,
- `arguments` and function-name should not be hidden by later vars.
- */
- var_idx = find_var(ctx, s, var_name);
- if (var_idx >= 0) {
- if (scope_level == 0
- && (var_idx & ARGUMENT_VAR_OFFSET)
- && (var_idx - ARGUMENT_VAR_OFFSET) >= arg_valid) {
- /* referring to an uninitialized argument */
- dbuf_putc(bc, OP_throw_var);
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- dbuf_putc(bc, JS_THROW_VAR_UNINITIALIZED);
- }
- if (!(var_idx & ARGUMENT_VAR_OFFSET))
- is_func_var = s->vars[var_idx].is_func_var;
+ /* argument scope: variables are not visible but pseudo
+ variables are visible */
+ if (!is_arg_scope) {
+ var_idx = find_var(ctx, s, var_name);
}
if (var_idx < 0 && is_pseudo_var)
@@ -29448,21 +29535,31 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
if (var_idx < 0 && var_name == JS_ATOM_arguments &&
s->has_arguments_binding) {
/* 'arguments' pseudo variable */
- var_idx = add_arguments_var(ctx, s, var_name);
+ var_idx = add_arguments_var(ctx, s);
}
if (var_idx < 0 && s->is_func_expr && var_name == s->func_name) {
/* add a new variable with the function name */
var_idx = add_func_var(ctx, s, var_name);
- is_func_var = TRUE;
}
}
if (var_idx >= 0) {
+ if ((op == OP_scope_put_var || op == OP_scope_make_ref) &&
+ !(var_idx & ARGUMENT_VAR_OFFSET) &&
+ s->vars[var_idx].is_const) {
+ /* only happens when assigning a function expression name
+ in strict mode */
+ dbuf_putc(bc, OP_throw_error);
+ dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+ dbuf_putc(bc, JS_THROW_VAR_RO);
+ goto done;
+ }
/* OP_scope_put_var_init is only used to initialize a
lexical variable, so it is never used in a with or var object. It
can be used with a closure (module global variable case). */
switch (op) {
case OP_scope_make_ref:
- if (is_func_var) {
+ if (!(var_idx & ARGUMENT_VAR_OFFSET) &&
+ s->vars[var_idx].var_kind == JS_VAR_FUNCTION_NAME) {
/* Create a dummy object reference for the func_var */
dbuf_putc(bc, OP_object);
dbuf_putc(bc, OP_get_loc);
@@ -29510,7 +29607,6 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
if (var_idx & ARGUMENT_VAR_OFFSET) {
dbuf_putc(bc, OP_get_arg + is_put);
dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
- /* XXX: should test if argument reference needs TDZ check */
} else {
if (is_put) {
if (s->vars[var_idx].is_lexical) {
@@ -29543,41 +29639,32 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
goto done;
}
/* check eval object */
- if (s->var_object_idx >= 0 && !is_pseudo_var) {
+ if (!is_arg_scope && s->var_object_idx >= 0 && !is_pseudo_var) {
dbuf_putc(bc, OP_get_loc);
dbuf_put_u16(bc, s->var_object_idx);
- dbuf_putc(bc, get_with_scope_opcode(op));
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- label_done = new_label_fd(s, label_done);
- dbuf_put_u32(bc, label_done);
- dbuf_putc(bc, 0);
- update_label(s, label_done, 1);
- s->jump_size++;
+ var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
}
+ /* check eval object in argument scope */
+ if (s->arg_var_object_idx >= 0 && !is_pseudo_var) {
+ dbuf_putc(bc, OP_get_loc);
+ dbuf_put_u16(bc, s->arg_var_object_idx);
+ var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
+ }
+
/* check parent scopes */
for (fd = s; fd->parent;) {
scope_level = fd->parent_scope_level;
fd = fd->parent;
- if (scope_level == 0) {
- /* function is defined as part of the argument parsing: hide vars
- from the function body.
- XXX: variables created from argument destructuring might need
- to be visible, should refine this method.
- */
- var_idx = find_arg(ctx, fd, var_name);
- goto check_idx;
- }
for (idx = fd->scopes[scope_level].first; idx >= 0;) {
vd = &fd->vars[idx];
if (vd->var_name == var_name) {
if (op == OP_scope_put_var || op == OP_scope_make_ref) {
if (vd->is_const) {
- dbuf_putc(bc, OP_throw_var);
+ dbuf_putc(bc, OP_throw_error);
dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
dbuf_putc(bc, JS_THROW_VAR_RO);
goto done;
}
- is_func_var = vd->is_func_var;
}
var_idx = idx;
break;
@@ -29587,26 +29674,19 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
if (idx >= 0) {
dbuf_putc(bc, OP_get_var_ref);
dbuf_put_u16(bc, idx);
- dbuf_putc(bc, get_with_scope_opcode(op));
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- label_done = new_label_fd(s, label_done);
- dbuf_put_u32(bc, label_done);
- dbuf_putc(bc, 1);
- update_label(s, label_done, 1);
- s->jump_size++;
+ var_object_test(ctx, s, var_name, op, bc, &label_done, 1);
}
}
idx = vd->scope_next;
}
+ is_arg_scope = (idx == ARG_SCOPE_END);
if (var_idx >= 0)
break;
-
- var_idx = find_var(ctx, fd, var_name);
- check_idx:
- if (var_idx >= 0) {
- if (!(var_idx & ARGUMENT_VAR_OFFSET))
- is_func_var = fd->vars[var_idx].is_func_var;
- break;
+
+ if (!is_arg_scope) {
+ var_idx = find_var(ctx, fd, var_name);
+ if (var_idx >= 0)
+ break;
}
if (is_pseudo_var) {
var_idx = resolve_pseudo_var(ctx, fd, var_name);
@@ -29614,33 +29694,39 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
break;
}
if (var_name == JS_ATOM_arguments && fd->has_arguments_binding) {
- var_idx = add_arguments_var(ctx, fd, var_name);
+ var_idx = add_arguments_var(ctx, fd);
break;
}
if (fd->is_func_expr && fd->func_name == var_name) {
/* add a new variable with the function name */
var_idx = add_func_var(ctx, fd, var_name);
- is_func_var = TRUE;
break;
}
/* check eval object */
- if (fd->var_object_idx >= 0 && !is_pseudo_var) {
- fd->vars[fd->var_object_idx].is_captured = 1;
+ if (!is_arg_scope && fd->var_object_idx >= 0 && !is_pseudo_var) {
+ vd = &fd->vars[fd->var_object_idx];
+ vd->is_captured = 1;
idx = get_closure_var(ctx, s, fd, FALSE,
- fd->var_object_idx, JS_ATOM__var_,
+ fd->var_object_idx, vd->var_name,
FALSE, FALSE, JS_VAR_NORMAL);
dbuf_putc(bc, OP_get_var_ref);
dbuf_put_u16(bc, idx);
- dbuf_putc(bc, get_with_scope_opcode(op));
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- label_done = new_label_fd(s, label_done);
- dbuf_put_u32(bc, label_done);
- dbuf_putc(bc, 0);
- update_label(s, label_done, 1);
- s->jump_size++;
+ var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
}
+ /* check eval object in argument scope */
+ if (fd->arg_var_object_idx >= 0 && !is_pseudo_var) {
+ vd = &fd->vars[fd->arg_var_object_idx];
+ vd->is_captured = 1;
+ idx = get_closure_var(ctx, s, fd, FALSE,
+ fd->arg_var_object_idx, vd->var_name,
+ FALSE, FALSE, JS_VAR_NORMAL);
+ dbuf_putc(bc, OP_get_var_ref);
+ dbuf_put_u16(bc, idx);
+ var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
+ }
+
if (fd->is_eval)
break; /* it it necessarily the top level function */
}
@@ -29665,6 +29751,7 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
}
goto has_idx;
} else if ((cv->var_name == JS_ATOM__var_ ||
+ cv->var_name == JS_ATOM__arg_var_ ||
cv->var_name == JS_ATOM__with_) && !is_pseudo_var) {
int is_with = (cv->var_name == JS_ATOM__with_);
if (fd != s) {
@@ -29678,13 +29765,7 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
}
dbuf_putc(bc, OP_get_var_ref);
dbuf_put_u16(bc, idx);
- dbuf_putc(bc, get_with_scope_opcode(op));
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- label_done = new_label_fd(s, label_done);
- dbuf_put_u32(bc, label_done);
- dbuf_putc(bc, is_with);
- update_label(s, label_done, 1);
- s->jump_size++;
+ var_object_test(ctx, s, var_name, op, bc, &label_done, is_with);
}
}
}
@@ -29709,14 +29790,14 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
has_idx:
if ((op == OP_scope_put_var || op == OP_scope_make_ref) &&
s->closure_var[idx].is_const) {
- dbuf_putc(bc, OP_throw_var);
+ dbuf_putc(bc, OP_throw_error);
dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
dbuf_putc(bc, JS_THROW_VAR_RO);
goto done;
}
switch (op) {
case OP_scope_make_ref:
- if (is_func_var) {
+ if (s->closure_var[idx].var_kind == JS_VAR_FUNCTION_NAME) {
/* Create a dummy object reference for the func_var */
dbuf_putc(bc, OP_object);
dbuf_putc(bc, OP_get_var_ref);
@@ -29956,7 +30037,7 @@ static int resolve_scope_private_field(JSContext *ctx, JSFunctionDef *s,
break;
case JS_VAR_PRIVATE_SETTER:
/* XXX: add clearer error message */
- dbuf_putc(bc, OP_throw_var);
+ dbuf_putc(bc, OP_throw_error);
dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
dbuf_putc(bc, JS_THROW_VAR_RO);
break;
@@ -29973,7 +30054,7 @@ static int resolve_scope_private_field(JSContext *ctx, JSFunctionDef *s,
case JS_VAR_PRIVATE_METHOD:
case JS_VAR_PRIVATE_GETTER:
/* XXX: add clearer error message */
- dbuf_putc(bc, OP_throw_var);
+ dbuf_putc(bc, OP_throw_error);
dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
dbuf_putc(bc, JS_THROW_VAR_RO);
break;
@@ -30025,17 +30106,33 @@ static void mark_eval_captured_variables(JSContext *ctx, JSFunctionDef *s,
}
}
+/* XXX: should handle the argument scope generically */
+static BOOL is_var_in_arg_scope(const JSVarDef *vd)
+{
+ return (vd->var_name == JS_ATOM_home_object ||
+ vd->var_name == JS_ATOM_this_active_func ||
+ vd->var_name == JS_ATOM_new_target ||
+ vd->var_name == JS_ATOM_this ||
+ vd->var_name == JS_ATOM__arg_var_ ||
+ vd->var_kind == JS_VAR_FUNCTION_NAME);
+}
+
static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
{
JSFunctionDef *fd;
JSVarDef *vd;
int i, scope_level, scope_idx;
- BOOL has_arguments_binding, has_this_binding;
+ BOOL has_arguments_binding, has_this_binding, is_arg_scope;
/* in non strict mode, variables are created in the caller's
environment object */
if (!s->is_eval && !(s->js_mode & JS_MODE_STRICT)) {
s->var_object_idx = add_var(ctx, s, JS_ATOM__var_);
+ if (s->has_parameter_expressions) {
+ /* an additional variable object is needed for the
+ argument scope */
+ s->arg_var_object_idx = add_var(ctx, s, JS_ATOM__arg_var_);
+ }
}
/* eval can potentially use 'arguments' so we must define it */
@@ -30051,8 +30148,14 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
s->home_object_var_idx = add_var(ctx, s, JS_ATOM_home_object);
}
has_arguments_binding = s->has_arguments_binding;
- if (has_arguments_binding)
- add_arguments_var(ctx, s, JS_ATOM_arguments);
+ if (has_arguments_binding) {
+ add_arguments_var(ctx, s);
+ /* also add an arguments binding in the argument scope to
+ raise an error if a direct eval in the argument scope tries
+ to redefine it */
+ if (s->has_parameter_expressions && !(s->js_mode & JS_MODE_STRICT))
+ add_arguments_arg(ctx, s);
+ }
if (s->is_func_expr && s->func_name != JS_ATOM_NULL)
add_func_var(ctx, s, s->func_name);
@@ -30069,7 +30172,6 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
fd = fd->parent;
if (!fd)
break;
- scope_idx = fd->scopes[scope_level].first;
/* add 'this' if it was not previously added */
if (!has_this_binding && fd->has_this_binding) {
if (fd->this_var_idx < 0)
@@ -30084,7 +30186,7 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
}
/* add 'arguments' if it was not previously added */
if (!has_arguments_binding && fd->has_arguments_binding) {
- add_arguments_var(ctx, fd, JS_ATOM_arguments);
+ add_arguments_var(ctx, fd);
has_arguments_binding = TRUE;
}
/* add function name */
@@ -30092,6 +30194,7 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
add_func_var(ctx, fd, fd->func_name);
/* add lexical variables */
+ scope_idx = fd->scopes[scope_level].first;
while (scope_idx >= 0) {
vd = &fd->vars[scope_idx];
vd->is_captured = 1;
@@ -30099,24 +30202,37 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
vd->var_name, vd->is_const, vd->is_lexical, vd->var_kind);
scope_idx = vd->scope_next;
}
- /* add unscoped variables */
- for(i = 0; i < fd->arg_count; i++) {
- vd = &fd->args[i];
- if (vd->var_name != JS_ATOM_NULL) {
- get_closure_var(ctx, s, fd,
- TRUE, i, vd->var_name, FALSE, FALSE,
- JS_VAR_NORMAL);
+ is_arg_scope = (scope_idx == ARG_SCOPE_END);
+ if (!is_arg_scope) {
+ /* add unscoped variables */
+ for(i = 0; i < fd->arg_count; i++) {
+ vd = &fd->args[i];
+ if (vd->var_name != JS_ATOM_NULL) {
+ get_closure_var(ctx, s, fd,
+ TRUE, i, vd->var_name, FALSE, FALSE,
+ JS_VAR_NORMAL);
+ }
}
- }
- for(i = 0; i < fd->var_count; i++) {
- vd = &fd->vars[i];
- /* do not close top level last result */
- if (vd->scope_level == 0 &&
- vd->var_name != JS_ATOM__ret_ &&
- vd->var_name != JS_ATOM_NULL) {
- get_closure_var(ctx, s, fd,
- FALSE, i, vd->var_name, FALSE, FALSE,
- JS_VAR_NORMAL);
+ for(i = 0; i < fd->var_count; i++) {
+ vd = &fd->vars[i];
+ /* do not close top level last result */
+ if (vd->scope_level == 0 &&
+ vd->var_name != JS_ATOM__ret_ &&
+ vd->var_name != JS_ATOM_NULL) {
+ get_closure_var(ctx, s, fd,
+ FALSE, i, vd->var_name, FALSE, FALSE,
+ JS_VAR_NORMAL);
+ }
+ }
+ } else {
+ for(i = 0; i < fd->var_count; i++) {
+ vd = &fd->vars[i];
+ /* do not close top level last result */
+ if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) {
+ get_closure_var(ctx, s, fd,
+ FALSE, i, vd->var_name, FALSE, FALSE,
+ JS_VAR_NORMAL);
+ }
}
}
if (fd->is_eval) {
@@ -30134,6 +30250,18 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
}
}
+static void set_closure_from_var(JSContext *ctx, JSClosureVar *cv,
+ JSVarDef *vd, int var_idx)
+{
+ cv->is_local = TRUE;
+ cv->is_arg = FALSE;
+ cv->is_const = vd->is_const;
+ cv->is_lexical = vd->is_lexical;
+ cv->var_kind = vd->var_kind;
+ cv->var_idx = var_idx;
+ cv->var_name = JS_DupAtom(ctx, vd->var_name);
+}
+
/* for direct eval compilation: add references to the variables of the
calling function */
static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
@@ -30141,7 +30269,8 @@ static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
{
int i, count;
JSVarDef *vd;
-
+ BOOL is_arg_scope;
+
count = b->arg_count + b->var_count + b->closure_var_count;
s->closure_var = NULL;
s->closure_var_count = 0;
@@ -30156,41 +30285,41 @@ static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
vd = &b->vardefs[b->arg_count + i];
if (vd->scope_level > 0) {
JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
- cv->is_local = TRUE;
- cv->is_arg = FALSE;
- cv->is_const = vd->is_const;
- cv->is_lexical = vd->is_lexical;
- cv->var_kind = vd->var_kind;
- cv->var_idx = i;
- cv->var_name = JS_DupAtom(ctx, vd->var_name);
+ set_closure_from_var(ctx, cv, vd, i);
}
i = vd->scope_next;
}
- /* Add argument variables */
- for(i = 0; i < b->arg_count; i++) {
- JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
- vd = &b->vardefs[i];
- cv->is_local = TRUE;
- cv->is_arg = TRUE;
- cv->is_const = FALSE;
- cv->is_lexical = FALSE;
- cv->var_kind = JS_VAR_NORMAL;
- cv->var_idx = i;
- cv->var_name = JS_DupAtom(ctx, vd->var_name);
- }
- /* Add local non lexical variables */
- for(i = 0; i < b->var_count; i++) {
- vd = &b->vardefs[b->arg_count + i];
- if (vd->scope_level == 0 && vd->var_name != JS_ATOM__ret_) {
+ is_arg_scope = (i == ARG_SCOPE_END);
+ if (!is_arg_scope) {
+ /* Add argument variables */
+ for(i = 0; i < b->arg_count; i++) {
JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
+ vd = &b->vardefs[i];
cv->is_local = TRUE;
- cv->is_arg = FALSE;
+ cv->is_arg = TRUE;
cv->is_const = FALSE;
cv->is_lexical = FALSE;
cv->var_kind = JS_VAR_NORMAL;
cv->var_idx = i;
cv->var_name = JS_DupAtom(ctx, vd->var_name);
}
+ /* Add local non lexical variables */
+ for(i = 0; i < b->var_count; i++) {
+ vd = &b->vardefs[b->arg_count + i];
+ if (vd->scope_level == 0 && vd->var_name != JS_ATOM__ret_) {
+ JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
+ set_closure_from_var(ctx, cv, vd, i);
+ }
+ }
+ } else {
+ /* only add pseudo variables */
+ for(i = 0; i < b->var_count; i++) {
+ vd = &b->vardefs[b->arg_count + i];
+ if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) {
+ JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
+ set_closure_from_var(ctx, cv, vd, i);
+ }
+ }
}
for(i = 0; i < b->closure_var_count; i++) {
JSClosureVar *cv0 = &b->closure_var[i];
@@ -30348,59 +30477,93 @@ static BOOL code_match(CodeContext *s, int pos, ...)
static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, DynBuf *bc)
{
- int i, idx, var_idx;
+ int i, idx, label_next = -1;
+
+ /* add the hoisted functions in arguments and local variables */
+ for(i = 0; i < s->arg_count; i++) {
+ JSVarDef *vd = &s->args[i];
+ if (vd->func_pool_idx >= 0) {
+ dbuf_putc(bc, OP_fclosure);
+ dbuf_put_u32(bc, vd->func_pool_idx);
+ dbuf_putc(bc, OP_put_arg);
+ dbuf_put_u16(bc, i);
+ }
+ }
+ for(i = 0; i < s->var_count; i++) {
+ JSVarDef *vd = &s->vars[i];
+ if (vd->scope_level == 0 && vd->func_pool_idx >= 0) {
+ dbuf_putc(bc, OP_fclosure);
+ dbuf_put_u32(bc, vd->func_pool_idx);
+ dbuf_putc(bc, OP_put_loc);
+ dbuf_put_u16(bc, i);
+ }
+ }
- /* add the hoisted functions and variables */
- for(i = 0; i < s->hoisted_def_count; i++) {
- JSHoistedDef *hf = &s->hoisted_def[i];
+ /* the module global variables must be initialized before
+ evaluating the module so that the exported functions are
+ visible if there are cyclic module references */
+ if (s->module) {
+ label_next = new_label_fd(s, -1);
+
+ /* if 'this' is true, initialize the global variables and return */
+ dbuf_putc(bc, OP_push_this);
+ dbuf_putc(bc, OP_if_false);
+ dbuf_put_u32(bc, label_next);
+ update_label(s, label_next, 1);
+ s->jump_size++;
+ }
+
+ /* add the global variables (only happens if s->is_global_var is
+ true) */
+ for(i = 0; i < s->global_var_count; i++) {
+ JSGlobalVar *hf = &s->global_vars[i];
int has_closure = 0;
BOOL force_init = hf->force_init;
- if (s->is_global_var && hf->var_name != JS_ATOM_NULL) {
- /* we are in an eval, so the closure contains all the
- enclosing variables */
- /* If the outer function has a variable environment,
- create a property for the variable there */
- for(idx = 0; idx < s->closure_var_count; idx++) {
- JSClosureVar *cv = &s->closure_var[idx];
- if (cv->var_name == hf->var_name) {
- has_closure = 2;
- force_init = FALSE;
- break;
- }
- if (cv->var_name == JS_ATOM__var_) {
- dbuf_putc(bc, OP_get_var_ref);
- dbuf_put_u16(bc, idx);
- has_closure = 1;
- force_init = TRUE;
- break;
- }
+ /* we are in an eval, so the closure contains all the
+ enclosing variables */
+ /* If the outer function has a variable environment,
+ create a property for the variable there */
+ for(idx = 0; idx < s->closure_var_count; idx++) {
+ JSClosureVar *cv = &s->closure_var[idx];
+ if (cv->var_name == hf->var_name) {
+ has_closure = 2;
+ force_init = FALSE;
+ break;
}
- if (!has_closure) {
- int flags;
-
- flags = 0;
- if (s->eval_type != JS_EVAL_TYPE_GLOBAL)
- flags |= JS_PROP_CONFIGURABLE;
- if (hf->cpool_idx >= 0 && !hf->is_lexical) {
- /* global function definitions need a specific handling */
- dbuf_putc(bc, OP_fclosure);
- dbuf_put_u32(bc, hf->cpool_idx);
-
- dbuf_putc(bc, OP_define_func);
- dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
- dbuf_putc(bc, flags);
-
- goto done_hoisted_def;
- } else {
- if (hf->is_lexical) {
- flags |= DEFINE_GLOBAL_LEX_VAR;
- if (!hf->is_const)
- flags |= JS_PROP_WRITABLE;
- }
- dbuf_putc(bc, OP_define_var);
- dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
- dbuf_putc(bc, flags);
+ if (cv->var_name == JS_ATOM__var_ ||
+ cv->var_name == JS_ATOM__arg_var_) {
+ dbuf_putc(bc, OP_get_var_ref);
+ dbuf_put_u16(bc, idx);
+ has_closure = 1;
+ force_init = TRUE;
+ break;
+ }
+ }
+ if (!has_closure) {
+ int flags;
+
+ flags = 0;
+ if (s->eval_type != JS_EVAL_TYPE_GLOBAL)
+ flags |= JS_PROP_CONFIGURABLE;
+ if (hf->cpool_idx >= 0 && !hf->is_lexical) {
+ /* global function definitions need a specific handling */
+ dbuf_putc(bc, OP_fclosure);
+ dbuf_put_u32(bc, hf->cpool_idx);
+
+ dbuf_putc(bc, OP_define_func);
+ dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
+ dbuf_putc(bc, flags);
+
+ goto done_global_var;
+ } else {
+ if (hf->is_lexical) {
+ flags |= DEFINE_GLOBAL_LEX_VAR;
+ if (!hf->is_const)
+ flags |= JS_PROP_WRITABLE;
}
+ dbuf_putc(bc, OP_define_var);
+ dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
+ dbuf_putc(bc, flags);
}
}
if (hf->cpool_idx >= 0 || force_init) {
@@ -30415,37 +30578,35 @@ static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, Dy
} else {
dbuf_putc(bc, OP_undefined);
}
- if (s->is_global_var) {
- if (has_closure == 2) {
- dbuf_putc(bc, OP_put_var_ref);
- dbuf_put_u16(bc, idx);
- } else if (has_closure == 1) {
- dbuf_putc(bc, OP_define_field);
- dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
- dbuf_putc(bc, OP_drop);
- } else {
- /* XXX: Check if variable is writable and enumerable */
- dbuf_putc(bc, OP_put_var);
- dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
- }
+ if (has_closure == 2) {
+ dbuf_putc(bc, OP_put_var_ref);
+ dbuf_put_u16(bc, idx);
+ } else if (has_closure == 1) {
+ dbuf_putc(bc, OP_define_field);
+ dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
+ dbuf_putc(bc, OP_drop);
} else {
- var_idx = hf->var_idx;
- if (var_idx & ARGUMENT_VAR_OFFSET) {
- dbuf_putc(bc, OP_put_arg);
- dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
- } else {
- dbuf_putc(bc, OP_put_loc);
- dbuf_put_u16(bc, var_idx);
- }
+ /* XXX: Check if variable is writable and enumerable */
+ dbuf_putc(bc, OP_put_var);
+ dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
}
}
- done_hoisted_def:
+ done_global_var:
JS_FreeAtom(ctx, hf->var_name);
}
- js_free(ctx, s->hoisted_def);
- s->hoisted_def = NULL;
- s->hoisted_def_count = 0;
- s->hoisted_def_size = 0;
+
+ if (s->module) {
+ dbuf_putc(bc, OP_return_undef);
+
+ dbuf_putc(bc, OP_label);
+ dbuf_put_u32(bc, label_next);
+ s->label_slots[label_next].pos2 = bc->size;
+ }
+
+ js_free(ctx, s->global_vars);
+ s->global_vars = NULL;
+ s->global_var_count = 0;
+ s->global_var_size = 0;
}
static int skip_dead_code(JSFunctionDef *s, const uint8_t *bc_buf, int bc_len,
@@ -30525,7 +30686,7 @@ static int get_label_pos(JSFunctionDef *s, int label)
variables when necessary */
static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
{
- int pos, pos_next, bc_len, op, len, i, idx, arg_valid, line_num;
+ int pos, pos_next, bc_len, op, len, i, idx, line_num;
uint8_t *bc_buf;
JSAtom var_name;
DynBuf bc_out;
@@ -30538,47 +30699,43 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
/* first pass for runtime checks (must be done before the
variables are created) */
- if (s->is_global_var) {
- for(i = 0; i < s->hoisted_def_count; i++) {
- JSHoistedDef *hf = &s->hoisted_def[i];
- int flags;
-
- if (hf->var_name != JS_ATOM_NULL) {
- /* check if global variable (XXX: simplify) */
- for(idx = 0; idx < s->closure_var_count; idx++) {
- JSClosureVar *cv = &s->closure_var[idx];
- if (cv->var_name == hf->var_name) {
- if (s->eval_type == JS_EVAL_TYPE_DIRECT &&
- cv->is_lexical) {
- /* Check if a lexical variable is
- redefined as 'var'. XXX: Could abort
- compilation here, but for consistency
- with the other checks, we delay the
- error generation. */
- dbuf_putc(&bc_out, OP_throw_var);
- dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
- dbuf_putc(&bc_out, JS_THROW_VAR_REDECL);
- }
- goto next;
- }
- if (cv->var_name == JS_ATOM__var_)
- goto next;
+ for(i = 0; i < s->global_var_count; i++) {
+ JSGlobalVar *hf = &s->global_vars[i];
+ int flags;
+
+ /* check if global variable (XXX: simplify) */
+ for(idx = 0; idx < s->closure_var_count; idx++) {
+ JSClosureVar *cv = &s->closure_var[idx];
+ if (cv->var_name == hf->var_name) {
+ if (s->eval_type == JS_EVAL_TYPE_DIRECT &&
+ cv->is_lexical) {
+ /* Check if a lexical variable is
+ redefined as 'var'. XXX: Could abort
+ compilation here, but for consistency
+ with the other checks, we delay the
+ error generation. */
+ dbuf_putc(&bc_out, OP_throw_error);
+ dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
+ dbuf_putc(&bc_out, JS_THROW_VAR_REDECL);
}
-
- dbuf_putc(&bc_out, OP_check_define_var);
- dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
- flags = 0;
- if (hf->is_lexical)
- flags |= DEFINE_GLOBAL_LEX_VAR;
- if (hf->cpool_idx >= 0)
- flags |= DEFINE_GLOBAL_FUNC_VAR;
- dbuf_putc(&bc_out, flags);
+ goto next;
}
- next: ;
+ if (cv->var_name == JS_ATOM__var_ ||
+ cv->var_name == JS_ATOM__arg_var_)
+ goto next;
}
+
+ dbuf_putc(&bc_out, OP_check_define_var);
+ dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
+ flags = 0;
+ if (hf->is_lexical)
+ flags |= DEFINE_GLOBAL_LEX_VAR;
+ if (hf->cpool_idx >= 0)
+ flags |= DEFINE_GLOBAL_FUNC_VAR;
+ dbuf_putc(&bc_out, flags);
+ next: ;
}
- arg_valid = 0;
line_num = 0; /* avoid warning */
for (pos = 0; pos < bc_len; pos = pos_next) {
op = bc_buf[pos];
@@ -30590,9 +30747,6 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
s->line_number_size++;
goto no_change;
- case OP_set_arg_valid_upto:
- arg_valid = get_u16(bc_buf + pos + 1);
- break;
case OP_eval: /* convert scope index to adjusted variable index */
{
int call_argc = get_u16(bc_buf + pos + 1);
@@ -30618,7 +30772,7 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
var_name = get_u32(bc_buf + pos + 1);
scope = get_u16(bc_buf + pos + 5);
pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,
- NULL, NULL, pos_next, arg_valid);
+ NULL, NULL, pos_next);
JS_FreeAtom(ctx, var_name);
break;
case OP_scope_make_ref:
@@ -30631,7 +30785,7 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
ls = &s->label_slots[label];
ls->ref_count--; /* always remove label reference */
pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,
- bc_buf, ls, pos_next, arg_valid);
+ bc_buf, ls, pos_next);
JS_FreeAtom(ctx, var_name);
}
break;
@@ -30712,7 +30866,7 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
case OP_return:
case OP_return_undef:
case OP_throw:
- case OP_throw_var:
+ case OP_throw_error:
case OP_ret:
if (OPTIMIZE) {
/* remove dead code */
@@ -30746,25 +30900,27 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
{
int scope_idx, scope = get_u16(bc_buf + pos + 1);
- if (scope == 1) {
+ if (scope == s->body_scope) {
instantiate_hoisted_definitions(ctx, s, &bc_out);
}
for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) {
JSVarDef *vd = &s->vars[scope_idx];
if (vd->scope_level == scope) {
- if (vd->var_kind == JS_VAR_FUNCTION_DECL ||
- vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) {
- /* Initialize lexical variable upon entering scope */
- dbuf_putc(&bc_out, OP_fclosure);
- dbuf_put_u32(&bc_out, vd->func_pool_or_scope_idx);
- dbuf_putc(&bc_out, OP_put_loc);
- dbuf_put_u16(&bc_out, scope_idx);
- } else {
- /* XXX: should check if variable can be used
- before initialization */
- dbuf_putc(&bc_out, OP_set_loc_uninitialized);
- dbuf_put_u16(&bc_out, scope_idx);
+ if (scope_idx != s->arguments_arg_idx) {
+ if (vd->var_kind == JS_VAR_FUNCTION_DECL ||
+ vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) {
+ /* Initialize lexical variable upon entering scope */
+ dbuf_putc(&bc_out, OP_fclosure);
+ dbuf_put_u32(&bc_out, vd->func_pool_idx);
+ dbuf_putc(&bc_out, OP_put_loc);
+ dbuf_put_u16(&bc_out, scope_idx);
+ } else {
+ /* XXX: should check if variable can be used
+ before initialization */
+ dbuf_putc(&bc_out, OP_set_loc_uninitialized);
+ dbuf_put_u16(&bc_out, scope_idx);
+ }
}
scope_idx = vd->scope_next;
} else {
@@ -31167,6 +31323,8 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
dbuf_putc(&bc_out, OP_special_object);
dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS);
}
+ if (s->arguments_arg_idx >= 0)
+ put_short_code(&bc_out, OP_set_loc, s->arguments_arg_idx);
put_short_code(&bc_out, OP_put_loc, s->arguments_var_idx);
}
/* initialize a reference to the current function if needed */
@@ -31181,6 +31339,11 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
put_short_code(&bc_out, OP_put_loc, s->var_object_idx);
}
+ if (s->arg_var_object_idx >= 0) {
+ dbuf_putc(&bc_out, OP_special_object);
+ dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
+ put_short_code(&bc_out, OP_put_loc, s->arg_var_object_idx);
+ }
for (pos = 0; pos < bc_len; pos = pos_next) {
int val;
@@ -31248,7 +31411,7 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
case OP_return_undef:
case OP_return_async:
case OP_throw:
- case OP_throw_var:
+ case OP_throw_error:
pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
goto no_change;
@@ -31969,56 +32132,91 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
/* compute the maximum stack size needed by the function */
typedef struct StackSizeState {
+ int bc_len;
int stack_len_max;
uint16_t *stack_level_tab;
+ int *pc_stack;
+ int pc_stack_len;
+ int pc_stack_size;
} StackSizeState;
-static __exception int compute_stack_size_rec(JSContext *ctx,
- JSFunctionDef *fd,
- StackSizeState *s,
- int pos, int op, int stack_len)
+/* 'op' is only used for error indication */
+static __exception int ss_check(JSContext *ctx, StackSizeState *s,
+ int pos, int op, int stack_len)
{
- int bc_len, diff, n_pop, pos_next;
- const JSOpCode *oi;
- const uint8_t *bc_buf;
-
+ if ((unsigned)pos >= s->bc_len) {
+ JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
+ return -1;
+ }
if (stack_len > s->stack_len_max) {
s->stack_len_max = stack_len;
- if (s->stack_len_max > JS_STACK_SIZE_MAX)
- goto stack_overflow;
+ if (s->stack_len_max > JS_STACK_SIZE_MAX) {
+ JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos);
+ return -1;
+ }
}
- bc_buf = fd->byte_code.buf;
- bc_len = fd->byte_code.size;
- for(;;) {
- if ((unsigned)pos >= bc_len)
- goto buf_overflow;
-#if 0
- printf("%5d: %d\n", pos, stack_len);
-#endif
- if (s->stack_level_tab[pos] != 0xffff) {
- /* already explored: check that the stack size is consistent */
- if (s->stack_level_tab[pos] != stack_len) {
- JS_ThrowInternalError(ctx, "unconsistent stack size: %d %d (pc=%d)",
- s->stack_level_tab[pos], stack_len, pos);
- return -1;
- } else {
- return 0;
- }
+ if (s->stack_level_tab[pos] != 0xffff) {
+ /* already explored: check that the stack size is consistent */
+ if (s->stack_level_tab[pos] != stack_len) {
+ JS_ThrowInternalError(ctx, "unconsistent stack size: %d %d (pc=%d)",
+ s->stack_level_tab[pos], stack_len, pos);
+ return -1;
} else {
- s->stack_level_tab[pos] = stack_len;
+ return 0;
}
+ }
+
+ /* mark as explored and store the stack size */
+ s->stack_level_tab[pos] = stack_len;
+
+ /* queue the new PC to explore */
+ if (js_resize_array(ctx, (void **)&s->pc_stack, sizeof(s->pc_stack[0]),
+ &s->pc_stack_size, s->pc_stack_len + 1))
+ return -1;
+ s->pc_stack[s->pc_stack_len++] = pos;
+ return 0;
+}
+static __exception int compute_stack_size(JSContext *ctx,
+ JSFunctionDef *fd,
+ int *pstack_size)
+{
+ StackSizeState s_s, *s = &s_s;
+ int i, diff, n_pop, pos_next, stack_len, pos, op;
+ const JSOpCode *oi;
+ const uint8_t *bc_buf;
+
+ bc_buf = fd->byte_code.buf;
+ s->bc_len = fd->byte_code.size;
+ /* bc_len > 0 */
+ s->stack_level_tab = js_malloc(ctx, sizeof(s->stack_level_tab[0]) *
+ s->bc_len);
+ if (!s->stack_level_tab)
+ return -1;
+ for(i = 0; i < s->bc_len; i++)
+ s->stack_level_tab[i] = 0xffff;
+ s->stack_len_max = 0;
+ s->pc_stack = NULL;
+ s->pc_stack_len = 0;
+ s->pc_stack_size = 0;
+
+ /* breadth-first graph exploration */
+ if (ss_check(ctx, s, 0, OP_invalid, 0))
+ goto fail;
+
+ while (s->pc_stack_len > 0) {
+ pos = s->pc_stack[--s->pc_stack_len];
+ stack_len = s->stack_level_tab[pos];
op = bc_buf[pos];
if (op == 0 || op >= OP_COUNT) {
JS_ThrowInternalError(ctx, "invalid opcode (op=%d, pc=%d)", op, pos);
- return -1;
+ goto fail;
}
oi = &short_opcode_info(op);
pos_next = pos + oi->size;
- if (pos_next > bc_len) {
- buf_overflow:
+ if (pos_next > s->bc_len) {
JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
- return -1;
+ goto fail;
}
n_pop = oi->n_pop;
/* call pops a variable number of arguments */
@@ -32034,13 +32232,15 @@ static __exception int compute_stack_size_rec(JSContext *ctx,
if (stack_len < n_pop) {
JS_ThrowInternalError(ctx, "stack underflow (op=%d, pc=%d)", op, pos);
- return -1;
+ goto fail;
}
stack_len += oi->n_push - n_pop;
if (stack_len > s->stack_len_max) {
s->stack_len_max = stack_len;
- if (s->stack_len_max > JS_STACK_SIZE_MAX)
- goto stack_overflow;
+ if (s->stack_len_max > JS_STACK_SIZE_MAX) {
+ JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos);
+ goto fail;
+ }
}
switch(op) {
case OP_tail_call:
@@ -32049,9 +32249,9 @@ static __exception int compute_stack_size_rec(JSContext *ctx,
case OP_return_undef:
case OP_return_async:
case OP_throw:
- case OP_throw_var:
+ case OP_throw_error:
case OP_ret:
- goto done;
+ goto done_insn;
case OP_goto:
diff = get_u32(bc_buf + pos + 1);
pos_next = pos + 1 + diff;
@@ -32068,73 +32268,57 @@ static __exception int compute_stack_size_rec(JSContext *ctx,
case OP_if_true8:
case OP_if_false8:
diff = (int8_t)bc_buf[pos + 1];
- if (compute_stack_size_rec(ctx, fd, s, pos + 1 + diff, op, stack_len))
- return -1;
+ if (ss_check(ctx, s, pos + 1 + diff, op, stack_len))
+ goto fail;
break;
#endif
case OP_if_true:
case OP_if_false:
case OP_catch:
diff = get_u32(bc_buf + pos + 1);
- if (compute_stack_size_rec(ctx, fd, s, pos + 1 + diff, op, stack_len))
- return -1;
+ if (ss_check(ctx, s, pos + 1 + diff, op, stack_len))
+ goto fail;
break;
case OP_gosub:
diff = get_u32(bc_buf + pos + 1);
- if (compute_stack_size_rec(ctx, fd, s, pos + 1 + diff, op, stack_len + 1))
- return -1;
+ if (ss_check(ctx, s, pos + 1 + diff, op, stack_len + 1))
+ goto fail;
break;
case OP_with_get_var:
case OP_with_delete_var:
diff = get_u32(bc_buf + pos + 5);
- if (compute_stack_size_rec(ctx, fd, s, pos + 5 + diff, op, stack_len + 1))
- return -1;
+ if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 1))
+ goto fail;
break;
case OP_with_make_ref:
case OP_with_get_ref:
case OP_with_get_ref_undef:
diff = get_u32(bc_buf + pos + 5);
- if (compute_stack_size_rec(ctx, fd, s, pos + 5 + diff, op, stack_len + 2))
- return -1;
+ if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 2))
+ goto fail;
break;
case OP_with_put_var:
diff = get_u32(bc_buf + pos + 5);
- if (compute_stack_size_rec(ctx, fd, s, pos + 5 + diff, op, stack_len - 1))
- return -1;
+ if (ss_check(ctx, s, pos + 5 + diff, op, stack_len - 1))
+ goto fail;
break;
default:
break;
}
- pos = pos_next;
+ if (ss_check(ctx, s, pos_next, op, stack_len))
+ goto fail;
+ done_insn: ;
}
- done:
- return 0;
-
- stack_overflow:
- JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos);
- return -1;
-}
-
-static __exception int compute_stack_size(JSContext *ctx,
- JSFunctionDef *fd,
- int *pstack_size)
-{
- StackSizeState s_s, *s = &s_s;
- int bc_len, i, ret;
-
- bc_len = fd->byte_code.size;
- /* bc_len > 0 */
- s->stack_level_tab = js_malloc(ctx, sizeof(s->stack_level_tab[0]) * bc_len);
- if (!s->stack_level_tab)
- return -1;
- for(i = 0; i < bc_len; i++)
- s->stack_level_tab[i] = 0xffff;
- s->stack_len_max = 0;
- ret = compute_stack_size_rec(ctx, fd, s, 0, OP_invalid, 0);
js_free(ctx, s->stack_level_tab);
+ js_free(ctx, s->pc_stack);
*pstack_size = s->stack_len_max;
- return ret;
+ return 0;
+ fail:
+ js_free(ctx, s->stack_level_tab);
+ js_free(ctx, s->pc_stack);
+ *pstack_size = 0;
+ return -1;
}
static int add_module_variables(JSContext *ctx, JSFunctionDef *fd)
@@ -32142,14 +32326,14 @@ static int add_module_variables(JSContext *ctx, JSFunctionDef *fd)
int i, idx;
JSModuleDef *m = fd->module;
JSExportEntry *me;
- JSHoistedDef *hf;
+ JSGlobalVar *hf;
/* The imported global variables were added as closure variables
in js_parse_import(). We add here the module global
variables. */
- for(i = 0; i < fd->hoisted_def_count; i++) {
- hf = &fd->hoisted_def[i];
+ for(i = 0; i < fd->global_var_count; i++) {
+ hf = &fd->global_vars[i];
if (add_closure_var(ctx, fd, TRUE, FALSE, i, hf->var_name, hf->is_const,
hf->is_lexical, FALSE) < 0)
return -1;
@@ -32187,6 +32371,10 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
for (scope = 0; scope < fd->scope_count; scope++) {
fd->scopes[scope].first = -1;
}
+ if (fd->has_parameter_expressions) {
+ /* special end of variable list marker for the argument scope */
+ fd->scopes[ARG_SCOPE_INDEX].first = ARG_SCOPE_END;
+ }
for (idx = 0; idx < fd->var_count; idx++) {
JSVarDef *vd = &fd->vars[idx];
vd->scope_next = fd->scopes[vd->scope_level].first;
@@ -32194,12 +32382,12 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
}
for (scope = 2; scope < fd->scope_count; scope++) {
JSVarScope *sd = &fd->scopes[scope];
- if (sd->first == -1)
+ if (sd->first < 0)
sd->first = fd->scopes[sd->parent].first;
}
for (idx = 0; idx < fd->var_count; idx++) {
JSVarDef *vd = &fd->vars[idx];
- if (vd->scope_next == -1 && vd->scope_level > 1) {
+ if (vd->scope_next < 0 && vd->scope_level > 1) {
scope = fd->scopes[vd->scope_level].parent;
vd->scope_next = fd->scopes[scope].first;
}
@@ -32571,7 +32759,8 @@ static int js_parse_function_check_names(JSParseState *s, JSFunctionDef *fd,
/* Check if argument name duplicates a destructuring parameter */
/* XXX: should have a flag for such variables */
for (i = 0; i < fd->var_count; i++) {
- if (fd->vars[i].var_name == name)
+ if (fd->vars[i].var_name == name &&
+ fd->vars[i].scope_level == 0)
goto duplicate;
}
}
@@ -32680,8 +32869,8 @@ static __exception int js_parse_function_decl2(JSParseState *s,
if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_MODULE &&
(func_type == JS_PARSE_FUNC_STATEMENT || func_type == JS_PARSE_FUNC_VAR)) {
- JSHoistedDef *hf;
- hf = find_hoisted_def(fd, func_name);
+ JSGlobalVar *hf;
+ hf = find_global_var(fd, func_name);
/* XXX: should check scope chain */
if (hf && hf->scope_level == fd->scope_level) {
js_parse_error(s, "invalid redefinition of global identifier in module code");
@@ -32691,21 +32880,23 @@ static __exception int js_parse_function_decl2(JSParseState *s,
}
if (func_type == JS_PARSE_FUNC_VAR) {
- /* Create lexical name here so function closure contains it */
if (!(fd->js_mode & JS_MODE_STRICT)
+ && func_kind == JS_FUNC_NORMAL
&& find_lexical_decl(ctx, fd, func_name, fd->scope_first, FALSE) < 0
&& !((func_idx = find_var(ctx, fd, func_name)) >= 0 && (func_idx & ARGUMENT_VAR_OFFSET))
&& !(func_name == JS_ATOM_arguments && fd->has_arguments_binding)) {
create_func_var = TRUE;
}
+ /* Create the lexical name here so that the function closure
+ contains it */
if (fd->is_eval &&
(fd->eval_type == JS_EVAL_TYPE_GLOBAL ||
fd->eval_type == JS_EVAL_TYPE_MODULE) &&
- fd->scope_level == 1) {
+ fd->scope_level == fd->body_scope) {
/* avoid creating a lexical variable in the global
scope. XXX: check annex B */
- JSHoistedDef *hf;
- hf = find_hoisted_def(fd, func_name);
+ JSGlobalVar *hf;
+ hf = find_global_var(fd, func_name);
/* XXX: should check scope chain */
if (hf && hf->scope_level == fd->scope_level) {
js_parse_error(s, "invalid redefinition of global identifier");
@@ -32780,6 +32971,7 @@ static __exception int js_parse_function_decl2(JSParseState *s,
/* parse arguments */
fd->has_simple_parameter_list = TRUE;
+ fd->has_parameter_expressions = FALSE;
has_opt_arg = FALSE;
if (func_type == JS_PARSE_FUNC_ARROW && s->token.val == TOK_IDENT) {
JSAtom name;
@@ -32792,13 +32984,30 @@ static __exception int js_parse_function_decl2(JSParseState *s,
goto fail;
fd->defined_arg_count = 1;
} else {
- if (js_parse_expect(s, '('))
- goto fail;
+ if (s->token.val == '(') {
+ int skip_bits;
+ /* if there is an '=' inside the parameter list, we
+ consider there is a parameter expression inside */
+ js_parse_skip_parens_token(s, &skip_bits, FALSE);
+ if (skip_bits & SKIP_HAS_ASSIGNMENT)
+ fd->has_parameter_expressions = TRUE;
+ if (next_token(s))
+ goto fail;
+ } else {
+ if (js_parse_expect(s, '('))
+ goto fail;
+ }
+ if (fd->has_parameter_expressions) {
+ fd->scope_level = -1; /* force no parent scope */
+ if (push_scope(s) < 0)
+ return -1;
+ }
+
while (s->token.val != ')') {
JSAtom name;
BOOL rest = FALSE;
- int idx;
+ int idx, has_initializer;
if (s->token.val == TOK_ELLIPSIS) {
fd->has_simple_parameter_list = FALSE;
@@ -32817,8 +33026,13 @@ static __exception int js_parse_function_decl2(JSParseState *s,
emit_op(s, OP_get_arg);
emit_u16(s, idx);
}
- if (js_parse_destructuring_element(s, TOK_VAR, 1, TRUE, -1, TRUE))
+ has_initializer = js_parse_destructuring_element(s, fd->has_parameter_expressions ? TOK_LET : TOK_VAR, 1, TRUE, -1, TRUE);
+ if (has_initializer < 0)
goto fail;
+ if (has_initializer)
+ has_opt_arg = TRUE;
+ if (!has_opt_arg)
+ fd->defined_arg_count++;
} else if (s->token.val == TOK_IDENT) {
if (s->token.u.ident.is_reserved) {
js_parse_error_reserved_identifier(s);
@@ -32829,6 +33043,11 @@ static __exception int js_parse_function_decl2(JSParseState *s,
js_parse_error_reserved_identifier(s);
goto fail;
}
+ if (fd->has_parameter_expressions) {
+ if (define_var(s, fd, name, JS_VAR_DEF_LET) < 0)
+ goto fail;
+ }
+ /* XXX: could avoid allocating an argument if rest is true */
idx = add_arg(ctx, fd, name);
if (idx < 0)
goto fail;
@@ -32837,70 +33056,55 @@ static __exception int js_parse_function_decl2(JSParseState *s,
if (rest) {
emit_op(s, OP_rest);
emit_u16(s, idx);
+ if (fd->has_parameter_expressions) {
+ emit_op(s, OP_dup);
+ emit_op(s, OP_scope_put_var_init);
+ emit_atom(s, name);
+ emit_u16(s, fd->scope_level);
+ }
emit_op(s, OP_put_arg);
emit_u16(s, idx);
fd->has_simple_parameter_list = FALSE;
has_opt_arg = TRUE;
} else if (s->token.val == '=') {
+ int label;
+
fd->has_simple_parameter_list = FALSE;
has_opt_arg = TRUE;
if (next_token(s))
goto fail;
- /* optimize `x = void 0` default value: no code needed */
- if (s->token.val == TOK_VOID) {
- JSParsePos pos;
- js_parse_get_pos(s, &pos);
- if (next_token(s))
- goto fail;
- if (s->token.val == TOK_NUMBER) {
- if (next_token(s))
- goto fail;
- if (s->token.val == ',') {
- if (next_token(s))
- goto fail;
- continue;
- }
- if (s->token.val == ')') {
- continue;
- }
- }
- if (js_parse_seek_token(s, &pos))
- goto fail;
+ label = new_label(s);
+ emit_op(s, OP_get_arg);
+ emit_u16(s, idx);
+ emit_op(s, OP_dup);
+ emit_op(s, OP_undefined);
+ emit_op(s, OP_strict_eq);
+ emit_goto(s, OP_if_false, label);
+ emit_op(s, OP_drop);
+ if (js_parse_assign_expr(s))
+ goto fail;
+ set_object_name(s, name);
+ emit_op(s, OP_dup);
+ emit_op(s, OP_put_arg);
+ emit_u16(s, idx);
+ emit_label(s, label);
+ emit_op(s, OP_scope_put_var_init);
+ emit_atom(s, name);
+ emit_u16(s, fd->scope_level);
+ } else {
+ if (!has_opt_arg) {
+ fd->defined_arg_count++;
}
-#if 0
- /* XXX: not correct for eval code */
- /* Check for a default value of `undefined`
- to omit default argument processing */
- if (s->token.val == TOK_IDENT &&
- s->token.u.ident.atom == JS_ATOM_undefined &&
- fd->parent == NULL &&
- ((tok = peek_token(s, FALSE)) == ',' || tok == ')')) {
- if (next_token(s)) /* ignore undefined token */
- goto fail;
- } else
-#endif
- {
- int label = new_label(s);
- if (idx > 0) {
- emit_op(s, OP_set_arg_valid_upto);
- emit_u16(s, idx);
- }
+ if (fd->has_parameter_expressions) {
+ /* copy the argument to the argument scope */
emit_op(s, OP_get_arg);
emit_u16(s, idx);
- emit_op(s, OP_undefined);
- emit_op(s, OP_strict_eq);
- emit_goto(s, OP_if_false, label);
- if (js_parse_assign_expr(s, TRUE))
- goto fail;
- set_object_name(s, name);
- emit_op(s, OP_put_arg);
- emit_u16(s, idx);
- emit_label(s, label);
+ emit_op(s, OP_scope_put_var_init);
+ emit_atom(s, name);
+ emit_u16(s, fd->scope_level);
}
- } else if (!has_opt_arg) {
- fd->defined_arg_count++;
}
} else {
js_parse_error(s, "missing formal parameter");
@@ -32922,6 +33126,41 @@ static __exception int js_parse_function_decl2(JSParseState *s,
}
}
+ if (fd->has_parameter_expressions) {
+ int idx;
+
+ /* Copy the variables in the argument scope to the variable
+ scope (see FunctionDeclarationInstantiation() in spec). The
+ normal arguments are already present, so no need to copy
+ them. */
+ idx = fd->scopes[fd->scope_level].first;
+ while (idx >= 0) {
+ JSVarDef *vd = &fd->vars[idx];
+ if (vd->scope_level != fd->scope_level)
+ break;
+ if (find_var(ctx, fd, vd->var_name) < 0) {
+ if (add_var(ctx, fd, vd->var_name) < 0)
+ goto fail;
+ vd = &fd->vars[idx]; /* fd->vars may have been reallocated */
+ emit_op(s, OP_scope_get_var);
+ emit_atom(s, vd->var_name);
+ emit_u16(s, fd->scope_level);
+ emit_op(s, OP_scope_put_var);
+ emit_atom(s, vd->var_name);
+ emit_u16(s, 0);
+ }
+ idx = vd->scope_next;
+ }
+
+ /* the argument scope has no parent, hence we don't use pop_scope(s) */
+ emit_op(s, OP_leave_scope);
+ emit_u16(s, fd->scope_level);
+
+ /* set the variable scope as the current scope */
+ fd->scope_level = 0;
+ fd->scope_first = fd->scopes[fd->scope_level].first;
+ }
+
if (next_token(s))
goto fail;
@@ -32933,7 +33172,8 @@ static __exception int js_parse_function_decl2(JSParseState *s,
/* in generators, yield expression is forbidden during the parsing
of the arguments */
fd->in_function_body = TRUE;
- push_scope(s); /* enter body scope: fd->scope_level = 1 */
+ push_scope(s); /* enter body scope */
+ fd->body_scope = fd->scope_level;
if (s->token.val == TOK_ARROW) {
if (next_token(s))
@@ -32943,7 +33183,7 @@ static __exception int js_parse_function_decl2(JSParseState *s,
if (js_parse_function_check_names(s, fd, func_name))
goto fail;
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
goto fail;
if (func_kind != JS_FUNC_NORMAL)
@@ -33025,10 +33265,10 @@ done:
emit_u32(s, idx);
if (create_func_var) {
if (s->cur_func->is_global_var) {
- JSHoistedDef *hf;
+ JSGlobalVar *hf;
/* the global variable must be defined at the start of the
function */
- hf = add_hoisted_def(ctx, s->cur_func, -1, func_name, -1, FALSE);
+ hf = add_global_var(ctx, s->cur_func, func_name);
if (!hf)
goto fail;
/* it is considered as defined at the top level
@@ -33058,7 +33298,7 @@ done:
}
if (lexical_func_idx >= 0) {
/* lexical variable will be initialized upon entering scope */
- s->cur_func->vars[lexical_func_idx].func_pool_or_scope_idx = idx;
+ s->cur_func->vars[lexical_func_idx].func_pool_idx = idx;
emit_op(s, OP_drop);
} else {
/* store function object into its lexical name */
@@ -33074,17 +33314,23 @@ done:
if (var_idx < 0)
goto fail;
/* the variable will be assigned at the top of the function */
- if (!add_hoisted_def(ctx, s->cur_func, idx, JS_ATOM_NULL, var_idx, FALSE))
- goto fail;
+ if (var_idx & ARGUMENT_VAR_OFFSET) {
+ s->cur_func->args[var_idx - ARGUMENT_VAR_OFFSET].func_pool_idx = idx;
+ } else {
+ s->cur_func->vars[var_idx].func_pool_idx = idx;
+ }
} else {
JSAtom func_var_name;
+ JSGlobalVar *hf;
if (func_name == JS_ATOM_NULL)
func_var_name = JS_ATOM__default_; /* export default */
else
func_var_name = func_name;
/* the variable will be assigned at the top of the function */
- if (!add_hoisted_def(ctx, s->cur_func, idx, func_var_name, -1, FALSE))
+ hf = add_global_var(ctx, s->cur_func, func_var_name);
+ if (!hf)
goto fail;
+ hf->cpool_idx = idx;
if (export_flag != JS_PARSE_EXPORT_NONE) {
if (!add_export_entry(s, s->cur_func->module, func_var_name,
export_flag == JS_PARSE_EXPORT_NAMED ? func_var_name : JS_ATOM_default, JS_EXPORT_TYPE_LOCAL))
@@ -33186,7 +33432,7 @@ static JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj,
JS_FreeValue(ctx, fun_obj);
if (js_create_module_function(ctx, m) < 0)
goto fail;
- if (js_instantiate_module(ctx, m) < 0)
+ if (js_link_module(ctx, m) < 0)
goto fail;
ret_val = js_evaluate_module(ctx, m);
if (JS_IsException(ret_val)) {
@@ -33308,7 +33554,8 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
s->allow_html_comments = !s->is_module;
push_scope(s); /* body scope */
-
+ fd->body_scope = fd->scope_level;
+
err = js_parse_program(s);
if (err) {
fail:
@@ -33371,19 +33618,27 @@ static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
}
-JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,
- const char *filename, int eval_flags)
+JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj,
+ const char *input, size_t input_len,
+ const char *filename, int eval_flags)
{
int eval_type = eval_flags & JS_EVAL_TYPE_MASK;
JSValue ret;
assert(eval_type == JS_EVAL_TYPE_GLOBAL ||
eval_type == JS_EVAL_TYPE_MODULE);
- ret = JS_EvalInternal(ctx, ctx->global_obj, input, input_len, filename,
+ ret = JS_EvalInternal(ctx, this_obj, input, input_len, filename,
eval_flags, -1);
return ret;
}
+JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,
+ const char *filename, int eval_flags)
+{
+ return JS_EvalThis(ctx, ctx->global_obj, input, input_len, filename,
+ eval_flags);
+}
+
int JS_ResolveModule(JSContext *ctx, JSValueConst obj)
{
if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {
@@ -33980,7 +34235,6 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj)
bc_put_leb128(s, vd->scope_next + 1);
flags = idx = 0;
bc_set_flags(&flags, &idx, vd->var_kind, 4);
- bc_set_flags(&flags, &idx, vd->is_func_var, 1);
bc_set_flags(&flags, &idx, vd->is_const, 1);
bc_set_flags(&flags, &idx, vd->is_lexical, 1);
bc_set_flags(&flags, &idx, vd->is_captured, 1);
@@ -34971,7 +35225,6 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
goto fail;
idx = 0;
vd->var_kind = bc_get_flags(v8, &idx, 4);
- vd->is_func_var = bc_get_flags(v8, &idx, 1);
vd->is_const = bc_get_flags(v8, &idx, 1);
vd->is_lexical = bc_get_flags(v8, &idx, 1);
vd->is_captured = bc_get_flags(v8, &idx, 1);
@@ -35628,16 +35881,39 @@ static JSAtom find_atom(JSContext *ctx, const char *name)
return atom;
}
-static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p,
- JSAtom atom, void *opaque)
+static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p,
+ JSAtom atom, void *opaque)
{
const JSCFunctionListEntry *e = opaque;
- JSValueConst obj = JS_MKPTR(JS_TAG_OBJECT, p);
+ JSValue val;
+
+ switch(e->def_type) {
+ case JS_DEF_CFUNC:
+ val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic,
+ e->name, e->u.func.length, e->u.func.cproto, e->magic);
+ break;
+ case JS_DEF_PROP_STRING:
+ val = JS_NewAtomString(ctx, e->u.str);
+ break;
+ case JS_DEF_OBJECT:
+ val = JS_NewObject(ctx);
+ JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len);
+ break;
+ default:
+ abort();
+ }
+ return val;
+}
+
+static int JS_InstantiateFunctionListItem(JSContext *ctx, JSValueConst obj,
+ JSAtom atom,
+ const JSCFunctionListEntry *e)
+{
JSValue val;
int prop_flags = e->prop_flags;
switch(e->def_type) {
- case JS_DEF_ALIAS:
+ case JS_DEF_ALIAS: /* using autoinit for aliases is not safe */
{
JSAtom atom1 = find_atom(ctx, e->u.alias.name);
switch (e->u.alias.base) {
@@ -35654,12 +35930,16 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p,
abort();
}
JS_FreeAtom(ctx, atom1);
- goto setval;
+ if (atom == JS_ATOM_Symbol_toPrimitive) {
+ /* Symbol.toPrimitive functions are not writable */
+ prop_flags = JS_PROP_CONFIGURABLE;
+ } else if (atom == JS_ATOM_Symbol_hasInstance) {
+ /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */
+ prop_flags = 0;
+ }
}
+ break;
case JS_DEF_CFUNC:
- val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic,
- e->name, e->u.func.length, e->u.func.cproto, e->magic);
- setval:
if (atom == JS_ATOM_Symbol_toPrimitive) {
/* Symbol.toPrimitive functions are not writable */
prop_flags = JS_PROP_CONFIGURABLE;
@@ -35667,8 +35947,10 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p,
/* Function.prototype[Symbol.hasInstance] is not writable nor configurable */
prop_flags = 0;
}
- break;
- case JS_DEF_CGETSET:
+ JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP,
+ (void *)e, prop_flags);
+ return 0;
+ case JS_DEF_CGETSET: /* XXX: use autoinit again ? */
case JS_DEF_CGETSET_MAGIC:
{
JSValue getter, setter;
@@ -35692,9 +35974,6 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p,
return 0;
}
break;
- case JS_DEF_PROP_STRING:
- val = JS_NewAtomString(ctx, e->u.str);
- break;
case JS_DEF_PROP_INT32:
val = JS_NewInt32(ctx, e->u.i32);
break;
@@ -35707,10 +35986,11 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p,
case JS_DEF_PROP_UNDEFINED:
val = JS_UNDEFINED;
break;
+ case JS_DEF_PROP_STRING:
case JS_DEF_OBJECT:
- val = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len);
- break;
+ JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP,
+ (void *)e, prop_flags);
+ return 0;
default:
abort();
}
@@ -35721,36 +36001,12 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p,
void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
const JSCFunctionListEntry *tab, int len)
{
- int i, prop_flags;
+ int i;
for (i = 0; i < len; i++) {
const JSCFunctionListEntry *e = &tab[i];
JSAtom atom = find_atom(ctx, e->name);
-
- switch (e->def_type) {
- case JS_DEF_CFUNC:
- case JS_DEF_CGETSET:
- case JS_DEF_CGETSET_MAGIC:
- case JS_DEF_PROP_STRING:
- case JS_DEF_ALIAS:
- case JS_DEF_OBJECT:
- prop_flags = JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE | (e->prop_flags & JS_PROP_ENUMERABLE);
- JS_DefineAutoInitProperty(ctx, obj, atom,
- JS_AUTOINIT_ID_PROP,
- (void *)e, prop_flags);
- break;
- case JS_DEF_PROP_INT32:
- case JS_DEF_PROP_INT64:
- case JS_DEF_PROP_DOUBLE:
- case JS_DEF_PROP_UNDEFINED:
- {
- JSObject *p = JS_VALUE_GET_OBJ(obj);
- JS_InstantiateFunctionListItem(ctx, p, atom, (void *)e);
- }
- break;
- default:
- abort();
- }
+ JS_InstantiateFunctionListItem(ctx, obj, atom, e);
JS_FreeAtom(ctx, atom);
}
}
@@ -37262,6 +37518,8 @@ static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
return tab;
}
+/* magic value: 0 = normal apply, 1 = apply for constructor, 2 =
+ Reflect.apply */
static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
@@ -37273,14 +37531,14 @@ static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
this_arg = argv[0];
array_arg = argv[1];
- if (JS_VALUE_GET_TAG(array_arg) == JS_TAG_UNDEFINED ||
- JS_VALUE_GET_TAG(array_arg) == JS_TAG_NULL) {
+ if ((JS_VALUE_GET_TAG(array_arg) == JS_TAG_UNDEFINED ||
+ JS_VALUE_GET_TAG(array_arg) == JS_TAG_NULL) && magic != 2) {
return JS_Call(ctx, this_val, this_arg, 0, NULL);
}
tab = build_arg_list(ctx, &len, array_arg);
if (!tab)
return JS_EXCEPTION;
- if (magic) {
+ if (magic & 1) {
ret = JS_CallConstructor2(ctx, this_val, this_arg, len, (JSValueConst *)tab);
} else {
ret = JS_Call(ctx, this_val, this_arg, len, (JSValueConst *)tab);
@@ -37650,7 +37908,7 @@ static JSValue js_array_constructor(JSContext *ctx, JSValueConst new_target,
return obj;
if (argc == 1 && JS_IsNumber(argv[0])) {
uint32_t len;
- if (JS_ToArrayLengthFree(ctx, &len, JS_DupValue(ctx, argv[0])))
+ if (JS_ToArrayLengthFree(ctx, &len, JS_DupValue(ctx, argv[0]), TRUE))
goto fail;
if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, len)) < 0)
goto fail;
@@ -39659,46 +39917,6 @@ static int js_string_get_own_property(JSContext *ctx,
return FALSE;
}
-static uint32_t js_string_obj_get_length(JSContext *ctx,
- JSValueConst obj)
-{
- JSObject *p;
- JSString *p1;
- uint32_t len = 0;
-
- /* This is a class exotic method: obj class_id is JS_CLASS_STRING */
- p = JS_VALUE_GET_OBJ(obj);
- if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {
- p1 = JS_VALUE_GET_STRING(p->u.object_data);
- len = p1->len;
- }
- return len;
-}
-
-static int js_string_get_own_property_names(JSContext *ctx,
- JSPropertyEnum **ptab,
- uint32_t *plen,
- JSValueConst obj)
-{
- JSPropertyEnum *tab;
- uint32_t len, i;
-
- len = js_string_obj_get_length(ctx, obj);
- tab = NULL;
- if (len > 0) {
- /* do not allocate 0 bytes */
- tab = js_malloc(ctx, sizeof(JSPropertyEnum) * len);
- if (!tab)
- return -1;
- for(i = 0; i < len; i++) {
- tab[i].atom = __JS_AtomFromUInt32(i);
- }
- }
- *ptab = tab;
- *plen = len;
- return 0;
-}
-
static int js_string_define_own_property(JSContext *ctx,
JSValueConst this_obj,
JSAtom prop, JSValueConst val,
@@ -39755,7 +39973,6 @@ static int js_string_delete_property(JSContext *ctx,
static const JSClassExoticMethods js_string_exotic_methods = {
.get_own_property = js_string_get_own_property,
- .get_own_property_names = js_string_get_own_property_names,
.define_own_property = js_string_define_own_property,
.delete_property = js_string_delete_property,
};
@@ -40359,15 +40576,17 @@ static JSValue js_string___GetSubstitution(JSContext *ctx, JSValueConst this_val
string_buffer_concat(b, sp, position + matched_len, sp->len);
} else if (c >= '0' && c <= '9') {
k = c - '0';
- c1 = string_get(rp, j);
- if (c1 >= '0' && c1 <= '9') {
- /* This behavior is specified in ES6 and refined in ECMA 2019 */
- /* ECMA 2019 does not have the extra test, but
- Test262 S15.5.4.11_A3_T1..3 require this behavior */
- k1 = k * 10 + c1 - '0';
- if (k1 >= 1 && k1 < captures_len) {
- k = k1;
- j++;
+ if (j < len) {
+ c1 = string_get(rp, j);
+ if (c1 >= '0' && c1 <= '9') {
+ /* This behavior is specified in ES6 and refined in ECMA 2019 */
+ /* ECMA 2019 does not have the extra test, but
+ Test262 S15.5.4.11_A3_T1..3 require this behavior */
+ k1 = k * 10 + c1 - '0';
+ if (k1 >= 1 && k1 < captures_len) {
+ k = k1;
+ j++;
+ }
}
}
if (k >= 1 && k < captures_len) {
@@ -42805,7 +43024,8 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val,
tab = JS_NewArray(ctx);
if (JS_IsException(tab))
goto exception;
- if (JS_SetPropertyInt64(ctx, tab, 0, JS_DupValue(ctx, matched)) < 0)
+ if (JS_DefinePropertyValueInt64(ctx, tab, 0, JS_DupValue(ctx, matched),
+ JS_PROP_C_W_E | JS_PROP_THROW) < 0)
goto exception;
for(n = 1; n < nCaptures; n++) {
JSValue capN;
@@ -42817,7 +43037,8 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val,
if (JS_IsException(capN))
goto exception;
}
- if (JS_SetPropertyInt64(ctx, tab, n, capN) < 0)
+ if (JS_DefinePropertyValueInt64(ctx, tab, n, capN,
+ JS_PROP_C_W_E | JS_PROP_THROW) < 0)
goto exception;
}
JS_FreeValue(ctx, namedCaptures);
@@ -42825,12 +43046,12 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val,
if (JS_IsException(namedCaptures))
goto exception;
if (functionalReplace) {
- if (JS_SetPropertyInt64(ctx, tab, n++, JS_NewInt32(ctx, position)) < 0)
+ if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_NewInt32(ctx, position), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
goto exception;
- if (JS_SetPropertyInt64(ctx, tab, n++, JS_DupValue(ctx, str)) < 0)
+ if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, str), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
goto exception;
if (!JS_IsUndefined(namedCaptures)) {
- if (JS_SetPropertyInt64(ctx, tab, n++, JS_DupValue(ctx, namedCaptures)) < 0)
+ if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, namedCaptures), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
goto exception;
}
args[0] = JS_UNDEFINED;
@@ -42917,8 +43138,10 @@ static JSValue js_regexp_Symbol_search(JSContext *ctx, JSValueConst this_val,
if (js_same_value(ctx, currentLastIndex, previousLastIndex)) {
JS_FreeValue(ctx, previousLastIndex);
} else {
- if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, previousLastIndex) < 0)
+ if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, previousLastIndex) < 0) {
+ previousLastIndex = JS_UNDEFINED;
goto exception;
+ }
}
JS_FreeValue(ctx, str);
JS_FreeValue(ctx, currentLastIndex);
@@ -43023,7 +43246,8 @@ static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val,
sub = js_sub_string(ctx, strp, p, q);
if (JS_IsException(sub))
goto exception;
- if (JS_SetPropertyInt64(ctx, A, lengthA++, sub) < 0)
+ if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub,
+ JS_PROP_C_W_E | JS_PROP_THROW) < 0)
goto exception;
if (lengthA == lim)
goto done;
@@ -43034,7 +43258,7 @@ static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val,
sub = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, z, i));
if (JS_IsException(sub))
goto exception;
- if (JS_SetPropertyInt64(ctx, A, lengthA++, sub) < 0)
+ if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
goto exception;
if (lengthA == lim)
goto done;
@@ -43049,7 +43273,7 @@ add_tail:
sub = js_sub_string(ctx, strp, p, size);
if (JS_IsException(sub))
goto exception;
- if (JS_SetPropertyInt64(ctx, A, lengthA++, sub) < 0)
+ if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
goto exception;
goto done;
exception:
@@ -43829,7 +44053,7 @@ void JS_AddIntrinsicJSON(JSContext *ctx)
static JSValue js_reflect_apply(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
- return js_function_apply(ctx, argv[0], max_int(0, argc - 1), argv + 1, 0);
+ return js_function_apply(ctx, argv[0], max_int(0, argc - 1), argv + 1, 2);
}
static JSValue js_reflect_construct(JSContext *ctx, JSValueConst this_val,
@@ -46772,26 +46996,15 @@ static JSValue js_promise_then_finally_func(JSContext *ctx, JSValueConst this_va
{
JSValueConst ctor = func_data[0];
JSValueConst onFinally = func_data[1];
- JSValue res, promise, resolving_funcs[2], ret, then_func;
+ JSValue res, promise, ret, then_func;
res = JS_Call(ctx, onFinally, JS_UNDEFINED, 0, NULL);
if (JS_IsException(res))
return res;
- promise = js_new_promise_capability(ctx, resolving_funcs, ctor);
- if (JS_IsException(promise)) {
- JS_FreeValue(ctx, res);
- return JS_EXCEPTION;
- }
- ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED,
- 1, (JSValueConst*)&res);
+ promise = js_promise_resolve(ctx, ctor, 1, (JSValueConst *)&res, 0);
JS_FreeValue(ctx, res);
- JS_FreeValue(ctx, resolving_funcs[0]);
- JS_FreeValue(ctx, resolving_funcs[1]);
- if (JS_IsException(ret)) {
- JS_FreeValue(ctx, promise);
- return ret;
- }
- JS_FreeValue(ctx, ret);
+ if (JS_IsException(promise))
+ return promise;
if (magic == 0) {
then_func = JS_NewCFunctionData(ctx, js_promise_finally_value_thunk, 0,
0, 1, argv);
@@ -47503,7 +47716,7 @@ static JSValue JS_SetThisTimeValue(JSContext *ctx, JSValueConst this_val, double
JSObject *p = JS_VALUE_GET_OBJ(this_val);
if (p->class_id == JS_CLASS_DATE) {
JS_FreeValue(ctx, p->u.object_data);
- p->u.object_data = __JS_NewFloat64(ctx, v);
+ p->u.object_data = JS_NewFloat64(ctx, v);
return JS_DupValue(ctx, p->u.object_data);
}
}
@@ -47547,7 +47760,7 @@ static char const month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
static char const day_names[] = "SunMonTueWedThuFriSat";
static __exception int get_date_fields(JSContext *ctx, JSValueConst obj,
- int64_t fields[9], int is_local, int force)
+ double fields[9], int is_local, int force)
{
double dval;
int64_t d, days, wd, y, i, md, h, m, s, ms, tz = 0;
@@ -47606,12 +47819,18 @@ static double time_clip(double t) {
return NAN;
}
-static double set_date_fields(int64_t fields[], int is_local) {
- int64_t days, y, m, md, h, d, i;
-
- i = fields[1];
- m = math_mod(i, 12);
- y = fields[0] + (i - m) / 12;
+/* The spec mandates the use of 'double' and it fixes the order
+ of the operations */
+static double set_date_fields(double fields[], int is_local) {
+ int64_t y;
+ double days, d, h, m1;
+ int i, m, md;
+
+ m1 = fields[1];
+ m = fmod(m1, 12);
+ if (m < 0)
+ m += 12;
+ y = (int64_t)(fields[0] + floor(m1 / 12));
days = days_from_year(y);
for(i = 0; i < m; i++) {
@@ -47621,7 +47840,8 @@ static double set_date_fields(int64_t fields[], int is_local) {
days += md;
}
days += fields[2] - 1;
- h = ((fields[3] * 60 + fields[4]) * 60 + fields[5]) * 1000 + fields[6];
+ h = fields[3] * 3600000 + fields[4] * 60000 +
+ fields[5] * 1000 + fields[6];
d = days * 86400000 + h;
if (is_local)
d += getTimezoneOffset(d) * 60000;
@@ -47632,7 +47852,7 @@ static JSValue get_date_field(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
// get_date_field(obj, n, is_local)
- int64_t fields[9];
+ double fields[9];
int res, n, is_local;
is_local = magic & 0x0F;
@@ -47646,14 +47866,14 @@ static JSValue get_date_field(JSContext *ctx, JSValueConst this_val,
if (magic & 0x100) { // getYear
fields[0] -= 1900;
}
- return JS_NewInt64(ctx, fields[n]);
+ return JS_NewFloat64(ctx, fields[n]);
}
static JSValue set_date_field(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
// _field(obj, first_field, end_field, args, is_local)
- int64_t fields[9];
+ double fields[9];
int res, first_field, end_field, is_local, i, n;
double d, a;
@@ -47695,7 +47915,7 @@ static JSValue get_date_string(JSContext *ctx, JSValueConst this_val,
{
// _string(obj, fmt, part)
char buf[64];
- int64_t fields[9];
+ double fields[9];
int res, fmt, part, pos;
int y, mon, d, h, m, s, ms, wd, tz;
@@ -47843,7 +48063,7 @@ static JSValue js_date_constructor(JSContext *ctx, JSValueConst new_target,
}
val = time_clip(val);
} else {
- int64_t fields[] = { 0, 0, 1, 0, 0, 0, 0 };
+ double fields[] = { 0, 0, 1, 0, 0, 0, 0 };
if (n > 7)
n = 7;
for(i = 0; i < n; i++) {
@@ -47862,12 +48082,12 @@ has_val:
JSValueConst args[3];
args[0] = new_target;
args[1] = ctx->class_proto[JS_CLASS_DATE];
- args[2] = __JS_NewFloat64(ctx, val);
+ args[2] = JS_NewFloat64(ctx, val);
rv = js___date_create(ctx, JS_UNDEFINED, 3, args);
#else
rv = js_create_from_ctor(ctx, new_target, JS_CLASS_DATE);
if (!JS_IsException(rv))
- JS_SetObjectData(ctx, rv, __JS_NewFloat64(ctx, val));
+ JS_SetObjectData(ctx, rv, JS_NewFloat64(ctx, val));
#endif
if (!JS_IsException(rv) && JS_IsUndefined(new_target)) {
/* invoked as a function, return (new Date()).toString(); */
@@ -47883,7 +48103,7 @@ static JSValue js_Date_UTC(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
// UTC(y, mon, d, h, m, s, ms)
- int64_t fields[] = { 0, 0, 1, 0, 0, 0, 0 };
+ double fields[] = { 0, 0, 1, 0, 0, 0, 0 };
int i, n;
double a;
@@ -47901,7 +48121,7 @@ static JSValue js_Date_UTC(JSContext *ctx, JSValueConst this_val,
if (i == 0 && fields[0] >= 0 && fields[0] < 100)
fields[0] += 1900;
}
- return __JS_NewFloat64(ctx, set_date_fields(fields, 0));
+ return JS_NewFloat64(ctx, set_date_fields(fields, 0));
}
static void string_skip_spaces(JSString *sp, int *pp) {
@@ -48011,6 +48231,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
// parse(s)
JSValue s, rv;
int64_t fields[] = { 0, 1, 1, 0, 0, 0, 0 };
+ double fields1[7];
int64_t tz, hh, mm;
double d;
int p, i, c, sgn;
@@ -48123,8 +48344,10 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
}
}
}
- d = set_date_fields(fields, is_local) - tz * 60000;
- rv = __JS_NewFloat64(ctx, d);
+ for(i = 0; i < 7; i++)
+ fields1[i] = fields[i];
+ d = set_date_fields(fields1, is_local) - tz * 60000;
+ rv = JS_NewFloat64(ctx, d);
done:
JS_FreeValue(ctx, s);
@@ -48194,7 +48417,7 @@ static JSValue js_date_getTime(JSContext *ctx, JSValueConst this_val,
if (JS_ThisTimeValue(ctx, &v, this_val))
return JS_EXCEPTION;
- return __JS_NewFloat64(ctx, v);
+ return JS_NewFloat64(ctx, v);
}
static JSValue js_date_setTime(JSContext *ctx, JSValueConst this_val,
@@ -48223,7 +48446,7 @@ static JSValue js_date_setYear(JSContext *ctx, JSValueConst this_val,
if (y >= 0 && y < 100)
y += 1900;
}
- args[0] = __JS_NewFloat64(ctx, y);
+ args[0] = JS_NewFloat64(ctx, y);
return set_date_field(ctx, this_val, 1, args, 0x011);
}
@@ -48714,9 +48937,11 @@ static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val)
}
static JSValue js_bigint_constructor(JSContext *ctx,
- JSValueConst this_val,
+ JSValueConst new_target,
int argc, JSValueConst *argv)
{
+ if (!JS_IsUndefined(new_target))
+ return JS_ThrowTypeError(ctx, "not a constructor");
return JS_ToBigIntCtorFree(ctx, JS_DupValue(ctx, argv[0]));
}
@@ -48962,7 +49187,7 @@ static const JSCFunctionListEntry js_bigint_proto_funcs[] = {
void JS_AddIntrinsicBigInt(JSContext *ctx)
{
JSRuntime *rt = ctx->rt;
- JSValue obj1;
+ JSValueConst obj1;
rt->bigint_ops.to_string = js_bigint_to_string;
rt->bigint_ops.from_string = js_string_to_bigint;
@@ -48974,9 +49199,8 @@ void JS_AddIntrinsicBigInt(JSContext *ctx)
JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_INT],
js_bigint_proto_funcs,
countof(js_bigint_proto_funcs));
- obj1 = JS_NewCFunction(ctx, js_bigint_constructor, "BigInt", 1);
- JS_NewGlobalCConstructor2(ctx, obj1, "BigInt",
- ctx->class_proto[JS_CLASS_BIG_INT]);
+ obj1 = JS_NewGlobalCConstructor(ctx, "BigInt", js_bigint_constructor, 1,
+ ctx->class_proto[JS_CLASS_BIG_INT]);
JS_SetPropertyFunctionList(ctx, obj1, js_bigint_funcs,
countof(js_bigint_funcs));
}
@@ -49194,10 +49418,12 @@ static const JSCFunctionListEntry js_bigfloat_proto_funcs[] = {
};
static JSValue js_bigfloat_constructor(JSContext *ctx,
- JSValueConst this_val,
+ JSValueConst new_target,
int argc, JSValueConst *argv)
{
JSValue val;
+ if (!JS_IsUndefined(new_target))
+ return JS_ThrowTypeError(ctx, "not a constructor");
if (argc == 0) {
bf_t *r;
val = JS_NewBigFloat(ctx);
@@ -49858,8 +50084,7 @@ static const JSCFunctionListEntry js_float_env_proto_funcs[] = {
void JS_AddIntrinsicBigFloat(JSContext *ctx)
{
JSRuntime *rt = ctx->rt;
- JSValue obj1;
- JSValueConst obj2;
+ JSValueConst obj1;
rt->bigfloat_ops.to_string = js_bigfloat_to_string;
rt->bigfloat_ops.from_string = js_string_to_bigfloat;
@@ -49873,9 +50098,8 @@ void JS_AddIntrinsicBigFloat(JSContext *ctx)
JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT],
js_bigfloat_proto_funcs,
countof(js_bigfloat_proto_funcs));
- obj1 = JS_NewCFunction(ctx, js_bigfloat_constructor, "BigFloat", 1);
- JS_NewGlobalCConstructor2(ctx, obj1, "BigFloat",
- ctx->class_proto[JS_CLASS_BIG_FLOAT]);
+ obj1 = JS_NewGlobalCConstructor(ctx, "BigFloat", js_bigfloat_constructor, 1,
+ ctx->class_proto[JS_CLASS_BIG_FLOAT]);
JS_SetPropertyFunctionList(ctx, obj1, js_bigfloat_funcs,
countof(js_bigfloat_funcs));
@@ -49883,10 +50107,10 @@ void JS_AddIntrinsicBigFloat(JSContext *ctx)
JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_FLOAT_ENV],
js_float_env_proto_funcs,
countof(js_float_env_proto_funcs));
- obj2 = JS_NewGlobalCConstructorOnly(ctx, "BigFloatEnv",
+ obj1 = JS_NewGlobalCConstructorOnly(ctx, "BigFloatEnv",
js_float_env_constructor, 1,
ctx->class_proto[JS_CLASS_FLOAT_ENV]);
- JS_SetPropertyFunctionList(ctx, obj2, js_float_env_funcs,
+ JS_SetPropertyFunctionList(ctx, obj1, js_float_env_funcs,
countof(js_float_env_funcs));
}
@@ -49989,10 +50213,12 @@ static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val,
}
static JSValue js_bigdecimal_constructor(JSContext *ctx,
- JSValueConst this_val,
+ JSValueConst new_target,
int argc, JSValueConst *argv)
{
JSValue val;
+ if (!JS_IsUndefined(new_target))
+ return JS_ThrowTypeError(ctx, "not a constructor");
if (argc == 0) {
bfdec_t *r;
val = JS_NewBigDecimal(ctx);
@@ -50348,7 +50574,7 @@ static const JSCFunctionListEntry js_bigdecimal_funcs[] = {
void JS_AddIntrinsicBigDecimal(JSContext *ctx)
{
JSRuntime *rt = ctx->rt;
- JSValue obj1;
+ JSValueConst obj1;
rt->bigdecimal_ops.to_string = js_bigdecimal_to_string;
rt->bigdecimal_ops.from_string = js_string_to_bigdecimal;
@@ -50360,9 +50586,9 @@ void JS_AddIntrinsicBigDecimal(JSContext *ctx)
JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL],
js_bigdecimal_proto_funcs,
countof(js_bigdecimal_proto_funcs));
- obj1 = JS_NewCFunction(ctx, js_bigdecimal_constructor, "BigDecimal", 1);
- JS_NewGlobalCConstructor2(ctx, obj1, "BigDecimal",
- ctx->class_proto[JS_CLASS_BIG_DECIMAL]);
+ obj1 = JS_NewGlobalCConstructor(ctx, "BigDecimal",
+ js_bigdecimal_constructor, 1,
+ ctx->class_proto[JS_CLASS_BIG_DECIMAL]);
JS_SetPropertyFunctionList(ctx, obj1, js_bigdecimal_funcs,
countof(js_bigdecimal_funcs));
}
@@ -50818,8 +51044,7 @@ static JSValue js_array_buffer_get_byteLength(JSContext *ctx,
JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, class_id);
if (!abuf)
return JS_EXCEPTION;
- if (abuf->detached)
- return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+ /* return 0 if detached */
return JS_NewUint32(ctx, abuf->byte_length);
}
diff --git a/quickjs.h b/quickjs.h
index bb84829..92457a2 100644
--- a/quickjs.h
+++ b/quickjs.h
@@ -776,7 +776,10 @@ JS_BOOL JS_DetectModule(const char *input, size_t input_len);
/* 'input' must be zero terminated i.e. input[input_len] = '\0'. */
JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,
const char *filename, int eval_flags);
-JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj);
+/* same as JS_Eval() but with an explicit 'this_obj' parameter */
+JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj,
+ const char *input, size_t input_len,
+ const char *filename, int eval_flags);
JSValue JS_GetGlobalObject(JSContext *ctx);
int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj);
int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
@@ -885,7 +888,9 @@ uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj,
#define JS_READ_OBJ_REFERENCE (1 << 3) /* allow object references */
JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len,
int flags);
-
+/* instantiate and evaluate a bytecode function. Only used when
+ reading a script or module with JS_ReadObject() */
+JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj);
/* load the dependencies of the module 'obj'. Useful when JS_ReadObject()
returns a module. */
int JS_ResolveModule(JSContext *ctx, JSValueConst obj);
diff --git a/release.sh b/release.sh
index a0bd6eb..6dc89fb 100755
--- a/release.sh
+++ b/release.sh
@@ -6,30 +6,23 @@ set -e
version=`cat VERSION`
if [ "$1" = "-h" ] ; then
- echo "release.sh [all]"
+ echo "release.sh [release_list]"
echo ""
- echo "all: build all the archives. Otherwise only build the quickjs source archive."
+ echo "release_list: extras binary win_binary quickjs"
+
exit 1
fi
-extras="no"
-binary="no"
-quickjs="no"
-
-if [ "$1" = "all" ] ; then
- extras="yes"
- binary="yes"
- quickjs="yes"
-elif [ "$1" = "binary" ] ; then
- binary="yes"
-else
- quickjs="yes"
+release_list="extras binary win_binary quickjs"
+
+if [ "$1" != "" ] ; then
+ release_list="$1"
fi
#################################################"
# extras
-if [ "$extras" = "yes" ] ; then
+if echo $release_list | grep -w -q extras ; then
d="quickjs-${version}"
name="quickjs-extras-${version}"
@@ -46,10 +39,58 @@ cp -a tests/bench-v8 $outdir/tests
fi
#################################################"
-# binary release
+# Windows binary release
+
+if echo $release_list | grep -w -q win_binary ; then
+
+# win64
+
+dlldir=/usr/x86_64-w64-mingw32/sys-root/mingw/bin
+cross_prefix="x86_64-w64-mingw32-"
+d="quickjs-win-x86_64-${version}"
+outdir="/tmp/${d}"
+
+rm -rf $outdir
+mkdir -p $outdir
+
+make CONFIG_WIN32=y qjs.exe
+cp qjs.exe $outdir
+${cross_prefix}strip $outdir/qjs.exe
+cp $dlldir/libwinpthread-1.dll $outdir
+
+( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
+
+make CONFIG_WIN32=y clean
+
+# win32
+
+dlldir=/usr/i686-w64-mingw32/sys-root/mingw/bin
+cross_prefix="i686-w64-mingw32-"
+d="quickjs-win-i686-${version}"
+outdir="/tmp/${d}"
+
+rm -rf $outdir
+mkdir -p $outdir
+
+make clean
+make CONFIG_WIN32=y clean
+
+make CONFIG_WIN32=y CONFIG_M32=y qjs.exe
+cp qjs.exe $outdir
+${cross_prefix}strip $outdir/qjs.exe
+cp $dlldir/libwinpthread-1.dll $outdir
+
+( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
+
+fi
+
+#################################################"
+# Linux binary release
-if [ "$binary" = "yes" ] ; then
+if echo $release_list | grep -w -q binary ; then
+make clean
+make CONFIG_WIN32=y clean
make -j4 qjs run-test262
make -j4 CONFIG_M32=y qjs32 run-test262-32
strip qjs run-test262 qjs32 run-test262-32
@@ -80,7 +121,7 @@ fi
#################################################"
# quickjs
-if [ "$quickjs" = "yes" ] ; then
+if echo $release_list | grep -w -q quickjs ; then
make build_doc
@@ -98,7 +139,7 @@ cp Makefile VERSION TODO Changelog readme.txt release.sh unicode_download.sh \
libregexp.c libregexp.h libregexp-opcode.h \
libunicode.c libunicode.h libunicode-table.h \
libbf.c libbf.h \
- jscompress.c unicode_gen.c unicode_gen_def.h \
+ unicode_gen.c unicode_gen_def.h \
run-test262.c test262o.conf test262.conf \
test262o_errors.txt test262_errors.txt \
$outdir
diff --git a/test262.conf b/test262.conf
index e1eeb03..f30a4ac 100644
--- a/test262.conf
+++ b/test262.conf
@@ -49,9 +49,12 @@ testdir=test262/test
# skipped features are tagged as such to avoid warnings
AggregateError
+align-detached-buffer-semantics-with-web-reality
+arbitrary-module-namespace-names=skip
Array.prototype.flat
Array.prototype.flatMap
Array.prototype.flatten
+Array.prototype.item=skip
Array.prototype.values
ArrayBuffer
arrow-function
@@ -82,7 +85,6 @@ DataView.prototype.getInt8
DataView.prototype.getUint16
DataView.prototype.getUint32
DataView.prototype.setUint8
-default-arg
default-parameters
destructuring-assignment
destructuring-binding
@@ -90,6 +92,7 @@ dynamic-import
export-star-as-namespace-from-module
FinalizationGroup=skip
FinalizationRegistry=skip
+FinalizationRegistry.prototype.cleanupSome=skip
Float32Array
Float64Array
for-in-order
@@ -99,10 +102,12 @@ globalThis
hashbang
host-gc-required=skip
import.meta
+Int16Array
Int32Array
Int8Array
IsHTMLDDA
json-superset
+legacy-regexp=skip
let
logical-assignment-operators
Map
@@ -114,6 +119,7 @@ Object.fromEntries
Object.is
optional-catch-binding
optional-chaining
+Promise
Promise.allSettled
Promise.any
Promise.prototype.finally
@@ -135,6 +141,7 @@ string-trimming
String.fromCodePoint
String.prototype.endsWith
String.prototype.includes
+String.prototype.item=skip
String.prototype.matchAll
String.prototype.replaceAll
String.prototype.trimEnd
@@ -159,14 +166,19 @@ tail-call-optimization=skip
template
top-level-await=skip
TypedArray
+TypedArray.prototype.item=skip
u180e
Uint16Array
+Uint32Array
Uint8Array
Uint8ClampedArray
WeakMap
WeakRef=skip
WeakSet
well-formed-json-stringify
+__getter__
+__proto__
+__setter__
[exclude]
# list excluded tests and directories here
@@ -183,8 +195,5 @@ test262/test/built-ins/ThrowTypeError/unique-per-realm-function-proto.js
#test262/test/built-ins/RegExp/CharacterClassEscapes/
#test262/test/built-ins/RegExp/property-escapes/
-# invalid tests
-test262/test/language/module-code/verify-dfs.js
-
[tests]
# list test files or use config.testdir
diff --git a/test262_errors.txt b/test262_errors.txt
index d00d4f1..502a650 100644
--- a/test262_errors.txt
+++ b/test262_errors.txt
@@ -1,30 +1,51 @@
test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: Test262Error: Expected a ReferenceError but got a ReferenceError
test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: strict mode: Test262Error: Expected a ReferenceError but got a ReferenceError
-test262/test/built-ins/Proxy/ownKeys/trap-is-undefined-target-is-proxy.js:29: Test262Error: Expected [0, length, foo, Symbol()] and [Symbol(), length, foo, 0] to have the same contents.
-test262/test/built-ins/Proxy/ownKeys/trap-is-undefined-target-is-proxy.js:29: strict mode: Test262Error: Expected [0, length, foo, Symbol()] and [Symbol(), length, foo, 0] to have the same contents.
test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: SyntaxError: invalid group name
test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: strict mode: SyntaxError: invalid group name
-test262/test/language/expressions/arrow-function/eval-var-scope-syntax-err.js:47: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
-test262/test/language/expressions/async-arrow-function/eval-var-scope-syntax-err.js:49: TypeError: $DONE() not called
-test262/test/language/expressions/async-function/named-eval-var-scope-syntax-err.js:33: TypeError: $DONE() not called
-test262/test/language/expressions/async-function/nameless-eval-var-scope-syntax-err.js:33: TypeError: $DONE() not called
-test262/test/language/expressions/async-generator/eval-var-scope-syntax-err.js:28: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
-test262/test/language/expressions/async-generator/named-eval-var-scope-syntax-err.js:28: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
-test262/test/language/expressions/class/elements/grammar-private-field-optional-chaining.js:26: SyntaxError: expecting field name
-test262/test/language/expressions/class/elements/grammar-private-field-optional-chaining.js:26: strict mode: SyntaxError: expecting field name
+test262/test/built-ins/TypedArray/prototype/every/BigInt/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArray/prototype/every/BigInt/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArray/prototype/every/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArray/prototype/every/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArray/prototype/filter/BigInt/callbackfn-detachbuffer.js:20: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArray/prototype/filter/BigInt/callbackfn-detachbuffer.js:20: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArray/prototype/filter/callbackfn-detachbuffer.js:20: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArray/prototype/filter/callbackfn-detachbuffer.js:20: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArray/prototype/findIndex/BigInt/predicate-may-detach-buffer.js:36: Test262Error: throws a TypeError getting a value from the detached buffer Expected a TypeError to be thrown but no exception was thrown at all (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArray/prototype/findIndex/BigInt/predicate-may-detach-buffer.js:36: strict mode: Test262Error: throws a TypeError getting a value from the detached buffer Expected a TypeError to be thrown but no exception was thrown at all (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArray/prototype/forEach/BigInt/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArray/prototype/forEach/BigInt/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArray/prototype/forEach/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArray/prototype/forEach/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArray/prototype/map/BigInt/callbackfn-detachbuffer.js:20: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArray/prototype/map/BigInt/callbackfn-detachbuffer.js:20: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArray/prototype/map/callbackfn-detachbuffer.js:20: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArray/prototype/map/callbackfn-detachbuffer.js:20: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArray/prototype/reduce/BigInt/callbackfn-detachbuffer.js:29: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArray/prototype/reduce/BigInt/callbackfn-detachbuffer.js:29: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArray/prototype/reduce/callbackfn-detachbuffer.js:29: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArray/prototype/reduce/callbackfn-detachbuffer.js:29: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArray/prototype/reduceRight/BigInt/callbackfn-detachbuffer.js:29: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArray/prototype/reduceRight/BigInt/callbackfn-detachbuffer.js:29: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArray/prototype/reduceRight/callbackfn-detachbuffer.js:29: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArray/prototype/reduceRight/callbackfn-detachbuffer.js:29: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArray/prototype/some/BigInt/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArray/prototype/some/BigInt/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArray/prototype/some/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArray/prototype/some/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:37: Test262Error: (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:37: strict mode: Test262Error: (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:38: Test262Error: (Testing with Float64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:38: strict mode: Test262Error: (Testing with Float64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/GetOwnProperty/BigInt/index-prop-desc.js:21: Test262Error: Expected SameValue(«43», «42») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/GetOwnProperty/BigInt/index-prop-desc.js:21: strict mode: Test262Error: Expected SameValue(«43», «42») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/GetOwnProperty/index-prop-desc.js:22: Test262Error: Expected SameValue(«43», «42») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/GetOwnProperty/index-prop-desc.js:22: strict mode: Test262Error: Expected SameValue(«43», «42») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer-realm.js:36: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer.js:34: TypeError: cannot convert bigint to number (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer.js:32: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer-realm.js:36: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer.js:32: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.)
test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: TypeError: $DONE() not called
test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: strict mode: TypeError: $DONE() not called
-test262/test/language/expressions/function/eval-var-scope-syntax-err.js:48: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
-test262/test/language/expressions/generators/eval-var-scope-syntax-err.js:49: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
-test262/test/language/expressions/object/method-definition/async-gen-meth-eval-var-scope-syntax-err.js:32: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
-test262/test/language/expressions/object/method-definition/async-meth-eval-var-scope-syntax-err.js:36: TypeError: $DONE() not called
-test262/test/language/expressions/object/method-definition/gen-meth-eval-var-scope-syntax-err.js:54: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
-test262/test/language/expressions/object/method-definition/meth-eval-var-scope-syntax-err.js:50: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:21: TypeError: cannot read property 'c' of undefined
test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: cannot read property '_b' of undefined
-test262/test/language/statements/async-function/eval-var-scope-syntax-err.js:33: TypeError: $DONE() not called
-test262/test/language/statements/async-generator/eval-var-scope-syntax-err.js:28: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
-test262/test/language/statements/class/elements/grammar-private-field-optional-chaining.js:26: SyntaxError: expecting field name
-test262/test/language/statements/class/elements/grammar-private-field-optional-chaining.js:26: strict mode: SyntaxError: expecting field name
-test262/test/language/statements/function/eval-var-scope-syntax-err.js:49: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
-test262/test/language/statements/generators/eval-var-scope-syntax-err.js:49: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
diff --git a/tests/test_builtin.js b/tests/test_builtin.js
index 5650c52..c044b2c 100644
--- a/tests/test_builtin.js
+++ b/tests/test_builtin.js
@@ -17,6 +17,22 @@ function assert(actual, expected, message) {
(message ? " (" + message + ")" : ""));
}
+function assert_throws(expected_error, func)
+{
+ var err = false;
+ try {
+ func();
+ } catch(e) {
+ err = true;
+ if (!(e instanceof expected_error)) {
+ throw Error("unexpected exception type");
+ }
+ }
+ if (!err) {
+ throw Error("expected exception");
+ }
+}
+
// load more elaborate version of assert if available
try { __loadScript("test_assert.js"); } catch(e) {}
@@ -39,7 +55,7 @@ function test_function()
function constructor1(a) {
this.x = a;
}
-
+
var r, g;
r = my_func.call(null, 1, 2);
@@ -48,6 +64,13 @@ function test_function()
r = my_func.apply(null, [1, 2]);
assert(r, 3, "apply");
+ r = (function () { return 1; }).apply(null, undefined);
+ assert(r, 1);
+
+ assert_throws(TypeError, (function() {
+ Reflect.apply((function () { return 1; }), null, undefined);
+ }));
+
r = new Function("a", "b", "return a + b;");
assert(r(2,3), 5, "function");
diff --git a/tests/test_language.js b/tests/test_language.js
index 6b08467..8d13deb 100644
--- a/tests/test_language.js
+++ b/tests/test_language.js
@@ -15,6 +15,22 @@ function assert(actual, expected, message) {
(message ? " (" + message + ")" : ""));
}
+function assert_throws(expected_error, func)
+{
+ var err = false;
+ try {
+ func();
+ } catch(e) {
+ err = true;
+ if (!(e instanceof expected_error)) {
+ throw Error("unexpected exception type");
+ }
+ }
+ if (!err) {
+ throw Error("expected exception");
+ }
+}
+
// load more elaborate version of assert if available
try { __loadScript("test_assert.js"); } catch(e) {}
@@ -233,8 +249,13 @@ function test_delete()
function test_prototype()
{
- function f() { }
+ var f = function f() { };
assert(f.prototype.constructor, f, "prototype");
+
+ var g = function g() { };
+ /* QuickJS bug */
+ Object.defineProperty(g, "prototype", { writable: false });
+ assert(g.prototype.constructor, g, "prototype");
}
function test_arguments()
@@ -376,6 +397,135 @@ function test_spread()
assert(Object.getOwnPropertyNames(x).toString(), "0,length");
}
+function test_function_length()
+{
+ assert( ((a, b = 1, c) => {}).length, 1);
+ assert( (([a,b]) => {}).length, 1);
+ assert( (({a,b}) => {}).length, 1);
+ assert( ((c, [a,b] = 1, d) => {}).length, 1);
+}
+
+function test_argument_scope()
+{
+ var f;
+ var c = "global";
+
+ f = function(a = eval("var arguments")) {};
+ assert_throws(SyntaxError, f);
+
+ f = function(a = eval("1"), b = arguments[0]) { return b; };
+ assert(f(12), 12);
+
+ f = function(a, b = arguments[0]) { return b; };
+ assert(f(12), 12);
+
+ f = function(a, b = () => arguments) { return b; };
+ assert(f(12)()[0], 12);
+
+ f = function(a = eval("1"), b = () => arguments) { return b; };
+ assert(f(12)()[0], 12);
+
+ (function() {
+ "use strict";
+ f = function(a = this) { return a; };
+ assert(f.call(123), 123);
+
+ f = function f(a = f) { return a; };
+ assert(f(), f);
+
+ f = function f(a = eval("f")) { return a; };
+ assert(f(), f);
+ })();
+
+ f = (a = eval("var c = 1"), probe = () => c) => {
+ var c = 2;
+ assert(c, 2);
+ assert(probe(), 1);
+ }
+ f();
+
+ f = (a = eval("var arguments = 1"), probe = () => arguments) => {
+ var arguments = 2;
+ assert(arguments, 2);
+ assert(probe(), 1);
+ }
+ f();
+
+ f = function f(a = eval("var c = 1"), b = c, probe = () => c) {
+ assert(b, 1);
+ assert(c, 1);
+ assert(probe(), 1)
+ }
+ f();
+
+ assert(c, "global");
+ f = function f(a, b = c, probe = () => c) {
+ eval("var c = 1");
+ assert(c, 1);
+ assert(b, "global");
+ assert(probe(), "global")
+ }
+ f();
+ assert(c, "global");
+
+ f = function f(a = eval("var c = 1"), probe = (d = eval("c")) => d) {
+ assert(probe(), 1)
+ }
+ f();
+}
+
+function test_function_expr_name()
+{
+ var f;
+
+ /* non strict mode test : assignment to the function name silently
+ fails */
+
+ f = function myfunc() {
+ myfunc = 1;
+ return myfunc;
+ };
+ assert(f(), f);
+
+ f = function myfunc() {
+ myfunc = 1;
+ (() => {
+ myfunc = 1;
+ })();
+ return myfunc;
+ };
+ assert(f(), f);
+
+ f = function myfunc() {
+ eval("myfunc = 1");
+ return myfunc;
+ };
+ assert(f(), f);
+
+ /* strict mode test : assignment to the function name raises a
+ TypeError exception */
+
+ f = function myfunc() {
+ "use strict";
+ myfunc = 1;
+ };
+ assert_throws(TypeError, f);
+
+ f = function myfunc() {
+ "use strict";
+ (() => {
+ myfunc = 1;
+ })();
+ };
+ assert_throws(TypeError, f);
+
+ f = function myfunc() {
+ "use strict";
+ eval("myfunc = 1");
+ };
+ assert_throws(TypeError, f);
+}
+
test_op1();
test_cvt();
test_eq();
@@ -392,3 +542,6 @@ test_regexp_skip();
test_labels();
test_destructuring();
test_spread();
+test_function_length();
+test_argument_scope();
+test_function_expr_name();