diff --git a/CMakeLists.txt b/CMakeLists.txt index a04a0135d..c8350b220 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,8 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_C_STANDARD 11) + set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON) diff --git a/qbs-resources/imports/QbsProduct.qbs b/qbs-resources/imports/QbsProduct.qbs index c8996d5bb..2044bff32 100644 --- a/qbs-resources/imports/QbsProduct.qbs +++ b/qbs-resources/imports/QbsProduct.qbs @@ -25,6 +25,7 @@ Product { return res; } cpp.cxxLanguageVersion: "c++20" + cpp.cLanguageVersion: qbs.toolchain.contains("msvc") ? "c11" : "gnu11" cpp.enableExceptions: true cpp.rpaths: qbsbuildconfig.libRPaths cpp.minimumMacosVersion: "11.0" diff --git a/src/lib/corelib/buildgraph/rulecommands.cpp b/src/lib/corelib/buildgraph/rulecommands.cpp index 593956046..a6f16a9d8 100644 --- a/src/lib/corelib/buildgraph/rulecommands.cpp +++ b/src/lib/corelib/buildgraph/rulecommands.cpp @@ -157,7 +157,7 @@ void AbstractCommand::applyCommandProperties(JSContext *ctx, const JSValue *scri if (m_predefinedProperties.contains(name)) return; // TODO: Use script class for command objects, don't allow setting random properties - if (!isSimpleValue(desc.value)) { + if (!JS_IsSimpleValue(ctx, desc.value)) { throw ErrorInfo(Tr::tr("Property '%1' has a type unsuitable for storing in a command " "object.").arg(name), m_codeLocation); } diff --git a/src/lib/corelib/buildgraph/rulesapplicator.cpp b/src/lib/corelib/buildgraph/rulesapplicator.cpp index 87d1af00a..2a1ff4f4e 100644 --- a/src/lib/corelib/buildgraph/rulesapplicator.cpp +++ b/src/lib/corelib/buildgraph/rulesapplicator.cpp @@ -591,7 +591,7 @@ class ArtifactBindingsExtractor const JSValue value = desc.value; if (JS_IsObject(value) && !JS_IsArray(m_ctx, value) && !JS_IsError(m_ctx, value) - && !JS_IsRegExp(m_ctx, value)) { + && !JS_IsRegExp(value)) { QString newModuleName; if (!moduleName.isEmpty()) newModuleName.append(moduleName + QLatin1Char('.')); diff --git a/src/lib/corelib/language/scriptengine.cpp b/src/lib/corelib/language/scriptengine.cpp index 16653e3b1..15f5d0c29 100644 --- a/src/lib/corelib/language/scriptengine.cpp +++ b/src/lib/corelib/language/scriptengine.cpp @@ -338,15 +338,9 @@ void ScriptEngine::checkContext(const QString &operation, QBS_ASSERT(false, continue); break; } - if (!m_evalPositions.empty()) { - const JSValue exVal = JS_NewObject(m_context); - const auto &[file, line] = m_evalPositions.top(); - build_backtrace(m_context, exVal, file.toUtf8().constData(), line, 0); - const JsException ex(m_context, exVal, {}); - m_logger.printWarning(ErrorInfo(warning, ex.stackTrace())); - } else { - m_logger.printWarning(ErrorInfo(warning)); - } + const JSValue exVal = JS_NewError(m_context); + const JsException ex(m_context, exVal, JS_GetBacktrace(m_context), {}); + m_logger.printWarning(ErrorInfo(warning, ex.stackTrace())); return; } } @@ -582,7 +576,7 @@ JSValue ScriptEngine::asJsValue(const QVariantMap &m, quintptr id, bool frozen) for (auto it = m.begin(); it != m.end(); ++it) setJsProperty(m_context, obj, it.key(), asJsValue(it.value(), 0, frozen)); if (frozen) - JS_ObjectSeal(m_context, obj, true); + JS_FreezeObject(m_context, obj); if (!id) return obj; m_jsValueCache[id] = obj; @@ -606,7 +600,7 @@ JSValue ScriptEngine::asJsValue(const QVariantList &l, quintptr id, bool frozen) for (int i = 0; i < l.size(); ++i) JS_SetPropertyUint32(m_context, array, i, asJsValue(l.at(i), 0, frozen)); if (frozen) - JS_ObjectSeal(m_context, array, true); + JS_FreezeObject(m_context, array); if (!id) return array; m_jsValueCache[id] = array; @@ -841,8 +835,9 @@ JSValue ScriptEngine::evaluate( const QByteArray &codeStr = code.toUtf8(); m_evalPositions.emplace(filePath, line); - const JSValue v = JS_EvalThis(m_context, globalObject(), codeStr.constData(), codeStr.length(), - filePath.toUtf8().constData(), line, JS_EVAL_TYPE_GLOBAL); + JSEvalOptions evalOptions{1, JS_EVAL_TYPE_GLOBAL, filePath.toUtf8().constData(), line}; + const JSValue v = JS_EvalThis2( + m_context, globalObject(), codeStr.constData(), codeStr.length(), &evalOptions); m_evalPositions.pop(); m_scopeChains.pop_back(); if (resultOwner == JsValueOwner::ScriptEngine && JS_VALUE_HAS_REF_COUNT(v)) @@ -871,7 +866,7 @@ JSClassID ScriptEngine::registerClass(const char *name, JSClassCall *constructor JSClassID id = 0; const auto classIt = m_classes.constFind(QLatin1String(name)); if (classIt == m_classes.constEnd()) { - JS_NewClassID(&id); + JS_NewClassID(m_jsRuntime, &id); const auto it = getProperty ? m_exoticMethods.insert(id, JSClassExoticMethods{getProperty, getPropertyNames}) : m_exoticMethods.end(); @@ -1083,7 +1078,7 @@ ScriptEngine::PropertyCacheKey::PropertyCacheKey(QString moduleName, JsException ScriptEngine::checkAndClearException(const CodeLocation &fallbackLocation) const { - return {m_context, JS_GetException(m_context), fallbackLocation}; + return {m_context, JS_GetException(m_context), JS_GetBacktrace(m_context), fallbackLocation}; } void ScriptEngine::clearRequestedProperties() diff --git a/src/lib/corelib/loader/dependenciesresolver.cpp b/src/lib/corelib/loader/dependenciesresolver.cpp index 8e5ec3888..d9ecbabea 100644 --- a/src/lib/corelib/loader/dependenciesresolver.cpp +++ b/src/lib/corelib/loader/dependenciesresolver.cpp @@ -1115,8 +1115,9 @@ QVariantMap safeToVariant(JSContext *ctx, const JSValue &v) if (JS_IsError(ctx, u)) throw ErrorInfo(getJsString(ctx, u)); const QString name = getJsString(ctx, prop); - result[name] = (JS_IsObject(u) && !JS_IsArray(ctx, u) && !JS_IsRegExp(ctx, u)) - ? safeToVariant(ctx, u) : getJsVariant(ctx, u); + result[name] = (JS_IsObject(u) && !JS_IsArray(ctx, u) && !JS_IsRegExp(u)) + ? safeToVariant(ctx, u) + : getJsVariant(ctx, u); }); return result; } diff --git a/src/lib/corelib/tools/error.cpp b/src/lib/corelib/tools/error.cpp index 2026a847a..45e8e581f 100644 --- a/src/lib/corelib/tools/error.cpp +++ b/src/lib/corelib/tools/error.cpp @@ -210,8 +210,9 @@ ErrorInfo::ErrorInfo(const QString &description, const QStringList &backtrace) for (const QString &traceLine : backtrace) { if (traceLine.contains(QStringLiteral(""))) continue; - static const std::regex regexpWithFunc("^(.+) at [^(]*\\((.+):(\\-?[0-9]+)\\)$"); - static const std::regex regexpWithoutFunc("^(.+) at (.+):(\\-?[0-9]+)$"); + static const std::regex regexpWithFunc( + "^(.+) at [^(]*\\((.+):(\\-?[0-9]+):(\\-?[0-9]+)\\)$"); + static const std::regex regexpWithoutFunc("^(.+) at (.+):(\\-?[0-9]+):(\\-?[0-9]+)$"); std::smatch match; const std::string tl = traceLine.toStdString(); bool hasMatch = std::regex_match(tl, match, regexpWithFunc); diff --git a/src/lib/corelib/tools/scripttools.cpp b/src/lib/corelib/tools/scripttools.cpp index 6aa44adbb..ccf1f4b53 100644 --- a/src/lib/corelib/tools/scripttools.cpp +++ b/src/lib/corelib/tools/scripttools.cpp @@ -83,13 +83,20 @@ TemporaryGlobalObjectSetter::~TemporaryGlobalObjectSetter() } JsException::JsException(JsException &&other) noexcept - : m_ctx(other.m_ctx), m_exception(other.m_exception), - m_fallbackLocation(std::move(other.m_fallbackLocation)) + : m_ctx(other.m_ctx) + , m_exception(other.m_exception) + , m_backtrace(other.m_exception) + , m_fallbackLocation(std::move(other.m_fallbackLocation)) { other.m_exception = JS_NULL; + other.m_backtrace = JS_NULL; } -JsException::~JsException() { JS_FreeValue(m_ctx, m_exception); } +JsException::~JsException() +{ + JS_FreeValue(m_ctx, m_exception); + JS_FreeValue(m_ctx, m_backtrace); +} QString JsException::message() const { @@ -113,8 +120,7 @@ QString JsException::message() const const QStringList JsException::stackTrace() const { - return getJsStringProperty(m_ctx, m_exception, QLatin1String("stack")) - .split(QLatin1Char('\n'), Qt::SkipEmptyParts); + return getJsString(m_ctx, m_backtrace).split(QLatin1Char('\n'), Qt::SkipEmptyParts); } ErrorInfo JsException::toErrorInfo() const diff --git a/src/lib/corelib/tools/scripttools.h b/src/lib/corelib/tools/scripttools.h index 20964cae5..0ea2144d6 100644 --- a/src/lib/corelib/tools/scripttools.h +++ b/src/lib/corelib/tools/scripttools.h @@ -179,20 +179,25 @@ class ScopedJsAtom class QBS_AUTOTEST_EXPORT JsException { public: - JsException(JSContext *ctx, JSValue ex, const CodeLocation &fallbackLocation) - : m_ctx(ctx), m_exception(ex), m_fallbackLocation(fallbackLocation) {} + JsException(JSContext *ctx, JSValue ex, JSValue bt, const CodeLocation &fallbackLocation) + : m_ctx(ctx) + , m_exception(ex) + , m_backtrace(bt) + , m_fallbackLocation(fallbackLocation) + {} JsException(JsException && other) noexcept; ~JsException(); JsException(const JsException &) = delete; JsException &operator=(const JsException &) = delete; - operator bool() const { return !JS_IsNull(m_exception); } + operator bool() const { return m_exception.tag != JS_TAG_UNINITIALIZED; } QString message() const; const QStringList stackTrace() const; ErrorInfo toErrorInfo() const; private: JSContext *m_ctx; JSValue m_exception; + JSValue m_backtrace; CodeLocation m_fallbackLocation; }; diff --git a/src/shared/quickjs/CMakeLists.txt b/src/shared/quickjs/CMakeLists.txt index d88739ab0..51e30294c 100644 --- a/src/shared/quickjs/CMakeLists.txt +++ b/src/shared/quickjs/CMakeLists.txt @@ -9,6 +9,7 @@ add_qbs_library(qbsquickjs libunicode.c libunicode.h list.h quickjs-atom.h + quickjs-c-atomics.h quickjs-opcode.h quickjs.c quickjs.h DEFINES diff --git a/src/shared/quickjs/cutils.c b/src/shared/quickjs/cutils.c index 95ae5688d..438087d06 100644 --- a/src/shared/quickjs/cutils.c +++ b/src/shared/quickjs/cutils.c @@ -22,14 +22,26 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include #include #include #include #include +#include +#if !defined(_MSC_VER) +#include +#endif #include "cutils.h" -void pstrcpy(char *buf, int buf_size, const char *str) +#undef NANOSEC +#define NANOSEC ((uint64_t) 1e9) + +#ifdef __GNUC__ +#pragma GCC visibility push(default) +#endif + +void js__pstrcpy(char *buf, int buf_size, const char *str) { int c; char *q = buf; @@ -47,16 +59,16 @@ void pstrcpy(char *buf, int buf_size, const char *str) } /* strcat and truncate. */ -char *pstrcat(char *buf, int buf_size, const char *s) +char *js__pstrcat(char *buf, int buf_size, const char *s) { int len; len = strlen(buf); if (len < buf_size) - pstrcpy(buf + len, buf_size - len, s); + js__pstrcpy(buf + len, buf_size - len, s); return buf; } -int strstart(const char *str, const char *val, const char **ptr) +int js__strstart(const char *str, const char *val, const char **ptr) { const char *p, *q; p = str; @@ -72,7 +84,7 @@ int strstart(const char *str, const char *val, const char **ptr) return 1; } -int has_suffix(const char *str, const char *suffix) +int js__has_suffix(const char *str, const char *suffix) { size_t len = strlen(str); size_t slen = strlen(suffix); @@ -113,7 +125,7 @@ int dbuf_realloc(DynBuf *s, size_t new_size) new_size = size; new_buf = s->realloc_func(s->opaque, s->buf, new_size); if (!new_buf) { - s->error = TRUE; + s->error = true; return -1; } s->buf = new_buf; @@ -122,7 +134,7 @@ int dbuf_realloc(DynBuf *s, size_t new_size) return 0; } -int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len) +int dbuf_write(DynBuf *s, size_t offset, const void *data, size_t len) { size_t end; end = offset + len; @@ -134,14 +146,16 @@ int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len) return 0; } -int dbuf_put(DynBuf *s, const uint8_t *data, size_t len) +int dbuf_put(DynBuf *s, const void *data, size_t len) { if (unlikely((s->size + len) > s->allocated_size)) { if (dbuf_realloc(s, s->size + len)) return -1; } - memcpy_no_ub(s->buf + s->size, data, len); - s->size += len; + if (len > 0) { + memcpy(s->buf + s->size, data, len); + s->size += len; + } return 0; } @@ -166,7 +180,7 @@ int dbuf_putstr(DynBuf *s, const char *str) return dbuf_put(s, (const uint8_t *)str, strlen(str)); } -int FORMAT_ATTR(2, 3) dbuf_printf(DynBuf *s, const char *fmt, ...) +int JS_PRINTF_FORMAT_ATTR(2, 3) dbuf_printf(DynBuf *s, JS_PRINTF_FORMAT const char *fmt, ...) { va_list ap; char buf[128]; @@ -175,7 +189,7 @@ int FORMAT_ATTR(2, 3) dbuf_printf(DynBuf *s, const char *fmt, ...) va_start(ap, fmt); len = vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); - if (len < sizeof(buf)) { + if (len < (int)sizeof(buf)) { /* fast case */ return dbuf_put(s, (uint8_t *)buf, len); } else { @@ -200,56 +214,85 @@ void dbuf_free(DynBuf *s) memset(s, 0, sizeof(*s)); } -/* Note: at most 31 bits are encoded. At most UTF8_CHAR_LEN_MAX bytes - are output. */ -int unicode_to_utf8(uint8_t *buf, unsigned int c) +/*--- UTF-8 utility functions --*/ + +/* Note: only encode valid codepoints (0x0000..0x10FFFF). + At most UTF8_CHAR_LEN_MAX bytes are output. */ + +/* Compute the number of bytes of the UTF-8 encoding for a codepoint + `c` is a code-point. + Returns the number of bytes. If a codepoint is beyond 0x10FFFF the + return value is 3 as the codepoint would be encoded as 0xFFFD. + */ +size_t utf8_encode_len(uint32_t c) { - uint8_t *q = buf; + if (c < 0x80) + return 1; + if (c < 0x800) + return 2; + if (c < 0x10000) + return 3; + if (c < 0x110000) + return 4; + return 3; +} +/* Encode a codepoint in UTF-8 + `buf` points to an array of at least `UTF8_CHAR_LEN_MAX` bytes + `c` is a code-point. + Returns the number of bytes. If a codepoint is beyond 0x10FFFF the + return value is 3 and the codepoint is encoded as 0xFFFD. + No null byte is stored after the encoded bytes. + Return value is in range 1..4 + */ +size_t utf8_encode(uint8_t buf[minimum_length(UTF8_CHAR_LEN_MAX)], uint32_t c) +{ if (c < 0x80) { - *q++ = c; - } else { - if (c < 0x800) { - *q++ = (c >> 6) | 0xc0; - } else { - if (c < 0x10000) { - *q++ = (c >> 12) | 0xe0; - } else { - if (c < 0x00200000) { - *q++ = (c >> 18) | 0xf0; - } else { - if (c < 0x04000000) { - *q++ = (c >> 24) | 0xf8; - } else if (c < 0x80000000) { - *q++ = (c >> 30) | 0xfc; - *q++ = ((c >> 24) & 0x3f) | 0x80; - } else { - return 0; - } - *q++ = ((c >> 18) & 0x3f) | 0x80; - } - *q++ = ((c >> 12) & 0x3f) | 0x80; - } - *q++ = ((c >> 6) & 0x3f) | 0x80; - } - *q++ = (c & 0x3f) | 0x80; + buf[0] = c; + return 1; } - return q - buf; + if (c < 0x800) { + buf[0] = (c >> 6) | 0xC0; + buf[1] = (c & 0x3F) | 0x80; + return 2; + } + if (c < 0x10000) { + buf[0] = (c >> 12) | 0xE0; + buf[1] = ((c >> 6) & 0x3F) | 0x80; + buf[2] = (c & 0x3F) | 0x80; + return 3; + } + if (c < 0x110000) { + buf[0] = (c >> 18) | 0xF0; + buf[1] = ((c >> 12) & 0x3F) | 0x80; + buf[2] = ((c >> 6) & 0x3F) | 0x80; + buf[3] = (c & 0x3F) | 0x80; + return 4; + } + buf[0] = (0xFFFD >> 12) | 0xE0; + buf[1] = ((0xFFFD >> 6) & 0x3F) | 0x80; + buf[2] = (0xFFFD & 0x3F) | 0x80; + return 3; } -static const unsigned int utf8_min_code[5] = { - 0x80, 0x800, 0x10000, 0x00200000, 0x04000000, -}; - -static const unsigned char utf8_first_code_mask[5] = { - 0x1f, 0xf, 0x7, 0x3, 0x1, -}; - -/* return -1 if error. *pp is not updated in this case. max_len must - be >= 1. The maximum length for a UTF8 byte sequence is 6 bytes. */ -int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp) +/* Decode a single code point from a UTF-8 encoded array of bytes + `p` is a valid pointer to an array of bytes + `pp` is a valid pointer to a `const uint8_t *` to store a pointer + to the byte following the current sequence. + Return the code point at `p`, in the range `0..0x10FFFF` + Return 0xFFFD on error. Only a single byte is consumed in this case + The maximum length for a UTF-8 byte sequence is 4 bytes. + This implements the algorithm specified in whatwg.org, except it accepts + UTF-8 encoded surrogates as JavaScript allows them in strings. + The source string is assumed to have at least UTF8_CHAR_LEN_MAX bytes + or be null terminated. + If `p[0]` is '\0', the return value is `0` and the byte is consumed. + cf: https://encoding.spec.whatwg.org/#utf-8-encoder + */ +uint32_t utf8_decode(const uint8_t *p, const uint8_t **pp) { - int l, c, b, i; + uint32_t c; + uint8_t lower, upper; c = *p++; if (c < 0x80) { @@ -257,76 +300,538 @@ int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp) return c; } switch(c) { - case 0xc0: case 0xc1: case 0xc2: case 0xc3: - case 0xc4: case 0xc5: case 0xc6: case 0xc7: - case 0xc8: case 0xc9: case 0xca: case 0xcb: - case 0xcc: case 0xcd: case 0xce: case 0xcf: - case 0xd0: case 0xd1: case 0xd2: case 0xd3: - case 0xd4: case 0xd5: case 0xd6: case 0xd7: - case 0xd8: case 0xd9: case 0xda: case 0xdb: - case 0xdc: case 0xdd: case 0xde: case 0xdf: - l = 1; + case 0xC2: case 0xC3: + case 0xC4: case 0xC5: case 0xC6: case 0xC7: + case 0xC8: case 0xC9: case 0xCA: case 0xCB: + case 0xCC: case 0xCD: case 0xCE: case 0xCF: + case 0xD0: case 0xD1: case 0xD2: case 0xD3: + case 0xD4: case 0xD5: case 0xD6: case 0xD7: + case 0xD8: case 0xD9: case 0xDA: case 0xDB: + case 0xDC: case 0xDD: case 0xDE: case 0xDF: + if (*p >= 0x80 && *p <= 0xBF) { + *pp = p + 1; + return ((c - 0xC0) << 6) + (*p - 0x80); + } + // otherwise encoding error + break; + case 0xE0: + lower = 0xA0; /* reject invalid encoding */ + goto need2; + case 0xE1: case 0xE2: case 0xE3: + case 0xE4: case 0xE5: case 0xE6: case 0xE7: + case 0xE8: case 0xE9: case 0xEA: case 0xEB: + case 0xEC: case 0xED: case 0xEE: case 0xEF: + lower = 0x80; + need2: + if (*p >= lower && *p <= 0xBF && p[1] >= 0x80 && p[1] <= 0xBF) { + *pp = p + 2; + return ((c - 0xE0) << 12) + ((*p - 0x80) << 6) + (p[1] - 0x80); + } + // otherwise encoding error + break; + case 0xF0: + lower = 0x90; /* reject invalid encoding */ + upper = 0xBF; + goto need3; + case 0xF4: + lower = 0x80; + upper = 0x8F; /* reject values above 0x10FFFF */ + goto need3; + case 0xF1: case 0xF2: case 0xF3: + lower = 0x80; + upper = 0xBF; + need3: + if (*p >= lower && *p <= upper && p[1] >= 0x80 && p[1] <= 0xBF + && p[2] >= 0x80 && p[2] <= 0xBF) { + *pp = p + 3; + return ((c - 0xF0) << 18) + ((*p - 0x80) << 12) + + ((p[1] - 0x80) << 6) + (p[2] - 0x80); + } + // otherwise encoding error break; - case 0xe0: case 0xe1: case 0xe2: case 0xe3: - case 0xe4: case 0xe5: case 0xe6: case 0xe7: - case 0xe8: case 0xe9: case 0xea: case 0xeb: - case 0xec: case 0xed: case 0xee: case 0xef: - l = 2; + default: + // invalid lead byte break; - case 0xf0: case 0xf1: case 0xf2: case 0xf3: - case 0xf4: case 0xf5: case 0xf6: case 0xf7: - l = 3; + } + *pp = p; + return 0xFFFD; +} + +uint32_t utf8_decode_len(const uint8_t *p, size_t max_len, const uint8_t **pp) { + switch (max_len) { + case 0: + *pp = p; + return 0xFFFD; + case 1: + if (*p < 0x80) + goto good; break; - case 0xf8: case 0xf9: case 0xfa: case 0xfb: - l = 4; + case 2: + if (*p < 0xE0) + goto good; break; - case 0xfc: case 0xfd: - l = 5; + case 3: + if (*p < 0xF0) + goto good; break; default: - return -1; + good: + return utf8_decode(p, pp); } - /* check that we have enough characters */ - if (l > (max_len - 1)) - return -1; - c &= utf8_first_code_mask[l - 1]; - for(i = 0; i < l; i++) { - b = *p++; - if (b < 0x80 || b >= 0xc0) - return -1; - c = (c << 6) | (b & 0x3f); + *pp = p + 1; + return 0xFFFD; +} + +/* Scan a UTF-8 encoded buffer for content type + `buf` is a valid pointer to a UTF-8 encoded string + `len` is the number of bytes to scan + `plen` points to a `size_t` variable to receive the number of units + Return value is a mask of bits. + - `UTF8_PLAIN_ASCII`: return value for 7-bit ASCII plain text + - `UTF8_NON_ASCII`: bit for non ASCII code points (8-bit or more) + - `UTF8_HAS_16BIT`: bit for 16-bit code points + - `UTF8_HAS_NON_BMP1`: bit for non-BMP1 code points, needs UTF-16 surrogate pairs + - `UTF8_HAS_ERRORS`: bit for encoding errors + */ +int utf8_scan(const char *buf, size_t buf_len, size_t *plen) +{ + const uint8_t *p, *p_end, *p_next; + size_t i, len; + int kind; + uint8_t cbits; + + kind = UTF8_PLAIN_ASCII; + cbits = 0; + len = buf_len; + // TODO: handle more than 1 byte at a time + for (i = 0; i < buf_len; i++) + cbits |= buf[i]; + if (cbits >= 0x80) { + p = (const uint8_t *)buf; + p_end = p + buf_len; + kind = UTF8_NON_ASCII; + len = 0; + while (p < p_end) { + len++; + if (*p++ >= 0x80) { + /* parse UTF-8 sequence, check for encoding error */ + uint32_t c = utf8_decode_len(p - 1, p_end - (p - 1), &p_next); + if (p_next == p) + kind |= UTF8_HAS_ERRORS; + p = p_next; + if (c > 0xFF) { + kind |= UTF8_HAS_16BIT; + if (c > 0xFFFF) { + len++; + kind |= UTF8_HAS_NON_BMP1; + } + } + } + } } - if (c < utf8_min_code[l - 1]) - return -1; - *pp = p; - return c; + *plen = len; + return kind; } -#if 0 +/* Decode a string encoded in UTF-8 into an array of bytes + `src` points to the source string. It is assumed to be correctly encoded + and only contains code points below 0x800 + `src_len` is the length of the source string + `dest` points to the destination array, it can be null if `dest_len` is `0` + `dest_len` is the length of the destination array. A null + terminator is stored at the end of the array unless `dest_len` is `0`. + */ +size_t utf8_decode_buf8(uint8_t *dest, size_t dest_len, const char *src, size_t src_len) +{ + const uint8_t *p, *p_end; + size_t i; -#if defined(EMSCRIPTEN) || defined(__ANDROID__) + p = (const uint8_t *)src; + p_end = p + src_len; + for (i = 0; p < p_end; i++) { + uint32_t c = *p++; + if (c >= 0xC0) + c = (c << 6) + *p++ - ((0xC0 << 6) + 0x80); + if (i < dest_len) + dest[i] = c; + } + if (i < dest_len) + dest[i] = '\0'; + else if (dest_len > 0) + dest[dest_len - 1] = '\0'; + return i; +} -static void *rqsort_arg; -static int (*rqsort_cmp)(const void *, const void *, void *); +/* Decode a string encoded in UTF-8 into an array of 16-bit words + `src` points to the source string. It is assumed to be correctly encoded. + `src_len` is the length of the source string + `dest` points to the destination array, it can be null if `dest_len` is `0` + `dest_len` is the length of the destination array. No null terminator is + stored at the end of the array. + */ +size_t utf8_decode_buf16(uint16_t *dest, size_t dest_len, const char *src, size_t src_len) +{ + const uint8_t *p, *p_end; + size_t i; -static int rqsort_cmp2(const void *p1, const void *p2) + p = (const uint8_t *)src; + p_end = p + src_len; + for (i = 0; p < p_end; i++) { + uint32_t c = *p++; + if (c >= 0x80) { + /* parse utf-8 sequence */ + c = utf8_decode_len(p - 1, p_end - (p - 1), &p); + /* encoding errors are converted as 0xFFFD and use a single byte */ + if (c > 0xFFFF) { + if (i < dest_len) + dest[i] = get_hi_surrogate(c); + i++; + c = get_lo_surrogate(c); + } + } + if (i < dest_len) + dest[i] = c; + } + return i; +} + +/* Encode a buffer of 8-bit bytes as a UTF-8 encoded string + `src` points to the source buffer. + `src_len` is the length of the source buffer + `dest` points to the destination array, it can be null if `dest_len` is `0` + `dest_len` is the length in bytes of the destination array. A null + terminator is stored at the end of the array unless `dest_len` is `0`. + */ +size_t utf8_encode_buf8(char *dest, size_t dest_len, const uint8_t *src, size_t src_len) { - return rqsort_cmp(p1, p2, rqsort_arg); + size_t i, j; + uint32_t c; + + for (i = j = 0; i < src_len; i++) { + c = src[i]; + if (c < 0x80) { + if (j + 1 >= dest_len) + goto overflow; + dest[j++] = c; + } else { + if (j + 2 >= dest_len) + goto overflow; + dest[j++] = (c >> 6) | 0xC0; + dest[j++] = (c & 0x3F) | 0x80; + } + } + if (j < dest_len) + dest[j] = '\0'; + return j; + +overflow: + if (j < dest_len) + dest[j] = '\0'; + while (i < src_len) + j += 1 + (src[i++] >= 0x80); + return j; } -/* not reentrant, but not needed with emscripten */ -void rqsort(void *base, size_t nmemb, size_t size, - int (*cmp)(const void *, const void *, void *), - void *arg) +/* Encode a buffer of 16-bit code points as a UTF-8 encoded string + `src` points to the source buffer. + `src_len` is the length of the source buffer + `dest` points to the destination array, it can be null if `dest_len` is `0` + `dest_len` is the length in bytes of the destination array. A null + terminator is stored at the end of the array unless `dest_len` is `0`. + */ +size_t utf8_encode_buf16(char *dest, size_t dest_len, const uint16_t *src, size_t src_len) { - rqsort_arg = arg; - rqsort_cmp = cmp; - qsort(base, nmemb, size, rqsort_cmp2); + size_t i, j; + uint32_t c; + + for (i = j = 0; i < src_len;) { + c = src[i++]; + if (c < 0x80) { + if (j + 1 >= dest_len) + goto overflow; + dest[j++] = c; + } else { + if (is_hi_surrogate(c) && i < src_len && is_lo_surrogate(src[i])) + c = from_surrogate(c, src[i++]); + if (j + utf8_encode_len(c) >= dest_len) + goto overflow; + j += utf8_encode((uint8_t *)dest + j, c); + } + } + if (j < dest_len) + dest[j] = '\0'; + return j; + +overflow: + i -= 1 + (c > 0xFFFF); + if (j < dest_len) + dest[j] = '\0'; + while (i < src_len) { + c = src[i++]; + if (c < 0x80) { + j++; + } else { + if (is_hi_surrogate(c) && i < src_len && is_lo_surrogate(src[i])) + c = from_surrogate(c, src[i++]); + j += utf8_encode_len(c); + } + } + return j; } +/*--- integer to string conversions --*/ + +/* All conversion functions: + - require a destination array `buf` of sufficient length + - write the string representation at the beginning of `buf` + - null terminate the string + - return the string length + */ + +/* 2 <= base <= 36 */ +char const digits36[36] = { + '0','1','2','3','4','5','6','7','8','9', + 'a','b','c','d','e','f','g','h','i','j', + 'k','l','m','n','o','p','q','r','s','t', + 'u','v','w','x','y','z' +}; + + +#define USE_SPECIAL_RADIX_10 1 // special case base 10 radix conversions +#define USE_SINGLE_CASE_FAST 1 // special case single digit numbers + +/* using u32toa_shift variant */ + +#define gen_digit(buf, c) if (is_be()) \ + buf = (buf >> 8) | ((uint64_t)(c) << ((sizeof(buf) - 1) * 8)); \ + else \ + buf = (buf << 8) | (c) + +static size_t u7toa_shift(char dest[minimum_length(8)], uint32_t n) +{ + size_t len = 1; + uint64_t buf = 0; + while (n >= 10) { + uint32_t quo = n % 10; + n /= 10; + gen_digit(buf, '0' + quo); + len++; + } + gen_digit(buf, '0' + n); + memcpy(dest, &buf, sizeof buf); + return len; +} + +static size_t u07toa_shift(char dest[minimum_length(8)], uint32_t n, size_t len) +{ + size_t i; + dest += len; + dest[7] = '\0'; + for (i = 7; i-- > 1;) { + uint32_t quo = n % 10; + n /= 10; + dest[i] = (char)('0' + quo); + } + dest[i] = (char)('0' + n); + return len + 7; +} + +size_t u32toa(char buf[minimum_length(11)], uint32_t n) +{ +#ifdef USE_SINGLE_CASE_FAST /* 10% */ + if (n < 10) { + buf[0] = (char)('0' + n); + buf[1] = '\0'; + return 1; + } #endif +#define TEN_POW_7 10000000 + if (n >= TEN_POW_7) { + uint32_t quo = n / TEN_POW_7; + n %= TEN_POW_7; + size_t len = u7toa_shift(buf, quo); + return u07toa_shift(buf, n, len); + } + return u7toa_shift(buf, n); +} -#else +size_t u64toa(char buf[minimum_length(21)], uint64_t n) +{ + if (likely(n < 0x100000000)) + return u32toa(buf, n); + + size_t len; + if (n >= TEN_POW_7) { + uint64_t n1 = n / TEN_POW_7; + n %= TEN_POW_7; + if (n1 >= TEN_POW_7) { + uint32_t quo = n1 / TEN_POW_7; + n1 %= TEN_POW_7; + len = u7toa_shift(buf, quo); + len = u07toa_shift(buf, n1, len); + } else { + len = u7toa_shift(buf, n1); + } + return u07toa_shift(buf, n, len); + } + return u7toa_shift(buf, n); +} + +size_t i32toa(char buf[minimum_length(12)], int32_t n) +{ + if (likely(n >= 0)) + return u32toa(buf, n); + + buf[0] = '-'; + return 1 + u32toa(buf + 1, -(uint32_t)n); +} + +size_t i64toa(char buf[minimum_length(22)], int64_t n) +{ + if (likely(n >= 0)) + return u64toa(buf, n); + + buf[0] = '-'; + return 1 + u64toa(buf + 1, -(uint64_t)n); +} + +/* using u32toa_radix_length variant */ + +static uint8_t const radix_shift[64] = { + 0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +size_t u32toa_radix(char buf[minimum_length(33)], uint32_t n, unsigned base) +{ + int shift; + +#ifdef USE_SPECIAL_RADIX_10 + if (likely(base == 10)) + return u32toa(buf, n); +#endif + if (n < base) { + buf[0] = digits36[n]; + buf[1] = '\0'; + return 1; + } + shift = radix_shift[base & 63]; + if (shift) { + uint32_t mask = (1 << shift) - 1; + size_t len = (32 - clz32(n) + shift - 1) / shift; + size_t last = n & mask; + char *end = buf + len; + n >>= shift; + *end-- = '\0'; + *end-- = digits36[last]; + while (n >= base) { + size_t quo = n & mask; + n >>= shift; + *end-- = digits36[quo]; + } + *end = digits36[n]; + return len; + } else { + size_t len = 2; + size_t last = n % base; + n /= base; + uint32_t nbase = base; + while (n >= nbase) { + nbase *= base; + len++; + } + char *end = buf + len; + *end-- = '\0'; + *end-- = digits36[last]; + while (n >= base) { + size_t quo = n % base; + n /= base; + *end-- = digits36[quo]; + } + *end = digits36[n]; + return len; + } +} + +size_t u64toa_radix(char buf[minimum_length(65)], uint64_t n, unsigned base) +{ + int shift; + +#ifdef USE_SPECIAL_RADIX_10 + if (likely(base == 10)) + return u64toa(buf, n); +#endif + shift = radix_shift[base & 63]; + if (shift) { + if (n < base) { + buf[0] = digits36[n]; + buf[1] = '\0'; + return 1; + } + uint64_t mask = (1 << shift) - 1; + size_t len = (64 - clz64(n) + shift - 1) / shift; + size_t last = n & mask; + char *end = buf + len; + n >>= shift; + *end-- = '\0'; + *end-- = digits36[last]; + while (n >= base) { + size_t quo = n & mask; + n >>= shift; + *end-- = digits36[quo]; + } + *end = digits36[n]; + return len; + } else { + if (likely(n < 0x100000000)) + return u32toa_radix(buf, n, base); + size_t last = n % base; + n /= base; + uint64_t nbase = base; + size_t len = 2; + while (n >= nbase) { + nbase *= base; + len++; + } + char *end = buf + len; + *end-- = '\0'; + *end-- = digits36[last]; + while (n >= base) { + size_t quo = n % base; + n /= base; + *end-- = digits36[quo]; + } + *end = digits36[n]; + return len; + } +} + +size_t i32toa_radix(char buf[minimum_length(34)], int32_t n, unsigned int base) +{ + if (likely(n >= 0)) + return u32toa_radix(buf, n, base); + + buf[0] = '-'; + return 1 + u32toa_radix(buf + 1, -(uint32_t)n, base); +} + +size_t i64toa_radix(char buf[minimum_length(66)], int64_t n, unsigned int base) +{ + if (likely(n >= 0)) + return u64toa_radix(buf, n, base); + + buf[0] = '-'; + return 1 + u64toa_radix(buf + 1, -(uint64_t)n, base); +} + +#undef gen_digit +#undef TEN_POW_7 +#undef USE_SPECIAL_RADIX_10 +#undef USE_SINGLE_CASE_FAST + +/*---- sorting with opaque argument ----*/ typedef void (*exchange_f)(void *a, void *b, size_t size); typedef int (*cmp_f)(const void *, const void *, void *opaque); @@ -627,4 +1132,285 @@ void rqsort(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque) } } +/*---- Portable time functions ----*/ + +#ifdef _WIN32 + // From: https://stackoverflow.com/a/26085827 +static int gettimeofday_msvc(struct timeval *tp) +{ + static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL); + + SYSTEMTIME system_time; + FILETIME file_time; + uint64_t time; + + GetSystemTime(&system_time); + SystemTimeToFileTime(&system_time, &file_time); + time = ((uint64_t)file_time.dwLowDateTime); + time += ((uint64_t)file_time.dwHighDateTime) << 32; + + tp->tv_sec = (long)((time - EPOCH) / 10000000L); + tp->tv_usec = (long)(system_time.wMilliseconds * 1000); + + return 0; +} + +uint64_t js__hrtime_ns(void) { + LARGE_INTEGER counter, frequency; + double scaled_freq; + double result; + + if (!QueryPerformanceFrequency(&frequency)) + abort(); + assert(frequency.QuadPart != 0); + + if (!QueryPerformanceCounter(&counter)) + abort(); + assert(counter.QuadPart != 0); + + /* Because we have no guarantee about the order of magnitude of the + * performance counter interval, integer math could cause this computation + * to overflow. Therefore we resort to floating point math. + */ + scaled_freq = (double) frequency.QuadPart / NANOSEC; + result = (double) counter.QuadPart / scaled_freq; + return (uint64_t) result; +} +#else +uint64_t js__hrtime_ns(void) { + struct timespec t; + + if (clock_gettime(CLOCK_MONOTONIC, &t)) + abort(); + + return t.tv_sec * NANOSEC + t.tv_nsec; +} +#endif + +int64_t js__gettimeofday_us(void) { + struct timeval tv; +#ifdef _WIN32 + gettimeofday_msvc(&tv); +#else + gettimeofday(&tv, NULL); +#endif + return ((int64_t)tv.tv_sec * 1000000) + tv.tv_usec; +} + +/*--- Cross-platform threading APIs. ----*/ + +#if !defined(EMSCRIPTEN) && !defined(__wasi__) + +#if defined(_WIN32) +typedef void (*js__once_cb)(void); + +typedef struct { + js__once_cb callback; +} js__once_data_t; + +static int WINAPI js__once_inner(INIT_ONCE *once, void *param, void **context) { + js__once_data_t *data = param; + + data->callback(); + + return 1; +} + +void js_once(js_once_t *guard, js__once_cb callback) { + js__once_data_t data = { .callback = callback }; + InitOnceExecuteOnce(guard, js__once_inner, (void*) &data, NULL); +} + +void js_mutex_init(js_mutex_t *mutex) { + InitializeCriticalSection(mutex); +} + +void js_mutex_destroy(js_mutex_t *mutex) { + DeleteCriticalSection(mutex); +} + +void js_mutex_lock(js_mutex_t *mutex) { + EnterCriticalSection(mutex); +} + +void js_mutex_unlock(js_mutex_t *mutex) { + LeaveCriticalSection(mutex); +} + +void js_cond_init(js_cond_t *cond) { + InitializeConditionVariable(cond); +} + +void js_cond_destroy(js_cond_t *cond) { + /* nothing to do */ + (void) cond; +} + +void js_cond_signal(js_cond_t *cond) { + WakeConditionVariable(cond); +} + +void js_cond_broadcast(js_cond_t *cond) { + WakeAllConditionVariable(cond); +} + +void js_cond_wait(js_cond_t *cond, js_mutex_t *mutex) { + if (!SleepConditionVariableCS(cond, mutex, INFINITE)) + abort(); +} + +int js_cond_timedwait(js_cond_t *cond, js_mutex_t *mutex, uint64_t timeout) { + if (SleepConditionVariableCS(cond, mutex, (DWORD)(timeout / 1e6))) + return 0; + if (GetLastError() != ERROR_TIMEOUT) + abort(); + return -1; +} + +#else /* !defined(_WIN32) */ + +void js_once(js_once_t *guard, void (*callback)(void)) { + if (pthread_once(guard, callback)) + abort(); +} + +void js_mutex_init(js_mutex_t *mutex) { + if (pthread_mutex_init(mutex, NULL)) + abort(); +} + +void js_mutex_destroy(js_mutex_t *mutex) { + if (pthread_mutex_destroy(mutex)) + abort(); +} + +void js_mutex_lock(js_mutex_t *mutex) { + if (pthread_mutex_lock(mutex)) + abort(); +} + +void js_mutex_unlock(js_mutex_t *mutex) { + if (pthread_mutex_unlock(mutex)) + abort(); +} + +void js_cond_init(js_cond_t *cond) { +#if defined(__APPLE__) && defined(__MACH__) + if (pthread_cond_init(cond, NULL)) + abort(); +#else + pthread_condattr_t attr; + + if (pthread_condattr_init(&attr)) + abort(); + + if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) + abort(); + + if (pthread_cond_init(cond, &attr)) + abort(); + + if (pthread_condattr_destroy(&attr)) + abort(); +#endif +} + +void js_cond_destroy(js_cond_t *cond) { +#if defined(__APPLE__) && defined(__MACH__) + /* It has been reported that destroying condition variables that have been + * signalled but not waited on can sometimes result in application crashes. + * See https://codereview.chromium.org/1323293005. + */ + pthread_mutex_t mutex; + struct timespec ts; + int err; + + if (pthread_mutex_init(&mutex, NULL)) + abort(); + + if (pthread_mutex_lock(&mutex)) + abort(); + + ts.tv_sec = 0; + ts.tv_nsec = 1; + + err = pthread_cond_timedwait_relative_np(cond, &mutex, &ts); + if (err != 0 && err != ETIMEDOUT) + abort(); + + if (pthread_mutex_unlock(&mutex)) + abort(); + + if (pthread_mutex_destroy(&mutex)) + abort(); +#endif /* defined(__APPLE__) && defined(__MACH__) */ + + if (pthread_cond_destroy(cond)) + abort(); +} + +void js_cond_signal(js_cond_t *cond) { + if (pthread_cond_signal(cond)) + abort(); +} + +void js_cond_broadcast(js_cond_t *cond) { + if (pthread_cond_broadcast(cond)) + abort(); +} + +void js_cond_wait(js_cond_t *cond, js_mutex_t *mutex) { +#if defined(__APPLE__) && defined(__MACH__) + int r; + + errno = 0; + r = pthread_cond_wait(cond, mutex); + + /* Workaround for a bug in OS X at least up to 13.6 + * See https://github.com/libuv/libuv/issues/4165 + */ + if (r == EINVAL && errno == EBUSY) + return; + if (r) + abort(); +#else + if (pthread_cond_wait(cond, mutex)) + abort(); +#endif +} + +int js_cond_timedwait(js_cond_t *cond, js_mutex_t *mutex, uint64_t timeout) { + int r; + struct timespec ts; + +#if !defined(__APPLE__) + timeout += js__hrtime_ns(); +#endif + + ts.tv_sec = timeout / NANOSEC; + ts.tv_nsec = timeout % NANOSEC; +#if defined(__APPLE__) && defined(__MACH__) + r = pthread_cond_timedwait_relative_np(cond, mutex, &ts); +#else + r = pthread_cond_timedwait(cond, mutex, &ts); +#endif + + if (r == 0) + return 0; + + if (r == ETIMEDOUT) + return -1; + + abort(); + + /* Pacify some compilers. */ + return -1; +} + +#endif + +#endif /* !defined(EMSCRIPTEN) && !defined(__wasi__) */ + +#ifdef __GNUC__ +#pragma GCC visibility pop #endif diff --git a/src/shared/quickjs/cutils.h b/src/shared/quickjs/cutils.h index 240f46663..4639a6b93 100644 --- a/src/shared/quickjs/cutils.h +++ b/src/shared/quickjs/cutils.h @@ -25,76 +25,110 @@ #ifndef CUTILS_H #define CUTILS_H +#include #include #include #include +#include + +#ifdef __cplusplus +extern "C" { +#endif #if defined(_MSC_VER) -#include -#include -typedef SSIZE_T ssize_t; -#else -#include +#include +#include +#define alloca _alloca +#define ssize_t ptrdiff_t +#endif +#if defined(__APPLE__) +#include +#elif defined(__linux__) || defined(__ANDROID__) || defined(__CYGWIN__) +#include +#elif defined(__FreeBSD__) +#include +#elif defined(_WIN32) +#include +#endif +#if !defined(_WIN32) && !defined(EMSCRIPTEN) && !defined(__wasi__) +#include +#include #endif -#ifdef __GNUC__ -#define likely(x) __builtin_expect(!!(x), 1) -#define unlikely(x) __builtin_expect(!!(x), 0) -#define force_inline inline __attribute__((always_inline)) -#define no_inline __attribute__((noinline)) -#define __maybe_unused __attribute__((unused)) +#if defined(_MSC_VER) && !defined(__clang__) +# define likely(x) (x) +# define unlikely(x) (x) +# define force_inline __forceinline +# define no_inline __declspec(noinline) +# define __maybe_unused +# define __attribute__(x) +# define __attribute(x) #else -#define likely(x) (x) -#define unlikely(x) (x) -#define force_inline -#define no_inline -#define __maybe_unused +# define likely(x) __builtin_expect(!!(x), 1) +# define unlikely(x) __builtin_expect(!!(x), 0) +# define force_inline inline __attribute__((always_inline)) +# define no_inline __attribute__((noinline)) +# define __maybe_unused __attribute__((unused)) #endif -#ifdef _MSC_VER -#define alloca _alloca +#if defined(_MSC_VER) && !defined(__clang__) +#include +#define INF INFINITY +#define NEG_INF -INFINITY +#else +#define INF (1.0/0.0) +#define NEG_INF (-1.0/0.0) #endif -#define xglue(x, y) x ## y -#define glue(x, y) xglue(x, y) -#define stringify(s) tostring(s) -#define tostring(s) #s - #ifndef offsetof #define offsetof(type, field) ((size_t) &((type *)0)->field) #endif #ifndef countof #define countof(x) (sizeof(x) / sizeof((x)[0])) +#ifndef endof +#define endof(x) ((x) + countof(x)) +#endif #endif #ifndef container_of /* return the pointer of type 'type *' containing 'ptr' as field 'member' */ #define container_of(ptr, type, member) ((type *)((uint8_t *)(ptr) - offsetof(type, member))) #endif -#if !defined(_MSC_VER) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -#define minimum_length(n) static n +#if defined(_MSC_VER) +#define minimum_length(n) n #else -#define minimum_length(n) n +#define minimum_length(n) static n #endif -typedef int BOOL; - -#ifndef FALSE -enum { - FALSE = 0, - TRUE = 1, -}; +/* Borrowed from Folly */ +#ifndef JS_PRINTF_FORMAT +#ifdef _MSC_VER +#include +#define JS_PRINTF_FORMAT _Printf_format_string_ +#define JS_PRINTF_FORMAT_ATTR(format_param, dots_param) +#else +#define JS_PRINTF_FORMAT +#if !defined(__clang__) && defined(__GNUC__) +#define JS_PRINTF_FORMAT_ATTR(format_param, dots_param) \ + __attribute__((format(gnu_printf, format_param, dots_param))) +#else +#define JS_PRINTF_FORMAT_ATTR(format_param, dots_param) \ + __attribute__((format(printf, format_param, dots_param))) +#endif +#endif #endif -void pstrcpy(char *buf, int buf_size, const char *str); -char *pstrcat(char *buf, int buf_size, const char *s); -int strstart(const char *str, const char *val, const char **ptr); -int has_suffix(const char *str, const char *suffix); +void js__pstrcpy(char *buf, int buf_size, const char *str); +char *js__pstrcat(char *buf, int buf_size, const char *s); +int js__strstart(const char *str, const char *val, const char **ptr); +int js__has_suffix(const char *str, const char *suffix); -/* Prevent UB when n == 0 and (src == NULL or dest == NULL) */ -static inline void memcpy_no_ub(void *dest, const void *src, size_t n) { - if (n) - memcpy(dest, src, n); +static inline uint8_t is_be(void) { + union { + uint16_t a; + uint8_t b; + } u = { 0x100 }; + return u.b; } static inline int max_int(int a, int b) @@ -148,12 +182,10 @@ static inline int64_t min_int64(int64_t a, int64_t b) /* WARNING: undefined if a = 0 */ static inline int clz32(unsigned int a) { -#ifdef _MSC_VER -#if defined(_M_ARM) || defined(_M_ARM64) - return _CountLeadingZeros(a); -#else - return (int) __lzcnt(a); -#endif +#if defined(_MSC_VER) && !defined(__clang__) + unsigned long index; + _BitScanReverse(&index, a); + return 31 - index; #else return __builtin_clz(a); #endif @@ -162,11 +194,16 @@ static inline int clz32(unsigned int a) /* WARNING: undefined if a = 0 */ static inline int clz64(uint64_t a) { -#ifdef _MSC_VER -#if defined(_M_ARM) || defined(_M_ARM64) - return _CountLeadingZeros64(a); +#if defined(_MSC_VER) && !defined(__clang__) +#if INTPTR_MAX == INT64_MAX + unsigned long index; + _BitScanReverse64(&index, a); + return 63 - index; #else - return (int) __lzcnt64(a); + if (a >> 32) + return clz32((unsigned)(a >> 32)); + else + return clz32((unsigned)a) + 32; #endif #else return __builtin_clzll(a); @@ -176,12 +213,10 @@ static inline int clz64(uint64_t a) /* WARNING: undefined if a = 0 */ static inline int ctz32(unsigned int a) { -#ifdef _MSC_VER -#if defined(_M_ARM) || defined(_M_ARM64) - return _CountTrailingZeros(a); -#else - return (int) _tzcnt_u32(a); -#endif +#if defined(_MSC_VER) && !defined(__clang__) + unsigned long index; + _BitScanForward(&index, a); + return index; #else return __builtin_ctz(a); #endif @@ -190,72 +225,70 @@ static inline int ctz32(unsigned int a) /* WARNING: undefined if a = 0 */ static inline int ctz64(uint64_t a) { -#ifdef _MSC_VER -#if defined(_M_ARM) || defined(_M_ARM64) - return _CountTrailingZeros64(a); -#else - return (int) _tzcnt_u64(a); -#endif +#if defined(_MSC_VER) && !defined(__clang__) + unsigned long index; + _BitScanForward64(&index, a); + return index; #else return __builtin_ctzll(a); #endif } -#pragma pack(push, 1) -struct packed_u64 { - uint64_t v; -}; -struct packed_u32 { - uint32_t v; -}; -struct packed_u16 { - uint16_t v; -}; -#pragma pack(pop) - static inline uint64_t get_u64(const uint8_t *tab) { - return ((const struct packed_u64 *)tab)->v; + uint64_t v; + memcpy(&v, tab, sizeof(v)); + return v; } static inline int64_t get_i64(const uint8_t *tab) { - return (int64_t)((const struct packed_u64 *)tab)->v; + int64_t v; + memcpy(&v, tab, sizeof(v)); + return v; } static inline void put_u64(uint8_t *tab, uint64_t val) { - ((struct packed_u64 *)tab)->v = val; + memcpy(tab, &val, sizeof(val)); } static inline uint32_t get_u32(const uint8_t *tab) { - return ((const struct packed_u32 *)tab)->v; + uint32_t v; + memcpy(&v, tab, sizeof(v)); + return v; } static inline int32_t get_i32(const uint8_t *tab) { - return (int32_t)((const struct packed_u32 *)tab)->v; + int32_t v; + memcpy(&v, tab, sizeof(v)); + return v; } static inline void put_u32(uint8_t *tab, uint32_t val) { - ((struct packed_u32 *)tab)->v = val; + memcpy(tab, &val, sizeof(val)); } static inline uint32_t get_u16(const uint8_t *tab) { - return ((const struct packed_u16 *)tab)->v; + uint16_t v; + memcpy(&v, tab, sizeof(v)); + return v; } static inline int32_t get_i16(const uint8_t *tab) { - return (int16_t)((const struct packed_u16 *)tab)->v; + int16_t v; + memcpy(&v, tab, sizeof(v)); + return v; } static inline void put_u16(uint8_t *tab, uint16_t val) { - ((struct packed_u16 *)tab)->v = val; + memcpy(tab, &val, sizeof(val)); } static inline uint32_t get_u8(const uint8_t *tab) @@ -302,6 +335,89 @@ static inline uint64_t bswap64(uint64_t v) } #endif +static inline void inplace_bswap16(uint8_t *tab) { + put_u16(tab, bswap16(get_u16(tab))); +} + +static inline void inplace_bswap32(uint8_t *tab) { + put_u32(tab, bswap32(get_u32(tab))); +} + +static inline double fromfp16(uint16_t v) { + double d, s; + int e; + if ((v & 0x7C00) == 0x7C00) { + d = (v & 0x3FF) ? NAN : INFINITY; + } else { + d = (v & 0x3FF) / 1024.; + e = (v & 0x7C00) >> 10; + if (e == 0) { + e = -14; + } else { + d += 1; + e -= 15; + } + d = scalbn(d, e); + } + s = (v & 0x8000) ? -1.0 : 1.0; + return d * s; +} + +static inline uint16_t tofp16(double d) { + uint16_t f, s; + double t; + int e; + s = 0; + if (copysign(1, d) < 0) { // preserve sign when |d| is negative zero + d = -d; + s = 0x8000; + } + if (isinf(d)) + return s | 0x7C00; + if (isnan(d)) + return s | 0x7C01; + if (d == 0) + return s | 0; + d = 2 * frexp(d, &e); + e--; + if (e > 15) + return s | 0x7C00; // out of range, return +/-infinity + if (e < -25) { + d = 0; + e = 0; + } else if (e < -14) { + d = scalbn(d, e + 14); + e = 0; + } else { + d -= 1; + e += 15; + } + d *= 1024.; + f = (uint16_t)d; + t = d - f; + if (t < 0.5) + goto done; + if (t == 0.5) + if ((f & 1) == 0) + goto done; + // adjust for rounding + if (++f == 1024) { + f = 0; + if (++e == 31) + return s | 0x7C00; // out of range, return +/-infinity + } +done: + return s | (e << 10) | f; +} + +static inline int isfp16nan(uint16_t v) { + return (v & 0x7FFF) > 0x7C00; +} + +static inline int isfp16zero(uint16_t v) { + return (v & 0x7FFF) == 0; +} + /* XXX: should take an extra argument to pass slack information to the caller */ typedef void *DynBufReallocFunc(void *opaque, void *ptr, size_t size); @@ -309,7 +425,7 @@ typedef struct DynBuf { uint8_t *buf; size_t size; size_t allocated_size; - BOOL error; /* true if a memory allocation error occurred */ + bool error; /* true if a memory allocation error occurred */ DynBufReallocFunc *realloc_func; void *opaque; /* for realloc_func */ } DynBuf; @@ -317,8 +433,8 @@ typedef struct DynBuf { void dbuf_init(DynBuf *s); void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func); int dbuf_realloc(DynBuf *s, size_t new_size); -int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len); -int dbuf_put(DynBuf *s, const uint8_t *data, size_t len); +int dbuf_write(DynBuf *s, size_t offset, const void *data, size_t len); +int dbuf_put(DynBuf *s, const void *data, size_t len); int dbuf_put_self(DynBuf *s, size_t offset, size_t len); int dbuf_putc(DynBuf *s, uint8_t c); int dbuf_putstr(DynBuf *s, const char *str); @@ -334,40 +450,48 @@ static inline int dbuf_put_u64(DynBuf *s, uint64_t val) { return dbuf_put(s, (uint8_t *)&val, 8); } - -#ifdef __GNUC__ -#define FORMAT_ATTR(x, y) __attribute__((format(printf, x, y))) -#else -#define FORMAT_ATTR(x, y) -#endif - -int FORMAT_ATTR(2, 3) dbuf_printf(DynBuf *s, const char *fmt, ...); - +int JS_PRINTF_FORMAT_ATTR(2, 3) dbuf_printf(DynBuf *s, JS_PRINTF_FORMAT const char *fmt, ...); void dbuf_free(DynBuf *s); -static inline BOOL dbuf_error(DynBuf *s) { +static inline bool dbuf_error(DynBuf *s) { return s->error; } static inline void dbuf_set_error(DynBuf *s) { - s->error = TRUE; + s->error = true; } -#define UTF8_CHAR_LEN_MAX 6 +/*---- UTF-8 and UTF-16 handling ----*/ -int unicode_to_utf8(uint8_t *buf, unsigned int c); -int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp); +#define UTF8_CHAR_LEN_MAX 4 -static inline BOOL is_surrogate(uint32_t c) +enum { + UTF8_PLAIN_ASCII = 0, // 7-bit ASCII plain text + UTF8_NON_ASCII = 1, // has non ASCII code points (8-bit or more) + UTF8_HAS_16BIT = 2, // has 16-bit code points + UTF8_HAS_NON_BMP1 = 4, // has non-BMP1 code points, needs UTF-16 surrogate pairs + UTF8_HAS_ERRORS = 8, // has encoding errors +}; +int utf8_scan(const char *buf, size_t len, size_t *plen); +size_t utf8_encode_len(uint32_t c); +size_t utf8_encode(uint8_t buf[minimum_length(UTF8_CHAR_LEN_MAX)], uint32_t c); +uint32_t utf8_decode_len(const uint8_t *p, size_t max_len, const uint8_t **pp); +uint32_t utf8_decode(const uint8_t *p, const uint8_t **pp); +size_t utf8_decode_buf8(uint8_t *dest, size_t dest_len, const char *src, size_t src_len); +size_t utf8_decode_buf16(uint16_t *dest, size_t dest_len, const char *src, size_t src_len); +size_t utf8_encode_buf8(char *dest, size_t dest_len, const uint8_t *src, size_t src_len); +size_t utf8_encode_buf16(char *dest, size_t dest_len, const uint16_t *src, size_t src_len); + +static inline bool is_surrogate(uint32_t c) { return (c >> 11) == (0xD800 >> 11); // 0xD800-0xDFFF } -static inline BOOL is_hi_surrogate(uint32_t c) +static inline bool is_hi_surrogate(uint32_t c) { return (c >> 10) == (0xD800 >> 10); // 0xD800-0xDBFF } -static inline BOOL is_lo_surrogate(uint32_t c) +static inline bool is_lo_surrogate(uint32_t c) { return (c >> 10) == (0xDC00 >> 10); // 0xDC00-0xDFFF } @@ -384,7 +508,7 @@ static inline uint32_t get_lo_surrogate(uint32_t c) static inline uint32_t from_surrogate(uint32_t hi, uint32_t lo) { - return 0x10000 + 0x400 * (hi - 0xD800) + (lo - 0xDC00); + return 65536 + 1024 * (hi & 1023) + (lo & 1023); } static inline int from_hex(int c) @@ -399,8 +523,78 @@ static inline int from_hex(int c) return -1; } +static inline uint8_t is_upper_ascii(uint8_t c) { + return c >= 'A' && c <= 'Z'; +} + +static inline uint8_t to_upper_ascii(uint8_t c) { + return c >= 'a' && c <= 'z' ? c - 'a' + 'A' : c; +} + +extern char const digits36[36]; +size_t u32toa(char buf[minimum_length(11)], uint32_t n); +size_t i32toa(char buf[minimum_length(12)], int32_t n); +size_t u64toa(char buf[minimum_length(21)], uint64_t n); +size_t i64toa(char buf[minimum_length(22)], int64_t n); +size_t u32toa_radix(char buf[minimum_length(33)], uint32_t n, unsigned int base); +size_t i32toa_radix(char buf[minimum_length(34)], int32_t n, unsigned base); +size_t u64toa_radix(char buf[minimum_length(65)], uint64_t n, unsigned int base); +size_t i64toa_radix(char buf[minimum_length(66)], int64_t n, unsigned int base); + void rqsort(void *base, size_t nmemb, size_t size, int (*cmp)(const void *, const void *, void *), void *arg); +int64_t js__gettimeofday_us(void); +uint64_t js__hrtime_ns(void); + +static inline size_t js__malloc_usable_size(const void *ptr) +{ +#if defined(__APPLE__) + return malloc_size(ptr); +#elif defined(_WIN32) + return _msize((void *)ptr); +#elif defined(__linux__) || defined(__ANDROID__) || defined(__CYGWIN__) || defined(__FreeBSD__) + return malloc_usable_size((void *)ptr); +#else + return 0; +#endif +} + +/* Cross-platform threading APIs. */ + +#if !defined(EMSCRIPTEN) && !defined(__wasi__) + +#if defined(_WIN32) +#define JS_ONCE_INIT INIT_ONCE_STATIC_INIT +typedef INIT_ONCE js_once_t; +typedef CRITICAL_SECTION js_mutex_t; +typedef CONDITION_VARIABLE js_cond_t; +#else +#define JS_ONCE_INIT PTHREAD_ONCE_INIT +typedef pthread_once_t js_once_t; +typedef pthread_mutex_t js_mutex_t; +typedef pthread_cond_t js_cond_t; +#endif + +void js_once(js_once_t *guard, void (*callback)(void)); + +void js_mutex_init(js_mutex_t *mutex); +void js_mutex_destroy(js_mutex_t *mutex); +void js_mutex_lock(js_mutex_t *mutex); +void js_mutex_unlock(js_mutex_t *mutex); + +void js_cond_init(js_cond_t *cond); +void js_cond_destroy(js_cond_t *cond); +void js_cond_signal(js_cond_t *cond); +void js_cond_broadcast(js_cond_t *cond); +void js_cond_wait(js_cond_t *cond, js_mutex_t *mutex); +int js_cond_timedwait(js_cond_t *cond, js_mutex_t *mutex, uint64_t timeout); + +#endif /* !defined(EMSCRIPTEN) && !defined(__wasi__) */ + +#ifdef __cplusplus +} /* extern "C" { */ +#endif + #endif /* CUTILS_H */ diff --git a/src/shared/quickjs/libbf.c b/src/shared/quickjs/libbf.c index 56b2be861..07d27cfa1 100644 --- a/src/shared/quickjs/libbf.c +++ b/src/shared/quickjs/libbf.c @@ -134,7 +134,6 @@ static inline slimb_t ceil_div(slimb_t a, slimb_t b) return a / b; } -#ifdef USE_BF_DEC /* b must be >= 1 */ static inline slimb_t floor_div(slimb_t a, slimb_t b) { @@ -144,7 +143,6 @@ static inline slimb_t floor_div(slimb_t a, slimb_t b) return (a - b + 1) / b; } } -#endif /* return r = a modulo b (0 <= r <= b - 1. b must be >= 1 */ static inline limb_t smod(slimb_t a, slimb_t b) @@ -309,7 +307,8 @@ int bf_set(bf_t *r, const bf_t *a) } r->sign = a->sign; r->expn = a->expn; - memcpy_no_ub(r->tab, a->tab, a->len * sizeof(limb_t)); + if (a->len > 0) + memcpy(r->tab, a->tab, a->len * sizeof(limb_t)); return 0; } @@ -647,20 +646,20 @@ int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags) rounding */ int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k) { - BOOL is_rndn; + bool is_rndn; slimb_t bit_pos, n; limb_t bit; if (a->expn == BF_EXP_INF || a->expn == BF_EXP_NAN) - return FALSE; + return false; if (rnd_mode == BF_RNDF) { return (k >= (prec + 1)); } if (a->expn == BF_EXP_ZERO) - return FALSE; + return false; is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA); if (k < (prec + 2)) - return FALSE; + return false; bit_pos = a->len * LIMB_BITS - 1 - prec; n = k - prec; /* bit pattern for RNDN or RNDNA: 0111.. or 1000... @@ -673,11 +672,11 @@ int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k) /* XXX: slow, but a few iterations on average */ while (n != 0) { if (get_bit(a->tab, a->len, bit_pos) != bit) - return TRUE; + return true; bit_pos--; n--; } - return FALSE; + return false; } /* Cannot fail with BF_ST_MEM_ERROR. */ @@ -956,20 +955,20 @@ static int bf_add_internal(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, i = r_len - tot_len; while (i < 0) { slimb_t ap, bp; - BOOL inflag; + bool inflag; ap = a_offset + i; bp = b_bit_offset + i * LIMB_BITS; - inflag = FALSE; + inflag = false; if (ap >= 0 && ap < a->len) { v1 = a->tab[ap]; - inflag = TRUE; + inflag = true; } else { v1 = 0; } if (bp + LIMB_BITS > 0 && bp < (slimb_t)(b->len * LIMB_BITS)) { v2 = get_bits(b->tab, b->len, bp); - inflag = TRUE; + inflag = true; } else { v2 = 0; } @@ -1602,9 +1601,7 @@ int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, r = &tmp; } if (bf_resize(r, a_len + b_len)) { -#ifdef USE_FFT_MUL fail: -#endif bf_set_nan(r); ret = BF_ST_MEM_ERROR; goto done; @@ -1713,6 +1710,13 @@ static int __bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, slimb_t d; na = n + nb; + +#if LIMB_LOG2_BITS == 6 + if (na >= (SIZE_MAX / sizeof(limb_t)) - 1) { + return BF_ST_MEM_ERROR; /* Return memory error status */ + } +#endif + taba = bf_malloc(s, (na + 1) * sizeof(limb_t)); if (!taba) goto fail; @@ -1754,7 +1758,7 @@ int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b, bf_t a1_s, *a1 = &a1_s; bf_t b1_s, *b1 = &b1_s; int q_sign, ret; - BOOL is_ceil, is_rndn; + bool is_ceil, is_rndn; assert(q != a && q != b); assert(r != a && r != b); @@ -1781,7 +1785,7 @@ int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b, case BF_RNDZ: case BF_RNDN: case BF_RNDNA: - is_ceil = FALSE; + is_ceil = false; break; case BF_RNDD: is_ceil = q_sign; @@ -1790,7 +1794,7 @@ int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b, is_ceil = q_sign ^ 1; break; case BF_RNDA: - is_ceil = TRUE; + is_ceil = true; break; case BF_DIVREM_EUCLIDIAN: is_ceil = a->sign; @@ -2301,14 +2305,11 @@ static int bf_pow_ui_ui(bf_t *r, limb_t a1, limb_t b, bf_t a; int ret; -#ifdef USE_BF_DEC if (a1 == 10 && b <= LIMB_DIGITS) { /* use precomputed powers. We do not round at this point because we expect the caller to do it */ ret = bf_set_ui(r, mp_pow_dec[b]); - } else -#endif - { + } else { bf_init(r->ctx, &a); ret = bf_set_ui(&a, a1); ret |= bf_pow_ui(r, &a, b, prec, flags); @@ -2839,7 +2840,7 @@ int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix, return ret; } -static inline int to_digit(int c) +static inline int bf_to_digit(int c) { if (c >= '0' && c <= '9') return c - '0'; @@ -2899,13 +2900,13 @@ static int strcasestart(const char *str, const char *val, const char **ptr) static int bf_atof_internal(bf_t *r, slimb_t *pexponent, const char *str, const char **pnext, int radix, - limb_t prec, bf_flags_t flags, BOOL is_dec) + limb_t prec, bf_flags_t flags, bool is_dec) { const char *p, *p_start; int is_neg, radix_bits, exp_is_neg, ret, digits_per_limb, shift; limb_t cur_limb; slimb_t pos, expn, int_len, digit_count; - BOOL has_decpt, is_bin_exp; + bool has_decpt, is_bin_exp; bf_t a_s, *a; *pexponent = 0; @@ -2946,7 +2947,7 @@ static int bf_atof_internal(bf_t *r, slimb_t *pexponent, goto no_prefix; } /* there must be a digit after the prefix */ - if (to_digit((uint8_t)*p) >= radix) { + if (bf_to_digit((uint8_t)*p) >= radix) { bf_set_nan(r); ret = 0; goto done; @@ -2990,18 +2991,18 @@ static int bf_atof_internal(bf_t *r, slimb_t *pexponent, cur_limb = 0; bf_resize(a, 1); pos = 0; - has_decpt = FALSE; + has_decpt = false; int_len = digit_count = 0; for(;;) { limb_t c; - if (*p == '.' && (p > p_start || to_digit(p[1]) < radix)) { + if (*p == '.' && (p > p_start || bf_to_digit(p[1]) < radix)) { if (has_decpt) break; - has_decpt = TRUE; + has_decpt = true; int_len = digit_count; p++; } - c = to_digit(*p); + c = bf_to_digit(*p); if (c >= radix) break; digit_count++; @@ -3066,7 +3067,7 @@ static int bf_atof_internal(bf_t *r, slimb_t *pexponent, /* parse the exponent, if any */ expn = 0; - is_bin_exp = FALSE; + is_bin_exp = false; if (((radix == 10 && (*p == 'e' || *p == 'E')) || (radix != 10 && (*p == '@' || (radix_bits && (*p == 'p' || *p == 'P'))))) && @@ -3082,7 +3083,7 @@ static int bf_atof_internal(bf_t *r, slimb_t *pexponent, } for(;;) { int c; - c = to_digit(*p); + c = bf_to_digit(*p); if (c >= 10) break; if (unlikely(expn > ((BF_RAW_EXP_MAX - 2 - 9) / 10))) { @@ -3161,14 +3162,14 @@ int bf_atof2(bf_t *r, slimb_t *pexponent, limb_t prec, bf_flags_t flags) { return bf_atof_internal(r, pexponent, str, pnext, radix, prec, flags, - FALSE); + false); } int bf_atof(bf_t *r, const char *str, const char **pnext, int radix, limb_t prec, bf_flags_t flags) { slimb_t dummy_exp; - return bf_atof_internal(r, &dummy_exp, str, pnext, radix, prec, flags, FALSE); + return bf_atof_internal(r, &dummy_exp, str, pnext, radix, prec, flags, false); } /* base conversion to radix */ @@ -3339,7 +3340,7 @@ slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv, { int is_neg; limb_t a; - BOOL is_ceil; + bool is_ceil; is_ceil = is_ceil1; a = a1; @@ -3509,7 +3510,7 @@ static int bf_integer_to_radix(bf_t *r, const bf_t *a, limb_t radixl) static int bf_convert_to_radix(bf_t *r, slimb_t *pE, const bf_t *a, int radix, limb_t P, bf_rnd_t rnd_mode, - BOOL is_fixed_exponent) + bool is_fixed_exponent) { slimb_t E, e, prec, extra_bits, ziv_extra_bits, prec0; bf_t B_s, *B = &B_s; @@ -3525,7 +3526,7 @@ static int bf_convert_to_radix(bf_t *r, slimb_t *pE, E = *pE; } else { /* compute the new exponent */ - E = 1 + bf_mul_log2_radix(a->expn - 1, radix, TRUE, FALSE); + E = 1 + bf_mul_log2_radix(a->expn - 1, radix, true, false); } // bf_print_str("a", a); // printf("E=%ld P=%ld radix=%d\n", E, P, radix); @@ -3538,7 +3539,7 @@ static int bf_convert_to_radix(bf_t *r, slimb_t *pE, e_sign = 1; } /* Note: precision for log2(radix) is not critical here */ - prec0 = bf_mul_log2_radix(P, radix, FALSE, TRUE); + prec0 = bf_mul_log2_radix(P, radix, false, true); ziv_extra_bits = 16; for(;;) { prec = prec0 + ziv_extra_bits; @@ -3631,12 +3632,12 @@ static void limb_to_a2(char *buf, limb_t n, unsigned int radix_bits, int len) } } -/* 'a' must be an integer if the is_dec = FALSE or if the radix is not +/* 'a' must be an integer if the is_dec = false or if the radix is not a power of two. A dot is added before the 'dot_pos' digit. dot_pos = n_digits does not display the dot. 0 <= dot_pos <= n_digits. n_digits >= 1. */ static void output_digits(DynBuf *s, const bf_t *a1, int radix, limb_t n_digits, - limb_t dot_pos, BOOL is_dec) + limb_t dot_pos, bool is_dec) { limb_t i, v, l; slimb_t pos, pos_incr; @@ -3720,7 +3721,7 @@ static void *bf_dbuf_realloc(void *opaque, void *ptr, size_t size) /* return the length in bytes. A trailing '\0' is added */ static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix, - limb_t prec, bf_flags_t flags, BOOL is_dec) + limb_t prec, bf_flags_t flags, bool is_dec) { bf_context_t *ctx = a2->ctx; DynBuf s_s, *s = &s_s; @@ -3809,11 +3810,11 @@ static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix, a->sign = 0; /* one more digit for the rounding */ - n = 1 + bf_mul_log2_radix(bf_max(a->expn, 0), radix, TRUE, TRUE); + n = 1 + bf_mul_log2_radix(bf_max(a->expn, 0), radix, true, true); n_digits = n + prec; n1 = n; if (bf_convert_to_radix(a1, &n1, a, radix, n_digits, - flags & BF_RND_MASK, TRUE)) + flags & BF_RND_MASK, true)) goto fail1; start = s->size; output_digits(s, a1, radix, n_digits, n, is_dec); @@ -3896,7 +3897,7 @@ static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix, slimb_t n_digits_max, n_digits_min; assert(prec != BF_PREC_INF); - n_digits = 1 + bf_mul_log2_radix(prec, radix, TRUE, TRUE); + n_digits = 1 + bf_mul_log2_radix(prec, radix, true, true); /* max number of digits for non exponential notation. The rational is to have the same rule as JS i.e. n_max = 21 for 64 bit float in base 10. */ @@ -3913,7 +3914,7 @@ static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix, while (n_digits_min < n_digits_max) { n_digits = (n_digits_min + n_digits_max) / 2; if (bf_convert_to_radix(a1, &n, a, radix, n_digits, - flags & BF_RND_MASK, FALSE)) { + flags & BF_RND_MASK, false)) { bf_delete(b); goto fail1; } @@ -3937,7 +3938,7 @@ static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix, } } if (bf_convert_to_radix(a1, &n, a, radix, n_digits, - flags & BF_RND_MASK, FALSE)) { + flags & BF_RND_MASK, false)) { fail1: bf_delete(a1); goto fail; @@ -4016,7 +4017,7 @@ static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix, char *bf_ftoa(size_t *plen, const bf_t *a, int radix, limb_t prec, bf_flags_t flags) { - return bf_ftoa_internal(plen, a, radix, prec, flags, FALSE); + return bf_ftoa_internal(plen, a, radix, prec, flags, false); } /***************************************************************/ @@ -4024,7 +4025,7 @@ char *bf_ftoa(size_t *plen, const bf_t *a, int radix, limb_t prec, /* Note: the algorithm is from MPFR */ static void bf_const_log2_rec(bf_t *T, bf_t *P, bf_t *Q, limb_t n1, - limb_t n2, BOOL need_P) + limb_t n2, bool need_P) { bf_context_t *s = T->ctx; if ((n2 - n1) == 1) { @@ -4044,7 +4045,7 @@ static void bf_const_log2_rec(bf_t *T, bf_t *P, bf_t *Q, limb_t n1, bf_t Q1_s, *Q1 = &Q1_s; m = n1 + ((n2 - n1) >> 1); - bf_const_log2_rec(T, P, Q, n1, m, TRUE); + bf_const_log2_rec(T, P, Q, n1, m, true); bf_init(s, T1); bf_init(s, P1); bf_init(s, Q1); @@ -4072,7 +4073,7 @@ static void bf_const_log2_internal(bf_t *T, limb_t prec) N = w / 3 + 1; bf_init(T->ctx, P); bf_init(T->ctx, Q); - bf_const_log2_rec(T, P, Q, 0, N, FALSE); + bf_const_log2_rec(T, P, Q, 0, N, false); bf_div(T, T, Q, prec, BF_RNDN); bf_delete(P); bf_delete(Q); @@ -4634,10 +4635,10 @@ static int bf_pow_int(bf_t *r, const bf_t *x, limb_t prec, void *opaque) return ret; } -/* x must be a finite non zero float. Return TRUE if there is a +/* x must be a finite non zero float. Return true if there is a floating point number r such as x=r^(2^n) and return this floating - point number 'r'. Otherwise return FALSE and r is undefined. */ -static BOOL check_exact_power2n(bf_t *r, const bf_t *x, slimb_t n) + point number 'r'. Otherwise return false and r is undefined. */ +static bool check_exact_power2n(bf_t *r, const bf_t *x, slimb_t n) { bf_context_t *s = r->ctx; bf_t T_s, *T = &T_s; @@ -4649,17 +4650,17 @@ static BOOL check_exact_power2n(bf_t *r, const bf_t *x, slimb_t n) /* fast check on the exponent */ if (n > (LIMB_BITS - 1)) { if (e != 0) - return FALSE; + return false; er = 0; } else { if ((e & (((limb_t)1 << n) - 1)) != 0) - return FALSE; + return false; er = e >> n; } /* every perfect odd square = 1 modulo 8 */ v = get_bits(x->tab, x->len, x->len * LIMB_BITS - x->expn + e); if ((v & 7) != 1) - return FALSE; + return false; bf_init(s, T); bf_set(T, x); @@ -4668,10 +4669,10 @@ static BOOL check_exact_power2n(bf_t *r, const bf_t *x, slimb_t n) if (i != 0) bf_set(T, r); if (bf_sqrtrem(r, NULL, T) != 0) - return FALSE; + return false; } r->expn += er; - return TRUE; + return true; } /* prec = BF_PREC_INF is accepted for x and y integers and y >= 0 */ @@ -4680,7 +4681,7 @@ int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags) bf_context_t *s = r->ctx; bf_t T_s, *T = &T_s; bf_t ytmp_s; - BOOL y_is_int, y_is_odd; + bool y_is_int, y_is_odd; int r_sign, ret, rnd_mode; slimb_t y_emin; @@ -4820,11 +4821,6 @@ int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags) bf_t *y1; if (y_emin < 0 && check_exact_power2n(r, T, -y_emin)) { /* the problem is reduced to a power to an integer */ -#if 0 - printf("\nn=%" PRId64 "\n", -(int64_t)y_emin); - bf_print_str("T", T); - bf_print_str("r", r); -#endif bf_set(T, r); y1 = &ytmp_s; y1->tab = y->tab; @@ -5076,7 +5072,7 @@ static int bf_atan_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) { bf_context_t *s = r->ctx; - BOOL add_pi2 = (BOOL)(intptr_t)opaque; + bool add_pi2 = (bool)(intptr_t)opaque; bf_t T_s, *T = &T_s; bf_t U_s, *U = &U_s; bf_t V_s, *V = &V_s; @@ -5201,7 +5197,7 @@ int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) } } - return bf_ziv_rounding(r, a, prec, flags, bf_atan_internal, (void *)FALSE); + return bf_ziv_rounding(r, a, prec, flags, bf_atan_internal, (void *)false); } static int bf_atan2_internal(bf_t *r, const bf_t *y, limb_t prec, void *opaque) @@ -5251,7 +5247,7 @@ int bf_atan2(bf_t *r, const bf_t *y, const bf_t *x, static int bf_asin_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) { bf_context_t *s = r->ctx; - BOOL is_acos = (BOOL)(intptr_t)opaque; + bool is_acos = (bool)(intptr_t)opaque; bf_t T_s, *T = &T_s; limb_t prec1, prec2; @@ -5317,7 +5313,7 @@ int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) } } - return bf_ziv_rounding(r, a, prec, flags, bf_asin_internal, (void *)FALSE); + return bf_ziv_rounding(r, a, prec, flags, bf_asin_internal, (void *)false); } int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) @@ -5351,7 +5347,7 @@ int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) return 0; } - return bf_ziv_rounding(r, a, prec, flags, bf_asin_internal, (void *)TRUE); + return bf_ziv_rounding(r, a, prec, flags, bf_asin_internal, (void *)true); } /***************************************************************/ @@ -5376,19 +5372,20 @@ int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) #if LIMB_BITS == 64 /* Note: we assume __int128 is available */ +/* uint128_t defined in libbf.h */ #define muldq(r1, r0, a, b) \ do { \ - unsigned __int128 __t; \ - __t = (unsigned __int128)(a) * (unsigned __int128)(b); \ + uint128_t __t; \ + __t = (uint128_t)(a) * (uint128_t)(b); \ r0 = __t; \ r1 = __t >> 64; \ } while (0) #define divdq(q, r, a1, a0, b) \ do { \ - unsigned __int128 __t; \ + uint128_t __t; \ limb_t __b = (b); \ - __t = ((unsigned __int128)(a1) << 64) | (a0); \ + __t = ((uint128_t)(a1) << 64) | (a0); \ q = __t / __b; \ r = __t % __b; \ } while (0) @@ -5497,7 +5494,6 @@ static inline limb_t fast_udiv(limb_t a, const FastDivData *s) return (t1 + t0) >> s->shift2; } -#endif // USE_BF_DEC /* contains 10^i */ const limb_t mp_pow_dec[LIMB_DIGITS + 1] = { 1U, @@ -5523,7 +5519,6 @@ const limb_t mp_pow_dec[LIMB_DIGITS + 1] = { 10000000000000000000U, #endif }; -#ifdef USE_BF_DEC /* precomputed from fast_udiv_init(10^i) */ static const FastDivData mp_pow_div[LIMB_DIGITS + 1] = { @@ -6335,34 +6330,6 @@ static limb_t get_digit(const limb_t *tab, limb_t len, slimb_t pos) return fast_shr_dec(tab[i], shift) % 10; } -#if 0 -static limb_t get_digits(const limb_t *tab, limb_t len, slimb_t pos) -{ - limb_t a0, a1; - int shift; - slimb_t i; - - i = floor_div(pos, LIMB_DIGITS); - shift = pos - i * LIMB_DIGITS; - if (i >= 0 && i < len) - a0 = tab[i]; - else - a0 = 0; - if (shift == 0) { - return a0; - } else { - i++; - if (i >= 0 && i < len) - a1 = tab[i]; - else - a1 = 0; - return fast_shr_dec(a0, shift) + - fast_urem(a1, &mp_pow_div[LIMB_DIGITS - shift]) * - mp_pow_dec[shift]; - } -} -#endif - /* return the addend for rounding. Note that prec can be <= 0 for bf_rint() */ static int bfdec_get_rnd_add(int *pret, const bfdec_t *r, limb_t l, slimb_t prec, int rnd_mode) @@ -6963,7 +6930,7 @@ int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b, bfdec_t b1_s, *b1 = &b1_s; bfdec_t r1_s, *r1 = &r1_s; int q_sign, res; - BOOL is_ceil, is_rndn; + bool is_ceil, is_rndn; assert(q != a && q != b); assert(r != a && r != b); @@ -6990,7 +6957,7 @@ int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b, case BF_RNDZ: case BF_RNDN: case BF_RNDNA: - is_ceil = FALSE; + is_ceil = false; break; case BF_RNDD: is_ceil = q_sign; @@ -6999,7 +6966,7 @@ int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b, is_ceil = q_sign ^ 1; break; case BF_RNDA: - is_ceil = TRUE; + is_ceil = true; break; case BF_DIVREM_EUCLIDIAN: is_ceil = a->sign; @@ -7229,7 +7196,7 @@ int bfdec_pow_ui(bfdec_t *r, const bfdec_t *a, limb_t b) char *bfdec_ftoa(size_t *plen, const bfdec_t *a, limb_t prec, bf_flags_t flags) { - return bf_ftoa_internal(plen, (const bf_t *)a, 10, prec, flags, TRUE); + return bf_ftoa_internal(plen, (const bf_t *)a, 10, prec, flags, true); } int bfdec_atof(bfdec_t *r, const char *str, const char **pnext, @@ -7237,7 +7204,7 @@ int bfdec_atof(bfdec_t *r, const char *str, const char **pnext, { slimb_t dummy_exp; return bf_atof_internal((bf_t *)r, &dummy_exp, str, pnext, 10, prec, - flags, TRUE); + flags, true); } #endif /* USE_BF_DEC */ @@ -7989,12 +7956,6 @@ static no_inline void limb_to_ntt(BFNTTState *s, int j, shift; limb_t base_mask1, a0, a1, a2, r, m, m_inv; -#if 0 - for(i = 0; i < a_len; i++) { - printf("%" PRId64 ": " FMT_LIMB "\n", - (int64_t)i, taba[i]); - } -#endif memset(tabr, 0, sizeof(NTTLimb) * fft_len * nb_mods); shift = dpl & (LIMB_BITS - 1); if (shift == 0) @@ -8121,14 +8082,6 @@ static no_inline void ntt_to_limb(BFNTTState *s, limb_t *tabr, limb_t r_len, } u[l] = r + carry[l]; -#if 0 - printf("%" PRId64 ": ", i); - for(j = nb_mods - 1; j >= 0; j--) { - printf(" %019" PRIu64, u[j]); - } - printf("\n"); -#endif - /* write the digits */ pos = i * dpl; for(j = 0; j < n_limb1; j++) { @@ -8222,14 +8175,6 @@ static no_inline void ntt_to_limb(BFNTTState *s, limb_t *tabr, limb_t r_len, } u[l] = r + carry[l]; -#if 0 - printf("%" PRId64 ": ", (int64_t)i); - for(j = nb_mods - 1; j >= 0; j--) { - printf(" " FMT_LIMB, u[j]); - } - printf("\n"); -#endif - /* write the digits */ pos = i * dpl; for(j = 0; j < n_limb1; j++) { @@ -8473,3 +8418,7 @@ int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len) } #endif /* !USE_FFT_MUL */ + +#undef malloc +#undef free +#undef realloc diff --git a/src/shared/quickjs/libbf.h b/src/shared/quickjs/libbf.h index b247952b1..3586532e8 100644 --- a/src/shared/quickjs/libbf.h +++ b/src/shared/quickjs/libbf.h @@ -1,6 +1,6 @@ /* * Tiny arbitrary precision floating point library - * + * * Copyright (c) 2017-2021 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -31,7 +31,7 @@ extern "C" { #endif -#if defined(__SIZEOF_INT128__) && (INTPTR_MAX >= INT64_MAX) +#if INTPTR_MAX >= INT64_MAX && !defined(_WIN32) && !defined(__TINYC__) #define LIMB_LOG2_BITS 6 #else #define LIMB_LOG2_BITS 5 @@ -40,8 +40,10 @@ extern "C" { #define LIMB_BITS (1 << LIMB_LOG2_BITS) #if LIMB_BITS == 64 -typedef __int128 int128_t; -typedef unsigned __int128 uint128_t; +#ifndef INT128_MAX +__extension__ typedef __int128 int128_t; +__extension__ typedef unsigned __int128 uint128_t; +#endif typedef int64_t slimb_t; typedef uint64_t limb_t; typedef uint128_t dlimb_t; @@ -175,7 +177,7 @@ static inline bf_flags_t bf_set_exp_bits(int n) #define BF_ST_UNDERFLOW (1 << 3) #define BF_ST_INEXACT (1 << 4) /* indicate that a memory allocation error occured. NaN is returned */ -#define BF_ST_MEM_ERROR (1 << 5) +#define BF_ST_MEM_ERROR (1 << 5) #define BF_RADIX_MAX 36 /* maximum radix for bf_atof() and bf_ftoa() */ @@ -288,7 +290,7 @@ int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags) int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, bf_flags_t flags); int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags); int bf_mul_ui(bf_t *r, const bf_t *a, uint64_t b1, limb_t prec, bf_flags_t flags); -int bf_mul_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, +int bf_mul_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, bf_flags_t flags); int bf_mul_2exp(bf_t *r, slimb_t e, limb_t prec, bf_flags_t flags); int bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags); @@ -345,12 +347,12 @@ int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix, /* fractional format: prec digits after the decimal point rounded with (flags & BF_RND_MASK) */ #define BF_FTOA_FORMAT_FRAC (1 << 16) -/* free format: - +/* free format: + For binary radices with bf_ftoa() and for bfdec_ftoa(): use the minimum number of digits to represent 'a'. The precision and the rounding mode are ignored. - + For the non binary radices with bf_ftoa(): use as many digits as necessary so that bf_atof() return the same number when using precision 'prec', rounding to nearest and the subnormal @@ -377,7 +379,7 @@ char *bf_ftoa(size_t *plen, const bf_t *a, int radix, limb_t prec, bf_flags_t flags); /* modulo 2^n instead of saturation. NaN and infinity return 0 */ -#define BF_GET_INT_MOD (1 << 0) +#define BF_GET_INT_MOD (1 << 0) int bf_get_int32(int *pres, const bf_t *a, int flags); int bf_get_int64(int64_t *pres, const bf_t *a, int flags); int bf_get_uint64(uint64_t *pres, const bf_t *a); @@ -391,10 +393,10 @@ int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags); int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k); slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv, int is_ceil1); -int mp_mul(bf_context_t *s, limb_t *result, - const limb_t *op1, limb_t op1_size, +int mp_mul(bf_context_t *s, limb_t *result, + const limb_t *op1, limb_t op1_size, const limb_t *op2, limb_t op2_size); -limb_t mp_add(limb_t *res, const limb_t *op1, const limb_t *op2, +limb_t mp_add(limb_t *res, const limb_t *op1, const limb_t *op2, limb_t n, limb_t carry); limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n); int mp_sqrtrem(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n); diff --git a/src/shared/quickjs/libregexp-opcode.h b/src/shared/quickjs/libregexp-opcode.h index f255e09f2..5c1714ab0 100644 --- a/src/shared/quickjs/libregexp-opcode.h +++ b/src/shared/quickjs/libregexp-opcode.h @@ -25,7 +25,8 @@ #ifdef DEF DEF(invalid, 1) /* never used */ -DEF(char, 3) +DEF(char8, 2) /* 7 bits in fact */ +DEF(char16, 3) DEF(char32, 5) DEF(dot, 1) DEF(any, 1) /* same as dot but match any character including line terminator */ diff --git a/src/shared/quickjs/libregexp.c b/src/shared/quickjs/libregexp.c index 4db042941..04c2888a8 100644 --- a/src/shared/quickjs/libregexp.c +++ b/src/shared/quickjs/libregexp.c @@ -30,7 +30,6 @@ #include "cutils.h" #include "libregexp.h" -#include "libunicode.h" /* TODO: @@ -61,15 +60,17 @@ typedef enum { #define TMP_BUF_SIZE 128 +// invariant: is_unicode ^ unicode_sets (or neither, but not both) typedef struct { DynBuf byte_code; const uint8_t *buf_ptr; const uint8_t *buf_end; const uint8_t *buf_start; int re_flags; - BOOL is_unicode; - BOOL ignore_case; - BOOL dotall; + bool is_unicode; + bool unicode_sets; + bool ignore_case; + bool dotall; int capture_count; int total_capture_count; /* -1 = not computed yet */ int has_named_captures; /* -1 = don't know, 0 = no, 1 = yes */ @@ -99,13 +100,13 @@ static const REOpCode reopcode_info[REOP_COUNT] = { }; #define RE_HEADER_FLAGS 0 -#define RE_HEADER_CAPTURE_COUNT 1 -#define RE_HEADER_STACK_SIZE 2 -#define RE_HEADER_BYTECODE_LEN 3 +#define RE_HEADER_CAPTURE_COUNT 2 +#define RE_HEADER_STACK_SIZE 3 +#define RE_HEADER_BYTECODE_LEN 4 -#define RE_HEADER_LEN 7 +#define RE_HEADER_LEN 8 -static inline int is_digit(int c) { +static inline int lre_is_digit(int c) { return c >= '0' && c <= '9'; } @@ -142,6 +143,32 @@ static const uint16_t char_range_s[] = { 0xFEFF, 0xFEFF + 1, }; +bool lre_is_space(int c) +{ + int i, n, low, high; + n = (countof(char_range_s) - 1) / 2; + for(i = 0; i < n; i++) { + low = char_range_s[2 * i + 1]; + if (c < low) + return false; + high = char_range_s[2 * i + 2]; + if (c < high) + return true; + } + return false; +} + +uint32_t const lre_id_start_table_ascii[4] = { + /* $ A-Z _ a-z */ + 0x00000000, 0x00000010, 0x87FFFFFE, 0x07FFFFFE +}; + +uint32_t const lre_id_continue_table_ascii[4] = { + /* $ 0-9 A-Z _ a-z */ + 0x00000000, 0x03FF0010, 0x87FFFFFE, 0x07FFFFFE +}; + + static const uint16_t char_range_w[] = { 4, 0x0030, 0x0039 + 1, @@ -161,7 +188,7 @@ typedef enum { CHAR_RANGE_W, } CharRangeEnum; -static const uint16_t * const char_range_table[] = { +static const uint16_t *char_range_table[] = { char_range_d, char_range_s, char_range_w, @@ -169,7 +196,7 @@ static const uint16_t * const char_range_table[] = { static int cr_init_char_range(REParseState *s, CharRange *cr, uint32_t c) { - BOOL invert; + bool invert; const uint16_t *c_pt; int len, i; @@ -236,15 +263,15 @@ static __maybe_unused void lre_dump_bytecode(const uint8_t *buf, } printf("%s", reopcode_info[opcode].name); switch(opcode) { - case REOP_char: + case REOP_char8: + val = get_u8(buf + pos + 1); + goto printchar; + case REOP_char16: val = get_u16(buf + pos + 1); - if (val >= ' ' && val <= 126) - printf(" '%c'", val); - else - printf(" 0x%04x", val); - break; + goto printchar; case REOP_char32: val = get_u32(buf + pos + 1); + printchar: if (val >= ' ' && val <= 126) printf(" '%c'", val); else @@ -347,7 +374,7 @@ static void re_emit_op_u16(REParseState *s, int op, uint32_t val) dbuf_put_u16(&s->byte_code, val); } -static int FORMAT_ATTR(2, 3) re_parse_error(REParseState *s, const char *fmt, ...) +static int JS_PRINTF_FORMAT_ATTR(2, 3) re_parse_error(REParseState *s, const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -363,7 +390,7 @@ static int re_parse_out_of_memory(REParseState *s) /* If allow_overflow is false, return -1 in case of overflow. Otherwise return INT32_MAX. */ -static int parse_digits(const uint8_t **pp, BOOL allow_overflow) +static int parse_digits(const uint8_t **pp, bool allow_overflow) { const uint8_t *p; uint64_t v; @@ -494,7 +521,7 @@ int lre_parse_escape(const uint8_t **pp, int allow_utf16) c -= '0'; if (allow_utf16 == 2) { /* only accept \0 not followed by digit */ - if (c != 0 || is_digit(*p)) + if (c != 0 || lre_is_digit(*p)) return -1; } else { /* parse a legacy octal sequence */ @@ -520,9 +547,8 @@ int lre_parse_escape(const uint8_t **pp, int allow_utf16) return c; } -#ifdef CONFIG_ALL_UNICODE /* XXX: we use the same chars for name and value */ -static BOOL is_unicode_char(int c) +static bool is_unicode_char(int c) { return ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || @@ -531,12 +557,12 @@ static BOOL is_unicode_char(int c) } static int parse_unicode_property(REParseState *s, CharRange *cr, - const uint8_t **pp, BOOL is_inv) + const uint8_t **pp, bool is_inv) { const uint8_t *p; char name[64], value[64]; char *q; - BOOL script_ext; + bool script_ext; int ret; p = *pp; @@ -566,10 +592,10 @@ static int parse_unicode_property(REParseState *s, CharRange *cr, // printf("name=%s value=%s\n", name, value); if (!strcmp(name, "Script") || !strcmp(name, "sc")) { - script_ext = FALSE; + script_ext = false; goto do_script; } else if (!strcmp(name, "Script_Extensions") || !strcmp(name, "scx")) { - script_ext = TRUE; + script_ext = true; do_script: cr_init(cr, s->opaque, lre_realloc); ret = unicode_script(cr, value, script_ext); @@ -623,15 +649,14 @@ static int parse_unicode_property(REParseState *s, CharRange *cr, out_of_memory: return re_parse_out_of_memory(s); } -#endif /* CONFIG_ALL_UNICODE */ /* return -1 if error otherwise the character or a class range (CLASS_RANGE_BASE). In case of class range, 'cr' is initialized. Otherwise, it is ignored. */ static int get_class_atom(REParseState *s, CharRange *cr, - const uint8_t **pp, BOOL inclass) + const uint8_t **pp, bool inclass) { - const uint8_t *p; + const uint8_t *p, *p_next; uint32_t c; int ret; @@ -683,7 +708,6 @@ static int get_class_atom(REParseState *s, CharRange *cr, c = '\\'; } break; -#ifdef CONFIG_ALL_UNICODE case 'p': case 'P': if (s->is_unicode) { @@ -693,7 +717,6 @@ static int get_class_atom(REParseState *s, CharRange *cr, break; } /* fall thru */ -#endif default: p--; ret = lre_parse_escape(&p, s->is_unicode * 2); @@ -704,6 +727,9 @@ static int get_class_atom(REParseState *s, CharRange *cr, /* always valid to escape these characters */ goto normal_char; } else if (s->is_unicode) { + // special case: allowed inside [] but not outside + if (ret == -2 && *p == '-' && inclass) + goto normal_char; invalid_escape: return re_parse_error(s, "invalid escape sequence in regular expression"); } else { @@ -722,15 +748,18 @@ static int get_class_atom(REParseState *s, CharRange *cr, /* fall thru */ default: normal_char: - /* normal char */ - if (c >= 128) { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); - if ((unsigned)c > 0xffff && !s->is_unicode) { - /* XXX: should handle non BMP-1 code points */ + p++; + if (c >= 0x80) { + c = utf8_decode(p - 1, &p_next); + if (p_next == p) + return re_parse_error(s, "invalid UTF-8 sequence"); + p = p_next; + if (c > 0xFFFF && !s->is_unicode) { + // TODO(chqrlie): should handle non BMP-1 code points in + // the calling function and no require the source string + // to be CESU-8 encoded if not s->is_unicode return re_parse_error(s, "malformed unicode char"); } - } else { - p++; } break; } @@ -776,30 +805,56 @@ static int re_emit_range(REParseState *s, const CharRange *cr) return 0; } +// s->unicode turns patterns like []] into syntax errors +// s->unicode_sets turns more patterns into errors, like [a-] or [[] static int re_parse_char_class(REParseState *s, const uint8_t **pp) { const uint8_t *p; uint32_t c1, c2; CharRange cr_s, *cr = &cr_s; CharRange cr1_s, *cr1 = &cr1_s; - BOOL invert; + bool invert; cr_init(cr, s->opaque, lre_realloc); p = *pp; p++; /* skip '[' */ - invert = FALSE; + if (s->unicode_sets) { + static const char verboten[] = + "()[{}/-|" "\0" + "&&!!##$$%%**++,,..::;;<<==>>??@@``~~" "\0" + "^^^_^^"; + const char *s = verboten; + int n = 1; + do { + if (!memcmp(s, p, n)) + if (p[n] == ']') + goto invalid_class_range; + s += n; + if (!*s) { + s++; + n++; + } + } while (n < 4); + } + + invert = false; if (*p == '^') { p++; - invert = TRUE; + invert = true; } for(;;) { if (*p == ']') break; - c1 = get_class_atom(s, cr1, &p, TRUE); + c1 = get_class_atom(s, cr1, &p, true); if ((int)c1 < 0) goto fail; + if (*p == '-' && p[1] == ']' && s->unicode_sets) { + if (c1 >= CLASS_RANGE_BASE) + cr_free(cr1); + goto invalid_class_range; + } if (*p == '-' && p[1] != ']') { const uint8_t *p0 = p + 1; if (c1 >= CLASS_RANGE_BASE) { @@ -810,7 +865,7 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp) /* Annex B: match '-' character */ goto class_atom; } - c2 = get_class_atom(s, cr1, &p0, TRUE); + c2 = get_class_atom(s, cr1, &p0, true); if ((int)c2 < 0) goto fail; if (c2 >= CLASS_RANGE_BASE) { @@ -868,14 +923,15 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp) - true if the opcodes may not advance the char pointer - false if the opcodes always advance the char pointer */ -static BOOL re_need_check_advance(const uint8_t *bc_buf, int bc_buf_len) +static bool re_need_check_advance(const uint8_t *bc_buf, int bc_buf_len) { int pos, opcode, len; uint32_t val; - BOOL ret; + bool ret; - ret = TRUE; + ret = true; pos = 0; + while (pos < bc_buf_len) { opcode = bc_buf[pos]; len = reopcode_info[opcode].size; @@ -888,12 +944,13 @@ static BOOL re_need_check_advance(const uint8_t *bc_buf, int bc_buf_len) val = get_u16(bc_buf + pos + 1); len += val * 8; goto simple_char; - case REOP_char: case REOP_char32: + case REOP_char16: + case REOP_char8: case REOP_dot: case REOP_any: simple_char: - ret = FALSE; + ret = false; break; case REOP_line_start: case REOP_line_end: @@ -912,8 +969,8 @@ static BOOL re_need_check_advance(const uint8_t *bc_buf, int bc_buf_len) case REOP_backward_back_reference: break; default: - /* safe behavior: we cannot predict the outcome */ - return TRUE; + /* safe behvior: we cannot predict the outcome */ + return true; } pos += len; } @@ -941,8 +998,9 @@ static int re_is_simple_quantifier(const uint8_t *bc_buf, int bc_buf_len) val = get_u16(bc_buf + pos + 1); len += val * 8; goto simple_char; - case REOP_char: case REOP_char32: + case REOP_char16: + case REOP_char8: case REOP_dot: case REOP_any: simple_char: @@ -964,35 +1022,35 @@ static int re_is_simple_quantifier(const uint8_t *bc_buf, int bc_buf_len) /* '*pp' is the first char after '<' */ static int re_parse_group_name(char *buf, int buf_size, const uint8_t **pp) { - const uint8_t *p, *p1; + const uint8_t *p, *p_next; uint32_t c, d; char *q; p = *pp; q = buf; for(;;) { - c = *p; + c = *p++; if (c == '\\') { - p++; if (*p != 'u') return -1; c = lre_parse_escape(&p, 2); // accept surrogate pairs + if ((int)c < 0) + return -1; } else if (c == '>') { break; - } else if (c >= 128) { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); + } else if (c >= 0x80) { + c = utf8_decode(p - 1, &p_next); + if (p_next == p) + return -1; + p = p_next; if (is_hi_surrogate(c)) { - d = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1); + d = utf8_decode(p, &p_next); if (is_lo_surrogate(d)) { c = from_surrogate(c, d); - p = p1; + p = p_next; } } - } else { - p++; } - if (c > 0x10FFFF) - return -1; if (q == buf) { if (!lre_js_is_ident_first(c)) return -1; @@ -1002,16 +1060,15 @@ static int re_parse_group_name(char *buf, int buf_size, const uint8_t **pp) } if ((q - buf + UTF8_CHAR_LEN_MAX + 1) > buf_size) return -1; - if (c < 128) { + if (c < 0x80) { *q++ = c; } else { - q += unicode_to_utf8((uint8_t*)q, c); + q += utf8_encode((uint8_t*)q, c); } } if (q == buf) return -1; *q = '\0'; - p++; *pp = p; return 0; } @@ -1079,7 +1136,7 @@ static int re_count_captures(REParseState *s) return s->total_capture_count; } -static BOOL re_has_named_captures(REParseState *s) +static bool re_has_named_captures(REParseState *s) { if (s->has_named_captures < 0) re_count_captures(s); @@ -1107,13 +1164,13 @@ static int find_group_name(REParseState *s, const char *name) return -1; } -static int re_parse_disjunction(REParseState *s, BOOL is_backward_dir); +static int re_parse_disjunction(REParseState *s, bool is_backward_dir); -static int re_parse_term(REParseState *s, BOOL is_backward_dir) +static int re_parse_term(REParseState *s, bool is_backward_dir) { const uint8_t *p; int c, last_atom_start, quant_min, quant_max, last_capture_count; - BOOL greedy, add_zero_advance_check, is_neg, is_backward_lookahead; + bool greedy, add_zero_advance_check, is_neg, is_backward_lookahead; CharRange cr_s, *cr = &cr_s; last_atom_start = -1; @@ -1142,18 +1199,18 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) case '{': if (s->is_unicode) { return re_parse_error(s, "syntax error"); - } else if (!is_digit(p[1])) { + } else if (!lre_is_digit(p[1])) { /* Annex B: we accept '{' not followed by digits as a normal atom */ goto parse_class_atom; } else { const uint8_t *p1 = p + 1; /* Annex B: error if it is like a repetition count */ - parse_digits(&p1, TRUE); + parse_digits(&p1, true); if (*p1 == ',') { p1++; - if (is_digit(*p1)) { - parse_digits(&p1, TRUE); + if (lre_is_digit(*p1)) { + parse_digits(&p1, true); } } if (*p1 != '}') { @@ -1179,14 +1236,14 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) return -1; } else if ((p[2] == '=' || p[2] == '!')) { is_neg = (p[2] == '!'); - is_backward_lookahead = FALSE; + is_backward_lookahead = false; p += 3; goto lookahead; } else if (p[2] == '<' && (p[3] == '=' || p[3] == '!')) { int pos; is_neg = (p[3] == '!'); - is_backward_lookahead = TRUE; + is_backward_lookahead = true; p += 4; /* lookahead */ lookahead: @@ -1300,7 +1357,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) p += 2; c = 0; if (s->is_unicode) { - if (is_digit(*p)) { + if (lre_is_digit(*p)) { return re_parse_error(s, "invalid decimal escape in regular expression"); } } else { @@ -1319,7 +1376,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) { const uint8_t *q = ++p; - c = parse_digits(&p, FALSE); + c = parse_digits(&p, false); if (c < 0 || (c >= s->capture_count && c >= re_count_captures(s))) { if (!s->is_unicode) { /* Annex B.1.4: accept legacy octal */ @@ -1368,7 +1425,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) goto parse_class_atom; default: parse_class_atom: - c = get_class_atom(s, cr, &p, FALSE); + c = get_class_atom(s, cr, &p, false); if ((int)c < 0) return -1; normal_char: @@ -1386,8 +1443,10 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) } else { if (s->ignore_case) c = lre_canonicalize(c, s->is_unicode); - if (c <= 0xffff) - re_emit_op_u16(s, REOP_char, c); + if (c <= 0x7f) + re_emit_op_u8(s, REOP_char8, c); + else if (c <= 0xffff) + re_emit_op_u16(s, REOP_char16, c); else re_emit_op_u32(s, REOP_char32, c); } @@ -1420,18 +1479,18 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) const uint8_t *p1 = p; /* As an extension (see ES6 annex B), we accept '{' not followed by digits as a normal atom */ - if (!is_digit(p[1])) { + if (!lre_is_digit(p[1])) { if (s->is_unicode) goto invalid_quant_count; break; } p++; - quant_min = parse_digits(&p, TRUE); + quant_min = parse_digits(&p, true); quant_max = quant_min; if (*p == ',') { p++; - if (is_digit(*p)) { - quant_max = parse_digits(&p, TRUE); + if (lre_is_digit(*p)) { + quant_max = parse_digits(&p, true); if (quant_max < quant_min) { invalid_quant_count: return re_parse_error(s, "invalid repetition count"); @@ -1449,10 +1508,10 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) return -1; } quantifier: - greedy = TRUE; + greedy = true; if (*p == '?') { p++; - greedy = FALSE; + greedy = false; } if (last_atom_start < 0) { return re_parse_error(s, "nothing to repeat"); @@ -1488,15 +1547,13 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) if (dbuf_error(&s->byte_code)) goto out_of_memory; - /* the spec tells that if there is no advance when - running the atom after the first quant_min times, - then there is no match. We remove this test when we - are sure the atom always advances the position. */ - add_zero_advance_check = re_need_check_advance(s->byte_code.buf + last_atom_start, - s->byte_code.size - last_atom_start); - } else { - add_zero_advance_check = FALSE; } + /* the spec tells that if there is no advance when + running the atom after the first quant_min times, + then there is no match. We remove this test when we + are sure the atom always advances the position. */ + add_zero_advance_check = re_need_check_advance(s->byte_code.buf + last_atom_start, + s->byte_code.size - last_atom_start); { int len, pos; @@ -1514,7 +1571,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) if (quant_max == 0) { s->byte_code.size = last_atom_start; } else if (quant_max == 1 || quant_max == INT32_MAX) { - BOOL has_goto = (quant_max == INT32_MAX); + bool has_goto = (quant_max == INT32_MAX); if (dbuf_insert(&s->byte_code, last_atom_start, 5 + add_zero_advance_check)) goto out_of_memory; s->byte_code.buf[last_atom_start] = REOP_split_goto_first + @@ -1601,7 +1658,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) return re_parse_out_of_memory(s); } -static int re_parse_alternative(REParseState *s, BOOL is_backward_dir) +static int re_parse_alternative(REParseState *s, bool is_backward_dir) { const uint8_t *p; int ret; @@ -1635,7 +1692,7 @@ static int re_parse_alternative(REParseState *s, BOOL is_backward_dir) return 0; } -static int re_parse_disjunction(REParseState *s, BOOL is_backward_dir) +static int re_parse_disjunction(REParseState *s, bool is_backward_dir) { int start, len, pos; @@ -1670,7 +1727,7 @@ static int re_parse_disjunction(REParseState *s, BOOL is_backward_dir) } /* the control flow is recursive so the analysis can be linear */ -static int compute_stack_size(const uint8_t *bc_buf, int bc_buf_len) +static int lre_compute_stack_size(const uint8_t *bc_buf, int bc_buf_len) { int stack_size, stack_size_max, pos, opcode, len; uint32_t val; @@ -1724,7 +1781,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, { REParseState s_s, *s = &s_s; int stack_size; - BOOL is_sticky; + bool is_sticky; memset(s, 0, sizeof(*s)); s->opaque = opaque; @@ -1736,6 +1793,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, is_sticky = ((re_flags & LRE_FLAG_STICKY) != 0); s->ignore_case = ((re_flags & LRE_FLAG_IGNORECASE) != 0); s->dotall = ((re_flags & LRE_FLAG_DOTALL) != 0); + s->unicode_sets = ((re_flags & LRE_FLAG_UNICODE_SETS) != 0); s->capture_count = 1; s->total_capture_count = -1; s->has_named_captures = -1; @@ -1743,7 +1801,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, dbuf_init2(&s->byte_code, opaque, lre_realloc); dbuf_init2(&s->group_names, opaque, lre_realloc); - dbuf_putc(&s->byte_code, re_flags); /* first element is the flags */ + dbuf_put_u16(&s->byte_code, re_flags); /* first element is the flags */ dbuf_putc(&s->byte_code, 0); /* second element is the number of captures */ dbuf_putc(&s->byte_code, 0); /* stack size */ dbuf_put_u32(&s->byte_code, 0); /* bytecode length */ @@ -1759,11 +1817,11 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, } re_emit_op_u8(s, REOP_save_start, 0); - if (re_parse_disjunction(s, FALSE)) { + if (re_parse_disjunction(s, false)) { error: dbuf_free(&s->byte_code); dbuf_free(&s->group_names); - pstrcpy(error_msg, error_msg_size, s->u.error_msg); + js__pstrcpy(error_msg, error_msg_size, s->u.error_msg); *plen = 0; return NULL; } @@ -1782,7 +1840,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, goto error; } - stack_size = compute_stack_size(s->byte_code.buf, s->byte_code.size); + stack_size = lre_compute_stack_size(s->byte_code.buf, s->byte_code.size); if (stack_size < 0) { re_parse_error(s, "too many imbricated quantifiers"); goto error; @@ -1796,7 +1854,8 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, /* add the named groups if needed */ if (s->group_names.size > (s->capture_count - 1)) { dbuf_put(&s->byte_code, s->group_names.buf, s->group_names.size); - s->byte_code.buf[RE_HEADER_FLAGS] |= LRE_FLAG_NAMED_GROUPS; + put_u16(s->byte_code.buf + RE_HEADER_FLAGS, + LRE_FLAG_NAMED_GROUPS | lre_get_flags(s->byte_code.buf)); } dbuf_free(&s->group_names); @@ -1809,12 +1868,12 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, return s->byte_code.buf; } -static BOOL is_line_terminator(uint32_t c) +static bool is_line_terminator(uint32_t c) { return (c == '\n' || c == '\r' || c == CP_LS || c == CP_PS); } -static BOOL is_word_char(uint32_t c) +static bool is_word_char(uint32_t c) { return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || @@ -1830,11 +1889,11 @@ static BOOL is_word_char(uint32_t c) const uint16_t *_p = (const uint16_t *)cptr; \ const uint16_t *_end = (const uint16_t *)cbuf_end; \ c = *_p++; \ - if (is_hi_surrogate(c) && cbuf_type == 2) { \ - if (_p < _end && is_lo_surrogate(*_p)) { \ - c = from_surrogate(c, *_p++); \ - } \ - } \ + if (is_hi_surrogate(c)) \ + if (cbuf_type == 2) \ + if (_p < _end) \ + if (is_lo_surrogate(*_p)) \ + c = from_surrogate(c, *_p++); \ cptr = (const void *)_p; \ } \ } while (0) @@ -1847,11 +1906,11 @@ static BOOL is_word_char(uint32_t c) const uint16_t *_p = (const uint16_t *)cptr; \ const uint16_t *_end = (const uint16_t *)cbuf_end; \ c = *_p++; \ - if (is_hi_surrogate(c) && cbuf_type == 2) { \ - if (_p < _end && is_lo_surrogate(*_p)) { \ - c = from_surrogate(c, *_p); \ - } \ - } \ + if (is_hi_surrogate(c)) \ + if (cbuf_type == 2) \ + if (_p < _end) \ + if (is_lo_surrogate(*_p)) \ + c = from_surrogate(c, *_p); \ } \ } while (0) @@ -1863,11 +1922,11 @@ static BOOL is_word_char(uint32_t c) const uint16_t *_p = (const uint16_t *)cptr - 1; \ const uint16_t *_start = (const uint16_t *)cbuf_start; \ c = *_p; \ - if (is_lo_surrogate(c) && cbuf_type == 2) { \ - if (_p > _start && is_hi_surrogate(_p[-1])) { \ - c = from_surrogate(*--_p, c); \ - } \ - } \ + if (is_lo_surrogate(c)) \ + if (cbuf_type == 2) \ + if (_p > _start) \ + if (is_hi_surrogate(_p[-1])) \ + c = from_surrogate(*--_p, c); \ } \ } while (0) @@ -1880,11 +1939,11 @@ static BOOL is_word_char(uint32_t c) const uint16_t *_p = (const uint16_t *)cptr - 1; \ const uint16_t *_start = (const uint16_t *)cbuf_start; \ c = *_p; \ - if (is_lo_surrogate(c) && cbuf_type == 2) { \ - if (_p > _start && is_hi_surrogate(_p[-1])) { \ - c = from_surrogate(*--_p, c); \ - } \ - } \ + if (is_lo_surrogate(c)) \ + if (cbuf_type == 2) \ + if (_p > _start) \ + if (is_hi_surrogate(_p[-1])) \ + c = from_surrogate(*--_p, c); \ cptr = (const void *)_p; \ } \ } while (0) @@ -1896,11 +1955,11 @@ static BOOL is_word_char(uint32_t c) } else { \ const uint16_t *_p = (const uint16_t *)cptr - 1; \ const uint16_t *_start = (const uint16_t *)cbuf_start; \ - if (is_lo_surrogate(*_p) && cbuf_type == 2) { \ - if (_p > _start && is_hi_surrogate(_p[-1])) { \ - --_p; \ - } \ - } \ + if (is_lo_surrogate(*_p)) \ + if (cbuf_type == 2) \ + if (_p > _start) \ + if (is_hi_surrogate(_p[-1])) \ + _p--; \ cptr = (const void *)_p; \ } \ } while (0) @@ -1920,7 +1979,7 @@ typedef struct REExecState { size_t count; /* only used for RE_EXEC_STATE_GREEDY_QUANT */ const uint8_t *cptr; const uint8_t *pc; - void *buf[0]; + void *buf[]; } REExecState; typedef struct { @@ -1930,9 +1989,9 @@ typedef struct { int cbuf_type; int capture_count; int stack_size_max; - BOOL multi_line; - BOOL ignore_case; - BOOL is_unicode; + bool multi_line; + bool ignore_case; + bool is_unicode; void *opaque; /* used for stack overflow check */ size_t state_size; @@ -1983,7 +2042,7 @@ static int push_state(REExecContext *s, static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture, StackInt *stack, int stack_len, const uint8_t *pc, const uint8_t *cptr, - BOOL no_recurse) + bool no_recurse) { int opcode, ret; int cbuf_type; @@ -2070,9 +2129,13 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture, val = get_u32(pc); pc += 4; goto test_char; - case REOP_char: + case REOP_char16: val = get_u16(pc); pc += 2; + goto test_char; + case REOP_char8: + val = get_u8(pc); + pc += 1; test_char: if (cptr >= cbuf_end) goto no_match; @@ -2193,17 +2256,17 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture, case REOP_word_boundary: case REOP_not_word_boundary: { - BOOL v1, v2; + bool v1, v2; /* char before */ if (cptr == s->cbuf) { - v1 = FALSE; + v1 = false; } else { PEEK_PREV_CHAR(c, cptr, s->cbuf, cbuf_type); v1 = is_word_char(c); } /* current char */ if (cptr >= cbuf_end) { - v2 = FALSE; + v2 = false; } else { PEEK_CHAR(c, cptr, cbuf_end, cbuf_type); v2 = is_word_char(c); @@ -2356,7 +2419,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture, q = 0; for(;;) { res = lre_exec_backtrack(s, capture, stack, stack_len, - pc1, cptr, TRUE); + pc1, cptr, true); if (res == -1) return res; if (!res) @@ -2421,7 +2484,7 @@ int lre_exec(uint8_t **capture, alloca_size = s->stack_size_max * sizeof(stack_buf[0]); stack_buf = alloca(alloca_size); ret = lre_exec_backtrack(s, capture, stack_buf, 0, bc_buf + RE_HEADER_LEN, - cbuf + (cindex << cbuf_type), FALSE); + cbuf + (cindex << cbuf_type), false); lre_realloc(s->opaque, s->state_stack, 0); return ret; } @@ -2433,7 +2496,7 @@ int lre_get_capture_count(const uint8_t *bc_buf) int lre_get_flags(const uint8_t *bc_buf) { - return bc_buf[RE_HEADER_FLAGS]; + return get_u16(bc_buf + RE_HEADER_FLAGS); } /* Return NULL if no group names. Otherwise, return a pointer to @@ -2447,11 +2510,85 @@ const char *lre_get_groupnames(const uint8_t *bc_buf) return (const char *)(bc_buf + RE_HEADER_LEN + re_bytecode_len); } +void lre_byte_swap(uint8_t *buf, size_t len, bool is_byte_swapped) +{ + uint8_t *p, *pe; + uint32_t n, r, nw; + + p = buf; + if (len < RE_HEADER_LEN) + abort(); + + // format is: + //
+ // + // + // + // etc. + inplace_bswap16(&p[RE_HEADER_FLAGS]); + + n = get_u32(&p[RE_HEADER_BYTECODE_LEN]); + inplace_bswap32(&p[RE_HEADER_BYTECODE_LEN]); + if (is_byte_swapped) + n = bswap32(n); + if (n > len - RE_HEADER_LEN) + abort(); + + p = &buf[RE_HEADER_LEN]; + pe = &p[n]; + + while (p < pe) { + n = reopcode_info[*p].size; + switch (n) { + case 1: + case 2: + break; + case 3: + switch (*p) { + case REOP_save_reset: // has two 8 bit arguments + break; + case REOP_range32: // variable length + nw = get_u16(&p[1]); // number of pairs of uint32_t + if (is_byte_swapped) + n = bswap16(n); + for (r = 3 + 8 * nw; n < r; n += 4) + inplace_bswap32(&p[n]); + goto doswap16; + case REOP_range: // variable length + nw = get_u16(&p[1]); // number of pairs of uint16_t + if (is_byte_swapped) + n = bswap16(n); + for (r = 3 + 4 * nw; n < r; n += 2) + inplace_bswap16(&p[n]); + goto doswap16; + default: + doswap16: + inplace_bswap16(&p[1]); + break; + } + break; + case 5: + inplace_bswap32(&p[1]); + break; + case 17: + assert(*p == REOP_simple_greedy_quant); + inplace_bswap32(&p[1]); + inplace_bswap32(&p[5]); + inplace_bswap32(&p[9]); + inplace_bswap32(&p[13]); + break; + default: + abort(); + } + p = &p[n]; + } +} + #ifdef TEST -BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size) +bool lre_check_stack_overflow(void *opaque, size_t alloca_size) { - return FALSE; + return false; } void *lre_realloc(void *opaque, void *ptr, size_t size) @@ -2470,7 +2607,7 @@ int main(int argc, char **argv) if (argc < 4) { printf("usage: %s regexp flags input\n", argv[0]); - return 1; + exit(1); } flags = atoi(argv[2]); bc = lre_compile(&len, error_msg, sizeof(error_msg), argv[1], diff --git a/src/shared/quickjs/libregexp.h b/src/shared/quickjs/libregexp.h index 7af7ece0f..0b8fec52b 100644 --- a/src/shared/quickjs/libregexp.h +++ b/src/shared/quickjs/libregexp.h @@ -24,8 +24,14 @@ #ifndef LIBREGEXP_H #define LIBREGEXP_H +#include #include -#include + +#include "libunicode.h" + +#ifdef __cplusplus +extern "C" { +#endif #define LRE_FLAG_GLOBAL (1 << 0) #define LRE_FLAG_IGNORECASE (1 << 1) @@ -35,6 +41,7 @@ #define LRE_FLAG_STICKY (1 << 5) #define LRE_FLAG_INDICES (1 << 6) /* Unused by libregexp, just recorded. */ #define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */ +#define LRE_FLAG_UNICODE_SETS (1 << 8) uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, const char *buf, size_t buf_len, int re_flags, @@ -47,9 +54,39 @@ int lre_exec(uint8_t **capture, int cbuf_type, void *opaque); int lre_parse_escape(const uint8_t **pp, int allow_utf16); +bool lre_is_space(int c); -/* must be provided by the user, return non zero if overflow */ -int lre_check_stack_overflow(void *opaque, size_t alloca_size); +void lre_byte_swap(uint8_t *buf, size_t len, bool is_byte_swapped); + +/* must be provided by the user */ +bool lre_check_stack_overflow(void *opaque, size_t alloca_size); void *lre_realloc(void *opaque, void *ptr, size_t size); +/* JS identifier test */ +extern uint32_t const lre_id_start_table_ascii[4]; +extern uint32_t const lre_id_continue_table_ascii[4]; + +static inline int lre_js_is_ident_first(int c) +{ + if ((uint32_t)c < 128) { + return (lre_id_start_table_ascii[c >> 5] >> (c & 31)) & 1; + } else { + return lre_is_id_start(c); + } +} + +static inline int lre_js_is_ident_next(int c) +{ + if ((uint32_t)c < 128) { + return (lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1; + } else { + /* ZWNJ and ZWJ are accepted in identifiers */ + return lre_is_id_continue(c) || c == 0x200C || c == 0x200D; + } +} + +#ifdef __cplusplus +} /* extern "C" { */ +#endif + #endif /* LIBREGEXP_H */ diff --git a/src/shared/quickjs/libunicode-table.h b/src/shared/quickjs/libunicode-table.h index 72d495e78..b48a3a746 100644 --- a/src/shared/quickjs/libunicode-table.h +++ b/src/shared/quickjs/libunicode-table.h @@ -3,7 +3,7 @@ #include -static const uint32_t case_conv_table1[370] = { +static const uint32_t case_conv_table1[378] = { 0x00209a30, 0x00309a00, 0x005a8173, 0x00601730, 0x006c0730, 0x006f81b3, 0x00701700, 0x007c0700, 0x007f8100, 0x00803040, 0x009801c3, 0x00988190, @@ -13,140 +13,143 @@ static const uint32_t case_conv_table1[370] = { 0x00c48230, 0x00c58240, 0x00c70130, 0x00c78130, 0x00c80130, 0x00c88240, 0x00c98130, 0x00ca0130, 0x00ca8100, 0x00cb0130, 0x00cb8130, 0x00cc0240, - 0x00cd0100, 0x00ce0130, 0x00ce8130, 0x00cf0100, - 0x00cf8130, 0x00d00640, 0x00d30130, 0x00d38240, - 0x00d48130, 0x00d60240, 0x00d70130, 0x00d78240, - 0x00d88230, 0x00d98440, 0x00db8130, 0x00dc0240, - 0x00de0240, 0x00df8100, 0x00e20350, 0x00e38350, - 0x00e50350, 0x00e69040, 0x00ee8100, 0x00ef1240, - 0x00f801b4, 0x00f88350, 0x00fa0240, 0x00fb0130, - 0x00fb8130, 0x00fc2840, 0x01100130, 0x01111240, - 0x011d0131, 0x011d8240, 0x011e8130, 0x011f0131, - 0x011f8201, 0x01208240, 0x01218130, 0x01220130, - 0x01228130, 0x01230a40, 0x01280101, 0x01288101, - 0x01290101, 0x01298100, 0x012a0100, 0x012b0200, - 0x012c8100, 0x012d8100, 0x012e0101, 0x01300100, - 0x01308101, 0x01318100, 0x01328101, 0x01330101, - 0x01340100, 0x01348100, 0x01350101, 0x01358101, - 0x01360101, 0x01378100, 0x01388101, 0x01390100, - 0x013a8100, 0x013e8101, 0x01400100, 0x01410101, - 0x01418100, 0x01438101, 0x01440100, 0x01448100, - 0x01450200, 0x01460100, 0x01490100, 0x014e8101, - 0x014f0101, 0x01a28173, 0x01b80440, 0x01bb0240, - 0x01bd8300, 0x01bf8130, 0x01c30130, 0x01c40330, - 0x01c60130, 0x01c70230, 0x01c801d0, 0x01c89130, - 0x01d18930, 0x01d60100, 0x01d68300, 0x01d801d3, - 0x01d89100, 0x01e10173, 0x01e18900, 0x01e60100, - 0x01e68200, 0x01e78130, 0x01e80173, 0x01e88173, - 0x01ea8173, 0x01eb0173, 0x01eb8100, 0x01ec1840, - 0x01f80173, 0x01f88173, 0x01f90100, 0x01f98100, - 0x01fa01a0, 0x01fa8173, 0x01fb8240, 0x01fc8130, - 0x01fd0240, 0x01fe8330, 0x02001030, 0x02082030, - 0x02182000, 0x02281000, 0x02302240, 0x02453640, - 0x02600130, 0x02608e40, 0x02678100, 0x02686040, - 0x0298a630, 0x02b0a600, 0x02c381b5, 0x08502631, - 0x08638131, 0x08668131, 0x08682b00, 0x087e8300, - 0x09d05011, 0x09f80610, 0x09fc0620, 0x0e400174, - 0x0e408174, 0x0e410174, 0x0e418174, 0x0e420174, - 0x0e428174, 0x0e430174, 0x0e438180, 0x0e440180, - 0x0e482b30, 0x0e5e8330, 0x0ebc8101, 0x0ebe8101, - 0x0ec70101, 0x0f007e40, 0x0f3f1840, 0x0f4b01b5, - 0x0f4b81b6, 0x0f4c01b6, 0x0f4c81b6, 0x0f4d01b7, - 0x0f4d8180, 0x0f4f0130, 0x0f506040, 0x0f800800, - 0x0f840830, 0x0f880600, 0x0f8c0630, 0x0f900800, - 0x0f940830, 0x0f980800, 0x0f9c0830, 0x0fa00600, - 0x0fa40630, 0x0fa801b0, 0x0fa88100, 0x0fa901d3, - 0x0fa98100, 0x0faa01d3, 0x0faa8100, 0x0fab01d3, - 0x0fab8100, 0x0fac8130, 0x0fad8130, 0x0fae8130, - 0x0faf8130, 0x0fb00800, 0x0fb40830, 0x0fb80200, - 0x0fb90400, 0x0fbb0200, 0x0fbc0201, 0x0fbd0201, - 0x0fbe0201, 0x0fc008b7, 0x0fc40867, 0x0fc808b8, - 0x0fcc0868, 0x0fd008b8, 0x0fd40868, 0x0fd80200, - 0x0fd901b9, 0x0fd981b1, 0x0fda01b9, 0x0fdb01b1, - 0x0fdb81d7, 0x0fdc0230, 0x0fdd0230, 0x0fde0161, - 0x0fdf0173, 0x0fe101b9, 0x0fe181b2, 0x0fe201ba, - 0x0fe301b2, 0x0fe381d8, 0x0fe40430, 0x0fe60162, - 0x0fe80200, 0x0fe901d0, 0x0fe981d0, 0x0feb01b0, - 0x0feb81d0, 0x0fec0230, 0x0fed0230, 0x0ff00201, - 0x0ff101d3, 0x0ff181d3, 0x0ff201ba, 0x0ff28101, - 0x0ff301b0, 0x0ff381d3, 0x0ff40230, 0x0ff50230, - 0x0ff60131, 0x0ff901ba, 0x0ff981b2, 0x0ffa01bb, - 0x0ffb01b2, 0x0ffb81d9, 0x0ffc0230, 0x0ffd0230, - 0x0ffe0162, 0x109301a0, 0x109501a0, 0x109581a0, - 0x10990131, 0x10a70101, 0x10b01031, 0x10b81001, - 0x10c18240, 0x125b1a31, 0x12681a01, 0x16003031, - 0x16183001, 0x16300240, 0x16310130, 0x16318130, - 0x16320130, 0x16328100, 0x16330100, 0x16338640, - 0x16368130, 0x16370130, 0x16378130, 0x16380130, - 0x16390240, 0x163a8240, 0x163f0230, 0x16406440, - 0x16758440, 0x16790240, 0x16802600, 0x16938100, - 0x16968100, 0x53202e40, 0x53401c40, 0x53910e40, - 0x53993e40, 0x53bc8440, 0x53be8130, 0x53bf0a40, - 0x53c58240, 0x53c68130, 0x53c80440, 0x53ca0101, - 0x53cb1440, 0x53d50130, 0x53d58130, 0x53d60130, - 0x53d68130, 0x53d70130, 0x53d80130, 0x53d88130, - 0x53d90130, 0x53d98131, 0x53da1040, 0x53e20131, - 0x53e28130, 0x53e30130, 0x53e38440, 0x53e80240, - 0x53eb0440, 0x53fa8240, 0x55a98101, 0x55b85020, - 0x7d8001b2, 0x7d8081b2, 0x7d8101b2, 0x7d8181da, - 0x7d8201da, 0x7d8281b3, 0x7d8301b3, 0x7d8981bb, - 0x7d8a01bb, 0x7d8a81bb, 0x7d8b01bc, 0x7d8b81bb, - 0x7f909a31, 0x7fa09a01, 0x82002831, 0x82142801, - 0x82582431, 0x826c2401, 0x82b80b31, 0x82be0f31, - 0x82c60731, 0x82ca0231, 0x82cb8b01, 0x82d18f01, - 0x82d98701, 0x82dd8201, 0x86403331, 0x86603301, + 0x00cd0100, 0x00cd8101, 0x00ce0130, 0x00ce8130, + 0x00cf0100, 0x00cf8130, 0x00d00640, 0x00d30130, + 0x00d38240, 0x00d48130, 0x00d60240, 0x00d70130, + 0x00d78240, 0x00d88230, 0x00d98440, 0x00db8130, + 0x00dc0240, 0x00de0240, 0x00df8100, 0x00e20350, + 0x00e38350, 0x00e50350, 0x00e69040, 0x00ee8100, + 0x00ef1240, 0x00f801b4, 0x00f88350, 0x00fa0240, + 0x00fb0130, 0x00fb8130, 0x00fc2840, 0x01100130, + 0x01111240, 0x011d0131, 0x011d8240, 0x011e8130, + 0x011f0131, 0x011f8201, 0x01208240, 0x01218130, + 0x01220130, 0x01228130, 0x01230a40, 0x01280101, + 0x01288101, 0x01290101, 0x01298100, 0x012a0100, + 0x012b0200, 0x012c8100, 0x012d8100, 0x012e0101, + 0x01300100, 0x01308101, 0x01318100, 0x01320101, + 0x01328101, 0x01330101, 0x01340100, 0x01348100, + 0x01350101, 0x01358101, 0x01360101, 0x01378100, + 0x01388101, 0x01390100, 0x013a8100, 0x013e8101, + 0x01400100, 0x01410101, 0x01418100, 0x01438101, + 0x01440100, 0x01448100, 0x01450200, 0x01460100, + 0x01490100, 0x014e8101, 0x014f0101, 0x01a28173, + 0x01b80440, 0x01bb0240, 0x01bd8300, 0x01bf8130, + 0x01c30130, 0x01c40330, 0x01c60130, 0x01c70230, + 0x01c801d0, 0x01c89130, 0x01d18930, 0x01d60100, + 0x01d68300, 0x01d801d3, 0x01d89100, 0x01e10173, + 0x01e18900, 0x01e60100, 0x01e68200, 0x01e78130, + 0x01e80173, 0x01e88173, 0x01ea8173, 0x01eb0173, + 0x01eb8100, 0x01ec1840, 0x01f80173, 0x01f88173, + 0x01f90100, 0x01f98100, 0x01fa01a0, 0x01fa8173, + 0x01fb8240, 0x01fc8130, 0x01fd0240, 0x01fe8330, + 0x02001030, 0x02082030, 0x02182000, 0x02281000, + 0x02302240, 0x02453640, 0x02600130, 0x02608e40, + 0x02678100, 0x02686040, 0x0298a630, 0x02b0a600, + 0x02c381b5, 0x08502631, 0x08638131, 0x08668131, + 0x08682b00, 0x087e8300, 0x09d05011, 0x09f80610, + 0x09fc0620, 0x0e400174, 0x0e408174, 0x0e410174, + 0x0e418174, 0x0e420174, 0x0e428174, 0x0e430174, + 0x0e438180, 0x0e440180, 0x0e448240, 0x0e482b30, + 0x0e5e8330, 0x0ebc8101, 0x0ebe8101, 0x0ec70101, + 0x0f007e40, 0x0f3f1840, 0x0f4b01b5, 0x0f4b81b6, + 0x0f4c01b6, 0x0f4c81b6, 0x0f4d01b7, 0x0f4d8180, + 0x0f4f0130, 0x0f506040, 0x0f800800, 0x0f840830, + 0x0f880600, 0x0f8c0630, 0x0f900800, 0x0f940830, + 0x0f980800, 0x0f9c0830, 0x0fa00600, 0x0fa40630, + 0x0fa801b0, 0x0fa88100, 0x0fa901d3, 0x0fa98100, + 0x0faa01d3, 0x0faa8100, 0x0fab01d3, 0x0fab8100, + 0x0fac8130, 0x0fad8130, 0x0fae8130, 0x0faf8130, + 0x0fb00800, 0x0fb40830, 0x0fb80200, 0x0fb90400, + 0x0fbb0201, 0x0fbc0201, 0x0fbd0201, 0x0fbe0201, + 0x0fc008b7, 0x0fc40867, 0x0fc808b8, 0x0fcc0868, + 0x0fd008b8, 0x0fd40868, 0x0fd80200, 0x0fd901b9, + 0x0fd981b1, 0x0fda01b9, 0x0fdb01b1, 0x0fdb81d7, + 0x0fdc0230, 0x0fdd0230, 0x0fde0161, 0x0fdf0173, + 0x0fe101b9, 0x0fe181b2, 0x0fe201ba, 0x0fe301b2, + 0x0fe381d8, 0x0fe40430, 0x0fe60162, 0x0fe80201, + 0x0fe901d0, 0x0fe981d0, 0x0feb01b0, 0x0feb81d0, + 0x0fec0230, 0x0fed0230, 0x0ff00201, 0x0ff101d3, + 0x0ff181d3, 0x0ff201ba, 0x0ff28101, 0x0ff301b0, + 0x0ff381d3, 0x0ff40231, 0x0ff50230, 0x0ff60131, + 0x0ff901ba, 0x0ff981b2, 0x0ffa01bb, 0x0ffb01b2, + 0x0ffb81d9, 0x0ffc0230, 0x0ffd0230, 0x0ffe0162, + 0x109301a0, 0x109501a0, 0x109581a0, 0x10990131, + 0x10a70101, 0x10b01031, 0x10b81001, 0x10c18240, + 0x125b1a31, 0x12681a01, 0x16003031, 0x16183001, + 0x16300240, 0x16310130, 0x16318130, 0x16320130, + 0x16328100, 0x16330100, 0x16338640, 0x16368130, + 0x16370130, 0x16378130, 0x16380130, 0x16390240, + 0x163a8240, 0x163f0230, 0x16406440, 0x16758440, + 0x16790240, 0x16802600, 0x16938100, 0x16968100, + 0x53202e40, 0x53401c40, 0x53910e40, 0x53993e40, + 0x53bc8440, 0x53be8130, 0x53bf0a40, 0x53c58240, + 0x53c68130, 0x53c80440, 0x53ca0101, 0x53cb1440, + 0x53d50130, 0x53d58130, 0x53d60130, 0x53d68130, + 0x53d70130, 0x53d80130, 0x53d88130, 0x53d90130, + 0x53d98131, 0x53da1040, 0x53e20131, 0x53e28130, + 0x53e30130, 0x53e38440, 0x53e58130, 0x53e60240, + 0x53e80240, 0x53eb0640, 0x53ee0130, 0x53fa8240, + 0x55a98101, 0x55b85020, 0x7d8001b2, 0x7d8081b2, + 0x7d8101b2, 0x7d8181da, 0x7d8201da, 0x7d8281b3, + 0x7d8301b3, 0x7d8981bb, 0x7d8a01bb, 0x7d8a81bb, + 0x7d8b01bc, 0x7d8b81bb, 0x7f909a31, 0x7fa09a01, + 0x82002831, 0x82142801, 0x82582431, 0x826c2401, + 0x82b80b31, 0x82be0f31, 0x82c60731, 0x82ca0231, + 0x82cb8b01, 0x82d18f01, 0x82d98701, 0x82dd8201, + 0x86403331, 0x86603301, 0x86a81631, 0x86b81601, 0x8c502031, 0x8c602001, 0xb7202031, 0xb7302001, 0xf4802231, 0xf4912201, }; -static const uint8_t case_conv_table2[370] = { +static const uint8_t case_conv_table2[378] = { 0x01, 0x00, 0x9c, 0x06, 0x07, 0x4d, 0x03, 0x04, 0x10, 0x00, 0x8f, 0x0b, 0x00, 0x00, 0x11, 0x00, - 0x08, 0x00, 0x53, 0x4a, 0x51, 0x00, 0x52, 0x00, - 0x53, 0x00, 0x3a, 0x54, 0x55, 0x00, 0x57, 0x59, - 0x3f, 0x5d, 0x5c, 0x00, 0x46, 0x61, 0x63, 0x42, - 0x64, 0x00, 0x66, 0x00, 0x68, 0x00, 0x6a, 0x00, - 0x6c, 0x00, 0x6e, 0x00, 0x00, 0x40, 0x00, 0x00, - 0x00, 0x00, 0x1a, 0x00, 0x93, 0x00, 0x00, 0x20, - 0x35, 0x00, 0x27, 0x00, 0x21, 0x00, 0x24, 0x22, - 0x2a, 0x00, 0x13, 0x6b, 0x6d, 0x00, 0x26, 0x24, - 0x27, 0x14, 0x16, 0x18, 0x1b, 0x1c, 0x3e, 0x1e, - 0x3f, 0x1f, 0x39, 0x3d, 0x22, 0x21, 0x41, 0x1e, - 0x40, 0x25, 0x25, 0x26, 0x28, 0x20, 0x2a, 0x48, - 0x2c, 0x43, 0x2e, 0x4b, 0x30, 0x4c, 0x32, 0x44, - 0x42, 0x99, 0x00, 0x00, 0x95, 0x8f, 0x7d, 0x7e, - 0x83, 0x84, 0x12, 0x80, 0x82, 0x76, 0x77, 0x12, - 0x7b, 0xa3, 0x7c, 0x78, 0x79, 0x8a, 0x92, 0x98, - 0xa6, 0xa0, 0x85, 0x00, 0x9a, 0xa1, 0x93, 0x75, - 0x33, 0x95, 0x00, 0x8e, 0x00, 0x74, 0x99, 0x98, - 0x97, 0x96, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, - 0xa1, 0xa0, 0x15, 0x2e, 0x2f, 0x30, 0xb4, 0xb5, - 0x4f, 0xaa, 0xa9, 0x12, 0x14, 0x1e, 0x21, 0x22, - 0x22, 0x2a, 0x34, 0x35, 0xa6, 0xa7, 0x36, 0x1f, - 0x49, 0x00, 0x00, 0x97, 0x01, 0x5a, 0xda, 0x1d, - 0x36, 0x05, 0x00, 0xc4, 0xc3, 0xc6, 0xc5, 0xc8, - 0xc7, 0xca, 0xc9, 0xcc, 0xcb, 0xc4, 0xd5, 0x45, - 0xd6, 0x42, 0xd7, 0x46, 0xd8, 0xce, 0xd0, 0xd2, - 0xd4, 0xda, 0xd9, 0xee, 0xf6, 0xfe, 0x0e, 0x07, - 0x0f, 0x80, 0x9f, 0x00, 0x21, 0x80, 0xa3, 0xed, - 0x00, 0xc0, 0x40, 0xc6, 0x60, 0xe7, 0xdb, 0xe6, - 0x99, 0xc0, 0x00, 0x00, 0x06, 0x60, 0xdc, 0x29, - 0xfd, 0x15, 0x12, 0x06, 0x16, 0xf8, 0xdd, 0x06, - 0x15, 0x12, 0x84, 0x08, 0xc6, 0x16, 0xff, 0xdf, - 0x03, 0xc0, 0x40, 0x00, 0x46, 0x60, 0xde, 0xe0, - 0x6d, 0x37, 0x38, 0x39, 0x15, 0x14, 0x17, 0x16, - 0x00, 0x1a, 0x19, 0x1c, 0x1b, 0x00, 0x5f, 0xb7, - 0x65, 0x44, 0x47, 0x00, 0x4f, 0x62, 0x4e, 0x50, - 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xa3, 0xa4, - 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb6, 0x00, - 0x00, 0x5a, 0x00, 0x47, 0x00, 0x5b, 0x56, 0x58, - 0x60, 0x5e, 0x70, 0x69, 0x6f, 0x4e, 0x00, 0x3b, - 0x67, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x45, 0xa8, - 0x8a, 0x8b, 0x8c, 0xab, 0xac, 0x58, 0x58, 0xaf, - 0x94, 0xb0, 0x6f, 0xb2, 0x5d, 0x5c, 0x5f, 0x5e, - 0x61, 0x60, 0x66, 0x67, 0x68, 0x69, 0x62, 0x63, - 0x64, 0x65, 0x6b, 0x6a, 0x6d, 0x6c, 0x6f, 0x6e, - 0x71, 0x70, + 0x08, 0x00, 0x53, 0x4b, 0x52, 0x00, 0x53, 0x00, + 0x54, 0x00, 0x3b, 0x55, 0x56, 0x00, 0x58, 0x5a, + 0x40, 0x5f, 0x5e, 0x00, 0x47, 0x52, 0x63, 0x65, + 0x43, 0x66, 0x00, 0x68, 0x00, 0x6a, 0x00, 0x6c, + 0x00, 0x6e, 0x00, 0x70, 0x00, 0x00, 0x41, 0x00, + 0x00, 0x00, 0x00, 0x1a, 0x00, 0x93, 0x00, 0x00, + 0x20, 0x36, 0x00, 0x28, 0x00, 0x24, 0x00, 0x24, + 0x25, 0x2d, 0x00, 0x13, 0x6d, 0x6f, 0x00, 0x29, + 0x27, 0x2a, 0x14, 0x16, 0x18, 0x1b, 0x1c, 0x41, + 0x1e, 0x42, 0x1f, 0x4e, 0x3c, 0x40, 0x22, 0x21, + 0x44, 0x21, 0x43, 0x26, 0x28, 0x27, 0x29, 0x23, + 0x2b, 0x4b, 0x2d, 0x46, 0x2f, 0x4c, 0x31, 0x4d, + 0x33, 0x47, 0x45, 0x99, 0x00, 0x00, 0x97, 0x91, + 0x7f, 0x80, 0x85, 0x86, 0x12, 0x82, 0x84, 0x78, + 0x79, 0x12, 0x7d, 0xa3, 0x7e, 0x7a, 0x7b, 0x8c, + 0x92, 0x98, 0xa6, 0xa0, 0x87, 0x00, 0x9a, 0xa1, + 0x95, 0x77, 0x33, 0x95, 0x00, 0x90, 0x00, 0x76, + 0x9b, 0x9a, 0x99, 0x98, 0x00, 0x00, 0xa0, 0x00, + 0x9e, 0x00, 0xa3, 0xa2, 0x15, 0x31, 0x32, 0x33, + 0xb7, 0xb8, 0x55, 0xac, 0xab, 0x12, 0x14, 0x1e, + 0x21, 0x22, 0x22, 0x2a, 0x34, 0x35, 0x00, 0xa8, + 0xa9, 0x39, 0x22, 0x4c, 0x00, 0x00, 0x97, 0x01, + 0x5a, 0xda, 0x1d, 0x36, 0x05, 0x00, 0xc7, 0xc6, + 0xc9, 0xc8, 0xcb, 0xca, 0xcd, 0xcc, 0xcf, 0xce, + 0xc4, 0xd8, 0x45, 0xd9, 0x42, 0xda, 0x46, 0xdb, + 0xd1, 0xd3, 0xd5, 0xd7, 0xdd, 0xdc, 0xf1, 0xf9, + 0x01, 0x11, 0x0a, 0x12, 0x80, 0x9f, 0x00, 0x21, + 0x80, 0xa3, 0xf0, 0x00, 0xc0, 0x40, 0xc6, 0x60, + 0xea, 0xde, 0xe6, 0x99, 0xc0, 0x00, 0x00, 0x06, + 0x60, 0xdf, 0x29, 0x00, 0x15, 0x12, 0x06, 0x16, + 0xfb, 0xe0, 0x09, 0x15, 0x12, 0x84, 0x0b, 0xc6, + 0x16, 0x02, 0xe2, 0x06, 0xc0, 0x40, 0x00, 0x46, + 0x60, 0xe1, 0xe3, 0x6d, 0x37, 0x38, 0x39, 0x18, + 0x17, 0x1a, 0x19, 0x00, 0x1d, 0x1c, 0x1f, 0x1e, + 0x00, 0x61, 0xba, 0x67, 0x45, 0x48, 0x00, 0x50, + 0x64, 0x4f, 0x51, 0x00, 0x00, 0x49, 0x00, 0x00, + 0x00, 0xa5, 0xa6, 0xa7, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xb9, 0x00, 0x00, 0x5c, 0x00, 0x4a, 0x00, + 0x5d, 0x57, 0x59, 0x62, 0x60, 0x72, 0x6b, 0x71, + 0x54, 0x00, 0x3e, 0x69, 0xbb, 0x00, 0x5b, 0x00, + 0x00, 0x00, 0x25, 0x00, 0x48, 0xaa, 0x8a, 0x8b, + 0x8c, 0xab, 0xac, 0x58, 0x58, 0xaf, 0x94, 0xb0, + 0x6f, 0xb2, 0x63, 0x62, 0x65, 0x64, 0x67, 0x66, + 0x6c, 0x6d, 0x6e, 0x6f, 0x68, 0x69, 0x6a, 0x6b, + 0x71, 0x70, 0x73, 0x72, 0x75, 0x74, 0x77, 0x76, + 0x79, 0x78, }; static const uint16_t case_conv_ext[58] = { @@ -160,45 +163,41 @@ static const uint16_t case_conv_ext[58] = { 0x006b, 0x00e5, }; -static const uint8_t unicode_prop_Cased1_table[196] = { +static const uint8_t unicode_prop_Cased1_table[193] = { 0x40, 0xa9, 0x80, 0x8e, 0x80, 0xfc, 0x80, 0xd3, - 0x80, 0x8c, 0x80, 0x8d, 0x81, 0x8d, 0x02, 0x80, - 0xe1, 0x80, 0x91, 0x85, 0x9a, 0x01, 0x00, 0x01, - 0x11, 0x00, 0x01, 0x04, 0x08, 0x01, 0x08, 0x30, - 0x08, 0x01, 0x15, 0x20, 0x00, 0x39, 0x99, 0x31, - 0x9d, 0x84, 0x40, 0x94, 0x80, 0xd6, 0x82, 0xa6, - 0x80, 0x41, 0x62, 0x80, 0xa6, 0x80, 0x4b, 0x72, - 0x80, 0x4c, 0x02, 0xf8, 0x02, 0x80, 0x8f, 0x80, - 0xb0, 0x40, 0xdb, 0x08, 0x80, 0x41, 0xd0, 0x80, - 0x8c, 0x80, 0x8f, 0x8c, 0xe4, 0x03, 0x01, 0x89, - 0x00, 0x14, 0x28, 0x10, 0x11, 0x02, 0x01, 0x18, - 0x0b, 0x24, 0x4b, 0x26, 0x01, 0x01, 0x86, 0xe5, - 0x80, 0x60, 0x79, 0xb6, 0x81, 0x40, 0x91, 0x81, - 0xbd, 0x88, 0x94, 0x05, 0x80, 0x98, 0x80, 0xa2, - 0x00, 0x80, 0x9b, 0x12, 0x82, 0x43, 0x34, 0xa2, - 0x06, 0x80, 0x8d, 0x60, 0x5c, 0x15, 0x01, 0x10, - 0xa9, 0x80, 0x88, 0x60, 0xcc, 0x44, 0xd4, 0x80, - 0xc6, 0x01, 0x08, 0x09, 0x0b, 0x80, 0x8b, 0x00, - 0x06, 0x80, 0xc0, 0x03, 0x0f, 0x06, 0x80, 0x9b, - 0x03, 0x04, 0x00, 0x16, 0x80, 0x41, 0x53, 0x81, - 0x98, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, - 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, - 0x9e, 0x80, 0x98, 0x07, 0x47, 0x33, 0x89, 0x80, - 0x93, 0x2d, 0x41, 0x04, 0xbd, 0x50, 0xc1, 0x99, - 0x85, 0x99, 0x85, 0x99, + 0x80, 0x9b, 0x81, 0x8d, 0x02, 0x80, 0xe1, 0x80, + 0x91, 0x85, 0x9a, 0x01, 0x00, 0x01, 0x11, 0x03, + 0x04, 0x08, 0x01, 0x08, 0x30, 0x08, 0x01, 0x15, + 0x20, 0x00, 0x39, 0x99, 0x31, 0x9d, 0x84, 0x40, + 0x94, 0x80, 0xd6, 0x82, 0xa6, 0x80, 0x41, 0x62, + 0x80, 0xa6, 0x80, 0x4b, 0x72, 0x80, 0x4c, 0x02, + 0xf8, 0x02, 0x80, 0x8f, 0x80, 0xb0, 0x40, 0xdb, + 0x08, 0x80, 0x41, 0xd0, 0x80, 0x8c, 0x80, 0x8f, + 0x8c, 0xe4, 0x03, 0x01, 0x89, 0x00, 0x14, 0x28, + 0x10, 0x11, 0x02, 0x01, 0x18, 0x0b, 0x24, 0x4b, + 0x26, 0x01, 0x01, 0x86, 0xe5, 0x80, 0x60, 0x79, + 0xb6, 0x81, 0x40, 0x91, 0x81, 0xbd, 0x88, 0x94, + 0x05, 0x80, 0x98, 0x80, 0xa2, 0x00, 0x80, 0x9b, + 0x12, 0x82, 0x43, 0x34, 0xa2, 0x06, 0x80, 0x8d, + 0x60, 0x5c, 0x15, 0x01, 0x10, 0xa9, 0x80, 0x88, + 0x60, 0xcc, 0x44, 0xd4, 0x80, 0xc6, 0x01, 0x08, + 0x09, 0x0b, 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, + 0x03, 0x0f, 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, + 0x16, 0x80, 0x41, 0x53, 0x81, 0x98, 0x80, 0x98, + 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, + 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, + 0x07, 0x47, 0x33, 0x89, 0x80, 0x93, 0x2d, 0x41, + 0x04, 0xbd, 0x50, 0xc1, 0x99, 0x85, 0x99, 0x85, + 0x99, }; -static const uint8_t unicode_prop_Cased1_index[21] = { - 0xb9, 0x02, 0xe0, // 002B9 at 39 - 0xc0, 0x1d, 0x20, // 01DC0 at 65 - 0xe5, 0x2c, 0x20, // 02CE5 at 97 - 0xb1, 0x07, 0x21, // 107B1 at 129 - 0xc1, 0xd6, 0x21, // 1D6C1 at 161 - 0x4a, 0xf1, 0x01, // 1F14A at 192 - 0x8a, 0xf1, 0x01, // 1F18A at 224 (upper bound) +static const uint8_t unicode_prop_Cased1_index[18] = { + 0xb9, 0x02, 0x80, 0xa0, 0x1e, 0x40, 0x9e, 0xa6, + 0x40, 0xbb, 0x07, 0x01, 0xdb, 0xd6, 0x01, 0x8a, + 0xf1, 0x01, }; -static const uint8_t unicode_prop_Case_Ignorable_table[737] = { +static const uint8_t unicode_prop_Case_Ignorable_table[764] = { 0xa6, 0x05, 0x80, 0x8a, 0x80, 0xa2, 0x00, 0x80, 0xc6, 0x03, 0x00, 0x03, 0x01, 0x81, 0x41, 0xf6, 0x40, 0xbf, 0x19, 0x18, 0x88, 0x08, 0x80, 0x40, @@ -207,7 +206,7 @@ static const uint8_t unicode_prop_Case_Ignorable_table[737] = { 0x89, 0x8a, 0x00, 0xa2, 0x80, 0x89, 0x94, 0x8f, 0x80, 0xe4, 0x38, 0x89, 0x03, 0xa0, 0x00, 0x80, 0x9d, 0x9a, 0xda, 0x8a, 0xb9, 0x8a, 0x18, 0x08, - 0x97, 0x97, 0xaa, 0x82, 0xab, 0x06, 0x0d, 0x87, + 0x97, 0x97, 0xaa, 0x82, 0xab, 0x06, 0x0c, 0x88, 0xa8, 0xb9, 0xb6, 0x00, 0x03, 0x3b, 0x02, 0x86, 0x89, 0x81, 0x8c, 0x80, 0x8e, 0x80, 0xb9, 0x03, 0x1f, 0x80, 0x93, 0x81, 0x99, 0x01, 0x81, 0xb8, @@ -261,26 +260,29 @@ static const uint8_t unicode_prop_Case_Ignorable_table[737] = { 0x80, 0x40, 0x94, 0x84, 0x44, 0x04, 0x28, 0xa9, 0x80, 0x88, 0x42, 0x45, 0x10, 0x0c, 0x83, 0xa7, 0x13, 0x80, 0x40, 0xa4, 0x81, 0x42, 0x3c, 0x83, - 0x41, 0x82, 0x81, 0xcf, 0x82, 0xc5, 0x8a, 0xb0, - 0x83, 0xfa, 0x80, 0xb5, 0x8e, 0xa8, 0x01, 0x81, - 0x89, 0x82, 0xb0, 0x19, 0x09, 0x03, 0x80, 0x89, - 0x80, 0xb1, 0x82, 0xa3, 0x20, 0x87, 0xbd, 0x80, - 0x8b, 0x81, 0xb3, 0x88, 0x89, 0x19, 0x80, 0xde, - 0x11, 0x00, 0x0d, 0x01, 0x80, 0x40, 0x9c, 0x02, - 0x87, 0x94, 0x81, 0xb8, 0x0a, 0x80, 0xa4, 0x32, - 0x84, 0x40, 0xc2, 0x39, 0x10, 0x80, 0x96, 0x80, - 0xd3, 0x28, 0x03, 0x08, 0x81, 0x40, 0xed, 0x1d, - 0x08, 0x81, 0x9a, 0x81, 0xd4, 0x39, 0x00, 0x81, - 0xe9, 0x00, 0x01, 0x28, 0x80, 0xe4, 0x11, 0x18, - 0x84, 0x41, 0x02, 0x88, 0x01, 0x40, 0xff, 0x08, - 0x03, 0x80, 0x40, 0x8f, 0x19, 0x0b, 0x80, 0x9f, - 0x89, 0xa7, 0x29, 0x1f, 0x80, 0x88, 0x29, 0x82, - 0xad, 0x8c, 0x01, 0x41, 0x95, 0x30, 0x28, 0x80, - 0xd1, 0x95, 0x0e, 0x01, 0x01, 0xf9, 0x2a, 0x00, - 0x08, 0x30, 0x80, 0xc7, 0x0a, 0x00, 0x80, 0x41, - 0x5a, 0x81, 0x8a, 0x81, 0xb3, 0x24, 0x00, 0x80, - 0x54, 0xec, 0x90, 0x85, 0x8e, 0x60, 0x36, 0x99, - 0x84, 0xba, 0x86, 0x88, 0x83, 0x44, 0x0a, 0x80, + 0xa5, 0x80, 0x99, 0x20, 0x80, 0x41, 0x3a, 0x81, + 0xce, 0x83, 0xc5, 0x8a, 0xb0, 0x83, 0xfa, 0x80, + 0xb5, 0x8e, 0xa8, 0x01, 0x81, 0x89, 0x82, 0xb0, + 0x19, 0x09, 0x03, 0x80, 0x89, 0x80, 0xb1, 0x82, + 0xa3, 0x20, 0x87, 0xbd, 0x80, 0x8b, 0x81, 0xb3, + 0x88, 0x89, 0x19, 0x80, 0xde, 0x11, 0x00, 0x0d, + 0x01, 0x80, 0x40, 0x9c, 0x02, 0x87, 0x94, 0x81, + 0xb8, 0x0a, 0x80, 0xa4, 0x32, 0x84, 0xc5, 0x85, + 0x8c, 0x00, 0x00, 0x80, 0x8d, 0x81, 0xd4, 0x39, + 0x10, 0x80, 0x96, 0x80, 0xd3, 0x28, 0x03, 0x08, + 0x81, 0x40, 0xed, 0x1d, 0x08, 0x81, 0x9a, 0x81, + 0xd4, 0x39, 0x00, 0x81, 0xe9, 0x00, 0x01, 0x28, + 0x80, 0xe4, 0x00, 0x01, 0x18, 0x84, 0x41, 0x02, + 0x88, 0x01, 0x40, 0xff, 0x08, 0x03, 0x80, 0x40, + 0x8f, 0x19, 0x0b, 0x80, 0x9f, 0x89, 0xa7, 0x29, + 0x1f, 0x80, 0x88, 0x29, 0x82, 0xad, 0x8c, 0x01, + 0x41, 0x95, 0x30, 0x28, 0x80, 0xd1, 0x95, 0x0e, + 0x01, 0x01, 0xf9, 0x2a, 0x00, 0x08, 0x30, 0x80, + 0xc7, 0x0a, 0x00, 0x80, 0x41, 0x5a, 0x81, 0x8a, + 0x81, 0xb3, 0x24, 0x00, 0x80, 0x96, 0x80, 0x54, + 0xd4, 0x90, 0x85, 0x8e, 0x60, 0x2c, 0xc7, 0x8b, + 0x12, 0x49, 0xbf, 0x84, 0xba, 0x86, 0x88, 0x83, + 0x41, 0xfb, 0x82, 0xa7, 0x81, 0x41, 0xe1, 0x80, 0xbe, 0x90, 0xbf, 0x08, 0x81, 0x60, 0x40, 0x0a, 0x18, 0x30, 0x81, 0x4c, 0x9d, 0x08, 0x83, 0x52, 0x5b, 0xad, 0x81, 0x96, 0x42, 0x1f, 0x82, 0x88, @@ -289,38 +291,24 @@ static const uint8_t unicode_prop_Case_Ignorable_table[737] = { 0x20, 0x8e, 0x45, 0x4f, 0x30, 0x90, 0x0e, 0x01, 0x04, 0x84, 0xbd, 0xa0, 0x80, 0x40, 0x9f, 0x8d, 0x41, 0x6f, 0x80, 0xbc, 0x83, 0x41, 0xfa, 0x84, - 0x43, 0xdf, 0x86, 0xec, 0x87, 0x4a, 0xae, 0x84, - 0x6c, 0x0c, 0x00, 0x80, 0x9d, 0xdf, 0xff, 0x40, - 0xef, + 0x40, 0xfd, 0x81, 0x42, 0xdf, 0x86, 0xec, 0x87, + 0x4a, 0xae, 0x84, 0x6c, 0x0c, 0x00, 0x80, 0x9d, + 0xdf, 0xff, 0x40, 0xef, }; -static const uint8_t unicode_prop_Case_Ignorable_index[69] = { - 0xbe, 0x05, 0x00, // 005BE at 32 - 0xfe, 0x07, 0x00, // 007FE at 64 - 0x52, 0x0a, 0xa0, // 00A52 at 101 - 0xc1, 0x0b, 0x00, // 00BC1 at 128 - 0x82, 0x0d, 0x00, // 00D82 at 160 - 0x3f, 0x10, 0x80, // 0103F at 196 - 0xd4, 0x17, 0x40, // 017D4 at 226 - 0xcf, 0x1a, 0x20, // 01ACF at 257 - 0xf5, 0x1c, 0x00, // 01CF5 at 288 - 0x80, 0x20, 0x00, // 02080 at 320 - 0x16, 0xa0, 0x00, // 0A016 at 352 - 0xc6, 0xa8, 0x00, // 0A8C6 at 384 - 0xc2, 0xaa, 0x60, // 0AAC2 at 419 - 0x56, 0xfe, 0x20, // 0FE56 at 449 - 0xb1, 0x07, 0x01, // 107B1 at 480 - 0x75, 0x10, 0x01, // 11075 at 512 - 0xeb, 0x12, 0x21, // 112EB at 545 - 0x41, 0x16, 0x01, // 11641 at 576 - 0x5c, 0x1a, 0x01, // 11A5C at 608 - 0x43, 0x1f, 0x01, // 11F43 at 640 - 0x2e, 0xcf, 0x41, // 1CF2E at 674 - 0x25, 0xe0, 0x01, // 1E025 at 704 - 0xf0, 0x01, 0x0e, // E01F0 at 736 (upper bound) +static const uint8_t unicode_prop_Case_Ignorable_index[72] = { + 0xbe, 0x05, 0x00, 0xfe, 0x07, 0x00, 0x52, 0x0a, + 0xa0, 0xc1, 0x0b, 0x00, 0x82, 0x0d, 0x00, 0x3f, + 0x10, 0x80, 0xd4, 0x17, 0x40, 0xcf, 0x1a, 0x20, + 0xf5, 0x1c, 0x00, 0x80, 0x20, 0x00, 0x16, 0xa0, + 0x00, 0xc6, 0xa8, 0x00, 0xc2, 0xaa, 0x60, 0x56, + 0xfe, 0x20, 0xb1, 0x07, 0x01, 0x02, 0x10, 0x01, + 0x42, 0x12, 0x41, 0xc4, 0x14, 0x21, 0xe1, 0x19, + 0x81, 0x48, 0x1d, 0x01, 0x44, 0x6b, 0x01, 0x83, + 0xd1, 0x21, 0x3e, 0xe1, 0x01, 0xf0, 0x01, 0x0e, }; -static const uint8_t unicode_prop_ID_Start_table[1100] = { +static const uint8_t unicode_prop_ID_Start_table[1133] = { 0xc0, 0x99, 0x85, 0x99, 0xae, 0x80, 0x89, 0x03, 0x04, 0x96, 0x80, 0x9e, 0x80, 0x41, 0xc9, 0x83, 0x8b, 0x8d, 0x26, 0x00, 0x80, 0x40, 0x80, 0x20, @@ -364,7 +352,7 @@ static const uint8_t unicode_prop_ID_Start_table[1100] = { 0x83, 0x99, 0xb5, 0x96, 0x88, 0xb4, 0xd1, 0x80, 0xdc, 0xae, 0x90, 0x87, 0xb5, 0x9d, 0x8c, 0x81, 0x89, 0xab, 0x99, 0xa3, 0xa8, 0x82, 0x89, 0xa3, - 0x81, 0x88, 0x86, 0xaa, 0x0a, 0xa8, 0x18, 0x28, + 0x81, 0x8a, 0x84, 0xaa, 0x0a, 0xa8, 0x18, 0x28, 0x0a, 0x04, 0x40, 0xbf, 0xbf, 0x41, 0x15, 0x0d, 0x81, 0xa5, 0x0d, 0x0f, 0x00, 0x00, 0x00, 0x80, 0x9e, 0x81, 0xb4, 0x06, 0x00, 0x12, 0x06, 0x13, @@ -380,8 +368,8 @@ static const uint8_t unicode_prop_ID_Start_table[1100] = { 0x41, 0xff, 0x59, 0xbf, 0xbf, 0x60, 0x56, 0x8c, 0xc2, 0xad, 0x81, 0x41, 0x0c, 0x82, 0x8f, 0x89, 0x81, 0x93, 0xae, 0x8f, 0x9e, 0x81, 0xcf, 0xa6, - 0x88, 0x81, 0xe6, 0x81, 0xbf, 0x21, 0x00, 0x04, - 0x97, 0x8f, 0x02, 0x03, 0x80, 0x96, 0x9c, 0xb3, + 0x88, 0x81, 0xe6, 0x81, 0xc2, 0x09, 0x00, 0x07, + 0x94, 0x8f, 0x02, 0x03, 0x80, 0x96, 0x9c, 0xb3, 0x8d, 0xb1, 0xbd, 0x2a, 0x00, 0x81, 0x8a, 0x9b, 0x89, 0x96, 0x98, 0x9c, 0x86, 0xae, 0x9b, 0x80, 0x8f, 0x20, 0x89, 0x89, 0x20, 0xa8, 0x96, 0x10, @@ -401,112 +389,95 @@ static const uint8_t unicode_prop_ID_Start_table[1100] = { 0xa5, 0x89, 0x9d, 0x81, 0xa3, 0x1f, 0x04, 0xa9, 0x40, 0x9d, 0x91, 0xa3, 0x83, 0xa3, 0x83, 0xa7, 0x87, 0xb3, 0x8b, 0x8a, 0x80, 0x8e, 0x06, 0x01, - 0x80, 0x8a, 0x80, 0x8e, 0x06, 0x01, 0xc2, 0x41, - 0x36, 0x88, 0x95, 0x89, 0x87, 0x97, 0x28, 0xa9, - 0x80, 0x88, 0xc4, 0x29, 0x00, 0xab, 0x01, 0x10, - 0x81, 0x96, 0x89, 0x96, 0x88, 0x9e, 0xc0, 0x92, - 0x01, 0x89, 0x95, 0x89, 0x99, 0xc5, 0xb7, 0x29, - 0xbf, 0x80, 0x8e, 0x18, 0x10, 0x9c, 0xa9, 0x9c, - 0x82, 0x9c, 0xa2, 0x38, 0x9b, 0x9a, 0xb5, 0x89, - 0x95, 0x89, 0x92, 0x8c, 0x91, 0xed, 0xc8, 0xb6, - 0xb2, 0x8c, 0xb2, 0x8c, 0xa3, 0x41, 0x5b, 0xa9, - 0x29, 0xcd, 0x9c, 0x89, 0x07, 0x95, 0xa9, 0x91, + 0x80, 0x8a, 0x80, 0x8e, 0x06, 0x01, 0x82, 0xb3, + 0x8b, 0x41, 0x36, 0x88, 0x95, 0x89, 0x87, 0x97, + 0x28, 0xa9, 0x80, 0x88, 0xc4, 0x29, 0x00, 0xab, + 0x01, 0x10, 0x81, 0x96, 0x89, 0x96, 0x88, 0x9e, + 0xc0, 0x92, 0x01, 0x89, 0x95, 0x89, 0x99, 0xc5, + 0xb7, 0x29, 0xbf, 0x80, 0x8e, 0x18, 0x10, 0x9c, + 0xa9, 0x9c, 0x82, 0x9c, 0xa2, 0x38, 0x9b, 0x9a, + 0xb5, 0x89, 0x95, 0x89, 0x92, 0x8c, 0x91, 0xed, + 0xc8, 0xb6, 0xb2, 0x8c, 0xb2, 0x8c, 0xa3, 0xa5, + 0x9b, 0x88, 0x96, 0x40, 0xf9, 0xa9, 0x29, 0x8f, + 0x82, 0xba, 0x9c, 0x89, 0x07, 0x95, 0xa9, 0x91, 0xad, 0x94, 0x9a, 0x96, 0x8b, 0xb4, 0xb8, 0x09, 0x80, 0x8c, 0xac, 0x9f, 0x98, 0x99, 0xa3, 0x9c, 0x01, 0x07, 0xa2, 0x10, 0x8b, 0xaf, 0x8d, 0x83, 0x94, 0x00, 0x80, 0xa2, 0x91, 0x80, 0x98, 0x92, 0x81, 0xbe, 0x30, 0x00, 0x18, 0x8e, 0x80, 0x89, 0x86, 0xae, 0xa5, 0x39, 0x09, 0x95, 0x06, 0x01, - 0x04, 0x10, 0x91, 0x80, 0x8b, 0x84, 0x40, 0x9d, - 0xb4, 0x91, 0x83, 0x93, 0x82, 0x9d, 0xaf, 0x93, - 0x08, 0x80, 0x40, 0xb7, 0xae, 0xa8, 0x83, 0xa3, - 0xaf, 0x93, 0x80, 0xba, 0xaa, 0x8c, 0x80, 0xc6, - 0x9a, 0xa4, 0x86, 0x40, 0xb8, 0xab, 0xf3, 0xbf, - 0x9e, 0x39, 0x01, 0x38, 0x08, 0x97, 0x8e, 0x00, - 0x80, 0xdd, 0x39, 0xa6, 0x8f, 0x00, 0x80, 0x9b, - 0x80, 0x89, 0xa7, 0x30, 0x94, 0x80, 0x8a, 0xad, - 0x92, 0x80, 0x91, 0xc8, 0x41, 0x06, 0x88, 0x80, - 0xa4, 0x90, 0x80, 0xb0, 0x9d, 0xef, 0x30, 0x08, - 0xa5, 0x94, 0x80, 0x98, 0x28, 0x08, 0x9f, 0x8d, - 0x80, 0x41, 0x46, 0x92, 0x8e, 0x00, 0x8c, 0x80, - 0xa1, 0xfb, 0x80, 0xce, 0x43, 0x99, 0xe5, 0xee, - 0x90, 0x40, 0xc3, 0x4a, 0x4b, 0xe0, 0x8e, 0x44, - 0x2f, 0x90, 0x85, 0x4f, 0xb8, 0x42, 0x46, 0x60, - 0x21, 0xb8, 0x42, 0x38, 0x86, 0x9e, 0x90, 0xce, - 0x90, 0x9d, 0x91, 0xaf, 0x8f, 0x83, 0x9e, 0x94, - 0x84, 0x92, 0x42, 0xaf, 0xbf, 0xff, 0xca, 0x20, - 0xc1, 0x8c, 0xbf, 0x08, 0x80, 0x9b, 0x57, 0xf7, - 0x87, 0x44, 0xd5, 0xa9, 0x88, 0x60, 0x22, 0xe6, - 0x18, 0x30, 0x08, 0x41, 0x22, 0x8e, 0x80, 0x9c, - 0x11, 0x80, 0x8d, 0x1f, 0x41, 0x8b, 0x49, 0x03, - 0xea, 0x84, 0x8c, 0x82, 0x88, 0x86, 0x89, 0x57, - 0x65, 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b, - 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f, - 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80, - 0x41, 0x53, 0x81, 0x98, 0x80, 0x98, 0x80, 0x9e, - 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, - 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x07, 0x47, - 0x33, 0x9e, 0x2d, 0x41, 0x04, 0xbd, 0x40, 0x91, - 0xac, 0x89, 0x86, 0x8f, 0x80, 0x41, 0x40, 0x9d, - 0x91, 0xab, 0x41, 0xe3, 0x9b, 0x42, 0xf3, 0x30, - 0x18, 0x08, 0x8e, 0x80, 0x40, 0xc4, 0xba, 0xc3, - 0x30, 0x44, 0xb3, 0x18, 0x9a, 0x01, 0x00, 0x08, - 0x80, 0x89, 0x03, 0x00, 0x00, 0x28, 0x18, 0x00, - 0x00, 0x02, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00, - 0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80, 0x90, - 0x51, 0x43, 0x60, 0xa6, 0xdf, 0x9f, 0x50, 0x39, - 0x85, 0x40, 0xdd, 0x81, 0x56, 0x81, 0x8d, 0x5d, - 0x30, 0x4c, 0x1e, 0x42, 0x1d, 0x45, 0xe1, 0x53, - 0x4a, 0x84, 0x50, 0x5f, + 0x04, 0x10, 0x91, 0x80, 0x8b, 0x84, 0x9d, 0x89, + 0x00, 0x08, 0x80, 0xa5, 0x00, 0x98, 0x00, 0x80, + 0xab, 0xb4, 0x91, 0x83, 0x93, 0x82, 0x9d, 0xaf, + 0x93, 0x08, 0x80, 0x40, 0xb7, 0xae, 0xa8, 0x83, + 0xa3, 0xaf, 0x93, 0x80, 0xba, 0xaa, 0x8c, 0x80, + 0xc6, 0x9a, 0xa4, 0x86, 0x40, 0xb8, 0xab, 0xf3, + 0xbf, 0x9e, 0x39, 0x01, 0x38, 0x08, 0x97, 0x8e, + 0x00, 0x80, 0xdd, 0x39, 0xa6, 0x8f, 0x00, 0x80, + 0x9b, 0x80, 0x89, 0xa7, 0x30, 0x94, 0x80, 0x8a, + 0xad, 0x92, 0x80, 0x91, 0xc8, 0x40, 0xc6, 0xa0, + 0x9e, 0x88, 0x80, 0xa4, 0x90, 0x80, 0xb0, 0x9d, + 0xef, 0x30, 0x08, 0xa5, 0x94, 0x80, 0x98, 0x28, + 0x08, 0x9f, 0x8d, 0x80, 0x41, 0x46, 0x92, 0x8e, + 0x00, 0x8c, 0x80, 0xa1, 0xfb, 0x80, 0xce, 0x43, + 0x99, 0xe5, 0xee, 0x90, 0x40, 0xc3, 0x4a, 0x4b, + 0xe0, 0x8e, 0x44, 0x2f, 0x90, 0x85, 0x98, 0x4f, + 0x9a, 0x84, 0x42, 0x46, 0x5a, 0xb8, 0x9d, 0x46, + 0xe1, 0x42, 0x38, 0x86, 0x9e, 0x90, 0xce, 0x90, + 0x9d, 0x91, 0xaf, 0x8f, 0x83, 0x9e, 0x94, 0x84, + 0x92, 0x41, 0xaf, 0xac, 0x40, 0xd2, 0xbf, 0xff, + 0xca, 0x20, 0xc1, 0x8c, 0xbf, 0x08, 0x80, 0x9b, + 0x57, 0xf7, 0x87, 0x44, 0xd5, 0xa8, 0x89, 0x60, + 0x22, 0xe6, 0x18, 0x30, 0x08, 0x41, 0x22, 0x8e, + 0x80, 0x9c, 0x11, 0x80, 0x8d, 0x1f, 0x41, 0x8b, + 0x49, 0x03, 0xea, 0x84, 0x8c, 0x82, 0x88, 0x86, + 0x89, 0x57, 0x65, 0xd4, 0x80, 0xc6, 0x01, 0x08, + 0x09, 0x0b, 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, + 0x03, 0x0f, 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, + 0x16, 0x80, 0x41, 0x53, 0x81, 0x98, 0x80, 0x98, + 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, + 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, + 0x07, 0x47, 0x33, 0x9e, 0x2d, 0x41, 0x04, 0xbd, + 0x40, 0x91, 0xac, 0x89, 0x86, 0x8f, 0x80, 0x41, + 0x40, 0x9d, 0x91, 0xab, 0x41, 0xe3, 0x9b, 0x40, + 0xe3, 0x9d, 0x08, 0x41, 0xee, 0x30, 0x18, 0x08, + 0x8e, 0x80, 0x40, 0xc4, 0xba, 0xc3, 0x30, 0x44, + 0xb3, 0x18, 0x9a, 0x01, 0x00, 0x08, 0x80, 0x89, + 0x03, 0x00, 0x00, 0x28, 0x18, 0x00, 0x00, 0x02, + 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00, 0x80, 0x89, + 0x80, 0x90, 0x22, 0x04, 0x80, 0x90, 0x51, 0x43, + 0x60, 0xa6, 0xdf, 0x9f, 0x50, 0x39, 0x85, 0x40, + 0xdd, 0x81, 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x8e, + 0x42, 0x6d, 0x49, 0xa1, 0x42, 0x1d, 0x45, 0xe1, + 0x53, 0x4a, 0x84, 0x50, 0x5f, }; -static const uint8_t unicode_prop_ID_Start_index[105] = { - 0xf6, 0x03, 0x20, // 003F6 at 33 - 0xa6, 0x07, 0x00, // 007A6 at 64 - 0xa9, 0x09, 0x20, // 009A9 at 97 - 0xb1, 0x0a, 0x00, // 00AB1 at 128 - 0xba, 0x0b, 0x20, // 00BBA at 161 - 0x3b, 0x0d, 0x20, // 00D3B at 193 - 0xc7, 0x0e, 0x20, // 00EC7 at 225 - 0x49, 0x12, 0x00, // 01249 at 256 - 0x9b, 0x16, 0x00, // 0169B at 288 - 0xac, 0x19, 0x00, // 019AC at 320 - 0xc0, 0x1d, 0x80, // 01DC0 at 356 - 0x80, 0x20, 0x20, // 02080 at 385 - 0x70, 0x2d, 0x00, // 02D70 at 416 - 0x00, 0x32, 0x00, // 03200 at 448 - 0xda, 0xa7, 0x00, // 0A7DA at 480 - 0x4c, 0xaa, 0x20, // 0AA4C at 513 - 0xc7, 0xd7, 0x20, // 0D7C7 at 545 - 0xfc, 0xfd, 0x20, // 0FDFC at 577 - 0x9d, 0x02, 0x21, // 1029D at 609 - 0x96, 0x05, 0x01, // 10596 at 640 - 0xf3, 0x08, 0x01, // 108F3 at 672 - 0xb3, 0x0c, 0x21, // 10CB3 at 705 - 0x73, 0x11, 0x61, // 11173 at 739 - 0x34, 0x13, 0x01, // 11334 at 768 - 0x1b, 0x17, 0x21, // 1171B at 801 - 0x8a, 0x1a, 0x01, // 11A8A at 832 - 0x34, 0x1f, 0x21, // 11F34 at 865 - 0xbf, 0x6a, 0x01, // 16ABF at 896 - 0x23, 0xb1, 0xa1, // 1B123 at 933 - 0xad, 0xd4, 0x01, // 1D4AD at 960 - 0x6f, 0xd7, 0x01, // 1D76F at 992 - 0xff, 0xe7, 0x61, // 1E7FF at 1027 - 0x5e, 0xee, 0x01, // 1EE5E at 1056 - 0xe1, 0xeb, 0x22, // 2EBE1 at 1089 - 0xb0, 0x23, 0x03, // 323B0 at 1120 (upper bound) +static const uint8_t unicode_prop_ID_Start_index[108] = { + 0xf6, 0x03, 0x20, 0xa6, 0x07, 0x00, 0xa9, 0x09, + 0x20, 0xb1, 0x0a, 0x00, 0xba, 0x0b, 0x20, 0x3b, + 0x0d, 0x20, 0xc7, 0x0e, 0x20, 0x49, 0x12, 0x00, + 0x9b, 0x16, 0x00, 0xac, 0x19, 0x00, 0xc0, 0x1d, + 0x80, 0x80, 0x20, 0x20, 0x70, 0x2d, 0x00, 0x00, + 0x32, 0x00, 0xdd, 0xa7, 0x00, 0x4c, 0xaa, 0x20, + 0xc7, 0xd7, 0x20, 0xfc, 0xfd, 0x20, 0x9d, 0x02, + 0x21, 0x96, 0x05, 0x01, 0x9f, 0x08, 0x01, 0x49, + 0x0c, 0x21, 0x76, 0x10, 0x21, 0xa9, 0x12, 0x01, + 0xb0, 0x14, 0x01, 0x42, 0x19, 0x41, 0x90, 0x1c, + 0x01, 0xf1, 0x2f, 0x21, 0x90, 0x6b, 0x21, 0x33, + 0xb1, 0x21, 0x06, 0xd5, 0x01, 0xc3, 0xd7, 0x01, + 0xff, 0xe7, 0x21, 0x63, 0xee, 0x01, 0x5e, 0xee, + 0x42, 0xb0, 0x23, 0x03, }; -static const uint8_t unicode_prop_ID_Continue1_table[660] = { +static const uint8_t unicode_prop_ID_Continue1_table[695] = { 0xaf, 0x89, 0xa4, 0x80, 0xd6, 0x80, 0x42, 0x47, 0xef, 0x96, 0x80, 0x40, 0xfa, 0x84, 0x41, 0x08, 0xac, 0x00, 0x01, 0x01, 0x00, 0xc7, 0x8a, 0xaf, 0x9e, 0x28, 0xe4, 0x31, 0x29, 0x08, 0x19, 0x89, 0x96, 0x80, 0x9d, 0x9a, 0xda, 0x8a, 0x8e, 0x89, 0xa0, 0x88, 0x88, 0x80, 0x97, 0x18, 0x88, 0x02, - 0x04, 0xaa, 0x82, 0xbb, 0x87, 0xa9, 0x97, 0x80, + 0x04, 0xaa, 0x82, 0xba, 0x88, 0xa9, 0x97, 0x80, 0xa0, 0xb5, 0x10, 0x91, 0x06, 0x89, 0x09, 0x89, 0x90, 0x82, 0xb7, 0x00, 0x31, 0x09, 0x82, 0x88, 0x80, 0x89, 0x09, 0x89, 0x8d, 0x01, 0x82, 0xb7, @@ -535,83 +506,83 @@ static const uint8_t unicode_prop_ID_Continue1_table[660] = { 0xae, 0x90, 0x8a, 0x89, 0x90, 0x88, 0x8b, 0x82, 0x9d, 0x8c, 0x81, 0x89, 0xab, 0x8d, 0xaf, 0x93, 0x87, 0x89, 0x85, 0x89, 0xf5, 0x10, 0x94, 0x18, - 0x28, 0x0a, 0x40, 0xc5, 0xbf, 0x42, 0x3e, 0x81, - 0x92, 0x80, 0xfa, 0x8c, 0x18, 0x82, 0x8b, 0x4b, - 0xfd, 0x82, 0x40, 0x8c, 0x80, 0xdf, 0x9f, 0x42, - 0x29, 0x85, 0xe8, 0x81, 0x60, 0x75, 0x84, 0x89, - 0xc4, 0x03, 0x89, 0x9f, 0x81, 0xcf, 0x81, 0x41, - 0x0f, 0x02, 0x03, 0x80, 0x96, 0x23, 0x80, 0xd2, - 0x81, 0xb1, 0x91, 0x89, 0x89, 0x85, 0x91, 0x8c, - 0x8a, 0x9b, 0x87, 0x98, 0x8c, 0xab, 0x83, 0xae, - 0x8d, 0x8e, 0x89, 0x8a, 0x80, 0x89, 0x89, 0xae, - 0x8d, 0x8b, 0x07, 0x09, 0x89, 0xa0, 0x82, 0xb1, - 0x00, 0x11, 0x0c, 0x08, 0x80, 0xa8, 0x24, 0x81, - 0x40, 0xeb, 0x38, 0x09, 0x89, 0x60, 0x4f, 0x23, - 0x80, 0x42, 0xe0, 0x8f, 0x8f, 0x8f, 0x11, 0x97, - 0x82, 0x40, 0xbf, 0x89, 0xa4, 0x80, 0x42, 0xbc, - 0x80, 0x40, 0xe1, 0x80, 0x40, 0x94, 0x84, 0x41, - 0x24, 0x89, 0x45, 0x56, 0x10, 0x0c, 0x83, 0xa7, - 0x13, 0x80, 0x40, 0xa4, 0x81, 0x42, 0x3c, 0x1f, - 0x89, 0x41, 0x70, 0x81, 0xcf, 0x82, 0xc5, 0x8a, - 0xb0, 0x83, 0xf9, 0x82, 0xb4, 0x8e, 0x9e, 0x8a, - 0x09, 0x89, 0x83, 0xac, 0x8a, 0x30, 0xac, 0x89, - 0x2a, 0xa3, 0x8d, 0x80, 0x89, 0x21, 0xab, 0x80, - 0x8b, 0x82, 0xaf, 0x8d, 0x3b, 0x80, 0x8b, 0xd1, - 0x8b, 0x28, 0x08, 0x40, 0x9c, 0x8b, 0x84, 0x89, - 0x2b, 0xb6, 0x08, 0x31, 0x09, 0x82, 0x88, 0x80, - 0x89, 0x09, 0x32, 0x84, 0x40, 0xbf, 0x91, 0x88, - 0x89, 0x18, 0xd0, 0x93, 0x8b, 0x89, 0x40, 0xd4, - 0x31, 0x88, 0x9a, 0x81, 0xd1, 0x90, 0x8e, 0x89, - 0xd0, 0x8c, 0x87, 0x89, 0xd2, 0x8e, 0x83, 0x89, - 0x40, 0xf1, 0x8e, 0x40, 0xa4, 0x89, 0xc5, 0x28, - 0x09, 0x18, 0x00, 0x81, 0x8b, 0x89, 0xf6, 0x31, - 0x32, 0x80, 0x9b, 0x89, 0xa7, 0x30, 0x1f, 0x80, - 0x88, 0x8a, 0xad, 0x8f, 0x41, 0x94, 0x38, 0x87, - 0x8f, 0x89, 0xb7, 0x95, 0x80, 0x8d, 0xf9, 0x2a, - 0x00, 0x08, 0x30, 0x07, 0x89, 0xaf, 0x20, 0x08, - 0x27, 0x89, 0x41, 0x48, 0x83, 0x88, 0x08, 0x80, - 0xaf, 0x32, 0x84, 0x8c, 0x89, 0x54, 0xe5, 0x05, - 0x8e, 0x60, 0x36, 0x09, 0x89, 0xd5, 0x89, 0xa5, - 0x84, 0xba, 0x86, 0x98, 0x89, 0x43, 0xf4, 0x00, - 0xb6, 0x33, 0xd0, 0x80, 0x8a, 0x81, 0x60, 0x4c, - 0xaa, 0x81, 0x52, 0x60, 0xad, 0x81, 0x96, 0x42, - 0x1d, 0x22, 0x2f, 0x39, 0x86, 0x9d, 0x83, 0x40, - 0x93, 0x82, 0x45, 0x88, 0xb1, 0x41, 0xff, 0xb6, - 0x83, 0xb1, 0x38, 0x8d, 0x80, 0x95, 0x20, 0x8e, - 0x45, 0x4f, 0x30, 0x90, 0x0e, 0x01, 0x04, 0xe3, - 0x80, 0x40, 0x9f, 0x86, 0x88, 0x89, 0x41, 0x63, - 0x80, 0xbc, 0x8d, 0x41, 0xf1, 0x8d, 0x43, 0xd5, - 0x86, 0xec, 0x34, 0x89, 0x52, 0x95, 0x89, 0x6c, - 0x05, 0x05, 0x40, 0xef, + 0x28, 0x0a, 0x40, 0xc5, 0xbf, 0x42, 0x0b, 0x81, + 0xb0, 0x81, 0x92, 0x80, 0xfa, 0x8c, 0x18, 0x82, + 0x8b, 0x4b, 0xfd, 0x82, 0x40, 0x8c, 0x80, 0xdf, + 0x9f, 0x42, 0x29, 0x85, 0xe8, 0x81, 0xdf, 0x80, + 0x60, 0x75, 0x23, 0x89, 0xc4, 0x03, 0x89, 0x9f, + 0x81, 0xcf, 0x81, 0x41, 0x0f, 0x02, 0x03, 0x80, + 0x96, 0x23, 0x80, 0xd2, 0x81, 0xb1, 0x91, 0x89, + 0x89, 0x85, 0x91, 0x8c, 0x8a, 0x9b, 0x87, 0x98, + 0x8c, 0xab, 0x83, 0xae, 0x8d, 0x8e, 0x89, 0x8a, + 0x80, 0x89, 0x89, 0xae, 0x8d, 0x8b, 0x07, 0x09, + 0x89, 0xa0, 0x82, 0xb1, 0x00, 0x11, 0x0c, 0x08, + 0x80, 0xa8, 0x24, 0x81, 0x40, 0xeb, 0x38, 0x09, + 0x89, 0x60, 0x4f, 0x23, 0x80, 0x42, 0xe0, 0x8f, + 0x8f, 0x8f, 0x11, 0x97, 0x82, 0x40, 0xbf, 0x89, + 0xa4, 0x80, 0xa4, 0x80, 0x42, 0x96, 0x80, 0x40, + 0xe1, 0x80, 0x40, 0x94, 0x84, 0x41, 0x24, 0x89, + 0x45, 0x56, 0x10, 0x0c, 0x83, 0xa7, 0x13, 0x80, + 0x40, 0xa4, 0x81, 0x42, 0x3c, 0x1f, 0x89, 0x85, + 0x89, 0x9e, 0x84, 0x41, 0x3c, 0x81, 0xce, 0x83, + 0xc5, 0x8a, 0xb0, 0x83, 0xf9, 0x82, 0xb4, 0x8e, + 0x9e, 0x8a, 0x09, 0x89, 0x83, 0xac, 0x8a, 0x30, + 0xac, 0x89, 0x2a, 0xa3, 0x8d, 0x80, 0x89, 0x21, + 0xab, 0x80, 0x8b, 0x82, 0xaf, 0x8d, 0x3b, 0x80, + 0x8b, 0xd1, 0x8b, 0x28, 0x08, 0x40, 0x9c, 0x8b, + 0x84, 0x89, 0x2b, 0xb6, 0x08, 0x31, 0x09, 0x82, + 0x88, 0x80, 0x89, 0x09, 0x32, 0x84, 0xc2, 0x88, + 0x00, 0x08, 0x03, 0x04, 0x00, 0x8d, 0x81, 0xd1, + 0x91, 0x88, 0x89, 0x18, 0xd0, 0x93, 0x8b, 0x89, + 0x40, 0xd4, 0x31, 0x88, 0x9a, 0x81, 0xd1, 0x90, + 0x8e, 0x89, 0xd0, 0x8c, 0x87, 0x89, 0x85, 0x93, + 0xb8, 0x8e, 0x83, 0x89, 0x40, 0xf1, 0x8e, 0x40, + 0xa4, 0x89, 0xc5, 0x28, 0x09, 0x18, 0x00, 0x81, + 0x8b, 0x89, 0xf6, 0x31, 0x32, 0x80, 0x9b, 0x89, + 0xa7, 0x30, 0x1f, 0x80, 0x88, 0x8a, 0xad, 0x8f, + 0x41, 0x55, 0x89, 0xb4, 0x38, 0x87, 0x8f, 0x89, + 0xb7, 0x95, 0x80, 0x8d, 0xf9, 0x2a, 0x00, 0x08, + 0x30, 0x07, 0x89, 0xaf, 0x20, 0x08, 0x27, 0x89, + 0x41, 0x48, 0x83, 0x88, 0x08, 0x80, 0xaf, 0x32, + 0x84, 0x8c, 0x8a, 0x54, 0xe4, 0x05, 0x8e, 0x60, + 0x2c, 0xc7, 0x9b, 0x49, 0x25, 0x89, 0xd5, 0x89, + 0xa5, 0x84, 0xba, 0x86, 0x98, 0x89, 0x42, 0x15, + 0x89, 0x41, 0xd4, 0x00, 0xb6, 0x33, 0xd0, 0x80, + 0x8a, 0x81, 0x60, 0x4c, 0xaa, 0x81, 0x50, 0x50, + 0x89, 0x42, 0x05, 0xad, 0x81, 0x96, 0x42, 0x1d, + 0x22, 0x2f, 0x39, 0x86, 0x9d, 0x83, 0x40, 0x93, + 0x82, 0x45, 0x88, 0xb1, 0x41, 0xff, 0xb6, 0x83, + 0xb1, 0x38, 0x8d, 0x80, 0x95, 0x20, 0x8e, 0x45, + 0x4f, 0x30, 0x90, 0x0e, 0x01, 0x04, 0xe3, 0x80, + 0x40, 0x9f, 0x86, 0x88, 0x89, 0x41, 0x63, 0x80, + 0xbc, 0x8d, 0x41, 0xf1, 0x8d, 0x40, 0xf3, 0x08, + 0x89, 0x42, 0xd4, 0x86, 0xec, 0x34, 0x89, 0x52, + 0x95, 0x89, 0x6c, 0x05, 0x05, 0x40, 0xef, +}; + +static const uint8_t unicode_prop_ID_Continue1_index[66] = { + 0xfa, 0x06, 0x00, 0x70, 0x09, 0x00, 0xf0, 0x0a, + 0x40, 0x57, 0x0c, 0x00, 0xf0, 0x0d, 0x60, 0xc7, + 0x0f, 0x20, 0xea, 0x17, 0x40, 0x05, 0x1b, 0x00, + 0x0e, 0x20, 0x00, 0xa0, 0xa6, 0x20, 0xe6, 0xa9, + 0x20, 0x10, 0xfe, 0x00, 0x40, 0x0a, 0x01, 0xc3, + 0x10, 0x01, 0x4e, 0x13, 0x01, 0x41, 0x16, 0x01, + 0x0b, 0x1a, 0x01, 0xaa, 0x1d, 0x01, 0x7a, 0x6d, + 0x21, 0x45, 0xd2, 0x21, 0xaf, 0xe2, 0x01, 0xf0, + 0x01, 0x0e, }; -static const uint8_t unicode_prop_ID_Continue1_index[63] = { - 0xfa, 0x06, 0x00, // 006FA at 32 - 0x70, 0x09, 0x00, // 00970 at 64 - 0xf0, 0x0a, 0x40, // 00AF0 at 98 - 0x57, 0x0c, 0x00, // 00C57 at 128 - 0xf0, 0x0d, 0x60, // 00DF0 at 163 - 0xc7, 0x0f, 0x20, // 00FC7 at 193 - 0xea, 0x17, 0x40, // 017EA at 226 - 0x05, 0x1b, 0x00, // 01B05 at 256 - 0x41, 0x20, 0x00, // 02041 at 288 - 0x0c, 0xa8, 0x80, // 0A80C at 324 - 0x37, 0xaa, 0x20, // 0AA37 at 353 - 0x50, 0xfe, 0x20, // 0FE50 at 385 - 0x3a, 0x0d, 0x21, // 10D3A at 417 - 0x74, 0x11, 0x01, // 11174 at 448 - 0x5a, 0x14, 0x21, // 1145A at 481 - 0x44, 0x19, 0x81, // 11944 at 516 - 0x5a, 0x1d, 0xa1, // 11D5A at 549 - 0xf5, 0x6a, 0x21, // 16AF5 at 577 - 0x45, 0xd2, 0x41, // 1D245 at 610 - 0xaf, 0xe2, 0x21, // 1E2AF at 641 - 0xf0, 0x01, 0x0e, // E01F0 at 672 (upper bound) +static const uint8_t unicode_prop_White_Space_table[22] = { + 0x88, 0x84, 0x91, 0x80, 0xe3, 0x80, 0x99, 0x80, + 0x55, 0xde, 0x80, 0x49, 0x7e, 0x8a, 0x9c, 0x0c, + 0x80, 0xae, 0x80, 0x4f, 0x9f, 0x80, }; -#ifdef CONFIG_ALL_UNICODE +static const uint8_t unicode_prop_White_Space_index[3] = { + 0x01, 0x30, 0x00, +}; -static const uint8_t unicode_cc_table[899] = { +static const uint8_t unicode_cc_table[916] = { 0xb2, 0xcf, 0xd4, 0x00, 0xe8, 0x03, 0xdc, 0x00, 0xe8, 0x00, 0xd8, 0x04, 0xdc, 0x01, 0xca, 0x03, 0xdc, 0x01, 0xca, 0x0a, 0xdc, 0x04, 0x01, 0x03, @@ -635,7 +606,7 @@ static const uint8_t unicode_cc_table[899] = { 0xc0, 0x00, 0xdc, 0xc0, 0x00, 0xdc, 0xc1, 0xb0, 0x6f, 0xc6, 0x00, 0xdc, 0xc0, 0x88, 0x00, 0xdc, 0x97, 0xc3, 0x80, 0xc8, 0x80, 0xc2, 0x80, 0xc4, - 0xaa, 0x02, 0xdc, 0xb0, 0x0b, 0xc0, 0x02, 0xdc, + 0xaa, 0x02, 0xdc, 0xb0, 0x0a, 0xc1, 0x02, 0xdc, 0xc3, 0xa9, 0xc4, 0x04, 0xdc, 0xcd, 0x80, 0x00, 0xdc, 0xc1, 0x00, 0xdc, 0xc1, 0x00, 0xdc, 0xc2, 0x02, 0xdc, 0x42, 0x1b, 0xc2, 0x00, 0xdc, 0xc1, @@ -693,73 +664,57 @@ static const uint8_t unicode_cc_table[899] = { 0xdc, 0xb0, 0xb1, 0x00, 0xdc, 0xb0, 0x64, 0xc4, 0xb6, 0x61, 0x00, 0xdc, 0x80, 0xc0, 0xa7, 0xc0, 0x00, 0x01, 0x00, 0xdc, 0x83, 0x00, 0x09, 0xb0, - 0x74, 0xc0, 0x00, 0xdc, 0xb2, 0x0c, 0xc3, 0xb1, - 0x52, 0xc1, 0xb0, 0x1f, 0x02, 0xdc, 0xb0, 0x15, - 0x01, 0xdc, 0xc2, 0x00, 0xdc, 0xc0, 0x03, 0xdc, - 0xb0, 0x00, 0xc0, 0x00, 0xdc, 0xc0, 0x00, 0xdc, - 0xb0, 0x8f, 0x00, 0x09, 0xa8, 0x00, 0x09, 0x8d, - 0x00, 0x09, 0xb0, 0x08, 0x00, 0x09, 0x00, 0x07, - 0xb0, 0x14, 0xc2, 0xaf, 0x01, 0x09, 0xb0, 0x0d, - 0x00, 0x07, 0xb0, 0x1b, 0x00, 0x09, 0x88, 0x00, - 0x07, 0xb0, 0x39, 0x00, 0x09, 0x00, 0x07, 0xb0, - 0x81, 0x00, 0x07, 0x00, 0x09, 0xb0, 0x1f, 0x01, - 0x07, 0x8f, 0x00, 0x09, 0x97, 0xc6, 0x82, 0xc4, - 0xb0, 0x9c, 0x00, 0x09, 0x82, 0x00, 0x07, 0x96, - 0xc0, 0xb0, 0x32, 0x00, 0x09, 0x00, 0x07, 0xb0, - 0xca, 0x00, 0x09, 0x00, 0x07, 0xb0, 0x4d, 0x00, - 0x09, 0xb0, 0x45, 0x00, 0x09, 0x00, 0x07, 0xb0, - 0x42, 0x00, 0x09, 0xb0, 0xdc, 0x00, 0x09, 0x00, - 0x07, 0xb0, 0xd1, 0x01, 0x09, 0x83, 0x00, 0x07, - 0xb0, 0x6b, 0x00, 0x09, 0xb0, 0x22, 0x00, 0x09, - 0x91, 0x00, 0x09, 0xb0, 0x20, 0x00, 0x09, 0xb1, - 0x74, 0x00, 0x09, 0xb0, 0xd1, 0x00, 0x07, 0x80, - 0x01, 0x09, 0xb0, 0x20, 0x00, 0x09, 0xb1, 0x78, - 0x01, 0x09, 0xb8, 0x43, 0x7c, 0x04, 0x01, 0xb0, - 0x0a, 0xc6, 0xb4, 0x88, 0x01, 0x06, 0xb8, 0x44, - 0x7b, 0x00, 0x01, 0xb8, 0x0c, 0x95, 0x01, 0xd8, - 0x02, 0x01, 0x82, 0x00, 0xe2, 0x04, 0xd8, 0x87, - 0x07, 0xdc, 0x81, 0xc4, 0x01, 0xdc, 0x9d, 0xc3, - 0xb0, 0x63, 0xc2, 0xb8, 0x05, 0x8a, 0xc6, 0x80, - 0xd0, 0x81, 0xc6, 0x80, 0xc1, 0x80, 0xc4, 0xb0, - 0x33, 0xc0, 0xb0, 0x6f, 0xc6, 0xb1, 0x46, 0xc0, - 0xb0, 0x0c, 0xc3, 0xb1, 0xcb, 0x01, 0xe8, 0x00, - 0xdc, 0xc0, 0xb3, 0xaf, 0x06, 0xdc, 0xb0, 0x3c, - 0xc5, 0x00, 0x07, + 0x74, 0xc0, 0x00, 0xdc, 0xb2, 0x0c, 0xc3, 0xb0, + 0x10, 0xc4, 0xb1, 0x0c, 0xc1, 0xb0, 0x1f, 0x02, + 0xdc, 0xb0, 0x15, 0x01, 0xdc, 0xc2, 0x00, 0xdc, + 0xc0, 0x03, 0xdc, 0xb0, 0x00, 0xc0, 0x00, 0xdc, + 0xc0, 0x00, 0xdc, 0xb0, 0x8f, 0x00, 0x09, 0xa8, + 0x00, 0x09, 0x8d, 0x00, 0x09, 0xb0, 0x08, 0x00, + 0x09, 0x00, 0x07, 0xb0, 0x14, 0xc2, 0xaf, 0x01, + 0x09, 0xb0, 0x0d, 0x00, 0x07, 0xb0, 0x1b, 0x00, + 0x09, 0x88, 0x00, 0x07, 0xb0, 0x39, 0x00, 0x09, + 0x00, 0x07, 0xb0, 0x81, 0x00, 0x07, 0x00, 0x09, + 0xb0, 0x1f, 0x01, 0x07, 0x8f, 0x00, 0x09, 0x97, + 0xc6, 0x82, 0xc4, 0xb0, 0x28, 0x02, 0x09, 0xb0, + 0x40, 0x00, 0x09, 0x82, 0x00, 0x07, 0x96, 0xc0, + 0xb0, 0x32, 0x00, 0x09, 0x00, 0x07, 0xb0, 0xca, + 0x00, 0x09, 0x00, 0x07, 0xb0, 0x4d, 0x00, 0x09, + 0xb0, 0x45, 0x00, 0x09, 0x00, 0x07, 0xb0, 0x42, + 0x00, 0x09, 0xb0, 0xdc, 0x00, 0x09, 0x00, 0x07, + 0xb0, 0xd1, 0x01, 0x09, 0x83, 0x00, 0x07, 0xb0, + 0x6b, 0x00, 0x09, 0xb0, 0x22, 0x00, 0x09, 0x91, + 0x00, 0x09, 0xb0, 0x20, 0x00, 0x09, 0xb1, 0x74, + 0x00, 0x09, 0xb0, 0xd1, 0x00, 0x07, 0x80, 0x01, + 0x09, 0xb0, 0x20, 0x00, 0x09, 0xb1, 0x78, 0x01, + 0x09, 0xb8, 0x39, 0xbb, 0x00, 0x09, 0xb8, 0x01, + 0x8f, 0x04, 0x01, 0xb0, 0x0a, 0xc6, 0xb4, 0x88, + 0x01, 0x06, 0xb8, 0x44, 0x7b, 0x00, 0x01, 0xb8, + 0x0c, 0x95, 0x01, 0xd8, 0x02, 0x01, 0x82, 0x00, + 0xe2, 0x04, 0xd8, 0x87, 0x07, 0xdc, 0x81, 0xc4, + 0x01, 0xdc, 0x9d, 0xc3, 0xb0, 0x63, 0xc2, 0xb8, + 0x05, 0x8a, 0xc6, 0x80, 0xd0, 0x81, 0xc6, 0x80, + 0xc1, 0x80, 0xc4, 0xb0, 0x33, 0xc0, 0xb0, 0x6f, + 0xc6, 0xb1, 0x46, 0xc0, 0xb0, 0x0c, 0xc3, 0xb1, + 0xcb, 0x01, 0xe8, 0x00, 0xdc, 0xc0, 0xb0, 0xcd, + 0xc0, 0x00, 0xdc, 0xb2, 0xaf, 0x06, 0xdc, 0xb0, + 0x3c, 0xc5, 0x00, 0x07, }; static const uint8_t unicode_cc_index[87] = { - 0x4d, 0x03, 0x00, // 0034D at 32 - 0x97, 0x05, 0x20, // 00597 at 65 - 0xc6, 0x05, 0x00, // 005C6 at 96 - 0xe7, 0x06, 0x00, // 006E7 at 128 - 0x45, 0x07, 0x00, // 00745 at 160 - 0x9c, 0x08, 0x00, // 0089C at 192 - 0x4d, 0x09, 0x00, // 0094D at 224 - 0x3c, 0x0b, 0x00, // 00B3C at 256 - 0x3d, 0x0d, 0x00, // 00D3D at 288 - 0x36, 0x0f, 0x00, // 00F36 at 320 - 0x38, 0x10, 0x20, // 01038 at 353 - 0x3a, 0x19, 0x00, // 0193A at 384 - 0xcb, 0x1a, 0x20, // 01ACB at 417 - 0xd3, 0x1c, 0x00, // 01CD3 at 448 - 0xcf, 0x1d, 0x00, // 01DCF at 480 - 0xe2, 0x20, 0x00, // 020E2 at 512 - 0x2e, 0x30, 0x20, // 0302E at 545 - 0x2b, 0xa9, 0x20, // 0A92B at 577 - 0xed, 0xab, 0x00, // 0ABED at 608 - 0x39, 0x0a, 0x01, // 10A39 at 640 - 0x51, 0x0f, 0x01, // 10F51 at 672 - 0x73, 0x11, 0x01, // 11173 at 704 - 0x75, 0x13, 0x01, // 11375 at 736 - 0x2b, 0x17, 0x21, // 1172B at 769 - 0x3f, 0x1c, 0x21, // 11C3F at 801 - 0x9e, 0xbc, 0x21, // 1BC9E at 833 - 0x08, 0xe0, 0x01, // 1E008 at 864 - 0x44, 0xe9, 0x01, // 1E944 at 896 - 0x4b, 0xe9, 0x01, // 1E94B at 928 (upper bound) + 0x4d, 0x03, 0x00, 0x97, 0x05, 0x20, 0xc6, 0x05, + 0x00, 0xe7, 0x06, 0x00, 0x45, 0x07, 0x00, 0x9c, + 0x08, 0x00, 0x4d, 0x09, 0x00, 0x3c, 0x0b, 0x00, + 0x3d, 0x0d, 0x00, 0x36, 0x0f, 0x00, 0x38, 0x10, + 0x20, 0x3a, 0x19, 0x00, 0xcb, 0x1a, 0x20, 0xd3, + 0x1c, 0x00, 0xcf, 0x1d, 0x00, 0xe2, 0x20, 0x00, + 0x2e, 0x30, 0x20, 0x2b, 0xa9, 0x20, 0xed, 0xab, + 0x00, 0x39, 0x0a, 0x01, 0x4c, 0x0f, 0x01, 0x35, + 0x11, 0x21, 0x66, 0x13, 0x01, 0x40, 0x16, 0x01, + 0x47, 0x1a, 0x01, 0xf0, 0x6a, 0x21, 0x8a, 0xd1, + 0x01, 0xec, 0xe4, 0x21, 0x4b, 0xe9, 0x01, }; -static const uint32_t unicode_decomp_table1[699] = { +static const uint32_t unicode_decomp_table1[709] = { 0x00280081, 0x002a0097, 0x002a8081, 0x002bc097, 0x002c8115, 0x002d0097, 0x002d4081, 0x002e0097, 0x002e4115, 0x002f0199, 0x00302016, 0x00400842, @@ -902,42 +857,45 @@ static const uint32_t unicode_decomp_table1[699] = { 0x3f9c01af, 0x3f9d0085, 0x3f9d852f, 0x3fa03aad, 0x3fbd442f, 0x3fc06f1f, 0x3fd7c11f, 0x3fd85fad, 0x3fe80081, 0x3fe84f1f, 0x3ff0831f, 0x3ff2831f, - 0x3ff4831f, 0x3ff6819f, 0x3ff80783, 0x41e04d83, - 0x41e70f91, 0x44268192, 0x442ac092, 0x444b8112, - 0x44d2c112, 0x452ec212, 0x456e8112, 0x464e0092, - 0x74578392, 0x746ec312, 0x75000d1f, 0x75068d1f, - 0x750d0d1f, 0x7513839f, 0x7515891f, 0x751a0d1f, - 0x75208d1f, 0x75271015, 0x752f439f, 0x7531459f, - 0x75340d1f, 0x753a8d1f, 0x75410395, 0x7543441f, - 0x7545839f, 0x75478d1f, 0x754e0795, 0x7552839f, - 0x75548d1f, 0x755b0d1f, 0x75618d1f, 0x75680d1f, - 0x756e8d1f, 0x75750d1f, 0x757b8d1f, 0x75820d1f, - 0x75888d1f, 0x758f0d1f, 0x75958d1f, 0x759c0d1f, - 0x75a28d1f, 0x75a90103, 0x75aa089f, 0x75ae4081, - 0x75ae839f, 0x75b04081, 0x75b08c9f, 0x75b6c081, - 0x75b7032d, 0x75b8889f, 0x75bcc081, 0x75bd039f, - 0x75bec081, 0x75bf0c9f, 0x75c54081, 0x75c5832d, - 0x75c7089f, 0x75cb4081, 0x75cb839f, 0x75cd4081, - 0x75cd8c9f, 0x75d3c081, 0x75d4032d, 0x75d5889f, - 0x75d9c081, 0x75da039f, 0x75dbc081, 0x75dc0c9f, - 0x75e24081, 0x75e2832d, 0x75e4089f, 0x75e84081, - 0x75e8839f, 0x75ea4081, 0x75ea8c9f, 0x75f0c081, - 0x75f1042d, 0x75f3851f, 0x75f6051f, 0x75f8851f, - 0x75fb051f, 0x75fd851f, 0x780c049f, 0x780e419f, - 0x780f059f, 0x7811c203, 0x7812d0ad, 0x781b0103, - 0x7b80022d, 0x7b814dad, 0x7b884203, 0x7b89c081, - 0x7b8a452d, 0x7b8d0403, 0x7b908081, 0x7b91dc03, - 0x7ba0052d, 0x7ba2c8ad, 0x7ba84483, 0x7baac8ad, - 0x7c400097, 0x7c404521, 0x7c440d25, 0x7c4a8087, - 0x7c4ac115, 0x7c4b4117, 0x7c4c0d1f, 0x7c528217, - 0x7c538099, 0x7c53c097, 0x7c5a8197, 0x7c640097, - 0x7c80012f, 0x7c808081, 0x7c841603, 0x7c9004c1, - 0x7c940103, 0x7efc051f, 0xbe0001ac, 0xbe00d110, - 0xbe0947ac, 0xbe0d3910, 0xbe29872c, 0xbe2d022c, - 0xbe2e3790, 0xbe49ff90, 0xbe69bc10, + 0x3ff4831f, 0x3ff6819f, 0x3ff80783, 0x41724092, + 0x41790092, 0x41e04d83, 0x41e70f91, 0x44268192, + 0x442ac092, 0x444b8112, 0x44d2c112, 0x44e0c192, + 0x44e38092, 0x44e44092, 0x44f14212, 0x452ec212, + 0x456e8112, 0x464e0092, 0x58484412, 0x5b5a0192, + 0x73358d1f, 0x733c051f, 0x74578392, 0x746ec312, + 0x75000d1f, 0x75068d1f, 0x750d0d1f, 0x7513839f, + 0x7515891f, 0x751a0d1f, 0x75208d1f, 0x75271015, + 0x752f439f, 0x7531459f, 0x75340d1f, 0x753a8d1f, + 0x75410395, 0x7543441f, 0x7545839f, 0x75478d1f, + 0x754e0795, 0x7552839f, 0x75548d1f, 0x755b0d1f, + 0x75618d1f, 0x75680d1f, 0x756e8d1f, 0x75750d1f, + 0x757b8d1f, 0x75820d1f, 0x75888d1f, 0x758f0d1f, + 0x75958d1f, 0x759c0d1f, 0x75a28d1f, 0x75a90103, + 0x75aa089f, 0x75ae4081, 0x75ae839f, 0x75b04081, + 0x75b08c9f, 0x75b6c081, 0x75b7032d, 0x75b8889f, + 0x75bcc081, 0x75bd039f, 0x75bec081, 0x75bf0c9f, + 0x75c54081, 0x75c5832d, 0x75c7089f, 0x75cb4081, + 0x75cb839f, 0x75cd4081, 0x75cd8c9f, 0x75d3c081, + 0x75d4032d, 0x75d5889f, 0x75d9c081, 0x75da039f, + 0x75dbc081, 0x75dc0c9f, 0x75e24081, 0x75e2832d, + 0x75e4089f, 0x75e84081, 0x75e8839f, 0x75ea4081, + 0x75ea8c9f, 0x75f0c081, 0x75f1042d, 0x75f3851f, + 0x75f6051f, 0x75f8851f, 0x75fb051f, 0x75fd851f, + 0x780c049f, 0x780e419f, 0x780f059f, 0x7811c203, + 0x7812d0ad, 0x781b0103, 0x7b80022d, 0x7b814dad, + 0x7b884203, 0x7b89c081, 0x7b8a452d, 0x7b8d0403, + 0x7b908081, 0x7b91dc03, 0x7ba0052d, 0x7ba2c8ad, + 0x7ba84483, 0x7baac8ad, 0x7c400097, 0x7c404521, + 0x7c440d25, 0x7c4a8087, 0x7c4ac115, 0x7c4b4117, + 0x7c4c0d1f, 0x7c528217, 0x7c538099, 0x7c53c097, + 0x7c5a8197, 0x7c640097, 0x7c80012f, 0x7c808081, + 0x7c841603, 0x7c9004c1, 0x7c940103, 0x7efc051f, + 0xbe0001ac, 0xbe00d110, 0xbe0947ac, 0xbe0d3910, + 0xbe29872c, 0xbe2d022c, 0xbe2e3790, 0xbe49ff90, + 0xbe69bc10, }; -static const uint16_t unicode_decomp_table2[699] = { +static const uint16_t unicode_decomp_table2[709] = { 0x0020, 0x0000, 0x0061, 0x0002, 0x0004, 0x0006, 0x03bc, 0x0008, 0x000a, 0x000c, 0x0015, 0x0095, 0x00a5, 0x00b9, 0x00c1, 0x00c3, 0x00c7, 0x00cb, 0x00d1, 0x00d7, 0x00dd, 0x00e0, 0x00e6, 0x00f8, @@ -1009,26 +967,27 @@ static const uint16_t unicode_decomp_table2[699] = { 0x1a77, 0x1a7f, 0x1a9d, 0x1aa2, 0x1ab6, 0x1ac0, 0x1ac6, 0x1ada, 0x1adf, 0x1ae5, 0x1af3, 0x1b23, 0x1b30, 0x1b38, 0x1b3c, 0x1b52, 0x1bc9, 0x1bdb, 0x1bdd, 0x1bdf, 0x3164, 0x1c20, 0x1c22, 0x1c24, - 0x1c26, 0x1c28, 0x1c2a, 0x1c48, 0x1c7e, 0x1cc4, 0x1cd2, 0x1cd7, - 0x1ce0, 0x1ce9, 0x1cfb, 0x1d04, 0x1d09, 0x1d29, 0x1d44, 0x1d46, - 0x1d48, 0x1d4a, 0x1d4c, 0x1d4e, 0x1d50, 0x1d52, 0x1d72, 0x1d74, - 0x1d76, 0x1d78, 0x1d7a, 0x1d81, 0x1d83, 0x1d85, 0x1d87, 0x1d96, - 0x1d98, 0x1d9a, 0x1d9c, 0x1d9e, 0x1da0, 0x1da2, 0x1da4, 0x1da6, - 0x1da8, 0x1daa, 0x1dac, 0x1dae, 0x1db0, 0x1db2, 0x1db6, 0x03f4, - 0x1db8, 0x2207, 0x1dba, 0x2202, 0x1dbc, 0x1dc4, 0x03f4, 0x1dc6, - 0x2207, 0x1dc8, 0x2202, 0x1dca, 0x1dd2, 0x03f4, 0x1dd4, 0x2207, - 0x1dd6, 0x2202, 0x1dd8, 0x1de0, 0x03f4, 0x1de2, 0x2207, 0x1de4, - 0x2202, 0x1de6, 0x1dee, 0x03f4, 0x1df0, 0x2207, 0x1df2, 0x2202, - 0x1df4, 0x1dfe, 0x1e00, 0x1e02, 0x1e04, 0x1e06, 0x1e08, 0x1e0a, - 0x1e0c, 0x1e0e, 0x1e16, 0x1e39, 0x1e3d, 0x1e43, 0x1e60, 0x062d, - 0x1e68, 0x1e74, 0x062c, 0x1e84, 0x1ef4, 0x1f00, 0x1f13, 0x1f25, - 0x1f38, 0x1f3a, 0x1f3e, 0x1f44, 0x1f4a, 0x1f4c, 0x1f50, 0x1f52, - 0x1f5a, 0x1f5d, 0x1f5f, 0x1f65, 0x1f67, 0x30b5, 0x1f6d, 0x1fc5, - 0x1fdb, 0x1fdf, 0x1fe1, 0x1fe6, 0x2033, 0x2044, 0x2145, 0x2155, - 0x215b, 0x2255, 0x2373, + 0x1c26, 0x1c28, 0x1c2a, 0x1c48, 0x1c4d, 0x1c52, 0x1c88, 0x1cce, + 0x1cdc, 0x1ce1, 0x1cea, 0x1cf3, 0x1d01, 0x1d06, 0x1d0b, 0x1d1d, + 0x1d2f, 0x1d38, 0x1d3d, 0x1d61, 0x1d6f, 0x1d71, 0x1d73, 0x1d93, + 0x1dae, 0x1db0, 0x1db2, 0x1db4, 0x1db6, 0x1db8, 0x1dba, 0x1dbc, + 0x1ddc, 0x1dde, 0x1de0, 0x1de2, 0x1de4, 0x1deb, 0x1ded, 0x1def, + 0x1df1, 0x1e00, 0x1e02, 0x1e04, 0x1e06, 0x1e08, 0x1e0a, 0x1e0c, + 0x1e0e, 0x1e10, 0x1e12, 0x1e14, 0x1e16, 0x1e18, 0x1e1a, 0x1e1c, + 0x1e20, 0x03f4, 0x1e22, 0x2207, 0x1e24, 0x2202, 0x1e26, 0x1e2e, + 0x03f4, 0x1e30, 0x2207, 0x1e32, 0x2202, 0x1e34, 0x1e3c, 0x03f4, + 0x1e3e, 0x2207, 0x1e40, 0x2202, 0x1e42, 0x1e4a, 0x03f4, 0x1e4c, + 0x2207, 0x1e4e, 0x2202, 0x1e50, 0x1e58, 0x03f4, 0x1e5a, 0x2207, + 0x1e5c, 0x2202, 0x1e5e, 0x1e68, 0x1e6a, 0x1e6c, 0x1e6e, 0x1e70, + 0x1e72, 0x1e74, 0x1e76, 0x1e78, 0x1e80, 0x1ea3, 0x1ea7, 0x1ead, + 0x1eca, 0x062d, 0x1ed2, 0x1ede, 0x062c, 0x1eee, 0x1f5e, 0x1f6a, + 0x1f7d, 0x1f8f, 0x1fa2, 0x1fa4, 0x1fa8, 0x1fae, 0x1fb4, 0x1fb6, + 0x1fba, 0x1fbc, 0x1fc4, 0x1fc7, 0x1fc9, 0x1fcf, 0x1fd1, 0x30b5, + 0x1fd7, 0x202f, 0x2045, 0x2049, 0x204b, 0x2050, 0x209d, 0x20ae, + 0x21af, 0x21bf, 0x21c5, 0x22bf, 0x23dd, }; -static const uint8_t unicode_decomp_data[9345] = { +static const uint8_t unicode_decomp_data[9451] = { 0x20, 0x88, 0x20, 0x84, 0x32, 0x33, 0x20, 0x81, 0x20, 0xa7, 0x31, 0x6f, 0x31, 0xd0, 0x34, 0x31, 0xd0, 0x32, 0x33, 0xd0, 0x34, 0x41, 0x80, 0x41, @@ -1934,273 +1893,286 @@ static const uint8_t unicode_decomp_data[9345] = { 0xaf, 0x00, 0xa6, 0x00, 0xa5, 0x00, 0xa9, 0x20, 0x00, 0x00, 0x02, 0x25, 0x90, 0x21, 0x91, 0x21, 0x92, 0x21, 0x93, 0x21, 0xa0, 0x25, 0xcb, 0x25, - 0xd0, 0x02, 0xd1, 0x02, 0xe6, 0x00, 0x99, 0x02, - 0x53, 0x02, 0x00, 0x00, 0xa3, 0x02, 0x66, 0xab, - 0xa5, 0x02, 0xa4, 0x02, 0x56, 0x02, 0x57, 0x02, - 0x91, 0x1d, 0x58, 0x02, 0x5e, 0x02, 0xa9, 0x02, - 0x64, 0x02, 0x62, 0x02, 0x60, 0x02, 0x9b, 0x02, - 0x27, 0x01, 0x9c, 0x02, 0x67, 0x02, 0x84, 0x02, - 0xaa, 0x02, 0xab, 0x02, 0x6c, 0x02, 0x04, 0xdf, - 0x8e, 0xa7, 0x6e, 0x02, 0x05, 0xdf, 0x8e, 0x02, - 0x06, 0xdf, 0xf8, 0x00, 0x76, 0x02, 0x77, 0x02, - 0x71, 0x00, 0x7a, 0x02, 0x08, 0xdf, 0x7d, 0x02, - 0x7e, 0x02, 0x80, 0x02, 0xa8, 0x02, 0xa6, 0x02, - 0x67, 0xab, 0xa7, 0x02, 0x88, 0x02, 0x71, 0x2c, - 0x00, 0x00, 0x8f, 0x02, 0xa1, 0x02, 0xa2, 0x02, - 0x98, 0x02, 0xc0, 0x01, 0xc1, 0x01, 0xc2, 0x01, - 0x0a, 0xdf, 0x1e, 0xdf, 0x41, 0x04, 0x40, 0x00, - 0x00, 0x00, 0x00, 0x14, 0x99, 0x10, 0xba, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x9b, 0x10, 0xba, 0x10, - 0x05, 0x05, 0xa5, 0x10, 0xba, 0x10, 0x05, 0x31, - 0x11, 0x27, 0x11, 0x32, 0x11, 0x27, 0x11, 0x55, - 0x47, 0x13, 0x3e, 0x13, 0x47, 0x13, 0x57, 0x13, - 0x55, 0xb9, 0x14, 0xba, 0x14, 0xb9, 0x14, 0xb0, - 0x14, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x14, 0xbd, - 0x14, 0x55, 0x50, 0xb8, 0x15, 0xaf, 0x15, 0xb9, - 0x15, 0xaf, 0x15, 0x55, 0x35, 0x19, 0x30, 0x19, - 0x05, 0x57, 0xd1, 0x65, 0xd1, 0x58, 0xd1, 0x65, - 0xd1, 0x5f, 0xd1, 0x6e, 0xd1, 0x5f, 0xd1, 0x6f, - 0xd1, 0x5f, 0xd1, 0x70, 0xd1, 0x5f, 0xd1, 0x71, - 0xd1, 0x5f, 0xd1, 0x72, 0xd1, 0x55, 0x55, 0x55, - 0x05, 0xb9, 0xd1, 0x65, 0xd1, 0xba, 0xd1, 0x65, - 0xd1, 0xbb, 0xd1, 0x6e, 0xd1, 0xbc, 0xd1, 0x6e, - 0xd1, 0xbb, 0xd1, 0x6f, 0xd1, 0xbc, 0xd1, 0x6f, - 0xd1, 0x55, 0x55, 0x55, 0x41, 0x00, 0x61, 0x00, - 0x41, 0x00, 0x61, 0x00, 0x69, 0x00, 0x41, 0x00, - 0x61, 0x00, 0x41, 0x00, 0x43, 0x44, 0x00, 0x00, - 0x47, 0x00, 0x00, 0x4a, 0x4b, 0x00, 0x00, 0x4e, - 0x4f, 0x50, 0x51, 0x00, 0x53, 0x54, 0x55, 0x56, - 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, - 0x00, 0x66, 0x68, 0x00, 0x70, 0x00, 0x41, 0x00, - 0x61, 0x00, 0x41, 0x42, 0x00, 0x44, 0x45, 0x46, - 0x47, 0x4a, 0x00, 0x53, 0x00, 0x61, 0x00, 0x41, - 0x42, 0x00, 0x44, 0x45, 0x46, 0x47, 0x00, 0x49, - 0x4a, 0x4b, 0x4c, 0x4d, 0x00, 0x4f, 0x53, 0x00, - 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, - 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, - 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, - 0x61, 0x00, 0x31, 0x01, 0x37, 0x02, 0x91, 0x03, + 0xd2, 0x05, 0x07, 0x03, 0x01, 0xda, 0x05, 0x07, + 0x03, 0x01, 0xd0, 0x02, 0xd1, 0x02, 0xe6, 0x00, + 0x99, 0x02, 0x53, 0x02, 0x00, 0x00, 0xa3, 0x02, + 0x66, 0xab, 0xa5, 0x02, 0xa4, 0x02, 0x56, 0x02, + 0x57, 0x02, 0x91, 0x1d, 0x58, 0x02, 0x5e, 0x02, + 0xa9, 0x02, 0x64, 0x02, 0x62, 0x02, 0x60, 0x02, + 0x9b, 0x02, 0x27, 0x01, 0x9c, 0x02, 0x67, 0x02, + 0x84, 0x02, 0xaa, 0x02, 0xab, 0x02, 0x6c, 0x02, + 0x04, 0xdf, 0x8e, 0xa7, 0x6e, 0x02, 0x05, 0xdf, + 0x8e, 0x02, 0x06, 0xdf, 0xf8, 0x00, 0x76, 0x02, + 0x77, 0x02, 0x71, 0x00, 0x7a, 0x02, 0x08, 0xdf, + 0x7d, 0x02, 0x7e, 0x02, 0x80, 0x02, 0xa8, 0x02, + 0xa6, 0x02, 0x67, 0xab, 0xa7, 0x02, 0x88, 0x02, + 0x71, 0x2c, 0x00, 0x00, 0x8f, 0x02, 0xa1, 0x02, + 0xa2, 0x02, 0x98, 0x02, 0xc0, 0x01, 0xc1, 0x01, + 0xc2, 0x01, 0x0a, 0xdf, 0x1e, 0xdf, 0x41, 0x04, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x14, 0x99, 0x10, + 0xba, 0x10, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x10, + 0xba, 0x10, 0x05, 0x05, 0xa5, 0x10, 0xba, 0x10, + 0x05, 0x31, 0x11, 0x27, 0x11, 0x32, 0x11, 0x27, + 0x11, 0x55, 0x47, 0x13, 0x3e, 0x13, 0x47, 0x13, + 0x57, 0x13, 0x55, 0x82, 0x13, 0xc9, 0x13, 0x00, + 0x00, 0x00, 0x00, 0x84, 0x13, 0xbb, 0x13, 0x05, + 0x05, 0x8b, 0x13, 0xc2, 0x13, 0x05, 0x90, 0x13, + 0xc9, 0x13, 0x05, 0xc2, 0x13, 0xc2, 0x13, 0x00, + 0x00, 0x00, 0x00, 0xc2, 0x13, 0xb8, 0x13, 0xc2, + 0x13, 0xc9, 0x13, 0x05, 0x55, 0xb9, 0x14, 0xba, + 0x14, 0xb9, 0x14, 0xb0, 0x14, 0x00, 0x00, 0x00, + 0x00, 0xb9, 0x14, 0xbd, 0x14, 0x55, 0x50, 0xb8, + 0x15, 0xaf, 0x15, 0xb9, 0x15, 0xaf, 0x15, 0x55, + 0x35, 0x19, 0x30, 0x19, 0x05, 0x1e, 0x61, 0x1e, + 0x61, 0x1e, 0x61, 0x29, 0x61, 0x1e, 0x61, 0x1f, + 0x61, 0x29, 0x61, 0x1f, 0x61, 0x1e, 0x61, 0x20, + 0x61, 0x21, 0x61, 0x1f, 0x61, 0x22, 0x61, 0x1f, + 0x61, 0x21, 0x61, 0x20, 0x61, 0x55, 0x55, 0x55, + 0x55, 0x67, 0x6d, 0x67, 0x6d, 0x63, 0x6d, 0x67, + 0x6d, 0x69, 0x6d, 0x67, 0x6d, 0x55, 0x05, 0x41, + 0x00, 0x30, 0x00, 0x57, 0xd1, 0x65, 0xd1, 0x58, + 0xd1, 0x65, 0xd1, 0x5f, 0xd1, 0x6e, 0xd1, 0x5f, + 0xd1, 0x6f, 0xd1, 0x5f, 0xd1, 0x70, 0xd1, 0x5f, + 0xd1, 0x71, 0xd1, 0x5f, 0xd1, 0x72, 0xd1, 0x55, + 0x55, 0x55, 0x05, 0xb9, 0xd1, 0x65, 0xd1, 0xba, + 0xd1, 0x65, 0xd1, 0xbb, 0xd1, 0x6e, 0xd1, 0xbc, + 0xd1, 0x6e, 0xd1, 0xbb, 0xd1, 0x6f, 0xd1, 0xbc, + 0xd1, 0x6f, 0xd1, 0x55, 0x55, 0x55, 0x41, 0x00, + 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x69, 0x00, + 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x43, 0x44, + 0x00, 0x00, 0x47, 0x00, 0x00, 0x4a, 0x4b, 0x00, + 0x00, 0x4e, 0x4f, 0x50, 0x51, 0x00, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, + 0x63, 0x64, 0x00, 0x66, 0x68, 0x00, 0x70, 0x00, + 0x41, 0x00, 0x61, 0x00, 0x41, 0x42, 0x00, 0x44, + 0x45, 0x46, 0x47, 0x4a, 0x00, 0x53, 0x00, 0x61, + 0x00, 0x41, 0x42, 0x00, 0x44, 0x45, 0x46, 0x47, + 0x00, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x00, 0x4f, + 0x53, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, + 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, + 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, + 0x41, 0x00, 0x61, 0x00, 0x31, 0x01, 0x37, 0x02, + 0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, + 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, 0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, 0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, 0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, 0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, - 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, 0x91, 0x03, - 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00, - 0x1f, 0x04, 0x20, 0x05, 0x0b, 0x0c, 0x30, 0x00, + 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, 0x0b, 0x0c, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, - 0x30, 0x04, 0x3a, 0x04, 0x3e, 0x04, 0x4b, 0x04, - 0x4d, 0x04, 0x4e, 0x04, 0x89, 0xa6, 0x30, 0x04, - 0xa9, 0x26, 0x28, 0xb9, 0x7f, 0x9f, 0x00, 0x01, - 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0a, - 0x0b, 0x0e, 0x0f, 0x11, 0x13, 0x14, 0x15, 0x16, - 0x17, 0x18, 0x1a, 0x1b, 0x61, 0x26, 0x25, 0x2f, - 0x7b, 0x51, 0xa6, 0xb1, 0x04, 0x27, 0x06, 0x00, - 0x01, 0x05, 0x08, 0x2a, 0x06, 0x1e, 0x08, 0x03, - 0x0d, 0x20, 0x19, 0x1a, 0x1b, 0x1c, 0x09, 0x0f, - 0x17, 0x0b, 0x18, 0x07, 0x0a, 0x00, 0x01, 0x04, - 0x06, 0x0c, 0x0e, 0x10, 0x44, 0x90, 0x77, 0x45, - 0x28, 0x06, 0x2c, 0x06, 0x00, 0x00, 0x47, 0x06, - 0x33, 0x06, 0x17, 0x10, 0x11, 0x12, 0x13, 0x00, - 0x06, 0x0e, 0x02, 0x0f, 0x34, 0x06, 0x2a, 0x06, - 0x2b, 0x06, 0x2e, 0x06, 0x00, 0x00, 0x36, 0x06, - 0x00, 0x00, 0x3a, 0x06, 0x2d, 0x06, 0x00, 0x00, - 0x4a, 0x06, 0x00, 0x00, 0x44, 0x06, 0x00, 0x00, - 0x46, 0x06, 0x33, 0x06, 0x39, 0x06, 0x00, 0x00, - 0x35, 0x06, 0x42, 0x06, 0x00, 0x00, 0x34, 0x06, - 0x00, 0x00, 0x00, 0x00, 0x2e, 0x06, 0x00, 0x00, - 0x36, 0x06, 0x00, 0x00, 0x3a, 0x06, 0x00, 0x00, - 0xba, 0x06, 0x00, 0x00, 0x6f, 0x06, 0x00, 0x00, - 0x28, 0x06, 0x2c, 0x06, 0x00, 0x00, 0x47, 0x06, - 0x00, 0x00, 0x00, 0x00, 0x2d, 0x06, 0x37, 0x06, - 0x4a, 0x06, 0x43, 0x06, 0x00, 0x00, 0x45, 0x06, - 0x46, 0x06, 0x33, 0x06, 0x39, 0x06, 0x41, 0x06, - 0x35, 0x06, 0x42, 0x06, 0x00, 0x00, 0x34, 0x06, + 0x30, 0x00, 0x30, 0x04, 0x3a, 0x04, 0x3e, 0x04, + 0x4b, 0x04, 0x4d, 0x04, 0x4e, 0x04, 0x89, 0xa6, + 0x30, 0x04, 0xa9, 0x26, 0x28, 0xb9, 0x7f, 0x9f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x0a, 0x0b, 0x0e, 0x0f, 0x11, 0x13, 0x14, + 0x15, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x61, 0x26, + 0x25, 0x2f, 0x7b, 0x51, 0xa6, 0xb1, 0x04, 0x27, + 0x06, 0x00, 0x01, 0x05, 0x08, 0x2a, 0x06, 0x1e, + 0x08, 0x03, 0x0d, 0x20, 0x19, 0x1a, 0x1b, 0x1c, + 0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07, 0x0a, 0x00, + 0x01, 0x04, 0x06, 0x0c, 0x0e, 0x10, 0x44, 0x90, + 0x77, 0x45, 0x28, 0x06, 0x2c, 0x06, 0x00, 0x00, + 0x47, 0x06, 0x33, 0x06, 0x17, 0x10, 0x11, 0x12, + 0x13, 0x00, 0x06, 0x0e, 0x02, 0x0f, 0x34, 0x06, 0x2a, 0x06, 0x2b, 0x06, 0x2e, 0x06, 0x00, 0x00, - 0x36, 0x06, 0x38, 0x06, 0x3a, 0x06, 0x6e, 0x06, - 0x00, 0x00, 0xa1, 0x06, 0x27, 0x06, 0x00, 0x01, - 0x05, 0x08, 0x20, 0x21, 0x0b, 0x06, 0x10, 0x23, - 0x2a, 0x06, 0x1a, 0x1b, 0x1c, 0x09, 0x0f, 0x17, - 0x0b, 0x18, 0x07, 0x0a, 0x00, 0x01, 0x04, 0x06, - 0x0c, 0x0e, 0x10, 0x28, 0x06, 0x2c, 0x06, 0x2f, - 0x06, 0x00, 0x00, 0x48, 0x06, 0x32, 0x06, 0x2d, - 0x06, 0x37, 0x06, 0x4a, 0x06, 0x2a, 0x06, 0x1a, - 0x1b, 0x1c, 0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07, - 0x0a, 0x00, 0x01, 0x04, 0x06, 0x0c, 0x0e, 0x10, - 0x30, 0x2e, 0x30, 0x00, 0x2c, 0x00, 0x28, 0x00, - 0x41, 0x00, 0x29, 0x00, 0x14, 0x30, 0x53, 0x00, - 0x15, 0x30, 0x43, 0x52, 0x43, 0x44, 0x57, 0x5a, - 0x41, 0x00, 0x48, 0x56, 0x4d, 0x56, 0x53, 0x44, - 0x53, 0x53, 0x50, 0x50, 0x56, 0x57, 0x43, 0x4d, - 0x43, 0x4d, 0x44, 0x4d, 0x52, 0x44, 0x4a, 0x4b, - 0x30, 0x30, 0x00, 0x68, 0x68, 0x4b, 0x62, 0x57, - 0x5b, 0xcc, 0x53, 0xc7, 0x30, 0x8c, 0x4e, 0x1a, - 0x59, 0xe3, 0x89, 0x29, 0x59, 0xa4, 0x4e, 0x20, - 0x66, 0x21, 0x71, 0x99, 0x65, 0x4d, 0x52, 0x8c, - 0x5f, 0x8d, 0x51, 0xb0, 0x65, 0x1d, 0x52, 0x42, - 0x7d, 0x1f, 0x75, 0xa9, 0x8c, 0xf0, 0x58, 0x39, - 0x54, 0x14, 0x6f, 0x95, 0x62, 0x55, 0x63, 0x00, - 0x4e, 0x09, 0x4e, 0x4a, 0x90, 0xe6, 0x5d, 0x2d, - 0x4e, 0xf3, 0x53, 0x07, 0x63, 0x70, 0x8d, 0x53, - 0x62, 0x81, 0x79, 0x7a, 0x7a, 0x08, 0x54, 0x80, - 0x6e, 0x09, 0x67, 0x08, 0x67, 0x33, 0x75, 0x72, - 0x52, 0xb6, 0x55, 0x4d, 0x91, 0x14, 0x30, 0x15, - 0x30, 0x2c, 0x67, 0x09, 0x4e, 0x8c, 0x4e, 0x89, - 0x5b, 0xb9, 0x70, 0x53, 0x62, 0xd7, 0x76, 0xdd, - 0x52, 0x57, 0x65, 0x97, 0x5f, 0xef, 0x53, 0x30, - 0x00, 0x38, 0x4e, 0x05, 0x00, 0x09, 0x22, 0x01, - 0x60, 0x4f, 0xae, 0x4f, 0xbb, 0x4f, 0x02, 0x50, - 0x7a, 0x50, 0x99, 0x50, 0xe7, 0x50, 0xcf, 0x50, - 0x9e, 0x34, 0x3a, 0x06, 0x4d, 0x51, 0x54, 0x51, - 0x64, 0x51, 0x77, 0x51, 0x1c, 0x05, 0xb9, 0x34, - 0x67, 0x51, 0x8d, 0x51, 0x4b, 0x05, 0x97, 0x51, - 0xa4, 0x51, 0xcc, 0x4e, 0xac, 0x51, 0xb5, 0x51, - 0xdf, 0x91, 0xf5, 0x51, 0x03, 0x52, 0xdf, 0x34, - 0x3b, 0x52, 0x46, 0x52, 0x72, 0x52, 0x77, 0x52, - 0x15, 0x35, 0x02, 0x00, 0x20, 0x80, 0x80, 0x00, - 0x08, 0x00, 0x00, 0xc7, 0x52, 0x00, 0x02, 0x1d, - 0x33, 0x3e, 0x3f, 0x50, 0x82, 0x8a, 0x93, 0xac, - 0xb6, 0xb8, 0xb8, 0xb8, 0x2c, 0x0a, 0x70, 0x70, - 0xca, 0x53, 0xdf, 0x53, 0x63, 0x0b, 0xeb, 0x53, - 0xf1, 0x53, 0x06, 0x54, 0x9e, 0x54, 0x38, 0x54, - 0x48, 0x54, 0x68, 0x54, 0xa2, 0x54, 0xf6, 0x54, - 0x10, 0x55, 0x53, 0x55, 0x63, 0x55, 0x84, 0x55, - 0x84, 0x55, 0x99, 0x55, 0xab, 0x55, 0xb3, 0x55, - 0xc2, 0x55, 0x16, 0x57, 0x06, 0x56, 0x17, 0x57, - 0x51, 0x56, 0x74, 0x56, 0x07, 0x52, 0xee, 0x58, - 0xce, 0x57, 0xf4, 0x57, 0x0d, 0x58, 0x8b, 0x57, - 0x32, 0x58, 0x31, 0x58, 0xac, 0x58, 0xe4, 0x14, - 0xf2, 0x58, 0xf7, 0x58, 0x06, 0x59, 0x1a, 0x59, - 0x22, 0x59, 0x62, 0x59, 0xa8, 0x16, 0xea, 0x16, - 0xec, 0x59, 0x1b, 0x5a, 0x27, 0x5a, 0xd8, 0x59, - 0x66, 0x5a, 0xee, 0x36, 0xfc, 0x36, 0x08, 0x5b, - 0x3e, 0x5b, 0x3e, 0x5b, 0xc8, 0x19, 0xc3, 0x5b, - 0xd8, 0x5b, 0xe7, 0x5b, 0xf3, 0x5b, 0x18, 0x1b, - 0xff, 0x5b, 0x06, 0x5c, 0x53, 0x5f, 0x22, 0x5c, - 0x81, 0x37, 0x60, 0x5c, 0x6e, 0x5c, 0xc0, 0x5c, - 0x8d, 0x5c, 0xe4, 0x1d, 0x43, 0x5d, 0xe6, 0x1d, - 0x6e, 0x5d, 0x6b, 0x5d, 0x7c, 0x5d, 0xe1, 0x5d, - 0xe2, 0x5d, 0x2f, 0x38, 0xfd, 0x5d, 0x28, 0x5e, - 0x3d, 0x5e, 0x69, 0x5e, 0x62, 0x38, 0x83, 0x21, - 0x7c, 0x38, 0xb0, 0x5e, 0xb3, 0x5e, 0xb6, 0x5e, - 0xca, 0x5e, 0x92, 0xa3, 0xfe, 0x5e, 0x31, 0x23, - 0x31, 0x23, 0x01, 0x82, 0x22, 0x5f, 0x22, 0x5f, - 0xc7, 0x38, 0xb8, 0x32, 0xda, 0x61, 0x62, 0x5f, - 0x6b, 0x5f, 0xe3, 0x38, 0x9a, 0x5f, 0xcd, 0x5f, - 0xd7, 0x5f, 0xf9, 0x5f, 0x81, 0x60, 0x3a, 0x39, - 0x1c, 0x39, 0x94, 0x60, 0xd4, 0x26, 0xc7, 0x60, - 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x08, 0x00, 0x0a, 0x00, 0x00, 0x02, 0x08, - 0x00, 0x80, 0x08, 0x00, 0x00, 0x08, 0x80, 0x28, - 0x80, 0x02, 0x00, 0x00, 0x02, 0x48, 0x61, 0x00, - 0x04, 0x06, 0x04, 0x32, 0x46, 0x6a, 0x5c, 0x67, - 0x96, 0xaa, 0xae, 0xc8, 0xd3, 0x5d, 0x62, 0x00, - 0x54, 0x77, 0xf3, 0x0c, 0x2b, 0x3d, 0x63, 0xfc, - 0x62, 0x68, 0x63, 0x83, 0x63, 0xe4, 0x63, 0xf1, - 0x2b, 0x22, 0x64, 0xc5, 0x63, 0xa9, 0x63, 0x2e, - 0x3a, 0x69, 0x64, 0x7e, 0x64, 0x9d, 0x64, 0x77, - 0x64, 0x6c, 0x3a, 0x4f, 0x65, 0x6c, 0x65, 0x0a, - 0x30, 0xe3, 0x65, 0xf8, 0x66, 0x49, 0x66, 0x19, - 0x3b, 0x91, 0x66, 0x08, 0x3b, 0xe4, 0x3a, 0x92, - 0x51, 0x95, 0x51, 0x00, 0x67, 0x9c, 0x66, 0xad, - 0x80, 0xd9, 0x43, 0x17, 0x67, 0x1b, 0x67, 0x21, - 0x67, 0x5e, 0x67, 0x53, 0x67, 0xc3, 0x33, 0x49, - 0x3b, 0xfa, 0x67, 0x85, 0x67, 0x52, 0x68, 0x85, - 0x68, 0x6d, 0x34, 0x8e, 0x68, 0x1f, 0x68, 0x14, - 0x69, 0x9d, 0x3b, 0x42, 0x69, 0xa3, 0x69, 0xea, - 0x69, 0xa8, 0x6a, 0xa3, 0x36, 0xdb, 0x6a, 0x18, - 0x3c, 0x21, 0x6b, 0xa7, 0x38, 0x54, 0x6b, 0x4e, - 0x3c, 0x72, 0x6b, 0x9f, 0x6b, 0xba, 0x6b, 0xbb, - 0x6b, 0x8d, 0x3a, 0x0b, 0x1d, 0xfa, 0x3a, 0x4e, - 0x6c, 0xbc, 0x3c, 0xbf, 0x6c, 0xcd, 0x6c, 0x67, - 0x6c, 0x16, 0x6d, 0x3e, 0x6d, 0x77, 0x6d, 0x41, - 0x6d, 0x69, 0x6d, 0x78, 0x6d, 0x85, 0x6d, 0x1e, - 0x3d, 0x34, 0x6d, 0x2f, 0x6e, 0x6e, 0x6e, 0x33, - 0x3d, 0xcb, 0x6e, 0xc7, 0x6e, 0xd1, 0x3e, 0xf9, - 0x6d, 0x6e, 0x6f, 0x5e, 0x3f, 0x8e, 0x3f, 0xc6, - 0x6f, 0x39, 0x70, 0x1e, 0x70, 0x1b, 0x70, 0x96, - 0x3d, 0x4a, 0x70, 0x7d, 0x70, 0x77, 0x70, 0xad, - 0x70, 0x25, 0x05, 0x45, 0x71, 0x63, 0x42, 0x9c, - 0x71, 0xab, 0x43, 0x28, 0x72, 0x35, 0x72, 0x50, - 0x72, 0x08, 0x46, 0x80, 0x72, 0x95, 0x72, 0x35, - 0x47, 0x02, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, - 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x02, 0x02, - 0x80, 0x8a, 0x00, 0x00, 0x20, 0x00, 0x08, 0x0a, - 0x00, 0x80, 0x88, 0x80, 0x20, 0x14, 0x48, 0x7a, - 0x73, 0x8b, 0x73, 0xac, 0x3e, 0xa5, 0x73, 0xb8, - 0x3e, 0xb8, 0x3e, 0x47, 0x74, 0x5c, 0x74, 0x71, - 0x74, 0x85, 0x74, 0xca, 0x74, 0x1b, 0x3f, 0x24, - 0x75, 0x36, 0x4c, 0x3e, 0x75, 0x92, 0x4c, 0x70, - 0x75, 0x9f, 0x21, 0x10, 0x76, 0xa1, 0x4f, 0xb8, - 0x4f, 0x44, 0x50, 0xfc, 0x3f, 0x08, 0x40, 0xf4, - 0x76, 0xf3, 0x50, 0xf2, 0x50, 0x19, 0x51, 0x33, - 0x51, 0x1e, 0x77, 0x1f, 0x77, 0x1f, 0x77, 0x4a, - 0x77, 0x39, 0x40, 0x8b, 0x77, 0x46, 0x40, 0x96, - 0x40, 0x1d, 0x54, 0x4e, 0x78, 0x8c, 0x78, 0xcc, - 0x78, 0xe3, 0x40, 0x26, 0x56, 0x56, 0x79, 0x9a, - 0x56, 0xc5, 0x56, 0x8f, 0x79, 0xeb, 0x79, 0x2f, - 0x41, 0x40, 0x7a, 0x4a, 0x7a, 0x4f, 0x7a, 0x7c, - 0x59, 0xa7, 0x5a, 0xa7, 0x5a, 0xee, 0x7a, 0x02, - 0x42, 0xab, 0x5b, 0xc6, 0x7b, 0xc9, 0x7b, 0x27, - 0x42, 0x80, 0x5c, 0xd2, 0x7c, 0xa0, 0x42, 0xe8, - 0x7c, 0xe3, 0x7c, 0x00, 0x7d, 0x86, 0x5f, 0x63, - 0x7d, 0x01, 0x43, 0xc7, 0x7d, 0x02, 0x7e, 0x45, - 0x7e, 0x34, 0x43, 0x28, 0x62, 0x47, 0x62, 0x59, - 0x43, 0xd9, 0x62, 0x7a, 0x7f, 0x3e, 0x63, 0x95, - 0x7f, 0xfa, 0x7f, 0x05, 0x80, 0xda, 0x64, 0x23, - 0x65, 0x60, 0x80, 0xa8, 0x65, 0x70, 0x80, 0x5f, - 0x33, 0xd5, 0x43, 0xb2, 0x80, 0x03, 0x81, 0x0b, - 0x44, 0x3e, 0x81, 0xb5, 0x5a, 0xa7, 0x67, 0xb5, - 0x67, 0x93, 0x33, 0x9c, 0x33, 0x01, 0x82, 0x04, - 0x82, 0x9e, 0x8f, 0x6b, 0x44, 0x91, 0x82, 0x8b, - 0x82, 0x9d, 0x82, 0xb3, 0x52, 0xb1, 0x82, 0xb3, - 0x82, 0xbd, 0x82, 0xe6, 0x82, 0x3c, 0x6b, 0xe5, - 0x82, 0x1d, 0x83, 0x63, 0x83, 0xad, 0x83, 0x23, - 0x83, 0xbd, 0x83, 0xe7, 0x83, 0x57, 0x84, 0x53, - 0x83, 0xca, 0x83, 0xcc, 0x83, 0xdc, 0x83, 0x36, - 0x6c, 0x6b, 0x6d, 0x02, 0x00, 0x00, 0x20, 0x22, - 0x2a, 0xa0, 0x0a, 0x00, 0x20, 0x80, 0x28, 0x00, - 0xa8, 0x20, 0x20, 0x00, 0x02, 0x80, 0x22, 0x02, - 0x8a, 0x08, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x28, 0xd5, 0x6c, 0x2b, 0x45, 0xf1, - 0x84, 0xf3, 0x84, 0x16, 0x85, 0xca, 0x73, 0x64, - 0x85, 0x2c, 0x6f, 0x5d, 0x45, 0x61, 0x45, 0xb1, - 0x6f, 0xd2, 0x70, 0x6b, 0x45, 0x50, 0x86, 0x5c, - 0x86, 0x67, 0x86, 0x69, 0x86, 0xa9, 0x86, 0x88, - 0x86, 0x0e, 0x87, 0xe2, 0x86, 0x79, 0x87, 0x28, - 0x87, 0x6b, 0x87, 0x86, 0x87, 0xd7, 0x45, 0xe1, - 0x87, 0x01, 0x88, 0xf9, 0x45, 0x60, 0x88, 0x63, - 0x88, 0x67, 0x76, 0xd7, 0x88, 0xde, 0x88, 0x35, - 0x46, 0xfa, 0x88, 0xbb, 0x34, 0xae, 0x78, 0x66, - 0x79, 0xbe, 0x46, 0xc7, 0x46, 0xa0, 0x8a, 0xed, - 0x8a, 0x8a, 0x8b, 0x55, 0x8c, 0xa8, 0x7c, 0xab, - 0x8c, 0xc1, 0x8c, 0x1b, 0x8d, 0x77, 0x8d, 0x2f, - 0x7f, 0x04, 0x08, 0xcb, 0x8d, 0xbc, 0x8d, 0xf0, - 0x8d, 0xde, 0x08, 0xd4, 0x8e, 0x38, 0x8f, 0xd2, - 0x85, 0xed, 0x85, 0x94, 0x90, 0xf1, 0x90, 0x11, - 0x91, 0x2e, 0x87, 0x1b, 0x91, 0x38, 0x92, 0xd7, - 0x92, 0xd8, 0x92, 0x7c, 0x92, 0xf9, 0x93, 0x15, - 0x94, 0xfa, 0x8b, 0x8b, 0x95, 0x95, 0x49, 0xb7, - 0x95, 0x77, 0x8d, 0xe6, 0x49, 0xc3, 0x96, 0xb2, - 0x5d, 0x23, 0x97, 0x45, 0x91, 0x1a, 0x92, 0x6e, - 0x4a, 0x76, 0x4a, 0xe0, 0x97, 0x0a, 0x94, 0xb2, - 0x4a, 0x96, 0x94, 0x0b, 0x98, 0x0b, 0x98, 0x29, - 0x98, 0xb6, 0x95, 0xe2, 0x98, 0x33, 0x4b, 0x29, - 0x99, 0xa7, 0x99, 0xc2, 0x99, 0xfe, 0x99, 0xce, - 0x4b, 0x30, 0x9b, 0x12, 0x9b, 0x40, 0x9c, 0xfd, - 0x9c, 0xce, 0x4c, 0xed, 0x4c, 0x67, 0x9d, 0xce, - 0xa0, 0xf8, 0x4c, 0x05, 0xa1, 0x0e, 0xa2, 0x91, - 0xa2, 0xbb, 0x9e, 0x56, 0x4d, 0xf9, 0x9e, 0xfe, - 0x9e, 0x05, 0x9f, 0x0f, 0x9f, 0x16, 0x9f, 0x3b, - 0x9f, 0x00, 0xa6, 0x02, 0x88, 0xa0, 0x00, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x28, 0x00, 0x08, 0xa0, - 0x80, 0xa0, 0x80, 0x00, 0x80, 0x80, 0x00, 0x0a, - 0x88, 0x80, 0x00, 0x80, 0x00, 0x20, 0x2a, 0x00, - 0x80, + 0x36, 0x06, 0x00, 0x00, 0x3a, 0x06, 0x2d, 0x06, + 0x00, 0x00, 0x4a, 0x06, 0x00, 0x00, 0x44, 0x06, + 0x00, 0x00, 0x46, 0x06, 0x33, 0x06, 0x39, 0x06, + 0x00, 0x00, 0x35, 0x06, 0x42, 0x06, 0x00, 0x00, + 0x34, 0x06, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x06, + 0x00, 0x00, 0x36, 0x06, 0x00, 0x00, 0x3a, 0x06, + 0x00, 0x00, 0xba, 0x06, 0x00, 0x00, 0x6f, 0x06, + 0x00, 0x00, 0x28, 0x06, 0x2c, 0x06, 0x00, 0x00, + 0x47, 0x06, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x06, + 0x37, 0x06, 0x4a, 0x06, 0x43, 0x06, 0x00, 0x00, + 0x45, 0x06, 0x46, 0x06, 0x33, 0x06, 0x39, 0x06, + 0x41, 0x06, 0x35, 0x06, 0x42, 0x06, 0x00, 0x00, + 0x34, 0x06, 0x2a, 0x06, 0x2b, 0x06, 0x2e, 0x06, + 0x00, 0x00, 0x36, 0x06, 0x38, 0x06, 0x3a, 0x06, + 0x6e, 0x06, 0x00, 0x00, 0xa1, 0x06, 0x27, 0x06, + 0x00, 0x01, 0x05, 0x08, 0x20, 0x21, 0x0b, 0x06, + 0x10, 0x23, 0x2a, 0x06, 0x1a, 0x1b, 0x1c, 0x09, + 0x0f, 0x17, 0x0b, 0x18, 0x07, 0x0a, 0x00, 0x01, + 0x04, 0x06, 0x0c, 0x0e, 0x10, 0x28, 0x06, 0x2c, + 0x06, 0x2f, 0x06, 0x00, 0x00, 0x48, 0x06, 0x32, + 0x06, 0x2d, 0x06, 0x37, 0x06, 0x4a, 0x06, 0x2a, + 0x06, 0x1a, 0x1b, 0x1c, 0x09, 0x0f, 0x17, 0x0b, + 0x18, 0x07, 0x0a, 0x00, 0x01, 0x04, 0x06, 0x0c, + 0x0e, 0x10, 0x30, 0x2e, 0x30, 0x00, 0x2c, 0x00, + 0x28, 0x00, 0x41, 0x00, 0x29, 0x00, 0x14, 0x30, + 0x53, 0x00, 0x15, 0x30, 0x43, 0x52, 0x43, 0x44, + 0x57, 0x5a, 0x41, 0x00, 0x48, 0x56, 0x4d, 0x56, + 0x53, 0x44, 0x53, 0x53, 0x50, 0x50, 0x56, 0x57, + 0x43, 0x4d, 0x43, 0x4d, 0x44, 0x4d, 0x52, 0x44, + 0x4a, 0x4b, 0x30, 0x30, 0x00, 0x68, 0x68, 0x4b, + 0x62, 0x57, 0x5b, 0xcc, 0x53, 0xc7, 0x30, 0x8c, + 0x4e, 0x1a, 0x59, 0xe3, 0x89, 0x29, 0x59, 0xa4, + 0x4e, 0x20, 0x66, 0x21, 0x71, 0x99, 0x65, 0x4d, + 0x52, 0x8c, 0x5f, 0x8d, 0x51, 0xb0, 0x65, 0x1d, + 0x52, 0x42, 0x7d, 0x1f, 0x75, 0xa9, 0x8c, 0xf0, + 0x58, 0x39, 0x54, 0x14, 0x6f, 0x95, 0x62, 0x55, + 0x63, 0x00, 0x4e, 0x09, 0x4e, 0x4a, 0x90, 0xe6, + 0x5d, 0x2d, 0x4e, 0xf3, 0x53, 0x07, 0x63, 0x70, + 0x8d, 0x53, 0x62, 0x81, 0x79, 0x7a, 0x7a, 0x08, + 0x54, 0x80, 0x6e, 0x09, 0x67, 0x08, 0x67, 0x33, + 0x75, 0x72, 0x52, 0xb6, 0x55, 0x4d, 0x91, 0x14, + 0x30, 0x15, 0x30, 0x2c, 0x67, 0x09, 0x4e, 0x8c, + 0x4e, 0x89, 0x5b, 0xb9, 0x70, 0x53, 0x62, 0xd7, + 0x76, 0xdd, 0x52, 0x57, 0x65, 0x97, 0x5f, 0xef, + 0x53, 0x30, 0x00, 0x38, 0x4e, 0x05, 0x00, 0x09, + 0x22, 0x01, 0x60, 0x4f, 0xae, 0x4f, 0xbb, 0x4f, + 0x02, 0x50, 0x7a, 0x50, 0x99, 0x50, 0xe7, 0x50, + 0xcf, 0x50, 0x9e, 0x34, 0x3a, 0x06, 0x4d, 0x51, + 0x54, 0x51, 0x64, 0x51, 0x77, 0x51, 0x1c, 0x05, + 0xb9, 0x34, 0x67, 0x51, 0x8d, 0x51, 0x4b, 0x05, + 0x97, 0x51, 0xa4, 0x51, 0xcc, 0x4e, 0xac, 0x51, + 0xb5, 0x51, 0xdf, 0x91, 0xf5, 0x51, 0x03, 0x52, + 0xdf, 0x34, 0x3b, 0x52, 0x46, 0x52, 0x72, 0x52, + 0x77, 0x52, 0x15, 0x35, 0x02, 0x00, 0x20, 0x80, + 0x80, 0x00, 0x08, 0x00, 0x00, 0xc7, 0x52, 0x00, + 0x02, 0x1d, 0x33, 0x3e, 0x3f, 0x50, 0x82, 0x8a, + 0x93, 0xac, 0xb6, 0xb8, 0xb8, 0xb8, 0x2c, 0x0a, + 0x70, 0x70, 0xca, 0x53, 0xdf, 0x53, 0x63, 0x0b, + 0xeb, 0x53, 0xf1, 0x53, 0x06, 0x54, 0x9e, 0x54, + 0x38, 0x54, 0x48, 0x54, 0x68, 0x54, 0xa2, 0x54, + 0xf6, 0x54, 0x10, 0x55, 0x53, 0x55, 0x63, 0x55, + 0x84, 0x55, 0x84, 0x55, 0x99, 0x55, 0xab, 0x55, + 0xb3, 0x55, 0xc2, 0x55, 0x16, 0x57, 0x06, 0x56, + 0x17, 0x57, 0x51, 0x56, 0x74, 0x56, 0x07, 0x52, + 0xee, 0x58, 0xce, 0x57, 0xf4, 0x57, 0x0d, 0x58, + 0x8b, 0x57, 0x32, 0x58, 0x31, 0x58, 0xac, 0x58, + 0xe4, 0x14, 0xf2, 0x58, 0xf7, 0x58, 0x06, 0x59, + 0x1a, 0x59, 0x22, 0x59, 0x62, 0x59, 0xa8, 0x16, + 0xea, 0x16, 0xec, 0x59, 0x1b, 0x5a, 0x27, 0x5a, + 0xd8, 0x59, 0x66, 0x5a, 0xee, 0x36, 0xfc, 0x36, + 0x08, 0x5b, 0x3e, 0x5b, 0x3e, 0x5b, 0xc8, 0x19, + 0xc3, 0x5b, 0xd8, 0x5b, 0xe7, 0x5b, 0xf3, 0x5b, + 0x18, 0x1b, 0xff, 0x5b, 0x06, 0x5c, 0x53, 0x5f, + 0x22, 0x5c, 0x81, 0x37, 0x60, 0x5c, 0x6e, 0x5c, + 0xc0, 0x5c, 0x8d, 0x5c, 0xe4, 0x1d, 0x43, 0x5d, + 0xe6, 0x1d, 0x6e, 0x5d, 0x6b, 0x5d, 0x7c, 0x5d, + 0xe1, 0x5d, 0xe2, 0x5d, 0x2f, 0x38, 0xfd, 0x5d, + 0x28, 0x5e, 0x3d, 0x5e, 0x69, 0x5e, 0x62, 0x38, + 0x83, 0x21, 0x7c, 0x38, 0xb0, 0x5e, 0xb3, 0x5e, + 0xb6, 0x5e, 0xca, 0x5e, 0x92, 0xa3, 0xfe, 0x5e, + 0x31, 0x23, 0x31, 0x23, 0x01, 0x82, 0x22, 0x5f, + 0x22, 0x5f, 0xc7, 0x38, 0xb8, 0x32, 0xda, 0x61, + 0x62, 0x5f, 0x6b, 0x5f, 0xe3, 0x38, 0x9a, 0x5f, + 0xcd, 0x5f, 0xd7, 0x5f, 0xf9, 0x5f, 0x81, 0x60, + 0x3a, 0x39, 0x1c, 0x39, 0x94, 0x60, 0xd4, 0x26, + 0xc7, 0x60, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x00, + 0x02, 0x08, 0x00, 0x80, 0x08, 0x00, 0x00, 0x08, + 0x80, 0x28, 0x80, 0x02, 0x00, 0x00, 0x02, 0x48, + 0x61, 0x00, 0x04, 0x06, 0x04, 0x32, 0x46, 0x6a, + 0x5c, 0x67, 0x96, 0xaa, 0xae, 0xc8, 0xd3, 0x5d, + 0x62, 0x00, 0x54, 0x77, 0xf3, 0x0c, 0x2b, 0x3d, + 0x63, 0xfc, 0x62, 0x68, 0x63, 0x83, 0x63, 0xe4, + 0x63, 0xf1, 0x2b, 0x22, 0x64, 0xc5, 0x63, 0xa9, + 0x63, 0x2e, 0x3a, 0x69, 0x64, 0x7e, 0x64, 0x9d, + 0x64, 0x77, 0x64, 0x6c, 0x3a, 0x4f, 0x65, 0x6c, + 0x65, 0x0a, 0x30, 0xe3, 0x65, 0xf8, 0x66, 0x49, + 0x66, 0x19, 0x3b, 0x91, 0x66, 0x08, 0x3b, 0xe4, + 0x3a, 0x92, 0x51, 0x95, 0x51, 0x00, 0x67, 0x9c, + 0x66, 0xad, 0x80, 0xd9, 0x43, 0x17, 0x67, 0x1b, + 0x67, 0x21, 0x67, 0x5e, 0x67, 0x53, 0x67, 0xc3, + 0x33, 0x49, 0x3b, 0xfa, 0x67, 0x85, 0x67, 0x52, + 0x68, 0x85, 0x68, 0x6d, 0x34, 0x8e, 0x68, 0x1f, + 0x68, 0x14, 0x69, 0x9d, 0x3b, 0x42, 0x69, 0xa3, + 0x69, 0xea, 0x69, 0xa8, 0x6a, 0xa3, 0x36, 0xdb, + 0x6a, 0x18, 0x3c, 0x21, 0x6b, 0xa7, 0x38, 0x54, + 0x6b, 0x4e, 0x3c, 0x72, 0x6b, 0x9f, 0x6b, 0xba, + 0x6b, 0xbb, 0x6b, 0x8d, 0x3a, 0x0b, 0x1d, 0xfa, + 0x3a, 0x4e, 0x6c, 0xbc, 0x3c, 0xbf, 0x6c, 0xcd, + 0x6c, 0x67, 0x6c, 0x16, 0x6d, 0x3e, 0x6d, 0x77, + 0x6d, 0x41, 0x6d, 0x69, 0x6d, 0x78, 0x6d, 0x85, + 0x6d, 0x1e, 0x3d, 0x34, 0x6d, 0x2f, 0x6e, 0x6e, + 0x6e, 0x33, 0x3d, 0xcb, 0x6e, 0xc7, 0x6e, 0xd1, + 0x3e, 0xf9, 0x6d, 0x6e, 0x6f, 0x5e, 0x3f, 0x8e, + 0x3f, 0xc6, 0x6f, 0x39, 0x70, 0x1e, 0x70, 0x1b, + 0x70, 0x96, 0x3d, 0x4a, 0x70, 0x7d, 0x70, 0x77, + 0x70, 0xad, 0x70, 0x25, 0x05, 0x45, 0x71, 0x63, + 0x42, 0x9c, 0x71, 0xab, 0x43, 0x28, 0x72, 0x35, + 0x72, 0x50, 0x72, 0x08, 0x46, 0x80, 0x72, 0x95, + 0x72, 0x35, 0x47, 0x02, 0x20, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, + 0x02, 0x02, 0x80, 0x8a, 0x00, 0x00, 0x20, 0x00, + 0x08, 0x0a, 0x00, 0x80, 0x88, 0x80, 0x20, 0x14, + 0x48, 0x7a, 0x73, 0x8b, 0x73, 0xac, 0x3e, 0xa5, + 0x73, 0xb8, 0x3e, 0xb8, 0x3e, 0x47, 0x74, 0x5c, + 0x74, 0x71, 0x74, 0x85, 0x74, 0xca, 0x74, 0x1b, + 0x3f, 0x24, 0x75, 0x36, 0x4c, 0x3e, 0x75, 0x92, + 0x4c, 0x70, 0x75, 0x9f, 0x21, 0x10, 0x76, 0xa1, + 0x4f, 0xb8, 0x4f, 0x44, 0x50, 0xfc, 0x3f, 0x08, + 0x40, 0xf4, 0x76, 0xf3, 0x50, 0xf2, 0x50, 0x19, + 0x51, 0x33, 0x51, 0x1e, 0x77, 0x1f, 0x77, 0x1f, + 0x77, 0x4a, 0x77, 0x39, 0x40, 0x8b, 0x77, 0x46, + 0x40, 0x96, 0x40, 0x1d, 0x54, 0x4e, 0x78, 0x8c, + 0x78, 0xcc, 0x78, 0xe3, 0x40, 0x26, 0x56, 0x56, + 0x79, 0x9a, 0x56, 0xc5, 0x56, 0x8f, 0x79, 0xeb, + 0x79, 0x2f, 0x41, 0x40, 0x7a, 0x4a, 0x7a, 0x4f, + 0x7a, 0x7c, 0x59, 0xa7, 0x5a, 0xa7, 0x5a, 0xee, + 0x7a, 0x02, 0x42, 0xab, 0x5b, 0xc6, 0x7b, 0xc9, + 0x7b, 0x27, 0x42, 0x80, 0x5c, 0xd2, 0x7c, 0xa0, + 0x42, 0xe8, 0x7c, 0xe3, 0x7c, 0x00, 0x7d, 0x86, + 0x5f, 0x63, 0x7d, 0x01, 0x43, 0xc7, 0x7d, 0x02, + 0x7e, 0x45, 0x7e, 0x34, 0x43, 0x28, 0x62, 0x47, + 0x62, 0x59, 0x43, 0xd9, 0x62, 0x7a, 0x7f, 0x3e, + 0x63, 0x95, 0x7f, 0xfa, 0x7f, 0x05, 0x80, 0xda, + 0x64, 0x23, 0x65, 0x60, 0x80, 0xa8, 0x65, 0x70, + 0x80, 0x5f, 0x33, 0xd5, 0x43, 0xb2, 0x80, 0x03, + 0x81, 0x0b, 0x44, 0x3e, 0x81, 0xb5, 0x5a, 0xa7, + 0x67, 0xb5, 0x67, 0x93, 0x33, 0x9c, 0x33, 0x01, + 0x82, 0x04, 0x82, 0x9e, 0x8f, 0x6b, 0x44, 0x91, + 0x82, 0x8b, 0x82, 0x9d, 0x82, 0xb3, 0x52, 0xb1, + 0x82, 0xb3, 0x82, 0xbd, 0x82, 0xe6, 0x82, 0x3c, + 0x6b, 0xe5, 0x82, 0x1d, 0x83, 0x63, 0x83, 0xad, + 0x83, 0x23, 0x83, 0xbd, 0x83, 0xe7, 0x83, 0x57, + 0x84, 0x53, 0x83, 0xca, 0x83, 0xcc, 0x83, 0xdc, + 0x83, 0x36, 0x6c, 0x6b, 0x6d, 0x02, 0x00, 0x00, + 0x20, 0x22, 0x2a, 0xa0, 0x0a, 0x00, 0x20, 0x80, + 0x28, 0x00, 0xa8, 0x20, 0x20, 0x00, 0x02, 0x80, + 0x22, 0x02, 0x8a, 0x08, 0x00, 0xaa, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x28, 0xd5, 0x6c, 0x2b, + 0x45, 0xf1, 0x84, 0xf3, 0x84, 0x16, 0x85, 0xca, + 0x73, 0x64, 0x85, 0x2c, 0x6f, 0x5d, 0x45, 0x61, + 0x45, 0xb1, 0x6f, 0xd2, 0x70, 0x6b, 0x45, 0x50, + 0x86, 0x5c, 0x86, 0x67, 0x86, 0x69, 0x86, 0xa9, + 0x86, 0x88, 0x86, 0x0e, 0x87, 0xe2, 0x86, 0x79, + 0x87, 0x28, 0x87, 0x6b, 0x87, 0x86, 0x87, 0xd7, + 0x45, 0xe1, 0x87, 0x01, 0x88, 0xf9, 0x45, 0x60, + 0x88, 0x63, 0x88, 0x67, 0x76, 0xd7, 0x88, 0xde, + 0x88, 0x35, 0x46, 0xfa, 0x88, 0xbb, 0x34, 0xae, + 0x78, 0x66, 0x79, 0xbe, 0x46, 0xc7, 0x46, 0xa0, + 0x8a, 0xed, 0x8a, 0x8a, 0x8b, 0x55, 0x8c, 0xa8, + 0x7c, 0xab, 0x8c, 0xc1, 0x8c, 0x1b, 0x8d, 0x77, + 0x8d, 0x2f, 0x7f, 0x04, 0x08, 0xcb, 0x8d, 0xbc, + 0x8d, 0xf0, 0x8d, 0xde, 0x08, 0xd4, 0x8e, 0x38, + 0x8f, 0xd2, 0x85, 0xed, 0x85, 0x94, 0x90, 0xf1, + 0x90, 0x11, 0x91, 0x2e, 0x87, 0x1b, 0x91, 0x38, + 0x92, 0xd7, 0x92, 0xd8, 0x92, 0x7c, 0x92, 0xf9, + 0x93, 0x15, 0x94, 0xfa, 0x8b, 0x8b, 0x95, 0x95, + 0x49, 0xb7, 0x95, 0x77, 0x8d, 0xe6, 0x49, 0xc3, + 0x96, 0xb2, 0x5d, 0x23, 0x97, 0x45, 0x91, 0x1a, + 0x92, 0x6e, 0x4a, 0x76, 0x4a, 0xe0, 0x97, 0x0a, + 0x94, 0xb2, 0x4a, 0x96, 0x94, 0x0b, 0x98, 0x0b, + 0x98, 0x29, 0x98, 0xb6, 0x95, 0xe2, 0x98, 0x33, + 0x4b, 0x29, 0x99, 0xa7, 0x99, 0xc2, 0x99, 0xfe, + 0x99, 0xce, 0x4b, 0x30, 0x9b, 0x12, 0x9b, 0x40, + 0x9c, 0xfd, 0x9c, 0xce, 0x4c, 0xed, 0x4c, 0x67, + 0x9d, 0xce, 0xa0, 0xf8, 0x4c, 0x05, 0xa1, 0x0e, + 0xa2, 0x91, 0xa2, 0xbb, 0x9e, 0x56, 0x4d, 0xf9, + 0x9e, 0xfe, 0x9e, 0x05, 0x9f, 0x0f, 0x9f, 0x16, + 0x9f, 0x3b, 0x9f, 0x00, 0xa6, 0x02, 0x88, 0xa0, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x28, 0x00, + 0x08, 0xa0, 0x80, 0xa0, 0x80, 0x00, 0x80, 0x80, + 0x00, 0x0a, 0x88, 0x80, 0x00, 0x80, 0x00, 0x20, + 0x2a, 0x00, 0x80, }; -static const uint16_t unicode_comp_table[945] = { +static const uint16_t unicode_comp_table[965] = { 0x4a01, 0x49c0, 0x4a02, 0x0280, 0x0281, 0x0282, 0x0283, 0x02c0, 0x02c2, 0x0a00, 0x0284, 0x2442, 0x0285, 0x07c0, 0x0980, 0x0982, 0x2440, 0x2280, 0x02c4, 0x2282, 0x2284, 0x2286, 0x02c6, 0x02c8, @@ -2317,9 +2289,11 @@ static const uint16_t unicode_comp_table[945] = { 0x5704, 0x5706, 0x5708, 0x570a, 0x570c, 0x570e, 0x5710, 0x5712, 0x5714, 0x5716, 0x5740, 0x5742, 0x5744, 0x5780, 0x5781, 0x57c0, 0x57c1, 0x5800, 0x5801, 0x5840, 0x5841, 0x5880, 0x5881, 0x5900, - 0x5901, 0x5902, 0x5903, 0x5940, 0x8f40, 0x8f42, 0x8f80, 0x8fc0, - 0x8fc1, 0x9000, 0x9001, 0x9041, 0x9040, 0x9043, 0x9080, 0x9081, - 0x90c0, + 0x5901, 0x5902, 0x5903, 0x5940, 0x8ec0, 0x8f00, 0x8fc0, 0x8fc2, + 0x9000, 0x9040, 0x9041, 0x9080, 0x9081, 0x90c0, 0x90c2, 0x9100, + 0x9140, 0x9182, 0x9180, 0x9183, 0x91c1, 0x91c0, 0x91c3, 0x9200, + 0x9201, 0x9240, 0x9280, 0x9282, 0x9284, 0x9281, 0x9285, 0x9287, + 0x9286, 0x9283, 0x92c1, 0x92c0, 0x92c2, }; typedef enum { @@ -2405,7 +2379,7 @@ static const char unicode_gc_name_table[] = "C,Other" "\0" ; -static const uint8_t unicode_gc_table[3948] = { +static const uint8_t unicode_gc_table[4070] = { 0xfa, 0x18, 0x17, 0x56, 0x0d, 0x56, 0x12, 0x13, 0x16, 0x0c, 0x16, 0x11, 0x36, 0xe9, 0x02, 0x36, 0x4c, 0x36, 0xe1, 0x12, 0x12, 0x16, 0x13, 0x0e, @@ -2449,8 +2423,8 @@ static const uint8_t unicode_gc_table[3948] = { 0x2d, 0xe5, 0x0e, 0x66, 0x04, 0xe6, 0x01, 0x04, 0x46, 0x04, 0x86, 0x20, 0xf6, 0x07, 0x00, 0xe5, 0x11, 0x46, 0x20, 0x16, 0x00, 0xe5, 0x03, 0x80, - 0xe5, 0x10, 0x0e, 0xa5, 0x00, 0x3b, 0xa0, 0xe6, - 0x00, 0xe5, 0x21, 0x04, 0xe6, 0x10, 0x1b, 0xe6, + 0xe5, 0x10, 0x0e, 0xa5, 0x00, 0x3b, 0x80, 0xe6, + 0x01, 0xe5, 0x21, 0x04, 0xe6, 0x10, 0x1b, 0xe6, 0x18, 0x07, 0xe5, 0x2e, 0x06, 0x07, 0x06, 0x05, 0x47, 0xe6, 0x00, 0x67, 0x06, 0x27, 0x05, 0xc6, 0xe5, 0x02, 0x26, 0x36, 0xe9, 0x02, 0x16, 0x04, @@ -2549,82 +2523,82 @@ static const uint8_t unicode_gc_table[3948] = { 0xe9, 0x02, 0xa0, 0xd6, 0x04, 0xb6, 0x20, 0xe6, 0x06, 0x08, 0xe6, 0x08, 0xe0, 0x29, 0x66, 0x07, 0xe5, 0x27, 0x06, 0x07, 0x86, 0x07, 0x06, 0x87, - 0x06, 0x27, 0xe5, 0x00, 0x40, 0xe9, 0x02, 0xd6, - 0xef, 0x02, 0xe6, 0x01, 0xef, 0x01, 0x36, 0x00, + 0x06, 0x27, 0xe5, 0x00, 0x00, 0x36, 0xe9, 0x02, + 0xd6, 0xef, 0x02, 0xe6, 0x01, 0xef, 0x01, 0x56, 0x26, 0x07, 0xe5, 0x16, 0x07, 0x66, 0x27, 0x26, 0x07, 0x46, 0x25, 0xe9, 0x02, 0xe5, 0x24, 0x06, 0x07, 0x26, 0x47, 0x06, 0x07, 0x46, 0x27, 0xe0, 0x00, 0x76, 0xe5, 0x1c, 0xe7, 0x00, 0xe6, 0x00, 0x27, 0x26, 0x40, 0x96, 0xe9, 0x02, 0x40, 0x45, 0xe9, 0x02, 0xe5, 0x16, 0xa4, 0x36, 0xe2, 0x01, - 0xc0, 0xe1, 0x23, 0x20, 0x41, 0xf6, 0x00, 0xe0, - 0x00, 0x46, 0x16, 0xe6, 0x05, 0x07, 0xc6, 0x65, - 0x06, 0xa5, 0x06, 0x25, 0x07, 0x26, 0x05, 0x80, - 0xe2, 0x24, 0xe4, 0x37, 0xe2, 0x05, 0x04, 0xe2, - 0x1a, 0xe4, 0x1d, 0xe6, 0x38, 0xff, 0x80, 0x0e, - 0xe2, 0x00, 0xff, 0x5a, 0xe2, 0x00, 0xe1, 0x00, - 0xa2, 0x20, 0xa1, 0x20, 0xe2, 0x00, 0xe1, 0x00, - 0xe2, 0x00, 0xe1, 0x00, 0xa2, 0x20, 0xa1, 0x20, - 0xe2, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x3f, 0xc2, 0xe1, 0x00, 0xe2, 0x06, 0x20, - 0xe2, 0x00, 0xe3, 0x00, 0xe2, 0x00, 0xe3, 0x00, - 0xe2, 0x00, 0xe3, 0x00, 0x82, 0x00, 0x22, 0x61, - 0x03, 0x0e, 0x02, 0x4e, 0x42, 0x00, 0x22, 0x61, - 0x03, 0x4e, 0x62, 0x20, 0x22, 0x61, 0x00, 0x4e, - 0xe2, 0x00, 0x81, 0x4e, 0x20, 0x42, 0x00, 0x22, - 0x61, 0x03, 0x2e, 0x00, 0xf7, 0x03, 0x9b, 0xb1, - 0x36, 0x14, 0x15, 0x12, 0x34, 0x15, 0x12, 0x14, - 0xf6, 0x00, 0x18, 0x19, 0x9b, 0x17, 0xf6, 0x01, - 0x14, 0x15, 0x76, 0x30, 0x56, 0x0c, 0x12, 0x13, - 0xf6, 0x03, 0x0c, 0x16, 0x10, 0xf6, 0x02, 0x17, - 0x9b, 0x00, 0xfb, 0x02, 0x0b, 0x04, 0x20, 0xab, - 0x4c, 0x12, 0x13, 0x04, 0xeb, 0x02, 0x4c, 0x12, - 0x13, 0x00, 0xe4, 0x05, 0x40, 0xed, 0x19, 0xe0, - 0x07, 0xe6, 0x05, 0x68, 0x06, 0x48, 0xe6, 0x04, - 0xe0, 0x07, 0x2f, 0x01, 0x6f, 0x01, 0x2f, 0x02, - 0x41, 0x22, 0x41, 0x02, 0x0f, 0x01, 0x2f, 0x0c, - 0x81, 0xaf, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, - 0x61, 0x0f, 0x02, 0x61, 0x02, 0x65, 0x02, 0x2f, - 0x22, 0x21, 0x8c, 0x3f, 0x42, 0x0f, 0x0c, 0x2f, - 0x02, 0x0f, 0xeb, 0x08, 0xea, 0x1b, 0x3f, 0x6a, - 0x0b, 0x2f, 0x60, 0x8c, 0x8f, 0x2c, 0x6f, 0x0c, - 0x2f, 0x0c, 0x2f, 0x0c, 0xcf, 0x0c, 0xef, 0x17, - 0x2c, 0x2f, 0x0c, 0x0f, 0x0c, 0xef, 0x17, 0xec, - 0x80, 0x84, 0xef, 0x00, 0x12, 0x13, 0x12, 0x13, - 0xef, 0x0c, 0x2c, 0xcf, 0x12, 0x13, 0xef, 0x49, - 0x0c, 0xef, 0x16, 0xec, 0x11, 0xef, 0x20, 0xac, - 0xef, 0x3d, 0xe0, 0x11, 0xef, 0x03, 0xe0, 0x0d, - 0xeb, 0x34, 0xef, 0x46, 0xeb, 0x0e, 0xef, 0x80, - 0x2f, 0x0c, 0xef, 0x01, 0x0c, 0xef, 0x2e, 0xec, - 0x00, 0xef, 0x67, 0x0c, 0xef, 0x80, 0x70, 0x12, - 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, - 0x13, 0x12, 0x13, 0x12, 0x13, 0xeb, 0x16, 0xef, - 0x24, 0x8c, 0x12, 0x13, 0xec, 0x17, 0x12, 0x13, + 0x3f, 0x80, 0xe1, 0x23, 0x20, 0x41, 0xf6, 0x00, + 0xe0, 0x00, 0x46, 0x16, 0xe6, 0x05, 0x07, 0xc6, + 0x65, 0x06, 0xa5, 0x06, 0x25, 0x07, 0x26, 0x05, + 0x80, 0xe2, 0x24, 0xe4, 0x37, 0xe2, 0x05, 0x04, + 0xe2, 0x1a, 0xe4, 0x1d, 0xe6, 0x38, 0xff, 0x80, + 0x0e, 0xe2, 0x00, 0xff, 0x5a, 0xe2, 0x00, 0xe1, + 0x00, 0xa2, 0x20, 0xa1, 0x20, 0xe2, 0x00, 0xe1, + 0x00, 0xe2, 0x00, 0xe1, 0x00, 0xa2, 0x20, 0xa1, + 0x20, 0xe2, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x3f, 0xc2, 0xe1, 0x00, 0xe2, 0x06, + 0x20, 0xe2, 0x00, 0xe3, 0x00, 0xe2, 0x00, 0xe3, + 0x00, 0xe2, 0x00, 0xe3, 0x00, 0x82, 0x00, 0x22, + 0x61, 0x03, 0x0e, 0x02, 0x4e, 0x42, 0x00, 0x22, + 0x61, 0x03, 0x4e, 0x62, 0x20, 0x22, 0x61, 0x00, + 0x4e, 0xe2, 0x00, 0x81, 0x4e, 0x20, 0x42, 0x00, + 0x22, 0x61, 0x03, 0x2e, 0x00, 0xf7, 0x03, 0x9b, + 0xb1, 0x36, 0x14, 0x15, 0x12, 0x34, 0x15, 0x12, + 0x14, 0xf6, 0x00, 0x18, 0x19, 0x9b, 0x17, 0xf6, + 0x01, 0x14, 0x15, 0x76, 0x30, 0x56, 0x0c, 0x12, + 0x13, 0xf6, 0x03, 0x0c, 0x16, 0x10, 0xf6, 0x02, + 0x17, 0x9b, 0x00, 0xfb, 0x02, 0x0b, 0x04, 0x20, + 0xab, 0x4c, 0x12, 0x13, 0x04, 0xeb, 0x02, 0x4c, + 0x12, 0x13, 0x00, 0xe4, 0x05, 0x40, 0xed, 0x19, + 0xe0, 0x07, 0xe6, 0x05, 0x68, 0x06, 0x48, 0xe6, + 0x04, 0xe0, 0x07, 0x2f, 0x01, 0x6f, 0x01, 0x2f, + 0x02, 0x41, 0x22, 0x41, 0x02, 0x0f, 0x01, 0x2f, + 0x0c, 0x81, 0xaf, 0x01, 0x0f, 0x01, 0x0f, 0x01, + 0x0f, 0x61, 0x0f, 0x02, 0x61, 0x02, 0x65, 0x02, + 0x2f, 0x22, 0x21, 0x8c, 0x3f, 0x42, 0x0f, 0x0c, + 0x2f, 0x02, 0x0f, 0xeb, 0x08, 0xea, 0x1b, 0x3f, + 0x6a, 0x0b, 0x2f, 0x60, 0x8c, 0x8f, 0x2c, 0x6f, + 0x0c, 0x2f, 0x0c, 0x2f, 0x0c, 0xcf, 0x0c, 0xef, + 0x17, 0x2c, 0x2f, 0x0c, 0x0f, 0x0c, 0xef, 0x17, + 0xec, 0x80, 0x84, 0xef, 0x00, 0x12, 0x13, 0x12, + 0x13, 0xef, 0x0c, 0x2c, 0xcf, 0x12, 0x13, 0xef, + 0x49, 0x0c, 0xef, 0x16, 0xec, 0x11, 0xef, 0x20, + 0xac, 0xef, 0x40, 0xe0, 0x0e, 0xef, 0x03, 0xe0, + 0x0d, 0xeb, 0x34, 0xef, 0x46, 0xeb, 0x0e, 0xef, + 0x80, 0x2f, 0x0c, 0xef, 0x01, 0x0c, 0xef, 0x2e, + 0xec, 0x00, 0xef, 0x67, 0x0c, 0xef, 0x80, 0x70, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, - 0xec, 0x08, 0xef, 0x80, 0x78, 0xec, 0x7b, 0x12, - 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, + 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0xeb, 0x16, + 0xef, 0x24, 0x8c, 0x12, 0x13, 0xec, 0x17, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, - 0x13, 0x12, 0x13, 0x12, 0x13, 0xec, 0x37, 0x12, - 0x13, 0x12, 0x13, 0xec, 0x18, 0x12, 0x13, 0xec, - 0x80, 0x7a, 0xef, 0x28, 0xec, 0x0d, 0x2f, 0xac, - 0xef, 0x1f, 0x20, 0xef, 0x18, 0x00, 0xef, 0x61, - 0xe1, 0x28, 0xe2, 0x28, 0x5f, 0x21, 0x22, 0xdf, - 0x41, 0x02, 0x3f, 0x02, 0x3f, 0x82, 0x24, 0x41, - 0x02, 0xff, 0x5a, 0x02, 0xaf, 0x7f, 0x46, 0x3f, - 0x80, 0x76, 0x0b, 0x36, 0xe2, 0x1e, 0x00, 0x02, - 0x80, 0x02, 0x20, 0xe5, 0x30, 0xc0, 0x04, 0x16, - 0xe0, 0x06, 0x06, 0xe5, 0x0f, 0xe0, 0x01, 0xc5, - 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, - 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xe6, - 0x18, 0x36, 0x14, 0x15, 0x14, 0x15, 0x56, 0x14, - 0x15, 0x16, 0x14, 0x15, 0xf6, 0x01, 0x11, 0x36, - 0x11, 0x16, 0x14, 0x15, 0x36, 0x14, 0x15, 0x12, - 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x96, - 0x04, 0xf6, 0x02, 0x31, 0x76, 0x11, 0x16, 0x12, - 0xf6, 0x05, 0x2f, 0x56, 0x12, 0x13, 0x12, 0x13, - 0x12, 0x13, 0x12, 0x13, 0x11, 0xe0, 0x1a, 0xef, - 0x12, 0x00, 0xef, 0x51, 0xe0, 0x04, 0xef, 0x80, - 0x4e, 0xe0, 0x12, 0xef, 0x04, 0x60, 0x17, 0x56, + 0x13, 0xec, 0x08, 0xef, 0x80, 0x78, 0xec, 0x7b, + 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, + 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, + 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0xec, 0x37, + 0x12, 0x13, 0x12, 0x13, 0xec, 0x18, 0x12, 0x13, + 0xec, 0x80, 0x7a, 0xef, 0x28, 0xec, 0x0d, 0x2f, + 0xac, 0xef, 0x1f, 0x20, 0xef, 0x18, 0x00, 0xef, + 0x61, 0xe1, 0x28, 0xe2, 0x28, 0x5f, 0x21, 0x22, + 0xdf, 0x41, 0x02, 0x3f, 0x02, 0x3f, 0x82, 0x24, + 0x41, 0x02, 0xff, 0x5a, 0x02, 0xaf, 0x7f, 0x46, + 0x3f, 0x80, 0x76, 0x0b, 0x36, 0xe2, 0x1e, 0x00, + 0x02, 0x80, 0x02, 0x20, 0xe5, 0x30, 0xc0, 0x04, + 0x16, 0xe0, 0x06, 0x06, 0xe5, 0x0f, 0xe0, 0x01, + 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, + 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, + 0xe6, 0x18, 0x36, 0x14, 0x15, 0x14, 0x15, 0x56, + 0x14, 0x15, 0x16, 0x14, 0x15, 0xf6, 0x01, 0x11, + 0x36, 0x11, 0x16, 0x14, 0x15, 0x36, 0x14, 0x15, + 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, + 0x96, 0x04, 0xf6, 0x02, 0x31, 0x76, 0x11, 0x16, + 0x12, 0xf6, 0x05, 0x2f, 0x56, 0x12, 0x13, 0x12, + 0x13, 0x12, 0x13, 0x12, 0x13, 0x11, 0xe0, 0x1a, + 0xef, 0x12, 0x00, 0xef, 0x51, 0xe0, 0x04, 0xef, + 0x80, 0x4e, 0xe0, 0x12, 0xef, 0x08, 0x17, 0x56, 0x0f, 0x04, 0x05, 0x0a, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x2f, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x11, @@ -2633,146 +2607,154 @@ static const uint8_t unicode_gc_table[3948] = { 0xe5, 0x4e, 0x20, 0x26, 0x2e, 0x24, 0x05, 0x11, 0xe5, 0x52, 0x16, 0x44, 0x05, 0x80, 0xe5, 0x23, 0x00, 0xe5, 0x56, 0x00, 0x2f, 0x6b, 0xef, 0x02, - 0xe5, 0x18, 0xef, 0x1c, 0xe0, 0x04, 0xe5, 0x08, - 0xef, 0x17, 0x00, 0xeb, 0x02, 0xef, 0x16, 0xeb, - 0x00, 0x0f, 0xeb, 0x07, 0xef, 0x18, 0xeb, 0x02, - 0xef, 0x1f, 0xeb, 0x07, 0xef, 0x80, 0xb8, 0xe5, - 0x99, 0x38, 0xef, 0x38, 0xe5, 0xc0, 0x11, 0x8d, - 0x04, 0xe5, 0x83, 0xef, 0x40, 0xef, 0x2f, 0xe0, - 0x01, 0xe5, 0x20, 0xa4, 0x36, 0xe5, 0x80, 0x84, - 0x04, 0x56, 0xe5, 0x08, 0xe9, 0x02, 0x25, 0xe0, - 0x0c, 0xff, 0x26, 0x05, 0x06, 0x48, 0x16, 0xe6, - 0x02, 0x16, 0x04, 0xff, 0x14, 0x24, 0x26, 0xe5, - 0x3e, 0xea, 0x02, 0x26, 0xb6, 0xe0, 0x00, 0xee, - 0x0f, 0xe4, 0x01, 0x2e, 0xff, 0x06, 0x22, 0xff, - 0x36, 0x04, 0xe2, 0x00, 0x9f, 0xff, 0x02, 0x04, - 0x2e, 0x7f, 0x05, 0x7f, 0x22, 0xff, 0x0d, 0x61, - 0x02, 0x81, 0x02, 0xff, 0x07, 0x41, 0x02, 0x3f, - 0x80, 0x3f, 0x00, 0x02, 0x00, 0x02, 0x7f, 0xe0, - 0x10, 0x44, 0x3f, 0x05, 0x24, 0x02, 0xc5, 0x06, - 0x45, 0x06, 0x65, 0x06, 0xe5, 0x0f, 0x27, 0x26, - 0x07, 0x6f, 0x06, 0x40, 0xab, 0x2f, 0x0d, 0x0f, - 0xa0, 0xe5, 0x2c, 0x76, 0xe0, 0x00, 0x27, 0xe5, - 0x2a, 0xe7, 0x08, 0x26, 0xe0, 0x00, 0x36, 0xe9, - 0x02, 0xa0, 0xe6, 0x0a, 0xa5, 0x56, 0x05, 0x16, - 0x25, 0x06, 0xe9, 0x02, 0xe5, 0x14, 0xe6, 0x00, - 0x36, 0xe5, 0x0f, 0xe6, 0x03, 0x27, 0xe0, 0x03, - 0x16, 0xe5, 0x15, 0x40, 0x46, 0x07, 0xe5, 0x27, - 0x06, 0x27, 0x66, 0x27, 0x26, 0x47, 0xf6, 0x05, - 0x00, 0x04, 0xe9, 0x02, 0x60, 0x36, 0x85, 0x06, - 0x04, 0xe5, 0x01, 0xe9, 0x02, 0x85, 0x00, 0xe5, - 0x21, 0xa6, 0x27, 0x26, 0x27, 0x26, 0xe0, 0x01, - 0x45, 0x06, 0xe5, 0x00, 0x06, 0x07, 0x20, 0xe9, - 0x02, 0x20, 0x76, 0xe5, 0x08, 0x04, 0xa5, 0x4f, - 0x05, 0x07, 0x06, 0x07, 0xe5, 0x2a, 0x06, 0x05, - 0x46, 0x25, 0x26, 0x85, 0x26, 0x05, 0x06, 0x05, - 0xe0, 0x10, 0x25, 0x04, 0x36, 0xe5, 0x03, 0x07, - 0x26, 0x27, 0x36, 0x05, 0x24, 0x07, 0x06, 0xe0, - 0x02, 0xa5, 0x20, 0xa5, 0x20, 0xa5, 0xe0, 0x01, - 0xc5, 0x00, 0xc5, 0x00, 0xe2, 0x23, 0x0e, 0x64, - 0xe2, 0x01, 0x04, 0x2e, 0x60, 0xe2, 0x48, 0xe5, - 0x1b, 0x27, 0x06, 0x27, 0x06, 0x27, 0x16, 0x07, - 0x06, 0x20, 0xe9, 0x02, 0xa0, 0xe5, 0xab, 0x1c, - 0xe0, 0x04, 0xe5, 0x0f, 0x60, 0xe5, 0x29, 0x60, - 0xfc, 0x87, 0x78, 0xfd, 0x98, 0x78, 0xe5, 0x80, - 0xe6, 0x20, 0xe5, 0x62, 0xe0, 0x1e, 0xc2, 0xe0, - 0x04, 0x82, 0x80, 0x05, 0x06, 0xe5, 0x02, 0x0c, - 0xe5, 0x05, 0x00, 0x85, 0x00, 0x05, 0x00, 0x25, - 0x00, 0x25, 0x00, 0xe5, 0x64, 0xee, 0x09, 0xe0, - 0x08, 0xe5, 0x80, 0xe3, 0x13, 0x12, 0xef, 0x08, - 0xe5, 0x38, 0x20, 0xe5, 0x2e, 0xc0, 0x0f, 0xe0, - 0x18, 0xe5, 0x04, 0x0d, 0x4f, 0xe6, 0x08, 0xd6, - 0x12, 0x13, 0x16, 0xa0, 0xe6, 0x08, 0x16, 0x31, - 0x30, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, + 0xe5, 0x18, 0xef, 0x1e, 0xe0, 0x01, 0x0f, 0xe5, + 0x08, 0xef, 0x17, 0x00, 0xeb, 0x02, 0xef, 0x16, + 0xeb, 0x00, 0x0f, 0xeb, 0x07, 0xef, 0x18, 0xeb, + 0x02, 0xef, 0x1f, 0xeb, 0x07, 0xef, 0x80, 0xb8, + 0xe5, 0x99, 0x38, 0xef, 0x38, 0xe5, 0xc0, 0x11, + 0x8d, 0x04, 0xe5, 0x83, 0xef, 0x40, 0xef, 0x2f, + 0xe0, 0x01, 0xe5, 0x20, 0xa4, 0x36, 0xe5, 0x80, + 0x84, 0x04, 0x56, 0xe5, 0x08, 0xe9, 0x02, 0x25, + 0xe0, 0x0c, 0xff, 0x26, 0x05, 0x06, 0x48, 0x16, + 0xe6, 0x02, 0x16, 0x04, 0xff, 0x14, 0x24, 0x26, + 0xe5, 0x3e, 0xea, 0x02, 0x26, 0xb6, 0xe0, 0x00, + 0xee, 0x0f, 0xe4, 0x01, 0x2e, 0xff, 0x06, 0x22, + 0xff, 0x36, 0x04, 0xe2, 0x00, 0x9f, 0xff, 0x02, + 0x04, 0x2e, 0x7f, 0x05, 0x7f, 0x22, 0xff, 0x0d, + 0x61, 0x02, 0x81, 0x02, 0xff, 0x07, 0x41, 0x02, + 0x5f, 0x3f, 0x20, 0x3f, 0x00, 0x02, 0x00, 0x02, + 0xdf, 0xe0, 0x0d, 0x44, 0x3f, 0x05, 0x24, 0x02, + 0xc5, 0x06, 0x45, 0x06, 0x65, 0x06, 0xe5, 0x0f, + 0x27, 0x26, 0x07, 0x6f, 0x06, 0x40, 0xab, 0x2f, + 0x0d, 0x0f, 0xa0, 0xe5, 0x2c, 0x76, 0xe0, 0x00, + 0x27, 0xe5, 0x2a, 0xe7, 0x08, 0x26, 0xe0, 0x00, + 0x36, 0xe9, 0x02, 0xa0, 0xe6, 0x0a, 0xa5, 0x56, + 0x05, 0x16, 0x25, 0x06, 0xe9, 0x02, 0xe5, 0x14, + 0xe6, 0x00, 0x36, 0xe5, 0x0f, 0xe6, 0x03, 0x27, + 0xe0, 0x03, 0x16, 0xe5, 0x15, 0x40, 0x46, 0x07, + 0xe5, 0x27, 0x06, 0x27, 0x66, 0x27, 0x26, 0x47, + 0xf6, 0x05, 0x00, 0x04, 0xe9, 0x02, 0x60, 0x36, + 0x85, 0x06, 0x04, 0xe5, 0x01, 0xe9, 0x02, 0x85, + 0x00, 0xe5, 0x21, 0xa6, 0x27, 0x26, 0x27, 0x26, + 0xe0, 0x01, 0x45, 0x06, 0xe5, 0x00, 0x06, 0x07, + 0x20, 0xe9, 0x02, 0x20, 0x76, 0xe5, 0x08, 0x04, + 0xa5, 0x4f, 0x05, 0x07, 0x06, 0x07, 0xe5, 0x2a, + 0x06, 0x05, 0x46, 0x25, 0x26, 0x85, 0x26, 0x05, + 0x06, 0x05, 0xe0, 0x10, 0x25, 0x04, 0x36, 0xe5, + 0x03, 0x07, 0x26, 0x27, 0x36, 0x05, 0x24, 0x07, + 0x06, 0xe0, 0x02, 0xa5, 0x20, 0xa5, 0x20, 0xa5, + 0xe0, 0x01, 0xc5, 0x00, 0xc5, 0x00, 0xe2, 0x23, + 0x0e, 0x64, 0xe2, 0x01, 0x04, 0x2e, 0x60, 0xe2, + 0x48, 0xe5, 0x1b, 0x27, 0x06, 0x27, 0x06, 0x27, + 0x16, 0x07, 0x06, 0x20, 0xe9, 0x02, 0xa0, 0xe5, + 0xab, 0x1c, 0xe0, 0x04, 0xe5, 0x0f, 0x60, 0xe5, + 0x29, 0x60, 0xfc, 0x87, 0x78, 0xfd, 0x98, 0x78, + 0xe5, 0x80, 0xe6, 0x20, 0xe5, 0x62, 0xe0, 0x1e, + 0xc2, 0xe0, 0x04, 0x82, 0x80, 0x05, 0x06, 0xe5, + 0x02, 0x0c, 0xe5, 0x05, 0x00, 0x85, 0x00, 0x05, + 0x00, 0x25, 0x00, 0x25, 0x00, 0xe5, 0x64, 0xee, + 0x09, 0xe0, 0x08, 0xe5, 0x80, 0xe3, 0x13, 0x12, + 0xef, 0x08, 0xe5, 0x38, 0x20, 0xe5, 0x2e, 0xc0, + 0x0f, 0xe0, 0x18, 0xe5, 0x04, 0x0d, 0x4f, 0xe6, + 0x08, 0xd6, 0x12, 0x13, 0x16, 0xa0, 0xe6, 0x08, + 0x16, 0x31, 0x30, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, - 0x13, 0x36, 0x12, 0x13, 0x76, 0x50, 0x56, 0x00, - 0x76, 0x11, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, - 0x56, 0x0c, 0x11, 0x4c, 0x00, 0x16, 0x0d, 0x36, - 0x60, 0x85, 0x00, 0xe5, 0x7f, 0x20, 0x1b, 0x00, - 0x56, 0x0d, 0x56, 0x12, 0x13, 0x16, 0x0c, 0x16, - 0x11, 0x36, 0xe9, 0x02, 0x36, 0x4c, 0x36, 0xe1, - 0x12, 0x12, 0x16, 0x13, 0x0e, 0x10, 0x0e, 0xe2, - 0x12, 0x12, 0x0c, 0x13, 0x0c, 0x12, 0x13, 0x16, - 0x12, 0x13, 0x36, 0xe5, 0x02, 0x04, 0xe5, 0x25, - 0x24, 0xe5, 0x17, 0x40, 0xa5, 0x20, 0xa5, 0x20, - 0xa5, 0x20, 0x45, 0x40, 0x2d, 0x0c, 0x0e, 0x0f, - 0x2d, 0x00, 0x0f, 0x6c, 0x2f, 0xe0, 0x02, 0x5b, - 0x2f, 0x20, 0xe5, 0x04, 0x00, 0xe5, 0x12, 0x00, - 0xe5, 0x0b, 0x00, 0x25, 0x00, 0xe5, 0x07, 0x20, - 0xe5, 0x06, 0xe0, 0x1a, 0xe5, 0x73, 0x80, 0x56, - 0x60, 0xeb, 0x25, 0x40, 0xef, 0x01, 0xea, 0x2d, - 0x6b, 0xef, 0x09, 0x2b, 0x4f, 0x00, 0xef, 0x05, - 0x40, 0x0f, 0xe0, 0x27, 0xef, 0x25, 0x06, 0xe0, - 0x7a, 0xe5, 0x15, 0x40, 0xe5, 0x29, 0xe0, 0x07, - 0x06, 0xeb, 0x13, 0x60, 0xe5, 0x18, 0x6b, 0xe0, - 0x01, 0xe5, 0x0c, 0x0a, 0xe5, 0x00, 0x0a, 0x80, - 0xe5, 0x1e, 0x86, 0x80, 0xe5, 0x16, 0x00, 0x16, - 0xe5, 0x1c, 0x60, 0xe5, 0x00, 0x16, 0x8a, 0xe0, - 0x22, 0xe1, 0x20, 0xe2, 0x20, 0xe5, 0x46, 0x20, - 0xe9, 0x02, 0xa0, 0xe1, 0x1c, 0x60, 0xe2, 0x1c, - 0x60, 0xe5, 0x20, 0xe0, 0x00, 0xe5, 0x2c, 0xe0, - 0x03, 0x16, 0xe1, 0x03, 0x00, 0xe1, 0x07, 0x00, - 0xc1, 0x00, 0x21, 0x00, 0xe2, 0x03, 0x00, 0xe2, - 0x07, 0x00, 0xc2, 0x00, 0x22, 0xe0, 0x3b, 0xe5, - 0x80, 0xaf, 0xe0, 0x01, 0xe5, 0x0e, 0xe0, 0x02, - 0xe5, 0x00, 0xe0, 0x10, 0xa4, 0x00, 0xe4, 0x22, - 0x00, 0xe4, 0x01, 0xe0, 0x3d, 0xa5, 0x20, 0x05, - 0x00, 0xe5, 0x24, 0x00, 0x25, 0x40, 0x05, 0x20, - 0xe5, 0x0f, 0x00, 0x16, 0xeb, 0x00, 0xe5, 0x0f, - 0x2f, 0xcb, 0xe5, 0x17, 0xe0, 0x00, 0xeb, 0x01, - 0xe0, 0x28, 0xe5, 0x0b, 0x00, 0x25, 0x80, 0x8b, - 0xe5, 0x0e, 0xab, 0x40, 0x16, 0xe5, 0x12, 0x80, - 0x16, 0xe0, 0x38, 0xe5, 0x30, 0x60, 0x2b, 0x25, - 0xeb, 0x08, 0x20, 0xeb, 0x26, 0x05, 0x46, 0x00, - 0x26, 0x80, 0x66, 0x65, 0x00, 0x45, 0x00, 0xe5, - 0x15, 0x20, 0x46, 0x60, 0x06, 0xeb, 0x01, 0xc0, - 0xf6, 0x01, 0xc0, 0xe5, 0x15, 0x2b, 0x16, 0xe5, - 0x15, 0x4b, 0xe0, 0x18, 0xe5, 0x00, 0x0f, 0xe5, - 0x14, 0x26, 0x60, 0x8b, 0xd6, 0xe0, 0x01, 0xe5, - 0x2e, 0x40, 0xd6, 0xe5, 0x0e, 0x20, 0xeb, 0x00, - 0xe5, 0x0b, 0x80, 0xeb, 0x00, 0xe5, 0x0a, 0xc0, - 0x76, 0xe0, 0x04, 0xcb, 0xe0, 0x48, 0xe5, 0x41, - 0xe0, 0x2f, 0xe1, 0x2b, 0xe0, 0x05, 0xe2, 0x2b, - 0xc0, 0xab, 0xe5, 0x1c, 0x66, 0xe0, 0x00, 0xe9, - 0x02, 0xe0, 0x80, 0x9e, 0xeb, 0x17, 0x00, 0xe5, - 0x22, 0x00, 0x26, 0x11, 0x20, 0x25, 0xe0, 0x43, - 0x46, 0xe5, 0x15, 0xeb, 0x02, 0x05, 0xe0, 0x00, - 0xe5, 0x0e, 0xe6, 0x03, 0x6b, 0x96, 0xe0, 0x0e, - 0xe5, 0x0a, 0x66, 0x76, 0xe0, 0x1e, 0xe5, 0x0d, - 0xcb, 0xe0, 0x0c, 0xe5, 0x0f, 0xe0, 0x01, 0x07, - 0x06, 0x07, 0xe5, 0x2d, 0xe6, 0x07, 0xd6, 0x60, - 0xeb, 0x0c, 0xe9, 0x02, 0x06, 0x25, 0x26, 0x05, - 0xe0, 0x01, 0x46, 0x07, 0xe5, 0x25, 0x47, 0x66, - 0x27, 0x26, 0x36, 0x1b, 0x76, 0x06, 0xe0, 0x02, - 0x1b, 0x20, 0xe5, 0x11, 0xc0, 0xe9, 0x02, 0xa0, - 0x46, 0xe5, 0x1c, 0x86, 0x07, 0xe6, 0x00, 0x00, - 0xe9, 0x02, 0x76, 0x05, 0x27, 0x05, 0xe0, 0x00, - 0xe5, 0x1b, 0x06, 0x36, 0x05, 0xe0, 0x01, 0x26, - 0x07, 0xe5, 0x28, 0x47, 0xe6, 0x01, 0x27, 0x65, - 0x76, 0x66, 0x16, 0x07, 0x06, 0xe9, 0x02, 0x05, - 0x16, 0x05, 0x56, 0x00, 0xeb, 0x0c, 0xe0, 0x03, - 0xe5, 0x0a, 0x00, 0xe5, 0x11, 0x47, 0x46, 0x27, - 0x06, 0x07, 0x26, 0xb6, 0x06, 0x25, 0x06, 0xe0, - 0x36, 0xc5, 0x00, 0x05, 0x00, 0x65, 0x00, 0xe5, - 0x07, 0x00, 0xe5, 0x02, 0x16, 0xa0, 0xe5, 0x27, - 0x06, 0x47, 0xe6, 0x00, 0x80, 0xe9, 0x02, 0xa0, - 0x26, 0x27, 0x00, 0xe5, 0x00, 0x20, 0x25, 0x20, - 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25, 0x00, 0x85, - 0x00, 0x26, 0x05, 0x27, 0x06, 0x67, 0x20, 0x27, - 0x20, 0x47, 0x20, 0x05, 0xa0, 0x07, 0x80, 0x85, - 0x27, 0x20, 0xc6, 0x40, 0x86, 0xe0, 0x80, 0x03, - 0xe5, 0x2d, 0x47, 0xe6, 0x00, 0x27, 0x46, 0x07, - 0x06, 0x65, 0x96, 0xe9, 0x02, 0x36, 0x00, 0x16, - 0x06, 0x45, 0xe0, 0x16, 0xe5, 0x28, 0x47, 0xa6, - 0x07, 0x06, 0x67, 0x26, 0x07, 0x26, 0x25, 0x16, - 0x05, 0xe0, 0x00, 0xe9, 0x02, 0xe0, 0x80, 0x1e, - 0xe5, 0x27, 0x47, 0x66, 0x20, 0x67, 0x26, 0x07, - 0x26, 0xf6, 0x0f, 0x65, 0x26, 0xe0, 0x1a, 0xe5, - 0x28, 0x47, 0xe6, 0x00, 0x27, 0x06, 0x07, 0x26, - 0x56, 0x05, 0xe0, 0x03, 0xe9, 0x02, 0xa0, 0xf6, - 0x05, 0xe0, 0x0b, 0xe5, 0x23, 0x06, 0x07, 0x06, - 0x27, 0xa6, 0x07, 0x06, 0x05, 0x16, 0xa0, 0xe9, - 0x02, 0xe0, 0x2e, 0xe5, 0x13, 0x20, 0x46, 0x27, + 0x13, 0x12, 0x13, 0x36, 0x12, 0x13, 0x76, 0x50, + 0x56, 0x00, 0x76, 0x11, 0x12, 0x13, 0x12, 0x13, + 0x12, 0x13, 0x56, 0x0c, 0x11, 0x4c, 0x00, 0x16, + 0x0d, 0x36, 0x60, 0x85, 0x00, 0xe5, 0x7f, 0x20, + 0x1b, 0x00, 0x56, 0x0d, 0x56, 0x12, 0x13, 0x16, + 0x0c, 0x16, 0x11, 0x36, 0xe9, 0x02, 0x36, 0x4c, + 0x36, 0xe1, 0x12, 0x12, 0x16, 0x13, 0x0e, 0x10, + 0x0e, 0xe2, 0x12, 0x12, 0x0c, 0x13, 0x0c, 0x12, + 0x13, 0x16, 0x12, 0x13, 0x36, 0xe5, 0x02, 0x04, + 0xe5, 0x25, 0x24, 0xe5, 0x17, 0x40, 0xa5, 0x20, + 0xa5, 0x20, 0xa5, 0x20, 0x45, 0x40, 0x2d, 0x0c, + 0x0e, 0x0f, 0x2d, 0x00, 0x0f, 0x6c, 0x2f, 0xe0, + 0x02, 0x5b, 0x2f, 0x20, 0xe5, 0x04, 0x00, 0xe5, + 0x12, 0x00, 0xe5, 0x0b, 0x00, 0x25, 0x00, 0xe5, + 0x07, 0x20, 0xe5, 0x06, 0xe0, 0x1a, 0xe5, 0x73, + 0x80, 0x56, 0x60, 0xeb, 0x25, 0x40, 0xef, 0x01, + 0xea, 0x2d, 0x6b, 0xef, 0x09, 0x2b, 0x4f, 0x00, + 0xef, 0x05, 0x40, 0x0f, 0xe0, 0x27, 0xef, 0x25, + 0x06, 0xe0, 0x7a, 0xe5, 0x15, 0x40, 0xe5, 0x29, + 0xe0, 0x07, 0x06, 0xeb, 0x13, 0x60, 0xe5, 0x18, + 0x6b, 0xe0, 0x01, 0xe5, 0x0c, 0x0a, 0xe5, 0x00, + 0x0a, 0x80, 0xe5, 0x1e, 0x86, 0x80, 0xe5, 0x16, + 0x00, 0x16, 0xe5, 0x1c, 0x60, 0xe5, 0x00, 0x16, + 0x8a, 0xe0, 0x22, 0xe1, 0x20, 0xe2, 0x20, 0xe5, + 0x46, 0x20, 0xe9, 0x02, 0xa0, 0xe1, 0x1c, 0x60, + 0xe2, 0x1c, 0x60, 0xe5, 0x20, 0xe0, 0x00, 0xe5, + 0x2c, 0xe0, 0x03, 0x16, 0xe1, 0x03, 0x00, 0xe1, + 0x07, 0x00, 0xc1, 0x00, 0x21, 0x00, 0xe2, 0x03, + 0x00, 0xe2, 0x07, 0x00, 0xc2, 0x00, 0x22, 0x40, + 0xe5, 0x2c, 0xe0, 0x04, 0xe5, 0x80, 0xaf, 0xe0, + 0x01, 0xe5, 0x0e, 0xe0, 0x02, 0xe5, 0x00, 0xe0, + 0x10, 0xa4, 0x00, 0xe4, 0x22, 0x00, 0xe4, 0x01, + 0xe0, 0x3d, 0xa5, 0x20, 0x05, 0x00, 0xe5, 0x24, + 0x00, 0x25, 0x40, 0x05, 0x20, 0xe5, 0x0f, 0x00, + 0x16, 0xeb, 0x00, 0xe5, 0x0f, 0x2f, 0xcb, 0xe5, + 0x17, 0xe0, 0x00, 0xeb, 0x01, 0xe0, 0x28, 0xe5, + 0x0b, 0x00, 0x25, 0x80, 0x8b, 0xe5, 0x0e, 0xab, + 0x40, 0x16, 0xe5, 0x12, 0x80, 0x16, 0xe0, 0x38, + 0xe5, 0x30, 0x60, 0x2b, 0x25, 0xeb, 0x08, 0x20, + 0xeb, 0x26, 0x05, 0x46, 0x00, 0x26, 0x80, 0x66, + 0x65, 0x00, 0x45, 0x00, 0xe5, 0x15, 0x20, 0x46, + 0x60, 0x06, 0xeb, 0x01, 0xc0, 0xf6, 0x01, 0xc0, + 0xe5, 0x15, 0x2b, 0x16, 0xe5, 0x15, 0x4b, 0xe0, + 0x18, 0xe5, 0x00, 0x0f, 0xe5, 0x14, 0x26, 0x60, + 0x8b, 0xd6, 0xe0, 0x01, 0xe5, 0x2e, 0x40, 0xd6, + 0xe5, 0x0e, 0x20, 0xeb, 0x00, 0xe5, 0x0b, 0x80, + 0xeb, 0x00, 0xe5, 0x0a, 0xc0, 0x76, 0xe0, 0x04, + 0xcb, 0xe0, 0x48, 0xe5, 0x41, 0xe0, 0x2f, 0xe1, + 0x2b, 0xe0, 0x05, 0xe2, 0x2b, 0xc0, 0xab, 0xe5, + 0x1c, 0x66, 0xe0, 0x00, 0xe9, 0x02, 0xa0, 0xe9, + 0x02, 0x65, 0x04, 0x05, 0xe1, 0x0e, 0x40, 0x86, + 0x11, 0x04, 0xe2, 0x0e, 0xe0, 0x00, 0x2c, 0xe0, + 0x80, 0x48, 0xeb, 0x17, 0x00, 0xe5, 0x22, 0x00, + 0x26, 0x11, 0x20, 0x25, 0xe0, 0x08, 0x45, 0xe0, + 0x2f, 0x66, 0xe5, 0x15, 0xeb, 0x02, 0x05, 0xe0, + 0x00, 0xe5, 0x0e, 0xe6, 0x03, 0x6b, 0x96, 0xe0, + 0x0e, 0xe5, 0x0a, 0x66, 0x76, 0xe0, 0x1e, 0xe5, + 0x0d, 0xcb, 0xe0, 0x0c, 0xe5, 0x0f, 0xe0, 0x01, + 0x07, 0x06, 0x07, 0xe5, 0x2d, 0xe6, 0x07, 0xd6, + 0x60, 0xeb, 0x0c, 0xe9, 0x02, 0x06, 0x25, 0x26, + 0x05, 0xe0, 0x01, 0x46, 0x07, 0xe5, 0x25, 0x47, + 0x66, 0x27, 0x26, 0x36, 0x1b, 0x76, 0x06, 0xe0, + 0x02, 0x1b, 0x20, 0xe5, 0x11, 0xc0, 0xe9, 0x02, + 0xa0, 0x46, 0xe5, 0x1c, 0x86, 0x07, 0xe6, 0x00, + 0x00, 0xe9, 0x02, 0x76, 0x05, 0x27, 0x05, 0xe0, + 0x00, 0xe5, 0x1b, 0x06, 0x36, 0x05, 0xe0, 0x01, + 0x26, 0x07, 0xe5, 0x28, 0x47, 0xe6, 0x01, 0x27, + 0x65, 0x76, 0x66, 0x16, 0x07, 0x06, 0xe9, 0x02, + 0x05, 0x16, 0x05, 0x56, 0x00, 0xeb, 0x0c, 0xe0, + 0x03, 0xe5, 0x0a, 0x00, 0xe5, 0x11, 0x47, 0x46, + 0x27, 0x06, 0x07, 0x26, 0xb6, 0x06, 0x25, 0x06, + 0xe0, 0x36, 0xc5, 0x00, 0x05, 0x00, 0x65, 0x00, + 0xe5, 0x07, 0x00, 0xe5, 0x02, 0x16, 0xa0, 0xe5, + 0x27, 0x06, 0x47, 0xe6, 0x00, 0x80, 0xe9, 0x02, + 0xa0, 0x26, 0x27, 0x00, 0xe5, 0x00, 0x20, 0x25, + 0x20, 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25, 0x00, + 0x85, 0x00, 0x26, 0x05, 0x27, 0x06, 0x67, 0x20, + 0x27, 0x20, 0x47, 0x20, 0x05, 0xa0, 0x07, 0x80, + 0x85, 0x27, 0x20, 0xc6, 0x40, 0x86, 0xe0, 0x03, + 0xe5, 0x02, 0x00, 0x05, 0x20, 0x05, 0x00, 0xe5, + 0x1e, 0x00, 0x05, 0x47, 0xa6, 0x00, 0x07, 0x20, + 0x07, 0x00, 0x67, 0x00, 0x27, 0x06, 0x07, 0x06, + 0x05, 0x06, 0x05, 0x36, 0x00, 0x36, 0xe0, 0x00, + 0x26, 0xe0, 0x15, 0xe5, 0x2d, 0x47, 0xe6, 0x00, + 0x27, 0x46, 0x07, 0x06, 0x65, 0x96, 0xe9, 0x02, + 0x36, 0x00, 0x16, 0x06, 0x45, 0xe0, 0x16, 0xe5, + 0x28, 0x47, 0xa6, 0x07, 0x06, 0x67, 0x26, 0x07, + 0x26, 0x25, 0x16, 0x05, 0xe0, 0x00, 0xe9, 0x02, + 0xe0, 0x80, 0x1e, 0xe5, 0x27, 0x47, 0x66, 0x20, + 0x67, 0x26, 0x07, 0x26, 0xf6, 0x0f, 0x65, 0x26, + 0xe0, 0x1a, 0xe5, 0x28, 0x47, 0xe6, 0x00, 0x27, + 0x06, 0x07, 0x26, 0x56, 0x05, 0xe0, 0x03, 0xe9, + 0x02, 0xa0, 0xf6, 0x05, 0xe0, 0x0b, 0xe5, 0x23, + 0x06, 0x07, 0x06, 0x27, 0xa6, 0x07, 0x06, 0x05, + 0x16, 0xa0, 0xe9, 0x02, 0xa0, 0xe9, 0x0c, 0xe0, + 0x14, 0xe5, 0x13, 0x20, 0x06, 0x07, 0x06, 0x27, 0x66, 0x07, 0x86, 0x60, 0xe9, 0x02, 0x2b, 0x56, 0x0f, 0xc5, 0xe0, 0x80, 0x31, 0xe5, 0x24, 0x47, 0xe6, 0x01, 0x07, 0x26, 0x16, 0xe0, 0x5c, 0xe1, @@ -2787,7 +2769,8 @@ static const uint8_t unicode_gc_table[3948] = { 0x05, 0x66, 0xf6, 0x00, 0x06, 0xe0, 0x00, 0x05, 0xa6, 0x27, 0x46, 0xe5, 0x26, 0xe6, 0x05, 0x07, 0x26, 0x56, 0x05, 0x96, 0xe0, 0x05, 0xe5, 0x41, - 0xc0, 0xf6, 0x02, 0xe0, 0x80, 0x6e, 0xe5, 0x01, + 0xc0, 0xf6, 0x02, 0xe0, 0x80, 0x2e, 0xe5, 0x19, + 0x16, 0xe0, 0x06, 0xe9, 0x02, 0xa0, 0xe5, 0x01, 0x00, 0xe5, 0x1d, 0x07, 0xc6, 0x00, 0xa6, 0x07, 0x06, 0x05, 0x96, 0xe0, 0x02, 0xe9, 0x02, 0xeb, 0x0b, 0x40, 0x36, 0xe5, 0x16, 0x20, 0xe6, 0x0e, @@ -2800,106 +2783,112 @@ static const uint8_t unicode_gc_table[3948] = { 0x80, 0xae, 0xe5, 0x0b, 0x26, 0x27, 0x36, 0xc0, 0x26, 0x05, 0x07, 0xe5, 0x05, 0x00, 0xe5, 0x1a, 0x27, 0x86, 0x40, 0x27, 0x06, 0x07, 0x06, 0xf6, - 0x05, 0xe9, 0x02, 0xe0, 0x4e, 0x05, 0xe0, 0x07, - 0xeb, 0x0d, 0xef, 0x00, 0x6d, 0xef, 0x09, 0xe0, - 0x05, 0x16, 0xe5, 0x83, 0x12, 0xe0, 0x5e, 0xea, - 0x67, 0x00, 0x96, 0xe0, 0x03, 0xe5, 0x80, 0x3c, - 0xe0, 0x89, 0xc4, 0xe5, 0x59, 0x36, 0xe0, 0x05, - 0xe5, 0x83, 0xa8, 0xfb, 0x08, 0x06, 0xa5, 0xe6, - 0x07, 0xe0, 0x8f, 0x22, 0xe5, 0x81, 0xbf, 0xe0, - 0xa1, 0x31, 0xe5, 0x81, 0xb1, 0xc0, 0xe5, 0x17, - 0x00, 0xe9, 0x02, 0x60, 0x36, 0xe5, 0x47, 0x00, - 0xe9, 0x02, 0xa0, 0xe5, 0x16, 0x20, 0x86, 0x16, - 0xe0, 0x02, 0xe5, 0x28, 0xc6, 0x96, 0x6f, 0x64, - 0x16, 0x0f, 0xe0, 0x02, 0xe9, 0x02, 0x00, 0xcb, - 0x00, 0xe5, 0x0d, 0x80, 0xe5, 0x0b, 0xe0, 0x82, - 0x28, 0xe1, 0x18, 0xe2, 0x18, 0xeb, 0x0f, 0x76, - 0xe0, 0x5d, 0xe5, 0x43, 0x60, 0x06, 0x05, 0xe7, - 0x2f, 0xc0, 0x66, 0xe4, 0x05, 0xe0, 0x38, 0x24, - 0x16, 0x04, 0x06, 0xe0, 0x03, 0x27, 0xe0, 0x06, - 0xe5, 0x97, 0x70, 0xe0, 0x00, 0xe5, 0x84, 0x4e, - 0xe0, 0x22, 0xe5, 0x01, 0xe0, 0xa2, 0x5f, 0x64, - 0x00, 0xc4, 0x00, 0x24, 0x00, 0xe5, 0x80, 0x9b, - 0xe0, 0x07, 0x05, 0xe0, 0x15, 0x45, 0x20, 0x05, - 0xe0, 0x06, 0x65, 0xe0, 0x00, 0xe5, 0x81, 0x04, - 0xe0, 0x88, 0x7c, 0xe5, 0x63, 0x80, 0xe5, 0x05, - 0x40, 0xe5, 0x01, 0xc0, 0xe5, 0x02, 0x20, 0x0f, - 0x26, 0x16, 0x7b, 0xe0, 0x91, 0xd4, 0xe6, 0x26, - 0x20, 0xe6, 0x0f, 0xe0, 0x01, 0xef, 0x6c, 0xe0, - 0x34, 0xef, 0x80, 0x6e, 0xe0, 0x02, 0xef, 0x1f, - 0x20, 0xef, 0x34, 0x27, 0x46, 0x4f, 0xa7, 0xfb, - 0x00, 0xe6, 0x00, 0x2f, 0xc6, 0xef, 0x16, 0x66, - 0xef, 0x35, 0xe0, 0x0d, 0xef, 0x3a, 0x46, 0x0f, - 0xe0, 0x72, 0xeb, 0x0c, 0xe0, 0x04, 0xeb, 0x0c, - 0xe0, 0x04, 0xef, 0x4f, 0xe0, 0x01, 0xeb, 0x11, - 0xe0, 0x7f, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12, - 0xc2, 0x00, 0xe2, 0x0a, 0xe1, 0x12, 0xe2, 0x12, - 0x01, 0x00, 0x21, 0x20, 0x01, 0x20, 0x21, 0x20, - 0x61, 0x00, 0xe1, 0x00, 0x62, 0x00, 0x02, 0x00, - 0xc2, 0x00, 0xe2, 0x03, 0xe1, 0x12, 0xe2, 0x12, - 0x21, 0x00, 0x61, 0x20, 0xe1, 0x00, 0x00, 0xc1, - 0x00, 0xe2, 0x12, 0x21, 0x00, 0x61, 0x00, 0x81, - 0x00, 0x01, 0x40, 0xc1, 0x00, 0xe2, 0x12, 0xe1, + 0x05, 0xe9, 0x02, 0x06, 0xe0, 0x4d, 0x05, 0xe0, + 0x07, 0xeb, 0x0d, 0xef, 0x00, 0x6d, 0xef, 0x09, + 0xe0, 0x05, 0x16, 0xe5, 0x83, 0x12, 0xe0, 0x5e, + 0xea, 0x67, 0x00, 0x96, 0xe0, 0x03, 0xe5, 0x80, + 0x3c, 0xe0, 0x89, 0xc4, 0xe5, 0x59, 0x36, 0xe0, + 0x05, 0xe5, 0x83, 0xa8, 0xfb, 0x08, 0x06, 0xa5, + 0xe6, 0x07, 0xe0, 0x02, 0xe5, 0x8f, 0x13, 0x80, + 0xe5, 0x81, 0xbf, 0xe0, 0x9a, 0x31, 0xe5, 0x16, + 0xe6, 0x04, 0x47, 0x46, 0xe9, 0x02, 0xe0, 0x86, + 0x3e, 0xe5, 0x81, 0xb1, 0xc0, 0xe5, 0x17, 0x00, + 0xe9, 0x02, 0x60, 0x36, 0xe5, 0x47, 0x00, 0xe9, + 0x02, 0xa0, 0xe5, 0x16, 0x20, 0x86, 0x16, 0xe0, + 0x02, 0xe5, 0x28, 0xc6, 0x96, 0x6f, 0x64, 0x16, + 0x0f, 0xe0, 0x02, 0xe9, 0x02, 0x00, 0xcb, 0x00, + 0xe5, 0x0d, 0x80, 0xe5, 0x0b, 0xe0, 0x81, 0x28, + 0x44, 0xe5, 0x20, 0x24, 0x56, 0xe9, 0x02, 0xe0, + 0x80, 0x3e, 0xe1, 0x18, 0xe2, 0x18, 0xeb, 0x0f, + 0x76, 0xe0, 0x5d, 0xe5, 0x43, 0x60, 0x06, 0x05, + 0xe7, 0x2f, 0xc0, 0x66, 0xe4, 0x05, 0xe0, 0x38, + 0x24, 0x16, 0x04, 0x06, 0xe0, 0x03, 0x27, 0xe0, + 0x06, 0xe5, 0x97, 0x70, 0xe0, 0x00, 0xe5, 0x84, + 0x4e, 0xe0, 0x21, 0xe5, 0x02, 0xe0, 0xa2, 0x5f, + 0x64, 0x00, 0xc4, 0x00, 0x24, 0x00, 0xe5, 0x80, + 0x9b, 0xe0, 0x07, 0x05, 0xe0, 0x15, 0x45, 0x20, + 0x05, 0xe0, 0x06, 0x65, 0xe0, 0x00, 0xe5, 0x81, + 0x04, 0xe0, 0x88, 0x7c, 0xe5, 0x63, 0x80, 0xe5, + 0x05, 0x40, 0xe5, 0x01, 0xc0, 0xe5, 0x02, 0x20, + 0x0f, 0x26, 0x16, 0x7b, 0xe0, 0x8e, 0xd4, 0xef, + 0x80, 0x68, 0xe9, 0x02, 0xa0, 0xef, 0x81, 0x2c, + 0xe0, 0x44, 0xe6, 0x26, 0x20, 0xe6, 0x0f, 0xe0, + 0x01, 0xef, 0x6c, 0xe0, 0x34, 0xef, 0x80, 0x6e, + 0xe0, 0x02, 0xef, 0x1f, 0x20, 0xef, 0x34, 0x27, + 0x46, 0x4f, 0xa7, 0xfb, 0x00, 0xe6, 0x00, 0x2f, + 0xc6, 0xef, 0x16, 0x66, 0xef, 0x35, 0xe0, 0x0d, + 0xef, 0x3a, 0x46, 0x0f, 0xe0, 0x72, 0xeb, 0x0c, + 0xe0, 0x04, 0xeb, 0x0c, 0xe0, 0x04, 0xef, 0x4f, + 0xe0, 0x01, 0xeb, 0x11, 0xe0, 0x7f, 0xe1, 0x12, + 0xe2, 0x12, 0xe1, 0x12, 0xc2, 0x00, 0xe2, 0x0a, + 0xe1, 0x12, 0xe2, 0x12, 0x01, 0x00, 0x21, 0x20, + 0x01, 0x20, 0x21, 0x20, 0x61, 0x00, 0xe1, 0x00, + 0x62, 0x00, 0x02, 0x00, 0xc2, 0x00, 0xe2, 0x03, + 0xe1, 0x12, 0xe2, 0x12, 0x21, 0x00, 0x61, 0x20, + 0xe1, 0x00, 0x00, 0xc1, 0x00, 0xe2, 0x12, 0x21, + 0x00, 0x61, 0x00, 0x81, 0x00, 0x01, 0x40, 0xc1, + 0x00, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, - 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x14, 0x20, - 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1, - 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11, - 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c, - 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2, - 0x11, 0x0c, 0xa2, 0x3f, 0x20, 0xe9, 0x2a, 0xef, - 0x81, 0x78, 0xe6, 0x2f, 0x6f, 0xe6, 0x2a, 0xef, - 0x00, 0x06, 0xef, 0x06, 0x06, 0x2f, 0x96, 0xe0, - 0x07, 0x86, 0x00, 0xe6, 0x07, 0xe0, 0x83, 0xc8, - 0xe2, 0x02, 0x05, 0xe2, 0x0c, 0xa0, 0xa2, 0xe0, - 0x80, 0x4d, 0xc6, 0x00, 0xe6, 0x09, 0x20, 0xc6, - 0x00, 0x26, 0x00, 0x86, 0x80, 0xe4, 0x36, 0xe0, - 0x19, 0x06, 0xe0, 0x68, 0xe5, 0x25, 0x40, 0xc6, - 0xc4, 0x20, 0xe9, 0x02, 0x60, 0x05, 0x0f, 0xe0, - 0x80, 0xb8, 0xe5, 0x16, 0x06, 0xe0, 0x09, 0xe5, - 0x24, 0x66, 0xe9, 0x02, 0x80, 0x0d, 0xe0, 0x81, - 0x48, 0xe5, 0x13, 0x04, 0x66, 0xe9, 0x02, 0xe0, - 0x82, 0x5e, 0xc5, 0x00, 0x65, 0x00, 0x25, 0x00, - 0xe5, 0x07, 0x00, 0xe5, 0x80, 0x3d, 0x20, 0xeb, - 0x01, 0xc6, 0xe0, 0x21, 0xe1, 0x1a, 0xe2, 0x1a, - 0xc6, 0x04, 0x60, 0xe9, 0x02, 0x60, 0x36, 0xe0, - 0x82, 0x89, 0xeb, 0x33, 0x0f, 0x4b, 0x0d, 0x6b, - 0xe0, 0x44, 0xeb, 0x25, 0x0f, 0xeb, 0x07, 0xe0, - 0x80, 0x3a, 0x65, 0x00, 0xe5, 0x13, 0x00, 0x25, - 0x00, 0x05, 0x20, 0x05, 0x00, 0xe5, 0x02, 0x00, - 0x65, 0x00, 0x05, 0x00, 0x05, 0xa0, 0x05, 0x60, - 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x45, 0x00, - 0x25, 0x00, 0x05, 0x20, 0x05, 0x00, 0x05, 0x00, - 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x25, 0x00, - 0x05, 0x20, 0x65, 0x00, 0xc5, 0x00, 0x65, 0x00, - 0x65, 0x00, 0x05, 0x00, 0xe5, 0x02, 0x00, 0xe5, - 0x09, 0x80, 0x45, 0x00, 0x85, 0x00, 0xe5, 0x09, - 0xe0, 0x2c, 0x2c, 0xe0, 0x80, 0x86, 0xef, 0x24, - 0x60, 0xef, 0x5c, 0xe0, 0x04, 0xef, 0x07, 0x20, - 0xef, 0x07, 0x00, 0xef, 0x07, 0x00, 0xef, 0x1d, - 0xe0, 0x02, 0xeb, 0x05, 0xef, 0x80, 0x19, 0xe0, - 0x30, 0xef, 0x15, 0xe0, 0x05, 0xef, 0x24, 0x60, - 0xef, 0x01, 0xc0, 0x2f, 0xe0, 0x06, 0xaf, 0xe0, - 0x80, 0x12, 0xef, 0x80, 0x73, 0x8e, 0xef, 0x82, - 0x50, 0x60, 0xef, 0x09, 0x40, 0xef, 0x05, 0x40, - 0xef, 0x6f, 0x60, 0xef, 0x57, 0xa0, 0xef, 0x04, - 0x60, 0x0f, 0xe0, 0x07, 0xef, 0x04, 0x60, 0xef, - 0x30, 0xe0, 0x00, 0xef, 0x02, 0xa0, 0xef, 0x20, - 0xe0, 0x00, 0xef, 0x16, 0x20, 0x2f, 0xe0, 0x46, - 0xef, 0x80, 0xcc, 0xe0, 0x04, 0xef, 0x06, 0x20, - 0xef, 0x05, 0x40, 0xef, 0x01, 0xc0, 0xef, 0x26, - 0x00, 0xcf, 0xe0, 0x00, 0xef, 0x06, 0x60, 0xef, - 0x01, 0xc0, 0xef, 0x01, 0xc0, 0xef, 0x80, 0x0b, - 0x00, 0xef, 0x2f, 0xe0, 0x1d, 0xe9, 0x02, 0xe0, - 0x83, 0x7e, 0xe5, 0xc0, 0x66, 0x58, 0xe0, 0x18, - 0xe5, 0x8f, 0xb2, 0xa0, 0xe5, 0x80, 0x56, 0x20, - 0xe5, 0x95, 0xfa, 0xe0, 0x06, 0xe5, 0x9c, 0xa9, - 0xe0, 0x8b, 0x97, 0xe5, 0x81, 0x96, 0xe0, 0x85, - 0x5a, 0xe5, 0x92, 0xc3, 0x80, 0xe5, 0x8f, 0xd8, - 0xe0, 0xca, 0x9b, 0xc9, 0x1b, 0xe0, 0x16, 0xfb, - 0x58, 0xe0, 0x78, 0xe6, 0x80, 0x68, 0xe0, 0xc0, - 0xbd, 0x88, 0xfd, 0xc0, 0xbf, 0x76, 0x20, 0xfd, - 0xc0, 0xbf, 0x76, 0x20, + 0x12, 0xe2, 0x14, 0x20, 0xe1, 0x11, 0x0c, 0xe2, + 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2, 0x11, + 0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, + 0xa2, 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, + 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0x3f, + 0x20, 0xe9, 0x2a, 0xef, 0x81, 0x78, 0xe6, 0x2f, + 0x6f, 0xe6, 0x2a, 0xef, 0x00, 0x06, 0xef, 0x06, + 0x06, 0x2f, 0x96, 0xe0, 0x07, 0x86, 0x00, 0xe6, + 0x07, 0xe0, 0x83, 0xc8, 0xe2, 0x02, 0x05, 0xe2, + 0x0c, 0xa0, 0xa2, 0xe0, 0x80, 0x4d, 0xc6, 0x00, + 0xe6, 0x09, 0x20, 0xc6, 0x00, 0x26, 0x00, 0x86, + 0x80, 0xe4, 0x36, 0xe0, 0x19, 0x06, 0xe0, 0x68, + 0xe5, 0x25, 0x40, 0xc6, 0xc4, 0x20, 0xe9, 0x02, + 0x60, 0x05, 0x0f, 0xe0, 0x80, 0xb8, 0xe5, 0x16, + 0x06, 0xe0, 0x09, 0xe5, 0x24, 0x66, 0xe9, 0x02, + 0x80, 0x0d, 0xe0, 0x81, 0x48, 0xe5, 0x13, 0x04, + 0x66, 0xe9, 0x02, 0xe0, 0x80, 0x4e, 0xe5, 0x16, + 0x26, 0x05, 0xe9, 0x02, 0x60, 0x16, 0xe0, 0x81, + 0x58, 0xc5, 0x00, 0x65, 0x00, 0x25, 0x00, 0xe5, + 0x07, 0x00, 0xe5, 0x80, 0x3d, 0x20, 0xeb, 0x01, + 0xc6, 0xe0, 0x21, 0xe1, 0x1a, 0xe2, 0x1a, 0xc6, + 0x04, 0x60, 0xe9, 0x02, 0x60, 0x36, 0xe0, 0x82, + 0x89, 0xeb, 0x33, 0x0f, 0x4b, 0x0d, 0x6b, 0xe0, + 0x44, 0xeb, 0x25, 0x0f, 0xeb, 0x07, 0xe0, 0x80, + 0x3a, 0x65, 0x00, 0xe5, 0x13, 0x00, 0x25, 0x00, + 0x05, 0x20, 0x05, 0x00, 0xe5, 0x02, 0x00, 0x65, + 0x00, 0x05, 0x00, 0x05, 0xa0, 0x05, 0x60, 0x05, + 0x00, 0x05, 0x00, 0x05, 0x00, 0x45, 0x00, 0x25, + 0x00, 0x05, 0x20, 0x05, 0x00, 0x05, 0x00, 0x05, + 0x00, 0x05, 0x00, 0x05, 0x00, 0x25, 0x00, 0x05, + 0x20, 0x65, 0x00, 0xc5, 0x00, 0x65, 0x00, 0x65, + 0x00, 0x05, 0x00, 0xe5, 0x02, 0x00, 0xe5, 0x09, + 0x80, 0x45, 0x00, 0x85, 0x00, 0xe5, 0x09, 0xe0, + 0x2c, 0x2c, 0xe0, 0x80, 0x86, 0xef, 0x24, 0x60, + 0xef, 0x5c, 0xe0, 0x04, 0xef, 0x07, 0x20, 0xef, + 0x07, 0x00, 0xef, 0x07, 0x00, 0xef, 0x1d, 0xe0, + 0x02, 0xeb, 0x05, 0xef, 0x80, 0x19, 0xe0, 0x30, + 0xef, 0x15, 0xe0, 0x05, 0xef, 0x24, 0x60, 0xef, + 0x01, 0xc0, 0x2f, 0xe0, 0x06, 0xaf, 0xe0, 0x80, + 0x12, 0xef, 0x80, 0x73, 0x8e, 0xef, 0x82, 0x50, + 0x60, 0xef, 0x09, 0x40, 0xef, 0x05, 0x40, 0xef, + 0x6f, 0x60, 0xef, 0x57, 0xa0, 0xef, 0x04, 0x60, + 0x0f, 0xe0, 0x07, 0xef, 0x04, 0x60, 0xef, 0x30, + 0xe0, 0x00, 0xef, 0x02, 0xa0, 0xef, 0x20, 0xe0, + 0x00, 0xef, 0x16, 0x20, 0xef, 0x04, 0x60, 0x2f, + 0xe0, 0x36, 0xef, 0x80, 0xcc, 0xe0, 0x04, 0xef, + 0x06, 0x20, 0xef, 0x05, 0x40, 0xef, 0x02, 0x80, + 0xef, 0x30, 0xc0, 0xef, 0x07, 0x20, 0xef, 0x03, + 0xa0, 0xef, 0x01, 0xc0, 0xef, 0x80, 0x0b, 0x00, + 0xef, 0x54, 0xe9, 0x02, 0xe0, 0x83, 0x7e, 0xe5, + 0xc0, 0x66, 0x58, 0xe0, 0x18, 0xe5, 0x8f, 0xb2, + 0xa0, 0xe5, 0x80, 0x56, 0x20, 0xe5, 0x95, 0xfa, + 0xe0, 0x06, 0xe5, 0x9c, 0xa9, 0xe0, 0x07, 0xe5, + 0x81, 0xe6, 0xe0, 0x89, 0x1a, 0xe5, 0x81, 0x96, + 0xe0, 0x85, 0x5a, 0xe5, 0x92, 0xc3, 0x80, 0xe5, + 0x8f, 0xd8, 0xe0, 0xca, 0x9b, 0xc9, 0x1b, 0xe0, + 0x16, 0xfb, 0x58, 0xe0, 0x78, 0xe6, 0x80, 0x68, + 0xe0, 0xc0, 0xbd, 0x88, 0xfd, 0xc0, 0xbf, 0x76, + 0x20, 0xfd, 0xc0, 0xbf, 0x76, 0x20, }; typedef enum { @@ -2946,11 +2935,13 @@ typedef enum { UNICODE_SCRIPT_Georgian, UNICODE_SCRIPT_Glagolitic, UNICODE_SCRIPT_Gothic, + UNICODE_SCRIPT_Garay, UNICODE_SCRIPT_Grantha, UNICODE_SCRIPT_Greek, UNICODE_SCRIPT_Gujarati, UNICODE_SCRIPT_Gunjala_Gondi, UNICODE_SCRIPT_Gurmukhi, + UNICODE_SCRIPT_Gurung_Khema, UNICODE_SCRIPT_Han, UNICODE_SCRIPT_Hangul, UNICODE_SCRIPT_Hanifi_Rohingya, @@ -2973,6 +2964,7 @@ typedef enum { UNICODE_SCRIPT_Khojki, UNICODE_SCRIPT_Khitan_Small_Script, UNICODE_SCRIPT_Khudawadi, + UNICODE_SCRIPT_Kirat_Rai, UNICODE_SCRIPT_Lao, UNICODE_SCRIPT_Latin, UNICODE_SCRIPT_Lepcha, @@ -3010,6 +3002,7 @@ typedef enum { UNICODE_SCRIPT_Nyiakeng_Puachue_Hmong, UNICODE_SCRIPT_Ogham, UNICODE_SCRIPT_Ol_Chiki, + UNICODE_SCRIPT_Ol_Onal, UNICODE_SCRIPT_Old_Hungarian, UNICODE_SCRIPT_Old_Italic, UNICODE_SCRIPT_Old_North_Arabian, @@ -3041,6 +3034,7 @@ typedef enum { UNICODE_SCRIPT_Sora_Sompeng, UNICODE_SCRIPT_Soyombo, UNICODE_SCRIPT_Sundanese, + UNICODE_SCRIPT_Sunuwar, UNICODE_SCRIPT_Syloti_Nagri, UNICODE_SCRIPT_Syriac, UNICODE_SCRIPT_Tagalog, @@ -3058,7 +3052,9 @@ typedef enum { UNICODE_SCRIPT_Tifinagh, UNICODE_SCRIPT_Tirhuta, UNICODE_SCRIPT_Tangsa, + UNICODE_SCRIPT_Todhri, UNICODE_SCRIPT_Toto, + UNICODE_SCRIPT_Tulu_Tigalari, UNICODE_SCRIPT_Ugaritic, UNICODE_SCRIPT_Vai, UNICODE_SCRIPT_Vithkuqi, @@ -3113,11 +3109,13 @@ static const char unicode_script_name_table[] = "Georgian,Geor" "\0" "Glagolitic,Glag" "\0" "Gothic,Goth" "\0" + "Garay,Gara" "\0" "Grantha,Gran" "\0" "Greek,Grek" "\0" "Gujarati,Gujr" "\0" "Gunjala_Gondi,Gong" "\0" "Gurmukhi,Guru" "\0" + "Gurung_Khema,Gukh" "\0" "Han,Hani" "\0" "Hangul,Hang" "\0" "Hanifi_Rohingya,Rohg" "\0" @@ -3140,6 +3138,7 @@ static const char unicode_script_name_table[] = "Khojki,Khoj" "\0" "Khitan_Small_Script,Kits" "\0" "Khudawadi,Sind" "\0" + "Kirat_Rai,Krai" "\0" "Lao,Laoo" "\0" "Latin,Latn" "\0" "Lepcha,Lepc" "\0" @@ -3177,6 +3176,7 @@ static const char unicode_script_name_table[] = "Nyiakeng_Puachue_Hmong,Hmnp" "\0" "Ogham,Ogam" "\0" "Ol_Chiki,Olck" "\0" + "Ol_Onal,Onao" "\0" "Old_Hungarian,Hung" "\0" "Old_Italic,Ital" "\0" "Old_North_Arabian,Narb" "\0" @@ -3208,6 +3208,7 @@ static const char unicode_script_name_table[] = "Sora_Sompeng,Sora" "\0" "Soyombo,Soyo" "\0" "Sundanese,Sund" "\0" + "Sunuwar,Sunu" "\0" "Syloti_Nagri,Sylo" "\0" "Syriac,Syrc" "\0" "Tagalog,Tglg" "\0" @@ -3225,7 +3226,9 @@ static const char unicode_script_name_table[] = "Tifinagh,Tfng" "\0" "Tirhuta,Tirh" "\0" "Tangsa,Tnsa" "\0" + "Todhri,Todr" "\0" "Toto,Toto" "\0" + "Tulu_Tigalari,Tutg" "\0" "Ugaritic,Ugar" "\0" "Vai,Vaii" "\0" "Vithkuqi,Vith" "\0" @@ -3236,87 +3239,87 @@ static const char unicode_script_name_table[] = "Zanabazar_Square,Zanb" "\0" ; -static const uint8_t unicode_script_table[2720] = { - 0xc0, 0x19, 0x99, 0x47, 0x85, 0x19, 0x99, 0x47, - 0xae, 0x19, 0x80, 0x47, 0x8e, 0x19, 0x80, 0x47, - 0x84, 0x19, 0x96, 0x47, 0x80, 0x19, 0x9e, 0x47, - 0x80, 0x19, 0xe1, 0x60, 0x47, 0xa6, 0x19, 0x84, - 0x47, 0x84, 0x19, 0x81, 0x0d, 0x93, 0x19, 0xe0, - 0x0f, 0x38, 0x83, 0x2c, 0x80, 0x19, 0x82, 0x2c, - 0x01, 0x83, 0x2c, 0x80, 0x19, 0x80, 0x2c, 0x03, - 0x80, 0x2c, 0x80, 0x19, 0x80, 0x2c, 0x80, 0x19, - 0x82, 0x2c, 0x00, 0x80, 0x2c, 0x00, 0x93, 0x2c, - 0x00, 0xbe, 0x2c, 0x8d, 0x1a, 0x8f, 0x2c, 0xe0, - 0x24, 0x1d, 0x81, 0x38, 0xe0, 0x48, 0x1d, 0x00, +static const uint8_t unicode_script_table[2803] = { + 0xc0, 0x19, 0x99, 0x4a, 0x85, 0x19, 0x99, 0x4a, + 0xae, 0x19, 0x80, 0x4a, 0x8e, 0x19, 0x80, 0x4a, + 0x84, 0x19, 0x96, 0x4a, 0x80, 0x19, 0x9e, 0x4a, + 0x80, 0x19, 0xe1, 0x60, 0x4a, 0xa6, 0x19, 0x84, + 0x4a, 0x84, 0x19, 0x81, 0x0d, 0x93, 0x19, 0xe0, + 0x0f, 0x3a, 0x83, 0x2d, 0x80, 0x19, 0x82, 0x2d, + 0x01, 0x83, 0x2d, 0x80, 0x19, 0x80, 0x2d, 0x03, + 0x80, 0x2d, 0x80, 0x19, 0x80, 0x2d, 0x80, 0x19, + 0x82, 0x2d, 0x00, 0x80, 0x2d, 0x00, 0x93, 0x2d, + 0x00, 0xbe, 0x2d, 0x8d, 0x1a, 0x8f, 0x2d, 0xe0, + 0x24, 0x1d, 0x81, 0x3a, 0xe0, 0x48, 0x1d, 0x00, 0xa5, 0x05, 0x01, 0xb1, 0x05, 0x01, 0x82, 0x05, - 0x00, 0xb6, 0x35, 0x07, 0x9a, 0x35, 0x03, 0x85, - 0x35, 0x0a, 0x84, 0x04, 0x80, 0x19, 0x85, 0x04, + 0x00, 0xb6, 0x37, 0x07, 0x9a, 0x37, 0x03, 0x85, + 0x37, 0x0a, 0x84, 0x04, 0x80, 0x19, 0x85, 0x04, 0x80, 0x19, 0x8d, 0x04, 0x80, 0x19, 0x82, 0x04, 0x80, 0x19, 0x9f, 0x04, 0x80, 0x19, 0x89, 0x04, - 0x8a, 0x38, 0x99, 0x04, 0x80, 0x38, 0xe0, 0x0b, - 0x04, 0x80, 0x19, 0xa1, 0x04, 0x8d, 0x8b, 0x00, - 0xbb, 0x8b, 0x01, 0x82, 0x8b, 0xaf, 0x04, 0xb1, - 0x95, 0x0d, 0xba, 0x66, 0x01, 0x82, 0x66, 0xad, - 0x7f, 0x01, 0x8e, 0x7f, 0x00, 0x9b, 0x52, 0x01, - 0x80, 0x52, 0x00, 0x8a, 0x8b, 0x04, 0x9e, 0x04, - 0x00, 0x81, 0x04, 0x05, 0xc9, 0x04, 0x80, 0x19, - 0x9c, 0x04, 0xd0, 0x20, 0x83, 0x38, 0x8e, 0x20, + 0x8a, 0x3a, 0x99, 0x04, 0x80, 0x3a, 0xe0, 0x0b, + 0x04, 0x80, 0x19, 0xa1, 0x04, 0x8d, 0x90, 0x00, + 0xbb, 0x90, 0x01, 0x82, 0x90, 0xaf, 0x04, 0xb1, + 0x9a, 0x0d, 0xba, 0x69, 0x01, 0x82, 0x69, 0xad, + 0x83, 0x01, 0x8e, 0x83, 0x00, 0x9b, 0x55, 0x01, + 0x80, 0x55, 0x00, 0x8a, 0x90, 0x04, 0x9e, 0x04, + 0x00, 0x81, 0x04, 0x04, 0xca, 0x04, 0x80, 0x19, + 0x9c, 0x04, 0xd0, 0x20, 0x83, 0x3a, 0x8e, 0x20, 0x81, 0x19, 0x99, 0x20, 0x83, 0x0b, 0x00, 0x87, 0x0b, 0x01, 0x81, 0x0b, 0x01, 0x95, 0x0b, 0x00, 0x86, 0x0b, 0x00, 0x80, 0x0b, 0x02, 0x83, 0x0b, 0x01, 0x88, 0x0b, 0x01, 0x81, 0x0b, 0x01, 0x83, 0x0b, 0x07, 0x80, 0x0b, 0x03, 0x81, 0x0b, 0x00, - 0x84, 0x0b, 0x01, 0x98, 0x0b, 0x01, 0x82, 0x2f, - 0x00, 0x85, 0x2f, 0x03, 0x81, 0x2f, 0x01, 0x95, - 0x2f, 0x00, 0x86, 0x2f, 0x00, 0x81, 0x2f, 0x00, - 0x81, 0x2f, 0x00, 0x81, 0x2f, 0x01, 0x80, 0x2f, - 0x00, 0x84, 0x2f, 0x03, 0x81, 0x2f, 0x01, 0x82, - 0x2f, 0x02, 0x80, 0x2f, 0x06, 0x83, 0x2f, 0x00, - 0x80, 0x2f, 0x06, 0x90, 0x2f, 0x09, 0x82, 0x2d, - 0x00, 0x88, 0x2d, 0x00, 0x82, 0x2d, 0x00, 0x95, - 0x2d, 0x00, 0x86, 0x2d, 0x00, 0x81, 0x2d, 0x00, - 0x84, 0x2d, 0x01, 0x89, 0x2d, 0x00, 0x82, 0x2d, - 0x00, 0x82, 0x2d, 0x01, 0x80, 0x2d, 0x0e, 0x83, - 0x2d, 0x01, 0x8b, 0x2d, 0x06, 0x86, 0x2d, 0x00, - 0x82, 0x74, 0x00, 0x87, 0x74, 0x01, 0x81, 0x74, - 0x01, 0x95, 0x74, 0x00, 0x86, 0x74, 0x00, 0x81, - 0x74, 0x00, 0x84, 0x74, 0x01, 0x88, 0x74, 0x01, - 0x81, 0x74, 0x01, 0x82, 0x74, 0x06, 0x82, 0x74, - 0x03, 0x81, 0x74, 0x00, 0x84, 0x74, 0x01, 0x91, - 0x74, 0x09, 0x81, 0x92, 0x00, 0x85, 0x92, 0x02, - 0x82, 0x92, 0x00, 0x83, 0x92, 0x02, 0x81, 0x92, - 0x00, 0x80, 0x92, 0x00, 0x81, 0x92, 0x02, 0x81, - 0x92, 0x02, 0x82, 0x92, 0x02, 0x8b, 0x92, 0x03, - 0x84, 0x92, 0x02, 0x82, 0x92, 0x00, 0x83, 0x92, - 0x01, 0x80, 0x92, 0x05, 0x80, 0x92, 0x0d, 0x94, - 0x92, 0x04, 0x8c, 0x94, 0x00, 0x82, 0x94, 0x00, - 0x96, 0x94, 0x00, 0x8f, 0x94, 0x01, 0x88, 0x94, - 0x00, 0x82, 0x94, 0x00, 0x83, 0x94, 0x06, 0x81, - 0x94, 0x00, 0x82, 0x94, 0x01, 0x80, 0x94, 0x01, - 0x83, 0x94, 0x01, 0x89, 0x94, 0x06, 0x88, 0x94, - 0x8c, 0x3d, 0x00, 0x82, 0x3d, 0x00, 0x96, 0x3d, - 0x00, 0x89, 0x3d, 0x00, 0x84, 0x3d, 0x01, 0x88, - 0x3d, 0x00, 0x82, 0x3d, 0x00, 0x83, 0x3d, 0x06, - 0x81, 0x3d, 0x05, 0x81, 0x3d, 0x00, 0x83, 0x3d, - 0x01, 0x89, 0x3d, 0x00, 0x82, 0x3d, 0x0b, 0x8c, - 0x51, 0x00, 0x82, 0x51, 0x00, 0xb2, 0x51, 0x00, - 0x82, 0x51, 0x00, 0x85, 0x51, 0x03, 0x8f, 0x51, - 0x01, 0x99, 0x51, 0x00, 0x82, 0x85, 0x00, 0x91, - 0x85, 0x02, 0x97, 0x85, 0x00, 0x88, 0x85, 0x00, - 0x80, 0x85, 0x01, 0x86, 0x85, 0x02, 0x80, 0x85, - 0x03, 0x85, 0x85, 0x00, 0x80, 0x85, 0x00, 0x87, - 0x85, 0x05, 0x89, 0x85, 0x01, 0x82, 0x85, 0x0b, - 0xb9, 0x96, 0x03, 0x80, 0x19, 0x9b, 0x96, 0x24, - 0x81, 0x46, 0x00, 0x80, 0x46, 0x00, 0x84, 0x46, - 0x00, 0x97, 0x46, 0x00, 0x80, 0x46, 0x00, 0x96, - 0x46, 0x01, 0x84, 0x46, 0x00, 0x80, 0x46, 0x00, - 0x86, 0x46, 0x00, 0x89, 0x46, 0x01, 0x83, 0x46, - 0x1f, 0xc7, 0x97, 0x00, 0xa3, 0x97, 0x03, 0xa6, - 0x97, 0x00, 0xa3, 0x97, 0x00, 0x8e, 0x97, 0x00, - 0x86, 0x97, 0x83, 0x19, 0x81, 0x97, 0x24, 0xe0, - 0x3f, 0x60, 0xa5, 0x28, 0x00, 0x80, 0x28, 0x04, + 0x84, 0x0b, 0x01, 0x98, 0x0b, 0x01, 0x82, 0x30, + 0x00, 0x85, 0x30, 0x03, 0x81, 0x30, 0x01, 0x95, + 0x30, 0x00, 0x86, 0x30, 0x00, 0x81, 0x30, 0x00, + 0x81, 0x30, 0x00, 0x81, 0x30, 0x01, 0x80, 0x30, + 0x00, 0x84, 0x30, 0x03, 0x81, 0x30, 0x01, 0x82, + 0x30, 0x02, 0x80, 0x30, 0x06, 0x83, 0x30, 0x00, + 0x80, 0x30, 0x06, 0x90, 0x30, 0x09, 0x82, 0x2e, + 0x00, 0x88, 0x2e, 0x00, 0x82, 0x2e, 0x00, 0x95, + 0x2e, 0x00, 0x86, 0x2e, 0x00, 0x81, 0x2e, 0x00, + 0x84, 0x2e, 0x01, 0x89, 0x2e, 0x00, 0x82, 0x2e, + 0x00, 0x82, 0x2e, 0x01, 0x80, 0x2e, 0x0e, 0x83, + 0x2e, 0x01, 0x8b, 0x2e, 0x06, 0x86, 0x2e, 0x00, + 0x82, 0x78, 0x00, 0x87, 0x78, 0x01, 0x81, 0x78, + 0x01, 0x95, 0x78, 0x00, 0x86, 0x78, 0x00, 0x81, + 0x78, 0x00, 0x84, 0x78, 0x01, 0x88, 0x78, 0x01, + 0x81, 0x78, 0x01, 0x82, 0x78, 0x06, 0x82, 0x78, + 0x03, 0x81, 0x78, 0x00, 0x84, 0x78, 0x01, 0x91, + 0x78, 0x09, 0x81, 0x97, 0x00, 0x85, 0x97, 0x02, + 0x82, 0x97, 0x00, 0x83, 0x97, 0x02, 0x81, 0x97, + 0x00, 0x80, 0x97, 0x00, 0x81, 0x97, 0x02, 0x81, + 0x97, 0x02, 0x82, 0x97, 0x02, 0x8b, 0x97, 0x03, + 0x84, 0x97, 0x02, 0x82, 0x97, 0x00, 0x83, 0x97, + 0x01, 0x80, 0x97, 0x05, 0x80, 0x97, 0x0d, 0x94, + 0x97, 0x04, 0x8c, 0x99, 0x00, 0x82, 0x99, 0x00, + 0x96, 0x99, 0x00, 0x8f, 0x99, 0x01, 0x88, 0x99, + 0x00, 0x82, 0x99, 0x00, 0x83, 0x99, 0x06, 0x81, + 0x99, 0x00, 0x82, 0x99, 0x01, 0x80, 0x99, 0x01, + 0x83, 0x99, 0x01, 0x89, 0x99, 0x06, 0x88, 0x99, + 0x8c, 0x3f, 0x00, 0x82, 0x3f, 0x00, 0x96, 0x3f, + 0x00, 0x89, 0x3f, 0x00, 0x84, 0x3f, 0x01, 0x88, + 0x3f, 0x00, 0x82, 0x3f, 0x00, 0x83, 0x3f, 0x06, + 0x81, 0x3f, 0x05, 0x81, 0x3f, 0x00, 0x83, 0x3f, + 0x01, 0x89, 0x3f, 0x00, 0x82, 0x3f, 0x0b, 0x8c, + 0x54, 0x00, 0x82, 0x54, 0x00, 0xb2, 0x54, 0x00, + 0x82, 0x54, 0x00, 0x85, 0x54, 0x03, 0x8f, 0x54, + 0x01, 0x99, 0x54, 0x00, 0x82, 0x89, 0x00, 0x91, + 0x89, 0x02, 0x97, 0x89, 0x00, 0x88, 0x89, 0x00, + 0x80, 0x89, 0x01, 0x86, 0x89, 0x02, 0x80, 0x89, + 0x03, 0x85, 0x89, 0x00, 0x80, 0x89, 0x00, 0x87, + 0x89, 0x05, 0x89, 0x89, 0x01, 0x82, 0x89, 0x0b, + 0xb9, 0x9b, 0x03, 0x80, 0x19, 0x9b, 0x9b, 0x24, + 0x81, 0x49, 0x00, 0x80, 0x49, 0x00, 0x84, 0x49, + 0x00, 0x97, 0x49, 0x00, 0x80, 0x49, 0x00, 0x96, + 0x49, 0x01, 0x84, 0x49, 0x00, 0x80, 0x49, 0x00, + 0x86, 0x49, 0x00, 0x89, 0x49, 0x01, 0x83, 0x49, + 0x1f, 0xc7, 0x9c, 0x00, 0xa3, 0x9c, 0x03, 0xa6, + 0x9c, 0x00, 0xa3, 0x9c, 0x00, 0x8e, 0x9c, 0x00, + 0x86, 0x9c, 0x83, 0x19, 0x81, 0x9c, 0x24, 0xe0, + 0x3f, 0x63, 0xa5, 0x28, 0x00, 0x80, 0x28, 0x04, 0x80, 0x28, 0x01, 0xaa, 0x28, 0x80, 0x19, 0x83, - 0x28, 0xe0, 0x9f, 0x31, 0xc8, 0x27, 0x00, 0x83, + 0x28, 0xe0, 0x9f, 0x33, 0xc8, 0x27, 0x00, 0x83, 0x27, 0x01, 0x86, 0x27, 0x00, 0x80, 0x27, 0x00, 0x83, 0x27, 0x01, 0xa8, 0x27, 0x00, 0x83, 0x27, 0x01, 0xa0, 0x27, 0x00, 0x83, 0x27, 0x01, 0x86, @@ -3324,366 +3327,430 @@ static const uint8_t unicode_script_table[2720] = { 0x8e, 0x27, 0x00, 0xb8, 0x27, 0x00, 0x83, 0x27, 0x01, 0xc2, 0x27, 0x01, 0x9f, 0x27, 0x02, 0x99, 0x27, 0x05, 0xd5, 0x17, 0x01, 0x85, 0x17, 0x01, - 0xe2, 0x1f, 0x12, 0x9c, 0x69, 0x02, 0xca, 0x7e, - 0x82, 0x19, 0x8a, 0x7e, 0x06, 0x95, 0x8c, 0x08, - 0x80, 0x8c, 0x94, 0x33, 0x81, 0x19, 0x08, 0x93, - 0x11, 0x0b, 0x8c, 0x8d, 0x00, 0x82, 0x8d, 0x00, - 0x81, 0x8d, 0x0b, 0xdd, 0x42, 0x01, 0x89, 0x42, - 0x05, 0x89, 0x42, 0x05, 0x81, 0x5d, 0x81, 0x19, - 0x80, 0x5d, 0x80, 0x19, 0x93, 0x5d, 0x05, 0xd8, - 0x5d, 0x06, 0xaa, 0x5d, 0x04, 0xc5, 0x12, 0x09, - 0x9e, 0x49, 0x00, 0x8b, 0x49, 0x03, 0x8b, 0x49, - 0x03, 0x80, 0x49, 0x02, 0x8b, 0x49, 0x9d, 0x8e, - 0x01, 0x84, 0x8e, 0x0a, 0xab, 0x64, 0x03, 0x99, - 0x64, 0x05, 0x8a, 0x64, 0x02, 0x81, 0x64, 0x9f, - 0x42, 0x9b, 0x10, 0x01, 0x81, 0x10, 0xbe, 0x8f, - 0x00, 0x9c, 0x8f, 0x01, 0x8a, 0x8f, 0x05, 0x89, - 0x8f, 0x05, 0x8d, 0x8f, 0x01, 0x9e, 0x38, 0x30, - 0xcc, 0x07, 0x02, 0xae, 0x07, 0x00, 0xbf, 0x89, - 0xb3, 0x0a, 0x07, 0x83, 0x0a, 0xb7, 0x48, 0x02, - 0x8e, 0x48, 0x02, 0x82, 0x48, 0xaf, 0x6a, 0x88, - 0x1d, 0x06, 0xaa, 0x28, 0x01, 0x82, 0x28, 0x87, - 0x89, 0x07, 0x82, 0x38, 0x80, 0x19, 0x8c, 0x38, - 0x80, 0x19, 0x86, 0x38, 0x83, 0x19, 0x80, 0x38, - 0x85, 0x19, 0x80, 0x38, 0x82, 0x19, 0x81, 0x38, - 0x80, 0x19, 0x04, 0xa5, 0x47, 0x84, 0x2c, 0x80, - 0x1d, 0xb0, 0x47, 0x84, 0x2c, 0x83, 0x47, 0x84, - 0x2c, 0x8c, 0x47, 0x80, 0x1d, 0xc5, 0x47, 0x80, - 0x2c, 0xbf, 0x38, 0xe0, 0x9f, 0x47, 0x95, 0x2c, - 0x01, 0x85, 0x2c, 0x01, 0xa5, 0x2c, 0x01, 0x85, - 0x2c, 0x01, 0x87, 0x2c, 0x00, 0x80, 0x2c, 0x00, - 0x80, 0x2c, 0x00, 0x80, 0x2c, 0x00, 0x9e, 0x2c, - 0x01, 0xb4, 0x2c, 0x00, 0x8e, 0x2c, 0x00, 0x8d, - 0x2c, 0x01, 0x85, 0x2c, 0x00, 0x92, 0x2c, 0x01, - 0x82, 0x2c, 0x00, 0x88, 0x2c, 0x00, 0x8b, 0x19, - 0x81, 0x38, 0xd6, 0x19, 0x00, 0x8a, 0x19, 0x80, - 0x47, 0x01, 0x8a, 0x19, 0x80, 0x47, 0x8e, 0x19, - 0x00, 0x8c, 0x47, 0x02, 0xa0, 0x19, 0x0e, 0xa0, - 0x38, 0x0e, 0xa5, 0x19, 0x80, 0x2c, 0x82, 0x19, - 0x81, 0x47, 0x85, 0x19, 0x80, 0x47, 0x9a, 0x19, - 0x80, 0x47, 0x90, 0x19, 0xa8, 0x47, 0x82, 0x19, - 0x03, 0xe2, 0x36, 0x19, 0x18, 0x8a, 0x19, 0x14, - 0xe3, 0x3f, 0x19, 0xe0, 0x9f, 0x0f, 0xe2, 0x13, - 0x19, 0x01, 0x9f, 0x19, 0x00, 0xe0, 0x08, 0x19, - 0xdf, 0x29, 0x9f, 0x47, 0xe0, 0x13, 0x1a, 0x04, - 0x86, 0x1a, 0xa5, 0x28, 0x00, 0x80, 0x28, 0x04, - 0x80, 0x28, 0x01, 0xb7, 0x98, 0x06, 0x81, 0x98, - 0x0d, 0x80, 0x98, 0x96, 0x27, 0x08, 0x86, 0x27, + 0xe2, 0x1f, 0x12, 0x9c, 0x6c, 0x02, 0xca, 0x82, + 0x82, 0x19, 0x8a, 0x82, 0x06, 0x95, 0x91, 0x08, + 0x80, 0x91, 0x94, 0x35, 0x81, 0x19, 0x08, 0x93, + 0x11, 0x0b, 0x8c, 0x92, 0x00, 0x82, 0x92, 0x00, + 0x81, 0x92, 0x0b, 0xdd, 0x44, 0x01, 0x89, 0x44, + 0x05, 0x89, 0x44, 0x05, 0x81, 0x60, 0x81, 0x19, + 0x80, 0x60, 0x80, 0x19, 0x93, 0x60, 0x05, 0xd8, + 0x60, 0x06, 0xaa, 0x60, 0x04, 0xc5, 0x12, 0x09, + 0x9e, 0x4c, 0x00, 0x8b, 0x4c, 0x03, 0x8b, 0x4c, + 0x03, 0x80, 0x4c, 0x02, 0x8b, 0x4c, 0x9d, 0x93, + 0x01, 0x84, 0x93, 0x0a, 0xab, 0x67, 0x03, 0x99, + 0x67, 0x05, 0x8a, 0x67, 0x02, 0x81, 0x67, 0x9f, + 0x44, 0x9b, 0x10, 0x01, 0x81, 0x10, 0xbe, 0x94, + 0x00, 0x9c, 0x94, 0x01, 0x8a, 0x94, 0x05, 0x89, + 0x94, 0x05, 0x8d, 0x94, 0x01, 0x9e, 0x3a, 0x30, + 0xcc, 0x07, 0x00, 0xb1, 0x07, 0xbf, 0x8d, 0xb3, + 0x0a, 0x07, 0x83, 0x0a, 0xb7, 0x4b, 0x02, 0x8e, + 0x4b, 0x02, 0x82, 0x4b, 0xaf, 0x6d, 0x8a, 0x1d, + 0x04, 0xaa, 0x28, 0x01, 0x82, 0x28, 0x87, 0x8d, + 0x07, 0x82, 0x3a, 0x80, 0x19, 0x8c, 0x3a, 0x80, + 0x19, 0x86, 0x3a, 0x83, 0x19, 0x80, 0x3a, 0x85, + 0x19, 0x80, 0x3a, 0x82, 0x19, 0x81, 0x3a, 0x80, + 0x19, 0x04, 0xa5, 0x4a, 0x84, 0x2d, 0x80, 0x1d, + 0xb0, 0x4a, 0x84, 0x2d, 0x83, 0x4a, 0x84, 0x2d, + 0x8c, 0x4a, 0x80, 0x1d, 0xc5, 0x4a, 0x80, 0x2d, + 0xbf, 0x3a, 0xe0, 0x9f, 0x4a, 0x95, 0x2d, 0x01, + 0x85, 0x2d, 0x01, 0xa5, 0x2d, 0x01, 0x85, 0x2d, + 0x01, 0x87, 0x2d, 0x00, 0x80, 0x2d, 0x00, 0x80, + 0x2d, 0x00, 0x80, 0x2d, 0x00, 0x9e, 0x2d, 0x01, + 0xb4, 0x2d, 0x00, 0x8e, 0x2d, 0x00, 0x8d, 0x2d, + 0x01, 0x85, 0x2d, 0x00, 0x92, 0x2d, 0x01, 0x82, + 0x2d, 0x00, 0x88, 0x2d, 0x00, 0x8b, 0x19, 0x81, + 0x3a, 0xd6, 0x19, 0x00, 0x8a, 0x19, 0x80, 0x4a, + 0x01, 0x8a, 0x19, 0x80, 0x4a, 0x8e, 0x19, 0x00, + 0x8c, 0x4a, 0x02, 0xa0, 0x19, 0x0e, 0xa0, 0x3a, + 0x0e, 0xa5, 0x19, 0x80, 0x2d, 0x82, 0x19, 0x81, + 0x4a, 0x85, 0x19, 0x80, 0x4a, 0x9a, 0x19, 0x80, + 0x4a, 0x90, 0x19, 0xa8, 0x4a, 0x82, 0x19, 0x03, + 0xe2, 0x39, 0x19, 0x15, 0x8a, 0x19, 0x14, 0xe3, + 0x3f, 0x19, 0xe0, 0x9f, 0x0f, 0xe2, 0x13, 0x19, + 0x01, 0x9f, 0x19, 0x00, 0xe0, 0x08, 0x19, 0xdf, + 0x29, 0x9f, 0x4a, 0xe0, 0x13, 0x1a, 0x04, 0x86, + 0x1a, 0xa5, 0x28, 0x00, 0x80, 0x28, 0x04, 0x80, + 0x28, 0x01, 0xb7, 0x9d, 0x06, 0x81, 0x9d, 0x0d, + 0x80, 0x9d, 0x96, 0x27, 0x08, 0x86, 0x27, 0x00, + 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x86, - 0x27, 0x00, 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, - 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x9f, 0x1d, - 0xdd, 0x19, 0x21, 0x99, 0x30, 0x00, 0xd8, 0x30, - 0x0b, 0xe0, 0x75, 0x30, 0x19, 0x8b, 0x19, 0x03, - 0x84, 0x19, 0x80, 0x30, 0x80, 0x19, 0x80, 0x30, - 0x98, 0x19, 0x88, 0x30, 0x83, 0x38, 0x81, 0x31, - 0x87, 0x19, 0x83, 0x30, 0x83, 0x19, 0x00, 0xd5, - 0x36, 0x01, 0x81, 0x38, 0x81, 0x19, 0x82, 0x36, - 0x80, 0x19, 0xd9, 0x3e, 0x81, 0x19, 0x82, 0x3e, - 0x04, 0xaa, 0x0d, 0x00, 0xdd, 0x31, 0x00, 0x8f, - 0x19, 0x9f, 0x0d, 0xa3, 0x19, 0x0b, 0x8f, 0x3e, - 0x9e, 0x31, 0x00, 0xbf, 0x19, 0x9e, 0x31, 0xd0, - 0x19, 0xae, 0x3e, 0x80, 0x19, 0xd7, 0x3e, 0xe0, - 0x47, 0x19, 0xf0, 0x09, 0x5f, 0x30, 0xbf, 0x19, - 0xf0, 0x41, 0x9f, 0x30, 0xe4, 0x2c, 0xa2, 0x02, - 0xb6, 0xa2, 0x08, 0xaf, 0x4c, 0xe0, 0xcb, 0x9d, - 0x13, 0xdf, 0x1d, 0xd7, 0x08, 0x07, 0xa1, 0x19, - 0xe0, 0x05, 0x47, 0x82, 0x19, 0xbf, 0x47, 0x04, - 0x81, 0x47, 0x00, 0x80, 0x47, 0x00, 0x84, 0x47, - 0x17, 0x8d, 0x47, 0xac, 0x8a, 0x02, 0x89, 0x19, - 0x05, 0xb7, 0x7a, 0x07, 0xc5, 0x80, 0x07, 0x8b, - 0x80, 0x05, 0x9f, 0x20, 0xad, 0x40, 0x80, 0x19, - 0x80, 0x40, 0xa3, 0x7d, 0x0a, 0x80, 0x7d, 0x9c, - 0x31, 0x02, 0xcd, 0x3b, 0x00, 0x80, 0x19, 0x89, - 0x3b, 0x03, 0x81, 0x3b, 0x9e, 0x60, 0x00, 0xb6, - 0x16, 0x08, 0x8d, 0x16, 0x01, 0x89, 0x16, 0x01, - 0x83, 0x16, 0x9f, 0x60, 0xc2, 0x90, 0x17, 0x84, - 0x90, 0x96, 0x57, 0x09, 0x85, 0x27, 0x01, 0x85, - 0x27, 0x01, 0x85, 0x27, 0x08, 0x86, 0x27, 0x00, - 0x86, 0x27, 0x00, 0xaa, 0x47, 0x80, 0x19, 0x88, - 0x47, 0x80, 0x2c, 0x83, 0x47, 0x81, 0x19, 0x03, - 0xcf, 0x17, 0xad, 0x57, 0x01, 0x89, 0x57, 0x05, - 0xf0, 0x1b, 0x43, 0x31, 0x0b, 0x96, 0x31, 0x03, - 0xb0, 0x31, 0x70, 0x10, 0xa3, 0xe1, 0x0d, 0x30, - 0x01, 0xe0, 0x09, 0x30, 0x25, 0x86, 0x47, 0x0b, - 0x84, 0x05, 0x04, 0x99, 0x35, 0x00, 0x84, 0x35, - 0x00, 0x80, 0x35, 0x00, 0x81, 0x35, 0x00, 0x81, - 0x35, 0x00, 0x89, 0x35, 0xe0, 0x12, 0x04, 0x0f, - 0xe1, 0x0a, 0x04, 0x81, 0x19, 0xcf, 0x04, 0x01, - 0xb5, 0x04, 0x06, 0x80, 0x04, 0x1f, 0x8f, 0x04, - 0x8f, 0x38, 0x89, 0x19, 0x05, 0x8d, 0x38, 0x81, - 0x1d, 0xa2, 0x19, 0x00, 0x92, 0x19, 0x00, 0x83, - 0x19, 0x03, 0x84, 0x04, 0x00, 0xe0, 0x26, 0x04, - 0x01, 0x80, 0x19, 0x00, 0x9f, 0x19, 0x99, 0x47, - 0x85, 0x19, 0x99, 0x47, 0x8a, 0x19, 0x89, 0x3e, - 0x80, 0x19, 0xac, 0x3e, 0x81, 0x19, 0x9e, 0x31, - 0x02, 0x85, 0x31, 0x01, 0x85, 0x31, 0x01, 0x85, - 0x31, 0x01, 0x82, 0x31, 0x02, 0x86, 0x19, 0x00, - 0x86, 0x19, 0x09, 0x84, 0x19, 0x01, 0x8b, 0x4b, - 0x00, 0x99, 0x4b, 0x00, 0x92, 0x4b, 0x00, 0x81, - 0x4b, 0x00, 0x8e, 0x4b, 0x01, 0x8d, 0x4b, 0x21, - 0xe0, 0x1a, 0x4b, 0x04, 0x82, 0x19, 0x03, 0xac, - 0x19, 0x02, 0x88, 0x19, 0xce, 0x2c, 0x00, 0x8c, - 0x19, 0x02, 0x80, 0x2c, 0x2e, 0xac, 0x19, 0x80, - 0x38, 0x60, 0x21, 0x9c, 0x4d, 0x02, 0xb0, 0x13, - 0x0e, 0x80, 0x38, 0x9a, 0x19, 0x03, 0xa3, 0x6c, - 0x08, 0x82, 0x6c, 0x9a, 0x2a, 0x04, 0xaa, 0x6e, - 0x04, 0x9d, 0x9c, 0x00, 0x80, 0x9c, 0xa3, 0x6f, - 0x03, 0x8d, 0x6f, 0x29, 0xcf, 0x1f, 0xaf, 0x82, - 0x9d, 0x76, 0x01, 0x89, 0x76, 0x05, 0xa3, 0x75, - 0x03, 0xa3, 0x75, 0x03, 0xa7, 0x25, 0x07, 0xb3, - 0x14, 0x0a, 0x80, 0x14, 0x8a, 0x9e, 0x00, 0x8e, - 0x9e, 0x00, 0x86, 0x9e, 0x00, 0x81, 0x9e, 0x00, - 0x8a, 0x9e, 0x00, 0x8e, 0x9e, 0x00, 0x86, 0x9e, - 0x00, 0x81, 0x9e, 0x42, 0xe0, 0xd6, 0x4a, 0x08, - 0x95, 0x4a, 0x09, 0x87, 0x4a, 0x17, 0x85, 0x47, - 0x00, 0xa9, 0x47, 0x00, 0x88, 0x47, 0x44, 0x85, - 0x1c, 0x01, 0x80, 0x1c, 0x00, 0xab, 0x1c, 0x00, - 0x81, 0x1c, 0x02, 0x80, 0x1c, 0x01, 0x80, 0x1c, - 0x95, 0x37, 0x00, 0x88, 0x37, 0x9f, 0x78, 0x9e, - 0x61, 0x07, 0x88, 0x61, 0x2f, 0x92, 0x34, 0x00, - 0x81, 0x34, 0x04, 0x84, 0x34, 0x9b, 0x7b, 0x02, - 0x80, 0x7b, 0x99, 0x4e, 0x04, 0x80, 0x4e, 0x3f, - 0x9f, 0x5a, 0x97, 0x59, 0x03, 0x93, 0x59, 0x01, - 0xad, 0x59, 0x83, 0x41, 0x00, 0x81, 0x41, 0x04, - 0x87, 0x41, 0x00, 0x82, 0x41, 0x00, 0x9c, 0x41, - 0x01, 0x82, 0x41, 0x03, 0x89, 0x41, 0x06, 0x88, - 0x41, 0x06, 0x9f, 0x71, 0x9f, 0x6d, 0x1f, 0xa6, - 0x53, 0x03, 0x8b, 0x53, 0x08, 0xb5, 0x06, 0x02, - 0x86, 0x06, 0x95, 0x3a, 0x01, 0x87, 0x3a, 0x92, - 0x39, 0x04, 0x87, 0x39, 0x91, 0x7c, 0x06, 0x83, - 0x7c, 0x0b, 0x86, 0x7c, 0x4f, 0xc8, 0x72, 0x36, - 0xb2, 0x6b, 0x0c, 0xb2, 0x6b, 0x06, 0x85, 0x6b, - 0xa7, 0x32, 0x07, 0x89, 0x32, 0x60, 0xc5, 0x9e, - 0x04, 0x00, 0xa9, 0xa1, 0x00, 0x82, 0xa1, 0x01, - 0x81, 0xa1, 0x4a, 0x82, 0x04, 0xa7, 0x70, 0x07, - 0xa9, 0x86, 0x15, 0x99, 0x73, 0x25, 0x9b, 0x18, - 0x13, 0x96, 0x26, 0x08, 0xcd, 0x0e, 0x03, 0xa3, - 0x0e, 0x08, 0x80, 0x0e, 0xc2, 0x3c, 0x09, 0x80, - 0x3c, 0x01, 0x98, 0x87, 0x06, 0x89, 0x87, 0x05, - 0xb4, 0x15, 0x00, 0x91, 0x15, 0x07, 0xa6, 0x50, - 0x08, 0xdf, 0x81, 0x00, 0x93, 0x85, 0x0a, 0x91, - 0x43, 0x00, 0xae, 0x43, 0x3d, 0x86, 0x5f, 0x00, - 0x80, 0x5f, 0x00, 0x83, 0x5f, 0x00, 0x8e, 0x5f, - 0x00, 0x8a, 0x5f, 0x05, 0xba, 0x45, 0x04, 0x89, - 0x45, 0x05, 0x83, 0x2b, 0x00, 0x87, 0x2b, 0x01, - 0x81, 0x2b, 0x01, 0x95, 0x2b, 0x00, 0x86, 0x2b, - 0x00, 0x81, 0x2b, 0x00, 0x84, 0x2b, 0x00, 0x80, - 0x38, 0x88, 0x2b, 0x01, 0x81, 0x2b, 0x01, 0x82, - 0x2b, 0x01, 0x80, 0x2b, 0x05, 0x80, 0x2b, 0x04, - 0x86, 0x2b, 0x01, 0x86, 0x2b, 0x02, 0x84, 0x2b, - 0x60, 0x2a, 0xdb, 0x65, 0x00, 0x84, 0x65, 0x1d, - 0xc7, 0x99, 0x07, 0x89, 0x99, 0x60, 0x45, 0xb5, - 0x83, 0x01, 0xa5, 0x83, 0x21, 0xc4, 0x5c, 0x0a, - 0x89, 0x5c, 0x05, 0x8c, 0x5d, 0x12, 0xb9, 0x91, - 0x05, 0x89, 0x91, 0x35, 0x9a, 0x02, 0x01, 0x8e, + 0x27, 0x00, 0x86, 0x27, 0x00, 0x9f, 0x1d, 0xdd, + 0x19, 0x21, 0x99, 0x32, 0x00, 0xd8, 0x32, 0x0b, + 0xe0, 0x75, 0x32, 0x19, 0x94, 0x19, 0x80, 0x32, + 0x80, 0x19, 0x80, 0x32, 0x98, 0x19, 0x88, 0x32, + 0x83, 0x3a, 0x81, 0x33, 0x87, 0x19, 0x83, 0x32, + 0x83, 0x19, 0x00, 0xd5, 0x38, 0x01, 0x81, 0x3a, + 0x81, 0x19, 0x82, 0x38, 0x80, 0x19, 0xd9, 0x40, + 0x81, 0x19, 0x82, 0x40, 0x04, 0xaa, 0x0d, 0x00, + 0xdd, 0x33, 0x00, 0x8f, 0x19, 0x9f, 0x0d, 0xa5, + 0x19, 0x08, 0x80, 0x19, 0x8f, 0x40, 0x9e, 0x33, + 0x00, 0xbf, 0x19, 0x9e, 0x33, 0xd0, 0x19, 0xae, + 0x40, 0x80, 0x19, 0xd7, 0x40, 0xe0, 0x47, 0x19, + 0xf0, 0x09, 0x5f, 0x32, 0xbf, 0x19, 0xf0, 0x41, + 0x9f, 0x32, 0xe4, 0x2c, 0xa9, 0x02, 0xb6, 0xa9, + 0x08, 0xaf, 0x4f, 0xe0, 0xcb, 0xa4, 0x13, 0xdf, + 0x1d, 0xd7, 0x08, 0x07, 0xa1, 0x19, 0xe0, 0x05, + 0x4a, 0x82, 0x19, 0xc2, 0x4a, 0x01, 0x81, 0x4a, + 0x00, 0x80, 0x4a, 0x00, 0x87, 0x4a, 0x14, 0x8d, + 0x4a, 0xac, 0x8f, 0x02, 0x89, 0x19, 0x05, 0xb7, + 0x7e, 0x07, 0xc5, 0x84, 0x07, 0x8b, 0x84, 0x05, + 0x9f, 0x20, 0xad, 0x42, 0x80, 0x19, 0x80, 0x42, + 0xa3, 0x81, 0x0a, 0x80, 0x81, 0x9c, 0x33, 0x02, + 0xcd, 0x3d, 0x00, 0x80, 0x19, 0x89, 0x3d, 0x03, + 0x81, 0x3d, 0x9e, 0x63, 0x00, 0xb6, 0x16, 0x08, + 0x8d, 0x16, 0x01, 0x89, 0x16, 0x01, 0x83, 0x16, + 0x9f, 0x63, 0xc2, 0x95, 0x17, 0x84, 0x95, 0x96, + 0x5a, 0x09, 0x85, 0x27, 0x01, 0x85, 0x27, 0x01, + 0x85, 0x27, 0x08, 0x86, 0x27, 0x00, 0x86, 0x27, + 0x00, 0xaa, 0x4a, 0x80, 0x19, 0x88, 0x4a, 0x80, + 0x2d, 0x83, 0x4a, 0x81, 0x19, 0x03, 0xcf, 0x17, + 0xad, 0x5a, 0x01, 0x89, 0x5a, 0x05, 0xf0, 0x1b, + 0x43, 0x33, 0x0b, 0x96, 0x33, 0x03, 0xb0, 0x33, + 0x70, 0x10, 0xa3, 0xe1, 0x0d, 0x32, 0x01, 0xe0, + 0x09, 0x32, 0x25, 0x86, 0x4a, 0x0b, 0x84, 0x05, + 0x04, 0x99, 0x37, 0x00, 0x84, 0x37, 0x00, 0x80, + 0x37, 0x00, 0x81, 0x37, 0x00, 0x81, 0x37, 0x00, + 0x89, 0x37, 0xe0, 0x12, 0x04, 0x0f, 0xe1, 0x0a, + 0x04, 0x81, 0x19, 0xcf, 0x04, 0x01, 0xb5, 0x04, + 0x06, 0x80, 0x04, 0x1f, 0x8f, 0x04, 0x8f, 0x3a, + 0x89, 0x19, 0x05, 0x8d, 0x3a, 0x81, 0x1d, 0xa2, + 0x19, 0x00, 0x92, 0x19, 0x00, 0x83, 0x19, 0x03, + 0x84, 0x04, 0x00, 0xe0, 0x26, 0x04, 0x01, 0x80, + 0x19, 0x00, 0x9f, 0x19, 0x99, 0x4a, 0x85, 0x19, + 0x99, 0x4a, 0x8a, 0x19, 0x89, 0x40, 0x80, 0x19, + 0xac, 0x40, 0x81, 0x19, 0x9e, 0x33, 0x02, 0x85, + 0x33, 0x01, 0x85, 0x33, 0x01, 0x85, 0x33, 0x01, + 0x82, 0x33, 0x02, 0x86, 0x19, 0x00, 0x86, 0x19, + 0x09, 0x84, 0x19, 0x01, 0x8b, 0x4e, 0x00, 0x99, + 0x4e, 0x00, 0x92, 0x4e, 0x00, 0x81, 0x4e, 0x00, + 0x8e, 0x4e, 0x01, 0x8d, 0x4e, 0x21, 0xe0, 0x1a, + 0x4e, 0x04, 0x82, 0x19, 0x03, 0xac, 0x19, 0x02, + 0x88, 0x19, 0xce, 0x2d, 0x00, 0x8c, 0x19, 0x02, + 0x80, 0x2d, 0x2e, 0xac, 0x19, 0x80, 0x3a, 0x60, + 0x21, 0x9c, 0x50, 0x02, 0xb0, 0x13, 0x0e, 0x80, + 0x3a, 0x9a, 0x19, 0x03, 0xa3, 0x70, 0x08, 0x82, + 0x70, 0x9a, 0x2a, 0x04, 0xaa, 0x72, 0x04, 0x9d, + 0xa3, 0x00, 0x80, 0xa3, 0xa3, 0x73, 0x03, 0x8d, + 0x73, 0x29, 0xcf, 0x1f, 0xaf, 0x86, 0x9d, 0x7a, + 0x01, 0x89, 0x7a, 0x05, 0xa3, 0x79, 0x03, 0xa3, + 0x79, 0x03, 0xa7, 0x25, 0x07, 0xb3, 0x14, 0x0a, + 0x80, 0x14, 0x8a, 0xa5, 0x00, 0x8e, 0xa5, 0x00, + 0x86, 0xa5, 0x00, 0x81, 0xa5, 0x00, 0x8a, 0xa5, + 0x00, 0x8e, 0xa5, 0x00, 0x86, 0xa5, 0x00, 0x81, + 0xa5, 0x02, 0xb3, 0xa0, 0x0b, 0xe0, 0xd6, 0x4d, + 0x08, 0x95, 0x4d, 0x09, 0x87, 0x4d, 0x17, 0x85, + 0x4a, 0x00, 0xa9, 0x4a, 0x00, 0x88, 0x4a, 0x44, + 0x85, 0x1c, 0x01, 0x80, 0x1c, 0x00, 0xab, 0x1c, + 0x00, 0x81, 0x1c, 0x02, 0x80, 0x1c, 0x01, 0x80, + 0x1c, 0x95, 0x39, 0x00, 0x88, 0x39, 0x9f, 0x7c, + 0x9e, 0x64, 0x07, 0x88, 0x64, 0x2f, 0x92, 0x36, + 0x00, 0x81, 0x36, 0x04, 0x84, 0x36, 0x9b, 0x7f, + 0x02, 0x80, 0x7f, 0x99, 0x51, 0x04, 0x80, 0x51, + 0x3f, 0x9f, 0x5d, 0x97, 0x5c, 0x03, 0x93, 0x5c, + 0x01, 0xad, 0x5c, 0x83, 0x43, 0x00, 0x81, 0x43, + 0x04, 0x87, 0x43, 0x00, 0x82, 0x43, 0x00, 0x9c, + 0x43, 0x01, 0x82, 0x43, 0x03, 0x89, 0x43, 0x06, + 0x88, 0x43, 0x06, 0x9f, 0x75, 0x9f, 0x71, 0x1f, + 0xa6, 0x56, 0x03, 0x8b, 0x56, 0x08, 0xb5, 0x06, + 0x02, 0x86, 0x06, 0x95, 0x3c, 0x01, 0x87, 0x3c, + 0x92, 0x3b, 0x04, 0x87, 0x3b, 0x91, 0x80, 0x06, + 0x83, 0x80, 0x0b, 0x86, 0x80, 0x4f, 0xc8, 0x76, + 0x36, 0xb2, 0x6f, 0x0c, 0xb2, 0x6f, 0x06, 0x85, + 0x6f, 0xa7, 0x34, 0x07, 0x89, 0x34, 0x05, 0xa5, + 0x2b, 0x02, 0x9c, 0x2b, 0x07, 0x81, 0x2b, 0x60, + 0x6f, 0x9e, 0x04, 0x00, 0xa9, 0xa8, 0x00, 0x82, + 0xa8, 0x01, 0x81, 0xa8, 0x0f, 0x82, 0x04, 0x36, + 0x83, 0x04, 0xa7, 0x74, 0x07, 0xa9, 0x8a, 0x15, + 0x99, 0x77, 0x25, 0x9b, 0x18, 0x13, 0x96, 0x26, + 0x08, 0xcd, 0x0e, 0x03, 0xa3, 0x0e, 0x08, 0x80, + 0x0e, 0xc2, 0x3e, 0x09, 0x80, 0x3e, 0x01, 0x98, + 0x8b, 0x06, 0x89, 0x8b, 0x05, 0xb4, 0x15, 0x00, + 0x91, 0x15, 0x07, 0xa6, 0x53, 0x08, 0xdf, 0x85, + 0x00, 0x93, 0x89, 0x0a, 0x91, 0x45, 0x00, 0xae, + 0x45, 0x3d, 0x86, 0x62, 0x00, 0x80, 0x62, 0x00, + 0x83, 0x62, 0x00, 0x8e, 0x62, 0x00, 0x8a, 0x62, + 0x05, 0xba, 0x47, 0x04, 0x89, 0x47, 0x05, 0x83, + 0x2c, 0x00, 0x87, 0x2c, 0x01, 0x81, 0x2c, 0x01, + 0x95, 0x2c, 0x00, 0x86, 0x2c, 0x00, 0x81, 0x2c, + 0x00, 0x84, 0x2c, 0x00, 0x80, 0x3a, 0x88, 0x2c, + 0x01, 0x81, 0x2c, 0x01, 0x82, 0x2c, 0x01, 0x80, + 0x2c, 0x05, 0x80, 0x2c, 0x04, 0x86, 0x2c, 0x01, + 0x86, 0x2c, 0x02, 0x84, 0x2c, 0x0a, 0x89, 0xa2, + 0x00, 0x80, 0xa2, 0x01, 0x80, 0xa2, 0x00, 0xa5, + 0xa2, 0x00, 0x89, 0xa2, 0x00, 0x80, 0xa2, 0x01, + 0x80, 0xa2, 0x00, 0x83, 0xa2, 0x00, 0x89, 0xa2, + 0x00, 0x81, 0xa2, 0x07, 0x81, 0xa2, 0x1c, 0xdb, + 0x68, 0x00, 0x84, 0x68, 0x1d, 0xc7, 0x9e, 0x07, + 0x89, 0x9e, 0x60, 0x45, 0xb5, 0x87, 0x01, 0xa5, + 0x87, 0x21, 0xc4, 0x5f, 0x0a, 0x89, 0x5f, 0x05, + 0x8c, 0x60, 0x12, 0xb9, 0x96, 0x05, 0x89, 0x96, + 0x05, 0x93, 0x63, 0x1b, 0x9a, 0x02, 0x01, 0x8e, 0x02, 0x03, 0x96, 0x02, 0x60, 0x58, 0xbb, 0x22, - 0x60, 0x03, 0xd2, 0xa0, 0x0b, 0x80, 0xa0, 0x86, + 0x60, 0x03, 0xd2, 0xa7, 0x0b, 0x80, 0xa7, 0x86, 0x21, 0x01, 0x80, 0x21, 0x01, 0x87, 0x21, 0x00, 0x81, 0x21, 0x00, 0x9d, 0x21, 0x00, 0x81, 0x21, 0x01, 0x8b, 0x21, 0x08, 0x89, 0x21, 0x45, 0x87, - 0x63, 0x01, 0xad, 0x63, 0x01, 0x8a, 0x63, 0x1a, - 0xc7, 0xa3, 0x07, 0xd2, 0x88, 0x0c, 0x8f, 0x12, - 0xb8, 0x79, 0x06, 0x89, 0x20, 0x60, 0x95, 0x88, - 0x0c, 0x00, 0xac, 0x0c, 0x00, 0x8d, 0x0c, 0x09, - 0x9c, 0x0c, 0x02, 0x9f, 0x54, 0x01, 0x95, 0x54, - 0x00, 0x8d, 0x54, 0x48, 0x86, 0x55, 0x00, 0x81, - 0x55, 0x00, 0xab, 0x55, 0x02, 0x80, 0x55, 0x00, - 0x81, 0x55, 0x00, 0x88, 0x55, 0x07, 0x89, 0x55, - 0x05, 0x85, 0x2e, 0x00, 0x81, 0x2e, 0x00, 0xa4, - 0x2e, 0x00, 0x81, 0x2e, 0x00, 0x85, 0x2e, 0x06, - 0x89, 0x2e, 0x60, 0xd5, 0x98, 0x4f, 0x06, 0x90, - 0x3f, 0x00, 0xa8, 0x3f, 0x02, 0x9b, 0x3f, 0x55, - 0x80, 0x4c, 0x0e, 0xb1, 0x92, 0x0c, 0x80, 0x92, - 0xe3, 0x39, 0x1b, 0x60, 0x05, 0xe0, 0x0e, 0x1b, - 0x00, 0x84, 0x1b, 0x0a, 0xe0, 0x63, 0x1b, 0x69, - 0xeb, 0xe0, 0x02, 0x1e, 0x0c, 0xe3, 0xf5, 0x24, - 0x6f, 0x49, 0xe1, 0xe6, 0x03, 0x70, 0x11, 0x58, - 0xe1, 0xd8, 0x08, 0x06, 0x9e, 0x5e, 0x00, 0x89, - 0x5e, 0x03, 0x81, 0x5e, 0xce, 0x9a, 0x00, 0x89, - 0x9a, 0x05, 0x9d, 0x09, 0x01, 0x85, 0x09, 0x09, - 0xc5, 0x77, 0x09, 0x89, 0x77, 0x00, 0x86, 0x77, - 0x00, 0x94, 0x77, 0x04, 0x92, 0x77, 0x62, 0x4f, - 0xda, 0x56, 0x60, 0x04, 0xca, 0x5b, 0x03, 0xb8, - 0x5b, 0x06, 0x90, 0x5b, 0x3f, 0x80, 0x93, 0x80, - 0x67, 0x81, 0x30, 0x80, 0x44, 0x0a, 0x81, 0x30, - 0x0d, 0xf0, 0x07, 0x97, 0x93, 0x07, 0xe2, 0x9f, - 0x93, 0xe1, 0x75, 0x44, 0x29, 0x88, 0x93, 0x70, - 0x12, 0x86, 0x83, 0x3e, 0x00, 0x86, 0x3e, 0x00, - 0x81, 0x3e, 0x00, 0x80, 0x3e, 0xe0, 0xbe, 0x36, - 0x82, 0x3e, 0x0e, 0x80, 0x36, 0x1c, 0x82, 0x36, - 0x01, 0x80, 0x3e, 0x0d, 0x83, 0x3e, 0x07, 0xe1, - 0x2b, 0x67, 0x68, 0xa3, 0xe0, 0x0a, 0x23, 0x04, - 0x8c, 0x23, 0x02, 0x88, 0x23, 0x06, 0x89, 0x23, - 0x01, 0x83, 0x23, 0x83, 0x19, 0x70, 0x01, 0xfb, - 0xad, 0x38, 0x01, 0x96, 0x38, 0x08, 0xe0, 0x13, - 0x19, 0x3b, 0xe0, 0x95, 0x19, 0x09, 0xa6, 0x19, - 0x01, 0xbd, 0x19, 0x82, 0x38, 0x90, 0x19, 0x87, - 0x38, 0x81, 0x19, 0x86, 0x38, 0x9d, 0x19, 0x83, - 0x38, 0xbc, 0x19, 0x14, 0xc5, 0x2c, 0x60, 0x19, - 0x93, 0x19, 0x0b, 0x93, 0x19, 0x0b, 0xd6, 0x19, - 0x08, 0x98, 0x19, 0x60, 0x26, 0xd4, 0x19, 0x00, - 0xc6, 0x19, 0x00, 0x81, 0x19, 0x01, 0x80, 0x19, - 0x01, 0x81, 0x19, 0x01, 0x83, 0x19, 0x00, 0x8b, - 0x19, 0x00, 0x80, 0x19, 0x00, 0x86, 0x19, 0x00, - 0xc0, 0x19, 0x00, 0x83, 0x19, 0x01, 0x87, 0x19, - 0x00, 0x86, 0x19, 0x00, 0x9b, 0x19, 0x00, 0x83, - 0x19, 0x00, 0x84, 0x19, 0x00, 0x80, 0x19, 0x02, - 0x86, 0x19, 0x00, 0xe0, 0xf3, 0x19, 0x01, 0xe0, - 0xc3, 0x19, 0x01, 0xb1, 0x19, 0xe2, 0x2b, 0x84, - 0x0e, 0x84, 0x84, 0x00, 0x8e, 0x84, 0x63, 0xef, - 0x9e, 0x47, 0x05, 0x85, 0x47, 0x60, 0x74, 0x86, - 0x29, 0x00, 0x90, 0x29, 0x01, 0x86, 0x29, 0x00, - 0x81, 0x29, 0x00, 0x84, 0x29, 0x04, 0xbd, 0x1d, - 0x20, 0x80, 0x1d, 0x60, 0x0f, 0xac, 0x68, 0x02, - 0x8d, 0x68, 0x01, 0x89, 0x68, 0x03, 0x81, 0x68, - 0x60, 0xdf, 0x9e, 0x9b, 0x10, 0xb9, 0x9f, 0x04, - 0x80, 0x9f, 0x61, 0x6f, 0xa9, 0x62, 0x62, 0x85, - 0x86, 0x27, 0x00, 0x83, 0x27, 0x00, 0x81, 0x27, - 0x00, 0x8e, 0x27, 0x00, 0xe0, 0x64, 0x58, 0x01, - 0x8f, 0x58, 0x28, 0xcb, 0x01, 0x03, 0x89, 0x01, - 0x03, 0x81, 0x01, 0x62, 0xb0, 0xc3, 0x19, 0x4b, - 0xbc, 0x19, 0x60, 0x61, 0x83, 0x04, 0x00, 0x9a, - 0x04, 0x00, 0x81, 0x04, 0x00, 0x80, 0x04, 0x01, - 0x80, 0x04, 0x00, 0x89, 0x04, 0x00, 0x83, 0x04, - 0x00, 0x80, 0x04, 0x00, 0x80, 0x04, 0x05, 0x80, - 0x04, 0x03, 0x80, 0x04, 0x00, 0x80, 0x04, 0x00, - 0x80, 0x04, 0x00, 0x82, 0x04, 0x00, 0x81, 0x04, - 0x00, 0x80, 0x04, 0x01, 0x80, 0x04, 0x00, 0x80, - 0x04, 0x00, 0x80, 0x04, 0x00, 0x80, 0x04, 0x00, - 0x80, 0x04, 0x00, 0x81, 0x04, 0x00, 0x80, 0x04, - 0x01, 0x83, 0x04, 0x00, 0x86, 0x04, 0x00, 0x83, - 0x04, 0x00, 0x83, 0x04, 0x00, 0x80, 0x04, 0x00, - 0x89, 0x04, 0x00, 0x90, 0x04, 0x04, 0x82, 0x04, - 0x00, 0x84, 0x04, 0x00, 0x90, 0x04, 0x33, 0x81, - 0x04, 0x60, 0xad, 0xab, 0x19, 0x03, 0xe0, 0x03, - 0x19, 0x0b, 0x8e, 0x19, 0x01, 0x8e, 0x19, 0x00, - 0x8e, 0x19, 0x00, 0xa4, 0x19, 0x09, 0xe0, 0x4d, - 0x19, 0x37, 0x99, 0x19, 0x80, 0x36, 0x81, 0x19, - 0x0c, 0xab, 0x19, 0x03, 0x88, 0x19, 0x06, 0x81, - 0x19, 0x0d, 0x85, 0x19, 0x60, 0x39, 0xe3, 0x77, - 0x19, 0x03, 0x90, 0x19, 0x02, 0x8c, 0x19, 0x02, - 0xe0, 0x16, 0x19, 0x03, 0xde, 0x19, 0x05, 0x8b, - 0x19, 0x03, 0x80, 0x19, 0x0e, 0x8b, 0x19, 0x03, - 0xb7, 0x19, 0x07, 0x89, 0x19, 0x05, 0xa7, 0x19, - 0x07, 0x9d, 0x19, 0x01, 0x81, 0x19, 0x4d, 0xe0, - 0xf3, 0x19, 0x0b, 0x8d, 0x19, 0x01, 0x8c, 0x19, - 0x02, 0x88, 0x19, 0x06, 0xad, 0x19, 0x00, 0x86, - 0x19, 0x07, 0x8d, 0x19, 0x03, 0x88, 0x19, 0x06, - 0x88, 0x19, 0x06, 0xe0, 0x32, 0x19, 0x00, 0xb6, - 0x19, 0x24, 0x89, 0x19, 0x63, 0xa5, 0xf0, 0x96, - 0x7f, 0x30, 0x1f, 0xef, 0xd9, 0x30, 0x05, 0xe0, - 0x7d, 0x30, 0x01, 0xf0, 0x06, 0x21, 0x30, 0x0d, - 0xf0, 0x0c, 0xd0, 0x30, 0x6b, 0xbe, 0xe1, 0xbd, - 0x30, 0x65, 0x81, 0xf0, 0x02, 0xea, 0x30, 0x04, - 0xef, 0xff, 0x30, 0x7a, 0xcb, 0xf0, 0x80, 0x19, - 0x1d, 0xdf, 0x19, 0x60, 0x1f, 0xe0, 0x8f, 0x38, + 0x66, 0x01, 0xad, 0x66, 0x01, 0x8a, 0x66, 0x1a, + 0xc7, 0xaa, 0x07, 0xd2, 0x8c, 0x0c, 0x8f, 0x12, + 0xb8, 0x7d, 0x06, 0x89, 0x20, 0x60, 0x55, 0xa1, + 0x8e, 0x0d, 0x89, 0x8e, 0x05, 0x88, 0x0c, 0x00, + 0xac, 0x0c, 0x00, 0x8d, 0x0c, 0x09, 0x9c, 0x0c, + 0x02, 0x9f, 0x57, 0x01, 0x95, 0x57, 0x00, 0x8d, + 0x57, 0x48, 0x86, 0x58, 0x00, 0x81, 0x58, 0x00, + 0xab, 0x58, 0x02, 0x80, 0x58, 0x00, 0x81, 0x58, + 0x00, 0x88, 0x58, 0x07, 0x89, 0x58, 0x05, 0x85, + 0x2f, 0x00, 0x81, 0x2f, 0x00, 0xa4, 0x2f, 0x00, + 0x81, 0x2f, 0x00, 0x85, 0x2f, 0x06, 0x89, 0x2f, + 0x60, 0xd5, 0x98, 0x52, 0x06, 0x90, 0x41, 0x00, + 0xa8, 0x41, 0x02, 0x9c, 0x41, 0x54, 0x80, 0x4f, + 0x0e, 0xb1, 0x97, 0x0c, 0x80, 0x97, 0xe3, 0x39, + 0x1b, 0x60, 0x05, 0xe0, 0x0e, 0x1b, 0x00, 0x84, + 0x1b, 0x0a, 0xe0, 0x63, 0x1b, 0x69, 0xeb, 0xe0, + 0x02, 0x1e, 0x0c, 0xe3, 0xf5, 0x24, 0x09, 0xef, + 0x3a, 0x24, 0x04, 0xe1, 0xe6, 0x03, 0x70, 0x0a, + 0x58, 0xb9, 0x31, 0x66, 0x65, 0xe1, 0xd8, 0x08, + 0x06, 0x9e, 0x61, 0x00, 0x89, 0x61, 0x03, 0x81, + 0x61, 0xce, 0x9f, 0x00, 0x89, 0x9f, 0x05, 0x9d, + 0x09, 0x01, 0x85, 0x09, 0x09, 0xc5, 0x7b, 0x09, + 0x89, 0x7b, 0x00, 0x86, 0x7b, 0x00, 0x94, 0x7b, + 0x04, 0x92, 0x7b, 0x61, 0x4f, 0xb9, 0x48, 0x60, + 0x65, 0xda, 0x59, 0x60, 0x04, 0xca, 0x5e, 0x03, + 0xb8, 0x5e, 0x06, 0x90, 0x5e, 0x3f, 0x80, 0x98, + 0x80, 0x6a, 0x81, 0x32, 0x80, 0x46, 0x0a, 0x81, + 0x32, 0x0d, 0xf0, 0x07, 0x97, 0x98, 0x07, 0xe2, + 0x9f, 0x98, 0xe1, 0x75, 0x46, 0x28, 0x80, 0x46, + 0x88, 0x98, 0x70, 0x12, 0x86, 0x83, 0x40, 0x00, + 0x86, 0x40, 0x00, 0x81, 0x40, 0x00, 0x80, 0x40, + 0xe0, 0xbe, 0x38, 0x82, 0x40, 0x0e, 0x80, 0x38, + 0x1c, 0x82, 0x38, 0x01, 0x80, 0x40, 0x0d, 0x83, + 0x40, 0x07, 0xe1, 0x2b, 0x6a, 0x68, 0xa3, 0xe0, + 0x0a, 0x23, 0x04, 0x8c, 0x23, 0x02, 0x88, 0x23, + 0x06, 0x89, 0x23, 0x01, 0x83, 0x23, 0x83, 0x19, + 0x6e, 0xfb, 0xe0, 0x99, 0x19, 0x05, 0xe1, 0x53, + 0x19, 0x4b, 0xad, 0x3a, 0x01, 0x96, 0x3a, 0x08, + 0xe0, 0x13, 0x19, 0x3b, 0xe0, 0x95, 0x19, 0x09, + 0xa6, 0x19, 0x01, 0xbd, 0x19, 0x82, 0x3a, 0x90, + 0x19, 0x87, 0x3a, 0x81, 0x19, 0x86, 0x3a, 0x9d, + 0x19, 0x83, 0x3a, 0xbc, 0x19, 0x14, 0xc5, 0x2d, + 0x60, 0x19, 0x93, 0x19, 0x0b, 0x93, 0x19, 0x0b, + 0xd6, 0x19, 0x08, 0x98, 0x19, 0x60, 0x26, 0xd4, + 0x19, 0x00, 0xc6, 0x19, 0x00, 0x81, 0x19, 0x01, + 0x80, 0x19, 0x01, 0x81, 0x19, 0x01, 0x83, 0x19, + 0x00, 0x8b, 0x19, 0x00, 0x80, 0x19, 0x00, 0x86, + 0x19, 0x00, 0xc0, 0x19, 0x00, 0x83, 0x19, 0x01, + 0x87, 0x19, 0x00, 0x86, 0x19, 0x00, 0x9b, 0x19, + 0x00, 0x83, 0x19, 0x00, 0x84, 0x19, 0x00, 0x80, + 0x19, 0x02, 0x86, 0x19, 0x00, 0xe0, 0xf3, 0x19, + 0x01, 0xe0, 0xc3, 0x19, 0x01, 0xb1, 0x19, 0xe2, + 0x2b, 0x88, 0x0e, 0x84, 0x88, 0x00, 0x8e, 0x88, + 0x63, 0xef, 0x9e, 0x4a, 0x05, 0x85, 0x4a, 0x60, + 0x74, 0x86, 0x29, 0x00, 0x90, 0x29, 0x01, 0x86, + 0x29, 0x00, 0x81, 0x29, 0x00, 0x84, 0x29, 0x04, + 0xbd, 0x1d, 0x20, 0x80, 0x1d, 0x60, 0x0f, 0xac, + 0x6b, 0x02, 0x8d, 0x6b, 0x01, 0x89, 0x6b, 0x03, + 0x81, 0x6b, 0x60, 0xdf, 0x9e, 0xa1, 0x10, 0xb9, + 0xa6, 0x04, 0x80, 0xa6, 0x61, 0x6f, 0xa9, 0x65, + 0x60, 0x75, 0xaa, 0x6e, 0x03, 0x80, 0x6e, 0x61, + 0x7f, 0x86, 0x27, 0x00, 0x83, 0x27, 0x00, 0x81, + 0x27, 0x00, 0x8e, 0x27, 0x00, 0xe0, 0x64, 0x5b, + 0x01, 0x8f, 0x5b, 0x28, 0xcb, 0x01, 0x03, 0x89, + 0x01, 0x03, 0x81, 0x01, 0x62, 0xb0, 0xc3, 0x19, + 0x4b, 0xbc, 0x19, 0x60, 0x61, 0x83, 0x04, 0x00, + 0x9a, 0x04, 0x00, 0x81, 0x04, 0x00, 0x80, 0x04, + 0x01, 0x80, 0x04, 0x00, 0x89, 0x04, 0x00, 0x83, + 0x04, 0x00, 0x80, 0x04, 0x00, 0x80, 0x04, 0x05, + 0x80, 0x04, 0x03, 0x80, 0x04, 0x00, 0x80, 0x04, + 0x00, 0x80, 0x04, 0x00, 0x82, 0x04, 0x00, 0x81, + 0x04, 0x00, 0x80, 0x04, 0x01, 0x80, 0x04, 0x00, + 0x80, 0x04, 0x00, 0x80, 0x04, 0x00, 0x80, 0x04, + 0x00, 0x80, 0x04, 0x00, 0x81, 0x04, 0x00, 0x80, + 0x04, 0x01, 0x83, 0x04, 0x00, 0x86, 0x04, 0x00, + 0x83, 0x04, 0x00, 0x83, 0x04, 0x00, 0x80, 0x04, + 0x00, 0x89, 0x04, 0x00, 0x90, 0x04, 0x04, 0x82, + 0x04, 0x00, 0x84, 0x04, 0x00, 0x90, 0x04, 0x33, + 0x81, 0x04, 0x60, 0xad, 0xab, 0x19, 0x03, 0xe0, + 0x03, 0x19, 0x0b, 0x8e, 0x19, 0x01, 0x8e, 0x19, + 0x00, 0x8e, 0x19, 0x00, 0xa4, 0x19, 0x09, 0xe0, + 0x4d, 0x19, 0x37, 0x99, 0x19, 0x80, 0x38, 0x81, + 0x19, 0x0c, 0xab, 0x19, 0x03, 0x88, 0x19, 0x06, + 0x81, 0x19, 0x0d, 0x85, 0x19, 0x60, 0x39, 0xe3, + 0x77, 0x19, 0x03, 0x90, 0x19, 0x02, 0x8c, 0x19, + 0x02, 0xe0, 0x16, 0x19, 0x03, 0xde, 0x19, 0x05, + 0x8b, 0x19, 0x03, 0x80, 0x19, 0x0e, 0x8b, 0x19, + 0x03, 0xb7, 0x19, 0x07, 0x89, 0x19, 0x05, 0xa7, + 0x19, 0x07, 0x9d, 0x19, 0x01, 0x8b, 0x19, 0x03, + 0x81, 0x19, 0x3d, 0xe0, 0xf3, 0x19, 0x0b, 0x8d, + 0x19, 0x01, 0x8c, 0x19, 0x02, 0x89, 0x19, 0x04, + 0xb7, 0x19, 0x06, 0x8e, 0x19, 0x01, 0x8a, 0x19, + 0x05, 0x88, 0x19, 0x06, 0xe0, 0x32, 0x19, 0x00, + 0xe0, 0x05, 0x19, 0x63, 0xa5, 0xf0, 0x96, 0x7f, + 0x32, 0x1f, 0xef, 0xd9, 0x32, 0x05, 0xe0, 0x7d, + 0x32, 0x01, 0xf0, 0x06, 0x21, 0x32, 0x0d, 0xf0, + 0x0c, 0xd0, 0x32, 0x0e, 0xe2, 0x0d, 0x32, 0x69, + 0x41, 0xe1, 0xbd, 0x32, 0x65, 0x81, 0xf0, 0x02, + 0xea, 0x32, 0x04, 0xef, 0xff, 0x32, 0x7a, 0xcb, + 0xf0, 0x80, 0x19, 0x1d, 0xdf, 0x19, 0x60, 0x1f, + 0xe0, 0x8f, 0x3a, }; -static const uint8_t unicode_script_ext_table[828] = { - 0x82, 0xc1, 0x00, 0x00, 0x01, 0x2c, 0x01, 0x00, - 0x00, 0x01, 0x2c, 0x1c, 0x00, 0x0c, 0x01, 0x47, - 0x80, 0x92, 0x00, 0x00, 0x02, 0x1d, 0x6e, 0x00, - 0x02, 0x1d, 0x29, 0x01, 0x02, 0x1d, 0x47, 0x00, - 0x02, 0x1d, 0x29, 0x81, 0x03, 0x00, 0x00, 0x06, - 0x04, 0x66, 0x32, 0x8b, 0x95, 0xa1, 0x0d, 0x00, - 0x00, 0x06, 0x04, 0x66, 0x32, 0x8b, 0x95, 0xa1, - 0x00, 0x03, 0x04, 0x8b, 0x95, 0x01, 0x00, 0x00, - 0x07, 0x01, 0x04, 0x66, 0x32, 0x8b, 0x95, 0xa1, - 0x1f, 0x00, 0x00, 0x09, 0x01, 0x04, 0x52, 0x53, - 0x73, 0x7c, 0x32, 0x86, 0x8b, 0x09, 0x00, 0x0a, - 0x02, 0x04, 0x8b, 0x09, 0x00, 0x09, 0x03, 0x04, - 0x95, 0xa1, 0x05, 0x00, 0x00, 0x02, 0x04, 0x8b, - 0x62, 0x00, 0x00, 0x02, 0x04, 0x32, 0x81, 0xfb, - 0x00, 0x00, 0x0d, 0x0b, 0x20, 0x2b, 0x2d, 0x2f, - 0x3d, 0x47, 0x51, 0x74, 0x81, 0x92, 0x94, 0x99, - 0x00, 0x0c, 0x0b, 0x20, 0x2b, 0x2d, 0x2f, 0x3d, - 0x47, 0x51, 0x74, 0x92, 0x94, 0x99, 0x10, 0x00, - 0x00, 0x14, 0x0b, 0x20, 0x22, 0x2e, 0x55, 0x2b, - 0x2d, 0x2f, 0x3d, 0x50, 0x51, 0x63, 0x74, 0x45, - 0x85, 0x8a, 0x91, 0x92, 0x94, 0x99, 0x00, 0x15, - 0x0b, 0x20, 0x22, 0x2e, 0x55, 0x2b, 0x2d, 0x2f, - 0x3d, 0x49, 0x50, 0x51, 0x63, 0x74, 0x45, 0x85, - 0x8a, 0x91, 0x92, 0x94, 0x99, 0x09, 0x04, 0x20, - 0x22, 0x3c, 0x50, 0x75, 0x00, 0x09, 0x03, 0x0b, - 0x15, 0x8a, 0x75, 0x00, 0x09, 0x02, 0x2f, 0x5f, - 0x75, 0x00, 0x09, 0x02, 0x2d, 0x43, 0x80, 0x75, - 0x00, 0x0d, 0x02, 0x2b, 0x92, 0x80, 0x71, 0x00, - 0x09, 0x02, 0x3d, 0x63, 0x82, 0xcf, 0x00, 0x09, - 0x03, 0x15, 0x60, 0x8e, 0x80, 0x30, 0x00, 0x00, - 0x02, 0x28, 0x47, 0x85, 0xb8, 0x00, 0x01, 0x04, - 0x11, 0x33, 0x8d, 0x8c, 0x80, 0x4a, 0x00, 0x01, - 0x02, 0x5d, 0x7a, 0x00, 0x00, 0x00, 0x02, 0x5d, - 0x7a, 0x84, 0x49, 0x00, 0x00, 0x04, 0x0b, 0x20, - 0x2b, 0x3d, 0x00, 0x01, 0x20, 0x00, 0x04, 0x0b, - 0x20, 0x2b, 0x3d, 0x00, 0x02, 0x20, 0x2b, 0x00, - 0x01, 0x20, 0x01, 0x02, 0x0b, 0x20, 0x00, 0x02, - 0x20, 0x81, 0x00, 0x02, 0x0b, 0x20, 0x00, 0x02, - 0x20, 0x81, 0x00, 0x06, 0x20, 0x3d, 0x51, 0x74, - 0x92, 0x94, 0x00, 0x01, 0x20, 0x01, 0x02, 0x20, - 0x81, 0x01, 0x01, 0x20, 0x00, 0x02, 0x20, 0x81, - 0x00, 0x02, 0x0b, 0x20, 0x06, 0x01, 0x20, 0x00, - 0x02, 0x20, 0x63, 0x00, 0x02, 0x0b, 0x20, 0x01, - 0x01, 0x20, 0x00, 0x02, 0x0b, 0x20, 0x03, 0x01, - 0x20, 0x00, 0x08, 0x0b, 0x20, 0x2b, 0x3d, 0x63, - 0x74, 0x94, 0x99, 0x00, 0x02, 0x20, 0x2b, 0x00, - 0x03, 0x20, 0x2b, 0x3d, 0x01, 0x02, 0x0b, 0x20, - 0x00, 0x01, 0x0b, 0x01, 0x02, 0x20, 0x2b, 0x00, - 0x01, 0x63, 0x80, 0x44, 0x00, 0x01, 0x01, 0x2c, - 0x35, 0x00, 0x00, 0x02, 0x1d, 0x8b, 0x00, 0x00, - 0x00, 0x01, 0x8b, 0x81, 0xb3, 0x00, 0x00, 0x02, - 0x47, 0x5d, 0x80, 0x3f, 0x00, 0x00, 0x03, 0x20, - 0x2b, 0x47, 0x8c, 0xd1, 0x00, 0x00, 0x02, 0x1d, - 0x29, 0x81, 0x3c, 0x00, 0x01, 0x06, 0x0d, 0x31, - 0x30, 0x36, 0x3e, 0xa2, 0x00, 0x05, 0x0d, 0x31, - 0x30, 0x36, 0x3e, 0x01, 0x00, 0x00, 0x01, 0x30, - 0x00, 0x00, 0x09, 0x06, 0x0d, 0x31, 0x30, 0x36, - 0x3e, 0xa2, 0x00, 0x00, 0x00, 0x05, 0x0d, 0x31, - 0x30, 0x36, 0x3e, 0x07, 0x06, 0x0d, 0x31, 0x30, - 0x36, 0x3e, 0xa2, 0x03, 0x05, 0x0d, 0x31, 0x30, - 0x36, 0x3e, 0x09, 0x00, 0x03, 0x02, 0x0d, 0x30, - 0x01, 0x00, 0x00, 0x05, 0x0d, 0x31, 0x30, 0x36, - 0x3e, 0x04, 0x02, 0x36, 0x3e, 0x00, 0x00, 0x00, - 0x05, 0x0d, 0x31, 0x30, 0x36, 0x3e, 0x03, 0x00, - 0x01, 0x03, 0x30, 0x36, 0x3e, 0x01, 0x01, 0x30, - 0x58, 0x00, 0x03, 0x02, 0x36, 0x3e, 0x02, 0x00, - 0x00, 0x02, 0x36, 0x3e, 0x59, 0x00, 0x00, 0x06, - 0x0d, 0x31, 0x30, 0x36, 0x3e, 0xa2, 0x00, 0x02, - 0x36, 0x3e, 0x80, 0x12, 0x00, 0x0f, 0x01, 0x30, - 0x1f, 0x00, 0x23, 0x01, 0x30, 0x3b, 0x00, 0x27, - 0x01, 0x30, 0x37, 0x00, 0x30, 0x01, 0x30, 0x0e, - 0x00, 0x0b, 0x01, 0x30, 0x32, 0x00, 0x00, 0x01, - 0x30, 0x57, 0x00, 0x18, 0x01, 0x30, 0x09, 0x00, - 0x04, 0x01, 0x30, 0x5f, 0x00, 0x1e, 0x01, 0x30, - 0xc0, 0x31, 0xef, 0x00, 0x00, 0x02, 0x1d, 0x29, - 0x80, 0x0f, 0x00, 0x07, 0x02, 0x30, 0x47, 0x80, - 0xa7, 0x00, 0x02, 0x0e, 0x20, 0x22, 0x2d, 0x2f, - 0x43, 0x3d, 0x3c, 0x50, 0x51, 0x5c, 0x63, 0x45, - 0x91, 0x99, 0x02, 0x0d, 0x20, 0x22, 0x2d, 0x2f, - 0x43, 0x3d, 0x3c, 0x50, 0x5c, 0x63, 0x45, 0x91, - 0x99, 0x03, 0x0b, 0x20, 0x22, 0x2d, 0x2f, 0x43, - 0x3c, 0x50, 0x5c, 0x45, 0x91, 0x99, 0x80, 0x36, - 0x00, 0x00, 0x02, 0x0b, 0x20, 0x00, 0x00, 0x00, - 0x02, 0x20, 0x92, 0x39, 0x00, 0x00, 0x03, 0x40, - 0x47, 0x60, 0x80, 0x1f, 0x00, 0x00, 0x02, 0x10, - 0x3b, 0xc0, 0x12, 0xed, 0x00, 0x01, 0x02, 0x04, - 0x66, 0x80, 0x31, 0x00, 0x00, 0x02, 0x04, 0x95, - 0x09, 0x00, 0x00, 0x02, 0x04, 0x95, 0x46, 0x00, - 0x01, 0x05, 0x0d, 0x31, 0x30, 0x36, 0x3e, 0x80, - 0x99, 0x00, 0x04, 0x06, 0x0d, 0x31, 0x30, 0x36, - 0x3e, 0xa2, 0x09, 0x00, 0x00, 0x02, 0x36, 0x3e, - 0x2c, 0x00, 0x01, 0x02, 0x36, 0x3e, 0x80, 0xdf, - 0x00, 0x01, 0x03, 0x1e, 0x1c, 0x4b, 0x00, 0x02, - 0x1c, 0x4b, 0x03, 0x00, 0x2c, 0x03, 0x1c, 0x4a, - 0x4b, 0x02, 0x00, 0x08, 0x02, 0x1c, 0x4b, 0x81, - 0x1f, 0x00, 0x1b, 0x02, 0x04, 0x1a, 0x87, 0x75, - 0x00, 0x00, 0x02, 0x53, 0x73, 0x87, 0x8d, 0x00, - 0x00, 0x02, 0x2b, 0x92, 0x00, 0x00, 0x00, 0x02, - 0x2b, 0x92, 0x36, 0x00, 0x01, 0x02, 0x2b, 0x92, - 0x8c, 0x12, 0x00, 0x01, 0x02, 0x2b, 0x92, 0x00, - 0x00, 0x00, 0x02, 0x2b, 0x92, 0xc0, 0x5c, 0x4b, - 0x00, 0x03, 0x01, 0x23, 0x96, 0x3b, 0x00, 0x11, - 0x01, 0x30, 0x9e, 0x5d, 0x00, 0x01, 0x01, 0x30, - 0xce, 0xcd, 0x2d, 0x00, +static const uint8_t unicode_script_ext_table[1253] = { + 0x80, 0x36, 0x00, 0x00, 0x10, 0x06, 0x13, 0x1a, + 0x23, 0x25, 0x28, 0x29, 0x2f, 0x2a, 0x2d, 0x32, + 0x4a, 0x51, 0x53, 0x72, 0x86, 0x81, 0x83, 0x00, + 0x00, 0x07, 0x0b, 0x1d, 0x20, 0x4a, 0x4f, 0x9b, + 0xa1, 0x09, 0x00, 0x00, 0x02, 0x0d, 0x4a, 0x00, + 0x00, 0x02, 0x02, 0x0d, 0x4a, 0x00, 0x00, 0x00, + 0x02, 0x4a, 0x4f, 0x08, 0x00, 0x00, 0x02, 0x4a, + 0x9b, 0x00, 0x00, 0x00, 0x02, 0x0d, 0x4a, 0x25, + 0x00, 0x00, 0x08, 0x17, 0x1a, 0x1d, 0x2d, 0x4a, + 0x72, 0x8e, 0x93, 0x00, 0x08, 0x17, 0x1d, 0x2d, + 0x4a, 0x79, 0x8e, 0x93, 0xa0, 0x00, 0x04, 0x17, + 0x1d, 0x4a, 0x9d, 0x00, 0x05, 0x29, 0x4a, 0x8e, + 0x90, 0x9b, 0x00, 0x0b, 0x14, 0x17, 0x1a, 0x1d, + 0x2a, 0x2d, 0x4a, 0x79, 0x90, 0x9d, 0xa0, 0x00, + 0x06, 0x1a, 0x25, 0x29, 0x2a, 0x40, 0x4a, 0x00, + 0x04, 0x1d, 0x2d, 0x4a, 0x72, 0x00, 0x09, 0x1a, + 0x23, 0x37, 0x4a, 0x72, 0x90, 0x93, 0x9d, 0xa0, + 0x00, 0x0a, 0x05, 0x1d, 0x23, 0x2a, 0x2d, 0x37, + 0x4a, 0x72, 0x90, 0x93, 0x00, 0x02, 0x4a, 0x9d, + 0x00, 0x03, 0x23, 0x4a, 0x90, 0x00, 0x04, 0x17, + 0x1d, 0x4a, 0x79, 0x00, 0x03, 0x17, 0x4a, 0x93, + 0x00, 0x02, 0x4a, 0x8e, 0x00, 0x02, 0x27, 0x4a, + 0x00, 0x00, 0x00, 0x02, 0x4a, 0x8e, 0x00, 0x03, + 0x1d, 0x4a, 0xa0, 0x00, 0x00, 0x00, 0x04, 0x2d, + 0x4a, 0x72, 0xa0, 0x0b, 0x00, 0x00, 0x02, 0x4a, + 0x90, 0x01, 0x00, 0x00, 0x05, 0x17, 0x23, 0x40, + 0x4a, 0x90, 0x00, 0x04, 0x17, 0x23, 0x4a, 0x90, + 0x00, 0x02, 0x4a, 0x90, 0x06, 0x00, 0x00, 0x03, + 0x4a, 0x8e, 0x90, 0x00, 0x02, 0x4a, 0x90, 0x00, + 0x00, 0x00, 0x03, 0x17, 0x4a, 0x90, 0x00, 0x06, + 0x14, 0x17, 0x2a, 0x4a, 0x8e, 0x9b, 0x0f, 0x00, + 0x00, 0x01, 0x2d, 0x01, 0x00, 0x00, 0x01, 0x2d, + 0x11, 0x00, 0x00, 0x02, 0x4a, 0x79, 0x04, 0x00, + 0x00, 0x03, 0x14, 0x4a, 0xa0, 0x03, 0x00, 0x0c, + 0x01, 0x4a, 0x03, 0x00, 0x01, 0x02, 0x1a, 0x2d, + 0x80, 0x8c, 0x00, 0x00, 0x02, 0x1d, 0x72, 0x00, + 0x02, 0x1d, 0x29, 0x01, 0x02, 0x1d, 0x4a, 0x00, + 0x02, 0x1d, 0x29, 0x80, 0x80, 0x00, 0x00, 0x03, + 0x05, 0x28, 0x29, 0x80, 0x01, 0x00, 0x00, 0x07, + 0x04, 0x2b, 0x69, 0x34, 0x90, 0x9a, 0xa8, 0x0d, + 0x00, 0x00, 0x07, 0x04, 0x2b, 0x69, 0x34, 0x90, + 0x9a, 0xa8, 0x00, 0x03, 0x04, 0x90, 0x9a, 0x01, + 0x00, 0x00, 0x08, 0x01, 0x04, 0x2b, 0x69, 0x34, + 0x90, 0x9a, 0xa8, 0x1f, 0x00, 0x00, 0x09, 0x01, + 0x04, 0x55, 0x56, 0x77, 0x80, 0x34, 0x8a, 0x90, + 0x09, 0x00, 0x0a, 0x02, 0x04, 0x90, 0x09, 0x00, + 0x09, 0x03, 0x04, 0x9a, 0xa8, 0x05, 0x00, 0x00, + 0x02, 0x04, 0x90, 0x62, 0x00, 0x00, 0x02, 0x04, + 0x34, 0x81, 0xfb, 0x00, 0x00, 0x0d, 0x0b, 0x20, + 0x2c, 0x2e, 0x30, 0x3f, 0x4a, 0x54, 0x78, 0x85, + 0x97, 0x99, 0x9e, 0x00, 0x0c, 0x0b, 0x20, 0x2c, + 0x2e, 0x30, 0x3f, 0x4a, 0x54, 0x78, 0x97, 0x99, + 0x9e, 0x10, 0x00, 0x00, 0x15, 0x0b, 0x20, 0x22, + 0x2f, 0x58, 0x2c, 0x2e, 0x30, 0x3f, 0x53, 0x54, + 0x66, 0x6e, 0x78, 0x47, 0x89, 0x8f, 0x96, 0x97, + 0x99, 0x9e, 0x00, 0x17, 0x0b, 0x20, 0x22, 0x2f, + 0x58, 0x2c, 0x2e, 0x31, 0x30, 0x3f, 0x4c, 0x53, + 0x54, 0x66, 0x6e, 0x78, 0x47, 0x89, 0x8f, 0x96, + 0x97, 0x99, 0x9e, 0x09, 0x04, 0x20, 0x22, 0x3e, + 0x53, 0x75, 0x00, 0x09, 0x03, 0x0b, 0x15, 0x8f, + 0x75, 0x00, 0x09, 0x02, 0x30, 0x62, 0x75, 0x00, + 0x09, 0x02, 0x2e, 0x45, 0x80, 0x75, 0x00, 0x0d, + 0x02, 0x2c, 0x97, 0x80, 0x71, 0x00, 0x09, 0x03, + 0x3f, 0x66, 0xa2, 0x82, 0xcf, 0x00, 0x09, 0x03, + 0x15, 0x63, 0x93, 0x80, 0x30, 0x00, 0x00, 0x03, + 0x28, 0x29, 0x4a, 0x85, 0x6e, 0x00, 0x02, 0x01, + 0x82, 0x46, 0x00, 0x01, 0x04, 0x11, 0x35, 0x92, + 0x91, 0x80, 0x4a, 0x00, 0x01, 0x02, 0x60, 0x7e, + 0x00, 0x00, 0x00, 0x02, 0x60, 0x7e, 0x84, 0x49, + 0x00, 0x00, 0x04, 0x0b, 0x20, 0x2c, 0x3f, 0x00, + 0x01, 0x20, 0x00, 0x04, 0x0b, 0x20, 0x2c, 0x3f, + 0x00, 0x03, 0x20, 0x2c, 0x3f, 0x00, 0x01, 0x20, + 0x01, 0x02, 0x0b, 0x20, 0x00, 0x02, 0x20, 0x85, + 0x00, 0x02, 0x0b, 0x20, 0x00, 0x02, 0x20, 0x85, + 0x00, 0x06, 0x20, 0x3f, 0x54, 0x78, 0x97, 0x99, + 0x00, 0x01, 0x20, 0x01, 0x02, 0x20, 0x85, 0x01, + 0x01, 0x20, 0x00, 0x02, 0x20, 0x85, 0x00, 0x02, + 0x0b, 0x20, 0x06, 0x01, 0x20, 0x00, 0x02, 0x20, + 0x66, 0x00, 0x02, 0x0b, 0x20, 0x01, 0x01, 0x20, + 0x00, 0x02, 0x0b, 0x20, 0x03, 0x01, 0x20, 0x00, + 0x0b, 0x0b, 0x20, 0x2c, 0x3f, 0x54, 0x66, 0x78, + 0x89, 0x99, 0x9e, 0xa2, 0x00, 0x02, 0x20, 0x2c, + 0x00, 0x04, 0x20, 0x2c, 0x3f, 0xa2, 0x01, 0x02, + 0x0b, 0x20, 0x00, 0x01, 0x0b, 0x01, 0x02, 0x20, + 0x2c, 0x00, 0x01, 0x66, 0x80, 0x44, 0x00, 0x01, + 0x01, 0x2d, 0x35, 0x00, 0x00, 0x03, 0x1d, 0x4a, + 0x90, 0x00, 0x00, 0x00, 0x01, 0x90, 0x81, 0xb3, + 0x00, 0x00, 0x03, 0x4a, 0x60, 0x7e, 0x1e, 0x00, + 0x00, 0x02, 0x01, 0x04, 0x09, 0x00, 0x00, 0x06, + 0x13, 0x28, 0x29, 0x6f, 0x50, 0x76, 0x01, 0x00, + 0x00, 0x04, 0x13, 0x2d, 0x6f, 0x5d, 0x80, 0x11, + 0x00, 0x00, 0x03, 0x20, 0x2c, 0x4a, 0x8c, 0xa5, + 0x00, 0x00, 0x02, 0x1a, 0x4a, 0x17, 0x00, 0x00, + 0x02, 0x06, 0x76, 0x00, 0x07, 0x06, 0x13, 0x28, + 0x6f, 0x3e, 0x51, 0x83, 0x09, 0x00, 0x00, 0x01, + 0x23, 0x03, 0x00, 0x00, 0x03, 0x01, 0x04, 0x6f, + 0x00, 0x00, 0x00, 0x02, 0x1d, 0x29, 0x81, 0x2b, + 0x00, 0x0f, 0x02, 0x32, 0x98, 0x00, 0x00, 0x00, + 0x07, 0x0d, 0x33, 0x32, 0x38, 0x40, 0x60, 0xa9, + 0x00, 0x08, 0x0d, 0x33, 0x32, 0x38, 0x40, 0x60, + 0x7e, 0xa9, 0x00, 0x05, 0x0d, 0x33, 0x32, 0x38, + 0x40, 0x01, 0x00, 0x00, 0x01, 0x32, 0x00, 0x00, + 0x01, 0x08, 0x0d, 0x33, 0x32, 0x38, 0x40, 0x60, + 0x9c, 0xa9, 0x01, 0x09, 0x0d, 0x33, 0x32, 0x38, + 0x40, 0x4f, 0x60, 0x9c, 0xa9, 0x05, 0x06, 0x0d, + 0x33, 0x32, 0x38, 0x40, 0xa9, 0x00, 0x00, 0x00, + 0x05, 0x0d, 0x33, 0x32, 0x38, 0x40, 0x07, 0x06, + 0x0d, 0x33, 0x32, 0x38, 0x40, 0xa9, 0x03, 0x05, + 0x0d, 0x33, 0x32, 0x38, 0x40, 0x09, 0x00, 0x03, + 0x02, 0x0d, 0x32, 0x01, 0x00, 0x00, 0x05, 0x0d, + 0x33, 0x32, 0x38, 0x40, 0x04, 0x02, 0x38, 0x40, + 0x00, 0x00, 0x00, 0x05, 0x0d, 0x33, 0x32, 0x38, + 0x40, 0x03, 0x00, 0x01, 0x03, 0x32, 0x38, 0x40, + 0x01, 0x01, 0x32, 0x58, 0x00, 0x03, 0x02, 0x38, + 0x40, 0x02, 0x00, 0x00, 0x02, 0x38, 0x40, 0x59, + 0x00, 0x00, 0x06, 0x0d, 0x33, 0x32, 0x38, 0x40, + 0xa9, 0x00, 0x02, 0x38, 0x40, 0x80, 0x12, 0x00, + 0x0f, 0x01, 0x32, 0x1f, 0x00, 0x25, 0x01, 0x32, + 0x08, 0x00, 0x00, 0x02, 0x32, 0x98, 0x2f, 0x00, + 0x27, 0x01, 0x32, 0x37, 0x00, 0x30, 0x01, 0x32, + 0x0e, 0x00, 0x0b, 0x01, 0x32, 0x32, 0x00, 0x00, + 0x01, 0x32, 0x57, 0x00, 0x18, 0x01, 0x32, 0x09, + 0x00, 0x04, 0x01, 0x32, 0x5f, 0x00, 0x1e, 0x01, + 0x32, 0xc0, 0x31, 0xef, 0x00, 0x00, 0x02, 0x1d, + 0x29, 0x80, 0x0f, 0x00, 0x07, 0x02, 0x32, 0x4a, + 0x80, 0xa7, 0x00, 0x02, 0x10, 0x20, 0x22, 0x2e, + 0x30, 0x45, 0x3f, 0x3e, 0x53, 0x54, 0x5f, 0x66, + 0x85, 0x47, 0x96, 0x9e, 0xa2, 0x02, 0x0f, 0x20, + 0x22, 0x2e, 0x30, 0x45, 0x3f, 0x3e, 0x53, 0x5f, + 0x66, 0x85, 0x47, 0x96, 0x9e, 0xa2, 0x01, 0x0b, + 0x20, 0x22, 0x2e, 0x30, 0x45, 0x3e, 0x53, 0x5f, + 0x47, 0x96, 0x9e, 0x00, 0x0c, 0x20, 0x22, 0x2e, + 0x30, 0x45, 0x3e, 0x53, 0x5f, 0x85, 0x47, 0x96, + 0x9e, 0x00, 0x0b, 0x20, 0x22, 0x2e, 0x30, 0x45, + 0x3e, 0x53, 0x5f, 0x47, 0x96, 0x9e, 0x80, 0x36, + 0x00, 0x00, 0x03, 0x0b, 0x20, 0xa2, 0x00, 0x00, + 0x00, 0x02, 0x20, 0x97, 0x39, 0x00, 0x00, 0x03, + 0x42, 0x4a, 0x63, 0x80, 0x1f, 0x00, 0x00, 0x02, + 0x10, 0x3d, 0xc0, 0x12, 0xed, 0x00, 0x01, 0x02, + 0x04, 0x69, 0x80, 0x31, 0x00, 0x00, 0x02, 0x04, + 0x9a, 0x09, 0x00, 0x00, 0x02, 0x04, 0x9a, 0x46, + 0x00, 0x01, 0x05, 0x0d, 0x33, 0x32, 0x38, 0x40, + 0x80, 0x99, 0x00, 0x04, 0x06, 0x0d, 0x33, 0x32, + 0x38, 0x40, 0xa9, 0x09, 0x00, 0x00, 0x02, 0x38, + 0x40, 0x2c, 0x00, 0x01, 0x02, 0x38, 0x40, 0x80, + 0xdf, 0x00, 0x01, 0x03, 0x1e, 0x1c, 0x4e, 0x00, + 0x02, 0x1c, 0x4e, 0x03, 0x00, 0x2c, 0x03, 0x1c, + 0x4d, 0x4e, 0x02, 0x00, 0x08, 0x02, 0x1c, 0x4e, + 0x81, 0x1f, 0x00, 0x1b, 0x02, 0x04, 0x1a, 0x87, + 0x75, 0x00, 0x00, 0x02, 0x56, 0x77, 0x87, 0x8d, + 0x00, 0x00, 0x02, 0x2c, 0x97, 0x00, 0x00, 0x00, + 0x02, 0x2c, 0x97, 0x36, 0x00, 0x01, 0x02, 0x2c, + 0x97, 0x8c, 0x12, 0x00, 0x01, 0x02, 0x2c, 0x97, + 0x00, 0x00, 0x00, 0x02, 0x2c, 0x97, 0xc0, 0x5c, + 0x4b, 0x00, 0x03, 0x01, 0x23, 0x96, 0x3b, 0x00, + 0x11, 0x01, 0x32, 0x9e, 0x5d, 0x00, 0x01, 0x01, + 0x32, 0xce, 0xcd, 0x2d, 0x00, }; static const uint8_t unicode_prop_Hyphen_table[28] = { @@ -3721,61 +3788,63 @@ static const uint8_t unicode_prop_Other_Math_table[200] = { 0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80, 0x90, }; -static const uint8_t unicode_prop_Other_Alphabetic_table[428] = { - 0x43, 0x44, 0x80, 0x42, 0x69, 0x8d, 0x00, 0x01, - 0x01, 0x00, 0xc7, 0x8a, 0xaf, 0x8c, 0x06, 0x8f, - 0x80, 0xe4, 0x33, 0x19, 0x0b, 0x80, 0xa2, 0x80, - 0x9d, 0x8f, 0xe5, 0x8a, 0xe4, 0x0a, 0x88, 0x02, - 0x03, 0x40, 0xa6, 0x8b, 0x16, 0x85, 0x93, 0xb5, - 0x09, 0x8e, 0x01, 0x22, 0x89, 0x81, 0x9c, 0x82, - 0xb9, 0x31, 0x09, 0x81, 0x89, 0x80, 0x89, 0x81, - 0x9c, 0x82, 0xb9, 0x23, 0x09, 0x0b, 0x80, 0x9d, - 0x0a, 0x80, 0x8a, 0x82, 0xb9, 0x38, 0x10, 0x81, - 0x94, 0x81, 0x95, 0x13, 0x82, 0xb9, 0x31, 0x09, - 0x81, 0x88, 0x81, 0x89, 0x81, 0x9d, 0x80, 0xba, - 0x22, 0x10, 0x82, 0x89, 0x80, 0xa7, 0x84, 0xb8, - 0x30, 0x10, 0x17, 0x81, 0x8a, 0x81, 0x9c, 0x82, - 0xb9, 0x30, 0x10, 0x17, 0x81, 0x8a, 0x81, 0x8e, - 0x80, 0x8b, 0x83, 0xb9, 0x30, 0x10, 0x82, 0x89, - 0x80, 0x89, 0x81, 0x9c, 0x82, 0xca, 0x28, 0x00, - 0x87, 0x91, 0x81, 0xbc, 0x01, 0x86, 0x91, 0x80, - 0xe2, 0x01, 0x28, 0x81, 0x8f, 0x80, 0x40, 0xa2, - 0x92, 0x88, 0x8a, 0x80, 0xa3, 0xed, 0x8b, 0x00, - 0x0b, 0x96, 0x1b, 0x10, 0x11, 0x32, 0x83, 0x8c, - 0x8b, 0x00, 0x89, 0x83, 0x46, 0x73, 0x81, 0x9d, - 0x81, 0x9d, 0x81, 0x9d, 0x81, 0xc1, 0x92, 0x40, - 0xbb, 0x81, 0xa1, 0x80, 0xf5, 0x8b, 0x83, 0x88, - 0x40, 0xdd, 0x84, 0xb8, 0x89, 0x81, 0x93, 0xc9, - 0x81, 0x8a, 0x82, 0xb0, 0x84, 0xaf, 0x8e, 0xbb, - 0x82, 0x9d, 0x88, 0x09, 0xb8, 0x8a, 0xb1, 0x92, - 0x41, 0xaf, 0x8d, 0x46, 0xc0, 0xb3, 0x48, 0xf5, - 0x9f, 0x60, 0x78, 0x73, 0x87, 0xa1, 0x81, 0x41, - 0x61, 0x07, 0x80, 0x96, 0x84, 0xd7, 0x81, 0xb1, - 0x8f, 0x00, 0xb8, 0x80, 0xa5, 0x84, 0x9b, 0x8b, - 0xac, 0x83, 0xaf, 0x8b, 0xa4, 0x80, 0xc2, 0x8d, - 0x8b, 0x07, 0x81, 0xac, 0x82, 0xb1, 0x00, 0x11, - 0x0c, 0x80, 0xab, 0x24, 0x80, 0x40, 0xec, 0x87, - 0x60, 0x4f, 0x32, 0x80, 0x48, 0x56, 0x84, 0x46, - 0x85, 0x10, 0x0c, 0x83, 0x43, 0x13, 0x83, 0x41, - 0x82, 0x81, 0x41, 0x52, 0x82, 0xb4, 0x8d, 0xac, - 0x81, 0x8a, 0x82, 0xac, 0x88, 0x88, 0x80, 0xbc, - 0x82, 0xa3, 0x8b, 0x91, 0x81, 0xb8, 0x82, 0xaf, - 0x8c, 0x8d, 0x81, 0xdb, 0x88, 0x08, 0x28, 0x08, - 0x40, 0x9c, 0x89, 0x96, 0x83, 0xb9, 0x31, 0x09, - 0x81, 0x89, 0x80, 0x89, 0x81, 0x40, 0xd0, 0x8c, - 0x02, 0xe9, 0x91, 0x40, 0xec, 0x31, 0x86, 0x9c, - 0x81, 0xd1, 0x8e, 0x00, 0xe9, 0x8a, 0xe6, 0x8d, - 0x41, 0x00, 0x8c, 0x40, 0xf6, 0x28, 0x09, 0x0a, - 0x00, 0x80, 0x40, 0x8d, 0x31, 0x2b, 0x80, 0x9b, - 0x89, 0xa9, 0x20, 0x83, 0x91, 0x8a, 0xad, 0x8d, - 0x41, 0x96, 0x38, 0x86, 0xd2, 0x95, 0x80, 0x8d, - 0xf9, 0x2a, 0x00, 0x08, 0x10, 0x02, 0x80, 0xc1, - 0x20, 0x08, 0x83, 0x41, 0x5b, 0x83, 0x88, 0x08, - 0x80, 0xaf, 0x32, 0x82, 0x60, 0x50, 0x0d, 0x00, - 0xb6, 0x33, 0xdc, 0x81, 0x60, 0x4c, 0xab, 0x80, - 0x60, 0x23, 0x60, 0x30, 0x90, 0x0e, 0x01, 0x04, - 0xe3, 0x80, 0x48, 0xb6, 0x80, 0x47, 0xe7, 0x99, - 0x85, 0x99, 0x85, 0x99, +static const uint8_t unicode_prop_Other_Alphabetic_table[443] = { + 0x43, 0x44, 0x80, 0x9c, 0x8c, 0x42, 0x3f, 0x8d, + 0x00, 0x01, 0x01, 0x00, 0xc7, 0x8a, 0xaf, 0x8c, + 0x06, 0x8f, 0x80, 0xe4, 0x33, 0x19, 0x0b, 0x80, + 0xa2, 0x80, 0x9d, 0x8f, 0xe5, 0x8a, 0xe4, 0x0a, + 0x88, 0x02, 0x03, 0xe9, 0x80, 0xbb, 0x8b, 0x16, + 0x85, 0x93, 0xb5, 0x09, 0x8e, 0x01, 0x22, 0x89, + 0x81, 0x9c, 0x82, 0xb9, 0x31, 0x09, 0x81, 0x89, + 0x80, 0x89, 0x81, 0x9c, 0x82, 0xb9, 0x23, 0x09, + 0x0b, 0x80, 0x9d, 0x0a, 0x80, 0x8a, 0x82, 0xb9, + 0x38, 0x10, 0x81, 0x94, 0x81, 0x95, 0x13, 0x82, + 0xb9, 0x31, 0x09, 0x81, 0x88, 0x81, 0x89, 0x81, + 0x9d, 0x80, 0xba, 0x22, 0x10, 0x82, 0x89, 0x80, + 0xa7, 0x84, 0xb8, 0x30, 0x10, 0x17, 0x81, 0x8a, + 0x81, 0x9c, 0x82, 0xb9, 0x30, 0x10, 0x17, 0x81, + 0x8a, 0x81, 0x8e, 0x80, 0x8b, 0x83, 0xb9, 0x30, + 0x10, 0x82, 0x89, 0x80, 0x89, 0x81, 0x9c, 0x82, + 0xca, 0x28, 0x00, 0x87, 0x91, 0x81, 0xbc, 0x01, + 0x86, 0x91, 0x80, 0xe2, 0x01, 0x28, 0x81, 0x8f, + 0x80, 0x40, 0xa2, 0x92, 0x88, 0x8a, 0x80, 0xa3, + 0xed, 0x8b, 0x00, 0x0b, 0x96, 0x1b, 0x10, 0x11, + 0x32, 0x83, 0x8c, 0x8b, 0x00, 0x89, 0x83, 0x46, + 0x73, 0x81, 0x9d, 0x81, 0x9d, 0x81, 0x9d, 0x81, + 0xc1, 0x92, 0x40, 0xbb, 0x81, 0xa1, 0x80, 0xf5, + 0x8b, 0x83, 0x88, 0x40, 0xdd, 0x84, 0xb8, 0x89, + 0x81, 0x93, 0xc9, 0x81, 0x8a, 0x82, 0xb0, 0x84, + 0xaf, 0x8e, 0xbb, 0x82, 0x9d, 0x88, 0x09, 0xb8, + 0x8a, 0xb1, 0x92, 0x41, 0x9b, 0xa1, 0x46, 0xc0, + 0xb3, 0x48, 0xf5, 0x9f, 0x60, 0x78, 0x73, 0x87, + 0xa1, 0x81, 0x41, 0x61, 0x07, 0x80, 0x96, 0x84, + 0xd7, 0x81, 0xb1, 0x8f, 0x00, 0xb8, 0x80, 0xa5, + 0x84, 0x9b, 0x8b, 0xac, 0x83, 0xaf, 0x8b, 0xa4, + 0x80, 0xc2, 0x8d, 0x8b, 0x07, 0x81, 0xac, 0x82, + 0xb1, 0x00, 0x11, 0x0c, 0x80, 0xab, 0x24, 0x80, + 0x40, 0xec, 0x87, 0x60, 0x4f, 0x32, 0x80, 0x48, + 0x56, 0x84, 0x46, 0x85, 0x10, 0x0c, 0x83, 0x43, + 0x13, 0x83, 0xc0, 0x80, 0x41, 0x40, 0x81, 0xce, + 0x80, 0x41, 0x02, 0x82, 0xb4, 0x8d, 0xac, 0x81, + 0x8a, 0x82, 0xac, 0x88, 0x88, 0x80, 0xbc, 0x82, + 0xa3, 0x8b, 0x91, 0x81, 0xb8, 0x82, 0xaf, 0x8c, + 0x8d, 0x81, 0xdb, 0x88, 0x08, 0x28, 0x08, 0x40, + 0x9c, 0x89, 0x96, 0x83, 0xb9, 0x31, 0x09, 0x81, + 0x89, 0x80, 0x89, 0x81, 0xd3, 0x88, 0x00, 0x08, + 0x03, 0x01, 0xe6, 0x8c, 0x02, 0xe9, 0x91, 0x40, + 0xec, 0x31, 0x86, 0x9c, 0x81, 0xd1, 0x8e, 0x00, + 0xe9, 0x8a, 0xe6, 0x8d, 0x41, 0x00, 0x8c, 0x40, + 0xf6, 0x28, 0x09, 0x0a, 0x00, 0x80, 0x40, 0x8d, + 0x31, 0x2b, 0x80, 0x9b, 0x89, 0xa9, 0x20, 0x83, + 0x91, 0x8a, 0xad, 0x8d, 0x41, 0x96, 0x38, 0x86, + 0xd2, 0x95, 0x80, 0x8d, 0xf9, 0x2a, 0x00, 0x08, + 0x10, 0x02, 0x80, 0xc1, 0x20, 0x08, 0x83, 0x41, + 0x5b, 0x83, 0x88, 0x08, 0x80, 0xaf, 0x32, 0x82, + 0x60, 0x41, 0xdc, 0x90, 0x4e, 0x1f, 0x00, 0xb6, + 0x33, 0xdc, 0x81, 0x60, 0x4c, 0xab, 0x80, 0x60, + 0x23, 0x60, 0x30, 0x90, 0x0e, 0x01, 0x04, 0xe3, + 0x80, 0x48, 0xb6, 0x80, 0x47, 0xe7, 0x99, 0x85, + 0x99, 0x85, 0x99, }; static const uint8_t unicode_prop_Other_Lowercase_table[69] = { @@ -3795,16 +3864,21 @@ static const uint8_t unicode_prop_Other_Uppercase_table[15] = { 0xcc, 0x5f, 0x99, 0x85, 0x99, 0x85, 0x99, }; -static const uint8_t unicode_prop_Other_Grapheme_Extend_table[65] = { +static const uint8_t unicode_prop_Other_Grapheme_Extend_table[112] = { 0x49, 0xbd, 0x80, 0x97, 0x80, 0x41, 0x65, 0x80, - 0x97, 0x80, 0xe5, 0x80, 0x97, 0x80, 0x40, 0xe9, - 0x80, 0x91, 0x81, 0xe6, 0x80, 0x97, 0x80, 0xf6, - 0x80, 0x8e, 0x80, 0x4d, 0x54, 0x80, 0x44, 0xd5, - 0x80, 0x50, 0x20, 0x81, 0x60, 0xcf, 0x6d, 0x81, - 0x53, 0x9d, 0x80, 0x97, 0x80, 0x41, 0x57, 0x80, - 0x8b, 0x80, 0x40, 0xf0, 0x80, 0x43, 0x7f, 0x80, - 0x60, 0xb8, 0x33, 0x07, 0x84, 0x6c, 0x2e, 0xac, - 0xdf, + 0x97, 0x80, 0xe5, 0x80, 0x97, 0x80, 0x40, 0xe7, + 0x00, 0x03, 0x08, 0x81, 0x88, 0x81, 0xe6, 0x80, + 0x97, 0x80, 0xf6, 0x80, 0x8e, 0x80, 0x49, 0x34, + 0x80, 0x9d, 0x80, 0x43, 0xff, 0x04, 0x00, 0x04, + 0x81, 0xe4, 0x80, 0xc6, 0x81, 0x44, 0x17, 0x80, + 0x50, 0x20, 0x81, 0x60, 0x79, 0x22, 0x80, 0xeb, + 0x80, 0x60, 0x55, 0xdc, 0x81, 0x52, 0x1f, 0x80, + 0xf3, 0x80, 0x41, 0x07, 0x80, 0x8d, 0x80, 0x88, + 0x80, 0xdf, 0x80, 0x88, 0x01, 0x00, 0x14, 0x80, + 0x40, 0xdf, 0x80, 0x8b, 0x80, 0x40, 0xf0, 0x80, + 0x41, 0x05, 0x80, 0x42, 0x78, 0x80, 0x8b, 0x80, + 0x46, 0x02, 0x80, 0x60, 0x50, 0xad, 0x81, 0x60, + 0x61, 0x72, 0x0d, 0x85, 0x6c, 0x2e, 0xac, 0xdf, }; static const uint8_t unicode_prop_Other_Default_Ignorable_Code_Point_table[32] = { @@ -3819,9 +3893,10 @@ static const uint8_t unicode_prop_Other_ID_Start_table[11] = { 0x4f, 0x6b, 0x81, }; -static const uint8_t unicode_prop_Other_ID_Continue_table[12] = { +static const uint8_t unicode_prop_Other_ID_Continue_table[22] = { 0x40, 0xb6, 0x80, 0x42, 0xce, 0x80, 0x4f, 0xe0, - 0x88, 0x46, 0x67, 0x80, + 0x88, 0x46, 0x67, 0x80, 0x46, 0x30, 0x81, 0x50, + 0xec, 0x80, 0x60, 0xce, 0x68, 0x80, }; static const uint8_t unicode_prop_Prepended_Concatenation_Mark_table[19] = { @@ -3856,7 +3931,7 @@ static const uint8_t unicode_prop_Changes_When_Casefolded1_table[29] = { 0x89, 0x10, 0x81, 0x8d, 0x80, }; -static const uint8_t unicode_prop_Changes_When_NFKC_Casefolded1_table[447] = { +static const uint8_t unicode_prop_Changes_When_NFKC_Casefolded1_table[450] = { 0x40, 0x9f, 0x06, 0x00, 0x01, 0x00, 0x01, 0x12, 0x10, 0x82, 0xf3, 0x80, 0x8b, 0x80, 0x40, 0x84, 0x01, 0x01, 0x80, 0xa2, 0x01, 0x80, 0x40, 0xbb, @@ -3898,21 +3973,22 @@ static const uint8_t unicode_prop_Changes_When_NFKC_Casefolded1_table[447] = { 0x92, 0x03, 0x1a, 0x00, 0x80, 0x40, 0x86, 0x08, 0x80, 0x9f, 0x99, 0x40, 0x83, 0x15, 0x0d, 0x0d, 0x0a, 0x16, 0x06, 0x80, 0x88, 0x47, 0x87, 0x20, - 0xa9, 0x80, 0x88, 0x60, 0xb4, 0xe4, 0x83, 0x54, - 0xb9, 0x86, 0x8d, 0x87, 0xbf, 0x85, 0x42, 0x3e, - 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b, 0x80, - 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f, 0x06, - 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80, 0x41, - 0x53, 0x81, 0x41, 0x23, 0x81, 0xb1, 0x48, 0x2f, - 0xbd, 0x4d, 0x91, 0x18, 0x9a, 0x01, 0x00, 0x08, - 0x80, 0x89, 0x03, 0x00, 0x00, 0x28, 0x18, 0x00, - 0x00, 0x02, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00, - 0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80, 0x90, - 0x42, 0x43, 0x8a, 0x84, 0x9e, 0x80, 0x9f, 0x99, - 0x82, 0xa2, 0x80, 0xee, 0x82, 0x8c, 0xab, 0x83, - 0x88, 0x31, 0x49, 0x9d, 0x89, 0x60, 0xfc, 0x05, - 0x42, 0x1d, 0x6b, 0x05, 0xe1, 0x4f, 0xff, + 0xa9, 0x80, 0x88, 0x60, 0xb4, 0xe4, 0x83, 0x50, + 0x31, 0xa3, 0x44, 0x63, 0x86, 0x8d, 0x87, 0xbf, + 0x85, 0x42, 0x3e, 0xd4, 0x80, 0xc6, 0x01, 0x08, + 0x09, 0x0b, 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, + 0x03, 0x0f, 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, + 0x16, 0x80, 0x41, 0x53, 0x81, 0x41, 0x23, 0x81, + 0xb1, 0x48, 0x2f, 0xbd, 0x4d, 0x91, 0x18, 0x9a, + 0x01, 0x00, 0x08, 0x80, 0x89, 0x03, 0x00, 0x00, + 0x28, 0x18, 0x00, 0x00, 0x02, 0x01, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x06, + 0x03, 0x03, 0x00, 0x80, 0x89, 0x80, 0x90, 0x22, + 0x04, 0x80, 0x90, 0x42, 0x43, 0x8a, 0x84, 0x9e, + 0x80, 0x9f, 0x99, 0x82, 0xa2, 0x80, 0xee, 0x82, + 0x8c, 0xab, 0x83, 0x88, 0x31, 0x49, 0x9d, 0x89, + 0x60, 0xfc, 0x05, 0x42, 0x1d, 0x6b, 0x05, 0xe1, + 0x4f, 0xff, }; static const uint8_t unicode_prop_ASCII_Hex_Digit_table[5] = { @@ -3924,14 +4000,15 @@ static const uint8_t unicode_prop_Bidi_Control_table[10] = { 0xb6, 0x83, }; -static const uint8_t unicode_prop_Dash_table[55] = { +static const uint8_t unicode_prop_Dash_table[58] = { 0xac, 0x80, 0x45, 0x5b, 0x80, 0xb2, 0x80, 0x4e, 0x40, 0x80, 0x44, 0x04, 0x80, 0x48, 0x08, 0x85, 0xbc, 0x80, 0xa6, 0x80, 0x8e, 0x80, 0x41, 0x85, 0x80, 0x4c, 0x03, 0x01, 0x80, 0x9e, 0x0b, 0x80, 0x9b, 0x80, 0x41, 0xbd, 0x80, 0x92, 0x80, 0xee, 0x80, 0x60, 0xcd, 0x8f, 0x81, 0xa4, 0x80, 0x89, - 0x80, 0x40, 0xa8, 0x80, 0x4f, 0x9e, 0x80, + 0x80, 0x40, 0xa8, 0x80, 0x4e, 0x5f, 0x80, 0x41, + 0x3d, 0x80, }; static const uint8_t unicode_prop_Deprecated_table[23] = { @@ -3940,7 +4017,7 @@ static const uint8_t unicode_prop_Deprecated_table[23] = { 0x42, 0xb8, 0x81, 0x6d, 0xdc, 0xd5, 0x80, }; -static const uint8_t unicode_prop_Diacritic_table[399] = { +static const uint8_t unicode_prop_Diacritic_table[438] = { 0xdd, 0x00, 0x80, 0xc6, 0x05, 0x03, 0x01, 0x81, 0x41, 0xf6, 0x40, 0x9e, 0x07, 0x25, 0x90, 0x0b, 0x80, 0x88, 0x81, 0x40, 0xfc, 0x84, 0x40, 0xd0, @@ -3953,59 +4030,66 @@ static const uint8_t unicode_prop_Diacritic_table[399] = { 0x8f, 0x80, 0xae, 0x82, 0xbb, 0x80, 0x8f, 0x06, 0x80, 0xf6, 0x80, 0xed, 0x80, 0x8f, 0x80, 0xed, 0x80, 0x8f, 0x80, 0xec, 0x81, 0x8f, 0x80, 0xfb, - 0x80, 0xfb, 0x28, 0x80, 0xea, 0x80, 0x8c, 0x84, - 0xca, 0x81, 0x9a, 0x00, 0x00, 0x03, 0x81, 0xc1, - 0x10, 0x81, 0xbd, 0x80, 0xef, 0x00, 0x81, 0xa7, - 0x0b, 0x84, 0x98, 0x30, 0x80, 0x89, 0x81, 0x42, - 0xc0, 0x82, 0x43, 0xb3, 0x81, 0x40, 0xb2, 0x8a, - 0x88, 0x80, 0x41, 0x5a, 0x82, 0x41, 0x38, 0x39, - 0x80, 0xaf, 0x8e, 0x81, 0x8a, 0xe7, 0x80, 0x8e, - 0x80, 0xa5, 0x88, 0xb5, 0x81, 0x40, 0x89, 0x81, - 0xbf, 0x85, 0xd1, 0x98, 0x18, 0x28, 0x0a, 0xb1, - 0xbe, 0xd8, 0x8b, 0xa4, 0x8a, 0x41, 0xbc, 0x00, - 0x82, 0x8a, 0x82, 0x8c, 0x82, 0x8c, 0x82, 0x8c, - 0x81, 0x4c, 0xef, 0x82, 0x41, 0x3c, 0x80, 0x41, - 0xf9, 0x85, 0xe8, 0x83, 0xde, 0x80, 0x60, 0x75, - 0x71, 0x80, 0x8b, 0x08, 0x80, 0x9b, 0x81, 0xd1, - 0x81, 0x8d, 0xa1, 0xe5, 0x82, 0xec, 0x81, 0x40, - 0xc9, 0x80, 0x9a, 0x91, 0xb8, 0x83, 0xa3, 0x80, - 0xde, 0x80, 0x8b, 0x80, 0xa3, 0x80, 0x40, 0x94, - 0x82, 0xc0, 0x83, 0xb2, 0x80, 0xe3, 0x84, 0x88, - 0x82, 0xff, 0x81, 0x60, 0x4f, 0x2f, 0x80, 0x43, - 0x00, 0x8f, 0x41, 0x0d, 0x00, 0x80, 0xae, 0x80, - 0xac, 0x81, 0xc2, 0x80, 0x42, 0xfb, 0x80, 0x44, - 0x9e, 0x28, 0xa9, 0x80, 0x88, 0x43, 0x29, 0x81, - 0x42, 0x3a, 0x85, 0x41, 0xd4, 0x82, 0xc5, 0x8a, - 0xb0, 0x83, 0x40, 0xbf, 0x80, 0xa8, 0x80, 0xc7, - 0x81, 0xf7, 0x81, 0xbd, 0x80, 0xcb, 0x80, 0x88, - 0x82, 0xe7, 0x81, 0x40, 0xb1, 0x81, 0xd0, 0x80, - 0x8f, 0x80, 0x97, 0x32, 0x84, 0x40, 0xcc, 0x02, - 0x80, 0xfa, 0x81, 0x40, 0xfa, 0x81, 0xfd, 0x80, - 0xf5, 0x81, 0xf2, 0x80, 0x41, 0x0c, 0x81, 0x41, - 0x01, 0x0b, 0x80, 0x40, 0x9b, 0x80, 0xd2, 0x80, - 0x91, 0x80, 0xd0, 0x80, 0x41, 0xa4, 0x80, 0x41, - 0x01, 0x00, 0x81, 0xd0, 0x80, 0x56, 0xae, 0x8e, - 0x60, 0x36, 0x99, 0x84, 0xba, 0x86, 0x44, 0x57, - 0x90, 0xcf, 0x81, 0x60, 0x3f, 0xfd, 0x18, 0x30, - 0x81, 0x5f, 0x00, 0xad, 0x81, 0x96, 0x42, 0x1f, - 0x12, 0x2f, 0x39, 0x86, 0x9d, 0x83, 0x4e, 0x81, - 0xbd, 0x40, 0xc1, 0x86, 0x41, 0x76, 0x80, 0xbc, - 0x83, 0x45, 0xdf, 0x86, 0xec, 0x10, 0x82, + 0x80, 0xee, 0x80, 0x8b, 0x28, 0x80, 0xea, 0x80, + 0x8c, 0x84, 0xca, 0x81, 0x9a, 0x00, 0x00, 0x03, + 0x81, 0xc1, 0x10, 0x81, 0xbd, 0x80, 0xef, 0x00, + 0x81, 0xa7, 0x0b, 0x84, 0x98, 0x30, 0x80, 0x89, + 0x81, 0x42, 0xc0, 0x82, 0x43, 0xb3, 0x81, 0x9d, + 0x80, 0x40, 0x93, 0x8a, 0x88, 0x80, 0x41, 0x5a, + 0x82, 0x41, 0x23, 0x80, 0x93, 0x39, 0x80, 0xaf, + 0x8e, 0x81, 0x8a, 0xe7, 0x80, 0x8e, 0x80, 0xa5, + 0x88, 0xb5, 0x81, 0xb9, 0x80, 0x8a, 0x81, 0xc1, + 0x81, 0xbf, 0x85, 0xd1, 0x98, 0x18, 0x28, 0x0a, + 0xb1, 0xbe, 0xd8, 0x8b, 0xa4, 0x8a, 0x41, 0xbc, + 0x00, 0x82, 0x8a, 0x82, 0x8c, 0x82, 0x8c, 0x82, + 0x8c, 0x81, 0x4c, 0xef, 0x82, 0x41, 0x3c, 0x80, + 0x41, 0xf9, 0x85, 0xe8, 0x83, 0xde, 0x80, 0x60, + 0x75, 0x71, 0x80, 0x8b, 0x08, 0x80, 0x9b, 0x81, + 0xd1, 0x81, 0x8d, 0xa1, 0xe5, 0x82, 0xec, 0x81, + 0x8b, 0x80, 0xa4, 0x80, 0x40, 0x96, 0x80, 0x9a, + 0x91, 0xb8, 0x83, 0xa3, 0x80, 0xde, 0x80, 0x8b, + 0x80, 0xa3, 0x80, 0x40, 0x94, 0x82, 0xc0, 0x83, + 0xb2, 0x80, 0xe3, 0x84, 0x88, 0x82, 0xff, 0x81, + 0x60, 0x4f, 0x2f, 0x80, 0x43, 0x00, 0x8f, 0x41, + 0x0d, 0x00, 0x80, 0xae, 0x80, 0xac, 0x81, 0xc2, + 0x80, 0x42, 0xfb, 0x80, 0x44, 0x9e, 0x28, 0xa9, + 0x80, 0x88, 0x42, 0x7c, 0x13, 0x80, 0x40, 0xa4, + 0x81, 0x42, 0x3a, 0x85, 0xa5, 0x80, 0x99, 0x84, + 0x41, 0x8e, 0x82, 0xc5, 0x8a, 0xb0, 0x83, 0x40, + 0xbf, 0x80, 0xa8, 0x80, 0xc7, 0x81, 0xf7, 0x81, + 0xbd, 0x80, 0xcb, 0x80, 0x88, 0x82, 0xe7, 0x81, + 0x40, 0xb1, 0x81, 0xcf, 0x81, 0x8f, 0x80, 0x97, + 0x32, 0x84, 0xd8, 0x10, 0x81, 0x8c, 0x81, 0xde, + 0x02, 0x80, 0xfa, 0x81, 0x40, 0xfa, 0x81, 0xfd, + 0x80, 0xf5, 0x81, 0xf2, 0x80, 0x41, 0x0c, 0x81, + 0x41, 0x01, 0x0b, 0x80, 0x40, 0x9b, 0x80, 0xd2, + 0x80, 0x91, 0x80, 0xd0, 0x80, 0x41, 0xa4, 0x80, + 0x41, 0x01, 0x00, 0x81, 0xd0, 0x80, 0x41, 0xa8, + 0x81, 0x96, 0x80, 0x54, 0xeb, 0x8e, 0x60, 0x2c, + 0xd8, 0x80, 0x49, 0xbf, 0x84, 0xba, 0x86, 0x42, + 0x33, 0x81, 0x42, 0x21, 0x90, 0xcf, 0x81, 0x60, + 0x3f, 0xfd, 0x18, 0x30, 0x81, 0x5f, 0x00, 0xad, + 0x81, 0x96, 0x42, 0x1f, 0x12, 0x2f, 0x39, 0x86, + 0x9d, 0x83, 0x4e, 0x81, 0xbd, 0x40, 0xc1, 0x86, + 0x41, 0x76, 0x80, 0xbc, 0x83, 0x42, 0xfd, 0x81, + 0x42, 0xdf, 0x86, 0xec, 0x10, 0x82, }; -static const uint8_t unicode_prop_Extender_table[92] = { +static const uint8_t unicode_prop_Extender_table[111] = { 0x40, 0xb6, 0x80, 0x42, 0x17, 0x81, 0x43, 0x6d, - 0x80, 0x41, 0xb8, 0x80, 0x43, 0x59, 0x80, 0x42, - 0xef, 0x80, 0xfe, 0x80, 0x49, 0x42, 0x80, 0xb7, - 0x80, 0x42, 0x62, 0x80, 0x41, 0x8d, 0x80, 0xc3, - 0x80, 0x53, 0x88, 0x80, 0xaa, 0x84, 0xe6, 0x81, - 0xdc, 0x82, 0x60, 0x6f, 0x15, 0x80, 0x45, 0xf5, - 0x80, 0x43, 0xc1, 0x80, 0x95, 0x80, 0x40, 0x88, - 0x80, 0xeb, 0x80, 0x94, 0x81, 0x60, 0x54, 0x7a, - 0x80, 0x48, 0x0f, 0x81, 0x4b, 0xd9, 0x80, 0x42, - 0x67, 0x82, 0x44, 0xce, 0x80, 0x60, 0x50, 0xa8, + 0x80, 0x41, 0xb8, 0x80, 0x42, 0x75, 0x80, 0x40, + 0x88, 0x80, 0xd8, 0x80, 0x42, 0xef, 0x80, 0xfe, + 0x80, 0x49, 0x42, 0x80, 0xb7, 0x80, 0x42, 0x62, + 0x80, 0x41, 0x8d, 0x80, 0xc3, 0x80, 0x53, 0x88, + 0x80, 0xaa, 0x84, 0xe6, 0x81, 0xdc, 0x82, 0x60, + 0x6f, 0x15, 0x80, 0x45, 0xf5, 0x80, 0x43, 0xc1, + 0x80, 0x95, 0x80, 0x40, 0x88, 0x80, 0xeb, 0x80, + 0x94, 0x81, 0x60, 0x54, 0x7a, 0x80, 0x48, 0x0f, + 0x81, 0x45, 0xca, 0x80, 0x9a, 0x03, 0x80, 0x44, + 0xc6, 0x80, 0x41, 0x24, 0x80, 0xf3, 0x81, 0x41, + 0xf1, 0x82, 0x44, 0xce, 0x80, 0x60, 0x50, 0xa8, 0x81, 0x44, 0x9b, 0x08, 0x80, 0x60, 0x71, 0x57, - 0x81, 0x48, 0x05, 0x82, + 0x81, 0x44, 0xb0, 0x80, 0x43, 0x53, 0x82, }; static const uint8_t unicode_prop_Hex_Digit_table[12] = { @@ -4013,24 +4097,28 @@ static const uint8_t unicode_prop_Hex_Digit_table[12] = { 0x89, 0x35, 0x99, 0x85, }; -static const uint8_t unicode_prop_IDS_Binary_Operator_table[5] = { - 0x60, 0x2f, 0xef, 0x09, 0x87, +static const uint8_t unicode_prop_IDS_Unary_Operator_table[4] = { + 0x60, 0x2f, 0xfd, 0x81, +}; + +static const uint8_t unicode_prop_IDS_Binary_Operator_table[8] = { + 0x60, 0x2f, 0xef, 0x09, 0x89, 0x41, 0xf0, 0x80, }; static const uint8_t unicode_prop_IDS_Trinary_Operator_table[4] = { 0x60, 0x2f, 0xf1, 0x81, }; -static const uint8_t unicode_prop_Ideographic_table[69] = { +static const uint8_t unicode_prop_Ideographic_table[72] = { 0x60, 0x30, 0x05, 0x81, 0x98, 0x88, 0x8d, 0x82, 0x43, 0xc4, 0x59, 0xbf, 0xbf, 0x60, 0x51, 0xff, 0x60, 0x58, 0xff, 0x41, 0x6d, 0x81, 0xe9, 0x60, 0x75, 0x09, 0x80, 0x9a, 0x57, 0xf7, 0x87, 0x44, - 0xd5, 0xa9, 0x88, 0x60, 0x24, 0x66, 0x41, 0x8b, + 0xd5, 0xa8, 0x89, 0x60, 0x24, 0x66, 0x41, 0x8b, 0x60, 0x4d, 0x03, 0x60, 0xa6, 0xdf, 0x9f, 0x50, 0x39, 0x85, 0x40, 0xdd, 0x81, 0x56, 0x81, 0x8d, - 0x5d, 0x30, 0x4c, 0x1e, 0x42, 0x1d, 0x45, 0xe1, - 0x53, 0x4a, 0x84, 0x50, 0x5f, + 0x5d, 0x30, 0x8e, 0x42, 0x6d, 0x49, 0xa1, 0x42, + 0x1d, 0x45, 0xe1, 0x53, 0x4a, 0x84, 0x50, 0x5f, }; static const uint8_t unicode_prop_Join_Control_table[4] = { @@ -4042,6 +4130,11 @@ static const uint8_t unicode_prop_Logical_Order_Exception_table[15] = { 0x80, 0x60, 0x90, 0xf9, 0x09, 0x00, 0x81, }; +static const uint8_t unicode_prop_Modifier_Combining_Mark_table[16] = { + 0x46, 0x53, 0x09, 0x80, 0x40, 0x82, 0x05, 0x02, + 0x81, 0x41, 0xe0, 0x08, 0x12, 0x80, 0x9e, 0x80, +}; + static const uint8_t unicode_prop_Noncharacter_Code_Point_table[71] = { 0x60, 0xfd, 0xcf, 0x9f, 0x42, 0x0d, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, @@ -4086,32 +4179,34 @@ static const uint8_t unicode_prop_Regional_Indicator_table[4] = { 0x61, 0xf1, 0xe5, 0x99, }; -static const uint8_t unicode_prop_Sentence_Terminal_table[196] = { +static const uint8_t unicode_prop_Sentence_Terminal_table[213] = { 0xa0, 0x80, 0x8b, 0x80, 0x8f, 0x80, 0x45, 0x48, 0x80, 0x40, 0x92, 0x82, 0x40, 0xb3, 0x80, 0xaa, 0x82, 0x40, 0xf5, 0x80, 0xbc, 0x00, 0x02, 0x81, 0x41, 0x24, 0x81, 0x46, 0xe3, 0x81, 0x43, 0x15, 0x03, 0x81, 0x43, 0x04, 0x80, 0x40, 0xc5, 0x81, - 0x40, 0xcb, 0x04, 0x80, 0x41, 0x39, 0x81, 0x41, - 0x61, 0x83, 0x40, 0xad, 0x09, 0x81, 0x9c, 0x81, - 0x40, 0xbb, 0x81, 0xc0, 0x81, 0x43, 0xbb, 0x81, - 0x88, 0x82, 0x4d, 0xe3, 0x80, 0x8c, 0x80, 0x95, - 0x81, 0x41, 0xac, 0x80, 0x60, 0x74, 0xfb, 0x80, - 0x41, 0x0d, 0x81, 0x40, 0xe2, 0x02, 0x80, 0x41, - 0x7d, 0x81, 0xd5, 0x81, 0xde, 0x80, 0x40, 0x97, - 0x81, 0x40, 0x92, 0x82, 0x40, 0x8f, 0x81, 0x40, - 0xf8, 0x80, 0x60, 0x52, 0x65, 0x02, 0x81, 0x40, - 0xa8, 0x80, 0x8b, 0x80, 0x8f, 0x80, 0xc0, 0x80, - 0x4a, 0xf3, 0x81, 0x44, 0xfc, 0x84, 0xab, 0x83, - 0x40, 0xbc, 0x81, 0xf4, 0x83, 0xfe, 0x82, 0x40, - 0x80, 0x0d, 0x80, 0x8f, 0x81, 0xd7, 0x08, 0x81, - 0xeb, 0x80, 0x41, 0xa0, 0x81, 0x41, 0x74, 0x0c, - 0x8e, 0xe8, 0x81, 0x40, 0xf8, 0x82, 0x42, 0x04, - 0x00, 0x80, 0x40, 0xfa, 0x81, 0xd6, 0x81, 0x41, - 0xa3, 0x81, 0x42, 0xb3, 0x81, 0xc9, 0x81, 0x60, - 0x4b, 0x28, 0x81, 0x40, 0x84, 0x80, 0xc0, 0x81, - 0x8a, 0x80, 0x43, 0x52, 0x80, 0x60, 0x4e, 0x05, - 0x80, 0x5d, 0xe7, 0x80, + 0x40, 0x9c, 0x81, 0xac, 0x04, 0x80, 0x41, 0x39, + 0x81, 0x41, 0x61, 0x83, 0x40, 0xa1, 0x81, 0x89, + 0x09, 0x81, 0x9c, 0x82, 0x40, 0xba, 0x81, 0xc0, + 0x81, 0x43, 0xa3, 0x80, 0x96, 0x81, 0x88, 0x82, + 0x4c, 0xae, 0x82, 0x41, 0x31, 0x80, 0x8c, 0x80, + 0x95, 0x81, 0x41, 0xac, 0x80, 0x60, 0x74, 0xfb, + 0x80, 0x41, 0x0d, 0x81, 0x40, 0xe2, 0x02, 0x80, + 0x41, 0x7d, 0x81, 0xd5, 0x81, 0xde, 0x80, 0x40, + 0x97, 0x81, 0x40, 0x92, 0x82, 0x40, 0x8f, 0x81, + 0x40, 0xf8, 0x80, 0x60, 0x52, 0x25, 0x01, 0x81, + 0xba, 0x02, 0x81, 0x40, 0xa8, 0x80, 0x8b, 0x80, + 0x8f, 0x80, 0xc0, 0x80, 0x4a, 0xf3, 0x81, 0x44, + 0xfc, 0x84, 0xab, 0x83, 0x40, 0xbc, 0x81, 0xf4, + 0x83, 0xfe, 0x82, 0x40, 0x80, 0x0d, 0x80, 0x8f, + 0x81, 0xd7, 0x08, 0x81, 0xeb, 0x80, 0x41, 0x29, + 0x81, 0xf4, 0x81, 0x41, 0x74, 0x0c, 0x8e, 0xe8, + 0x81, 0x40, 0xf8, 0x82, 0x42, 0x04, 0x00, 0x80, + 0x40, 0xfa, 0x81, 0xd6, 0x81, 0x41, 0xa3, 0x81, + 0x42, 0xb3, 0x81, 0xc9, 0x81, 0x60, 0x4b, 0x28, + 0x81, 0x40, 0x84, 0x80, 0xc0, 0x81, 0x8a, 0x80, + 0x42, 0x28, 0x81, 0x41, 0x27, 0x80, 0x60, 0x4e, + 0x05, 0x80, 0x5d, 0xe7, 0x80, }; static const uint8_t unicode_prop_Soft_Dotted_table[79] = { @@ -4127,47 +4222,49 @@ static const uint8_t unicode_prop_Soft_Dotted_table[79] = { 0x85, 0x80, 0x41, 0x30, 0x81, 0x99, 0x80, }; -static const uint8_t unicode_prop_Terminal_Punctuation_table[248] = { +static const uint8_t unicode_prop_Terminal_Punctuation_table[264] = { 0xa0, 0x80, 0x89, 0x00, 0x80, 0x8a, 0x0a, 0x80, 0x43, 0x3d, 0x07, 0x80, 0x42, 0x00, 0x80, 0xb8, 0x80, 0xc7, 0x80, 0x8d, 0x00, 0x82, 0x40, 0xb3, 0x80, 0xaa, 0x8a, 0x00, 0x40, 0xea, 0x81, 0xb5, - 0x8e, 0x9e, 0x80, 0x41, 0x04, 0x81, 0x44, 0xf3, - 0x81, 0x40, 0xab, 0x03, 0x85, 0x41, 0x36, 0x81, - 0x43, 0x14, 0x87, 0x43, 0x04, 0x80, 0xfb, 0x82, - 0xc6, 0x81, 0x40, 0x9c, 0x12, 0x80, 0xa6, 0x19, - 0x81, 0x41, 0x39, 0x81, 0x41, 0x61, 0x83, 0x40, - 0xad, 0x08, 0x82, 0x9c, 0x81, 0x40, 0xbb, 0x84, - 0xbd, 0x81, 0x43, 0xbb, 0x81, 0x88, 0x82, 0x4d, - 0xe3, 0x80, 0x8c, 0x03, 0x80, 0x89, 0x00, 0x0a, + 0x28, 0x87, 0x9e, 0x80, 0x41, 0x04, 0x81, 0x44, + 0xf3, 0x81, 0x40, 0xab, 0x03, 0x85, 0x41, 0x36, + 0x81, 0x43, 0x14, 0x87, 0x43, 0x04, 0x80, 0xfb, + 0x82, 0xc6, 0x81, 0x40, 0x9c, 0x12, 0x80, 0xa6, + 0x19, 0x81, 0x41, 0x39, 0x81, 0x41, 0x61, 0x83, + 0x40, 0xa1, 0x81, 0x89, 0x08, 0x82, 0x9c, 0x82, + 0x40, 0xba, 0x84, 0xbd, 0x81, 0x43, 0xa3, 0x80, + 0x96, 0x81, 0x88, 0x82, 0x4c, 0xae, 0x82, 0x41, + 0x31, 0x80, 0x8c, 0x03, 0x80, 0x89, 0x00, 0x0a, 0x81, 0x41, 0xab, 0x81, 0x60, 0x74, 0xfa, 0x81, 0x41, 0x0c, 0x82, 0x40, 0xe2, 0x84, 0x41, 0x7d, 0x81, 0xd5, 0x81, 0xde, 0x80, 0x40, 0x96, 0x82, 0x40, 0x92, 0x82, 0xfe, 0x80, 0x8f, 0x81, 0x40, - 0xf8, 0x80, 0x60, 0x52, 0x63, 0x10, 0x83, 0x40, - 0xa8, 0x80, 0x89, 0x00, 0x80, 0x8a, 0x0a, 0x80, - 0xc0, 0x01, 0x80, 0x44, 0x39, 0x80, 0xaf, 0x80, - 0x44, 0x85, 0x80, 0x40, 0xc6, 0x80, 0x41, 0x35, - 0x81, 0x40, 0x97, 0x85, 0xc3, 0x85, 0xd8, 0x83, - 0x43, 0xb7, 0x84, 0xab, 0x83, 0x40, 0xbc, 0x86, - 0xef, 0x83, 0xfe, 0x82, 0x40, 0x80, 0x0d, 0x80, - 0x8f, 0x81, 0xd7, 0x84, 0xeb, 0x80, 0x41, 0xa0, - 0x82, 0x8b, 0x81, 0x41, 0x65, 0x1a, 0x8e, 0xe8, - 0x81, 0x40, 0xf8, 0x82, 0x42, 0x04, 0x00, 0x80, - 0x40, 0xfa, 0x81, 0xd6, 0x0b, 0x81, 0x41, 0x9d, - 0x82, 0xac, 0x80, 0x42, 0x84, 0x81, 0xc9, 0x81, - 0x45, 0x2a, 0x84, 0x60, 0x45, 0xf8, 0x81, 0x40, - 0x84, 0x80, 0xc0, 0x82, 0x89, 0x80, 0x43, 0x51, + 0xf8, 0x80, 0x60, 0x52, 0x25, 0x01, 0x81, 0xb8, + 0x10, 0x83, 0x40, 0xa8, 0x80, 0x89, 0x00, 0x80, + 0x8a, 0x0a, 0x80, 0xc0, 0x01, 0x80, 0x44, 0x39, + 0x80, 0xaf, 0x80, 0x44, 0x85, 0x80, 0x40, 0xc6, + 0x80, 0x41, 0x35, 0x81, 0x40, 0x97, 0x85, 0xc3, + 0x85, 0xd8, 0x83, 0x43, 0xb7, 0x84, 0xab, 0x83, + 0x40, 0xbc, 0x86, 0xef, 0x83, 0xfe, 0x82, 0x40, + 0x80, 0x0d, 0x80, 0x8f, 0x81, 0xd7, 0x84, 0xeb, + 0x80, 0x41, 0x29, 0x81, 0xf4, 0x82, 0x8b, 0x81, + 0x41, 0x65, 0x1a, 0x8e, 0xe8, 0x81, 0x40, 0xf8, + 0x82, 0x42, 0x04, 0x00, 0x80, 0x40, 0xfa, 0x81, + 0xd6, 0x0b, 0x81, 0x41, 0x9d, 0x82, 0xac, 0x80, + 0x42, 0x84, 0x81, 0xc9, 0x81, 0x45, 0x2a, 0x84, + 0x60, 0x45, 0xf8, 0x81, 0x40, 0x84, 0x80, 0xc0, + 0x82, 0x89, 0x80, 0x42, 0x28, 0x81, 0x41, 0x26, 0x81, 0x60, 0x4e, 0x05, 0x80, 0x5d, 0xe6, 0x83, }; -static const uint8_t unicode_prop_Unified_Ideograph_table[45] = { +static const uint8_t unicode_prop_Unified_Ideograph_table[48] = { 0x60, 0x33, 0xff, 0x59, 0xbf, 0xbf, 0x60, 0x51, 0xff, 0x60, 0x5a, 0x0d, 0x08, 0x00, 0x81, 0x89, 0x00, 0x00, 0x09, 0x82, 0x61, 0x05, 0xd5, 0x60, 0xa6, 0xdf, 0x9f, 0x50, 0x39, 0x85, 0x40, 0xdd, - 0x81, 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x54, 0x1e, - 0x53, 0x4a, 0x84, 0x50, 0x5f, + 0x81, 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x8e, 0x42, + 0x6d, 0x51, 0xa1, 0x53, 0x4a, 0x84, 0x50, 0x5f, }; static const uint8_t unicode_prop_Variation_Selector_table[13] = { @@ -4175,12 +4272,6 @@ static const uint8_t unicode_prop_Variation_Selector_table[13] = { 0x6d, 0x02, 0xef, 0x40, 0xef, }; -static const uint8_t unicode_prop_White_Space_table[22] = { - 0x88, 0x84, 0x91, 0x80, 0xe3, 0x80, 0x99, 0x80, - 0x55, 0xde, 0x80, 0x49, 0x7e, 0x8a, 0x9c, 0x0c, - 0x80, 0xae, 0x80, 0x4f, 0x9f, 0x80, -}; - static const uint8_t unicode_prop_Bidi_Mirrored_table[173] = { 0xa7, 0x81, 0x91, 0x00, 0x80, 0x9b, 0x00, 0x80, 0x9c, 0x00, 0x80, 0xac, 0x80, 0x8e, 0x80, 0x4e, @@ -4188,7 +4279,7 @@ static const uint8_t unicode_prop_Bidi_Mirrored_table[173] = { 0x89, 0x81, 0xb5, 0x81, 0x8d, 0x81, 0x40, 0xb0, 0x80, 0x40, 0xbf, 0x1a, 0x2a, 0x02, 0x0a, 0x18, 0x18, 0x00, 0x03, 0x88, 0x20, 0x80, 0x91, 0x23, - 0x88, 0x08, 0x00, 0x39, 0x9e, 0x0b, 0x20, 0x88, + 0x88, 0x08, 0x00, 0x38, 0x9f, 0x0b, 0x20, 0x88, 0x09, 0x92, 0x21, 0x88, 0x21, 0x0b, 0x97, 0x81, 0x8f, 0x3b, 0x93, 0x0e, 0x81, 0x44, 0x3c, 0x8d, 0xc9, 0x01, 0x18, 0x08, 0x14, 0x1c, 0x12, 0x8d, @@ -4206,7 +4297,7 @@ static const uint8_t unicode_prop_Bidi_Mirrored_table[173] = { 0x80, 0xb8, 0x80, 0xb8, 0x80, }; -static const uint8_t unicode_prop_Emoji_table[239] = { +static const uint8_t unicode_prop_Emoji_table[238] = { 0xa2, 0x05, 0x04, 0x89, 0xee, 0x03, 0x80, 0x5f, 0x8c, 0x80, 0x8b, 0x80, 0x40, 0xd7, 0x80, 0x95, 0x80, 0xd9, 0x85, 0x8e, 0x81, 0x41, 0x6e, 0x81, @@ -4235,8 +4326,8 @@ static const uint8_t unicode_prop_Emoji_table[239] = { 0x02, 0x05, 0xd5, 0xaf, 0xc5, 0x27, 0x0a, 0x83, 0x89, 0x10, 0x01, 0x10, 0x81, 0x89, 0x40, 0xe2, 0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80, 0x89, 0x80, - 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x88, 0x86, 0xad, - 0x06, 0x87, 0x8d, 0x83, 0x88, 0x86, 0x88, + 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x89, 0x84, 0xb7, + 0x86, 0x8e, 0x81, 0x8a, 0x85, 0x88, }; static const uint8_t unicode_prop_Emoji_Component_table[28] = { @@ -4262,7 +4353,7 @@ static const uint8_t unicode_prop_Emoji_Modifier_Base_table[71] = { 0x10, 0x8c, 0x40, 0xe4, 0x82, 0xa9, 0x88, }; -static const uint8_t unicode_prop_Emoji_Presentation_table[145] = { +static const uint8_t unicode_prop_Emoji_Presentation_table[144] = { 0x60, 0x23, 0x19, 0x81, 0x40, 0xcc, 0x1a, 0x01, 0x80, 0x42, 0x08, 0x81, 0x94, 0x81, 0xb1, 0x8b, 0xaa, 0x80, 0x92, 0x80, 0x8c, 0x07, 0x81, 0x90, @@ -4279,9 +4370,8 @@ static const uint8_t unicode_prop_Emoji_Presentation_table[145] = { 0x80, 0x99, 0x81, 0x8c, 0x80, 0xd5, 0xd4, 0xaf, 0xc5, 0x28, 0x12, 0x0a, 0x1b, 0x8a, 0x0e, 0x88, 0x40, 0xe2, 0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80, - 0x89, 0x80, 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x88, - 0x86, 0xad, 0x06, 0x87, 0x8d, 0x83, 0x88, 0x86, - 0x88, + 0x89, 0x80, 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x89, + 0x84, 0xb7, 0x86, 0x8e, 0x81, 0x8a, 0x85, 0x88, }; static const uint8_t unicode_prop_Extended_Pictographic_table[156] = { @@ -4341,11 +4431,13 @@ typedef enum { UNICODE_PROP_Diacritic, UNICODE_PROP_Extender, UNICODE_PROP_Hex_Digit, + UNICODE_PROP_IDS_Unary_Operator, UNICODE_PROP_IDS_Binary_Operator, UNICODE_PROP_IDS_Trinary_Operator, UNICODE_PROP_Ideographic, UNICODE_PROP_Join_Control, UNICODE_PROP_Logical_Order_Exception, + UNICODE_PROP_Modifier_Combining_Mark, UNICODE_PROP_Noncharacter_Code_Point, UNICODE_PROP_Pattern_Syntax, UNICODE_PROP_Pattern_White_Space, @@ -4382,12 +4474,15 @@ typedef enum { UNICODE_PROP_Grapheme_Base, UNICODE_PROP_Grapheme_Extend, UNICODE_PROP_ID_Continue, + UNICODE_PROP_ID_Compat_Math_Start, + UNICODE_PROP_ID_Compat_Math_Continue, UNICODE_PROP_Lowercase, UNICODE_PROP_Math, UNICODE_PROP_Uppercase, UNICODE_PROP_XID_Continue, UNICODE_PROP_XID_Start, UNICODE_PROP_Cased1, + UNICODE_PROP_InCB, UNICODE_PROP_COUNT, } UnicodePropertyEnum; @@ -4399,11 +4494,13 @@ static const char unicode_prop_name_table[] = "Diacritic,Dia" "\0" "Extender,Ext" "\0" "Hex_Digit,Hex" "\0" + "IDS_Unary_Operator,IDSU" "\0" "IDS_Binary_Operator,IDSB" "\0" "IDS_Trinary_Operator,IDST" "\0" "Ideographic,Ideo" "\0" "Join_Control,Join_C" "\0" "Logical_Order_Exception,LOE" "\0" + "Modifier_Combining_Mark,MCM" "\0" "Noncharacter_Code_Point,NChar" "\0" "Pattern_Syntax,Pat_Syn" "\0" "Pattern_White_Space,Pat_WS" "\0" @@ -4440,6 +4537,8 @@ static const char unicode_prop_name_table[] = "Grapheme_Base,Gr_Base" "\0" "Grapheme_Extend,Gr_Ext" "\0" "ID_Continue,IDC" "\0" + "ID_Compat_Math_Start" "\0" + "ID_Compat_Math_Continue" "\0" "Lowercase,Lower" "\0" "Math" "\0" "Uppercase,Upper" "\0" @@ -4471,11 +4570,13 @@ static const uint8_t * const unicode_prop_table[] = { unicode_prop_Diacritic_table, unicode_prop_Extender_table, unicode_prop_Hex_Digit_table, + unicode_prop_IDS_Unary_Operator_table, unicode_prop_IDS_Binary_Operator_table, unicode_prop_IDS_Trinary_Operator_table, unicode_prop_Ideographic_table, unicode_prop_Join_Control_table, unicode_prop_Logical_Order_Exception_table, + unicode_prop_Modifier_Combining_Mark_table, unicode_prop_Noncharacter_Code_Point_table, unicode_prop_Pattern_Syntax_table, unicode_prop_Pattern_White_Space_table, @@ -4524,11 +4625,13 @@ static const uint16_t unicode_prop_len_table[] = { countof(unicode_prop_Diacritic_table), countof(unicode_prop_Extender_table), countof(unicode_prop_Hex_Digit_table), + countof(unicode_prop_IDS_Unary_Operator_table), countof(unicode_prop_IDS_Binary_Operator_table), countof(unicode_prop_IDS_Trinary_Operator_table), countof(unicode_prop_Ideographic_table), countof(unicode_prop_Join_Control_table), countof(unicode_prop_Logical_Order_Exception_table), + countof(unicode_prop_Modifier_Combining_Mark_table), countof(unicode_prop_Noncharacter_Code_Point_table), countof(unicode_prop_Pattern_Syntax_table), countof(unicode_prop_Pattern_White_Space_table), @@ -4553,5 +4656,3 @@ static const uint16_t unicode_prop_len_table[] = { countof(unicode_prop_Case_Ignorable_table), }; -#endif /* CONFIG_ALL_UNICODE */ -/* 62 tables / 32261 bytes, 5 index / 345 bytes */ diff --git a/src/shared/quickjs/libunicode.c b/src/shared/quickjs/libunicode.c index 482c51944..a621c5235 100644 --- a/src/shared/quickjs/libunicode.c +++ b/src/shared/quickjs/libunicode.c @@ -31,6 +31,7 @@ #include "libunicode.h" #include "libunicode-table.h" +// note: stored as 4 bit tag, not much room left enum { RUN_TYPE_U, RUN_TYPE_L, @@ -189,7 +190,7 @@ int lre_case_conv(uint32_t *res, uint32_t c, int conv_type) return 1; } -static int lre_case_folding_entry(uint32_t c, uint32_t idx, uint32_t v, BOOL is_unicode) +static int lre_case_folding_entry(uint32_t c, uint32_t idx, uint32_t v, bool is_unicode) { uint32_t res[LRE_CC_RES_LEN_MAX]; int len; @@ -215,7 +216,7 @@ static int lre_case_folding_entry(uint32_t c, uint32_t idx, uint32_t v, BOOL is_ c = c - 'a' + 'A'; } else { /* legacy regexp: to upper case if single char >= 128 */ - len = lre_case_conv_entry(res, c, FALSE, idx, v); + len = lre_case_conv_entry(res, c, false, idx, v); if (len == 1 && res[0] >= 128) c = res[0]; } @@ -224,7 +225,7 @@ static int lre_case_folding_entry(uint32_t c, uint32_t idx, uint32_t v, BOOL is_ } /* JS regexp specific rules for case folding */ -int lre_canonicalize(uint32_t c, BOOL is_unicode) +int lre_canonicalize(uint32_t c, bool is_unicode) { if (c < 128) { /* fast case */ @@ -301,7 +302,7 @@ static int get_index_pos(uint32_t *pcode, uint32_t c, return (idx_min + 1) * UNICODE_INDEX_BLOCK_LEN + (v >> 21); } -static BOOL lre_is_in_table(uint32_t c, const uint8_t *table, +static bool lre_is_in_table(uint32_t c, const uint8_t *table, const uint8_t *index_table, int index_table_len) { uint32_t code, b, bit; @@ -310,17 +311,9 @@ static BOOL lre_is_in_table(uint32_t c, const uint8_t *table, pos = get_index_pos(&code, c, index_table, index_table_len); if (pos < 0) - return FALSE; /* outside the table */ + return false; /* outside the table */ p = table + pos; bit = 0; - /* Compressed run length encoding: - 00..3F: 2 packed lengths: 3-bit + 3-bit - 40..5F: 5-bits plus extra byte for length - 60..7F: 5-bits plus 2 extra bytes for length - 80..FF: 7-bit length - lengths must be incremented to get character count - Ranges alternate between false and true return value. - */ for(;;) { b = *p++; if (b < 64) { @@ -344,7 +337,7 @@ static BOOL lre_is_in_table(uint32_t c, const uint8_t *table, } } -BOOL lre_is_cased(uint32_t c) +bool lre_is_cased(uint32_t c) { uint32_t v, code, len; int idx, idx_min, idx_max; @@ -361,7 +354,7 @@ BOOL lre_is_cased(uint32_t c) } else if (c >= code + len) { idx_min = idx + 1; } else { - return TRUE; + return true; } } return lre_is_in_table(c, unicode_prop_Cased1_table, @@ -369,7 +362,7 @@ BOOL lre_is_cased(uint32_t c) sizeof(unicode_prop_Cased1_index) / 3); } -BOOL lre_is_case_ignorable(uint32_t c) +bool lre_is_case_ignorable(uint32_t c) { return lre_is_in_table(c, unicode_prop_Case_Ignorable_table, unicode_prop_Case_Ignorable_index, @@ -537,16 +530,14 @@ int cr_invert(CharRange *cr) return 0; } -#ifdef CONFIG_ALL_UNICODE - -BOOL lre_is_id_start(uint32_t c) +bool lre_is_id_start(uint32_t c) { return lre_is_in_table(c, unicode_prop_ID_Start_table, unicode_prop_ID_Start_index, sizeof(unicode_prop_ID_Start_index) / 3); } -BOOL lre_is_id_continue(uint32_t c) +bool lre_is_id_continue(uint32_t c) { return lre_is_id_start(c) || lre_is_in_table(c, unicode_prop_ID_Continue1_table, @@ -554,6 +545,13 @@ BOOL lre_is_id_continue(uint32_t c) sizeof(unicode_prop_ID_Continue1_index) / 3); } +bool lre_is_white_space(uint32_t c) +{ + return lre_is_in_table(c, unicode_prop_White_Space_table, + unicode_prop_White_Space_index, + sizeof(unicode_prop_White_Space_index) / 3); +} + #define UNICODE_DECOMP_LEN_MAX 18 typedef enum { @@ -761,7 +759,7 @@ static int unicode_decomp_entry(uint32_t *res, uint32_t c, /* return the length of the decomposition (length <= UNICODE_DECOMP_LEN_MAX) or 0 if no decomposition */ -static int unicode_decomp_char(uint32_t *res, uint32_t c, BOOL is_compat1) +static int unicode_decomp_char(uint32_t *res, uint32_t c, bool is_compat1) { uint32_t v, type, is_compat, code, len; int idx_min, idx_max, idx; @@ -837,13 +835,6 @@ static int unicode_get_cc(uint32_t c) if (pos < 0) return 0; p = unicode_cc_table + pos; - /* Compressed run length encoding: - - 2 high order bits are combining class type - - 0:0, 1:230, 2:extra byte linear progression, 3:extra byte - - 00..2F: range length (add 1) - - 30..37: 3-bit range-length + 1 extra byte - - 38..3F: 3-bit range-length + 2 extra byte - */ for(;;) { b = *p++; type = b >> 6; @@ -908,13 +899,6 @@ static void sort_cc(int *buf, int len) buf[k + 1] = ch1; j++; } -#if 0 - printf("cc:"); - for(k = start; k < j; k++) { - printf(" %3d", unicode_get_cc(buf[k])); - } - printf("\n"); -#endif i = j; } } @@ -969,7 +953,7 @@ int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len, void *opaque, DynBufReallocFunc *realloc_func) { int *buf, buf_len, i, p, starter_pos, cc, last_cc, out_len; - BOOL is_compat; + bool is_compat; DynBuf dbuf_s, *dbuf = &dbuf_s; is_compat = n_type >> 1; @@ -1069,14 +1053,14 @@ static int unicode_find_name(const char *name_table, const char *name) /* 'cr' must be initialized and empty. Return 0 if OK, -1 if error, -2 if not found */ int unicode_script(CharRange *cr, - const char *script_name, BOOL is_ext) + const char *script_name, bool is_ext) { int script_idx; const uint8_t *p, *p_end; uint32_t c, c1, b, n, v, v_len, i, type; - CharRange cr1_s, *cr1; - CharRange cr2_s, *cr2 = &cr2_s; - BOOL is_common; + CharRange cr1_s = { 0 }, *cr1 = NULL; + CharRange cr2_s = { 0 }, *cr2 = &cr2_s; + bool is_common; script_idx = unicode_find_name(unicode_script_name_table, script_name); if (script_idx < 0) @@ -1196,15 +1180,6 @@ static int unicode_general_category1(CharRange *cr, uint32_t gc_mask) p = unicode_gc_table; p_end = unicode_gc_table + countof(unicode_gc_table); c = 0; - /* Compressed range encoding: - initial byte: - bits 0..4: category number (special case 31) - bits 5..7: range length (add 1) - special case bits 5..7 == 7: read an extra byte - - 00..7F: range length (add 7 + 1) - - 80..BF: 6-bits plus extra byte for range length (add 7 + 128) - - C0..FF: 6-bits plus 2 extra bytes for range length (add 7 + 128 + 16384) - */ while (p < p_end) { b = *p++; n = b >> 5; @@ -1258,14 +1233,6 @@ static int unicode_prop1(CharRange *cr, int prop_idx) p_end = p + unicode_prop_len_table[prop_idx]; c = 0; bit = 0; - /* Compressed range encoding: - 00..3F: 2 packed lengths: 3-bit + 3-bit - 40..5F: 5-bits plus extra byte for length - 60..7F: 5-bits plus 2 extra bytes for length - 80..FF: 7-bit length - lengths must be incremented to get character count - Ranges alternate between false and true return value. - */ while (p < p_end) { c0 = c; b = *p++; @@ -1413,7 +1380,7 @@ static void cr_sort_and_remove_overlap(CharRange *cr) /* canonicalize a character set using the JS regex case folding rules (see lre_canonicalize()) */ -int cr_regexp_canonicalize(CharRange *cr, BOOL is_unicode) +int cr_regexp_canonicalize(CharRange *cr, bool is_unicode) { CharRange cr_inter, cr_mask, cr_result, cr_sub; uint32_t v, code, len, i, idx, start, end, c, d_start, d_end, d; @@ -1761,42 +1728,6 @@ int unicode_prop(CharRange *cr, const char *prop_name) POP_XOR, POP_END); break; -#if 0 - case UNICODE_PROP_ID_Start: - ret = unicode_prop_ops(cr, - POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl), - POP_PROP, UNICODE_PROP_Other_ID_Start, - POP_UNION, - POP_PROP, UNICODE_PROP_Pattern_Syntax, - POP_PROP, UNICODE_PROP_Pattern_White_Space, - POP_UNION, - POP_INVERT, - POP_INTER, - POP_END); - break; - case UNICODE_PROP_ID_Continue: - ret = unicode_prop_ops(cr, - POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl) | - M(Mn) | M(Mc) | M(Nd) | M(Pc), - POP_PROP, UNICODE_PROP_Other_ID_Start, - POP_UNION, - POP_PROP, UNICODE_PROP_Other_ID_Continue, - POP_UNION, - POP_PROP, UNICODE_PROP_Pattern_Syntax, - POP_PROP, UNICODE_PROP_Pattern_White_Space, - POP_UNION, - POP_INVERT, - POP_INTER, - POP_END); - break; - case UNICODE_PROP_Case_Ignorable: - ret = unicode_prop_ops(cr, - POP_GC, M(Mn) | M(Cf) | M(Lm) | M(Sk), - POP_PROP, UNICODE_PROP_Case_Ignorable1, - POP_XOR, - POP_END); - break; -#else /* we use the existing tables */ case UNICODE_PROP_ID_Continue: ret = unicode_prop_ops(cr, @@ -1805,7 +1736,6 @@ int unicode_prop(CharRange *cr, const char *prop_name) POP_XOR, POP_END); break; -#endif default: if (prop_idx >= countof(unicode_prop_table)) return -2; @@ -1814,99 +1744,3 @@ int unicode_prop(CharRange *cr, const char *prop_name) } return ret; } - -#endif /* CONFIG_ALL_UNICODE */ - -/*---- lre codepoint categorizing functions ----*/ - -#define S UNICODE_C_SPACE -#define D UNICODE_C_DIGIT -#define X UNICODE_C_XDIGIT -#define U UNICODE_C_UPPER -#define L UNICODE_C_LOWER -#define _ UNICODE_C_UNDER -#define d UNICODE_C_DOLLAR - -uint8_t const lre_ctype_bits[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, S, S, S, S, S, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - - S, 0, 0, 0, d, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - X|D, X|D, X|D, X|D, X|D, X|D, X|D, X|D, - X|D, X|D, 0, 0, 0, 0, 0, 0, - - 0, X|U, X|U, X|U, X|U, X|U, X|U, U, - U, U, U, U, U, U, U, U, - U, U, U, U, U, U, U, U, - U, U, U, 0, 0, 0, 0, _, - - 0, X|L, X|L, X|L, X|L, X|L, X|L, L, - L, L, L, L, L, L, L, L, - L, L, L, L, L, L, L, L, - L, L, L, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - - S, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, -}; - -#undef S -#undef D -#undef X -#undef U -#undef L -#undef _ -#undef d - -/* code point ranges for Zs,Zl or Zp property */ -static const uint16_t char_range_s[] = { - 10, - 0x0009, 0x000D + 1, - 0x0020, 0x0020 + 1, - 0x00A0, 0x00A0 + 1, - 0x1680, 0x1680 + 1, - 0x2000, 0x200A + 1, - /* 2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; */ - /* 2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; */ - 0x2028, 0x2029 + 1, - 0x202F, 0x202F + 1, - 0x205F, 0x205F + 1, - 0x3000, 0x3000 + 1, - /* FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; */ - 0xFEFF, 0xFEFF + 1, -}; - -BOOL lre_is_space_non_ascii(uint32_t c) -{ - size_t i, n; - - n = countof(char_range_s); - for(i = 5; i < n; i += 2) { - uint32_t low = char_range_s[i]; - uint32_t high = char_range_s[i + 1]; - if (c < low) - return FALSE; - if (c < high) - return TRUE; - } - return FALSE; -} diff --git a/src/shared/quickjs/libunicode.h b/src/shared/quickjs/libunicode.h index cc2f244c7..8e6f2a01d 100644 --- a/src/shared/quickjs/libunicode.h +++ b/src/shared/quickjs/libunicode.h @@ -24,13 +24,28 @@ #ifndef LIBUNICODE_H #define LIBUNICODE_H -#include +#include +#include +#include -/* define it to include all the unicode tables (40KB larger) */ -#define CONFIG_ALL_UNICODE +#ifdef __cplusplus +extern "C" { +#endif #define LRE_CC_RES_LEN_MAX 3 +typedef enum { + UNICODE_NFC, + UNICODE_NFD, + UNICODE_NFKC, + UNICODE_NFKD, +} UnicodeNormalizationEnum; + +int lre_case_conv(uint32_t *res, uint32_t c, int conv_type); +int lre_canonicalize(uint32_t c, bool is_unicode); +bool lre_is_cased(uint32_t c); +bool lre_is_case_ignorable(uint32_t c); + /* char ranges */ typedef struct { @@ -87,15 +102,11 @@ int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len, const uint32_t *b_pt, int b_len, int op); int cr_invert(CharRange *cr); +int cr_regexp_canonicalize(CharRange *cr, bool is_unicode); -int cr_regexp_canonicalize(CharRange *cr, int is_unicode); - -typedef enum { - UNICODE_NFC, - UNICODE_NFD, - UNICODE_NFKC, - UNICODE_NFKD, -} UnicodeNormalizationEnum; +bool lre_is_id_start(uint32_t c); +bool lre_is_id_continue(uint32_t c); +bool lre_is_white_space(uint32_t c); int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len, UnicodeNormalizationEnum n_type, @@ -103,80 +114,13 @@ int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len, /* Unicode character range functions */ -int unicode_script(CharRange *cr, const char *script_name, int is_ext); +int unicode_script(CharRange *cr, + const char *script_name, bool is_ext); int unicode_general_category(CharRange *cr, const char *gc_name); int unicode_prop(CharRange *cr, const char *prop_name); -int lre_case_conv(uint32_t *res, uint32_t c, int conv_type); -int lre_canonicalize(uint32_t c, int is_unicode); - -/* Code point type categories */ -enum { - UNICODE_C_SPACE = (1 << 0), - UNICODE_C_DIGIT = (1 << 1), - UNICODE_C_UPPER = (1 << 2), - UNICODE_C_LOWER = (1 << 3), - UNICODE_C_UNDER = (1 << 4), - UNICODE_C_DOLLAR = (1 << 5), - UNICODE_C_XDIGIT = (1 << 6), -}; -extern uint8_t const lre_ctype_bits[256]; - -/* zero or non-zero return value */ -int lre_is_cased(uint32_t c); -int lre_is_case_ignorable(uint32_t c); -int lre_is_id_start(uint32_t c); -int lre_is_id_continue(uint32_t c); - -static inline int lre_is_space_byte(uint8_t c) { - return lre_ctype_bits[c] & UNICODE_C_SPACE; -} - -static inline int lre_is_id_start_byte(uint8_t c) { - return lre_ctype_bits[c] & (UNICODE_C_UPPER | UNICODE_C_LOWER | - UNICODE_C_UNDER | UNICODE_C_DOLLAR); -} - -static inline int lre_is_id_continue_byte(uint8_t c) { - return lre_ctype_bits[c] & (UNICODE_C_UPPER | UNICODE_C_LOWER | - UNICODE_C_UNDER | UNICODE_C_DOLLAR | - UNICODE_C_DIGIT); -} - -int lre_is_space_non_ascii(uint32_t c); - -static inline int lre_is_space(uint32_t c) { - if (c < 256) - return lre_is_space_byte(c); - else - return lre_is_space_non_ascii(c); -} - -static inline int lre_js_is_ident_first(uint32_t c) { - if (c < 128) { - return lre_is_id_start_byte(c); - } else { -#ifdef CONFIG_ALL_UNICODE - return lre_is_id_start(c); -#else - return !lre_is_space_non_ascii(c); -#endif - } -} - -static inline int lre_js_is_ident_next(uint32_t c) { - if (c < 128) { - return lre_is_id_continue_byte(c); - } else { - /* ZWNJ and ZWJ are accepted in identifiers */ - if (c >= 0x200C && c <= 0x200D) - return TRUE; -#ifdef CONFIG_ALL_UNICODE - return lre_is_id_continue(c); -#else - return !lre_is_space_non_ascii(c); +#ifdef __cplusplus +} /* extern "C" { */ #endif - } -} #endif /* LIBUNICODE_H */ diff --git a/src/shared/quickjs/list.h b/src/shared/quickjs/list.h index 809831115..b8dd71681 100644 --- a/src/shared/quickjs/list.h +++ b/src/shared/quickjs/list.h @@ -28,6 +28,10 @@ #include #endif +#ifdef __cplusplus +extern "C" { +#endif + struct list_head { struct list_head *prev; struct list_head *next; @@ -96,4 +100,8 @@ static inline int list_empty(struct list_head *el) for(el = (head)->prev, el1 = el->prev; el != (head); \ el = el1, el1 = el->prev) +#ifdef __cplusplus +} /* extern "C" { */ +#endif + #endif /* LIST_H */ diff --git a/src/shared/quickjs/quickjs-atom.h b/src/shared/quickjs/quickjs-atom.h index f4d5838d4..358fe2306 100644 --- a/src/shared/quickjs/quickjs-atom.h +++ b/src/shared/quickjs/quickjs-atom.h @@ -78,9 +78,9 @@ DEF(await, "await") /* empty string */ DEF(empty_string, "") /* identifiers */ +DEF(keys, "keys") +DEF(size, "size") DEF(length, "length") -DEF(fileName, "fileName") -DEF(lineNumber, "lineNumber") DEF(message, "message") DEF(cause, "cause") DEF(errors, "errors") @@ -172,19 +172,11 @@ DEF(status, "status") DEF(reason, "reason") DEF(globalThis, "globalThis") DEF(bigint, "bigint") -#ifdef CONFIG_BIGNUM -DEF(bigfloat, "bigfloat") -DEF(bigdecimal, "bigdecimal") -DEF(roundingMode, "roundingMode") -DEF(maximumSignificantDigits, "maximumSignificantDigits") -DEF(maximumFractionDigits, "maximumFractionDigits") -#endif -/* the following 3 atoms are only used with CONFIG_ATOMICS */ DEF(not_equal, "not-equal") DEF(timed_out, "timed-out") DEF(ok, "ok") -/* */ DEF(toJSON, "toJSON") +DEF(maxByteLength, "maxByteLength") /* class names */ DEF(Object, "Object") DEF(Array, "Array") @@ -213,21 +205,20 @@ DEF(Int32Array, "Int32Array") DEF(Uint32Array, "Uint32Array") DEF(BigInt64Array, "BigInt64Array") DEF(BigUint64Array, "BigUint64Array") +DEF(Float16Array, "Float16Array") DEF(Float32Array, "Float32Array") DEF(Float64Array, "Float64Array") DEF(DataView, "DataView") DEF(BigInt, "BigInt") -#ifdef CONFIG_BIGNUM -DEF(BigFloat, "BigFloat") -DEF(BigFloatEnv, "BigFloatEnv") -DEF(BigDecimal, "BigDecimal") -DEF(OperatorSet, "OperatorSet") -DEF(Operators, "Operators") -#endif +DEF(WeakRef, "WeakRef") +DEF(FinalizationRegistry, "FinalizationRegistry") DEF(Map, "Map") DEF(Set, "Set") /* Map + 1 */ DEF(WeakMap, "WeakMap") /* Map + 2 */ DEF(WeakSet, "WeakSet") /* Map + 3 */ +DEF(Iterator, "Iterator") +DEF(IteratorHelper, "Iterator Helper") +DEF(IteratorWrap, "Iterator Wrap") DEF(Map_Iterator, "Map Iterator") DEF(Set_Iterator, "Set Iterator") DEF(Array_Iterator, "Array Iterator") @@ -250,6 +241,7 @@ DEF(SyntaxError, "SyntaxError") DEF(TypeError, "TypeError") DEF(URIError, "URIError") DEF(InternalError, "InternalError") +DEF(CallSite, "CallSite") /* private symbols */ DEF(Private_brand, "") /* symbols */ @@ -266,8 +258,5 @@ DEF(Symbol_hasInstance, "Symbol.hasInstance") DEF(Symbol_species, "Symbol.species") DEF(Symbol_unscopables, "Symbol.unscopables") DEF(Symbol_asyncIterator, "Symbol.asyncIterator") -#ifdef CONFIG_BIGNUM -DEF(Symbol_operatorSet, "Symbol.operatorSet") -#endif #endif /* DEF */ diff --git a/src/shared/quickjs/quickjs-c-atomics.h b/src/shared/quickjs/quickjs-c-atomics.h new file mode 100644 index 000000000..8fc6b7203 --- /dev/null +++ b/src/shared/quickjs/quickjs-c-atomics.h @@ -0,0 +1,54 @@ +/* + * QuickJS C atomics definitions + * + * Copyright (c) 2023 Marcin Kolny + * + * 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. + */ + +#if (defined(__GNUC__) || defined(__GNUG__)) && !defined(__clang__) + // Use GCC builtins for version < 4.9 +# if((__GNUC__ << 16) + __GNUC_MINOR__ < ((4) << 16) + 9) +# define GCC_BUILTIN_ATOMICS +# endif +#endif + +#ifdef GCC_BUILTIN_ATOMICS +#define atomic_fetch_add(obj, arg) \ + __atomic_fetch_add(obj, arg, __ATOMIC_SEQ_CST) +#define atomic_compare_exchange_strong(obj, expected, desired) \ + __atomic_compare_exchange_n(obj, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) +#define atomic_exchange(obj, desired) \ + __atomic_exchange_n (obj, desired, __ATOMIC_SEQ_CST) +#define atomic_load(obj) \ + __atomic_load_n(obj, __ATOMIC_SEQ_CST) +#define atomic_store(obj, desired) \ + __atomic_store_n(obj, desired, __ATOMIC_SEQ_CST) +#define atomic_fetch_or(obj, arg) \ + __atomic_fetch_or(obj, arg, __ATOMIC_SEQ_CST) +#define atomic_fetch_xor(obj, arg) \ + __atomic_fetch_xor(obj, arg, __ATOMIC_SEQ_CST) +#define atomic_fetch_and(obj, arg) \ + __atomic_fetch_and(obj, arg, __ATOMIC_SEQ_CST) +#define atomic_fetch_sub(obj, arg) \ + __atomic_fetch_sub(obj, arg, __ATOMIC_SEQ_CST) +#define _Atomic +#else +#include +#endif diff --git a/src/shared/quickjs/quickjs-opcode.h b/src/shared/quickjs/quickjs-opcode.h index 1e1821259..fb5394c58 100644 --- a/src/shared/quickjs/quickjs-opcode.h +++ b/src/shared/quickjs/quickjs-opcode.h @@ -44,6 +44,7 @@ FMT(loc) FMT(arg) FMT(var_ref) FMT(u32) +FMT(u32x2) FMT(i32) FMT(const) FMT(label) @@ -110,6 +111,7 @@ DEF( return, 1, 1, 0, none) DEF( return_undef, 1, 0, 0, none) DEF(check_ctor_return, 1, 1, 2, none) DEF( check_ctor, 1, 0, 0, none) +DEF( init_ctor, 1, 0, 1, none) 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) @@ -135,9 +137,12 @@ DEF( put_ref_value, 1, 3, 0, none) DEF( define_var, 6, 0, 0, atom_u8) DEF(check_define_var, 6, 0, 0, atom_u8) DEF( define_func, 6, 1, 0, atom_u8) + +// order matters, see IC counterparts DEF( get_field, 5, 1, 1, atom) DEF( get_field2, 5, 1, 2, atom) DEF( put_field, 5, 2, 0, atom) + DEF( get_private_field, 1, 2, 1, none) /* obj prop -> value */ DEF( put_private_field, 1, 3, 0, none) /* obj value prop -> */ DEF(define_private_field, 1, 3, 1, none) /* obj prop value -> obj */ @@ -172,7 +177,6 @@ DEF(set_loc_uninitialized, 3, 0, 0, loc) DEF( get_loc_check, 3, 0, 1, loc) DEF( put_loc_check, 3, 1, 0, loc) /* must come after get_loc_check */ DEF( put_loc_check_init, 3, 1, 0, loc) -DEF(get_loc_checkthis, 3, 0, 1, loc) DEF(get_var_ref_check, 3, 0, 1, var_ref) DEF(put_var_ref_check, 3, 1, 0, var_ref) /* must come after get_var_ref_check */ DEF(put_var_ref_check_init, 3, 1, 0, var_ref) @@ -234,15 +238,20 @@ DEF( typeof, 1, 1, 1, none) DEF( delete, 1, 2, 1, none) DEF( delete_var, 5, 0, 1, atom) +/* warning: order matters (see js_parse_assign_expr) */ DEF( mul, 1, 2, 1, none) DEF( div, 1, 2, 1, none) DEF( mod, 1, 2, 1, none) DEF( add, 1, 2, 1, none) DEF( sub, 1, 2, 1, none) -DEF( pow, 1, 2, 1, none) DEF( shl, 1, 2, 1, none) DEF( sar, 1, 2, 1, none) DEF( shr, 1, 2, 1, none) +DEF( and, 1, 2, 1, none) +DEF( xor, 1, 2, 1, none) +DEF( or, 1, 2, 1, none) +DEF( pow, 1, 2, 1, none) + DEF( lt, 1, 2, 1, none) DEF( lte, 1, 2, 1, none) DEF( gt, 1, 2, 1, none) @@ -253,15 +262,8 @@ DEF( eq, 1, 2, 1, none) DEF( neq, 1, 2, 1, none) DEF( strict_eq, 1, 2, 1, none) DEF( strict_neq, 1, 2, 1, none) -DEF( and, 1, 2, 1, none) -DEF( xor, 1, 2, 1, none) -DEF( or, 1, 2, 1, none) DEF(is_undefined_or_null, 1, 1, 1, none) DEF( private_in, 1, 2, 1, none) -#ifdef CONFIG_BIGNUM -DEF( mul_pow10, 1, 2, 1, none) -DEF( math_mod, 1, 2, 1, none) -#endif /* must be the last non short and non temporary opcode */ DEF( nop, 1, 0, 0, none) @@ -272,8 +274,6 @@ def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */ def( label, 5, 0, 0, label) /* emitted in phase 1, removed in phase 3 */ -/* the following opcodes must be in the same order as the 'with_x' and - get_var_undef, get_var and put_var opcodes */ def(scope_get_var_undef, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ def( scope_get_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ def( scope_put_var, 7, 1, 0, atom_u16) /* emitted in phase 1, removed in phase 2 */ @@ -281,7 +281,6 @@ def(scope_delete_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase def( scope_make_ref, 11, 0, 2, atom_label_u16) /* emitted in phase 1, removed in phase 2 */ def( scope_get_ref, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */ def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */ -def(scope_get_var_checkthis, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2, only used to return 'this' in derived class constructors */ def(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */ def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */ def(scope_put_private_field, 7, 2, 0, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */ @@ -290,9 +289,8 @@ def(get_field_opt_chain, 5, 1, 1, atom) /* emitted in phase 1, removed in phase def(get_array_el_opt_chain, 1, 2, 1, none) /* emitted in phase 1, removed in phase 2 */ def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */ -def( line_num, 5, 0, 0, u32) /* emitted in phase 1, removed in phase 3 */ +def( source_loc, 9, 0, 0, u32x2) /* emitted in phase 1, removed in phase 3 */ -#if SHORT_OPCODES DEF( push_minus1, 1, 0, 1, none_int) DEF( push_0, 1, 0, 1, none_int) DEF( push_1, 1, 0, 1, none_int) @@ -312,6 +310,7 @@ DEF( get_loc8, 2, 0, 1, loc8) DEF( put_loc8, 2, 1, 0, loc8) DEF( set_loc8, 2, 1, 1, loc8) +DEF( get_loc0_loc1, 1, 0, 2, none_loc) DEF( get_loc0, 1, 0, 1, none_loc) DEF( get_loc1, 1, 0, 1, none_loc) DEF( get_loc2, 1, 0, 1, none_loc) @@ -365,7 +364,11 @@ DEF( is_undefined, 1, 1, 1, none) DEF( is_null, 1, 1, 1, none) DEF(typeof_is_undefined, 1, 1, 1, none) DEF( typeof_is_function, 1, 1, 1, none) -#endif + +// order matters, see non-IC counterparts +DEF( get_field_ic, 5, 1, 1, none) +DEF( get_field2_ic, 5, 1, 2, none) +DEF( put_field_ic, 5, 2, 0, none) #undef DEF #undef def diff --git a/src/shared/quickjs/quickjs.c b/src/shared/quickjs/quickjs.c index 3bafe6948..35967d9a4 100644 --- a/src/shared/quickjs/quickjs.c +++ b/src/shared/quickjs/quickjs.c @@ -1,8 +1,10 @@ /* * QuickJS Javascript Engine * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon + * Copyright (c) 2017-2024 Fabrice Bellard + * Copyright (c) 2017-2024 Charlie Gordon + * Copyright (c) 2023-2025 Ben Noordhuis + * Copyright (c) 2023-2025 Saúl Ibarra Corretgé * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,25 +30,21 @@ #include #include #include -#ifndef _MSC_VER +#if !defined(_MSC_VER) #include +#if defined(_WIN32) +#include +#include +#endif #endif #include #include #include -#if defined(__APPLE__) -#include -#elif defined(__linux__) -#include -#elif defined(__FreeBSD__) -#include -#endif #ifdef _MSC_VER #include #include #endif - #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \ || defined(__APPLE__) #include @@ -58,11 +56,8 @@ #include "list.h" #include "quickjs.h" #include "libregexp.h" -#include "libunicode.h" #include "libbf.h" -#define OPTIMIZE 0 -#define SHORT_OPCODES 1 #if defined(EMSCRIPTEN) || defined(_MSC_VER) #define DIRECT_DISPATCH 0 #else @@ -75,59 +70,43 @@ #define MALLOC_OVERHEAD 8 #endif -#if !defined(_WIN32) -/* define it if printf uses the RNDN rounding mode instead of RNDNA */ -#define CONFIG_PRINTF_RNDN +#if defined(__NEWLIB__) +#define NO_TM_GMTOFF #endif -/* define to include Atomics.* operations which depend on the OS - threads */ -#if !defined(EMSCRIPTEN) && !defined(_MSC_VER) +// atomic_store etc. are completely busted in recent versions of tcc; +// somehow the compiler forgets to load |ptr| into %rdi when calling +// the __atomic_*() helpers in its lib/stdatomic.c and lib/atomic.S +#if !defined(__TINYC__) && !defined(EMSCRIPTEN) && !defined(__wasi__) && !__STDC_NO_ATOMICS__ +#include "quickjs-c-atomics.h" #define CONFIG_ATOMICS #endif -#if !defined(EMSCRIPTEN) -/* enable stack limitation */ -#define CONFIG_STACK_CHECK +#ifndef __GNUC__ +#define __extension__ #endif -/* dump object free */ -//#define DUMP_FREE -//#define DUMP_CLOSURE -/* dump the bytecode of the compiled functions: combination of bits - 1: dump pass 3 final byte code - 2: dump pass 2 code - 4: dump pass 1 code - 8: dump stdlib functions - 16: dump bytecode in hex - 32: dump line number table - 64: dump compute_stack_size - */ -//#define DUMP_BYTECODE (1) -/* dump the occurence of the automatic GC */ -//#define DUMP_GC -/* dump objects freed by the garbage collector */ -//#define DUMP_GC_FREE -/* dump objects leaking when freeing the runtime */ -//#define DUMP_LEAKS 1 -/* dump memory usage before running the garbage collector */ -//#define DUMP_MEM -//#define DUMP_OBJECTS /* dump objects in JS_FreeContext */ -//#define DUMP_ATOMS /* dump atoms in JS_FreeContext */ -//#define DUMP_SHAPES /* dump shapes in JS_FreeContext */ -//#define DUMP_MODULE_RESOLVE -//#define DUMP_PROMISE -//#define DUMP_READ_OBJECT - -/* test the GC by forcing it before each object allocation */ -//#define FORCE_GC_AT_MALLOC - -#ifdef CONFIG_ATOMICS -#include -#include -#include +#ifndef NDEBUG +#define ENABLE_DUMPS #endif +//#define FORCE_GC_AT_MALLOC /* test the GC by forcing it before each object allocation */ + +#define check_dump_flag(rt, flag) ((rt->dump_flags & (flag +0)) == (flag +0)) + +#define STRINGIFY_(x) #x +#define STRINGIFY(x) STRINGIFY_(x) + +#define QJS_VERSION_STRING \ + STRINGIFY(QJS_VERSION_MAJOR) "." STRINGIFY(QJS_VERSION_MINOR) "." STRINGIFY(QJS_VERSION_PATCH) QJS_VERSION_SUFFIX + +const char* JS_GetVersion(void) { + return QJS_VERSION_STRING; +} + +#undef STRINFIGY_ +#undef STRINGIFY + static double safe_strtod(const char *restrict nptr, char **restrict endptr) { #if defined(_MSC_VER) || defined(__MINGW32__) @@ -178,20 +157,18 @@ enum { JS_CLASS_UINT32_ARRAY, /* u.array (typed_array) */ JS_CLASS_BIG_INT64_ARRAY, /* u.array (typed_array) */ JS_CLASS_BIG_UINT64_ARRAY, /* u.array (typed_array) */ + JS_CLASS_FLOAT16_ARRAY, /* u.array (typed_array) */ JS_CLASS_FLOAT32_ARRAY, /* u.array (typed_array) */ JS_CLASS_FLOAT64_ARRAY, /* u.array (typed_array) */ JS_CLASS_DATAVIEW, /* u.typed_array */ JS_CLASS_BIG_INT, /* u.object_data */ -#ifdef CONFIG_BIGNUM - JS_CLASS_BIG_FLOAT, /* u.object_data */ - JS_CLASS_FLOAT_ENV, /* u.float_env */ - JS_CLASS_BIG_DECIMAL, /* u.object_data */ - JS_CLASS_OPERATOR_SET, /* u.operator_set */ -#endif JS_CLASS_MAP, /* u.map_state */ JS_CLASS_SET, /* u.map_state */ JS_CLASS_WEAKMAP, /* u.map_state */ JS_CLASS_WEAKSET, /* u.map_state */ + JS_CLASS_ITERATOR, + JS_CLASS_ITERATOR_HELPER, /* u.iterator_helper_data */ + JS_CLASS_ITERATOR_WRAP, /* u.iterator_wrap_data */ JS_CLASS_MAP_ITERATOR, /* u.map_iterator_data */ JS_CLASS_SET_ITERATOR, /* u.map_iterator_data */ JS_CLASS_ARRAY_ITERATOR, /* u.array_iterator_data */ @@ -208,6 +185,9 @@ enum { JS_CLASS_ASYNC_FROM_SYNC_ITERATOR, /* u.async_from_sync_iterator_data */ JS_CLASS_ASYNC_GENERATOR_FUNCTION, /* u.func */ JS_CLASS_ASYNC_GENERATOR, /* u.async_generator_data */ + JS_CLASS_WEAK_REF, + JS_CLASS_FINALIZATION_REGISTRY, + JS_CLASS_CALL_SITE, JS_CLASS_INIT_COUNT, /* last entry for predefined classes */ }; @@ -228,47 +208,39 @@ typedef enum JSErrorEnum { JS_AGGREGATE_ERROR, JS_NATIVE_ERROR_COUNT, /* number of different NativeError objects */ + JS_PLAIN_ERROR = JS_NATIVE_ERROR_COUNT } JSErrorEnum; #define JS_MAX_LOCAL_VARS 65535 #define JS_STACK_SIZE_MAX 65534 #define JS_STRING_LEN_MAX ((1 << 30) - 1) -#ifdef __GNUC__ #define __exception __attribute__((warn_unused_result)) -#else -#define __exception -#endif typedef struct JSShape JSShape; typedef struct JSString JSString; typedef struct JSString JSAtomStruct; +#define JS_VALUE_GET_STRING(v) ((JSString *)JS_VALUE_GET_PTR(v)) + typedef enum { JS_GC_PHASE_NONE, JS_GC_PHASE_DECREF, JS_GC_PHASE_REMOVE_CYCLES, } JSGCPhaseEnum; -typedef enum OPCodeEnum OPCodeEnum; +typedef struct JSMallocState { + size_t malloc_count; + size_t malloc_size; + size_t malloc_limit; + void *opaque; /* user opaque */ +} JSMallocState; -/* function pointers are used for numeric operations so that it is - possible to remove some numeric types */ -typedef struct { - JSValue (*to_string)(JSContext *ctx, JSValueConst val); - JSValue (*from_string)(JSContext *ctx, const char *buf, - int radix, int flags, slimb_t *pexponent); - int (*unary_arith)(JSContext *ctx, - JSValue *pres, OPCodeEnum op, JSValue op1); - int (*binary_arith)(JSContext *ctx, OPCodeEnum op, - JSValue *pres, JSValue op1, JSValue op2); - int (*compare)(JSContext *ctx, OPCodeEnum op, - JSValue op1, JSValue op2); - /* only for bigfloat: */ - JSValue (*mul_pow10_to_float64)(JSContext *ctx, const bf_t *a, - int64_t exponent); - int (*mul_pow10)(JSContext *ctx, JSValue *sp); -} JSNumericOperations; +typedef struct JSRuntimeFinalizerState { + struct JSRuntimeFinalizerState *next; + JSRuntimeFinalizer *finalizer; + void *arg; +} JSRuntimeFinalizerState; struct JSRuntime { JSMallocFunctions mf; @@ -283,6 +255,7 @@ struct JSRuntime { JSAtomStruct **atom_array; int atom_free_index; /* 0 = none */ + JSClassID js_class_id_alloc; /* counter for user defined classes */ int class_count; /* size of class_array */ JSClass *class_array; @@ -295,7 +268,7 @@ struct JSRuntime { struct list_head tmp_obj_list; /* used during GC */ JSGCPhaseEnum gc_phase : 8; size_t malloc_gc_threshold; -#ifdef DUMP_LEAKS +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS struct list_head string_list; /* list of JSString.link */ #endif /* stack limitation */ @@ -305,7 +278,11 @@ struct JSRuntime { JSValue current_exception; /* true if inside an out of memory error, to avoid recursing */ - BOOL in_out_of_memory : 8; + bool in_out_of_memory; + /* and likewise if inside Error.prepareStackTrace() */ + bool in_prepare_stack_trace; + /* true if inside JS_FreeRuntime */ + bool in_free; struct JSStackFrame *current_stack_frame; @@ -323,23 +300,21 @@ struct JSRuntime { /* timestamp for internal use in module evaluation */ int64_t module_async_evaluation_next_timestamp; - BOOL can_block : 8; /* TRUE if Atomics.wait can block */ /* used to allocate, free and clone SharedArrayBuffers */ JSSharedArrayBufferFunctions sab_funcs; + bool can_block; /* true if Atomics.wait can block */ + uint32_t dump_flags : 24; + /* Shape hash table */ int shape_hash_bits; int shape_hash_size; int shape_hash_count; /* number of hashed shapes */ JSShape **shape_hash; bf_context_t bf_ctx; - JSNumericOperations bigint_ops; -#ifdef CONFIG_BIGNUM - JSNumericOperations bigfloat_ops; - JSNumericOperations bigdecimal_ops; - uint32_t operator_count; -#endif void *user_opaque; + void *libc_opaque; + JSRuntimeFinalizerState *finalizers; }; struct JSClass { @@ -352,21 +327,16 @@ struct JSClass { const JSClassExoticMethods *exotic; }; -#define JS_MODE_STRICT (1 << 0) -#define JS_MODE_STRIP (1 << 1) -#define JS_MODE_MATH (1 << 2) -#define JS_MODE_ASYNC (1 << 3) /* async function */ - typedef struct JSStackFrame { struct JSStackFrame *prev_frame; /* NULL if first stack frame */ JSValue cur_func; /* current function, JS_UNDEFINED if the frame is detached */ JSValue *arg_buf; /* arguments */ JSValue *var_buf; /* variables */ - struct list_head var_ref_list; /* list of JSVarRef.var_ref_link */ - const uint8_t *cur_pc; /* only used in bytecode functions : PC of the + struct list_head var_ref_list; /* list of JSVarRef.link */ + uint8_t *cur_pc; /* only used in bytecode functions : PC of the instruction after the call */ - int arg_count; - int js_mode; /* for C functions, only JS_MODE_MATH may be set */ + uint32_t arg_count : 31; + uint32_t is_strict_mode : 1; /* only used in generators. Current stack pointer value. NULL if the function is running. */ JSValue *cur_sp; @@ -399,6 +369,11 @@ typedef struct JSVarRef { struct { int __gc_ref_count; /* corresponds to header.ref_count */ uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */ + + /* 0 : the JSVarRef is on the stack. header.link is an element + of JSStackFrame.var_ref_list. + 1 : the JSVarRef is detached. header.link has the normal meanning + */ uint8_t is_detached : 1; uint8_t is_arg : 1; uint16_t var_idx; /* index of the corresponding function variable on @@ -407,34 +382,19 @@ typedef struct JSVarRef { }; JSValue *pvalue; /* pointer to the value, either on the stack or to 'value' */ - union { - JSValue value; /* used when is_detached = TRUE */ - struct { - struct list_head var_ref_link; /* JSStackFrame.var_ref_list list */ - struct JSAsyncFunctionState *async_func; /* != NULL if async stack frame */ - }; /* used when is_detached = FALSE */ - }; + JSValue value; /* used when the variable is no longer on the stack */ } JSVarRef; -/* the same structure is used for big integers and big floats. Big - integers are never infinite or NaNs */ -typedef struct JSBigFloat { - JSRefCountHeader header; /* must come first, 32-bit */ - bf_t num; -} JSBigFloat; - -#ifdef CONFIG_BIGNUM -typedef struct JSFloatEnv { - limb_t prec; - bf_flags_t flags; - unsigned int status; -} JSFloatEnv; +typedef struct JSRefCountHeader { + int ref_count; +} JSRefCountHeader; -typedef struct JSBigDecimal { +/* the same structure is used for big integers. + Big integers are never infinite or NaNs */ +typedef struct JSBigInt { JSRefCountHeader header; /* must come first, 32-bit */ - bfdec_t num; -} JSBigDecimal; -#endif + bf_t num; +} JSBigInt; typedef enum { JS_AUTOINIT_ID_PROTOTYPE, @@ -463,6 +423,11 @@ struct JSContext { JSValue regexp_ctor; JSValue promise_ctor; JSValue native_error_proto[JS_NATIVE_ERROR_COUNT]; + JSValue error_ctor; + JSValue error_back_trace; + JSValue error_prepare_stack; + int error_stack_trace_limit; + JSValue iterator_ctor; JSValue iterator_proto; JSValue async_iterator_proto; JSValue array_proto_values; @@ -472,23 +437,20 @@ struct JSContext { JSValue global_obj; /* global object */ JSValue global_var_obj; /* contains the global let/const definitions */ + double time_origin; + uint64_t random_state; bf_context_t *bf_ctx; /* points to rt->bf_ctx, shared by all contexts */ -#ifdef CONFIG_BIGNUM - JSFloatEnv fp_env; /* global FP environment */ - BOOL bignum_ext : 8; /* enable math mode */ - BOOL allow_operator_overloading : 8; -#endif /* when the counter reaches zero, JSRutime.interrupt_handler is called */ int interrupt_counter; struct list_head loaded_modules; /* list of JSModuleDef.link */ /* if NULL, RegExp compilation is not supported */ - JSValue (*compile_regexp)(JSContext *ctx, JSValueConst pattern, - JSValueConst flags); + JSValue (*compile_regexp)(JSContext *ctx, JSValue pattern, + JSValue flags); /* if NULL, eval is not supported */ - JSValue (*eval_internal)(JSContext *ctx, JSValueConst this_obj, + JSValue (*eval_internal)(JSContext *ctx, JSValue this_obj, const char *input, size_t input_len, const char *filename, int line, int flags, int scope_idx); void *user_opaque; @@ -504,6 +466,22 @@ typedef union JSFloat64Union { uint32_t u32[2]; } JSFloat64Union; +typedef enum { + JS_WEAK_REF_KIND_MAP, + JS_WEAK_REF_KIND_WEAK_REF, + JS_WEAK_REF_KIND_FINALIZATION_REGISTRY_ENTRY, +} JSWeakRefKindEnum; + +typedef struct JSWeakRefRecord { + JSWeakRefKindEnum kind; + struct JSWeakRefRecord *next_weak_ref; + union { + struct JSMapRecord *map_record; + struct JSWeakRefData *weak_ref_data; + struct JSFinRecEntry *fin_rec_entry; + } u; +} JSWeakRefRecord; + enum { JS_ATOM_TYPE_STRING = 1, JS_ATOM_TYPE_GLOBAL_SYMBOL, @@ -534,12 +512,13 @@ struct JSString { uint32_t hash : 30; uint8_t atom_type : 2; /* != 0 if atom, JS_ATOM_TYPE_x */ uint32_t hash_next; /* atom_index for JS_ATOM_TYPE_SYMBOL */ -#ifdef DUMP_LEAKS + JSWeakRefRecord *first_weak_ref; +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS struct list_head link; /* string list */ #endif union { - uint8_t str8[0]; /* 8 bit strings will get an extra null terminator */ - uint16_t str16[0]; + __extension__ uint8_t str8[0]; /* 8 bit strings will get an extra null terminator */ + __extension__ uint16_t str16[0]; } u; }; @@ -550,7 +529,7 @@ typedef struct JSClosureVar { uint8_t is_lexical : 1; uint8_t var_kind : 4; /* see JSVarKindEnum */ /* 8 bits available */ - uint16_t var_idx; /* is_local = TRUE: index to a normal variable of the + 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; @@ -622,9 +601,82 @@ typedef enum JSFunctionKindEnum { JS_FUNC_ASYNC_GENERATOR = (JS_FUNC_GENERATOR | JS_FUNC_ASYNC), } JSFunctionKindEnum; +#define IC_CACHE_ITEM_CAPACITY 4 + +typedef struct JSInlineCacheRingSlot { + /* SoA for space optimization: 56 bytes */ + JSShape* shape[IC_CACHE_ITEM_CAPACITY]; + uint32_t prop_offset[IC_CACHE_ITEM_CAPACITY]; + JSAtom atom; + uint8_t index; +} JSInlineCacheRingSlot; + +typedef struct JSInlineCacheHashSlot { + JSAtom atom; + uint32_t index; + struct JSInlineCacheHashSlot *next; +} JSInlineCacheHashSlot; + +typedef struct JSInlineCache { + uint32_t count; + uint32_t capacity; + uint32_t hash_bits; + JSInlineCacheHashSlot **hash; + JSInlineCacheRingSlot *cache; +} JSInlineCache; + +#define INLINE_CACHE_MISS ((uint32_t)-1) // sentinel + +// This is a struct so we don't tie up two argument registers in calls to +// JS_GetPropertyInternal2 and JS_SetPropertyInternal2 in the common case +// where there is no IC and therefore no offset to update. +typedef struct JSInlineCacheUpdate { + JSInlineCache *ic; + uint32_t offset; +} JSInlineCacheUpdate; + +static JSInlineCache *init_ic(JSContext *ctx); +static int rebuild_ic(JSContext *ctx, JSInlineCache *ic); +static int resize_ic_hash(JSContext *ctx, JSInlineCache *ic); +static int free_ic(JSRuntime *rt, JSInlineCache *ic); +static void add_ic_slot(JSContext *ctx, JSInlineCacheUpdate *icu, + JSAtom atom, JSObject *object, uint32_t prop_offset); + +static uint32_t get_ic_prop_offset(const JSInlineCacheUpdate *icu, + JSShape *shape) +{ + uint32_t i, cache_offset = icu->offset; + JSInlineCache *ic = icu->ic; + JSInlineCacheRingSlot *cr; + JSShape *shape_slot; + assert(cache_offset < ic->capacity); + cr = ic->cache + cache_offset; + i = cr->index; + for (;;) { + shape_slot = *(cr->shape + i); + if (likely(shape_slot == shape)) { + cr->index = i; + return cr->prop_offset[i]; + } + + i = (i + 1) % countof(cr->shape); + if (unlikely(i == cr->index)) { + break; + } + } + + return INLINE_CACHE_MISS; +} + +static force_inline JSAtom get_ic_atom(JSInlineCache *ic, uint32_t cache_offset) +{ + assert(cache_offset < ic->capacity); + return ic->cache[cache_offset].atom; +} + typedef struct JSFunctionBytecode { JSGCObjectHeader header; /* must come first */ - uint8_t js_mode; + uint8_t is_strict_mode : 1; uint8_t has_prototype : 1; /* true if a prototype field is necessary */ uint8_t has_simple_parameter_list : 1; uint8_t is_derived_class_constructor : 1; @@ -635,11 +687,8 @@ typedef struct JSFunctionBytecode { uint8_t super_call_allowed : 1; uint8_t super_allowed : 1; uint8_t arguments_allowed : 1; - uint8_t has_debug : 1; uint8_t backtrace_barrier : 1; /* stop backtrace on this function */ - uint8_t read_only_bytecode : 1; - uint8_t is_direct_or_indirect_eval : 1; /* used by JS_GetScriptOrModuleName() */ - /* XXX: 10 bits available */ + /* XXX: 5 bits available */ uint8_t *byte_code_buf; /* (self pointer) */ int byte_code_len; JSAtom func_name; @@ -653,22 +702,21 @@ typedef struct JSFunctionBytecode { JSValue *cpool; /* constant pool (self pointer) */ int cpool_count; int closure_var_count; - struct { - /* debug info, move to separate structure to save memory? */ - JSAtom filename; - int line_num; - int source_len; - int pc2line_len; - uint8_t *pc2line_buf; - char *source; - } debug; + JSInlineCache *ic; + JSAtom filename; + int line_num; + int col_num; + int source_len; + int pc2line_len; + uint8_t *pc2line_buf; + char *source; } JSFunctionBytecode; typedef struct JSBoundFunction { JSValue func_obj; JSValue this_val; int argc; - JSValue argv[0]; + JSValue argv[]; } JSBoundFunction; typedef enum JSIteratorKindEnum { @@ -677,13 +725,23 @@ typedef enum JSIteratorKindEnum { JS_ITERATOR_KIND_KEY_AND_VALUE, } JSIteratorKindEnum; +typedef enum JSIteratorHelperKindEnum { + JS_ITERATOR_HELPER_KIND_DROP, + JS_ITERATOR_HELPER_KIND_EVERY, + JS_ITERATOR_HELPER_KIND_FILTER, + JS_ITERATOR_HELPER_KIND_FIND, + JS_ITERATOR_HELPER_KIND_FLAT_MAP, + JS_ITERATOR_HELPER_KIND_FOR_EACH, + JS_ITERATOR_HELPER_KIND_MAP, + JS_ITERATOR_HELPER_KIND_SOME, + JS_ITERATOR_HELPER_KIND_TAKE, +} JSIteratorHelperKindEnum; + typedef struct JSForInIterator { JSValue obj; + bool is_array; + uint32_t array_length; uint32_t idx; - uint32_t atom_count; - uint8_t in_prototype_chain; - uint8_t is_array; - JSPropertyEnum *tab_atom; /* is_array = FALSE */ } JSForInIterator; typedef struct JSRegExp { @@ -700,6 +758,7 @@ typedef struct JSProxyData { typedef struct JSArrayBuffer { int byte_length; /* 0 if detached */ + int max_byte_length; /* -1 if not resizable; >= byte_length otherwise */ uint8_t detached; uint8_t shared; /* if shared, the array buffer cannot be detached */ uint8_t *data; /* NULL if detached */ @@ -712,67 +771,26 @@ typedef struct JSTypedArray { struct list_head link; /* link to arraybuffer */ JSObject *obj; /* back pointer to the TypedArray/DataView object */ JSObject *buffer; /* based array buffer */ - uint32_t offset; /* offset in the array buffer */ - uint32_t length; /* length in the array buffer */ + uint32_t offset; /* byte offset in the array buffer */ + uint32_t length; /* byte length in the array buffer */ + bool track_rab; /* auto-track length of backing array buffer */ } JSTypedArray; typedef struct JSAsyncFunctionState { - JSGCObjectHeader header; - JSValue this_val; /* 'this' argument */ + JSValue this_val; /* 'this' generator argument */ int argc; /* number of function arguments */ - BOOL throw_flag; /* used to throw an exception in JS_CallInternal() */ - BOOL is_completed; /* TRUE if the function has returned. The stack - frame is no longer valid */ - JSValue resolving_funcs[2]; /* only used in JS async functions */ + bool throw_flag; /* used to throw an exception in JS_CallInternal() */ JSStackFrame frame; } JSAsyncFunctionState; -typedef enum { - /* binary operators */ - JS_OVOP_ADD, - JS_OVOP_SUB, - JS_OVOP_MUL, - JS_OVOP_DIV, - JS_OVOP_MOD, - JS_OVOP_POW, - JS_OVOP_OR, - JS_OVOP_AND, - JS_OVOP_XOR, - JS_OVOP_SHL, - JS_OVOP_SAR, - JS_OVOP_SHR, - JS_OVOP_EQ, - JS_OVOP_LESS, - - JS_OVOP_BINARY_COUNT, - /* unary operators */ - JS_OVOP_POS = JS_OVOP_BINARY_COUNT, - JS_OVOP_NEG, - JS_OVOP_INC, - JS_OVOP_DEC, - JS_OVOP_NOT, - - JS_OVOP_COUNT, -} JSOverloadableOperatorEnum; - -typedef struct { - uint32_t operator_index; - JSObject *ops[JS_OVOP_BINARY_COUNT]; /* self operators */ -} JSBinaryOperatorDefEntry; - -typedef struct { - int count; - JSBinaryOperatorDefEntry *tab; -} JSBinaryOperatorDef; - -typedef struct { - uint32_t operator_counter; - BOOL is_primitive; /* OperatorSet for a primitive type */ - /* NULL if no operator is defined */ - JSObject *self_ops[JS_OVOP_COUNT]; /* self operators */ - JSBinaryOperatorDef left; - JSBinaryOperatorDef right; -} JSOperatorSetData; +/* XXX: could use an object instead to avoid the + JS_TAG_ASYNC_FUNCTION tag for the GC */ +typedef struct JSAsyncFunctionData { + JSGCObjectHeader header; /* must come first */ + JSValue resolving_funcs[2]; + bool is_active; /* true if the async function state is valid */ + JSAsyncFunctionState func_state; +} JSAsyncFunctionData; typedef struct JSReqModuleEntry { JSAtom module_name; @@ -841,9 +859,9 @@ struct JSModuleDef { JSValue module_ns; JSValue func_obj; /* only used for JS modules */ JSModuleInitFunc *init_func; /* only used for C modules */ - BOOL has_tla : 8; /* true if func_obj contains await */ - BOOL resolved : 8; - BOOL func_created : 8; + bool has_tla; /* true if func_obj contains await */ + bool resolved; + bool func_created; JSModuleStatus status : 8; /* temp use during js_module_link() & js_module_evaluate() */ int dfs_index, dfs_ancestor_index; @@ -853,15 +871,14 @@ struct JSModuleDef { int async_parent_modules_count; int async_parent_modules_size; int pending_async_dependencies; - BOOL async_evaluation; + bool async_evaluation; int64_t async_evaluation_timestamp; JSModuleDef *cycle_root; JSValue promise; /* corresponds to spec field: capability */ JSValue resolving_funcs[2]; /* corresponds to spec field: capability */ - /* true if evaluation yielded an exception. It is saved in eval_exception */ - BOOL eval_has_exception : 8; + bool eval_has_exception; JSValue eval_exception; JSValue meta_obj; /* for import.meta */ }; @@ -871,7 +888,7 @@ typedef struct JSJobEntry { JSContext *ctx; JSJobFunc *job_func; int argc; - JSValue argv[0]; + JSValue argv[]; } JSJobEntry; typedef struct JSProperty { @@ -920,7 +937,7 @@ struct JSShape { int deleted_prop_count; JSShape *shape_hash_next; /* in JSRuntime.shape_hash[h] list */ JSObject *proto; - JSShapeProperty prop[0]; /* prop_size elements */ + JSShapeProperty prop[]; /* prop_size elements */ }; struct JSObject { @@ -932,10 +949,10 @@ 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 (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 is_exotic : 1; /* true if object has exotic property handlers */ + 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() */ uint8_t is_HTMLDDA : 1; /* specific annex B IsHtmlDDA behavior */ uint16_t class_id; /* see JS_CLASS_x */ @@ -945,7 +962,7 @@ struct JSObject { JSShape *shape; /* prototype and property names + flag */ JSProperty *prop; /* array of properties */ /* byte offsets: 24/40 */ - struct JSMapRecord *first_weak_ref; /* XXX: use a bit and an external hash table? */ + JSWeakRefRecord *first_weak_ref; /* byte offsets: 28/48 */ union { void *opaque; @@ -954,19 +971,17 @@ struct JSObject { struct JSForInIterator *for_in_iterator; /* JS_CLASS_FOR_IN_ITERATOR */ struct JSArrayBuffer *array_buffer; /* JS_CLASS_ARRAY_BUFFER, JS_CLASS_SHARED_ARRAY_BUFFER */ struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_DATAVIEW */ -#ifdef CONFIG_BIGNUM - struct JSFloatEnv *float_env; /* JS_CLASS_FLOAT_ENV */ - struct JSOperatorSetData *operator_set; /* JS_CLASS_OPERATOR_SET */ -#endif struct JSMapState *map_state; /* JS_CLASS_MAP..JS_CLASS_WEAKSET */ struct JSMapIteratorData *map_iterator_data; /* JS_CLASS_MAP_ITERATOR, JS_CLASS_SET_ITERATOR */ struct JSArrayIteratorData *array_iterator_data; /* JS_CLASS_ARRAY_ITERATOR, JS_CLASS_STRING_ITERATOR */ struct JSRegExpStringIteratorData *regexp_string_iterator_data; /* JS_CLASS_REGEXP_STRING_ITERATOR */ struct JSGeneratorData *generator_data; /* JS_CLASS_GENERATOR */ + struct JSIteratorHelperData *iterator_helper_data; /* JS_CLASS_ITERATOR_HELPER */ + struct JSIteratorWrapData *iterator_wrap_data; /* JS_CLASS_ITERATOR_WRAP */ struct JSProxyData *proxy_data; /* JS_CLASS_PROXY */ struct JSPromiseData *promise_data; /* JS_CLASS_PROMISE */ struct JSPromiseFunctionData *promise_function_data; /* JS_CLASS_PROMISE_RESOLVE_FUNCTION, JS_CLASS_PROMISE_REJECT_FUNCTION */ - struct JSAsyncFunctionState *async_function_data; /* JS_CLASS_ASYNC_FUNCTION_RESOLVE, JS_CLASS_ASYNC_FUNCTION_REJECT */ + struct JSAsyncFunctionData *async_function_data; /* JS_CLASS_ASYNC_FUNCTION_RESOLVE, JS_CLASS_ASYNC_FUNCTION_REJECT */ struct JSAsyncFromSyncIteratorData *async_from_sync_iterator_data; /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */ struct JSAsyncGeneratorData *async_generator_data; /* JS_CLASS_ASYNC_GENERATOR */ struct { /* JS_CLASS_BYTECODE_FUNCTION: 12/24 bytes */ @@ -999,6 +1014,7 @@ struct JSObject { uint32_t *uint32_ptr; /* JS_CLASS_UINT32_ARRAY */ int64_t *int64_ptr; /* JS_CLASS_INT64_ARRAY */ uint64_t *uint64_ptr; /* JS_CLASS_UINT64_ARRAY */ + uint16_t *fp16_ptr; /* JS_CLASS_FLOAT16_ARRAY */ float *float_ptr; /* JS_CLASS_FLOAT32_ARRAY */ double *double_ptr; /* JS_CLASS_FLOAT64_ARRAY */ } u; @@ -1010,6 +1026,15 @@ struct JSObject { /* byte sizes: 40/48/72 */ }; +typedef struct JSCallSiteData { + JSValue filename; + JSValue func; + JSValue func_name; + bool native; + int line_num; + int col_num; +} JSCallSiteData; + enum { __JS_ATOM_NULL = JS_ATOM_NULL, #define DEF(name, str) JS_ATOM_ ## name, @@ -1034,7 +1059,7 @@ typedef enum OPCodeFormat { #undef FMT } OPCodeFormat; -enum OPCodeEnum { +typedef enum OPCodeEnum { #define FMT(f) #define DEF(id, size, n_pop, n_push, f) OP_ ## id, #define def(id, size, n_pop, n_push, f) @@ -1054,96 +1079,99 @@ enum OPCodeEnum { #undef DEF #undef FMT OP_TEMP_END, -}; +} OPCodeEnum; static int JS_InitAtoms(JSRuntime *rt); static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len, int atom_type); static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p); static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b); -static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_obj, - int argc, JSValueConst *argv, int flags); -static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_obj, - int argc, JSValueConst *argv, int flags); -static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_obj, JSValueConst new_target, +static JSValue js_call_c_function(JSContext *ctx, JSValue func_obj, + JSValue this_obj, + int argc, JSValue *argv, int flags); +static JSValue js_call_bound_function(JSContext *ctx, JSValue func_obj, + JSValue this_obj, + int argc, JSValue *argv, int flags); +static JSValue JS_CallInternal(JSContext *ctx, JSValue func_obj, + JSValue this_obj, JSValue new_target, int argc, JSValue *argv, int flags); static JSValue JS_CallConstructorInternal(JSContext *ctx, - JSValueConst func_obj, - JSValueConst new_target, + JSValue func_obj, + JSValue new_target, int argc, JSValue *argv, int flags); -static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj, - int argc, JSValueConst *argv); +static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValue this_obj, + int argc, JSValue *argv); static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom, - int argc, JSValueConst *argv); + int argc, JSValue *argv); static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen, - JSValue val, BOOL is_array_ctor); -static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj, - JSValueConst val, int flags, int scope_idx); -static __maybe_unused void JS_DumpAtoms(JSRuntime *rt); + JSValue val, bool is_array_ctor); +static JSValue JS_EvalObject(JSContext *ctx, JSValue this_obj, + JSValue val, int flags, int scope_idx); +JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowInternalError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...); + static __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p); static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt); static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p); static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p); -static __maybe_unused void JS_DumpValueShort(JSRuntime *rt, JSValueConst val); -static __maybe_unused void JS_DumpValue(JSContext *ctx, JSValueConst val); -static __maybe_unused void JS_PrintValue(JSContext *ctx, - const char *str, - JSValueConst val); +static __maybe_unused void JS_DumpValue(JSRuntime *rt, JSValue val); +static __maybe_unused void JS_DumpAtoms(JSRuntime *rt); static __maybe_unused void JS_DumpShapes(JSRuntime *rt); -static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic); + +static JSValue js_function_apply(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic); static void js_array_finalizer(JSRuntime *rt, JSValue val); -static void js_array_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); +static void js_array_mark(JSRuntime *rt, JSValue val, + JS_MarkFunc *mark_func); static void js_object_data_finalizer(JSRuntime *rt, JSValue val); -static void js_object_data_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); +static void js_object_data_mark(JSRuntime *rt, JSValue val, + JS_MarkFunc *mark_func); static void js_c_function_finalizer(JSRuntime *rt, JSValue val); -static void js_c_function_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); +static void js_c_function_mark(JSRuntime *rt, JSValue val, + JS_MarkFunc *mark_func); static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val); -static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val, +static void js_bytecode_function_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func); static void js_bound_function_finalizer(JSRuntime *rt, JSValue val); -static void js_bound_function_mark(JSRuntime *rt, JSValueConst val, +static void js_bound_function_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func); static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val); -static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val, +static void js_for_in_iterator_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func); static void js_regexp_finalizer(JSRuntime *rt, JSValue val); static void js_array_buffer_finalizer(JSRuntime *rt, JSValue val); static void js_typed_array_finalizer(JSRuntime *rt, JSValue val); -static void js_typed_array_mark(JSRuntime *rt, JSValueConst val, +static void js_typed_array_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func); static void js_proxy_finalizer(JSRuntime *rt, JSValue val); -static void js_proxy_mark(JSRuntime *rt, JSValueConst val, +static void js_proxy_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func); static void js_map_finalizer(JSRuntime *rt, JSValue val); -static void js_map_mark(JSRuntime *rt, JSValueConst val, +static void js_map_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func); static void js_map_iterator_finalizer(JSRuntime *rt, JSValue val); -static void js_map_iterator_mark(JSRuntime *rt, JSValueConst val, +static void js_map_iterator_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func); static void js_array_iterator_finalizer(JSRuntime *rt, JSValue val); -static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val, +static void js_array_iterator_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func); +static void js_iterator_helper_finalizer(JSRuntime *rt, JSValue val); +static void js_iterator_helper_mark(JSRuntime *rt, JSValue val, + JS_MarkFunc *mark_func); +static void js_iterator_wrap_finalizer(JSRuntime *rt, JSValue val); +static void js_iterator_wrap_mark(JSRuntime *rt, JSValue val, + JS_MarkFunc *mark_func); static void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val); -static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val, +static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func); static void js_generator_finalizer(JSRuntime *rt, JSValue obj); -static void js_generator_mark(JSRuntime *rt, JSValueConst val, +static void js_generator_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func); static void js_promise_finalizer(JSRuntime *rt, JSValue val); -static void js_promise_mark(JSRuntime *rt, JSValueConst val, +static void js_promise_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func); static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val); -static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val, +static void js_promise_resolve_function_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func); -#ifdef CONFIG_BIGNUM -static void js_operator_set_finalizer(JSRuntime *rt, JSValue val); -static void js_operator_set_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func); -#endif #define HINT_STRING 0 #define HINT_NUMBER 1 @@ -1155,13 +1183,16 @@ static int JS_ToBoolFree(JSContext *ctx, JSValue val); static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val); static int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val); static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val); -static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern, - JSValueConst flags); -static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor, +static JSValue js_new_string8_len(JSContext *ctx, const char *buf, int len); +static JSValue js_compile_regexp(JSContext *ctx, JSValue pattern, + JSValue flags); +static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValue ctor, JSValue pattern, JSValue bc); static void gc_decref(JSRuntime *rt); static int JS_NewClass1(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def, JSAtom name); +static JSValue js_array_push(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int unshift); typedef enum JSStrictEqModeEnum { JS_EQ_STRICT, @@ -1169,120 +1200,106 @@ typedef enum JSStrictEqModeEnum { JS_EQ_SAME_VALUE_ZERO, } JSStrictEqModeEnum; -static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, +static bool js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, JSStrictEqModeEnum eq_mode); -static BOOL js_strict_eq(JSContext *ctx, JSValueConst op1, JSValueConst op2); -static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2); -static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2); -static JSValue JS_ToObject(JSContext *ctx, JSValueConst val); +static bool js_strict_eq(JSContext *ctx, JSValue op1, JSValue op2); +static bool js_same_value(JSContext *ctx, JSValue op1, JSValue op2); +static bool js_same_value_zero(JSContext *ctx, JSValue op1, JSValue op2); static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val); static JSProperty *add_property(JSContext *ctx, JSObject *p, JSAtom prop, int prop_flags); static JSValue JS_NewBigInt(JSContext *ctx); -static inline bf_t *JS_GetBigInt(JSValueConst val) +static inline bf_t *JS_GetBigInt(JSValue val) { - JSBigFloat *p = JS_VALUE_GET_PTR(val); + JSBigInt *p = JS_VALUE_GET_PTR(val); return &p->num; } -static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val, - BOOL convert_to_safe_integer); +static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val); static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val); static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val); -static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val); +static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValue val); +static bf_t *JS_ToBigInt1(JSContext *ctx, bf_t *buf, JSValue val); static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf); -#ifdef CONFIG_BIGNUM -static void js_float_env_finalizer(JSRuntime *rt, JSValue val); -static JSValue JS_NewBigFloat(JSContext *ctx); -static inline bf_t *JS_GetBigFloat(JSValueConst val) -{ - JSBigFloat *p = JS_VALUE_GET_PTR(val); - return &p->num; -} -static JSValue JS_NewBigDecimal(JSContext *ctx); -static inline bfdec_t *JS_GetBigDecimal(JSValueConst val) -{ - JSBigDecimal *p = JS_VALUE_GET_PTR(val); - return &p->num; -} -static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val); -static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val, - BOOL allow_null_or_undefined); -static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val); -#endif +JSValue JS_ThrowOutOfMemory(JSContext *ctx); static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx); -static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj); -static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj, - JSValueConst proto_val, BOOL throw_flag); - -static int js_resolve_proxy(JSContext *ctx, JSValueConst *pval, int throw_exception); -static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj); -static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj); +static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValue obj); +static int js_proxy_setPrototypeOf(JSContext *ctx, JSValue obj, + JSValue proto_val, bool throw_flag); +static int js_proxy_isExtensible(JSContext *ctx, JSValue obj); +static int js_proxy_preventExtensions(JSContext *ctx, JSValue obj); +static int js_proxy_isArray(JSContext *ctx, JSValue obj); static int JS_CreateProperty(JSContext *ctx, JSObject *p, - JSAtom prop, JSValueConst val, - JSValueConst getter, JSValueConst setter, + JSAtom prop, JSValue val, + JSValue getter, JSValue setter, int flags); static int js_string_memcmp(const JSString *p1, const JSString *p2, int len); -static void reset_weak_ref(JSRuntime *rt, JSObject *p); +static void reset_weak_ref(JSRuntime *rt, JSWeakRefRecord **first_weak_ref); +static bool is_valid_weakref_target(JSValue val); +static void insert_weakref_record(JSValue target, struct JSWeakRefRecord *wr); static JSValue js_array_buffer_constructor3(JSContext *ctx, - JSValueConst new_target, - uint64_t len, JSClassID class_id, + JSValue new_target, + uint64_t len, uint64_t *max_len, + JSClassID class_id, uint8_t *buf, JSFreeArrayBufferDataFunc *free_func, - void *opaque, BOOL alloc_flag); -static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj); + void *opaque, bool alloc_flag); +static void js_array_buffer_free(JSRuntime *rt, void *opaque, void *ptr); +static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValue obj); +static bool array_buffer_is_resizable(const JSArrayBuffer *abuf); static JSValue js_typed_array_constructor(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv, + JSValue this_val, + int argc, JSValue *argv, int classid); static JSValue js_typed_array_constructor_ta(JSContext *ctx, - JSValueConst new_target, - JSValueConst src_obj, - int classid); -static BOOL typed_array_is_detached(JSContext *ctx, JSObject *p); + JSValue new_target, + JSValue src_obj, + int classid, uint32_t len); +static bool is_typed_array(JSClassID class_id); +static bool typed_array_is_oob(JSObject *p); static uint32_t typed_array_get_length(JSContext *ctx, JSObject *p); static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx); +static JSValue JS_ThrowTypeErrorArrayBufferOOB(JSContext *ctx); static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, int var_idx, - BOOL is_arg); -static void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s); -static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s); -static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_obj, - int argc, JSValueConst *argv, + bool is_arg); +static JSValue js_generator_function_call(JSContext *ctx, JSValue func_obj, + JSValue this_obj, + int argc, JSValue *argv, int flags); static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val); -static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val, +static void js_async_function_resolve_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func); -static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, +static JSValue JS_EvalInternal(JSContext *ctx, JSValue this_obj, const char *input, size_t input_len, const char *filename, int line, int flags, int scope_idx); static void js_free_module_def(JSContext *ctx, JSModuleDef *m); static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m, JS_MarkFunc *mark_func); static JSValue js_import_meta(JSContext *ctx); -static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier); +static JSValue js_dynamic_import(JSContext *ctx, JSValue specifier); static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref); static JSValue js_new_promise_capability(JSContext *ctx, JSValue *resolving_funcs, - JSValueConst ctor); + JSValue ctor); static __exception int perform_promise_then(JSContext *ctx, - JSValueConst promise, - JSValueConst *resolve_reject, - JSValueConst *cap_resolving_funcs); -static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic); + JSValue promise, + JSValue *resolve_reject, + JSValue *cap_resolving_funcs); +static JSValue js_promise_resolve(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic); static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); -static int js_string_compare(JSContext *ctx, - const JSString *p1, const JSString *p2); -static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val); -static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, +static bool js_string_eq(const JSString *p1, const JSString *p2); +static int js_string_compare(const JSString *p1, const JSString *p2); +static int JS_SetPropertyValue(JSContext *ctx, JSValue this_obj, JSValue prop, JSValue val, int flags); -static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val); -static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val); +static int JS_NumberIsInteger(JSContext *ctx, JSValue val); +static bool JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValue val); static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val); static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc, JSObject *p, JSAtom prop); static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc); +static void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s, + JS_MarkFunc *mark_func); static void JS_AddIntrinsicBasicObjects(JSContext *ctx); static void js_free_shape(JSRuntime *rt, JSShape *sh); static void js_free_shape_null(JSRuntime *rt, JSShape *sh); @@ -1290,53 +1307,152 @@ static int js_shape_prepare_update(JSContext *ctx, JSObject *p, JSShapeProperty **pprs); static int init_shape_hash(JSRuntime *rt); static __exception int js_get_length32(JSContext *ctx, uint32_t *pres, - JSValueConst obj); + JSValue obj); static __exception int js_get_length64(JSContext *ctx, int64_t *pres, - JSValueConst obj); + JSValue obj); +static __exception int js_set_length64(JSContext *ctx, JSValue obj, + int64_t len); static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len); static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen, - JSValueConst array_arg); -static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj, + JSValue array_arg); +static bool js_get_fast_array(JSContext *ctx, JSValue obj, JSValue **arrpp, uint32_t *countp); static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx, - JSValueConst sync_iter); + JSValue sync_iter); static void js_c_function_data_finalizer(JSRuntime *rt, JSValue val); -static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val, +static void js_c_function_data_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func); -static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_val, - int argc, JSValueConst *argv, int flags); +static JSValue js_c_function_data_call(JSContext *ctx, JSValue func_obj, + JSValue this_val, + int argc, JSValue *argv, int flags); static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val); 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 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 JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); -static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int is_map); + +static void js_set_uncatchable_error(JSContext *ctx, JSValue val, bool flag); + +static JSValue js_new_callsite(JSContext *ctx, JSCallSiteData *csd); +static void js_new_callsite_data(JSContext *ctx, JSCallSiteData *csd, JSStackFrame *sf); +static void js_new_callsite_data2(JSContext *ctx, JSCallSiteData *csd, const char *filename, int line_num, int col_num); +static void _JS_AddIntrinsicCallSite(JSContext *ctx); + +static void JS_SetOpaqueInternal(JSValue obj, void *opaque); static const JSClassExoticMethods js_arguments_exotic_methods; static const JSClassExoticMethods js_string_exotic_methods; static const JSClassExoticMethods js_proxy_exotic_methods; static const JSClassExoticMethods js_module_ns_exotic_methods; -static JSClassID js_class_id_alloc = JS_CLASS_INIT_COUNT; + +static inline bool double_is_int32(double d) +{ + uint64_t u, e; + JSFloat64Union t; + + t.d = d; + u = t.u64; + + e = ((u >> 52) & 0x7FF) - 1023; + if (e > 30) { + // accept 0, INT32_MIN, reject too large, too small, nan, inf, -0 + return !u || (u == 0xc1e0000000000000); + } else { + // shift out sign, exponent and whole part bits + // value is fractional if remaining low bits are non-zero + return !(u << 12 << e); + } +} + +static JSValue js_float64(double d) +{ + return __JS_NewFloat64(d); +} + +static int compare_u32(uint32_t a, uint32_t b) +{ + return -(a < b) + (b < a); // -1, 0 or 1 +} + +static JSValue js_int32(int32_t v) +{ + return JS_MKVAL(JS_TAG_INT, v); +} + +static JSValue js_uint32(uint32_t v) +{ + if (v <= INT32_MAX) + return js_int32(v); + else + return js_float64(v); +} + +static JSValue js_int64(int64_t v) +{ + if (v >= INT32_MIN && v <= INT32_MAX) + return js_int32(v); + else + return js_float64(v); +} + +#define JS_NewInt64(ctx, val) js_int64(val) + +static JSValue js_number(double d) +{ + if (double_is_int32(d)) + return js_int32((int32_t)d); + else + return js_float64(d); +} + +JSValue JS_NewNumber(JSContext *ctx, double d) +{ + return js_number(d); +} + +static JSValue js_bool(bool v) +{ + return JS_MKVAL(JS_TAG_BOOL, (v != 0)); +} + +static JSValue js_dup(JSValue v) +{ + if (JS_VALUE_HAS_REF_COUNT(v)) { + JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); + p->ref_count++; + } + return v; +} + +JSValue JS_DupValue(JSContext *ctx, JSValue v) +{ + return js_dup(v); +} + +JSValue JS_DupValueRT(JSRuntime *rt, JSValue v) +{ + return js_dup(v); +} static void js_trigger_gc(JSRuntime *rt, size_t size) { - BOOL force_gc; + bool force_gc; #ifdef FORCE_GC_AT_MALLOC - force_gc = TRUE; + force_gc = true; #else force_gc = ((rt->malloc_state.malloc_size + size) > rt->malloc_gc_threshold); #endif if (force_gc) { -#ifdef DUMP_GC - printf("GC: size=%" PRIu64 "\n", - (uint64_t)rt->malloc_state.malloc_size); +#ifdef ENABLE_DUMPS // JS_DUMP_GC + if (check_dump_flag(rt, JS_DUMP_GC)) { + printf("GC: size=%zd\n", rt->malloc_state.malloc_size); + } #endif JS_RunGC(rt); rt->malloc_gc_threshold = rt->malloc_state.malloc_size + @@ -1349,19 +1465,93 @@ static size_t js_malloc_usable_size_unknown(const void *ptr) return 0; } +void *js_calloc_rt(JSRuntime *rt, size_t count, size_t size) +{ + void *ptr; + JSMallocState *s; + + /* Do not allocate zero bytes: behavior is platform dependent */ + assert(count != 0 && size != 0); + + if (size > 0) + if (unlikely(count != (count * size) / size)) + return NULL; + + s = &rt->malloc_state; + /* When malloc_limit is 0 (unlimited), malloc_limit - 1 will be SIZE_MAX. */ + if (unlikely(s->malloc_size + (count * size) > s->malloc_limit - 1)) + return NULL; + + ptr = rt->mf.js_calloc(s->opaque, count, size); + if (!ptr) + return NULL; + + s->malloc_count++; + s->malloc_size += rt->mf.js_malloc_usable_size(ptr) + MALLOC_OVERHEAD; + return ptr; +} + void *js_malloc_rt(JSRuntime *rt, size_t size) { - return rt->mf.js_malloc(&rt->malloc_state, size); + void *ptr; + JSMallocState *s; + + /* Do not allocate zero bytes: behavior is platform dependent */ + assert(size != 0); + + s = &rt->malloc_state; + /* When malloc_limit is 0 (unlimited), malloc_limit - 1 will be SIZE_MAX. */ + if (unlikely(s->malloc_size + size > s->malloc_limit - 1)) + return NULL; + + ptr = rt->mf.js_malloc(s->opaque, size); + if (!ptr) + return NULL; + + s->malloc_count++; + s->malloc_size += rt->mf.js_malloc_usable_size(ptr) + MALLOC_OVERHEAD; + return ptr; } void js_free_rt(JSRuntime *rt, void *ptr) { - rt->mf.js_free(&rt->malloc_state, ptr); + JSMallocState *s; + + if (!ptr) + return; + + s = &rt->malloc_state; + s->malloc_count--; + s->malloc_size -= rt->mf.js_malloc_usable_size(ptr) + MALLOC_OVERHEAD; + rt->mf.js_free(s->opaque, ptr); } void *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size) { - return rt->mf.js_realloc(&rt->malloc_state, ptr, size); + size_t old_size; + JSMallocState *s; + + if (!ptr) { + if (size == 0) + return NULL; + return js_malloc_rt(rt, size); + } + if (unlikely(size == 0)) { + js_free_rt(rt, ptr); + return NULL; + } + old_size = rt->mf.js_malloc_usable_size(ptr); + s = &rt->malloc_state; + /* When malloc_limit is 0 (unlimited), malloc_limit - 1 will be SIZE_MAX. */ + if (s->malloc_size + size - old_size > s->malloc_limit - 1) + return NULL; + + ptr = rt->mf.js_realloc(s->opaque, ptr, size); + if (!ptr) + return NULL; + + s->malloc_size += rt->mf.js_malloc_usable_size(ptr) - old_size; + return ptr; } size_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr) @@ -1369,13 +1559,16 @@ size_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr) return rt->mf.js_malloc_usable_size(ptr); } +/** + * This used to be implemented as malloc + memset, but using calloc + * yields better performance in initial, bursty allocations, something useful + * for QuickJS. + * + * More information: https://github.com/quickjs-ng/quickjs/pull/519 + */ void *js_mallocz_rt(JSRuntime *rt, size_t size) { - void *ptr; - ptr = js_malloc_rt(rt, size); - if (!ptr) - return NULL; - return memset(ptr, 0, size); + return js_calloc_rt(rt, 1, size); } /* called by libbf */ @@ -1385,6 +1578,18 @@ static void *js_bf_realloc(void *opaque, void *ptr, size_t size) return js_realloc_rt(rt, ptr, size); } +/* Throw out of memory in case of error */ +void *js_calloc(JSContext *ctx, size_t count, size_t size) +{ + void *ptr; + ptr = js_calloc_rt(ctx->rt, count, size); + if (unlikely(!ptr)) { + JS_ThrowOutOfMemory(ctx); + return NULL; + } + return ptr; +} + /* Throw out of memory in case of error */ void *js_malloc(JSContext *ctx, size_t size) { @@ -1491,9 +1696,14 @@ static inline int js_resize_array(JSContext *ctx, void **parray, int elem_size, return 0; } +static void *js_dbuf_realloc(void *ctx, void *ptr, size_t size) +{ + return js_realloc(ctx, ptr, size); +} + static inline void js_dbuf_init(JSContext *ctx, DynBuf *s) { - dbuf_init2(s, ctx->rt, (DynBufReallocFunc *)js_realloc_rt); + dbuf_init2(s, ctx, js_dbuf_realloc); } static inline int is_digit(int c) { @@ -1540,20 +1750,18 @@ static JSClassShortDef const js_std_class_def[] = { { JS_ATOM_Uint32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT32_ARRAY */ { JS_ATOM_BigInt64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_BIG_INT64_ARRAY */ { JS_ATOM_BigUint64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_BIG_UINT64_ARRAY */ + { JS_ATOM_Float16Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT16_ARRAY */ { JS_ATOM_Float32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT32_ARRAY */ { JS_ATOM_Float64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT64_ARRAY */ { JS_ATOM_DataView, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_DATAVIEW */ { JS_ATOM_BigInt, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_INT */ -#ifdef CONFIG_BIGNUM - { JS_ATOM_BigFloat, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_FLOAT */ - { JS_ATOM_BigFloatEnv, js_float_env_finalizer, NULL }, /* JS_CLASS_FLOAT_ENV */ - { JS_ATOM_BigDecimal, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_DECIMAL */ - { JS_ATOM_OperatorSet, js_operator_set_finalizer, js_operator_set_mark }, /* JS_CLASS_OPERATOR_SET */ -#endif { JS_ATOM_Map, js_map_finalizer, js_map_mark }, /* JS_CLASS_MAP */ { JS_ATOM_Set, js_map_finalizer, js_map_mark }, /* JS_CLASS_SET */ { JS_ATOM_WeakMap, js_map_finalizer, js_map_mark }, /* JS_CLASS_WEAKMAP */ { JS_ATOM_WeakSet, js_map_finalizer, js_map_mark }, /* JS_CLASS_WEAKSET */ + { JS_ATOM_Iterator, NULL, NULL }, /* JS_CLASS_ITERATOR */ + { JS_ATOM_IteratorHelper, js_iterator_helper_finalizer, js_iterator_helper_mark }, /* JS_CLASS_ITERATOR_HELPER */ + { JS_ATOM_IteratorWrap, js_iterator_wrap_finalizer, js_iterator_wrap_mark }, /* JS_CLASS_ITERATOR_WRAP */ { JS_ATOM_Map_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_MAP_ITERATOR */ { JS_ATOM_Set_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_SET_ITERATOR */ { JS_ATOM_Array_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_ARRAY_ITERATOR */ @@ -1579,84 +1787,13 @@ static int init_class_range(JSRuntime *rt, JSClassShortDef const *tab, return 0; } -static JSValue JS_ThrowUnsupportedOperation(JSContext *ctx) -{ - return JS_ThrowTypeError(ctx, "unsupported operation"); -} - -static JSValue invalid_to_string(JSContext *ctx, JSValueConst val) -{ - return JS_ThrowUnsupportedOperation(ctx); -} - -static JSValue invalid_from_string(JSContext *ctx, const char *buf, - int radix, int flags, slimb_t *pexponent) -{ - return JS_NAN; -} - -static int invalid_unary_arith(JSContext *ctx, - JSValue *pres, OPCodeEnum op, JSValue op1) -{ - JS_FreeValue(ctx, op1); - JS_ThrowUnsupportedOperation(ctx); - return -1; -} - -static int invalid_binary_arith(JSContext *ctx, OPCodeEnum op, - JSValue *pres, JSValue op1, JSValue op2) -{ - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - JS_ThrowUnsupportedOperation(ctx); - return -1; -} - -static JSValue invalid_mul_pow10_to_float64(JSContext *ctx, const bf_t *a, - int64_t exponent) -{ - return JS_ThrowUnsupportedOperation(ctx); -} - -static int invalid_mul_pow10(JSContext *ctx, JSValue *sp) -{ - JS_ThrowUnsupportedOperation(ctx); - return -1; -} - -static void set_dummy_numeric_ops(JSNumericOperations *ops) -{ - ops->to_string = invalid_to_string; - ops->from_string = invalid_from_string; - ops->unary_arith = invalid_unary_arith; - ops->binary_arith = invalid_binary_arith; - ops->mul_pow10_to_float64 = invalid_mul_pow10_to_float64; - ops->mul_pow10 = invalid_mul_pow10; -} - -#if !defined(CONFIG_STACK_CHECK) -/* no stack limitation */ -static inline uintptr_t js_get_stack_pointer(void) -{ - return 0; -} - -static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size) -{ - return FALSE; -} -#else -// Uses code from LLVM project. +/* Uses code from LLVM project. */ static inline uintptr_t js_get_stack_pointer(void) { -#ifdef _MSC_VER - return (uintptr_t) _AddressOfReturnAddress(); -#elif defined __has_builtin -#if __has_builtin(__builtin_frame_address) - return (uintptr_t) __builtin_frame_address(0); -#endif -#elif defined __GNUC__ - return (uintptr_t) __builtin_frame_address(0); +#if defined(__clang__) || defined(__GNUC__) + return (uintptr_t)__builtin_frame_address(0); +#elif defined(_MSC_VER) + return (uintptr_t)_AddressOfReturnAddress(); #else char CharOnStack = 0; // The volatile store here is intended to escape the local variable, to @@ -1669,13 +1806,12 @@ static inline uintptr_t js_get_stack_pointer(void) #endif } -static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size) +static inline bool js_check_stack_overflow(JSRuntime *rt, size_t alloca_size) { uintptr_t sp; sp = js_get_stack_pointer() - alloca_size; return unlikely(sp < rt->stack_limit); } -#endif JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque) { @@ -1684,33 +1820,30 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque) memset(&ms, 0, sizeof(ms)); ms.opaque = opaque; - ms.malloc_limit = -1; + ms.malloc_limit = 0; - rt = mf->js_malloc(&ms, sizeof(JSRuntime)); + rt = mf->js_calloc(opaque, 1, sizeof(JSRuntime)); if (!rt) return NULL; - memset(rt, 0, sizeof(*rt)); rt->mf = *mf; if (!rt->mf.js_malloc_usable_size) { /* use dummy function if none provided */ rt->mf.js_malloc_usable_size = js_malloc_usable_size_unknown; } + /* Inline what js_malloc_rt does since we cannot use it here. */ + ms.malloc_count++; + ms.malloc_size += rt->mf.js_malloc_usable_size(rt) + MALLOC_OVERHEAD; rt->malloc_state = ms; rt->malloc_gc_threshold = 256 * 1024; bf_context_init(&rt->bf_ctx, js_bf_realloc, rt); - set_dummy_numeric_ops(&rt->bigint_ops); -#ifdef CONFIG_BIGNUM - set_dummy_numeric_ops(&rt->bigfloat_ops); - set_dummy_numeric_ops(&rt->bigdecimal_ops); -#endif init_list_head(&rt->context_list); init_list_head(&rt->gc_obj_list); init_list_head(&rt->gc_zero_ref_count_list); rt->gc_phase = JS_GC_PHASE_NONE; -#ifdef DUMP_LEAKS +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS init_list_head(&rt->string_list); #endif init_list_head(&rt->job_list); @@ -1733,10 +1866,16 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque) if (init_shape_hash(rt)) goto fail; + rt->js_class_id_alloc = JS_CLASS_INIT_COUNT; + rt->stack_size = JS_DEFAULT_STACK_SIZE; +#ifdef __wasi__ + rt->stack_size = 0; +#endif + JS_UpdateStackTop(rt); - rt->current_exception = JS_NULL; + rt->current_exception = JS_UNINITIALIZED; return rt; fail: @@ -1754,84 +1893,45 @@ void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque) rt->user_opaque = opaque; } -/* default memory allocation functions with memory limitation */ -static size_t js_def_malloc_usable_size(const void *ptr) +int JS_AddRuntimeFinalizer(JSRuntime *rt, JSRuntimeFinalizer *finalizer, + void *arg) { -#if defined(__APPLE__) - return malloc_size(ptr); -#elif defined(_WIN32) - return _msize((void *)ptr); -#elif defined(EMSCRIPTEN) + JSRuntimeFinalizerState *fs = js_malloc_rt(rt, sizeof(*fs)); + if (!fs) + return -1; + fs->next = rt->finalizers; + fs->finalizer = finalizer; + fs->arg = arg; + rt->finalizers = fs; return 0; -#elif defined(__linux__) - return malloc_usable_size((void *)ptr); -#else - /* change this to `return 0;` if compilation fails */ - return malloc_usable_size((void *)ptr); -#endif } -static void *js_def_malloc(JSMallocState *s, size_t size) +static void *js_def_calloc(void *opaque, size_t count, size_t size) { - void *ptr; - - /* Do not allocate zero bytes: behavior is platform dependent */ - assert(size != 0); - - if (unlikely(s->malloc_size + size > s->malloc_limit)) - return NULL; - - ptr = malloc(size); - if (!ptr) - return NULL; - - s->malloc_count++; - s->malloc_size += js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD; - return ptr; + return calloc(count, size); } -static void js_def_free(JSMallocState *s, void *ptr) +static void *js_def_malloc(void *opaque, size_t size) { - if (!ptr) - return; + return malloc(size); +} - s->malloc_count--; - s->malloc_size -= js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD; +static void js_def_free(void *opaque, void *ptr) +{ free(ptr); } -static void *js_def_realloc(JSMallocState *s, void *ptr, size_t size) +static void *js_def_realloc(void *opaque, void *ptr, size_t size) { - size_t old_size; - - if (!ptr) { - if (size == 0) - return NULL; - return js_def_malloc(s, size); - } - old_size = js_def_malloc_usable_size(ptr); - if (size == 0) { - s->malloc_count--; - s->malloc_size -= old_size + MALLOC_OVERHEAD; - free(ptr); - return NULL; - } - if (s->malloc_size + size - old_size > s->malloc_limit) - return NULL; - - ptr = realloc(ptr, size); - if (!ptr) - return NULL; - - s->malloc_size += js_def_malloc_usable_size(ptr) - old_size; - return ptr; + return realloc(ptr, size); } static const JSMallocFunctions def_malloc_funcs = { + js_def_calloc, js_def_malloc, js_def_free, js_def_realloc, - js_def_malloc_usable_size, + js__malloc_usable_size }; JSRuntime *JS_NewRuntime(void) @@ -1844,6 +1944,26 @@ void JS_SetMemoryLimit(JSRuntime *rt, size_t limit) rt->malloc_state.malloc_limit = limit; } +void JS_SetDumpFlags(JSRuntime *rt, uint64_t flags) +{ +#ifdef ENABLE_DUMPS + rt->dump_flags = flags; +#endif +} + +uint64_t JS_GetDumpFlags(JSRuntime *rt) +{ +#ifdef ENABLE_DUMPS + return rt->dump_flags; +#else + return 0; +#endif +} + +size_t JS_GetGCThreshold(JSRuntime *rt) { + return rt->malloc_gc_threshold; +} + /* use -1 to disable automatic GC */ void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold) { @@ -1860,7 +1980,7 @@ void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque) rt->interrupt_opaque = opaque; } -void JS_SetCanBlock(JSRuntime *rt, BOOL can_block) +void JS_SetCanBlock(JSRuntime *rt, bool can_block) { rt->can_block = can_block; } @@ -1873,12 +1993,14 @@ void JS_SetSharedArrayBufferFunctions(JSRuntime *rt, /* return 0 if OK, < 0 if exception */ int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func, - int argc, JSValueConst *argv) + int argc, JSValue *argv) { JSRuntime *rt = ctx->rt; JSJobEntry *e; int i; + assert(!rt->in_free); + e = js_malloc(ctx, sizeof(*e) + argc * sizeof(JSValue)); if (!e) return -1; @@ -1886,13 +2008,13 @@ int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func, e->job_func = job_func; e->argc = argc; for(i = 0; i < argc; i++) { - e->argv[i] = JS_DupValue(ctx, argv[i]); + e->argv[i] = js_dup(argv[i]); } list_add_tail(&e->link, &rt->job_list); return 0; } -BOOL JS_IsJobPending(JSRuntime *rt) +bool JS_IsJobPending(JSRuntime *rt) { return !list_empty(&rt->job_list); } @@ -1915,7 +2037,7 @@ int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx) e = list_entry(rt->job_list.next, JSJobEntry, link); list_del(&e->link); ctx = e->ctx; - res = e->job_func(e->ctx, e->argc, (JSValueConst *)e->argv); + res = e->job_func(e->ctx, e->argc, e->argv); for(i = 0; i < e->argc; i++) JS_FreeValue(ctx, e->argv[i]); if (JS_IsException(res)) @@ -1933,7 +2055,7 @@ static inline uint32_t atom_get_free(const JSAtomStruct *p) return (uintptr_t)p >> 1; } -static inline BOOL atom_is_free(const JSAtomStruct *p) +static inline bool atom_is_free(const JSAtomStruct *p) { return (uintptr_t)p & 1; } @@ -1956,7 +2078,7 @@ static JSString *js_alloc_string_rt(JSRuntime *rt, int max_len, int is_wide_char str->atom_type = 0; str->hash = 0; /* optional but costless */ str->hash_next = 0; /* optional */ -#ifdef DUMP_LEAKS +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS list_add_tail(&str->link, &rt->string_list); #endif return str; @@ -1980,7 +2102,7 @@ static inline void js_free_string(JSRuntime *rt, JSString *str) if (str->atom_type) { JS_FreeAtomStruct(rt, str); } else { -#ifdef DUMP_LEAKS +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS list_del(&str->link); #endif js_free_rt(rt, str); @@ -1999,6 +2121,7 @@ void JS_FreeRuntime(JSRuntime *rt) struct list_head *el, *el1; int i; + rt->in_free = true; JS_FreeValueRT(rt, rt->current_exception); list_for_each_safe(el, el1, &rt->job_list) { @@ -2011,10 +2134,10 @@ void JS_FreeRuntime(JSRuntime *rt) JS_RunGC(rt); -#ifdef DUMP_LEAKS +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS /* leaking objects */ - { - BOOL header_done; + if (check_dump_flag(rt, JS_DUMP_LEAKS)) { + bool header_done; JSGCObjectHeader *p; int count; @@ -2026,14 +2149,14 @@ void JS_FreeRuntime(JSRuntime *rt) } gc_decref(rt); - header_done = FALSE; + header_done = false; list_for_each(el, &rt->gc_obj_list) { p = list_entry(el, JSGCObjectHeader, link); if (p->ref_count != 0) { if (!header_done) { printf("Object leaks:\n"); JS_DumpObjectHeader(rt); - header_done = TRUE; + header_done = true; } JS_DumpGCObject(rt, p); } @@ -2050,7 +2173,7 @@ void JS_FreeRuntime(JSRuntime *rt) printf("Secondary object leaks: %d\n", count); } #endif - fflush(stdout); + assert(list_empty(&rt->gc_obj_list)); /* free the classes */ @@ -2064,17 +2187,17 @@ void JS_FreeRuntime(JSRuntime *rt) bf_context_end(&rt->bf_ctx); -#ifdef DUMP_LEAKS +#ifdef ENABLE_DUMPS // JS_DUMP_ATOM_LEAKS /* only the atoms defined in JS_InitAtoms() should be left */ - { - BOOL header_done = FALSE; + if (check_dump_flag(rt, JS_DUMP_ATOM_LEAKS)) { + bool header_done = false; for(i = 0; i < rt->atom_size; i++) { JSAtomStruct *p = rt->atom_array[i]; if (!atom_is_free(p) /* && p->str*/) { if (i >= JS_ATOM_END || p->header.ref_count != 1) { if (!header_done) { - header_done = TRUE; + header_done = true; if (rt->rt_info) { printf("%s:1: atom leakage:", rt->rt_info); } else { @@ -2126,7 +2249,7 @@ void JS_FreeRuntime(JSRuntime *rt) for(i = 0; i < rt->atom_size; i++) { JSAtomStruct *p = rt->atom_array[i]; if (!atom_is_free(p)) { -#ifdef DUMP_LEAKS +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS list_del(&p->link); #endif js_free_rt(rt, p); @@ -2135,8 +2258,8 @@ void JS_FreeRuntime(JSRuntime *rt) js_free_rt(rt, rt->atom_array); js_free_rt(rt, rt->atom_hash); js_free_rt(rt, rt->shape_hash); -#ifdef DUMP_LEAKS - if (!list_empty(&rt->string_list)) { +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS + if (check_dump_flag(rt, JS_DUMP_LEAKS) && !list_empty(&rt->string_list)) { if (rt->rt_info) { printf("%s:1: string leakage:", rt->rt_info); } else { @@ -2163,22 +2286,33 @@ void JS_FreeRuntime(JSRuntime *rt) if (rt->rt_info) printf("\n"); } - { +#endif + + while (rt->finalizers) { + JSRuntimeFinalizerState *fs = rt->finalizers; + rt->finalizers = fs->next; + fs->finalizer(rt, fs->arg); + js_free_rt(rt, fs); + } + +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS + if (check_dump_flag(rt, JS_DUMP_LEAKS)) { JSMallocState *s = &rt->malloc_state; if (s->malloc_count > 1) { if (rt->rt_info) printf("%s:1: ", rt->rt_info); - printf("Memory leak: %"PRIu64" bytes lost in %"PRIu64" block%s\n", - (uint64_t)(s->malloc_size - sizeof(JSRuntime)), - (uint64_t)(s->malloc_count - 1), &"s"[s->malloc_count == 2]); + printf("Memory leak: %zd bytes lost in %zd block%s\n", + s->malloc_size - sizeof(JSRuntime), + s->malloc_count - 1, &"s"[s->malloc_count == 2]); } } #endif { - JSMallocState ms = rt->malloc_state; - rt->mf.js_free(&ms, rt); + JSMallocState *ms = &rt->malloc_state; + rt->mf.js_free(ms->opaque, rt); } + fflush(stdout); } JSContext *JS_NewContextRaw(JSRuntime *rt) @@ -2201,15 +2335,16 @@ JSContext *JS_NewContextRaw(JSRuntime *rt) ctx->rt = rt; list_add_tail(&ctx->link, &rt->context_list); ctx->bf_ctx = &rt->bf_ctx; -#ifdef CONFIG_BIGNUM - ctx->fp_env.prec = 113; - ctx->fp_env.flags = bf_set_exp_bits(15) | BF_RNDN | BF_FLAG_SUBNORMAL; -#endif for(i = 0; i < rt->class_count; i++) ctx->class_proto[i] = JS_NULL; ctx->array_ctor = JS_NULL; + ctx->iterator_ctor = JS_NULL; ctx->regexp_ctor = JS_NULL; ctx->promise_ctor = JS_NULL; + ctx->error_ctor = JS_NULL; + ctx->error_back_trace = JS_UNDEFINED; + ctx->error_prepare_stack = JS_UNDEFINED; + ctx->error_stack_trace_limit = 10; init_list_head(&ctx->loaded_modules); JS_AddIntrinsicBasicObjects(ctx); @@ -2227,7 +2362,6 @@ JSContext *JS_NewContext(JSRuntime *rt) JS_AddIntrinsicBaseObjects(ctx); JS_AddIntrinsicDate(ctx); JS_AddIntrinsicEval(ctx); - JS_AddIntrinsicStringNormalize(ctx); JS_AddIntrinsicRegExp(ctx); JS_AddIntrinsicJSON(ctx); JS_AddIntrinsicProxy(ctx); @@ -2235,6 +2369,10 @@ JSContext *JS_NewContext(JSRuntime *rt) JS_AddIntrinsicTypedArrays(ctx); JS_AddIntrinsicPromise(ctx); JS_AddIntrinsicBigInt(ctx); + JS_AddIntrinsicWeakRef(ctx); + + JS_AddPerformance(ctx); + return ctx; } @@ -2260,16 +2398,19 @@ static inline void set_value(JSContext *ctx, JSValue *pval, JSValue new_val) void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj) { - JSRuntime *rt = ctx->rt; - assert(class_id < rt->class_count); + assert(class_id < ctx->rt->class_count); set_value(ctx, &ctx->class_proto[class_id], obj); } JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id) { - JSRuntime *rt = ctx->rt; - assert(class_id < rt->class_count); - return JS_DupValue(ctx, ctx->class_proto[class_id]); + assert(class_id < ctx->rt->class_count); + return js_dup(ctx->class_proto[class_id]); +} + +JSValue JS_GetFunctionProto(JSContext *ctx) +{ + return js_dup(ctx->function_proto); } typedef enum JSFreeModuleEnum { @@ -2320,10 +2461,13 @@ static void JS_MarkContext(JSRuntime *rt, JSContext *ctx, for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) { JS_MarkValue(rt, ctx->native_error_proto[i], mark_func); } + JS_MarkValue(rt, ctx->error_ctor, mark_func); + JS_MarkValue(rt, ctx->error_back_trace, mark_func); + JS_MarkValue(rt, ctx->error_prepare_stack, mark_func); for(i = 0; i < rt->class_count; i++) { JS_MarkValue(rt, ctx->class_proto[i], mark_func); } - JS_MarkValue(rt, ctx->iterator_proto, mark_func); + JS_MarkValue(rt, ctx->iterator_ctor, mark_func); JS_MarkValue(rt, ctx->async_iterator_proto, mark_func); JS_MarkValue(rt, ctx->promise_ctor, mark_func); JS_MarkValue(rt, ctx->array_ctor, mark_func); @@ -2344,14 +2488,16 @@ void JS_FreeContext(JSContext *ctx) return; assert(ctx->header.ref_count == 0); -#ifdef DUMP_ATOMS - JS_DumpAtoms(ctx->rt); +#ifdef ENABLE_DUMPS // JS_DUMP_ATOMS + if (check_dump_flag(rt, JS_DUMP_ATOMS)) + JS_DumpAtoms(ctx->rt); #endif -#ifdef DUMP_SHAPES - JS_DumpShapes(ctx->rt); +#ifdef ENABLE_DUMPS // JS_DUMP_SHAPES + if (check_dump_flag(rt, JS_DUMP_SHAPES)) + JS_DumpShapes(ctx->rt); #endif -#ifdef DUMP_OBJECTS - { +#ifdef ENABLE_DUMPS // JS_DUMP_OBJECTS + if (check_dump_flag(rt, JS_DUMP_OBJECTS)) { struct list_head *el; JSGCObjectHeader *p; printf("JSObjects: {\n"); @@ -2363,8 +2509,8 @@ void JS_FreeContext(JSContext *ctx) printf("}\n"); } #endif -#ifdef DUMP_MEM - { +#ifdef ENABLE_DUMPS // JS_DUMP_MEM + if (check_dump_flag(rt, JS_DUMP_MEM)) { JSMemoryUsage stats; JS_ComputeMemoryUsage(rt, &stats); JS_DumpMemoryUsage(stdout, &stats, rt); @@ -2383,11 +2529,14 @@ void JS_FreeContext(JSContext *ctx) for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) { JS_FreeValue(ctx, ctx->native_error_proto[i]); } + JS_FreeValue(ctx, ctx->error_ctor); + JS_FreeValue(ctx, ctx->error_back_trace); + JS_FreeValue(ctx, ctx->error_prepare_stack); for(i = 0; i < rt->class_count; i++) { JS_FreeValue(ctx, ctx->class_proto[i]); } js_free_rt(rt, ctx->class_proto); - JS_FreeValue(ctx, ctx->iterator_proto); + JS_FreeValue(ctx, ctx->iterator_ctor); JS_FreeValue(ctx, ctx->async_iterator_proto); JS_FreeValue(ctx, ctx->promise_ctor); JS_FreeValue(ctx, ctx->array_ctor); @@ -2409,11 +2558,15 @@ JSRuntime *JS_GetRuntime(JSContext *ctx) static void update_stack_limit(JSRuntime *rt) { +#if defined(__wasi__) + rt->stack_limit = 0; /* no limit */ +#else if (rt->stack_size == 0) { rt->stack_limit = 0; /* no limit */ } else { rt->stack_limit = rt->stack_top - rt->stack_size; } +#endif } void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size) @@ -2428,24 +2581,11 @@ void JS_UpdateStackTop(JSRuntime *rt) update_stack_limit(rt); } -static inline BOOL is_strict_mode(JSContext *ctx) -{ - JSStackFrame *sf = ctx->rt->current_stack_frame; - return (sf && (sf->js_mode & JS_MODE_STRICT)); -} - -#ifdef CONFIG_BIGNUM -static inline BOOL is_math_mode(JSContext *ctx) +static inline bool is_strict_mode(JSContext *ctx) { JSStackFrame *sf = ctx->rt->current_stack_frame; - return (sf && (sf->js_mode & JS_MODE_MATH)); -} -#else -static inline BOOL is_math_mode(JSContext *ctx) -{ - return FALSE; + return sf && sf->is_strict_mode; } -#endif /* JSAtom support */ @@ -2456,16 +2596,12 @@ static inline BOOL is_math_mode(JSContext *ctx) /* return the max count from the hash size */ #define JS_ATOM_COUNT_RESIZE(n) ((n) * 2) -static inline BOOL __JS_AtomIsConst(JSAtom v) +static inline bool __JS_AtomIsConst(JSAtom v) { -#if defined(DUMP_LEAKS) && DUMP_LEAKS > 1 - return (int32_t)v <= 0; -#else - return (int32_t)v < JS_ATOM_END; -#endif + return (int32_t)v < JS_ATOM_END; } -static inline BOOL __JS_AtomIsTaggedInt(JSAtom v) +static inline bool __JS_AtomIsTaggedInt(JSAtom v) { return (v & JS_ATOM_TAG_INT) != 0; } @@ -2485,8 +2621,8 @@ static inline int is_num(int c) return c >= '0' && c <= '9'; } -/* return TRUE if the string is a number n with 0 <= n <= 2^32-1 */ -static inline BOOL is_num_string(uint32_t *pval, const JSString *p) +/* return true if the string is a number n with 0 <= n <= 2^32-1 */ +static inline bool is_num_string(uint32_t *pval, const JSString *p) { uint32_t n; uint64_t n64; @@ -2494,29 +2630,29 @@ static inline BOOL is_num_string(uint32_t *pval, const JSString *p) len = p->len; if (len == 0 || len > 10) - return FALSE; + return false; c = string_get(p, 0); if (is_num(c)) { if (c == '0') { if (len != 1) - return FALSE; + return false; n = 0; } else { n = c - '0'; for(i = 1; i < len; i++) { c = string_get(p, i); if (!is_num(c)) - return FALSE; + return false; n64 = (uint64_t)n * 10 + (c - '0'); if ((n64 >> 32) != 0) - return FALSE; + return false; n = n64; } } *pval = n; - return TRUE; + return true; } else { - return FALSE; + return false; } } @@ -2549,34 +2685,34 @@ static uint32_t hash_string(const JSString *str, uint32_t h) return h; } -static __maybe_unused void JS_DumpChar(JSRuntime *rt, int c, int sep) +static __maybe_unused void JS_DumpString(JSRuntime *rt, + const JSString *p) { - if (c == sep || c == '\\') { - putchar('\\'); - putchar(c); - } else if (c >= ' ' && c <= 126) { - putchar(c); - } else if (c == '\n') { - putchar('\\'); - putchar('n'); - } else { - printf("\\u%04x", c); - } -} - -static __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p) -{ - int i, sep; + int i, c, sep; if (p == NULL) { printf(""); return; } - printf("%d", p->header.ref_count); - sep = (p->header.ref_count == 1) ? '\"' : '\''; + if (p->header.ref_count != 1) + printf("%d", p->header.ref_count); + if (p->is_wide_char) + putchar('L'); + sep = '\"'; putchar(sep); for(i = 0; i < p->len; i++) { - JS_DumpChar(rt, string_get(p, i), sep); + c = string_get(p, i); + if (c == sep || c == '\\') { + putchar('\\'); + putchar(c); + } else if (c >= ' ' && c <= 126) { + putchar(c); + } else if (c == '\n') { + putchar('\\'); + putchar('n'); + } else { + printf("\\u%04x", c); + } } putchar(sep); } @@ -2725,11 +2861,7 @@ static JSAtomKindEnum JS_AtomGetKind(JSContext *ctx, JSAtom v) default: abort(); } -} - -static BOOL JS_AtomIsString(JSContext *ctx, JSAtom v) -{ - return JS_AtomGetKind(ctx, v) == JS_ATOM_KIND_STRING; + return (JSAtomKindEnum){-1}; // pacify compiler } static JSAtom js_get_atom_index(JSRuntime *rt, JSAtomStruct *p) @@ -2757,9 +2889,6 @@ static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type) JSAtomStruct *p; int len; -#if 0 - printf("__JS_NewAtom: "); JS_DumpString(rt, str); printf("\n"); -#endif if (atom_type < JS_ATOM_TYPE_SYMBOL) { /* str is not NULL */ if (str->atom_type == atom_type) { @@ -2825,7 +2954,7 @@ static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type) } p->header.ref_count = 1; /* not refcounted */ p->atom_type = JS_ATOM_TYPE_SYMBOL; -#ifdef DUMP_LEAKS +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS list_add_tail(&p->link, &rt->string_list); #endif new_array[0] = p; @@ -2858,7 +2987,7 @@ static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type) p->header.ref_count = 1; p->is_wide_char = str->is_wide_char; p->len = str->len; -#ifdef DUMP_LEAKS +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS list_add_tail(&p->link, &rt->string_list); #endif memcpy(p->u.str8, str->u.str8, (str->len << str->is_wide_char) + @@ -2872,7 +3001,7 @@ static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type) p->header.ref_count = 1; p->is_wide_char = 1; /* Hack to represent NULL as a JSString */ p->len = 0; -#ifdef DUMP_LEAKS +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS list_add_tail(&p->link, &rt->string_list); #endif } @@ -2885,6 +3014,7 @@ static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type) p->hash = h; p->hash_next = i; /* atom_index */ p->atom_type = atom_type; + p->first_weak_ref = NULL; rt->atom_count++; @@ -2906,7 +3036,8 @@ static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type) return i; } -/* only works with zero terminated 8 bit strings */ +// XXX: `str` must be pure ASCII. No UTF-8 encoded strings +// XXX: `str` must not be the string representation of a small integer static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len, int atom_type) { @@ -2919,7 +3050,7 @@ static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len, return __JS_NewAtom(rt, p, atom_type); } -/* Warning: str must be ASCII only */ +// XXX: `str` must be raw 8-bit contents. No UTF-8 encoded strings static JSAtom __JS_FindAtom(JSRuntime *rt, const char *str, size_t len, int atom_type) { @@ -2948,12 +3079,6 @@ static JSAtom __JS_FindAtom(JSRuntime *rt, const char *str, size_t len, static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p) { -#if 0 /* JS_ATOM_NULL is not refcounted: __JS_AtomIsConst() includes 0 */ - if (unlikely(i == JS_ATOM_NULL)) { - p->header.ref_count = INT32_MAX / 2; - return; - } -#endif uint32_t i = p->hash_next; /* atom_index */ if (p->atom_type != JS_ATOM_TYPE_SYMBOL) { JSAtomStruct *p0, *p1; @@ -2980,8 +3105,11 @@ static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p) /* insert in free atom list */ rt->atom_array[i] = atom_set_free(rt->atom_free_index); rt->atom_free_index = i; + if (unlikely(p->first_weak_ref)) { + reset_weak_ref(rt, &p->first_weak_ref); + } /* free the string structure */ -#ifdef DUMP_LEAKS +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS list_del(&p->link); #endif js_free_rt(rt, p); @@ -3014,13 +3142,14 @@ static JSAtom JS_NewAtomStr(JSContext *ctx, JSString *p) return __JS_NewAtom(rt, p, JS_ATOM_TYPE_STRING); } -/* str is UTF-8 encoded */ +/* `str` may be pure ASCII or UTF-8 encoded */ JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len) { JSValue val; if (len == 0 || !is_digit(*str)) { - // XXX: this will not work if UTF-8 encoded str contains non ASCII bytes + // TODO(chqrlie): this does not work if `str` has UTF-8 encoded contents + // bug example: `({ "\u00c3\u00a9": 1 }).\u00e9` evaluates to `1`. JSAtom atom = __JS_FindAtom(ctx->rt, str, len, JS_ATOM_TYPE_STRING); if (atom) return atom; @@ -3031,6 +3160,7 @@ JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len) return JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(val)); } +/* `str` may be pure ASCII or UTF-8 encoded */ JSAtom JS_NewAtom(JSContext *ctx, const char *str) { return JS_NewAtomLen(ctx, str, strlen(str)); @@ -3041,10 +3171,9 @@ JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n) if (n <= JS_ATOM_MAX_INT) { return __JS_AtomFromUInt32(n); } else { - char buf[11]; - JSValue val; - snprintf(buf, sizeof(buf), "%u", n); - val = JS_NewString(ctx, buf); + char buf[16]; + size_t len = u32toa(buf, n); + JSValue val = js_new_string8_len(ctx, buf, len); if (JS_IsException(val)) return JS_ATOM_NULL; return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val), @@ -3058,9 +3187,8 @@ static JSAtom JS_NewAtomInt64(JSContext *ctx, int64_t n) return __JS_AtomFromUInt32((uint32_t)n); } else { char buf[24]; - JSValue val; - snprintf(buf, sizeof(buf), "%" PRId64 , n); - val = JS_NewString(ctx, buf); + size_t len = i64toa(buf, n); + JSValue val = js_new_string8_len(ctx, buf, len); if (JS_IsException(val)) return JS_ATOM_NULL; return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val), @@ -3069,7 +3197,7 @@ static JSAtom JS_NewAtomInt64(JSContext *ctx, int64_t n) } /* 'p' is freed */ -static JSValue JS_NewSymbol(JSContext *ctx, JSString *p, int atom_type) +static JSValue JS_NewSymbolInternal(JSContext *ctx, JSString *p, int atom_type) { JSRuntime *rt = ctx->rt; JSAtom atom; @@ -3089,8 +3217,17 @@ static JSValue JS_NewSymbolFromAtom(JSContext *ctx, JSAtom descr, assert(!__JS_AtomIsTaggedInt(descr)); assert(descr < rt->atom_size); p = rt->atom_array[descr]; - JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p)); - return JS_NewSymbol(ctx, p, atom_type); + js_dup(JS_MKPTR(JS_TAG_STRING, p)); + return JS_NewSymbolInternal(ctx, p, atom_type); +} + +/* `description` may be pure ASCII or UTF-8 encoded */ +JSValue JS_NewSymbol(JSContext *ctx, const char *description, bool is_global) +{ + JSAtom atom = JS_NewAtom(ctx, description); + if (atom == JS_ATOM_NULL) + return JS_EXCEPTION; + return JS_NewSymbolFromAtom(ctx, atom, is_global ? JS_ATOM_TYPE_GLOBAL_SYMBOL : JS_ATOM_TYPE_SYMBOL); } #define ATOM_GET_STR_BUF_SIZE 64 @@ -3101,42 +3238,32 @@ static const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size, { if (__JS_AtomIsTaggedInt(atom)) { snprintf(buf, buf_size, "%u", __JS_AtomToUInt32(atom)); - } else { - JSAtomStruct *p; + } else if (atom == JS_ATOM_NULL) { + snprintf(buf, buf_size, ""); + } else if (atom >= rt->atom_size) { assert(atom < rt->atom_size); - if (atom == JS_ATOM_NULL) { - snprintf(buf, buf_size, ""); - } else { - int i, c; - char *q; - JSString *str; - - q = buf; - p = rt->atom_array[atom]; + snprintf(buf, buf_size, "", atom); + } else { + JSAtomStruct *p = rt->atom_array[atom]; + *buf = '\0'; + if (atom_is_free(p)) { assert(!atom_is_free(p)); - str = p; - if (str) { - if (!str->is_wide_char) { - /* special case ASCII strings */ - c = 0; - for(i = 0; i < str->len; i++) { - c |= str->u.str8[i]; - } - if (c < 0x80) - return (const char *)str->u.str8; - } + snprintf(buf, buf_size, "", atom); + } else if (p != NULL) { + JSString *str = p; + if (str->is_wide_char) { + /* encode surrogates correctly */ + utf8_encode_buf16(buf, buf_size, str->u.str16, str->len); + } else { + /* special case ASCII strings */ + int i, c = 0; for(i = 0; i < str->len; i++) { - c = string_get(str, i); - if ((q - buf) >= buf_size - UTF8_CHAR_LEN_MAX) - break; - if (c < 128) { - *q++ = c; - } else { - q += unicode_to_utf8((uint8_t *)q, c); - } + c |= str->u.str8[i]; } + if (c < 0x80) + return (const char *)str->u.str8; + utf8_encode_buf8(buf, buf_size, str->u.str8, str->len); } - *q = '\0'; } } return buf; @@ -3147,13 +3274,13 @@ static const char *JS_AtomGetStr(JSContext *ctx, char *buf, int buf_size, JSAtom return JS_AtomGetStrRT(ctx->rt, buf, buf_size, atom); } -static JSValue __JS_AtomToValue(JSContext *ctx, JSAtom atom, BOOL force_string) +static JSValue __JS_AtomToValue(JSContext *ctx, JSAtom atom, bool force_string) { char buf[ATOM_GET_STR_BUF_SIZE]; if (__JS_AtomIsTaggedInt(atom)) { - snprintf(buf, sizeof(buf), "%u", __JS_AtomToUInt32(atom)); - return JS_NewString(ctx, buf); + size_t len = u32toa(buf, __JS_AtomToUInt32(atom)); + return js_new_string8_len(ctx, buf, len); } else { JSRuntime *rt = ctx->rt; JSAtomStruct *p; @@ -3167,30 +3294,30 @@ static JSValue __JS_AtomToValue(JSContext *ctx, JSAtom atom, BOOL force_string) p = rt->atom_array[JS_ATOM_empty_string]; } ret_string: - return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p)); + return js_dup(JS_MKPTR(JS_TAG_STRING, p)); } else { - return JS_DupValue(ctx, JS_MKPTR(JS_TAG_SYMBOL, p)); + return js_dup(JS_MKPTR(JS_TAG_SYMBOL, p)); } } } JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom) { - return __JS_AtomToValue(ctx, atom, FALSE); + return __JS_AtomToValue(ctx, atom, false); } JSValue JS_AtomToString(JSContext *ctx, JSAtom atom) { - return __JS_AtomToValue(ctx, atom, TRUE); + return __JS_AtomToValue(ctx, atom, true); } -/* return TRUE if the atom is an array index (i.e. 0 <= index <= +/* return true if the atom is an array index (i.e. 0 <= index <= 2^32-2 and return its value */ -static BOOL JS_AtomIsArrayIndex(JSContext *ctx, uint32_t *pval, JSAtom atom) +static bool JS_AtomIsArrayIndex(JSContext *ctx, uint32_t *pval, JSAtom atom) { if (__JS_AtomIsTaggedInt(atom)) { *pval = __JS_AtomToUInt32(atom); - return TRUE; + return true; } else { JSRuntime *rt = ctx->rt; JSAtomStruct *p; @@ -3201,10 +3328,10 @@ static BOOL JS_AtomIsArrayIndex(JSContext *ctx, uint32_t *pval, JSAtom atom) if (p->atom_type == JS_ATOM_TYPE_STRING && is_num_string(&val, p) && val != -1) { *pval = val; - return TRUE; + return true; } else { *pval = 0; - return FALSE; + return false; } } } @@ -3221,7 +3348,7 @@ static JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom) JSValue num, str; if (__JS_AtomIsTaggedInt(atom)) - return JS_NewInt32(ctx, __JS_AtomToUInt32(atom)); + return js_int32(__JS_AtomToUInt32(atom)); assert(atom < rt->atom_size); p1 = rt->atom_array[atom]; if (p1->atom_type != JS_ATOM_TYPE_STRING) @@ -3263,7 +3390,7 @@ static JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom) /* -0 case is specific */ if (c == '0' && len == 2) { minus_zero: - return __JS_NewFloat64(ctx, -0.0); + return js_float64(-0.0); } } if (!is_num(c)) { @@ -3272,8 +3399,6 @@ static JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom) return JS_UNDEFINED; } } - /* XXX: bignum: would be better to only accept integer to avoid - relying on current floating point precision */ /* this is ECMA CanonicalNumericIndexString primitive */ num = JS_ToNumber(ctx, JS_MKPTR(JS_TAG_STRING, p)); if (JS_IsException(num)) @@ -3283,9 +3408,9 @@ static JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom) JS_FreeValue(ctx, num); return str; } - ret = js_string_compare(ctx, p, JS_VALUE_GET_STRING(str)); + ret = js_string_eq(p, JS_VALUE_GET_STRING(str)); JS_FreeValue(ctx, str); - if (ret == 0) { + if (ret) { return num; } else { JS_FreeValue(ctx, num); @@ -3293,17 +3418,17 @@ static JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom) } } -/* return -1 if exception or TRUE/FALSE */ +/* return -1 if exception or true/false */ static int JS_AtomIsNumericIndex(JSContext *ctx, JSAtom atom) { JSValue num; num = JS_AtomIsNumericIndex1(ctx, atom); if (likely(JS_IsUndefined(num))) - return FALSE; + return false; if (JS_IsException(num)) return -1; JS_FreeValue(ctx, num); - return TRUE; + return true; } void JS_FreeAtom(JSContext *ctx, JSAtom v) @@ -3318,15 +3443,15 @@ void JS_FreeAtomRT(JSRuntime *rt, JSAtom v) __JS_FreeAtom(rt, v); } -/* return TRUE if 'v' is a symbol with a string description */ -static BOOL JS_AtomSymbolHasDescription(JSContext *ctx, JSAtom v) +/* return true if 'v' is a symbol with a string description */ +static bool JS_AtomSymbolHasDescription(JSContext *ctx, JSAtom v) { JSRuntime *rt; JSAtomStruct *p; rt = ctx->rt; if (__JS_AtomIsTaggedInt(v)) - return FALSE; + return false; p = rt->atom_array[v]; return (((p->atom_type == JS_ATOM_TYPE_SYMBOL && p->hash == JS_ATOM_HASH_SYMBOL) || @@ -3387,6 +3512,8 @@ const char *JS_AtomToCString(JSContext *ctx, JSAtom atom) } /* return a string atom containing name concatenated with str1 */ +/* `str1` may be pure ASCII or UTF-8 encoded */ +// TODO(chqrlie): use string concatenation instead of UTF-8 conversion static JSAtom js_atom_concat_str(JSContext *ctx, JSAtom name, const char *str1) { JSValue str; @@ -3422,49 +3549,38 @@ static JSAtom js_atom_concat_str(JSContext *ctx, JSAtom name, const char *str1) static JSAtom js_atom_concat_num(JSContext *ctx, JSAtom name, uint32_t n) { char buf[16]; - snprintf(buf, sizeof(buf), "%u", n); + u32toa(buf, n); return js_atom_concat_str(ctx, name, buf); } -static inline BOOL JS_IsEmptyString(JSValueConst v) +static inline bool JS_IsEmptyString(JSValue v) { return JS_VALUE_GET_TAG(v) == JS_TAG_STRING && JS_VALUE_GET_STRING(v)->len == 0; } /* JSClass support */ -#ifdef CONFIG_ATOMICS -static pthread_mutex_t js_class_id_mutex = PTHREAD_MUTEX_INITIALIZER; -#endif - -/* a new class ID is allocated if *pclass_id != 0 */ -JSClassID JS_NewClassID(JSClassID *pclass_id) +/* a new class ID is allocated if *pclass_id == 0, otherwise *pclass_id is left unchanged */ +JSClassID JS_NewClassID(JSRuntime *rt, JSClassID *pclass_id) { - JSClassID class_id; -#ifdef CONFIG_ATOMICS - pthread_mutex_lock(&js_class_id_mutex); -#endif - class_id = *pclass_id; + JSClassID class_id = *pclass_id; if (class_id == 0) { - class_id = js_class_id_alloc++; + class_id = rt->js_class_id_alloc++; *pclass_id = class_id; } -#ifdef CONFIG_ATOMICS - pthread_mutex_unlock(&js_class_id_mutex); -#endif return class_id; } JSClassID JS_GetClassID(JSValue v) { - JSObject *p; - if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT) - return JS_INVALID_CLASS_ID; - p = JS_VALUE_GET_OBJ(v); - return p->class_id; + JSObject *p; + if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT) + return JS_INVALID_CLASS_ID; + p = JS_VALUE_GET_OBJ(v); + return p->class_id; } -BOOL JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id) +bool JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id) { return (class_id < rt->class_count && rt->class_array[class_id].class_id != 0); @@ -3526,6 +3642,7 @@ int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def) int ret, len; JSAtom name; + // XXX: class_def->class_name must be raw 8-bit contents. No UTF-8 encoded strings len = strlen(class_def->class_name); name = __JS_FindAtom(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING); if (name == JS_ATOM_NULL) { @@ -3538,13 +3655,11 @@ int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def) return ret; } -static JSValue js_new_string8(JSContext *ctx, const uint8_t *buf, int len) +// XXX: `buf` contains raw 8-bit data, no UTF-8 decoding is performed +// XXX: no special case for len == 0 +static JSValue js_new_string8_len(JSContext *ctx, const char *buf, int len) { JSString *str; - - if (len <= 0) { - return JS_AtomToString(ctx, JS_ATOM_empty_string); - } str = js_alloc_string(ctx, len, 0); if (!str) return JS_EXCEPTION; @@ -3553,7 +3668,14 @@ static JSValue js_new_string8(JSContext *ctx, const uint8_t *buf, int len) return JS_MKPTR(JS_TAG_STRING, str); } -static JSValue js_new_string16(JSContext *ctx, const uint16_t *buf, int len) +// XXX: `buf` contains raw 8-bit data, no UTF-8 decoding is performed +// XXX: no special case for the empty string +static inline JSValue js_new_string8(JSContext *ctx, const char *str) +{ + return js_new_string8_len(ctx, str, strlen(str)); +} + +static JSValue js_new_string16_len(JSContext *ctx, const uint16_t *buf, int len) { JSString *str; str = js_alloc_string(ctx, len, 1); @@ -3566,11 +3688,11 @@ static JSValue js_new_string16(JSContext *ctx, const uint16_t *buf, int len) static JSValue js_new_string_char(JSContext *ctx, uint16_t c) { if (c < 0x100) { - uint8_t ch8 = c; - return js_new_string8(ctx, &ch8, 1); + char ch8 = c; + return js_new_string8_len(ctx, &ch8, 1); } else { uint16_t ch16 = c; - return js_new_string16(ctx, &ch16, 1); + return js_new_string16_len(ctx, &ch16, 1); } } @@ -3578,9 +3700,12 @@ static JSValue js_sub_string(JSContext *ctx, JSString *p, int start, int end) { int len = end - start; if (start == 0 && end == p->len) { - return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p)); + return js_dup(JS_MKPTR(JS_TAG_STRING, p)); + } + if (len <= 0) { + return JS_AtomToString(ctx, JS_ATOM_empty_string); } - if (p->is_wide_char && len > 0) { + if (p->is_wide_char) { JSString *str; int i; uint16_t c = 0; @@ -3588,7 +3713,7 @@ static JSValue js_sub_string(JSContext *ctx, JSString *p, int start, int end) c |= p->u.str16[i]; } if (c > 0xFF) - return js_new_string16(ctx, p->u.str16 + start, len); + return js_new_string16_len(ctx, p->u.str16 + start, len); str = js_alloc_string(ctx, len, 0); if (!str) @@ -3599,7 +3724,7 @@ static JSValue js_sub_string(JSContext *ctx, JSString *p, int start, int end) str->u.str8[len] = '\0'; return JS_MKPTR(JS_TAG_STRING, str); } else { - return js_new_string8(ctx, p->u.str8 + start, len); + return js_new_string8_len(ctx, (const char *)(p->u.str8 + start), len); } } @@ -3629,7 +3754,7 @@ static int string_buffer_init2(JSContext *ctx, StringBuffer *s, int size, s->size = 0; return s->error_status = -1; } -#ifdef DUMP_LEAKS +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS /* the StringBuffer may reallocate the JSString, only link it at the end */ list_del(&s->str->link); #endif @@ -3688,7 +3813,7 @@ static no_inline int string_buffer_realloc(StringBuffer *s, int new_len, int c) return -1; if (new_len > JS_STRING_LEN_MAX) { - JS_ThrowInternalError(s->ctx, "string too long"); + JS_ThrowRangeError(s->ctx, "invalid string length"); return string_buffer_set_error(s); } new_size = min_int(max_int(new_len, s->size * 3 / 2), JS_STRING_LEN_MAX); @@ -3848,7 +3973,7 @@ static int string_buffer_concat(StringBuffer *s, const JSString *p, return string_buffer_write8(s, p->u.str8 + from, to - from); } -static int string_buffer_concat_value(StringBuffer *s, JSValueConst v) +static int string_buffer_concat_value(StringBuffer *s, JSValue v) { JSString *p; JSValue v1; @@ -3929,7 +4054,7 @@ static JSValue string_buffer_end(StringBuffer *s) } if (!s->is_wide_char) str->u.str8[s->len] = 0; -#ifdef DUMP_LEAKS +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS list_add_tail(&str->link, &s->ctx->rt->string_list); #endif str->is_wide_char = s->is_wide_char; @@ -3941,61 +4066,44 @@ static JSValue string_buffer_end(StringBuffer *s) /* create a string from a UTF-8 buffer */ JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len) { - const uint8_t *p, *p_end, *p_start, *p_next; - uint32_t c; - StringBuffer b_s, *b = &b_s; - size_t len1; + JSString *str; + size_t len; + int kind; - p_start = (const uint8_t *)buf; - p_end = p_start + buf_len; - p = p_start; - while (p < p_end && *p < 128) - p++; - len1 = p - p_start; - if (len1 > JS_STRING_LEN_MAX) - return JS_ThrowInternalError(ctx, "string too long"); - if (p == p_end) { - /* ASCII string */ - return js_new_string8(ctx, (const uint8_t *)buf, buf_len); - } else { - if (string_buffer_init(ctx, b, buf_len)) - goto fail; - string_buffer_write8(b, p_start, len1); - while (p < p_end) { - if (*p < 128) { - string_buffer_putc8(b, *p++); - } else { - /* parse utf-8 sequence, return 0xFFFFFFFF for error */ - c = unicode_from_utf8(p, p_end - p, &p_next); - if (c < 0x10000) { - p = p_next; - } else if (c <= 0x10FFFF) { - p = p_next; - /* surrogate pair */ - string_buffer_putc16(b, get_hi_surrogate(c)); - c = get_lo_surrogate(c); - } else { - /* invalid char */ - c = 0xfffd; - /* skip the invalid chars */ - /* XXX: seems incorrect. Why not just use c = *p++; ? */ - while (p < p_end && (*p >= 0x80 && *p < 0xc0)) - p++; - if (p < p_end) { - p++; - while (p < p_end && (*p >= 0x80 && *p < 0xc0)) - p++; - } - } - string_buffer_putc16(b, c); - } - } + if (buf_len <= 0) { + return JS_AtomToString(ctx, JS_ATOM_empty_string); } - return string_buffer_end(b); + /* Compute string kind and length: 7-bit, 8-bit, 16-bit, 16-bit UTF-16 */ + kind = utf8_scan(buf, buf_len, &len); + if (len > JS_STRING_LEN_MAX) + return JS_ThrowRangeError(ctx, "invalid string length"); - fail: - string_buffer_free(b); - return JS_EXCEPTION; + switch (kind) { + case UTF8_PLAIN_ASCII: + str = js_alloc_string(ctx, len, 0); + if (!str) + return JS_EXCEPTION; + memcpy(str->u.str8, buf, len); + str->u.str8[len] = '\0'; + break; + case UTF8_NON_ASCII: + /* buf contains non-ASCII code-points, but limited to 8-bit values */ + str = js_alloc_string(ctx, len, 0); + if (!str) + return JS_EXCEPTION; + utf8_decode_buf8(str->u.str8, len + 1, buf, buf_len); + break; + default: + // This causes a potential problem in JS_ThrowError if message is invalid + //if (kind & UTF8_HAS_ERRORS) + // return JS_ThrowRangeError(ctx, "invalid UTF-8 sequence"); + str = js_alloc_string(ctx, len, 1); + if (!str) + return JS_EXCEPTION; + utf8_decode_buf16(str->u.str16, len, buf, buf_len); + break; + } + return JS_MKPTR(JS_TAG_STRING, str); } static JSValue JS_ConcatString3(JSContext *ctx, const char *str1, @@ -4029,11 +4137,7 @@ static JSValue JS_ConcatString3(JSContext *ctx, const char *str1, return JS_EXCEPTION; } -JSValue JS_NewString(JSContext *ctx, const char *str) -{ - return JS_NewStringLen(ctx, str, strlen(str)); -} - +/* `str` may be pure ASCII or UTF-8 encoded */ JSValue JS_NewAtomString(JSContext *ctx, const char *str) { JSAtom atom = JS_NewAtom(ctx, str); @@ -4047,21 +4151,41 @@ JSValue JS_NewAtomString(JSContext *ctx, const char *str) /* return (NULL, 0) if exception. */ /* return pointer into a JSString with a live ref_count */ /* cesu8 determines if non-BMP1 codepoints are encoded as 1 or 2 utf-8 sequences */ -const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, BOOL cesu8) +const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValue val1, bool cesu8) { JSValue val; JSString *str, *str_new; int pos, len, c, c1; + JSObject *p; uint8_t *q; - if (JS_VALUE_GET_TAG(val1) != JS_TAG_STRING) { - val = JS_ToString(ctx, val1); - if (JS_IsException(val)) - goto fail; - } else { - val = JS_DupValue(ctx, val1); + if (JS_VALUE_GET_TAG(val1) == JS_TAG_STRING) { + val = js_dup(val1); + goto go; } + val = JS_ToString(ctx, val1); + if (!JS_IsException(val)) + goto go; + + // Stringification can fail when there is an exception pending, + // e.g. a stack overflow InternalError. Special-case exception + // objects to make debugging easier, look up the .message property + // and stringify that. + if (JS_VALUE_GET_TAG(val1) != JS_TAG_OBJECT) + goto fail; + + p = JS_VALUE_GET_OBJ(val1); + if (p->class_id != JS_CLASS_ERROR) + goto fail; + + val = JS_GetProperty(ctx, val1, JS_ATOM_message); + if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING) { + JS_FreeValue(ctx, val); + goto fail; + } + +go: str = JS_VALUE_GET_STRING(val); len = str->len; if (!str->is_wide_char) { @@ -4126,7 +4250,7 @@ const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, BO /* c = 0xfffd; */ /* error */ } } - q += unicode_to_utf8(q, c); + q += utf8_encode(q, c); } } } @@ -4193,21 +4317,20 @@ static int js_string_memcmp(const JSString *p1, const JSString *p2, int len) return res; } +static bool js_string_eq(const JSString *p1, const JSString *p2) { + if (p1->len != p2->len) + return false; + return js_string_memcmp(p1, p2, p1->len) == 0; +} + /* return < 0, 0 or > 0 */ -static int js_string_compare(JSContext *ctx, - const JSString *p1, const JSString *p2) +static int js_string_compare(const JSString *p1, const JSString *p2) { int res, len; len = min_int(p1->len, p2->len); res = js_string_memcmp(p1, p2, len); - if (res == 0) { - if (p1->len == p2->len) - res = 0; - else if (p1->len < p2->len) - res = -1; - else - res = 1; - } + if (res == 0) + res = compare_u32(p1->len, p2->len); return res; } @@ -4233,7 +4356,7 @@ static JSValue JS_ConcatString1(JSContext *ctx, len = p1->len + p2->len; if (len > JS_STRING_LEN_MAX) - return JS_ThrowInternalError(ctx, "string too long"); + return JS_ThrowRangeError(ctx, "invalid string length"); is_wide_char = p1->is_wide_char | p2->is_wide_char; p = js_alloc_string(ctx, len, is_wide_char); if (!p) @@ -4249,43 +4372,7 @@ static JSValue JS_ConcatString1(JSContext *ctx, return JS_MKPTR(JS_TAG_STRING, p); } -static BOOL JS_ConcatStringInPlace(JSContext *ctx, JSString *p1, JSValueConst op2) { - if (JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) { - JSString *p2 = JS_VALUE_GET_STRING(op2); - size_t size1; - - if (p2->len == 0) - return TRUE; - if (p1->header.ref_count != 1) - return FALSE; - size1 = js_malloc_usable_size(ctx, p1); - if (p1->is_wide_char) { - if (size1 >= sizeof(*p1) + ((p1->len + p2->len) << 1)) { - if (p2->is_wide_char) { - memcpy(p1->u.str16 + p1->len, p2->u.str16, p2->len << 1); - p1->len += p2->len; - return TRUE; - } else { - size_t i; - for (i = 0; i < p2->len; i++) { - p1->u.str16[p1->len++] = p2->u.str8[i]; - } - return TRUE; - } - } - } else if (!p2->is_wide_char) { - if (size1 >= sizeof(*p1) + p1->len + p2->len + 1) { - memcpy(p1->u.str8 + p1->len, p2->u.str8, p2->len); - p1->len += p2->len; - p1->u.str8[p1->len] = '\0'; - return TRUE; - } - } - } - return FALSE; -} - -/* op1 and op2 are converted to strings. For convenience, op1 or op2 = +/* op1 and op2 are converted to strings. For convience, op1 or op2 = JS_EXCEPTION are accepted and return JS_EXCEPTION. */ static JSValue JS_ConcatString(JSContext *ctx, JSValue op1, JSValue op2) { @@ -4307,11 +4394,27 @@ static JSValue JS_ConcatString(JSContext *ctx, JSValue op1, JSValue op2) } } p1 = JS_VALUE_GET_STRING(op1); - if (JS_ConcatStringInPlace(ctx, p1, op2)) { + p2 = JS_VALUE_GET_STRING(op2); + + /* XXX: could also check if p1 is empty */ + if (p2->len == 0) { + goto ret_op1; + } + if (p1->header.ref_count == 1 && p1->is_wide_char == p2->is_wide_char + && js_malloc_usable_size(ctx, p1) >= sizeof(*p1) + ((p1->len + p2->len) << p2->is_wide_char) + 1 - p1->is_wide_char) { + /* Concatenate in place in available space at the end of p1 */ + if (p1->is_wide_char) { + memcpy(p1->u.str16 + p1->len, p2->u.str16, p2->len << 1); + p1->len += p2->len; + } else { + memcpy(p1->u.str8 + p1->len, p2->u.str8, p2->len); + p1->len += p2->len; + p1->u.str8[p1->len] = '\0'; + } + ret_op1: JS_FreeValue(ctx, op2); return op1; } - p2 = JS_VALUE_GET_STRING(op2); ret = JS_ConcatString1(ctx, p1, p2); JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); @@ -4447,7 +4550,7 @@ static no_inline JSShape *js_new_shape2(JSContext *ctx, JSObject *proto, sh->header.ref_count = 1; add_gc_object(rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE); if (proto) - JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, proto)); + js_dup(JS_MKPTR(JS_TAG_OBJECT, proto)); sh->proto = proto; memset(prop_hash_end(sh) - hash_size, 0, sizeof(prop_hash_end(sh)[0]) * hash_size); @@ -4458,8 +4561,8 @@ static no_inline JSShape *js_new_shape2(JSContext *ctx, JSObject *proto, /* insert in the hash table */ sh->hash = shape_initial_hash(proto); - sh->is_hashed = TRUE; - sh->has_small_array_index = FALSE; + sh->is_hashed = true; + sh->has_small_array_index = false; js_shape_hash_link(ctx->rt, sh); return sh; } @@ -4490,9 +4593,9 @@ static JSShape *js_clone_shape(JSContext *ctx, JSShape *sh1) sh = get_shape_from_alloc(sh_alloc, hash_size); sh->header.ref_count = 1; add_gc_object(ctx->rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE); - sh->is_hashed = FALSE; + sh->is_hashed = false; if (sh->proto) { - JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto)); + js_dup(JS_MKPTR(JS_TAG_OBJECT, sh->proto)); } for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) { JS_DupAtom(ctx, pr->atom); @@ -4548,7 +4651,6 @@ static no_inline int resize_properties(JSContext *ctx, JSShape **psh, JSShapeProperty *pr; void *sh_alloc; intptr_t h; - JSShape *old_sh; sh = *psh; new_size = max_int(count, sh->prop_size * 3 / 2); @@ -4564,21 +4666,19 @@ static no_inline int resize_properties(JSContext *ctx, JSShape **psh, new_hash_size = sh->prop_hash_mask + 1; while (new_hash_size < new_size) new_hash_size = 2 * new_hash_size; - /* resize the property shapes. Using js_realloc() is not possible in - case the GC runs during the allocation */ - old_sh = sh; - sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size)); - if (!sh_alloc) - return -1; - sh = get_shape_from_alloc(sh_alloc, new_hash_size); - list_del(&old_sh->header.link); - /* copy all the shape properties */ - memcpy(sh, old_sh, - sizeof(JSShape) + sizeof(sh->prop[0]) * old_sh->prop_count); - list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); - if (new_hash_size != (sh->prop_hash_mask + 1)) { + JSShape *old_sh; /* resize the hash table and the properties */ + old_sh = sh; + sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size)); + if (!sh_alloc) + return -1; + sh = get_shape_from_alloc(sh_alloc, new_hash_size); + list_del(&old_sh->header.link); + /* copy all the fields and the properties */ + memcpy(sh, old_sh, + sizeof(JSShape) + sizeof(sh->prop[0]) * old_sh->prop_count); + list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); new_hash_mask = new_hash_size - 1; sh->prop_hash_mask = new_hash_mask; memset(prop_hash_end(sh) - new_hash_size, 0, @@ -4590,12 +4690,20 @@ static no_inline int resize_properties(JSContext *ctx, JSShape **psh, prop_hash_end(sh)[-h - 1] = i + 1; } } + js_free(ctx, get_alloc_from_shape(old_sh)); } else { - /* just copy the previous hash table */ - memcpy(prop_hash_end(sh) - new_hash_size, prop_hash_end(old_sh) - new_hash_size, - sizeof(prop_hash_end(sh)[0]) * new_hash_size); + /* only resize the properties */ + list_del(&sh->header.link); + sh_alloc = js_realloc(ctx, get_alloc_from_shape(sh), + get_shape_size(new_hash_size, new_size)); + if (unlikely(!sh_alloc)) { + /* insert again in the GC list */ + list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); + return -1; + } + sh = get_shape_from_alloc(sh_alloc, new_hash_size); + list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); } - js_free(ctx, get_alloc_from_shape(old_sh)); *psh = sh; sh->prop_size = new_size; return 0; @@ -4819,7 +4927,7 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas if (unlikely(!p)) goto fail; p->class_id = class_id; - p->extensible = TRUE; + p->extensible = true; p->free_mark = 0; p->is_exotic = 0; p->fast_array = 0; @@ -4858,7 +4966,7 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas pr = add_property(ctx, p, JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_LENGTH); } - pr->u.value = JS_NewInt32(ctx, 0); + pr->u.value = js_int32(0); } break; case JS_CLASS_C_FUNCTION: @@ -4874,6 +4982,7 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas case JS_CLASS_UINT32_ARRAY: case JS_CLASS_BIG_INT64_ARRAY: case JS_CLASS_BIG_UINT64_ARRAY: + case JS_CLASS_FLOAT16_ARRAY: case JS_CLASS_FLOAT32_ARRAY: case JS_CLASS_FLOAT64_ARRAY: p->is_exotic = 1; @@ -4891,10 +5000,6 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas case JS_CLASS_SYMBOL: case JS_CLASS_DATE: case JS_CLASS_BIG_INT: -#ifdef CONFIG_BIGNUM - case JS_CLASS_BIG_FLOAT: - case JS_CLASS_BIG_DECIMAL: -#endif p->u.object_data = JS_UNDEFINED; goto set_exotic; case JS_CLASS_REGEXP: @@ -4913,7 +5018,7 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas return JS_MKPTR(JS_TAG_OBJECT, p); } -static JSObject *get_proto_obj(JSValueConst proto_val) +static JSObject *get_proto_obj(JSValue proto_val) { if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT) return NULL; @@ -4922,7 +5027,7 @@ static JSObject *get_proto_obj(JSValueConst proto_val) } /* WARNING: proto must be an object or JS_NULL */ -JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto_val, +JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValue proto_val, JSClassID class_id) { JSShape *sh; @@ -4940,8 +5045,7 @@ JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto_val, return JS_NewObjectFromShape(ctx, sh, class_id); } -#if 0 -static JSValue JS_GetObjectData(JSContext *ctx, JSValueConst obj) +static int JS_SetObjectData(JSContext *ctx, JSValue obj, JSValue val) { JSObject *p; @@ -4954,34 +5058,6 @@ static JSValue JS_GetObjectData(JSContext *ctx, JSValueConst obj) case JS_CLASS_SYMBOL: case JS_CLASS_DATE: case JS_CLASS_BIG_INT: -#ifdef CONFIG_BIGNUM - case JS_CLASS_BIG_FLOAT: - case JS_CLASS_BIG_DECIMAL: -#endif - return JS_DupValue(ctx, p->u.object_data); - } - } - return JS_UNDEFINED; -} -#endif - -static int JS_SetObjectData(JSContext *ctx, JSValueConst obj, JSValue val) -{ - JSObject *p; - - if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { - p = JS_VALUE_GET_OBJ(obj); - switch(p->class_id) { - case JS_CLASS_NUMBER: - case JS_CLASS_STRING: - case JS_CLASS_BOOLEAN: - case JS_CLASS_SYMBOL: - case JS_CLASS_DATE: - case JS_CLASS_BIG_INT: -#ifdef CONFIG_BIGNUM - case JS_CLASS_BIG_FLOAT: - case JS_CLASS_BIG_DECIMAL: -#endif JS_FreeValue(ctx, p->u.object_data); p->u.object_data = val; return 0; @@ -4998,7 +5074,7 @@ JSValue JS_NewObjectClass(JSContext *ctx, int class_id) return JS_NewObjectProtoClass(ctx, ctx->class_proto[class_id], class_id); } -JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto) +JSValue JS_NewObjectProto(JSContext *ctx, JSValue proto) { return JS_NewObjectProtoClass(ctx, proto, JS_CLASS_OBJECT); } @@ -5015,17 +5091,17 @@ JSValue JS_NewObject(JSContext *ctx) return JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_OBJECT); } -static void js_function_set_properties(JSContext *ctx, JSValueConst func_obj, +static void js_function_set_properties(JSContext *ctx, JSValue func_obj, JSAtom name, int len) { /* ES6 feature non compatible with ES5.1: length is configurable */ - JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length, JS_NewInt32(ctx, len), + JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length, js_int32(len), JS_PROP_CONFIGURABLE); JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, JS_AtomToString(ctx, name), JS_PROP_CONFIGURABLE); } -static BOOL js_class_has_bytecode(JSClassID class_id) +static bool js_class_has_bytecode(JSClassID class_id) { return (class_id == JS_CLASS_BYTECODE_FUNCTION || class_id == JS_CLASS_GENERATOR_FUNCTION || @@ -5034,7 +5110,7 @@ static BOOL js_class_has_bytecode(JSClassID class_id) } /* return NULL without exception if not a function or no bytecode */ -static JSFunctionBytecode *JS_GetFunctionBytecode(JSValueConst val) +static JSFunctionBytecode *JS_GetFunctionBytecode(JSValue val) { JSObject *p; if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) @@ -5045,8 +5121,8 @@ static JSFunctionBytecode *JS_GetFunctionBytecode(JSValueConst val) return p->u.func.function_bytecode; } -static void js_method_set_home_object(JSContext *ctx, JSValueConst func_obj, - JSValueConst home_obj) +static void js_method_set_home_object(JSContext *ctx, JSValue func_obj, + JSValue home_obj) { JSObject *p, *p1; JSFunctionBytecode *b; @@ -5063,7 +5139,7 @@ static void js_method_set_home_object(JSContext *ctx, JSValueConst func_obj, JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1)); } if (JS_VALUE_GET_TAG(home_obj) == JS_TAG_OBJECT) - p1 = JS_VALUE_GET_OBJ(JS_DupValue(ctx, home_obj)); + p1 = JS_VALUE_GET_OBJ(js_dup(home_obj)); else p1 = NULL; p->u.func.home_object = p1; @@ -5085,8 +5161,8 @@ static JSValue js_get_function_name(JSContext *ctx, JSAtom name) 'flags'. 'flags' is a bitmask of JS_PROP_HAS_GET and JS_PROP_HAS_SET. Also set the home object of the method. Return < 0 if exception. */ -static int js_method_set_properties(JSContext *ctx, JSValueConst func_obj, - JSAtom name, int flags, JSValueConst home_obj) +static int js_method_set_properties(JSContext *ctx, JSValue func_obj, + JSAtom name, int flags, JSValue home_obj) { JSValue name_str; @@ -5106,10 +5182,11 @@ static int js_method_set_properties(JSContext *ctx, JSValueConst func_obj, } /* Note: at least 'length' arguments will be readable in 'argv' */ +/* `name` may be NULL, pure ASCII or UTF-8 encoded */ static JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func, const char *name, int length, JSCFunctionEnum cproto, int magic, - JSValueConst proto_val) + JSValue proto_val) { JSValue func_obj; JSObject *p; @@ -5150,7 +5227,7 @@ typedef struct JSCFunctionDataRecord { uint8_t length; uint8_t data_len; uint16_t magic; - JSValue data[0]; + JSValue data[]; } JSCFunctionDataRecord; static void js_c_function_data_finalizer(JSRuntime *rt, JSValue val) @@ -5166,7 +5243,7 @@ static void js_c_function_data_finalizer(JSRuntime *rt, JSValue val) } } -static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val, +static void js_c_function_data_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) { JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA); @@ -5179,12 +5256,12 @@ static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val, } } -static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_val, - int argc, JSValueConst *argv, int flags) +static JSValue js_c_function_data_call(JSContext *ctx, JSValue func_obj, + JSValue this_val, + int argc, JSValue *argv, int flags) { JSCFunctionDataRecord *s = JS_GetOpaque(func_obj, JS_CLASS_C_FUNCTION_DATA); - JSValueConst *arg_buf; + JSValue *arg_buf; int i; /* XXX: could add the function on the stack for debug */ @@ -5203,7 +5280,7 @@ static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj, JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func, int length, int magic, int data_len, - JSValueConst *data) + JSValue *data) { JSCFunctionDataRecord *s; JSValue func_obj; @@ -5223,8 +5300,8 @@ JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func, s->data_len = data_len; s->magic = magic; for(i = 0; i < data_len; i++) - s->data[i] = JS_DupValue(ctx, data[i]); - JS_SetOpaque(func_obj, s); + s->data[i] = js_dup(data[i]); + JS_SetOpaqueInternal(func_obj, s); js_function_set_properties(ctx, func_obj, JS_ATOM_empty_string, length); return func_obj; @@ -5313,8 +5390,33 @@ static force_inline JSShapeProperty *find_own_property(JSProperty **ppr, return NULL; } +static force_inline JSShapeProperty* find_own_property_ic(JSProperty** ppr, JSObject* p, + JSAtom atom, uint32_t* offset) +{ + JSShape* sh; + JSShapeProperty *pr, *prop; + intptr_t h, i; + sh = p->shape; + h = (uintptr_t)atom & sh->prop_hash_mask; + h = prop_hash_end(sh)[-h - 1]; + prop = get_shape_prop(sh); + while (h) { + i = h - 1; + pr = &prop[i]; + if (likely(pr->atom == atom)) { + *ppr = &p->prop[i]; + *offset = i; + /* the compiler should be able to assume that pr != NULL here */ + return pr; + } + h = pr->hash_next; + } + *ppr = NULL; + return NULL; +} + /* indicate that the object may be part of a function prototype cycle */ -static void set_cycle_flag(JSContext *ctx, JSValueConst obj) +static void set_cycle_flag(JSContext *ctx, JSValue obj) { } @@ -5325,12 +5427,10 @@ static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref) if (--var_ref->header.ref_count == 0) { if (var_ref->is_detached) { JS_FreeValueRT(rt, var_ref->value); + remove_gc_object(&var_ref->header); } else { - list_del(&var_ref->var_ref_link); /* still on the stack */ - if (var_ref->async_func) - async_func_free(rt, var_ref->async_func); + list_del(&var_ref->header.link); /* still on the stack */ } - remove_gc_object(&var_ref->header); js_free_rt(rt, var_ref); } } @@ -5347,7 +5447,7 @@ static void js_array_finalizer(JSRuntime *rt, JSValue val) js_free_rt(rt, p->u.array.u.values); } -static void js_array_mark(JSRuntime *rt, JSValueConst val, +static void js_array_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); @@ -5365,7 +5465,7 @@ static void js_object_data_finalizer(JSRuntime *rt, JSValue val) p->u.object_data = JS_UNDEFINED; } -static void js_object_data_mark(JSRuntime *rt, JSValueConst val, +static void js_object_data_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); @@ -5380,7 +5480,7 @@ static void js_c_function_finalizer(JSRuntime *rt, JSValue val) JS_FreeContext(p->u.cfunc.realm); } -static void js_c_function_mark(JSRuntime *rt, JSValueConst val, +static void js_c_function_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); @@ -5412,7 +5512,7 @@ static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val) } } -static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val, +static void js_bytecode_function_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); @@ -5428,7 +5528,7 @@ static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val, if (var_refs) { for(i = 0; i < b->closure_var_count; i++) { JSVarRef *var_ref = var_refs[i]; - if (var_ref) { + if (var_ref && var_ref->is_detached) { mark_func(rt, &var_ref->header); } } @@ -5453,7 +5553,7 @@ static void js_bound_function_finalizer(JSRuntime *rt, JSValue val) js_free_rt(rt, bf); } -static void js_bound_function_mark(JSRuntime *rt, JSValueConst val, +static void js_bound_function_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); @@ -5470,19 +5570,11 @@ static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val) { JSObject *p = JS_VALUE_GET_OBJ(val); JSForInIterator *it = p->u.for_in_iterator; - int i; - JS_FreeValueRT(rt, it->obj); - if (!it->is_array) { - for(i = 0; i < it->atom_count; i++) { - JS_FreeAtomRT(rt, it->tab_atom[i].atom); - } - js_free_rt(rt, it->tab_atom); - } js_free_rt(rt, it); } -static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val, +static void js_for_in_iterator_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); @@ -5516,7 +5608,7 @@ static void free_object(JSRuntime *rt, JSObject *p) p->prop = NULL; if (unlikely(p->first_weak_ref)) { - reset_weak_ref(rt, p); + reset_weak_ref(rt, &p->first_weak_ref); } finalizer = rt->class_array[p->class_id].finalizer; @@ -5546,9 +5638,6 @@ static void free_gc_object(JSRuntime *rt, JSGCObjectHeader *gp) case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: free_function_bytecode(rt, (JSFunctionBytecode *)gp); break; - case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: - __async_func_free(rt, (JSAsyncFunctionState *)gp); - break; default: abort(); } @@ -5572,18 +5661,22 @@ static void free_zero_refcount(JSRuntime *rt) } /* called with the ref_count of 'v' reaches zero. */ -static void __JS_FreeValueRT(JSRuntime *rt, JSValue v) +static void js_free_value_rt(JSRuntime *rt, JSValue v) { uint32_t tag = JS_VALUE_GET_TAG(v); -#ifdef DUMP_FREE - { - printf("Freeing "); - if (tag == JS_TAG_OBJECT) { - JS_DumpObject(rt, JS_VALUE_GET_OBJ(v)); - } else { - JS_DumpValueShort(rt, v); - printf("\n"); +#ifdef ENABLE_DUMPS // JS_DUMP_FREE + if (check_dump_flag(rt, JS_DUMP_FREE)) { + /* Prevent invalid object access during GC */ + if ((rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) + || (tag != JS_TAG_OBJECT && tag != JS_TAG_FUNCTION_BYTECODE)) { + printf("Freeing "); + if (tag == JS_TAG_OBJECT) { + JS_DumpObject(rt, JS_VALUE_GET_OBJ(v)); + } else { + JS_DumpValue(rt, v); + printf("\n"); + } } } #endif @@ -5595,7 +5688,7 @@ static void __JS_FreeValueRT(JSRuntime *rt, JSValue v) if (p->atom_type) { JS_FreeAtomStruct(rt, p); } else { -#ifdef DUMP_LEAKS +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS list_del(&p->link); #endif js_free_rt(rt, p); @@ -5619,24 +5712,12 @@ static void __JS_FreeValueRT(JSRuntime *rt, JSValue v) abort(); /* never freed here */ break; case JS_TAG_BIG_INT: -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: -#endif { - JSBigFloat *bf = JS_VALUE_GET_PTR(v); + JSBigInt *bf = JS_VALUE_GET_PTR(v); bf_delete(&bf->num); js_free_rt(rt, bf); } break; -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_DECIMAL: - { - JSBigDecimal *bf = JS_VALUE_GET_PTR(v); - bfdec_delete(&bf->num); - js_free_rt(rt, bf); - } - break; -#endif case JS_TAG_SYMBOL: { JSAtomStruct *p = JS_VALUE_GET_PTR(v); @@ -5644,14 +5725,24 @@ static void __JS_FreeValueRT(JSRuntime *rt, JSValue v) } break; default: - printf("__JS_FreeValue: unknown tag=%d\n", tag); + printf("js_free_value_rt: unknown tag=%d\n", tag); abort(); } } -static void __JS_FreeValue(JSContext *ctx, JSValue v) +void JS_FreeValueRT(JSRuntime *rt, JSValue v) +{ + if (JS_VALUE_HAS_REF_COUNT(v)) { + JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); + if (--p->ref_count <= 0) { + js_free_value_rt(rt, v); + } + } +} + +void JS_FreeValue(JSContext *ctx, JSValue v) { - __JS_FreeValueRT(ctx->rt, v); + JS_FreeValueRT(ctx->rt, v); } /* garbage collection */ @@ -5669,7 +5760,7 @@ static void remove_gc_object(JSGCObjectHeader *h) list_del(&h->link); } -void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) +void JS_MarkValue(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) { if (JS_VALUE_HAS_REF_COUNT(val)) { switch(JS_VALUE_GET_TAG(val)) { @@ -5707,9 +5798,11 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp, if (pr->u.getset.setter) mark_func(rt, &pr->u.getset.setter->header); } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { - /* Note: the tag does not matter - provided it is a GC object */ - mark_func(rt, &pr->u.var_ref->header); + if (pr->u.var_ref->is_detached) { + /* Note: the tag does not matter + provided it is a GC object */ + mark_func(rt, &pr->u.var_ref->header); + } } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { js_autoinit_mark(rt, pr, mark_func); } @@ -5731,6 +5824,7 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp, case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: /* the template objects can be part of a cycle */ { + JSShape **shape, *(*shapes)[IC_CACHE_ITEM_CAPACITY]; JSFunctionBytecode *b = (JSFunctionBytecode *)gp; int i; for(i = 0; i < b->cpool_count; i++) { @@ -5738,37 +5832,29 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp, } if (b->realm) mark_func(rt, &b->realm->header); + if (b->ic) { + for (i = 0; i < b->ic->count; i++) { + shapes = &b->ic->cache[i].shape; + for (shape = *shapes; shape != endof(*shapes); shape++) + if (*shape) + mark_func(rt, &(*shape)->header); + } + } } break; case JS_GC_OBJ_TYPE_VAR_REF: { JSVarRef *var_ref = (JSVarRef *)gp; - if (var_ref->is_detached) { - JS_MarkValue(rt, *var_ref->pvalue, mark_func); - } else if (var_ref->async_func) { - mark_func(rt, &var_ref->async_func->header); - } + /* only detached variable referenced are taken into account */ + assert(var_ref->is_detached); + JS_MarkValue(rt, *var_ref->pvalue, mark_func); } break; case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: { - JSAsyncFunctionState *s = (JSAsyncFunctionState *)gp; - JSStackFrame *sf = &s->frame; - JSValue *sp; - - if (!s->is_completed) { - JS_MarkValue(rt, sf->cur_func, mark_func); - JS_MarkValue(rt, s->this_val, mark_func); - /* sf->cur_sp = NULL if the function is running */ - if (sf->cur_sp) { - /* if the function is running, cur_sp is not known so we - cannot mark the stack. Marking the variables is not needed - because a running function cannot be part of a removable - cycle */ - for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) - JS_MarkValue(rt, *sp, mark_func); - } - } + JSAsyncFunctionData *s = (JSAsyncFunctionData *)gp; + if (s->is_active) + async_func_mark(rt, &s->func_state, mark_func); JS_MarkValue(rt, s->resolving_funcs[0], mark_func); JS_MarkValue(rt, s->resolving_funcs[1], mark_func); } @@ -5865,8 +5951,8 @@ static void gc_free_cycles(JSRuntime *rt) { struct list_head *el, *el1; JSGCObjectHeader *p; -#ifdef DUMP_GC_FREE - BOOL header_done = FALSE; +#ifdef ENABLE_DUMPS // JS_DUMP_GC_FREE + bool header_done = false; #endif rt->gc_phase = JS_GC_PHASE_REMOVE_CYCLES; @@ -5876,20 +5962,21 @@ static void gc_free_cycles(JSRuntime *rt) if (el == &rt->tmp_obj_list) break; p = list_entry(el, JSGCObjectHeader, link); - /* Only need to free the GC object associated with JS values - or async functions. The rest will be automatically removed - because they must be referenced by them. */ + /* Only need to free the GC object associated with JS + values. The rest will be automatically removed because they + must be referenced by them. */ switch(p->gc_obj_type) { case JS_GC_OBJ_TYPE_JS_OBJECT: case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: - case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: -#ifdef DUMP_GC_FREE - if (!header_done) { - printf("Freeing cycles:\n"); - JS_DumpObjectHeader(rt); - header_done = TRUE; +#ifdef ENABLE_DUMPS // JS_DUMP_GC_FREE + if (check_dump_flag(rt, JS_DUMP_GC_FREE)) { + if (!header_done) { + printf("Freeing cycles:\n"); + JS_DumpObjectHeader(rt); + header_done = true; + } + JS_DumpGCObject(rt, p); } - JS_DumpGCObject(rt, p); #endif free_gc_object(rt, p); break; @@ -5904,8 +5991,7 @@ static void gc_free_cycles(JSRuntime *rt) list_for_each_safe(el, el1, &rt->gc_zero_ref_count_list) { p = list_entry(el, JSGCObjectHeader, link); assert(p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT || - p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE || - p->gc_obj_type == JS_GC_OBJ_TYPE_ASYNC_FUNCTION); + p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE); js_free_rt(rt, p); } @@ -5928,11 +6014,11 @@ void JS_RunGC(JSRuntime *rt) /* Return false if not an object or if the object has already been freed (zombie objects are visible in finalizers when freeing cycles). */ -BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj) +bool JS_IsLiveObject(JSRuntime *rt, JSValue obj) { JSObject *p; if (!JS_IsObject(obj)) - return FALSE; + return false; p = JS_VALUE_GET_OBJ(obj); return !p->free_mark; } @@ -5950,7 +6036,7 @@ typedef struct JSMemoryUsage_helper { int64_t js_func_pc2line_size; } JSMemoryUsage_helper; -static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp); +static void compute_value_size(JSValue val, JSMemoryUsage_helper *hp); static void compute_jsstring_size(JSString *str, JSMemoryUsage_helper *hp) { @@ -5967,52 +6053,43 @@ static void compute_bytecode_size(JSFunctionBytecode *b, JSMemoryUsage_helper *h int memory_used_count, js_func_size, i; memory_used_count = 0; - js_func_size = offsetof(JSFunctionBytecode, debug); + js_func_size = sizeof(*b); if (b->vardefs) { js_func_size += (b->arg_count + b->var_count) * sizeof(*b->vardefs); } if (b->cpool) { js_func_size += b->cpool_count * sizeof(*b->cpool); for (i = 0; i < b->cpool_count; i++) { - JSValueConst val = b->cpool[i]; + JSValue val = b->cpool[i]; compute_value_size(val, hp); } } if (b->closure_var) { js_func_size += b->closure_var_count * sizeof(*b->closure_var); } - if (!b->read_only_bytecode && b->byte_code_buf) { + if (b->byte_code_buf) { hp->js_func_code_size += b->byte_code_len; } - if (b->has_debug) { - js_func_size += sizeof(*b) - offsetof(JSFunctionBytecode, debug); - if (b->debug.source) { - memory_used_count++; - js_func_size += b->debug.source_len + 1; - } - if (b->debug.pc2line_len) { - memory_used_count++; - hp->js_func_pc2line_count += 1; - hp->js_func_pc2line_size += b->debug.pc2line_len; - } + memory_used_count++; + js_func_size += b->source_len + 1; + if (b->pc2line_len) { + memory_used_count++; + hp->js_func_pc2line_count += 1; + hp->js_func_pc2line_size += b->pc2line_len; } hp->js_func_size += js_func_size; hp->js_func_count += 1; hp->memory_used_count += memory_used_count; } -static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp) +static void compute_value_size(JSValue val, JSMemoryUsage_helper *hp) { switch(JS_VALUE_GET_TAG(val)) { case JS_TAG_STRING: compute_jsstring_size(JS_VALUE_GET_STRING(val), hp); break; case JS_TAG_BIG_INT: -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: - case JS_TAG_BIG_DECIMAL: -#endif - /* should track JSBigFloat usage */ + /* should track JSBigInt usage */ break; } } @@ -6029,7 +6106,7 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s) s->malloc_limit = rt->malloc_state.malloc_limit; s->memory_used_count = 2; /* rt + rt->class_array */ - s->memory_used_size = sizeof(JSRuntime) + sizeof(JSValue) * rt->class_count; + s->memory_used_size = sizeof(JSRuntime) + sizeof(JSClass) * rt->class_count; list_for_each(el, &rt->context_list) { JSContext *ctx = list_entry(el, JSContext, link); @@ -6138,10 +6215,6 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s) case JS_CLASS_SYMBOL: /* u.object_data */ case JS_CLASS_DATE: /* u.object_data */ case JS_CLASS_BIG_INT: /* u.object_data */ -#ifdef CONFIG_BIGNUM - case JS_CLASS_BIG_FLOAT: /* u.object_data */ - case JS_CLASS_BIG_DECIMAL: /* u.object_data */ -#endif compute_value_size(p->u.object_data, hp); break; case JS_CLASS_C_FUNCTION: /* u.cfunc */ @@ -6232,12 +6305,10 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s) case JS_CLASS_UINT32_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_BIG_INT64_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_BIG_UINT64_ARRAY: /* u.typed_array / u.array */ + case JS_CLASS_FLOAT16_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_FLOAT32_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_FLOAT64_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_DATAVIEW: /* u.typed_array */ -#ifdef CONFIG_BIGNUM - case JS_CLASS_FLOAT_ENV: /* u.float_env */ -#endif case JS_CLASS_MAP: /* u.map_state */ case JS_CLASS_SET: /* u.map_state */ case JS_CLASS_WEAKMAP: /* u.map_state */ @@ -6307,13 +6378,8 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s) void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt) { - fprintf(fp, "QuickJS memory usage -- " -#ifdef CONFIG_BIGNUM - "BigNum " -#endif - CONFIG_VERSION " version, %d-bit, malloc limit: %"PRId64"\n\n", - (int)sizeof(void *) * 8, s->malloc_limit); -#if 1 + fprintf(fp, "QuickJS-ng memory usage -- %s version, %d-bit, %s Endian, malloc limit: %"PRId64"\n\n", + JS_GetVersion(), (int)sizeof(void *) * 8, is_be() ? "Big" : "Little", s->malloc_limit); if (rt) { static const struct { const char *name; @@ -6358,10 +6424,10 @@ void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt) if (obj_classes[0]) fprintf(fp, " %5d %2.0d %s\n", obj_classes[0], 0, "none"); for (class_id = 1; class_id < JS_CLASS_INIT_COUNT; class_id++) { - if (obj_classes[class_id] && class_id < rt->class_count) { + if (obj_classes[class_id]) { char buf[ATOM_GET_STR_BUF_SIZE]; fprintf(fp, " %5d %2.0d %s\n", obj_classes[class_id], class_id, - JS_AtomGetStrRT(rt, buf, sizeof(buf), rt->class_array[class_id].class_name)); + JS_AtomGetStrRT(rt, buf, sizeof(buf), js_std_class_def[class_id - 1].class_name)); } } if (obj_classes[JS_CLASS_INIT_COUNT]) @@ -6369,7 +6435,6 @@ void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt) } fprintf(fp, "\n"); } -#endif fprintf(fp, "%-20s %8s %8s\n", "NAME", "COUNT", "SIZE"); if (s->malloc_count) { @@ -6436,7 +6501,7 @@ void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt) JSValue JS_GetGlobalObject(JSContext *ctx) { - return JS_DupValue(ctx, ctx->global_obj); + return js_dup(ctx->global_obj); } /* WARNING: obj is freed */ @@ -6454,13 +6519,21 @@ JSValue JS_GetException(JSContext *ctx) JSValue val; JSRuntime *rt = ctx->rt; val = rt->current_exception; - rt->current_exception = JS_NULL; + rt->current_exception = JS_UNINITIALIZED; return val; } -JS_BOOL JS_HasException(JSContext *ctx) +bool JS_HasException(JSContext *ctx) { - return !JS_IsNull(ctx->rt->current_exception); + return !JS_IsUninitialized(ctx->rt->current_exception); +} + +/* returns the pending backtrace (cannot be called twice). */ +JSValue JS_GetBacktrace(JSContext *ctx) +{ + JSValue val = ctx->error_back_trace; + ctx->error_back_trace = JS_UNDEFINED; + return val; } static void dbuf_put_leb128(DynBuf *s, uint32_t v) @@ -6519,21 +6592,20 @@ static int get_sleb128(int32_t *pval, const uint8_t *buf, } static int find_line_num(JSContext *ctx, JSFunctionBytecode *b, - uint32_t pc_value) + uint32_t pc_value, int *col) { const uint8_t *p_end, *p; - int new_line_num, line_num, pc, v, ret; + int new_line_num, new_col_num, line_num, col_num, pc, v, ret; unsigned int op; - if (!b->has_debug || !b->debug.pc2line_buf) { - /* function was stripped */ - return -1; - } - - p = b->debug.pc2line_buf; - p_end = p + b->debug.pc2line_len; + *col = 1; + p = b->pc2line_buf; + if (!p) + goto fail; + p_end = p + b->pc2line_len; pc = 0; - line_num = b->debug.line_num; + line_num = b->line_num; + col_num = b->col_num; while (p < p_end) { op = *p++; if (op == 0) { @@ -6544,11 +6616,8 @@ static int find_line_num(JSContext *ctx, JSFunctionBytecode *b, pc += val; p += ret; ret = get_sleb128(&v, p, p_end); - if (ret < 0) { - fail: - /* should never happen */ - return b->debug.line_num; - } + if (ret < 0) + goto fail; p += ret; new_line_num = line_num + v; } else { @@ -6556,21 +6625,31 @@ static int find_line_num(JSContext *ctx, JSFunctionBytecode *b, pc += (op / PC2LINE_RANGE); new_line_num = line_num + (op % PC2LINE_RANGE) + PC2LINE_BASE; } + ret = get_sleb128(&v, p, p_end); + if (ret < 0) + goto fail; + p += ret; + new_col_num = col_num + v; if (pc_value < pc) - return line_num; + break; line_num = new_line_num; + col_num = new_col_num; } + *col = col_num; return line_num; +fail: + /* should never happen */ + return b->line_num; } /* in order to avoid executing arbitrary code during the stack trace generation, we only look at simple 'name' properties containing a string. */ -static const char *get_func_name(JSContext *ctx, JSValueConst func) +static const char *get_func_name(JSContext *ctx, JSValue func) { JSProperty *pr; JSShapeProperty *prs; - JSValueConst val; + JSValue val; if (JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT) return NULL; @@ -6585,131 +6664,254 @@ static const char *get_func_name(JSContext *ctx, JSValueConst func) return JS_ToCString(ctx, val); } +/* Note: it is important that no exception is returned by this function */ +static bool can_add_backtrace(JSValue obj) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) + return false; + p = JS_VALUE_GET_OBJ(obj); + if (p->class_id != JS_CLASS_ERROR) + return false; + if (find_own_property1(p, JS_ATOM_stack)) + return false; + return true; +} + #define JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL (1 << 0) /* only taken into account if filename is provided */ #define JS_BACKTRACE_FLAG_SINGLE_LEVEL (1 << 1) +#define JS_BACKTRACE_FLAG_FILTER_FUNC (1 << 2) /* if filename != NULL, an additional level is added with the filename and line number information (used for parse error). */ -void build_backtrace(JSContext *ctx, JSValueConst error_obj, - const char *filename, int line_num, +static void build_backtrace(JSContext *ctx, JSValue error_val, JSValue filter_func, + const char *filename, int line_num, int col_num, int backtrace_flags) { - JSStackFrame *sf; - JSValue str; + JSStackFrame *sf, *sf_start; + JSValue stack, prepare, saved_exception; DynBuf dbuf; const char *func_name_str; const char *str1; JSObject *p; - BOOL backtrace_barrier; - - js_dbuf_init(ctx, &dbuf); - if (filename) { - dbuf_printf(&dbuf, " at %s", filename); - if (line_num != -1) - dbuf_printf(&dbuf, ":%d", line_num); - dbuf_putc(&dbuf, '\n'); - str = JS_NewString(ctx, filename); - JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_fileName, str, - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_lineNumber, JS_NewInt32(ctx, line_num), - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - if (backtrace_flags & JS_BACKTRACE_FLAG_SINGLE_LEVEL) + JSFunctionBytecode *b; + bool backtrace_barrier, has_prepare, has_filter_func; + JSRuntime *rt; + JSCallSiteData csd[64]; + uint32_t i; + int stack_trace_limit; + + saved_exception = JS_UNINITIALIZED; + stack_trace_limit = ctx->error_stack_trace_limit; + stack_trace_limit = min_int(stack_trace_limit, countof(csd)); + stack_trace_limit = max_int(stack_trace_limit, 0); + rt = ctx->rt; + has_prepare = false; + has_filter_func = backtrace_flags & JS_BACKTRACE_FLAG_FILTER_FUNC; + i = 0; + + if (!rt->in_prepare_stack_trace && !JS_IsNull(ctx->error_ctor)) { + prepare = js_dup(ctx->error_prepare_stack); + has_prepare = JS_IsFunction(ctx, prepare); + rt->in_prepare_stack_trace = true; + } + + if (has_prepare) { + saved_exception = rt->current_exception; + rt->current_exception = JS_UNINITIALIZED; + if (stack_trace_limit == 0) goto done; + if (filename) + js_new_callsite_data2(ctx, &csd[i++], filename, line_num, col_num); + } else { + js_dbuf_init(ctx, &dbuf); + if (stack_trace_limit == 0) + goto done; + if (filename) { + i++; + dbuf_printf(&dbuf, " at %s", filename); + if (line_num != -1) + dbuf_printf(&dbuf, ":%d:%d", line_num, col_num); + dbuf_putc(&dbuf, '\n'); + } } - for(sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) { + + if (filename && (backtrace_flags & JS_BACKTRACE_FLAG_SINGLE_LEVEL)) + goto done; + + sf_start = rt->current_stack_frame; + + /* Find the frame we want to start from. Note that when a filter is used the filter + function will be the first, but we also specify we want to skip the first one. */ + if (has_filter_func) { + for (sf = sf_start; sf != NULL && i < stack_trace_limit; sf = sf->prev_frame) { + if (js_same_value(ctx, sf->cur_func, filter_func)) { + sf_start = sf; + break; + } + } + } + + for (sf = sf_start; sf != NULL && i < stack_trace_limit; sf = sf->prev_frame) { if (backtrace_flags & JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL) { backtrace_flags &= ~JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL; continue; } - func_name_str = get_func_name(ctx, sf->cur_func); - if (!func_name_str || func_name_str[0] == '\0') - str1 = ""; - else - str1 = func_name_str; - dbuf_printf(&dbuf, " at %s", str1); - JS_FreeCString(ctx, func_name_str); p = JS_VALUE_GET_OBJ(sf->cur_func); - backtrace_barrier = FALSE; - if (js_class_has_bytecode(p->class_id)) { - JSFunctionBytecode *b; - const char *atom_str; - int line_num1; + b = NULL; + backtrace_barrier = false; + if (js_class_has_bytecode(p->class_id)) { b = p->u.func.function_bytecode; backtrace_barrier = b->backtrace_barrier; - if (b->has_debug) { - line_num1 = find_line_num(ctx, b, - sf->cur_pc - b->byte_code_buf - 1); - atom_str = JS_AtomToCString(ctx, b->debug.filename); - dbuf_printf(&dbuf, " (%s", - atom_str ? atom_str : ""); + } + + if (has_prepare) { + js_new_callsite_data(ctx, &csd[i], sf); + } else { + /* func_name_str is UTF-8 encoded if needed */ + func_name_str = get_func_name(ctx, sf->cur_func); + if (!func_name_str || func_name_str[0] == '\0') + str1 = ""; + else + str1 = func_name_str; + dbuf_printf(&dbuf, " at %s", str1); + JS_FreeCString(ctx, func_name_str); + + if (b && sf->cur_pc) { + const char *atom_str; + int line_num1, col_num1; + uint32_t pc; + + pc = sf->cur_pc - b->byte_code_buf - 1; + line_num1 = find_line_num(ctx, b, pc, &col_num1); + atom_str = b->filename ? JS_AtomToCString(ctx, b->filename) : NULL; + dbuf_printf(&dbuf, " (%s", atom_str ? atom_str : ""); JS_FreeCString(ctx, atom_str); if (line_num1 != -1) - dbuf_printf(&dbuf, ":%d", line_num1); + dbuf_printf(&dbuf, ":%d:%d", line_num1, col_num1); dbuf_putc(&dbuf, ')'); + } else if (b) { + // FIXME(bnoordhuis) Missing `sf->cur_pc = pc` in bytecode + // handler in JS_CallInternal. Almost never user observable + // except with intercepting JS proxies that throw exceptions. + dbuf_printf(&dbuf, " (missing)"); + } else { + dbuf_printf(&dbuf, " (native)"); } - } else { - dbuf_printf(&dbuf, " (native)"); + dbuf_putc(&dbuf, '\n'); } - dbuf_putc(&dbuf, '\n'); + i++; + /* stop backtrace if JS_EVAL_FLAG_BACKTRACE_BARRIER was used */ if (backtrace_barrier) break; } done: - dbuf_putc(&dbuf, '\0'); - if (dbuf_error(&dbuf)) - str = JS_NULL; - else - str = JS_NewString(ctx, (char *)dbuf.buf); - dbuf_free(&dbuf); - JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_stack, str, - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); + if (has_prepare) { + int j = 0, k; + stack = JS_NewArray(ctx); + if (JS_IsException(stack)) { + stack = JS_NULL; + } else { + for (; j < i; j++) { + JSValue v = js_new_callsite(ctx, &csd[j]); + if (JS_IsException(v)) + break; + if (JS_DefinePropertyValueUint32(ctx, stack, j, v, JS_PROP_C_W_E) < 0) { + JS_FreeValue(ctx, v); + break; + } + } + } + // Clear the csd's we didn't use in case of error. + for (k = j; k < i; k++) { + JS_FreeValue(ctx, csd[k].filename); + JS_FreeValue(ctx, csd[k].func); + JS_FreeValue(ctx, csd[k].func_name); + } + JSValue args[] = { + error_val, + stack, + }; + JSValue stack2 = JS_Call(ctx, prepare, ctx->error_ctor, countof(args), args); + JS_FreeValue(ctx, stack); + if (JS_IsException(stack2)) + stack = JS_NULL; + else + stack = stack2; + JS_FreeValue(ctx, prepare); + JS_FreeValue(ctx, rt->current_exception); + rt->current_exception = saved_exception; + } else { + if (dbuf_error(&dbuf)) + stack = JS_NULL; + else + stack = JS_NewStringLen(ctx, (char *)dbuf.buf, dbuf.size); + dbuf_free(&dbuf); + } + + rt->in_prepare_stack_trace = false; + if (JS_IsUndefined(ctx->error_back_trace)) + ctx->error_back_trace = js_dup(stack); + if (has_filter_func || can_add_backtrace(error_val)) { + JS_DefinePropertyValue(ctx, error_val, JS_ATOM_stack, stack, + JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); + } else { + JS_FreeValue(ctx, stack); + } } -/* Note: it is important that no exception is returned by this function */ -static BOOL is_backtrace_needed(JSContext *ctx, JSValueConst obj) +JSValue JS_NewError(JSContext *ctx) { - JSObject *p; - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) - return FALSE; - p = JS_VALUE_GET_OBJ(obj); - if (p->class_id != JS_CLASS_ERROR) - return FALSE; - if (find_own_property1(p, JS_ATOM_stack)) - return FALSE; - return TRUE; + JSValue obj = JS_NewObjectClass(ctx, JS_CLASS_ERROR); + if (JS_IsException(obj)) + return JS_EXCEPTION; + build_backtrace(ctx, obj, JS_UNDEFINED, NULL, 0, 0, 0); + return obj; } -JSValue JS_NewError(JSContext *ctx) +static JSValue JS_MakeError(JSContext *ctx, JSErrorEnum error_num, + const char *message, bool add_backtrace) { - return JS_NewObjectClass(ctx, JS_CLASS_ERROR); + JSValue obj, msg; + + if (error_num == JS_PLAIN_ERROR) { + obj = JS_NewObjectClass(ctx, JS_CLASS_ERROR); + } else { + obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[error_num], + JS_CLASS_ERROR); + } + if (JS_IsException(obj)) + return JS_EXCEPTION; + msg = JS_NewString(ctx, message); + if (JS_IsException(msg)) + msg = JS_NewString(ctx, "Invalid error message"); + if (!JS_IsException(msg)) { + JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, msg, + JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); + } + if (add_backtrace) + build_backtrace(ctx, obj, JS_UNDEFINED, NULL, 0, 0, 0); + return obj; } +/* fmt and arguments may be pure ASCII or UTF-8 encoded contents */ static JSValue JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num, - const char *fmt, va_list ap, BOOL add_backtrace) + const char *fmt, va_list ap, bool add_backtrace) { - char buf[8192]; - JSValue obj, ret; + char buf[256]; + JSValue obj; vsnprintf(buf, sizeof(buf), fmt, ap); - obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[error_num], - JS_CLASS_ERROR); + obj = JS_MakeError(ctx, error_num, buf, add_backtrace); if (unlikely(JS_IsException(obj))) { /* out of memory: throw JS_NULL to avoid recursing */ obj = JS_NULL; - } else { - JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, - JS_NewString(ctx, buf), - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - } - if (add_backtrace) { - build_backtrace(ctx, obj, NULL, 0, 0); } - ret = JS_Throw(ctx, obj); - return ret; + return JS_Throw(ctx, obj); } static JSValue JS_ThrowError(JSContext *ctx, JSErrorEnum error_num, @@ -6717,7 +6919,7 @@ static JSValue JS_ThrowError(JSContext *ctx, JSErrorEnum error_num, { JSRuntime *rt = ctx->rt; JSStackFrame *sf; - BOOL add_backtrace; + bool add_backtrace; /* the backtrace is added later if called from a bytecode function */ sf = rt->current_stack_frame; @@ -6726,7 +6928,18 @@ static JSValue JS_ThrowError(JSContext *ctx, JSErrorEnum error_num, return JS_ThrowError2(ctx, error_num, fmt, ap, add_backtrace); } -JSValue FORMAT_ATTR(2, 3) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...) +JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowPlainError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...) +{ + JSValue val; + va_list ap; + + va_start(ap, fmt); + val = JS_ThrowError(ctx, JS_PLAIN_ERROR, fmt, ap); + va_end(ap); + return val; +} + +JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowSyntaxError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...) { JSValue val; va_list ap; @@ -6737,7 +6950,7 @@ JSValue FORMAT_ATTR(2, 3) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, . return val; } -JSValue FORMAT_ATTR(2, 3) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...) +JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowTypeError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...) { JSValue val; va_list ap; @@ -6748,7 +6961,7 @@ JSValue FORMAT_ATTR(2, 3) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ... return val; } -static int FORMAT_ATTR(3, 4) JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags, const char *fmt, ...) +static int JS_PRINTF_FORMAT_ATTR(3, 4) JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags, JS_PRINTF_FORMAT const char *fmt, ...) { va_list ap; @@ -6759,12 +6972,12 @@ static int FORMAT_ATTR(3, 4) JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags, va_end(ap); return -1; } else { - return FALSE; + return false; } } /* never use it directly */ -static JSValue FORMAT_ATTR(3, 4) __JS_ThrowTypeErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...) +static JSValue JS_PRINTF_FORMAT_ATTR(3, 4) __JS_ThrowTypeErrorAtom(JSContext *ctx, JSAtom atom, JS_PRINTF_FORMAT const char *fmt, ...) { char buf[ATOM_GET_STR_BUF_SIZE]; return JS_ThrowTypeError(ctx, fmt, @@ -6772,7 +6985,7 @@ static JSValue FORMAT_ATTR(3, 4) __JS_ThrowTypeErrorAtom(JSContext *ctx, JSAtom } /* never use it directly */ -static JSValue FORMAT_ATTR(3, 4) __JS_ThrowSyntaxErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...) +static JSValue JS_PRINTF_FORMAT_ATTR(3, 4) __JS_ThrowSyntaxErrorAtom(JSContext *ctx, JSAtom atom, JS_PRINTF_FORMAT const char *fmt, ...) { char buf[ATOM_GET_STR_BUF_SIZE]; return JS_ThrowSyntaxError(ctx, fmt, @@ -6791,11 +7004,11 @@ static int JS_ThrowTypeErrorReadOnly(JSContext *ctx, int flags, JSAtom atom) JS_ThrowTypeErrorAtom(ctx, "'%s' is read-only", atom); return -1; } else { - return FALSE; + return false; } } -JSValue FORMAT_ATTR(2, 3) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...) +JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowReferenceError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...) { JSValue val; va_list ap; @@ -6806,7 +7019,7 @@ JSValue FORMAT_ATTR(2, 3) JS_ThrowReferenceError(JSContext *ctx, const char *fmt return val; } -JSValue FORMAT_ATTR(2, 3) JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...) +JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowRangeError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...) { JSValue val; va_list ap; @@ -6817,7 +7030,7 @@ JSValue FORMAT_ATTR(2, 3) JS_ThrowRangeError(JSContext *ctx, const char *fmt, .. return val; } -JSValue FORMAT_ATTR(2, 3) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...) +JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowInternalError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...) { JSValue val; va_list ap; @@ -6832,16 +7045,16 @@ JSValue JS_ThrowOutOfMemory(JSContext *ctx) { JSRuntime *rt = ctx->rt; if (!rt->in_out_of_memory) { - rt->in_out_of_memory = TRUE; + rt->in_out_of_memory = true; JS_ThrowInternalError(ctx, "out of memory"); - rt->in_out_of_memory = FALSE; + rt->in_out_of_memory = false; } return JS_EXCEPTION; } static JSValue JS_ThrowStackOverflow(JSContext *ctx) { - return JS_ThrowInternalError(ctx, "stack overflow"); + return JS_ThrowRangeError(ctx, "Maximum call stack size exceeded"); } static JSValue JS_ThrowTypeErrorNotAnObject(JSContext *ctx) @@ -6857,7 +7070,7 @@ static JSValue JS_ThrowTypeErrorNotASymbol(JSContext *ctx) static JSValue JS_ThrowReferenceErrorNotDefined(JSContext *ctx, JSAtom name) { char buf[ATOM_GET_STR_BUF_SIZE]; - return JS_ThrowReferenceError(ctx, "'%s' is not defined", + return JS_ThrowReferenceError(ctx, "%s is not defined", JS_AtomGetStr(ctx, buf, sizeof(buf), name)); } @@ -6871,7 +7084,7 @@ static JSValue JS_ThrowReferenceErrorUninitialized(JSContext *ctx, JSAtom name) static JSValue JS_ThrowReferenceErrorUninitialized2(JSContext *ctx, JSFunctionBytecode *b, - int idx, BOOL is_ref) + int idx, bool is_ref) { JSAtom atom = JS_ATOM_NULL; if (is_ref) { @@ -6900,7 +7113,7 @@ static no_inline __exception int __js_poll_interrupts(JSContext *ctx) if (rt->interrupt_handler(rt, rt->interrupt_opaque)) { /* XXX: should set a specific flag to avoid catching */ JS_ThrowInternalError(ctx, "interrupted"); - JS_SetUncatchableError(ctx, ctx->rt->current_exception, TRUE); + js_set_uncatchable_error(ctx, ctx->rt->current_exception, true); return -1; } } @@ -6916,10 +7129,10 @@ static inline __exception int js_poll_interrupts(JSContext *ctx) } } -/* return -1 (exception) or TRUE/FALSE */ -static int JS_SetPrototypeInternal(JSContext *ctx, JSValueConst obj, - JSValueConst proto_val, - BOOL throw_flag) +/* return -1 (exception) or true/false */ +static int JS_SetPrototypeInternal(JSContext *ctx, JSValue obj, + JSValue proto_val, + bool throw_flag) { JSObject *proto, *p, *p1; JSShape *sh; @@ -6945,19 +7158,26 @@ static int JS_SetPrototypeInternal(JSContext *ctx, JSValueConst obj, } if (throw_flag && JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) - return TRUE; + return true; if (unlikely(p->class_id == JS_CLASS_PROXY)) return js_proxy_setPrototypeOf(ctx, obj, proto_val, throw_flag); sh = p->shape; if (sh->proto == proto) - return TRUE; + return true; + if (p == JS_VALUE_GET_OBJ(ctx->class_proto[JS_CLASS_OBJECT])) { + if (throw_flag) { + JS_ThrowTypeError(ctx, "'Immutable prototype object \'Object.prototype\' cannot have their prototype set'"); + return -1; + } + return false; + } if (!p->extensible) { if (throw_flag) { JS_ThrowTypeError(ctx, "object is not extensible"); return -1; } else { - return FALSE; + return false; } } if (proto) { @@ -6969,13 +7189,13 @@ static int JS_SetPrototypeInternal(JSContext *ctx, JSValueConst obj, JS_ThrowTypeError(ctx, "circular prototype chain"); return -1; } else { - return FALSE; + return false; } } /* Note: for Proxy objects, proto is NULL */ p1 = p1->shape->proto; } while (p1 != NULL); - JS_DupValue(ctx, proto_val); + js_dup(proto_val); } if (js_shape_prepare_update(ctx, p, NULL)) @@ -6984,30 +7204,22 @@ static int JS_SetPrototypeInternal(JSContext *ctx, JSValueConst obj, if (sh->proto) JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto)); sh->proto = proto; - return TRUE; + return true; } -/* return -1 (exception) or TRUE/FALSE */ -int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val) +/* return -1 (exception) or true/false */ +int JS_SetPrototype(JSContext *ctx, JSValue obj, JSValue proto_val) { - return JS_SetPrototypeInternal(ctx, obj, proto_val, TRUE); + return JS_SetPrototypeInternal(ctx, obj, proto_val, true); } /* Only works for primitive types, otherwise return JS_NULL. */ -static JSValueConst JS_GetPrototypePrimitive(JSContext *ctx, JSValueConst val) +static JSValue JS_GetPrototypePrimitive(JSContext *ctx, JSValue val) { switch(JS_VALUE_GET_NORM_TAG(val)) { case JS_TAG_BIG_INT: val = ctx->class_proto[JS_CLASS_BIG_INT]; break; -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: - val = ctx->class_proto[JS_CLASS_BIG_FLOAT]; - break; - case JS_TAG_BIG_DECIMAL: - val = ctx->class_proto[JS_CLASS_BIG_DECIMAL]; - break; -#endif case JS_TAG_INT: case JS_TAG_FLOAT64: val = ctx->class_proto[JS_CLASS_NUMBER]; @@ -7032,7 +7244,7 @@ static JSValueConst JS_GetPrototypePrimitive(JSContext *ctx, JSValueConst val) } /* Return an Object, JS_NULL or JS_EXCEPTION in case of Proxy object. */ -JSValue JS_GetPrototype(JSContext *ctx, JSValueConst obj) +JSValue JS_GetPrototype(JSContext *ctx, JSValue obj) { JSValue val; if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { @@ -7045,10 +7257,10 @@ JSValue JS_GetPrototype(JSContext *ctx, JSValueConst obj) if (!p) val = JS_NULL; else - val = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); + val = js_dup(JS_MKPTR(JS_TAG_OBJECT, p)); } } else { - val = JS_DupValue(ctx, JS_GetPrototypePrimitive(ctx, obj)); + val = js_dup(JS_GetPrototypePrimitive(ctx, obj)); } return val; } @@ -7061,17 +7273,25 @@ static JSValue JS_GetPrototypeFree(JSContext *ctx, JSValue obj) return obj1; } -/* return TRUE, FALSE or (-1) in case of exception */ -static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val, - JSValueConst obj) +int JS_GetLength(JSContext *ctx, JSValue obj, int64_t *pres) { + return js_get_length64(ctx, pres, obj); +} + +int JS_SetLength(JSContext *ctx, JSValue obj, int64_t len) { + return js_set_length64(ctx, obj, len); +} + +/* return true, false or (-1) in case of exception */ +static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValue val, + JSValue obj) { JSValue obj_proto; JSObject *proto; const JSObject *p, *proto1; - BOOL ret; + int ret; if (!JS_IsFunction(ctx, obj)) - return FALSE; + return false; p = JS_VALUE_GET_OBJ(obj); if (p->class_id == JS_CLASS_BOUND_FUNCTION) { JSBoundFunction *s = p->u.bound_function; @@ -7080,7 +7300,7 @@ static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val, /* Only explicitly boxed values are instances of constructors */ if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) - return FALSE; + return false; obj_proto = JS_GetProperty(ctx, obj, JS_ATOM_prototype); if (JS_VALUE_GET_TAG(obj_proto) != JS_TAG_OBJECT) { if (!JS_IsException(obj_proto)) @@ -7096,7 +7316,7 @@ static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val, /* slow case if proxy in the prototype chain */ if (unlikely(p->class_id == JS_CLASS_PROXY)) { JSValue obj1; - obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, (JSObject *)p)); + obj1 = js_dup(JS_MKPTR(JS_TAG_OBJECT, (JSObject *)p)); for(;;) { obj1 = JS_GetPrototypeFree(ctx, obj1); if (JS_IsException(obj1)) { @@ -7104,12 +7324,12 @@ static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val, break; } if (JS_IsNull(obj1)) { - ret = FALSE; + ret = false; break; } if (proto == JS_VALUE_GET_OBJ(obj1)) { JS_FreeValue(ctx, obj1); - ret = TRUE; + ret = true; break; } /* must check for timeout to avoid infinite loop */ @@ -7120,13 +7340,13 @@ static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val, } } } else { - ret = FALSE; + ret = false; } break; } p = proto1; if (proto == p) { - ret = TRUE; + ret = true; break; } } @@ -7135,8 +7355,8 @@ static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val, return ret; } -/* return TRUE, FALSE or (-1) in case of exception */ -int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj) +/* return true, false or (-1) in case of exception */ +int JS_IsInstanceOf(JSContext *ctx, JSValue val, JSValue obj) { JSValue method; @@ -7193,15 +7413,17 @@ static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop, return 0; } -JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, - JSAtom prop, JSValueConst this_obj, - BOOL throw_ref_error) +static JSValue JS_GetPropertyInternal2(JSContext *ctx, JSValue obj, + JSAtom prop, JSValue this_obj, + JSInlineCacheUpdate *icu, + bool throw_ref_error) { JSObject *p; JSProperty *pr; JSShapeProperty *prs; - uint32_t tag; + uint32_t tag, offset, proto_depth; + offset = proto_depth = 0; tag = JS_VALUE_GET_TAG(obj); if (unlikely(tag != JS_TAG_OBJECT)) { switch(tag) { @@ -7218,14 +7440,11 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, uint32_t idx, ch; idx = __JS_AtomToUInt32(prop); if (idx < p1->len) { - if (p1->is_wide_char) - ch = p1->u.str16[idx]; - else - ch = p1->u.str8[idx]; + ch = string_get(p1, idx); return js_new_string_char(ctx, ch); } } else if (prop == JS_ATOM_length) { - return JS_NewInt32(ctx, p1->len); + return js_int32(p1->len); } } break; @@ -7241,7 +7460,7 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, } for(;;) { - prs = find_own_property(&pr, p, prop); + prs = find_own_property_ic(&pr, p, prop, &offset); if (prs) { /* found */ if (unlikely(prs->flags & JS_PROP_TMASK)) { @@ -7251,14 +7470,14 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, } else { JSValue func = JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter); /* Note: the field could be removed in the getter */ - func = JS_DupValue(ctx, func); + func = js_dup(func); return JS_CallFree(ctx, func, this_obj, 0, NULL); } } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { JSValue val = *pr->u.var_ref->pvalue; if (unlikely(JS_IsUninitialized(val))) return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); - return JS_DupValue(ctx, val); + return js_dup(val); } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { /* Instantiate property and retry */ if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) @@ -7268,7 +7487,9 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, } else { if (JS_IsUndefined(pr->u.value) && ctx->handleUndefined) ctx->handleUndefined(ctx); - return JS_DupValue(ctx, pr->u.value); + if (proto_depth == 0) + add_ic_slot(ctx, icu, prop, p, offset); + return js_dup(pr->u.value); } } if (unlikely(p->is_exotic)) { @@ -7279,12 +7500,10 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, if (idx < p->u.array.count) { /* we avoid duplicating the code */ 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) { + } else if (is_typed_array(p->class_id)) { return JS_UNDEFINED; } - } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_FLOAT64_ARRAY) { + } else if (is_typed_array(p->class_id)) { int ret; ret = JS_AtomIsNumericIndex(ctx, prop); if (ret != 0) { @@ -7301,7 +7520,7 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, /* XXX: should pass throw_ref_error */ /* Note: if 'p' is a prototype, it can be freed in the called function */ - obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); + obj1 = js_dup(JS_MKPTR(JS_TAG_OBJECT, p)); retval = em->get_property(ctx, obj1, prop, this_obj); JS_FreeValue(ctx, obj1); return retval; @@ -7313,7 +7532,7 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, /* Note: if 'p' is a prototype, it can be freed in the called function */ - obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); + obj1 = js_dup(JS_MKPTR(JS_TAG_OBJECT, p)); ret = em->get_own_property(ctx, &desc, obj1, prop); JS_FreeValue(ctx, obj1); if (ret < 0) @@ -7330,6 +7549,7 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, } } } + proto_depth++; p = p->shape->proto; if (!p) break; @@ -7341,6 +7561,36 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, } } +static JSValue JS_GetPropertyInternal(JSContext *ctx, JSValue obj, + JSAtom prop, JSValue this_obj, + bool throw_ref_error) +{ + return JS_GetPropertyInternal2(ctx, obj, prop, this_obj, NULL, throw_ref_error); +} + +JSValue JS_GetProperty(JSContext *ctx, JSValue this_obj, JSAtom prop) +{ + return JS_GetPropertyInternal2(ctx, this_obj, prop, this_obj, NULL, false); +} + +static JSValue JS_GetPropertyInternalWithIC(JSContext *ctx, JSValue obj, + JSAtom prop, JSValue this_obj, + JSInlineCacheUpdate *icu, + bool throw_ref_error) +{ + uint32_t tag, offset; + JSObject *p; + tag = JS_VALUE_GET_TAG(obj); + if (unlikely(tag != JS_TAG_OBJECT)) + goto slow_path; + p = JS_VALUE_GET_OBJ(obj); + offset = get_ic_prop_offset(icu, p->shape); + if (likely(offset != INLINE_CACHE_MISS)) + return js_dup(p->prop[offset].u.value); +slow_path: + return JS_GetPropertyInternal2(ctx, obj, prop, this_obj, icu, throw_ref_error); +} + static JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *ctx, JSAtom atom) { return JS_ThrowTypeErrorAtom(ctx, "private class field '%s' does not exist", @@ -7349,8 +7599,8 @@ static JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *ctx, JSAtom atom) /* Private fields can be added even on non extensible objects or Proxies */ -static int JS_DefinePrivateField(JSContext *ctx, JSValueConst obj, - JSValueConst name, JSValue val) +static int JS_DefinePrivateField(JSContext *ctx, JSValue obj, + JSValue name, JSValue val) { JSObject *p; JSShapeProperty *prs; @@ -7384,8 +7634,8 @@ static int JS_DefinePrivateField(JSContext *ctx, JSValueConst obj, return 0; } -static JSValue JS_GetPrivateField(JSContext *ctx, JSValueConst obj, - JSValueConst name) +static JSValue JS_GetPrivateField(JSContext *ctx, JSValue obj, + JSValue name) { JSObject *p; JSShapeProperty *prs; @@ -7404,11 +7654,11 @@ static JSValue JS_GetPrivateField(JSContext *ctx, JSValueConst obj, JS_ThrowTypeErrorPrivateNotFound(ctx, prop); return JS_EXCEPTION; } - return JS_DupValue(ctx, pr->u.value); + return js_dup(pr->u.value); } -static int JS_SetPrivateField(JSContext *ctx, JSValueConst obj, - JSValueConst name, JSValue val) +static int JS_SetPrivateField(JSContext *ctx, JSValue obj, + JSValue name, JSValue val) { JSObject *p; JSShapeProperty *prs; @@ -7439,7 +7689,7 @@ static int JS_SetPrivateField(JSContext *ctx, JSValueConst obj, /* add a private brand field to 'home_obj' if not already present and if obj is != null add a private brand to it */ -static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj) +static int JS_AddBrand(JSContext *ctx, JSValue obj, JSValue home_obj) { JSObject *p, *p1; JSShapeProperty *prs; @@ -7463,9 +7713,9 @@ static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj) JS_FreeValue(ctx, brand); return -1; } - pr->u.value = JS_DupValue(ctx, brand); + pr->u.value = js_dup(brand); } else { - brand = JS_DupValue(ctx, pr->u.value); + brand = js_dup(pr->u.value); } brand_atom = js_symbol_to_atom(ctx, brand); @@ -7485,17 +7735,18 @@ static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj) } else { JS_FreeAtom(ctx, brand_atom); } + return 0; } /* return a boolean telling if the brand of the home object of 'func' is present on 'obj' or -1 in case of exception */ -static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func) +static int JS_CheckBrand(JSContext *ctx, JSValue obj, JSValue func) { JSObject *p, *p1, *home_obj; JSShapeProperty *prs; JSProperty *pr; - JSValueConst brand; + JSValue brand; /* get the home object of 'func' */ if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)) @@ -7528,7 +7779,7 @@ static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func) } static uint32_t js_string_obj_get_length(JSContext *ctx, - JSValueConst obj) + JSValue obj) { JSObject *p; JSString *p1; @@ -7549,7 +7800,7 @@ static int num_keys_cmp(const void *p1, const void *p2, void *opaque) JSAtom atom1 = ((const JSPropertyEnum *)p1)->atom; JSAtom atom2 = ((const JSPropertyEnum *)p2)->atom; uint32_t v1, v2; - BOOL atom1_is_integer, atom2_is_integer; + bool atom1_is_integer, atom2_is_integer; atom1_is_integer = JS_AtomIsArrayIndex(ctx, &v1, atom1); atom2_is_integer = JS_AtomIsArrayIndex(ctx, &v2, atom2); @@ -7586,7 +7837,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, 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, exotic_keys_count; - BOOL is_enumerable, num_sorted; + bool is_enumerable, num_sorted; uint32_t num_key; JSAtomKindEnum kind; @@ -7649,7 +7900,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, atom = tab_exotic[i].atom; kind = JS_AtomGetKind(ctx, atom); if (((flags >> kind) & 1) != 0) { - is_enumerable = FALSE; + is_enumerable = false; if (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY)) { JSPropertyDescriptor desc; int res; @@ -7689,7 +7940,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, str_index = num_keys_count; sym_index = str_index + str_keys_count; - num_sorted = TRUE; + num_sorted = true; sh = p->shape; for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) { atom = prs->atom; @@ -7700,7 +7951,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, ((flags >> kind) & 1) != 0) { if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) { j = num_index++; - num_sorted = FALSE; + num_sorted = false; } else if (kind == JS_ATOM_KIND_STRING) { j = str_index++; } else { @@ -7729,7 +7980,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, js_free_prop_enum(ctx, tab_atom, num_index); return -1; } - tab_atom[num_index].is_enumerable = TRUE; + tab_atom[num_index].is_enumerable = true; num_index++; } } @@ -7766,7 +8017,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, } int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, - uint32_t *plen, JSValueConst obj, int flags) + uint32_t *plen, JSValue obj, int flags) { if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) { JS_ThrowTypeErrorNotAnObject(ctx); @@ -7777,7 +8028,7 @@ int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, } /* Return -1 if exception, - FALSE if the property does not exist, TRUE if it exists. If TRUE is + false if the property does not exist, true if it exists. If true is returned, the property descriptor 'desc' is filled present. */ static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc, JSObject *p, JSAtom prop) @@ -7797,16 +8048,16 @@ static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc, if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { desc->flags |= JS_PROP_GETSET; if (pr->u.getset.getter) - desc->getter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter)); + desc->getter = js_dup(JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter)); if (pr->u.getset.setter) - desc->setter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter)); + desc->setter = js_dup(JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter)); } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { JSValue val = *pr->u.var_ref->pvalue; if (unlikely(JS_IsUninitialized(val))) { JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); return -1; } - desc->value = JS_DupValue(ctx, val); + desc->value = js_dup(val); } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { /* Instantiate property and retry */ if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) @@ -7814,7 +8065,7 @@ static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc, goto retry; } } else { - desc->value = JS_DupValue(ctx, pr->u.value); + desc->value = js_dup(pr->u.value); } } else { /* for consistency, send the exception even if desc is NULL */ @@ -7827,7 +8078,7 @@ static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc, /* nothing to do: delay instantiation until actual value and/or attributes are read */ } } - return TRUE; + return true; } if (p->is_exotic) { if (p->fast_array) { @@ -7843,7 +8094,7 @@ static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc, desc->setter = JS_UNDEFINED; desc->value = JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx); } - return TRUE; + return true; } } } else { @@ -7854,11 +8105,11 @@ static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc, } } } - return FALSE; + return false; } int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc, - JSValueConst obj, JSAtom prop) + JSValue obj, JSAtom prop) { if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) { JS_ThrowTypeErrorNotAnObject(ctx); @@ -7867,13 +8118,19 @@ int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc, return JS_GetOwnPropertyInternal(ctx, desc, JS_VALUE_GET_OBJ(obj), prop); } -/* return -1 if exception (Proxy object only) or TRUE/FALSE */ -int JS_IsExtensible(JSContext *ctx, JSValueConst obj) +void JS_FreePropertyEnum(JSContext *ctx, JSPropertyEnum *tab, + uint32_t len) +{ + js_free_prop_enum(ctx, tab, len); +} + +/* return -1 if exception (Proxy object only) or true/false */ +int JS_IsExtensible(JSContext *ctx, JSValue obj) { JSObject *p; if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) - return FALSE; + return false; p = JS_VALUE_GET_OBJ(obj); if (unlikely(p->class_id == JS_CLASS_PROXY)) return js_proxy_isExtensible(ctx, obj); @@ -7881,61 +8138,60 @@ int JS_IsExtensible(JSContext *ctx, JSValueConst obj) return p->extensible; } -/* return -1 if exception (Proxy object only) or TRUE/FALSE */ -int JS_PreventExtensions(JSContext *ctx, JSValueConst obj) +/* return -1 if exception (Proxy object only) or true/false */ +int JS_PreventExtensions(JSContext *ctx, JSValue obj) { JSObject *p; if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) - return FALSE; + return false; p = JS_VALUE_GET_OBJ(obj); if (unlikely(p->class_id == JS_CLASS_PROXY)) return js_proxy_preventExtensions(ctx, obj); - p->extensible = FALSE; - return TRUE; + p->extensible = false; + return true; } -/* return -1 if exception otherwise TRUE or FALSE */ -int JS_HasProperty(JSContext *ctx, JSValueConst obj, JSAtom prop) +/* return -1 if exception otherwise true or false */ +int JS_HasProperty(JSContext *ctx, JSValue obj, JSAtom prop) { JSObject *p; int ret; JSValue obj1; if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) - return FALSE; + return false; p = JS_VALUE_GET_OBJ(obj); for(;;) { if (p->is_exotic) { const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; if (em && em->has_property) { /* has_property can free the prototype */ - obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); + obj1 = js_dup(JS_MKPTR(JS_TAG_OBJECT, p)); ret = em->has_property(ctx, obj1, prop); JS_FreeValue(ctx, obj1); return ret; } } /* JS_GetOwnPropertyInternal can free the prototype */ - JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); + js_dup(JS_MKPTR(JS_TAG_OBJECT, p)); ret = JS_GetOwnPropertyInternal(ctx, NULL, p, prop); JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); if (ret != 0) return ret; - if (p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_FLOAT64_ARRAY) { + if (is_typed_array(p->class_id)) { ret = JS_AtomIsNumericIndex(ctx, prop); if (ret != 0) { if (ret < 0) return -1; - return FALSE; + return false; } } p = p->shape->proto; if (!p) break; } - return FALSE; + return false; } /* val must be a symbol */ @@ -7946,7 +8202,7 @@ static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val) } /* return JS_ATOM_NULL in case of exception */ -JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val) +JSAtom JS_ValueToAtom(JSContext *ctx, JSValue val) { JSAtom atom; uint32_t tag; @@ -7972,120 +8228,154 @@ JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val) return atom; } -static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj, +static bool js_get_fast_array_element(JSContext *ctx, JSObject *p, + uint32_t idx, JSValue *pval) +{ + switch(p->class_id) { + case JS_CLASS_ARRAY: + case JS_CLASS_ARGUMENTS: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = js_dup(p->u.array.u.values[idx]); + return true; + case JS_CLASS_INT8_ARRAY: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = js_int32(p->u.array.u.int8_ptr[idx]); + return true; + case JS_CLASS_UINT8C_ARRAY: + case JS_CLASS_UINT8_ARRAY: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = js_int32(p->u.array.u.uint8_ptr[idx]); + return true; + case JS_CLASS_INT16_ARRAY: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = js_int32(p->u.array.u.int16_ptr[idx]); + return true; + case JS_CLASS_UINT16_ARRAY: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = js_int32(p->u.array.u.uint16_ptr[idx]); + return true; + case JS_CLASS_INT32_ARRAY: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = js_int32(p->u.array.u.int32_ptr[idx]); + return true; + case JS_CLASS_UINT32_ARRAY: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = js_uint32(p->u.array.u.uint32_ptr[idx]); + return true; + case JS_CLASS_BIG_INT64_ARRAY: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]); + return true; + case JS_CLASS_BIG_UINT64_ARRAY: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]); + return true; + case JS_CLASS_FLOAT16_ARRAY: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = js_float64(fromfp16(p->u.array.u.fp16_ptr[idx])); + return true; + case JS_CLASS_FLOAT32_ARRAY: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = js_float64(p->u.array.u.float_ptr[idx]); + return true; + case JS_CLASS_FLOAT64_ARRAY: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = js_float64(p->u.array.u.double_ptr[idx]); + return true; + default: + return false; + } +} + +static JSValue JS_GetPropertyValue(JSContext *ctx, JSValue this_obj, JSValue prop) { JSAtom atom; JSValue ret; + uint32_t tag; - if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT && - JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) { - JSObject *p; - uint32_t idx; - /* fast path for array access */ - p = JS_VALUE_GET_OBJ(this_obj); - idx = JS_VALUE_GET_INT(prop); - switch(p->class_id) { - case JS_CLASS_ARRAY: - case JS_CLASS_ARGUMENTS: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return JS_DupValue(ctx, p->u.array.u.values[idx]); - case JS_CLASS_INT8_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return JS_NewInt32(ctx, p->u.array.u.int8_ptr[idx]); - case JS_CLASS_UINT8C_ARRAY: - case JS_CLASS_UINT8_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return JS_NewInt32(ctx, p->u.array.u.uint8_ptr[idx]); - case JS_CLASS_INT16_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return JS_NewInt32(ctx, p->u.array.u.int16_ptr[idx]); - case JS_CLASS_UINT16_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return JS_NewInt32(ctx, p->u.array.u.uint16_ptr[idx]); - case JS_CLASS_INT32_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return JS_NewInt32(ctx, p->u.array.u.int32_ptr[idx]); - case JS_CLASS_UINT32_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return JS_NewUint32(ctx, p->u.array.u.uint32_ptr[idx]); - case JS_CLASS_BIG_INT64_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]); - case JS_CLASS_BIG_UINT64_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]); - case JS_CLASS_FLOAT32_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return __JS_NewFloat64(ctx, p->u.array.u.float_ptr[idx]); - case JS_CLASS_FLOAT64_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return __JS_NewFloat64(ctx, p->u.array.u.double_ptr[idx]); - default: - goto slow_path; + tag = JS_VALUE_GET_TAG(this_obj); + if (likely(tag == JS_TAG_OBJECT)) { + if (JS_VALUE_GET_TAG(prop) == JS_TAG_INT) { + JSObject *p = JS_VALUE_GET_OBJ(this_obj); + uint32_t idx = JS_VALUE_GET_INT(prop); + JSValue val; + /* fast path for array and typed array access */ + if (js_get_fast_array_element(ctx, p, idx, &val)) + return val; } } else { - slow_path: - atom = JS_ValueToAtom(ctx, prop); - JS_FreeValue(ctx, prop); - if (unlikely(atom == JS_ATOM_NULL)) - return JS_EXCEPTION; - ret = JS_GetProperty(ctx, this_obj, atom); - JS_FreeAtom(ctx, atom); - return ret; + switch(tag) { + case JS_TAG_NULL: + JS_FreeValue(ctx, prop); + return JS_ThrowTypeError(ctx, "cannot read property of null"); + case JS_TAG_UNDEFINED: + JS_FreeValue(ctx, prop); + return JS_ThrowTypeError(ctx, "cannot read property of undefined"); + } } + atom = JS_ValueToAtom(ctx, prop); + JS_FreeValue(ctx, prop); + if (unlikely(atom == JS_ATOM_NULL)) + return JS_EXCEPTION; + ret = JS_GetProperty(ctx, this_obj, atom); + JS_FreeAtom(ctx, atom); + return ret; } -JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj, +JSValue JS_GetPropertyUint32(JSContext *ctx, JSValue this_obj, uint32_t idx) { - return JS_GetPropertyValue(ctx, this_obj, JS_NewUint32(ctx, idx)); + return JS_GetPropertyInt64(ctx, this_obj, idx); } /* Check if an object has a generalized numeric property. Return value: - -1 for exception, - TRUE if property exists, stored into *pval, - FALSE if proprty does not exist. + -1 for exception, *pval set to JS_EXCEPTION + true if property exists, stored into *pval, + false if property does not exist. *pval set to JS_UNDEFINED. */ -static int JS_TryGetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, JSValue *pval) +static int JS_TryGetPropertyInt64(JSContext *ctx, JSValue obj, int64_t idx, JSValue *pval) { - JSValue val = JS_UNDEFINED; + JSValue val; JSAtom prop; int present; - if (likely((uint64_t)idx <= JS_ATOM_MAX_INT)) { - /* fast path */ - present = JS_HasProperty(ctx, obj, __JS_AtomFromUInt32(idx)); + if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT && + (uint64_t)idx <= INT32_MAX)) { + /* fast path for array and typed array access */ + JSObject *p = JS_VALUE_GET_OBJ(obj); + if (js_get_fast_array_element(ctx, p, idx, pval)) + return true; + } + val = JS_EXCEPTION; + present = -1; + prop = JS_NewAtomInt64(ctx, idx); + if (likely(prop != JS_ATOM_NULL)) { + present = JS_HasProperty(ctx, obj, prop); if (present > 0) { - val = JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx)); + val = JS_GetProperty(ctx, obj, prop); if (unlikely(JS_IsException(val))) present = -1; + } else if (present == false) { + val = JS_UNDEFINED; } - } else { - prop = JS_NewAtomInt64(ctx, idx); - present = -1; - if (likely(prop != JS_ATOM_NULL)) { - present = JS_HasProperty(ctx, obj, prop); - if (present > 0) { - val = JS_GetProperty(ctx, obj, prop); - if (unlikely(JS_IsException(val))) - present = -1; - } - JS_FreeAtom(ctx, prop); - } + JS_FreeAtom(ctx, prop); } *pval = val; return present; } -static JSValue JS_GetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx) +JSValue JS_GetPropertyInt64(JSContext *ctx, JSValue obj, int64_t idx) { JSAtom prop; JSValue val; - if ((uint64_t)idx <= INT32_MAX) { - /* fast path for fast arrays */ - return JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx)); + if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT && + (uint64_t)idx <= INT32_MAX)) { + /* fast path for array and typed array access */ + JSObject *p = JS_VALUE_GET_OBJ(obj); + if (js_get_fast_array_element(ctx, p, idx, &val)) + return val; } prop = JS_NewAtomInt64(ctx, idx); if (prop == JS_ATOM_NULL) @@ -8096,7 +8386,8 @@ static JSValue JS_GetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx return val; } -JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj, +/* `prop` may be pure ASCII or UTF-8 encoded */ +JSValue JS_GetPropertyStr(JSContext *ctx, JSValue this_obj, const char *prop) { JSAtom atom; @@ -8138,7 +8429,7 @@ static JSProperty *add_property(JSContext *ctx, if (!new_sh) return NULL; /* hash the cloned shape */ - new_sh->is_hashed = TRUE; + new_sh->is_hashed = true; js_shape_hash_link(ctx->rt, new_sh); js_free_shape(ctx->rt, p->shape); p->shape = new_sh; @@ -8206,7 +8497,7 @@ static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom) if (likely(pr->atom == atom)) { /* found ! */ if (!(pr->flags & JS_PROP_CONFIGURABLE)) - return FALSE; + return false; /* realloc the shape if needed */ if (lpr) lpr_idx = lpr - get_shape_prop(sh); @@ -8235,7 +8526,7 @@ static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom) sh->deleted_prop_count >= ((unsigned)sh->prop_count / 2)) { compact_properties(ctx, p); } - return TRUE; + return true; } lpr = pr; h = pr->hash_next; @@ -8252,13 +8543,13 @@ static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom) if (idx == p->u.array.count - 1) { JS_FreeValue(ctx, p->u.array.u.values[idx]); p->u.array.count = idx; - return TRUE; + return true; } if (convert_fast_array_to_array(ctx, p)) return -1; goto redo; } else { - return FALSE; + return false; } } } else { @@ -8269,23 +8560,23 @@ static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom) } } /* not found */ - return TRUE; + return true; } static int call_setter(JSContext *ctx, JSObject *setter, - JSValueConst this_obj, JSValue val, int flags) + JSValue this_obj, JSValue val, int flags) { JSValue ret, func; if (likely(setter)) { func = JS_MKPTR(JS_TAG_OBJECT, setter); /* Note: the field could be removed in the setter */ - func = JS_DupValue(ctx, func); - ret = JS_CallFree(ctx, func, this_obj, 1, (JSValueConst *)&val); + func = js_dup(func); + ret = JS_CallFree(ctx, func, this_obj, 1, &val); JS_FreeValue(ctx, val); if (JS_IsException(ret)) return -1; JS_FreeValue(ctx, ret); - return TRUE; + return true; } else { JS_FreeValue(ctx, val); if ((flags & JS_PROP_THROW) || @@ -8293,7 +8584,7 @@ static int call_setter(JSContext *ctx, JSObject *setter, JS_ThrowTypeError(ctx, "no setter for property"); return -1; } - return FALSE; + return false; } } @@ -8305,7 +8596,7 @@ static int set_array_length(JSContext *ctx, JSObject *p, JSValue val, int i, ret; /* Note: this call can reallocate the properties of 'p' */ - ret = JS_ToArrayLengthFree(ctx, &len, val, FALSE); + ret = JS_ToArrayLengthFree(ctx, &len, val, false); if (ret) return -1; /* JS_ToArrayLengthFree() must be done before the read-only test */ @@ -8320,7 +8611,7 @@ static int set_array_length(JSContext *ctx, JSObject *p, JSValue val, } p->u.array.count = len; } - p->prop[0].u.value = JS_NewUint32(ctx, len); + p->prop[0].u.value = js_uint32(len); } else { /* Note: length is always a uint32 because the object is an array */ @@ -8380,12 +8671,12 @@ static int set_array_length(JSContext *ctx, JSObject *p, JSValue val, } else { cur_len = len; } - set_value(ctx, &p->prop[0].u.value, JS_NewUint32(ctx, cur_len)); + set_value(ctx, &p->prop[0].u.value, js_uint32(cur_len)); if (unlikely(cur_len > len)) { return JS_ThrowTypeErrorOrFalse(ctx, flags, "not configurable"); } } - return TRUE; + return true; } /* return -1 if exception */ @@ -8406,7 +8697,7 @@ static int expand_fast_array(JSContext *ctx, JSObject *p, uint32_t new_len) } /* Preconditions: 'p' must be of class JS_CLASS_ARRAY, p->fast_array = - TRUE and p->extensible = TRUE */ + true and p->extensible = true */ static int add_fast_array_element(JSContext *ctx, JSObject *p, JSValue val, int flags) { @@ -8423,7 +8714,7 @@ static int add_fast_array_element(JSContext *ctx, JSObject *p, JS_FreeValue(ctx, val); return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length); } - p->prop[0].u.value = JS_NewInt32(ctx, new_len); + p->prop[0].u.value = js_int32(new_len); } } if (unlikely(new_len > p->u.array.u1.size)) { @@ -8434,31 +8725,7 @@ static int add_fast_array_element(JSContext *ctx, JSObject *p, } p->u.array.u.values[new_len - 1] = val; p->u.array.count = new_len; - return TRUE; -} - -/* Allocate a new fast array. Its 'length' property is set to zero. It - maximum size is 2^31-1 elements. For convenience, 'len' is a 64 bit - integer. WARNING: the content of the array is not initialized. */ -static JSValue js_allocate_fast_array(JSContext *ctx, int64_t len) -{ - JSValue arr; - JSObject *p; - - if (len > INT32_MAX) - return JS_ThrowRangeError(ctx, "invalid array length"); - arr = JS_NewArray(ctx); - if (JS_IsException(arr)) - return arr; - if (len > 0) { - p = JS_VALUE_GET_OBJ(arr); - if (expand_fast_array(ctx, p, len) < 0) { - JS_FreeValue(ctx, arr); - return JS_EXCEPTION; - } - p->u.array.count = len; - } - return arr; + return true; } static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc) @@ -8468,63 +8735,53 @@ static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc) JS_FreeValue(ctx, desc->value); } -/* return -1 in case of exception or TRUE or FALSE. Warning: 'val' is +/* return -1 in case of exception or true or false. Warning: 'val' is freed by the function. 'flags' is a bitmask of JS_PROP_NO_ADD, JS_PROP_THROW or JS_PROP_THROW_STRICT. If JS_PROP_NO_ADD is set, - the new property is not added and an error is raised. 'this_obj' is - the receiver. If obj != this_obj, then obj must be an object - (Reflect.set case). */ -int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj, - JSAtom prop, JSValue val, JSValueConst this_obj, int flags) + the new property is not added and an error is raised. + 'obj' must be an object when obj != this_obj. + */ +static int JS_SetPropertyInternal2(JSContext *ctx, JSValue obj, JSAtom prop, + JSValue val, JSValue this_obj, int flags, + JSInlineCacheUpdate *icu) { JSObject *p, *p1; JSShapeProperty *prs; JSProperty *pr; - uint32_t tag; JSPropertyDescriptor desc; int ret; -#if 0 - printf("JS_SetPropertyInternal: "); print_atom(ctx, prop); printf("\n"); -#endif - tag = JS_VALUE_GET_TAG(this_obj); - if (unlikely(tag != JS_TAG_OBJECT)) { - if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { - p = NULL; - p1 = JS_VALUE_GET_OBJ(obj); - goto prototype_lookup; - } else { - switch(tag) { - case JS_TAG_NULL: - JS_FreeValue(ctx, val); - JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of null", prop); - return -1; - case JS_TAG_UNDEFINED: - JS_FreeValue(ctx, val); - JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of undefined", prop); - return -1; - default: - /* even on a primitive type we can have setters on the prototype */ - p = NULL; - p1 = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj)); - goto prototype_lookup; - } - } - } else { + uint32_t offset = 0; + + switch(JS_VALUE_GET_TAG(this_obj)) { + case JS_TAG_NULL: + JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of null", prop); + goto fail; + case JS_TAG_UNDEFINED: + JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of undefined", prop); + goto fail; + case JS_TAG_OBJECT: p = JS_VALUE_GET_OBJ(this_obj); p1 = JS_VALUE_GET_OBJ(obj); - if (unlikely(p != p1)) - goto retry2; + if (p == p1) + break; + goto retry2; + default: + if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) + obj = JS_GetPrototypePrimitive(ctx, obj); + p = NULL; + p1 = JS_VALUE_GET_OBJ(obj); + goto prototype_lookup; } - /* fast path if obj == this_obj */ - retry: - prs = find_own_property(&pr, p1, prop); +retry: + prs = find_own_property_ic(&pr, p1, prop, &offset); if (prs) { if (likely((prs->flags & (JS_PROP_TMASK | JS_PROP_WRITABLE | JS_PROP_LENGTH)) == JS_PROP_WRITABLE)) { /* fast case */ + add_ic_slot(ctx, icu, prop, p, offset); set_value(ctx, &pr->u.value, val); - return TRUE; + return true; } else if (prs->flags & JS_PROP_LENGTH) { assert(p->class_id == JS_CLASS_ARRAY); assert(prop == JS_ATOM_length); @@ -8538,13 +8795,11 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj, if (p->class_id == JS_CLASS_MODULE_NS) goto read_only_prop; set_value(ctx, pr->u.var_ref->pvalue, val); - return TRUE; + 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, prs)) { - JS_FreeValue(ctx, val); - return -1; - } + if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) + goto fail; goto retry; } else { goto read_only_prop; @@ -8558,23 +8813,19 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj, uint32_t idx = __JS_AtomToUInt32(prop); if (idx < p1->u.array.count) { if (unlikely(p == p1)) - return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val, flags); + return JS_SetPropertyValue(ctx, this_obj, js_int32(idx), val, flags); else break; - } else if (p1->class_id >= JS_CLASS_UINT8C_ARRAY && - p1->class_id <= JS_CLASS_FLOAT64_ARRAY) { + } else if (is_typed_array(p1->class_id)) { goto typed_array_oob; } - } else if (p1->class_id >= JS_CLASS_UINT8C_ARRAY && - p1->class_id <= JS_CLASS_FLOAT64_ARRAY) { + } else if (is_typed_array(p1->class_id)) { ret = JS_AtomIsNumericIndex(ctx, prop); if (ret != 0) { - if (ret < 0) { - JS_FreeValue(ctx, val); - return -1; - } + if (ret < 0) + goto fail; typed_array_oob: - /* must convert the argument even if out of bound access */ + // per spec: evaluate value for side effects if (p1->class_id == JS_CLASS_BIG_INT64_ARRAY || p1->class_id == JS_CLASS_BIG_UINT64_ARRAY) { int64_t v; @@ -8586,7 +8837,7 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj, if (JS_IsException(val)) return -1; } - return TRUE; + return true; } } } else { @@ -8595,7 +8846,7 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj, JSValue obj1; if (em->set_property) { /* set_property can free the prototype */ - obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1)); + obj1 = js_dup(JS_MKPTR(JS_TAG_OBJECT, p1)); ret = em->set_property(ctx, obj1, prop, val, this_obj, flags); JS_FreeValue(ctx, obj1); @@ -8604,14 +8855,12 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj, } if (em->get_own_property) { /* get_own_property can free the prototype */ - obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1)); + obj1 = js_dup(JS_MKPTR(JS_TAG_OBJECT, p1)); ret = em->get_own_property(ctx, &desc, obj1, prop); JS_FreeValue(ctx, obj1); - if (ret < 0) { - JS_FreeValue(ctx, val); - return ret; - } + if (ret < 0) + goto fail; if (ret) { if (desc.flags & JS_PROP_GETSET) { JSObject *setter; @@ -8664,22 +8913,21 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj, } if (unlikely(flags & JS_PROP_NO_ADD)) { - JS_FreeValue(ctx, val); JS_ThrowReferenceErrorNotDefined(ctx, prop); - return -1; + goto fail; } if (unlikely(!p)) { - JS_FreeValue(ctx, val); - return JS_ThrowTypeErrorOrFalse(ctx, flags, "not an object"); + ret = JS_ThrowTypeErrorOrFalse(ctx, flags, "not an object"); + goto done; } if (unlikely(!p->extensible)) { - JS_FreeValue(ctx, val); - return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible"); + ret = JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible"); + goto done; } - if (likely(p == JS_VALUE_GET_OBJ(obj))) { + if (p == JS_VALUE_GET_OBJ(obj)) { if (p->is_exotic) { if (p->class_id == JS_CLASS_ARRAY && p->fast_array && __JS_AtomIsTaggedInt(prop)) { @@ -8687,65 +8935,94 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj, if (idx == p->u.array.count) { /* fast case */ return add_fast_array_element(ctx, p, val, flags); - } else { - goto generic_create_prop; } - } else { - goto generic_create_prop; } + goto generic_create_prop; } else { pr = add_property(ctx, p, prop, JS_PROP_C_W_E); - if (unlikely(!pr)) { - JS_FreeValue(ctx, val); - return -1; - } + if (!pr) + goto fail; pr->u.value = val; - return TRUE; + return true; } - } else { - /* generic case: modify the property in this_obj if it already exists */ - ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop); - if (ret < 0) { - JS_FreeValue(ctx, val); - return ret; - } - if (ret) { - if (desc.flags & JS_PROP_GETSET) { - JS_FreeValue(ctx, desc.getter); - JS_FreeValue(ctx, desc.setter); - JS_FreeValue(ctx, val); - return JS_ThrowTypeErrorOrFalse(ctx, flags, "setter is forbidden"); - } else { - JS_FreeValue(ctx, desc.value); - if (!(desc.flags & JS_PROP_WRITABLE) || - p->class_id == JS_CLASS_MODULE_NS) { - read_only_prop: - JS_FreeValue(ctx, val); - return JS_ThrowTypeErrorReadOnly(ctx, flags, prop); - } - } - ret = JS_DefineProperty(ctx, this_obj, prop, val, - JS_UNDEFINED, JS_UNDEFINED, - JS_PROP_HAS_VALUE); - JS_FreeValue(ctx, val); - return ret; - } else { - generic_create_prop: - ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED, - flags | - JS_PROP_HAS_VALUE | - JS_PROP_HAS_ENUMERABLE | - JS_PROP_HAS_WRITABLE | - JS_PROP_HAS_CONFIGURABLE | - JS_PROP_C_W_E); - JS_FreeValue(ctx, val); - return ret; + } + + // TODO(bnoordhuis) return JSProperty slot and update in place + // when plain property (not is_exotic/setter/etc.) to avoid + // calling find_own_property() thrice? + ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop); + if (ret < 0) + goto fail; + + if (ret) { + JS_FreeValue(ctx, desc.value); + if (desc.flags & JS_PROP_GETSET) { + JS_FreeValue(ctx, desc.getter); + JS_FreeValue(ctx, desc.setter); + ret = JS_ThrowTypeErrorOrFalse(ctx, flags, "setter is forbidden"); + goto done; + } else if (!(desc.flags & JS_PROP_WRITABLE) || + p->class_id == JS_CLASS_MODULE_NS) { + read_only_prop: + ret = JS_ThrowTypeErrorReadOnly(ctx, flags, prop); + goto done; } + ret = JS_DefineProperty(ctx, this_obj, prop, val, + JS_UNDEFINED, JS_UNDEFINED, + JS_PROP_HAS_VALUE); + } else { + generic_create_prop: + ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED, + flags | + JS_PROP_HAS_VALUE | + JS_PROP_HAS_ENUMERABLE | + JS_PROP_HAS_WRITABLE | + JS_PROP_HAS_CONFIGURABLE | + JS_PROP_C_W_E); + } + +done: + JS_FreeValue(ctx, val); + return ret; +fail: + JS_FreeValue(ctx, val); + return -1; +} + +static int JS_SetPropertyInternal(JSContext *ctx, JSValue this_obj, + JSAtom prop, JSValue val, int flags) +{ + return JS_SetPropertyInternal2(ctx, this_obj, prop, val, this_obj, + flags, NULL); +} + +int JS_SetProperty(JSContext *ctx, JSValue this_obj, JSAtom prop, JSValue val) +{ + return JS_SetPropertyInternal2(ctx, this_obj, prop, val, this_obj, JS_PROP_THROW, NULL); +} + +// XXX(bnoordhuis) only used by OP_put_field_ic, maybe inline at call site +static int JS_SetPropertyInternalWithIC(JSContext *ctx, JSValue this_obj, + JSAtom prop, JSValue val, int flags, + JSInlineCacheUpdate *icu) { + uint32_t tag, offset; + JSObject *p; + tag = JS_VALUE_GET_TAG(this_obj); + if (unlikely(tag != JS_TAG_OBJECT)) + goto slow_path; + p = JS_VALUE_GET_OBJ(this_obj); + offset = get_ic_prop_offset(icu, p->shape); + if (likely(offset != INLINE_CACHE_MISS)) { + set_value(ctx, &p->prop[offset].u.value, val); + return true; } +slow_path: + return JS_SetPropertyInternal2(ctx, this_obj, prop, val, this_obj, + flags, icu); } /* flags can be JS_PROP_THROW or JS_PROP_THROW_STRICT */ -static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, +static int JS_SetPropertyValue(JSContext *ctx, JSValue this_obj, JSValue prop, JSValue val, int flags) { if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT && @@ -8795,7 +9072,7 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, break; case JS_CLASS_UINT8C_ARRAY: if (JS_ToUint8ClampFree(ctx, &v, val)) - return -1; + goto ta_cvt_fail; /* Note: the conversion can detach the typed array, so the array bound check must be done after */ if (unlikely(idx >= (uint32_t)p->u.array.count)) @@ -8805,7 +9082,7 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, case JS_CLASS_INT8_ARRAY: case JS_CLASS_UINT8_ARRAY: if (JS_ToInt32Free(ctx, &v, val)) - return -1; + goto ta_cvt_fail; if (unlikely(idx >= (uint32_t)p->u.array.count)) goto ta_out_of_bound; p->u.array.u.uint8_ptr[idx] = v; @@ -8813,7 +9090,7 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, case JS_CLASS_INT16_ARRAY: case JS_CLASS_UINT16_ARRAY: if (JS_ToInt32Free(ctx, &v, val)) - return -1; + goto ta_cvt_fail; if (unlikely(idx >= (uint32_t)p->u.array.count)) goto ta_out_of_bound; p->u.array.u.uint16_ptr[idx] = v; @@ -8821,7 +9098,7 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, case JS_CLASS_INT32_ARRAY: case JS_CLASS_UINT32_ARRAY: if (JS_ToInt32Free(ctx, &v, val)) - return -1; + goto ta_cvt_fail; if (unlikely(idx >= (uint32_t)p->u.array.count)) goto ta_out_of_bound; p->u.array.u.uint32_ptr[idx] = v; @@ -8832,32 +9109,48 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, { int64_t v; if (JS_ToBigInt64Free(ctx, &v, val)) - return -1; + goto ta_cvt_fail; if (unlikely(idx >= (uint32_t)p->u.array.count)) goto ta_out_of_bound; p->u.array.u.uint64_ptr[idx] = v; } break; + case JS_CLASS_FLOAT16_ARRAY: + if (JS_ToFloat64Free(ctx, &d, val)) + goto ta_cvt_fail; + if (unlikely(idx >= (uint32_t)p->u.array.count)) + goto ta_out_of_bound; + p->u.array.u.fp16_ptr[idx] = tofp16(d); + break; case JS_CLASS_FLOAT32_ARRAY: if (JS_ToFloat64Free(ctx, &d, val)) - return -1; + goto ta_cvt_fail; if (unlikely(idx >= (uint32_t)p->u.array.count)) goto ta_out_of_bound; p->u.array.u.float_ptr[idx] = d; break; case JS_CLASS_FLOAT64_ARRAY: - if (JS_ToFloat64Free(ctx, &d, val)) + if (JS_ToFloat64Free(ctx, &d, val)) { + ta_cvt_fail: + if (flags & JS_PROP_REFLECT_DEFINE_PROPERTY) { + JS_FreeValue(ctx, JS_GetException(ctx)); + return false; + } return -1; + } if (unlikely(idx >= (uint32_t)p->u.array.count)) { ta_out_of_bound: - return TRUE; + if (typed_array_is_oob(p)) + if (flags & JS_PROP_DEFINE_PROPERTY) + return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index"); + return true; // per spec: no OOB exception } p->u.array.u.double_ptr[idx] = d; break; default: goto slow_path; } - return TRUE; + return true; } else { JSAtom atom; int ret; @@ -8868,20 +9161,20 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, JS_FreeValue(ctx, val); return -1; } - ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, flags); + ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, flags); JS_FreeAtom(ctx, atom); return ret; } } -int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj, +int JS_SetPropertyUint32(JSContext *ctx, JSValue this_obj, uint32_t idx, JSValue val) { - return JS_SetPropertyValue(ctx, this_obj, JS_NewUint32(ctx, idx), val, + return JS_SetPropertyValue(ctx, this_obj, js_uint32(idx), val, JS_PROP_THROW); } -int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj, +int JS_SetPropertyInt64(JSContext *ctx, JSValue this_obj, int64_t idx, JSValue val) { JSAtom prop; @@ -8889,7 +9182,7 @@ int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj, if ((uint64_t)idx <= INT32_MAX) { /* fast path for fast arrays */ - return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val, + return JS_SetPropertyValue(ctx, this_obj, js_int32(idx), val, JS_PROP_THROW); } prop = JS_NewAtomInt64(ctx, idx); @@ -8902,13 +9195,14 @@ int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj, return res; } -int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj, +/* `prop` may be pure ASCII or UTF-8 encoded */ +int JS_SetPropertyStr(JSContext *ctx, JSValue this_obj, const char *prop, JSValue val) { JSAtom atom; int ret; atom = JS_NewAtom(ctx, prop); - ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, JS_PROP_THROW); + ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, JS_PROP_THROW); JS_FreeAtom(ctx, atom); return ret; } @@ -8925,8 +9219,8 @@ static int get_prop_flags(int flags, int def_flags) } static int JS_CreateProperty(JSContext *ctx, JSObject *p, - JSAtom prop, JSValueConst val, - JSValueConst getter, JSValueConst setter, + JSAtom prop, JSValue val, + JSValue getter, JSValue setter, int flags) { JSProperty *pr; @@ -8949,7 +9243,7 @@ static int JS_CreateProperty(JSContext *ctx, JSObject *p, if (prop_flags != JS_PROP_C_W_E) goto convert_to_array; return add_fast_array_element(ctx, p, - JS_DupValue(ctx, val), flags); + js_dup(val), flags); } else { goto convert_to_array; } @@ -8974,11 +9268,10 @@ static int JS_CreateProperty(JSContext *ctx, JSObject *p, /* XXX: should update the length after defining the property */ len = idx + 1; - set_value(ctx, &plen->u.value, JS_NewUint32(ctx, len)); + set_value(ctx, &plen->u.value, js_uint32(len)); } } - } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_FLOAT64_ARRAY) { + } else if (is_typed_array(p->class_id)) { ret = JS_AtomIsNumericIndex(ctx, prop); if (ret != 0) { if (ret < 0) @@ -9019,36 +9312,36 @@ static int JS_CreateProperty(JSContext *ctx, JSObject *p, pr->u.getset.getter = NULL; if ((flags & JS_PROP_HAS_GET) && JS_IsFunction(ctx, getter)) { pr->u.getset.getter = - JS_VALUE_GET_OBJ(JS_DupValue(ctx, getter)); + JS_VALUE_GET_OBJ(js_dup(getter)); } pr->u.getset.setter = NULL; if ((flags & JS_PROP_HAS_SET) && JS_IsFunction(ctx, setter)) { pr->u.getset.setter = - JS_VALUE_GET_OBJ(JS_DupValue(ctx, setter)); + JS_VALUE_GET_OBJ(js_dup(setter)); } } else { if (flags & JS_PROP_HAS_VALUE) { - pr->u.value = JS_DupValue(ctx, val); + pr->u.value = js_dup(val); } else { pr->u.value = JS_UNDEFINED; } } - return TRUE; + return true; } -/* return FALSE if not OK */ -static BOOL check_define_prop_flags(int prop_flags, int flags) +/* return false if not OK */ +static bool check_define_prop_flags(int prop_flags, int flags) { - BOOL has_accessor, is_getset; + bool has_accessor, is_getset; if (!(prop_flags & JS_PROP_CONFIGURABLE)) { if ((flags & (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) == (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) { - return FALSE; + return false; } if ((flags & JS_PROP_HAS_ENUMERABLE) && (flags & JS_PROP_ENUMERABLE) != (prop_flags & JS_PROP_ENUMERABLE)) - return FALSE; + return false; } if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { @@ -9056,16 +9349,16 @@ static BOOL check_define_prop_flags(int prop_flags, int flags) has_accessor = ((flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) != 0); is_getset = ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET); if (has_accessor != is_getset) - return FALSE; + return false; if (!has_accessor && !is_getset && !(prop_flags & JS_PROP_WRITABLE)) { /* not writable: cannot set the writable bit */ if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) - return FALSE; + return false; } } } - return TRUE; + return true; } /* ensure that the shape can be safely modified */ @@ -9090,7 +9383,7 @@ static int js_shape_prepare_update(JSContext *ctx, JSObject *p, *pprs = get_shape_prop(sh) + idx; } else { js_shape_hash_unlink(ctx->rt, sh); - sh->is_hashed = FALSE; + sh->is_hashed = false; } } return 0; @@ -9112,14 +9405,14 @@ static int js_update_property_flags(JSContext *ctx, JSObject *p, JS_PROP_HAS_GET, JS_PROP_HAS_SET, JS_PROP_HAS_VALUE, JS_PROP_HAS_CONFIGURABLE, JS_PROP_HAS_WRITABLE, JS_PROP_HAS_ENUMERABLE, JS_PROP_THROW, JS_PROP_NO_EXOTIC. - If JS_PROP_THROW is set, return an exception instead of FALSE. + If JS_PROP_THROW is set, return an exception instead of false. if JS_PROP_NO_EXOTIC is set, do not call the exotic define_own_property callback. - return -1 (exception), FALSE or TRUE. + return -1 (exception), false or true. */ -int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValueConst val, - JSValueConst getter, JSValueConst setter, int flags) +int JS_DefineProperty(JSContext *ctx, JSValue this_obj, + JSAtom prop, JSValue val, + JSValue getter, JSValue setter, int flags) { JSObject *p; JSShapeProperty *prs; @@ -9139,11 +9432,11 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, 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)) { + js_dup(val), false)) { return -1; } /* this code relies on the fact that Uint32 are never allocated */ - val = JS_NewUint32(ctx, array_length); + val = js_uint32(array_length); /* prs may have been modified */ prs = find_own_property(&pr, p, prop); assert(prs != NULL); @@ -9207,14 +9500,14 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, if (pr->u.getset.getter) JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter)); if (new_getter) - JS_DupValue(ctx, getter); + js_dup(getter); pr->u.getset.getter = new_getter; } if (flags & JS_PROP_HAS_SET) { if (pr->u.getset.setter) JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter)); if (new_setter) - JS_DupValue(ctx, setter); + js_dup(setter); pr->u.getset.setter = new_setter; } } else { @@ -9236,7 +9529,7 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, if (!js_same_value(ctx, val, pr->u.value)) { goto not_configurable; } else { - return TRUE; + return true; } } } @@ -9248,22 +9541,18 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, spaces. */ if (!js_same_value(ctx, val, *pr->u.var_ref->pvalue)) goto not_configurable; - } else { - /* update the reference */ - set_value(ctx, pr->u.var_ref->pvalue, - JS_DupValue(ctx, val)); } + /* update the reference */ + set_value(ctx, pr->u.var_ref->pvalue, + js_dup(val)); } /* if writable is set to false, no longer a reference (for mapped arguments) */ if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) { JSValue val1; - if (p->class_id == JS_CLASS_MODULE_NS) { - return JS_ThrowTypeErrorOrFalse(ctx, flags, "module namespace properties have writable = false"); - } if (js_shape_prepare_update(ctx, p, &prs)) return -1; - val1 = JS_DupValue(ctx, *pr->u.var_ref->pvalue); + val1 = js_dup(*pr->u.var_ref->pvalue); free_var_ref(ctx->rt, pr->u.var_ref); pr->u.value = val1; prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE); @@ -9272,10 +9561,10 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, 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), + res = set_array_length(ctx, p, js_dup(val), flags); } else { - res = TRUE; + res = true; } /* still need to reset the writable flag if needed. The JS_PROP_LENGTH is kept because the @@ -9292,7 +9581,7 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, } else { if (flags & JS_PROP_HAS_VALUE) { JS_FreeValue(ctx, pr->u.value); - pr->u.value = JS_DupValue(ctx, val); + pr->u.value = js_dup(val); } if (flags & JS_PROP_HAS_WRITABLE) { if (js_update_property_flags(ctx, p, &prs, @@ -9311,7 +9600,7 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, if (js_update_property_flags(ctx, p, &prs, (prs->flags & ~mask) | (flags & mask))) return -1; - return TRUE; + return true; } /* handle modification of fast array elements */ @@ -9333,13 +9622,12 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, goto redo_prop_update; } if (flags & JS_PROP_HAS_VALUE) { - set_value(ctx, &p->u.array.u.values[idx], JS_DupValue(ctx, val)); + set_value(ctx, &p->u.array.u.values[idx], js_dup(val)); } - return TRUE; + return true; } } - } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_FLOAT64_ARRAY) { + } else if (is_typed_array(p->class_id)) { JSValue num; int ret; @@ -9369,7 +9657,7 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, } idx = __JS_AtomToUInt32(prop); /* if the typed array is detached, p->u.array.count = 0 */ - if (idx >= p->u.array.count) { + if (idx >= typed_array_get_length(ctx, p)) { typed_array_oob: return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound index in typed array"); } @@ -9379,9 +9667,9 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, return JS_ThrowTypeErrorOrFalse(ctx, flags, "invalid descriptor flags"); } if (flags & JS_PROP_HAS_VALUE) { - return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), JS_DupValue(ctx, val), flags); + return JS_SetPropertyValue(ctx, this_obj, js_int32(idx), js_dup(val), flags); } - return TRUE; + return true; typed_array_done: ; } } @@ -9389,7 +9677,7 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, return JS_CreateProperty(ctx, p, prop, val, getter, setter, flags); } -static int JS_DefineAutoInitProperty(JSContext *ctx, JSValueConst this_obj, +static int JS_DefineAutoInitProperty(JSContext *ctx, JSValue this_obj, JSAtom prop, JSAutoInitIDEnum id, void *opaque, int flags) { @@ -9397,14 +9685,14 @@ static int JS_DefineAutoInitProperty(JSContext *ctx, JSValueConst this_obj, JSProperty *pr; if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT) - return FALSE; + return false; p = JS_VALUE_GET_OBJ(this_obj); if (find_own_property(&pr, p, prop)) { /* property already exists */ abort(); - return FALSE; + return false; } /* Specialized CreateProperty */ @@ -9416,11 +9704,11 @@ static int JS_DefineAutoInitProperty(JSContext *ctx, JSValueConst this_obj, assert(id <= 3); pr->u.init.realm_and_id |= id; pr->u.init.opaque = opaque; - return TRUE; + return true; } /* shortcut to add or redefine a new property value */ -int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj, +int JS_DefinePropertyValue(JSContext *ctx, JSValue this_obj, JSAtom prop, JSValue val, int flags) { int ret; @@ -9430,7 +9718,7 @@ int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj, return ret; } -int JS_DefinePropertyValueValue(JSContext *ctx, JSValueConst this_obj, +int JS_DefinePropertyValueValue(JSContext *ctx, JSValue this_obj, JSValue prop, JSValue val, int flags) { JSAtom atom; @@ -9446,21 +9734,22 @@ int JS_DefinePropertyValueValue(JSContext *ctx, JSValueConst this_obj, return ret; } -int JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj, +int JS_DefinePropertyValueUint32(JSContext *ctx, JSValue this_obj, uint32_t idx, JSValue val, int flags) { - return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewUint32(ctx, idx), + return JS_DefinePropertyValueValue(ctx, this_obj, js_uint32(idx), val, flags); } -int JS_DefinePropertyValueInt64(JSContext *ctx, JSValueConst this_obj, +int JS_DefinePropertyValueInt64(JSContext *ctx, JSValue this_obj, int64_t idx, JSValue val, int flags) { - return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewInt64(ctx, idx), + return JS_DefinePropertyValueValue(ctx, this_obj, js_int64(idx), val, flags); } -int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj, +/* `prop` may be pure ASCII or UTF-8 encoded */ +int JS_DefinePropertyValueStr(JSContext *ctx, JSValue this_obj, const char *prop, JSValue val, int flags) { JSAtom atom; @@ -9472,7 +9761,7 @@ int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj, } /* shortcut to add getter & setter */ -int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj, +int JS_DefinePropertyGetSet(JSContext *ctx, JSValue this_obj, JSAtom prop, JSValue getter, JSValue setter, int flags) { @@ -9485,36 +9774,36 @@ int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj, return ret; } -static int JS_CreateDataPropertyUint32(JSContext *ctx, JSValueConst this_obj, +static int JS_CreateDataPropertyUint32(JSContext *ctx, JSValue this_obj, int64_t idx, JSValue val, int flags) { - return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewInt64(ctx, idx), + return JS_DefinePropertyValueValue(ctx, this_obj, js_int64(idx), val, flags | JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE | JS_PROP_WRITABLE); } -/* return TRUE if 'obj' has a non empty 'name' string */ -static BOOL js_object_has_name(JSContext *ctx, JSValueConst obj) +/* return true if 'obj' has a non empty 'name' string */ +static bool js_object_has_name(JSContext *ctx, JSValue obj) { JSProperty *pr; JSShapeProperty *prs; - JSValueConst val; + JSValue val; JSString *p; prs = find_own_property(&pr, JS_VALUE_GET_OBJ(obj), JS_ATOM_name); if (!prs) - return FALSE; + return false; if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL) - return TRUE; + return true; val = pr->u.value; if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING) - return TRUE; + return true; p = JS_VALUE_GET_STRING(val); return (p->len != 0); } -static int JS_DefineObjectName(JSContext *ctx, JSValueConst obj, +static int JS_DefineObjectName(JSContext *ctx, JSValue obj, JSAtom name, int flags) { if (name != JS_ATOM_NULL @@ -9526,8 +9815,8 @@ static int JS_DefineObjectName(JSContext *ctx, JSValueConst obj, return 0; } -static int JS_DefineObjectNameComputed(JSContext *ctx, JSValueConst obj, - JSValueConst str, int flags) +static int JS_DefineObjectNameComputed(JSContext *ctx, JSValue obj, + JSValue str, int flags) { if (JS_IsObject(obj) && !js_object_has_name(ctx, obj)) { @@ -9632,7 +9921,7 @@ static int JS_DefineGlobalVar(JSContext *ctx, JSAtom prop, int def_flags) /* 'def_flags' is 0 or JS_PROP_CONFIGURABLE. */ /* XXX: could support exotic global object. */ static int JS_DefineGlobalFunction(JSContext *ctx, JSAtom prop, - JSValueConst func, int def_flags) + JSValue func, int def_flags) { JSObject *p; @@ -9653,7 +9942,7 @@ static int JS_DefineGlobalFunction(JSContext *ctx, JSAtom prop, } static JSValue JS_GetGlobalVar(JSContext *ctx, JSAtom prop, - BOOL throw_ref_error) + bool throw_ref_error) { JSObject *p; JSShapeProperty *prs; @@ -9666,7 +9955,7 @@ static JSValue JS_GetGlobalVar(JSContext *ctx, JSAtom prop, /* XXX: should handle JS_PROP_TMASK properties */ if (unlikely(JS_IsUninitialized(pr->u.value))) return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); - return JS_DupValue(ctx, pr->u.value); + return js_dup(pr->u.value); } if (ctx->scopeLookup) { struct LookupResult result = ctx->scopeLookup(ctx, prop); @@ -9698,14 +9987,14 @@ static int JS_GetGlobalVarRef(JSContext *ctx, JSAtom prop, JSValue *sp) if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) { return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop); } - sp[0] = JS_DupValue(ctx, ctx->global_var_obj); + sp[0] = js_dup(ctx->global_var_obj); } else { int ret; ret = JS_HasProperty(ctx, ctx->global_obj, prop); if (ret < 0) return -1; if (ret) { - sp[0] = JS_DupValue(ctx, ctx->global_obj); + sp[0] = js_dup(ctx->global_obj); } else { sp[0] = JS_UNDEFINED; } @@ -9725,7 +10014,7 @@ static int JS_CheckGlobalVar(JSContext *ctx, JSAtom prop) p = JS_VALUE_GET_OBJ(ctx->global_var_obj); prs = find_own_property1(p, prop); if (prs) { - ret = TRUE; + ret = true; } else { ret = JS_HasProperty(ctx, ctx->global_obj, prop); if (ret < 0) @@ -9773,17 +10062,17 @@ static int JS_SetGlobalVar(JSContext *ctx, JSAtom prop, JSValue val, struct LookupResult result = ctx->scopeLookup(ctx, prop); if (result.useResult) { JS_FreeValue(ctx, result.value); - return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, result.scope, flags); + return JS_SetPropertyInternal2(ctx, ctx->global_obj, prop, val, result.scope, flags, NULL); } } - return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, ctx->global_obj, flags); + return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, flags); } -/* return -1, FALSE or TRUE. return FALSE if not configurable or +/* return -1, false or true. return false if not configurable or invalid object. return -1 in case of exception. flags can be 0, JS_PROP_THROW or JS_PROP_THROW_STRICT */ -int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags) +int JS_DeleteProperty(JSContext *ctx, JSValue obj, JSAtom prop, int flags) { JSValue obj1; JSObject *p; @@ -9795,17 +10084,17 @@ int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags) p = JS_VALUE_GET_OBJ(obj1); res = delete_property(ctx, p, prop); JS_FreeValue(ctx, obj1); - if (res != FALSE) + if (res != false) return res; if ((flags & JS_PROP_THROW) || ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) { JS_ThrowTypeError(ctx, "could not delete property"); return -1; } - return FALSE; + return false; } -int JS_DeletePropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, int flags) +int JS_DeletePropertyInt64(JSContext *ctx, JSValue obj, int64_t idx, int flags) { JSAtom prop; int res; @@ -9822,15 +10111,15 @@ int JS_DeletePropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, int fl return res; } -BOOL JS_IsFunction(JSContext *ctx, JSValueConst val) +bool JS_IsFunction(JSContext *ctx, JSValue val) { JSObject *p; if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) - return FALSE; + return false; p = JS_VALUE_GET_OBJ(val); switch(p->class_id) { case JS_CLASS_BYTECODE_FUNCTION: - return TRUE; + return true; case JS_CLASS_PROXY: return p->u.proxy_data->is_func; default: @@ -9838,65 +10127,80 @@ BOOL JS_IsFunction(JSContext *ctx, JSValueConst val) } } -BOOL JS_IsCFunction(JSContext *ctx, JSValueConst val, JSCFunction *func, int magic) +bool JS_IsCFunction(JSContext *ctx, JSValue val, JSCFunction *func, int magic) { JSObject *p; if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) - return FALSE; + return false; p = JS_VALUE_GET_OBJ(val); if (p->class_id == JS_CLASS_C_FUNCTION) return (p->u.cfunc.c_function.generic == func && p->u.cfunc.magic == magic); else - return FALSE; + return false; } -BOOL JS_IsConstructor(JSContext *ctx, JSValueConst val) +bool JS_IsConstructor(JSContext *ctx, JSValue val) { JSObject *p; if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) - return FALSE; + return false; p = JS_VALUE_GET_OBJ(val); return p->is_constructor; } -BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, BOOL val) +bool JS_SetConstructorBit(JSContext *ctx, JSValue func_obj, bool val) { JSObject *p; if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT) - return FALSE; + return false; p = JS_VALUE_GET_OBJ(func_obj); p->is_constructor = val; - return TRUE; + return true; } -JS_BOOL JS_IsArrayBuffer(JSValueConst v) +bool JS_IsRegExp(JSValue val) { - if (!JS_IsObject(v)) - return FALSE; - JSObject *p = JS_VALUE_GET_OBJ(v); - return p->class_id == JS_CLASS_ARRAY_BUFFER || p->class_id == JS_CLASS_SHARED_ARRAY_BUFFER; + if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) + return false; + return JS_VALUE_GET_OBJ(val)->class_id == JS_CLASS_REGEXP; +} + +bool JS_IsMap(JSValue val) +{ + if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) + return false; + return JS_VALUE_GET_OBJ(val)->class_id == JS_CLASS_MAP; } -BOOL JS_IsError(JSContext *ctx, JSValueConst val) +int JS_IsSimpleValue(JSContext* ctx, JSValue v) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT) + return 1; + p = JS_VALUE_GET_OBJ(v); + return p->class_id >= JS_CLASS_OBJECT && p->class_id <= JS_CLASS_BOOLEAN; +} + +bool JS_IsError(JSContext *ctx, JSValue val) { JSObject *p; if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) - return FALSE; + return false; p = JS_VALUE_GET_OBJ(val); return (p->class_id == JS_CLASS_ERROR); } /* used to avoid catching interrupt exceptions */ -BOOL JS_IsUncatchableError(JSContext *ctx, JSValueConst val) +bool JS_IsUncatchableError(JSContext *ctx, JSValue val) { JSObject *p; if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) - return FALSE; + return false; p = JS_VALUE_GET_OBJ(val); return p->class_id == JS_CLASS_ERROR && p->is_uncatchable_error; } -void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag) +static void js_set_uncatchable_error(JSContext *ctx, JSValue val, bool flag) { JSObject *p; if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) @@ -9906,22 +10210,48 @@ void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag) p->is_uncatchable_error = flag; } +void JS_SetUncatchableError(JSContext *ctx, JSValue val) +{ + js_set_uncatchable_error(ctx, val, true); +} + +void JS_ClearUncatchableError(JSContext *ctx, JSValue val) +{ + js_set_uncatchable_error(ctx, val, false); +} + void JS_ResetUncatchableError(JSContext *ctx) { - JS_SetUncatchableError(ctx, ctx->rt->current_exception, FALSE); + js_set_uncatchable_error(ctx, ctx->rt->current_exception, false); } -void JS_SetOpaque(JSValue obj, void *opaque) +int JS_SetOpaque(JSValue obj, void *opaque) { - JSObject *p; + JSObject *p; if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { p = JS_VALUE_GET_OBJ(obj); - p->u.opaque = opaque; + // User code can't set the opaque of internal objects. + if (p->class_id >= JS_CLASS_INIT_COUNT) { + p->u.opaque = opaque; + return 0; + } } + + return -1; +} + +/* |obj| must be a JSObject of an internal class. */ +static void JS_SetOpaqueInternal(JSValue obj, void *opaque) +{ + JSObject *p; + assert(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT); + p = JS_VALUE_GET_OBJ(obj); + assert(p->class_id < JS_CLASS_INIT_COUNT); + p->u.opaque = opaque; } /* return NULL if not an object of class class_id */ -void *JS_GetOpaque(JSValueConst obj, JSClassID class_id) +void *JS_GetOpaque(JSValue obj, JSClassID class_id) { JSObject *p; if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) @@ -9932,7 +10262,7 @@ void *JS_GetOpaque(JSValueConst obj, JSClassID class_id) return p->u.opaque; } -void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id) +void *JS_GetOpaque2(JSContext *ctx, JSValue obj, JSClassID class_id) { void *p = JS_GetOpaque(obj, class_id); if (unlikely(!p)) { @@ -9941,10 +10271,22 @@ void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id) return p; } +void *JS_GetAnyOpaque(JSValue obj, JSClassID *class_id) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) { + *class_id = 0; + return NULL; + } + p = JS_VALUE_GET_OBJ(obj); + *class_id = p->class_id; + return p->u.opaque; +} + static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint) { int i; - BOOL force_ordinary; + bool force_ordinary; JSAtom method_name; JSValue method, ret; @@ -9974,7 +10316,7 @@ static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint) break; } arg = JS_AtomToString(ctx, atom); - ret = JS_CallFree(ctx, method, val, 1, (JSValueConst *)&arg); + ret = JS_CallFree(ctx, method, val, 1, &arg); JS_FreeValue(ctx, arg); if (JS_IsException(ret)) goto exception; @@ -10015,25 +10357,25 @@ static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint) return JS_EXCEPTION; } -static JSValue JS_ToPrimitive(JSContext *ctx, JSValueConst val, int hint) +static JSValue JS_ToPrimitive(JSContext *ctx, JSValue val, int hint) { - return JS_ToPrimitiveFree(ctx, JS_DupValue(ctx, val), hint); + return JS_ToPrimitiveFree(ctx, js_dup(val), hint); } -void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj) +void JS_SetIsHTMLDDA(JSContext *ctx, JSValue obj) { JSObject *p; if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) return; p = JS_VALUE_GET_OBJ(obj); - p->is_HTMLDDA = TRUE; + p->is_HTMLDDA = true; } -static inline BOOL JS_IsHTMLDDA(JSContext *ctx, JSValueConst obj) +static inline bool JS_IsHTMLDDA(JSContext *ctx, JSValue obj) { JSObject *p; if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) - return FALSE; + return false; p = JS_VALUE_GET_OBJ(obj); return p->is_HTMLDDA; } @@ -10052,36 +10394,22 @@ static int JS_ToBoolFree(JSContext *ctx, JSValue val) return -1; case JS_TAG_STRING: { - BOOL ret = JS_VALUE_GET_STRING(val)->len != 0; + bool ret = JS_VALUE_GET_STRING(val)->len != 0; JS_FreeValue(ctx, val); return ret; } case JS_TAG_BIG_INT: -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: -#endif { - JSBigFloat *p = JS_VALUE_GET_PTR(val); - BOOL ret; + JSBigInt *p = JS_VALUE_GET_PTR(val); + bool ret; ret = p->num.expn != BF_EXP_ZERO && p->num.expn != BF_EXP_NAN; JS_FreeValue(ctx, val); return ret; } -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_DECIMAL: - { - JSBigDecimal *p = JS_VALUE_GET_PTR(val); - BOOL ret; - ret = p->num.expn != BF_EXP_ZERO && p->num.expn != BF_EXP_NAN; - JS_FreeValue(ctx, val); - return ret; - } -#endif case JS_TAG_OBJECT: { JSObject *p = JS_VALUE_GET_OBJ(val); - BOOL ret; - ret = !p->is_HTMLDDA; + bool ret = !p->is_HTMLDDA; JS_FreeValue(ctx, val); return ret; } @@ -10092,16 +10420,17 @@ static int JS_ToBoolFree(JSContext *ctx, JSValue val) return !isnan(d) && d != 0; } else { JS_FreeValue(ctx, val); - return TRUE; + return true; } } } -int JS_ToBool(JSContext *ctx, JSValueConst val) +int JS_ToBool(JSContext *ctx, JSValue val) { - return JS_ToBoolFree(ctx, JS_DupValue(ctx, val)); + return JS_ToBoolFree(ctx, js_dup(val)); } +/* pc points to pure ASCII or UTF-8, null terminated contents */ static int skip_spaces(const char *pc) { const uint8_t *p, *p_next, *p_start; @@ -10109,19 +10438,19 @@ static int skip_spaces(const char *pc) p = p_start = (const uint8_t *)pc; for (;;) { - c = *p; - if (c < 128) { + c = *p++; + if (c < 0x80) { if (!((c >= 0x09 && c <= 0x0d) || (c == 0x20))) break; - p++; } else { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next); + c = utf8_decode(p - 1, &p_next); + /* no need to test for invalid UTF-8, 0xFFFD is not a space */ if (!lre_is_space(c)) break; p = p_next; } } - return p - p_start; + return p - 1 - p_start; } static inline int to_digit(int c) @@ -10137,7 +10466,7 @@ static inline int to_digit(int c) } /* XXX: remove */ -static double js_strtod(const char *str, int radix, BOOL is_float) +static double js_strtod(const char *str, int radix, bool is_float) { double d; int c; @@ -10163,10 +10492,7 @@ static double js_strtod(const char *str, int radix, BOOL is_float) n_max = ((uint64_t)-1 - (radix - 1)) / radix; /* XXX: could be more precise */ int_exp = 0; - while (*p != '\0') { - c = to_digit((uint8_t)*p); - if (c >= radix) - break; + while ((c = to_digit(*p)) < radix) { if (n <= n_max) { n = n * radix + c; } else { @@ -10189,33 +10515,9 @@ static double js_strtod(const char *str, int radix, BOOL is_float) return d; } -#define ATOD_INT_ONLY (1 << 0) -/* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */ -#define ATOD_ACCEPT_BIN_OCT (1 << 2) -/* accept O prefix as octal if radix == 0 and properly formed (Annex B) */ -#define ATOD_ACCEPT_LEGACY_OCTAL (1 << 4) -/* accept _ between digits as a digit separator */ -#define ATOD_ACCEPT_UNDERSCORES (1 << 5) -/* allow a suffix to override the type */ -#define ATOD_ACCEPT_SUFFIX (1 << 6) -/* default type */ -#define ATOD_TYPE_MASK (3 << 7) -#define ATOD_TYPE_FLOAT64 (0 << 7) -#define ATOD_TYPE_BIG_INT (1 << 7) -#ifdef CONFIG_BIGNUM -#define ATOD_TYPE_BIG_FLOAT (2 << 7) -#define ATOD_TYPE_BIG_DECIMAL (3 << 7) -/* assume bigint mode: floats are parsed as integers if no decimal - point nor exponent */ -#define ATOD_MODE_BIGINT (1 << 9) -#endif -/* accept -0x1 */ -#define ATOD_ACCEPT_PREFIX_AFTER_SIGN (1 << 10) - -static JSValue js_string_to_bigint(JSContext *ctx, const char *buf, - int radix, int flags, slimb_t *pexponent) +static JSValue js_string_to_bigint(JSContext *ctx, const char *buf, int radix) { - bf_t a_s, *a = &a_s; + bf_t *a; int ret; JSValue val; val = JS_NewBigInt(ctx); @@ -10227,211 +10529,136 @@ static JSValue js_string_to_bigint(JSContext *ctx, const char *buf, JS_FreeValue(ctx, val); return JS_ThrowOutOfMemory(ctx); } -#ifdef CONFIG_BIGNUM - val = JS_CompactBigInt1(ctx, val, (flags & ATOD_MODE_BIGINT) != 0); -#else - val = JS_CompactBigInt1(ctx, val, FALSE); -#endif - return val; -} - -#ifdef CONFIG_BIGNUM -static JSValue js_string_to_bigfloat(JSContext *ctx, const char *buf, - int radix, int flags, slimb_t *pexponent) -{ - bf_t *a; - int ret; - JSValue val; - - val = JS_NewBigFloat(ctx); - if (JS_IsException(val)) - return val; - a = JS_GetBigFloat(val); - if (flags & ATOD_ACCEPT_SUFFIX) { - /* return the exponent to get infinite precision */ - ret = bf_atof2(a, pexponent, buf, NULL, radix, BF_PREC_INF, - BF_RNDZ | BF_ATOF_EXPONENT); - } else { - ret = bf_atof(a, buf, NULL, radix, ctx->fp_env.prec, - ctx->fp_env.flags); - } - if (ret & BF_ST_MEM_ERROR) { - JS_FreeValue(ctx, val); - return JS_ThrowOutOfMemory(ctx); - } - return val; -} - -static JSValue js_string_to_bigdecimal(JSContext *ctx, const char *buf, - int radix, int flags, slimb_t *pexponent) -{ - bfdec_t *a; - int ret; - JSValue val; + return JS_CompactBigInt1(ctx, val); +} + +/* `js_atof(ctx, p, len, pp, radix, flags)` + Convert the string pointed to by `p` to a number value. + Return an exception in case of memory error. + Return `JS_NAN` if invalid syntax. + - `p` points to a null terminated UTF-8 encoded char array, + - `len` the length of the array, + - `pp` if not null receives a pointer to the next character, + - `radix` must be in range 2 to 36, else return `JS_NAN`. + - `flags` is a combination of the flags below. + There is a null byte at `p[len]`, but there might be embedded null + bytes between `p[0]` and `p[len]` which must produce `JS_NAN` if + the `ATOD_NO_TRAILING_CHARS` flag is present. + */ - val = JS_NewBigDecimal(ctx); - if (JS_IsException(val)) - return val; - a = JS_GetBigDecimal(val); - ret = bfdec_atof(a, buf, NULL, BF_PREC_INF, - BF_RNDZ | BF_ATOF_NO_NAN_INF); - if (ret & BF_ST_MEM_ERROR) { - JS_FreeValue(ctx, val); - return JS_ThrowOutOfMemory(ctx); - } - return val; -} -#endif +#define ATOD_TRIM_SPACES (1 << 0) /* trim white space */ +#define ATOD_ACCEPT_EMPTY (1 << 1) /* accept an empty string, value is 0 */ +#define ATOD_ACCEPT_FLOAT (1 << 2) /* parse decimal floating point syntax */ +#define ATOD_ACCEPT_INFINITY (1 << 3) /* parse Infinity as a float point number */ +#define ATOD_ACCEPT_BIN_OCT (1 << 4) /* accept 0o and 0b prefixes */ +#define ATOD_ACCEPT_HEX_PREFIX (1 << 5) /* accept 0x prefix for radix 16 */ +#define ATOD_ACCEPT_UNDERSCORES (1 << 6) /* accept _ between digits as a digit separator */ +#define ATOD_ACCEPT_SUFFIX (1 << 7) /* allow 'n' suffix to produce BigInt */ +#define ATOD_WANT_BIG_INT (1 << 8) /* return type must be BigInt */ +#define ATOD_DECIMAL_AFTER_SIGN (1 << 9) /* only accept decimal number after sign */ +#define ATOD_NO_TRAILING_CHARS (1 << 10) /* do not accept trailing characters */ + +static JSValue js_atof(JSContext *ctx, const char *p, size_t len, + const char **pp, int radix, int flags) +{ + const char *p_start; + const char *end = p + len; + int sep; + bool is_float; + char buf1[64], *buf = buf1; + size_t i, j; + JSValue val = JS_NAN; + double d; + char sign; -/* return an exception in case of memory error. Return JS_NAN if - invalid syntax */ -#ifdef CONFIG_BIGNUM -static JSValue js_atof2(JSContext *ctx, const char *str, const char **pp, - int radix, int flags, slimb_t *pexponent) -#else -static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, - int radix, int flags) -#endif -{ - const char *p, *p_start; - int sep, is_neg; - BOOL is_float, has_legacy_octal; - int atod_type = flags & ATOD_TYPE_MASK; - char buf1[64], *buf; - int i, j, len; - BOOL buf_allocated = FALSE; - JSValue val; + if (radix < 2 || radix > 36) + goto done; /* optional separator between digits */ sep = (flags & ATOD_ACCEPT_UNDERSCORES) ? '_' : 256; - has_legacy_octal = FALSE; - - p = str; - p_start = p; - is_neg = 0; - if (p[0] == '+') { - p++; - p_start++; - if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN)) - goto no_radix_prefix; - } else if (p[0] == '-') { + sign = 0; + if (flags & ATOD_TRIM_SPACES) + p += skip_spaces(p); + if (p == end && (flags & ATOD_ACCEPT_EMPTY)) { + if (pp) *pp = p; + if (flags & ATOD_WANT_BIG_INT) + return JS_NewBigInt64(ctx, 0); + else + return js_int32(0); + } + if (*p == '+' || *p == '-') { + sign = *p; p++; - p_start++; - is_neg = 1; - if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN)) - goto no_radix_prefix; + if (flags & ATOD_DECIMAL_AFTER_SIGN) + flags &= ~(ATOD_ACCEPT_HEX_PREFIX | ATOD_ACCEPT_BIN_OCT); } if (p[0] == '0') { if ((p[1] == 'x' || p[1] == 'X') && - (radix == 0 || radix == 16)) { + ((flags & ATOD_ACCEPT_HEX_PREFIX) || radix == 16)) { p += 2; radix = 16; - } else if ((p[1] == 'o' || p[1] == 'O') && - radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) { - p += 2; - radix = 8; - } else if ((p[1] == 'b' || p[1] == 'B') && - radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) { - p += 2; - radix = 2; - } else if ((p[1] >= '0' && p[1] <= '9') && - radix == 0 && (flags & ATOD_ACCEPT_LEGACY_OCTAL)) { - int i; - has_legacy_octal = TRUE; - sep = 256; - for (i = 1; (p[i] >= '0' && p[i] <= '7'); i++) - continue; - if (p[i] == '8' || p[i] == '9') - goto no_prefix; - p += 1; - radix = 8; - } else { - goto no_prefix; + } else if (flags & ATOD_ACCEPT_BIN_OCT) { + if (p[1] == 'o' || p[1] == 'O') { + p += 2; + radix = 8; + } else if (p[1] == 'b' || p[1] == 'B') { + p += 2; + radix = 2; + } } - /* there must be a digit after the prefix */ - if (to_digit((uint8_t)*p) >= radix) - goto fail; - no_prefix: ; } else { - no_radix_prefix: - if (!(flags & ATOD_INT_ONLY) && - (atod_type == ATOD_TYPE_FLOAT64 -#ifdef CONFIG_BIGNUM - || atod_type == ATOD_TYPE_BIG_FLOAT -#endif - ) && - strstart(p, "Infinity", &p)) { -#ifdef CONFIG_BIGNUM - if (atod_type == ATOD_TYPE_BIG_FLOAT) { - bf_t *a; - val = JS_NewBigFloat(ctx); - if (JS_IsException(val)) - goto done; - a = JS_GetBigFloat(val); - bf_set_inf(a, is_neg); - } else -#endif - { - double d = INFINITY; - if (is_neg) - d = -d; - val = JS_NewFloat64(ctx, d); - } + if (*p == 'I' && (flags & ATOD_ACCEPT_INFINITY) && js__strstart(p, "Infinity", &p)) { + d = INF; + if (sign == '-') + d = -d; + val = js_float64(d); goto done; } } - if (radix == 0) - radix = 10; - is_float = FALSE; + is_float = false; p_start = p; - while (to_digit((uint8_t)*p) < radix - || (*p == sep && (radix != 10 || - p != p_start + 1 || p[-1] != '0') && - to_digit((uint8_t)p[1]) < radix)) { + while (to_digit(*p) < radix) { p++; + if (*p == sep && to_digit(p[1]) < radix) + p++; } - if (!(flags & ATOD_INT_ONLY)) { - if (*p == '.' && (p > p_start || to_digit((uint8_t)p[1]) < radix)) { - is_float = TRUE; + if ((flags & ATOD_ACCEPT_FLOAT) && radix == 10) { + if (*p == '.' && (p > p_start || to_digit(p[1]) < radix)) { + is_float = true; p++; - if (*p == sep) - goto fail; - while (to_digit((uint8_t)*p) < radix || - (*p == sep && to_digit((uint8_t)p[1]) < radix)) + while (to_digit(*p) < radix) { p++; + if (*p == sep && to_digit(p[1]) < radix) + p++; + } } - if (p > p_start && - (((*p == 'e' || *p == 'E') && radix == 10) || - ((*p == 'p' || *p == 'P') && (radix == 2 || radix == 8 || radix == 16)))) { - const char *p1 = p + 1; - is_float = TRUE; - if (*p1 == '+') { - p1++; - } else if (*p1 == '-') { - p1++; - } - if (is_digit((uint8_t)*p1)) { - p = p1 + 1; - while (is_digit((uint8_t)*p) || (*p == sep && is_digit((uint8_t)p[1]))) + if (p > p_start && (*p == 'e' || *p == 'E')) { + i = 1; + if (p[1] == '+' || p[1] == '-') { + i++; + } + if (is_digit(p[i])) { + is_float = true; + p += i + 1; + while (is_digit(*p) || (*p == sep && is_digit(p[1]))) p++; } } } if (p == p_start) - goto fail; + goto done; - buf = buf1; - buf_allocated = FALSE; len = p - p_start; if (unlikely((len + 2) > sizeof(buf1))) { buf = js_malloc_rt(ctx->rt, len + 2); /* no exception raised */ - if (!buf) - goto mem_error; - buf_allocated = TRUE; + if (!buf) { + if (pp) *pp = p; + return JS_ThrowOutOfMemory(ctx); + } } - /* remove the separators and the radix prefixes */ + /* remove the separators and the radix prefix */ j = 0; - if (is_neg) + if (sign == '-') buf[j++] = '-'; for (i = 0; i < len; i++) { if (p_start[i] != '_') @@ -10442,95 +10669,32 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, if (flags & ATOD_ACCEPT_SUFFIX) { if (*p == 'n') { p++; - atod_type = ATOD_TYPE_BIG_INT; - } else -#ifdef CONFIG_BIGNUM - if (*p == 'l') { - p++; - atod_type = ATOD_TYPE_BIG_FLOAT; - } else if (*p == 'm') { - p++; - atod_type = ATOD_TYPE_BIG_DECIMAL; - } else if (flags & ATOD_MODE_BIGINT) { - if (!is_float) - atod_type = ATOD_TYPE_BIG_INT; - if (has_legacy_octal) - goto fail; - } else -#endif - { - if (is_float && radix != 10) - goto fail; + flags |= ATOD_WANT_BIG_INT; } + } + + if (flags & ATOD_WANT_BIG_INT) { + if (!is_float) + val = js_string_to_bigint(ctx, buf, radix); } else { - if (atod_type == ATOD_TYPE_FLOAT64) { -#ifdef CONFIG_BIGNUM - if (flags & ATOD_MODE_BIGINT) { - if (!is_float) - atod_type = ATOD_TYPE_BIG_INT; - if (has_legacy_octal) - goto fail; - } else -#endif - { - if (is_float && radix != 10) - goto fail; - } - } + d = js_strtod(buf, radix, is_float); + val = js_number(d); /* return int or float64 */ } - switch(atod_type) { - case ATOD_TYPE_FLOAT64: - { - double d; - d = js_strtod(buf, radix, is_float); - /* return int or float64 */ - val = JS_NewFloat64(ctx, d); + done: + if (flags & ATOD_NO_TRAILING_CHARS) { + if (flags & ATOD_TRIM_SPACES) + p += skip_spaces(p); + if (p != end) { + JS_FreeValue(ctx, val); + val = JS_NAN; } - break; - case ATOD_TYPE_BIG_INT: - if (has_legacy_octal || is_float) - goto fail; - val = ctx->rt->bigint_ops.from_string(ctx, buf, radix, flags, NULL); - break; -#ifdef CONFIG_BIGNUM - case ATOD_TYPE_BIG_FLOAT: - if (has_legacy_octal) - goto fail; - val = ctx->rt->bigfloat_ops.from_string(ctx, buf, radix, flags, - pexponent); - break; - case ATOD_TYPE_BIG_DECIMAL: - if (radix != 10) - goto fail; - val = ctx->rt->bigdecimal_ops.from_string(ctx, buf, radix, flags, NULL); - break; -#endif - default: - abort(); } - -done: - if (buf_allocated) + if (buf != buf1) js_free_rt(ctx->rt, buf); - if (pp) - *pp = p; + if (pp) *pp = p; return val; - fail: - val = JS_NAN; - goto done; - mem_error: - val = JS_ThrowOutOfMemory(ctx); - goto done; -} - -#ifdef CONFIG_BIGNUM -static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, - int radix, int flags) -{ - return js_atof2(ctx, str, pp, radix, flags, NULL); } -#endif typedef enum JSToNumberHintEnum { TON_FLAG_NUMBER, @@ -10549,26 +10713,10 @@ static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val, case JS_TAG_BIG_INT: if (flag != TON_FLAG_NUMERIC) { JS_FreeValue(ctx, val); - return JS_ThrowTypeError(ctx, "cannot convert bigint to number"); + return JS_ThrowTypeError(ctx, "cannot convert BigInt to number"); } ret = val; break; -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_DECIMAL: - if (flag != TON_FLAG_NUMERIC) { - JS_FreeValue(ctx, val); - return JS_ThrowTypeError(ctx, "cannot convert bigdecimal to number"); - } - ret = val; - break; - case JS_TAG_BIG_FLOAT: - if (flag != TON_FLAG_NUMERIC) { - JS_FreeValue(ctx, val); - return JS_ThrowTypeError(ctx, "cannot convert bigfloat to number"); - } - ret = val; - break; -#endif case JS_TAG_FLOAT64: case JS_TAG_INT: case JS_TAG_EXCEPTION: @@ -10576,7 +10724,7 @@ static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val, break; case JS_TAG_BOOL: case JS_TAG_NULL: - ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val)); + ret = js_int32(JS_VALUE_GET_INT(val)); break; case JS_TAG_UNDEFINED: ret = JS_NAN; @@ -10589,28 +10737,18 @@ static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val, case JS_TAG_STRING: { const char *str; - const char *p; size_t len; + int flags; str = JS_ToCStringLen(ctx, &len, val); JS_FreeValue(ctx, val); if (!str) return JS_EXCEPTION; - p = str; - p += skip_spaces(p); - if ((p - str) == len) { - ret = JS_NewInt32(ctx, 0); - } else { - int flags = ATOD_ACCEPT_BIN_OCT; - ret = js_atof(ctx, p, &p, 0, flags); - if (!JS_IsException(ret)) { - p += skip_spaces(p); - if ((p - str) != len) { - JS_FreeValue(ctx, ret); - ret = JS_NAN; - } - } - } + flags = ATOD_TRIM_SPACES | ATOD_ACCEPT_EMPTY | + ATOD_ACCEPT_FLOAT | ATOD_ACCEPT_INFINITY | + ATOD_ACCEPT_HEX_PREFIX | ATOD_ACCEPT_BIN_OCT | + ATOD_DECIMAL_AFTER_SIGN | ATOD_NO_TRAILING_CHARS; + ret = js_atof(ctx, str, len, NULL, 10, flags); JS_FreeCString(ctx, str); } break; @@ -10635,9 +10773,9 @@ static JSValue JS_ToNumericFree(JSContext *ctx, JSValue val) return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMERIC); } -static JSValue JS_ToNumeric(JSContext *ctx, JSValueConst val) +static JSValue JS_ToNumeric(JSContext *ctx, JSValue val) { - return JS_ToNumericFree(ctx, JS_DupValue(ctx, val)); + return JS_ToNumericFree(ctx, js_dup(val)); } static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres, @@ -10660,11 +10798,8 @@ static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres, d = JS_VALUE_GET_FLOAT64(val); break; case JS_TAG_BIG_INT: -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: -#endif { - JSBigFloat *p = JS_VALUE_GET_PTR(val); + JSBigInt *p = JS_VALUE_GET_PTR(val); /* XXX: there can be a double rounding issue with some primitives (such as JS_ToUint8ClampFree()), but it is not critical to fix it. */ @@ -10695,14 +10830,14 @@ static inline int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val) } } -int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val) +int JS_ToFloat64(JSContext *ctx, double *pres, JSValue val) { - return JS_ToFloat64Free(ctx, pres, JS_DupValue(ctx, val)); + return JS_ToFloat64Free(ctx, pres, js_dup(val)); } -static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val) +JSValue JS_ToNumber(JSContext *ctx, JSValue val) { - return JS_ToNumberFree(ctx, JS_DupValue(ctx, val)); + return JS_ToNumberFree(ctx, js_dup(val)); } /* same as JS_ToNumber() but return 0 in case of NaN/Undefined */ @@ -10718,52 +10853,20 @@ static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val) case JS_TAG_BOOL: case JS_TAG_NULL: case JS_TAG_UNDEFINED: - ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val)); + ret = js_int32(JS_VALUE_GET_INT(val)); break; case JS_TAG_FLOAT64: { double d = JS_VALUE_GET_FLOAT64(val); if (isnan(d)) { - ret = JS_NewInt32(ctx, 0); + ret = js_int32(0); } else { /* convert -0 to +0 */ d = trunc(d) + 0.0; - ret = JS_NewFloat64(ctx, d); - } - } - break; -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: - { - bf_t a_s, *a, r_s, *r = &r_s; - BOOL is_nan; - - a = JS_ToBigFloat(ctx, &a_s, val); - if (!a) { - JS_FreeValue(ctx, val); - return JS_EXCEPTION; - } - if (!bf_is_finite(a)) { - is_nan = bf_is_nan(a); - if (is_nan) - ret = JS_NewInt32(ctx, 0); - else - ret = JS_DupValue(ctx, val); - } else { - ret = JS_NewBigInt(ctx); - if (!JS_IsException(ret)) { - r = JS_GetBigInt(ret); - bf_set(r, a); - bf_rint(r, BF_RNDZ); - ret = JS_CompactBigInt(ctx, ret); - } + ret = js_number(d); } - if (a == &a_s) - bf_delete(a); - JS_FreeValue(ctx, val); } break; -#endif default: val = JS_ToNumberFree(ctx, val); if (JS_IsException(val)) @@ -10806,15 +10909,6 @@ static int JS_ToInt32SatFree(JSContext *ctx, int *pres, JSValue val) } } break; -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: - { - JSBigFloat *p = JS_VALUE_GET_PTR(val); - bf_get_int32(&ret, &p->num, 0); - JS_FreeValue(ctx, val); - } - break; -#endif default: val = JS_ToNumberFree(ctx, val); if (JS_IsException(val)) { @@ -10827,15 +10921,15 @@ static int JS_ToInt32SatFree(JSContext *ctx, int *pres, JSValue val) return 0; } -int JS_ToInt32Sat(JSContext *ctx, int *pres, JSValueConst val) +int JS_ToInt32Sat(JSContext *ctx, int *pres, JSValue val) { - return JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val)); + return JS_ToInt32SatFree(ctx, pres, js_dup(val)); } -int JS_ToInt32Clamp(JSContext *ctx, int *pres, JSValueConst val, +int JS_ToInt32Clamp(JSContext *ctx, int *pres, JSValue val, int min, int max, int min_offset) { - int res = JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val)); + int res = JS_ToInt32SatFree(ctx, pres, js_dup(val)); if (res == 0) { if (*pres < min) { *pres += min_offset; @@ -10873,22 +10967,13 @@ static int JS_ToInt64SatFree(JSContext *ctx, int64_t *pres, JSValue val) } else { if (d < INT64_MIN) *pres = INT64_MIN; - else if (d >= 0x1p63) /* must use INT64_MAX + 1 because INT64_MAX cannot be exactly represented as a double */ + else if (d >= 0x1p63) *pres = INT64_MAX; else *pres = (int64_t)d; } } return 0; -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: - { - JSBigFloat *p = JS_VALUE_GET_PTR(val); - bf_get_int64(pres, &p->num, 0); - JS_FreeValue(ctx, val); - } - return 0; -#endif default: val = JS_ToNumberFree(ctx, val); if (JS_IsException(val)) { @@ -10899,15 +10984,15 @@ static int JS_ToInt64SatFree(JSContext *ctx, int64_t *pres, JSValue val) } } -int JS_ToInt64Sat(JSContext *ctx, int64_t *pres, JSValueConst val) +int JS_ToInt64Sat(JSContext *ctx, int64_t *pres, JSValue val) { - return JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val)); + return JS_ToInt64SatFree(ctx, pres, js_dup(val)); } -int JS_ToInt64Clamp(JSContext *ctx, int64_t *pres, JSValueConst val, +int JS_ToInt64Clamp(JSContext *ctx, int64_t *pres, JSValue val, int64_t min, int64_t max, int64_t neg_offset) { - int res = JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val)); + int res = JS_ToInt64SatFree(ctx, pres, js_dup(val)); if (res == 0) { if (*pres < 0) *pres += neg_offset; @@ -10954,21 +11039,13 @@ static int JS_ToInt64Free(JSContext *ctx, int64_t *pres, JSValue val) ret = v << ((e - 1023) - 52); /* take the sign into account */ if (u.u64 >> 63) - ret = -ret; + if (ret != INT64_MIN) + ret = -ret; } else { ret = 0; /* also handles NaN and +inf */ } } break; -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: - { - JSBigFloat *p = JS_VALUE_GET_PTR(val); - bf_get_int64(&ret, &p->num, BF_GET_INT_MOD); - JS_FreeValue(ctx, val); - } - break; -#endif default: val = JS_ToNumberFree(ctx, val); if (JS_IsException(val)) { @@ -10981,12 +11058,12 @@ static int JS_ToInt64Free(JSContext *ctx, int64_t *pres, JSValue val) return 0; } -int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val) +int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValue val) { - return JS_ToInt64Free(ctx, pres, JS_DupValue(ctx, val)); + return JS_ToInt64Free(ctx, pres, js_dup(val)); } -int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val) +int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValue val) { if (JS_IsBigInt(ctx, val)) return JS_ToBigInt64(ctx, pres, val); @@ -11029,21 +11106,13 @@ static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val) ret = v >> 32; /* take the sign into account */ if (u.u64 >> 63) - ret = -ret; + if (ret != INT32_MIN) + ret = -ret; } else { ret = 0; /* also handles NaN and +inf */ } } break; -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: - { - JSBigFloat *p = JS_VALUE_GET_PTR(val); - bf_get_int32(&ret, &p->num, BF_GET_INT_MOD); - JS_FreeValue(ctx, val); - } - break; -#endif default: val = JS_ToNumberFree(ctx, val); if (JS_IsException(val)) { @@ -11056,9 +11125,9 @@ static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val) return 0; } -int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val) +int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValue val) { - return JS_ToInt32Free(ctx, pres, JS_DupValue(ctx, val)); + return JS_ToInt32Free(ctx, pres, js_dup(val)); } static inline int JS_ToUint32Free(JSContext *ctx, uint32_t *pres, JSValue val) @@ -11079,9 +11148,6 @@ static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val) case JS_TAG_NULL: case JS_TAG_UNDEFINED: res = JS_VALUE_GET_INT(val); -#ifdef CONFIG_BIGNUM - int_clamp: -#endif res = max_int(0, min_int(255, res)); break; case JS_TAG_FLOAT64: @@ -11099,20 +11165,6 @@ static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val) } } break; -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: - { - JSBigFloat *p = JS_VALUE_GET_PTR(val); - bf_t r_s, *r = &r_s; - bf_init(ctx->bf_ctx, r); - bf_set(r, &p->num); - bf_rint(r, BF_RNDN); - bf_get_int32(&res, r, 0); - bf_delete(r); - JS_FreeValue(ctx, val); - } - goto int_clamp; -#endif default: val = JS_ToNumberFree(ctx, val); if (JS_IsException(val)) { @@ -11126,7 +11178,7 @@ static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val) } static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen, - JSValue val, BOOL is_array_ctor) + JSValue val, bool is_array_ctor) { uint32_t tag, len; @@ -11144,13 +11196,10 @@ static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen, } break; case JS_TAG_BIG_INT: -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: -#endif { - JSBigFloat *p = JS_VALUE_GET_PTR(val); + JSBigInt *p = JS_VALUE_GET_PTR(val); bf_t a; - BOOL res; + bool res; bf_get_int32((int32_t *)&len, &p->num, BF_GET_INT_MOD); bf_init(ctx->bf_ctx, &a); bf_set_ui(&a, len); @@ -11178,7 +11227,7 @@ static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen, if (JS_IsException(val)) return -1; /* cannot recurse because val is a number */ - if (JS_ToArrayLengthFree(ctx, &len, val, TRUE)) + if (JS_ToArrayLengthFree(ctx, &len, val, true)) return -1; } else { /* legacy behavior: must do the conversion twice and compare */ @@ -11190,7 +11239,7 @@ static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen, if (JS_IsException(val)) return -1; /* cannot recurse because val is a number */ - if (JS_ToArrayLengthFree(ctx, &len1, val, FALSE)) + if (JS_ToArrayLengthFree(ctx, &len1, val, false)) return -1; if (len1 != len) { fail: @@ -11207,13 +11256,13 @@ static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen, #define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1) -static BOOL is_safe_integer(double d) +static bool is_safe_integer(double d) { return isfinite(d) && floor(d) == d && fabs(d) <= (double)MAX_SAFE_INTEGER; } -int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val) +int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValue val) { int64_t v; if (JS_ToInt64Sat(ctx, &v, val)) @@ -11238,17 +11287,17 @@ static __exception int JS_ToLengthFree(JSContext *ctx, int64_t *plen, } /* Note: can return an exception */ -static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val) +static int JS_NumberIsInteger(JSContext *ctx, JSValue val) { double d; if (!JS_IsNumber(val)) - return FALSE; + return false; if (unlikely(JS_ToFloat64(ctx, &d, val))) return -1; return isfinite(d) && floor(d) == d; } -static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val) +static bool JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValue val) { uint32_t tag; @@ -11268,35 +11317,22 @@ static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val) } case JS_TAG_BIG_INT: { - JSBigFloat *p = JS_VALUE_GET_PTR(val); + JSBigInt *p = JS_VALUE_GET_PTR(val); /* Note: integer zeros are not necessarily positive */ return p->num.sign && !bf_is_zero(&p->num); } -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: - { - JSBigFloat *p = JS_VALUE_GET_PTR(val); - return p->num.sign; - } - break; - case JS_TAG_BIG_DECIMAL: - { - JSBigDecimal *p = JS_VALUE_GET_PTR(val); - return p->num.sign; - } - break; -#endif default: - return FALSE; + return false; } } -static JSValue js_bigint_to_string1(JSContext *ctx, JSValueConst val, int radix) +static JSValue js_bigint_to_string1(JSContext *ctx, JSValue val, int radix) { JSValue ret; bf_t a_s, *a; char *str; int saved_sign; + size_t len; a = JS_ToBigInt(ctx, &a_s, val); if (!a) @@ -11304,414 +11340,380 @@ static JSValue js_bigint_to_string1(JSContext *ctx, JSValueConst val, int radix) saved_sign = a->sign; if (a->expn == BF_EXP_ZERO) a->sign = 0; - str = bf_ftoa(NULL, a, radix, 0, BF_RNDZ | BF_FTOA_FORMAT_FRAC | + str = bf_ftoa(&len, a, radix, 0, BF_RNDZ | BF_FTOA_FORMAT_FRAC | BF_FTOA_JS_QUIRKS); a->sign = saved_sign; JS_FreeBigInt(ctx, a, &a_s); if (!str) return JS_ThrowOutOfMemory(ctx); - ret = JS_NewString(ctx, str); + ret = js_new_string8_len(ctx, str, len); bf_free(ctx->bf_ctx, str); return ret; } -static JSValue js_bigint_to_string(JSContext *ctx, JSValueConst val) +static JSValue js_bigint_to_string(JSContext *ctx, JSValue val) { return js_bigint_to_string1(ctx, val, 10); } -#ifdef CONFIG_BIGNUM - -static JSValue js_ftoa(JSContext *ctx, JSValueConst val1, int radix, - limb_t prec, bf_flags_t flags) -{ - JSValue val, ret; - bf_t a_s, *a; - char *str; - int saved_sign; - - val = JS_ToNumeric(ctx, val1); - if (JS_IsException(val)) - return val; - a = JS_ToBigFloat(ctx, &a_s, val); - if (!a) { - JS_FreeValue(ctx, val); - return JS_EXCEPTION; - } - saved_sign = a->sign; - if (a->expn == BF_EXP_ZERO) - a->sign = 0; - flags |= BF_FTOA_JS_QUIRKS; - if ((flags & BF_FTOA_FORMAT_MASK) == BF_FTOA_FORMAT_FREE_MIN) { - /* Note: for floating point numbers with a radix which is not - a power of two, the current precision is used to compute - the number of digits. */ - if ((radix & (radix - 1)) != 0) { - bf_t r_s, *r = &r_s; - int prec, flags1; - /* must round first */ - if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) { - prec = ctx->fp_env.prec; - flags1 = ctx->fp_env.flags & - (BF_FLAG_SUBNORMAL | (BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)); - } else { - prec = 53; - flags1 = bf_set_exp_bits(11) | BF_FLAG_SUBNORMAL; - } - bf_init(ctx->bf_ctx, r); - bf_set(r, a); - bf_round(r, prec, flags1 | BF_RNDN); - str = bf_ftoa(NULL, r, radix, prec, flags1 | flags); - bf_delete(r); - } else { - str = bf_ftoa(NULL, a, radix, BF_PREC_INF, flags); - } - } else { - str = bf_ftoa(NULL, a, radix, prec, flags); - } - a->sign = saved_sign; - if (a == &a_s) - bf_delete(a); - JS_FreeValue(ctx, val); - if (!str) - return JS_ThrowOutOfMemory(ctx); - ret = JS_NewString(ctx, str); - bf_free(ctx->bf_ctx, str); - return ret; -} +/*---- floating point number to string conversions ----*/ -static JSValue js_bigfloat_to_string(JSContext *ctx, JSValueConst val) -{ - return js_ftoa(ctx, val, 10, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN); -} +/* JavaScript rounding is specified as round to nearest tie away + from zero (RNDNA), but in `printf` the "ties" case is not + specified (in most cases it is RNDN, round to nearest, tie to even), + so we must round manually. We generate 2 extra places and make + an extra call to snprintf if these are exactly '50'. + We set the current rounding mode to FE_DOWNWARD to check if the + last 2 places become '49'. If not, we must round up, which is + performed in place using the string digits. -static JSValue js_bigdecimal_to_string1(JSContext *ctx, JSValueConst val, - limb_t prec, int flags) -{ - JSValue ret; - bfdec_t *a; - char *str; - int saved_sign; + Note that we cannot rely on snprintf for rounding up: + the code below fails on macOS for `0.5.toFixed(0)`: gives `0` expected `1` + fesetround(FE_UPWARD); + snprintf(dest, size, "%.*f", n_digits, d); + fesetround(FE_TONEAREST); + */ - a = JS_ToBigDecimal(ctx, val); - if (!a) - return JS_EXCEPTION; - saved_sign = a->sign; - if (a->expn == BF_EXP_ZERO) - a->sign = 0; - str = bfdec_ftoa(NULL, a, prec, flags | BF_FTOA_JS_QUIRKS); - a->sign = saved_sign; - if (!str) - return JS_ThrowOutOfMemory(ctx); - ret = JS_NewString(ctx, str); - bf_free(ctx->bf_ctx, str); - return ret; -} +/* `js_fcvt` minimum buffer length: + - up to 21 digits in integral part + - 1 potential decimal point + - up to 102 decimals + - 1 null terminator + */ +#define JS_FCVT_BUF_SIZE (21+1+102+1) + +/* `js_ecvt` minimum buffer length: + - 1 leading digit + - 1 potential decimal point + - up to 102 decimals + - 5 exponent characters (from 'e-324' to 'e+308') + - 1 null terminator + */ +#define JS_ECVT_BUF_SIZE (1+1+102+5+1) -static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val) -{ - return js_bigdecimal_to_string1(ctx, val, 0, - BF_RNDZ | BF_FTOA_FORMAT_FREE); +/* `js_dtoa` minimum buffer length: + - 8 byte prefix + - either JS_FCVT_BUF_SIZE or JS_ECVT_BUF_SIZE + - JS_FCVT_BUF_SIZE is larger than JS_ECVT_BUF_SIZE + */ +#define JS_DTOA_BUF_SIZE (8+JS_FCVT_BUF_SIZE) + +/* `js_ecvt1`: compute the digits and decimal point spot for a double + - `d` is finite, positive or zero + - `n_digits` number of significant digits in range 1..103 + - `buf` receives the printf result + - `buf` has a fixed format: n_digits with a decimal point at offset 1 + and exponent 'e{+/-}xx[x]' at offset n_digits+1 + Return n_digits + Store the position of the decimal point into `*decpt` + */ +static int js_ecvt1(double d, int n_digits, + char dest[minimum_length(JS_ECVT_BUF_SIZE)], + size_t size, int *decpt) +{ + /* d is positive, ensure decimal point is always present */ + snprintf(dest, size, "%#.*e", n_digits - 1, d); + /* dest contents: + 0: first digit + 1: '.' decimal point (locale specific) + 2..n_digits: (n_digits-1) additional digits + n_digits+1: 'e' exponent mark + n_digits+2..: exponent sign, value and null terminator + */ + /* extract the exponent (actually the position of the decimal point) */ + *decpt = 1 + atoi(dest + n_digits + 2); + return n_digits; } -#endif /* CONFIG_BIGNUM */ - -/* 2 <= base <= 36 */ -static char const digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz"; - -static char *i64toa(char *buf_end, int64_t n, unsigned int base) -{ - char *q = buf_end; - int digit, is_neg; - - is_neg = 0; - if (n < 0) { - is_neg = 1; - n = -n; - } - *--q = '\0'; - if (base == 10) { - /* division by known base uses multiplication */ - do { - digit = (uint64_t)n % 10; - n = (uint64_t)n / 10; - *--q = '0' + digit; - } while (n != 0); - } else { - do { - digit = (uint64_t)n % base; - n = (uint64_t)n / base; - *--q = digits[digit]; - } while (n != 0); - } - if (is_neg) - *--q = '-'; - return q; -} - -/* buf1 contains the printf result */ -static void js_ecvt1(double d, int n_digits, int *decpt, int *sign, char *buf, - int rounding_mode, char *buf1, int buf1_size) -{ - if (rounding_mode != FE_TONEAREST) - fesetround(rounding_mode); - snprintf(buf1, buf1_size, "%+.*e", n_digits - 1, d); - if (rounding_mode != FE_TONEAREST) - fesetround(FE_TONEAREST); - *sign = (buf1[0] == '-'); - /* mantissa */ - buf[0] = buf1[1]; - if (n_digits > 1) - memcpy(buf + 1, buf1 + 3, n_digits - 1); - buf[n_digits] = '\0'; - /* exponent */ - *decpt = atoi(buf1 + n_digits + 2 + (n_digits > 1)) + 1; -} - -/* maximum buffer size for js_dtoa */ -#define JS_DTOA_BUF_SIZE 128 - -/* needed because ecvt usually limits the number of digits to - 17. Return the number of digits. */ -static int js_ecvt(double d, int n_digits, int *decpt, int *sign, char *buf, - BOOL is_fixed) -{ - int rounding_mode; - char buf_tmp[JS_DTOA_BUF_SIZE]; - - if (!is_fixed) { - unsigned int n_digits_min, n_digits_max; - /* find the minimum amount of digits (XXX: inefficient but simple) */ - n_digits_min = 1; - n_digits_max = 17; - while (n_digits_min < n_digits_max) { +/* `js_ecvt`: compute the digits and decimal point spot for a double + with proper javascript rounding. We cannot use `ecvt` for multiple + resasons: portability, because of the number of digits is typically + limited to 17, finally because the default rounding is inadequate. + `d` is finite and positive or zero. + `n_digits` number of significant digits in range 1..101 + or 0 for automatic (only as many digits as necessary) + Return the number of digits produced in `dest`. + Store the position of the decimal point into `*decpt` + */ +static int js_ecvt(double d, int n_digits, + char dest[minimum_length(JS_ECVT_BUF_SIZE)], + size_t size, int *decpt) +{ + if (n_digits == 0) { + /* find the minimum number of digits (XXX: inefficient but simple) */ + // TODO(chqrlie) use direct method from quickjs-printf + unsigned int n_digits_min = 1; + unsigned int n_digits_max = 17; + for (;;) { n_digits = (n_digits_min + n_digits_max) / 2; - js_ecvt1(d, n_digits, decpt, sign, buf, FE_TONEAREST, - buf_tmp, sizeof(buf_tmp)); - if (safe_strtod(buf_tmp, NULL) == d) { - /* no need to keep the trailing zeros */ - while (n_digits >= 2 && buf[n_digits - 1] == '0') + js_ecvt1(d, n_digits, dest, size, decpt); + if (n_digits_min == n_digits_max) + return n_digits; + /* dest contents: + 0: first digit + 1: '.' decimal point (locale specific) + 2..n_digits: (n_digits-1) additional digits + n_digits+1: 'e' exponent mark + n_digits+2..: exponent sign, value and null terminator + */ + if (safe_strtod(dest, NULL) == d) { + unsigned int n0 = n_digits; + /* enough digits */ + /* strip the trailing zeros */ + while (dest[n_digits] == '0') n_digits--; + if (n_digits == n_digits_min) + return n_digits; + /* done if trailing zeros and not denormal or huge */ + if (n_digits < n0 && d > 3e-308 && d < 8e307) + return n_digits; n_digits_max = n_digits; } else { + /* need at least one more digit */ n_digits_min = n_digits + 1; } } - n_digits = n_digits_max; - rounding_mode = FE_TONEAREST; } else { - rounding_mode = FE_TONEAREST; -#ifdef CONFIG_PRINTF_RNDN - { - char buf1[JS_DTOA_BUF_SIZE], buf2[JS_DTOA_BUF_SIZE]; - int decpt1, sign1, decpt2, sign2; - /* The JS rounding is specified as round to nearest ties away - from zero (RNDNA), but in printf the "ties" case is not - specified (for example it is RNDN for glibc, RNDNA for - Windows), so we must round manually. */ - js_ecvt1(d, n_digits + 1, &decpt1, &sign1, buf1, FE_TONEAREST, - buf_tmp, sizeof(buf_tmp)); - /* XXX: could use 2 digits to reduce the average running time */ - if (buf1[n_digits] == '5') { - js_ecvt1(d, n_digits + 1, &decpt1, &sign1, buf1, FE_DOWNWARD, - buf_tmp, sizeof(buf_tmp)); - js_ecvt1(d, n_digits + 1, &decpt2, &sign2, buf2, FE_UPWARD, - buf_tmp, sizeof(buf_tmp)); - if (memcmp(buf1, buf2, n_digits + 1) == 0 && decpt1 == decpt2) { - /* exact result: round away from zero */ - if (sign1) - rounding_mode = FE_DOWNWARD; - else - rounding_mode = FE_UPWARD; +#if defined(FE_DOWNWARD) && defined(FE_TONEAREST) + int i; + /* generate 2 extra digits: 99% chances to avoid 2 calls */ + js_ecvt1(d, n_digits + 2, dest, size, decpt); + if (dest[n_digits + 1] < '5') + return n_digits; /* truncate the 2 extra digits */ + if (dest[n_digits + 1] == '5' && dest[n_digits + 2] == '0') { + /* close to half-way: try rounding toward 0 */ + fesetround(FE_DOWNWARD); + js_ecvt1(d, n_digits + 2, dest, size, decpt); + fesetround(FE_TONEAREST); + if (dest[n_digits + 1] < '5') + return n_digits; /* truncate the 2 extra digits */ + } + /* round up in the string */ + for(i = n_digits;; i--) { + /* ignore the locale specific decimal point */ + if (is_digit(dest[i])) { + if (dest[i]++ < '9') + break; + dest[i] = '0'; + if (i == 0) { + dest[0] = '1'; + (*decpt)++; + break; } } } -#endif /* CONFIG_PRINTF_RNDN */ + return n_digits; /* truncate the 2 extra digits */ +#else + /* No disambiguation available, eg: __wasi__ targets */ + return js_ecvt1(d, n_digits, dest, size, decpt); +#endif } - js_ecvt1(d, n_digits, decpt, sign, buf, rounding_mode, - buf_tmp, sizeof(buf_tmp)); - return n_digits; } -static int js_fcvt1(char (*buf)[JS_DTOA_BUF_SIZE], double d, int n_digits, - int rounding_mode) -{ - int n; - if (rounding_mode != FE_TONEAREST) - fesetround(rounding_mode); - n = snprintf(*buf, sizeof(*buf), "%.*f", n_digits, d); - if (rounding_mode != FE_TONEAREST) - fesetround(FE_TONEAREST); - assert(n < sizeof(*buf)); - return n; -} - -static void js_fcvt(char (*buf)[JS_DTOA_BUF_SIZE], double d, int n_digits) -{ - int rounding_mode; - rounding_mode = FE_TONEAREST; -#ifdef CONFIG_PRINTF_RNDN - { - int n1, n2; - char buf1[JS_DTOA_BUF_SIZE]; - char buf2[JS_DTOA_BUF_SIZE]; - - /* The JS rounding is specified as round to nearest ties away from - zero (RNDNA), but in printf the "ties" case is not specified - (for example it is RNDN for glibc, RNDNA for Windows), so we - must round manually. */ - n1 = js_fcvt1(&buf1, d, n_digits + 1, FE_TONEAREST); - rounding_mode = FE_TONEAREST; - /* XXX: could use 2 digits to reduce the average running time */ - if (buf1[n1 - 1] == '5') { - n1 = js_fcvt1(&buf1, d, n_digits + 1, FE_DOWNWARD); - n2 = js_fcvt1(&buf2, d, n_digits + 1, FE_UPWARD); - if (n1 == n2 && memcmp(buf1, buf2, n1) == 0) { - /* exact result: round away from zero */ - if (buf1[0] == '-') - rounding_mode = FE_DOWNWARD; - else - rounding_mode = FE_UPWARD; +/* `js_fcvt`: convert a floating point value to %f format using RNDNA + `d` is finite and positive or zero. + `n_digits` number of decimal places in range 0..100 + Return the number of characters produced in `dest`. + */ +static size_t js_fcvt(double d, int n_digits, + char dest[minimum_length(JS_FCVT_BUF_SIZE)], size_t size) +{ +#if defined(FE_DOWNWARD) && defined(FE_TONEAREST) + int i, n1; + /* generate 2 extra digits: 99% chances to avoid 2 calls */ + n1 = snprintf(dest, size, "%.*f", n_digits + 2, d) - 2; + if (dest[n1] >= '5') { + if (dest[n1] == '5' && dest[n1 + 1] == '0') { + /* close to half-way: try rounding toward 0 */ + fesetround(FE_DOWNWARD); + n1 = snprintf(dest, size, "%.*f", n_digits + 2, d) - 2; + fesetround(FE_TONEAREST); + } + if (dest[n1] >= '5') { /* number should be rounded up */ + /* d is either exactly half way or greater: round the string manually */ + for (i = n1 - 1;; i--) { + /* ignore the locale specific decimal point */ + if (is_digit(dest[i])) { + if (dest[i]++ < '9') + break; + dest[i] = '0'; + if (i == 0) { + dest[0] = '1'; + dest[n1] = '0'; + dest[n1 - n_digits - 1] = '0'; + dest[n1 - n_digits] = '.'; + n1++; + break; + } + } } } } -#endif /* CONFIG_PRINTF_RNDN */ - js_fcvt1(buf, d, n_digits, rounding_mode); + /* truncate the extra 2 digits and the decimal point if !n_digits */ + n1 -= !n_digits; + //dest[n1] = '\0'; // optional + return n1; +#else + /* No disambiguation available, eg: __wasi__ targets */ + return snprintf(dest, size, "%.*f", n_digits, d); +#endif } -/* radix != 10 is only supported with flags = JS_DTOA_VAR_FORMAT */ -/* use as many digits as necessary */ -#define JS_DTOA_VAR_FORMAT (0 << 0) -/* use n_digits significant digits (1 <= n_digits <= 101) */ -#define JS_DTOA_FIXED_FORMAT (1 << 0) -/* force fractional format: [-]dd.dd with n_digits fractional digits */ -#define JS_DTOA_FRAC_FORMAT (2 << 0) -/* force exponential notation either in fixed or variable format */ -#define JS_DTOA_FORCE_EXP (1 << 2) - -/* XXX: slow and maybe not fully correct. Use libbf when it is fast enough. - XXX: radix != 10 is only supported for small integers -*/ -static void js_dtoa1(char (*buf)[JS_DTOA_BUF_SIZE], double d, - int radix, int n_digits, int flags) +static JSValue js_dtoa_infinite(JSContext *ctx, double d) +{ + // TODO(chqrlie) use atoms for NaN and Infinite? + if (isnan(d)) + return js_new_string8(ctx, "NaN"); + if (d < 0) + return js_new_string8(ctx, "-Infinity"); + else + return js_new_string8(ctx, "Infinity"); +} + +#define JS_DTOA_TOSTRING 0 /* use as many digits as necessary */ +#define JS_DTOA_EXPONENTIAL 1 /* use exponential notation either fixed or variable digits */ +#define JS_DTOA_FIXED 2 /* force fixed number of fractional digits */ +#define JS_DTOA_PRECISION 3 /* use n_digits significant digits (1 <= n_digits <= 101) */ + +/* `js_dtoa`: convert a floating point number to a string + - `mode`: one of the 4 supported formats + - `n_digits`: digit number according to mode + - TOSTRING: 0 only. As many digits as necessary + - EXPONENTIAL: 0 as many decimals as necessary + - 1..101 number of significant digits + - FIXED: 0..100 number of decimal places + - PRECISION: 1..101 number of significant digits + */ +// XXX: should use libbf or quickjs-printf. +static JSValue js_dtoa(JSContext *ctx, double d, int n_digits, int mode) { - char *q; + char buf[JS_DTOA_BUF_SIZE]; + size_t len; + char *start; + int sign, decpt, exp, i, k, n, n_max; - if (!isfinite(d)) { - if (isnan(d)) { - pstrcpy(*buf, sizeof(*buf), "NaN"); - } else if (d < 0) { - pstrcpy(*buf, sizeof(*buf), "-Infinity"); - } else { - pstrcpy(*buf, sizeof(*buf), "Infinity"); - } - } else if (flags == JS_DTOA_VAR_FORMAT) { - int64_t i64; - char buf1[70], *ptr; - if (d > (double)MAX_SAFE_INTEGER || d < (double)-MAX_SAFE_INTEGER) - goto generic_conv; - i64 = (int64_t)d; - if (d != i64) - goto generic_conv; - /* fast path for integers */ - ptr = i64toa(buf1 + sizeof(buf1), i64, radix); - pstrcpy(*buf, sizeof(*buf), ptr); - } else { - if (d == 0.0) - d = 0.0; /* convert -0 to 0 */ - if (flags == JS_DTOA_FRAC_FORMAT) { - js_fcvt(buf, d, n_digits); - } else { - char buf1[JS_DTOA_BUF_SIZE]; - int sign, decpt, k, n, i, p, n_max; - BOOL is_fixed; - generic_conv: - is_fixed = ((flags & 3) == JS_DTOA_FIXED_FORMAT); - if (is_fixed) { - n_max = n_digits; - } else { - n_max = 21; - } - /* the number has k digits (k >= 1) */ - k = js_ecvt(d, n_digits, &decpt, &sign, buf1, is_fixed); - n = decpt; /* d=10^(n-k)*(buf1) i.e. d= < x.yyyy 10^(n-1) */ - q = *buf; - if (sign) - *q++ = '-'; - if (flags & JS_DTOA_FORCE_EXP) - goto force_exp; - if (n >= 1 && n <= n_max) { - if (k <= n) { - memcpy(q, buf1, k); - q += k; - for(i = 0; i < (n - k); i++) - *q++ = '0'; - *q = '\0'; - } else { - /* k > n */ - memcpy(q, buf1, n); - q += n; - *q++ = '.'; - for(i = 0; i < (k - n); i++) - *q++ = buf1[n + i]; - *q = '\0'; - } - } else if (n >= -5 && n <= 0) { - *q++ = '0'; - *q++ = '.'; - for(i = 0; i < -n; i++) - *q++ = '0'; - memcpy(q, buf1, k); - q += k; - *q = '\0'; + if (!isfinite(d)) + return js_dtoa_infinite(ctx, d); + + sign = (d < 0); + start = buf + 8; + d = fabs(d); /* also converts -0 to 0 */ + + if (mode != JS_DTOA_EXPONENTIAL && n_digits == 0) { + /* fast path for exact integers in variable format: + clip to MAX_SAFE_INTEGER because to ensure insignificant + digits are generated as 0. + used for JS_DTOA_TOSTRING and JS_DTOA_FIXED without decimals. + */ + if (d <= (double)MAX_SAFE_INTEGER) { + uint64_t u64 = (uint64_t)d; + if (d == u64) { + len = u64toa(start, u64); + goto done; + } + } + } + if (mode == JS_DTOA_FIXED) { + len = js_fcvt(d, n_digits, start, sizeof(buf) - 8); + // TODO(chqrlie) patch the locale specific decimal point + goto done; + } + + n_max = (n_digits > 0) ? n_digits : 21; + /* the number has k digits (1 <= k <= n_max) */ + k = js_ecvt(d, n_digits, start, sizeof(buf) - 8, &decpt); + /* buffer contents: + 0: first digit + 1: '.' decimal point + 2..k: (k-1) additional digits + */ + n = decpt; /* d=10^(n-k)*(buf1) i.e. d= < x.yyyy 10^(n-1) */ + if (mode != JS_DTOA_EXPONENTIAL) { + /* mode is JS_DTOA_PRECISION or JS_DTOA_TOSTRING */ + if (n >= 1 && n <= n_max) { + /* between 1 and n_max digits before the decimal point */ + if (k <= n) { + /* all digits before the point, append zeros */ + start[1] = start[0]; + start++; + for(i = k; i < n; i++) + start[i] = '0'; + len = n; } else { - force_exp: - /* exponential notation */ - *q++ = buf1[0]; - if (k > 1) { - *q++ = '.'; - for(i = 1; i < k; i++) - *q++ = buf1[i]; - } - *q++ = 'e'; - p = n - 1; - if (p >= 0) - *q++ = '+'; - snprintf(q, *buf + sizeof(*buf) - q, "%d", p); + /* k > n: move digits before the point */ + for(i = 1; i < n; i++) + start[i] = start[i + 1]; + start[i] = '.'; + len = 1 + k; } + goto done; + } + if (n >= -5 && n <= 0) { + /* insert -n leading 0 decimals and a '0.' prefix */ + n = -n; + start[1] = start[0]; + start -= n + 1; + start[0] = '0'; + start[1] = '.'; + for(i = 0; i < n; i++) + start[2 + i] = '0'; + len = 2 + k + n; + goto done; } } -} + /* exponential notation */ + exp = n - 1; + /* count the digits and the decimal point if at least one decimal */ + len = k + (k > 1); + start[1] = '.'; /* patch the locale specific decimal point */ + start[len] = 'e'; + start[len + 1] = '+'; + if (exp < 0) { + start[len + 1] = '-'; + exp = -exp; + } + len += 2 + 1 + (exp > 9) + (exp > 99); + for (i = len - 1; exp > 9;) { + int quo = exp / 10; + start[i--] = (char)('0' + exp % 10); + exp = quo; + } + start[i] = (char)('0' + exp); -static JSValue js_dtoa(JSContext *ctx, - double d, int radix, int n_digits, int flags) -{ - char buf[JS_DTOA_BUF_SIZE]; - js_dtoa1(&buf, d, radix, n_digits, flags); - return JS_NewString(ctx, buf); + done: + start[-1] = '-'; /* prepend the sign if negative */ + return js_new_string8_len(ctx, start - sign, len + sign); } +/* `js_dtoa_radix`: convert a floating point number using a specific base + - `d` must be finite + - `radix` must be in range 2..36 + */ static JSValue js_dtoa_radix(JSContext *ctx, double d, int radix) { - char buf[2200], *ptr, *ptr2; - /* d is finite */ - int sign = d < 0; - int digit; + char buf[2200], *ptr, *ptr2, *ptr3; + int sign, digit; double frac, d0; - int64_t n0 = 0; + int64_t n0; + + if (!isfinite(d)) + return js_dtoa_infinite(ctx, d); + + sign = (d < 0); d = fabs(d); d0 = trunc(d); + n0 = 0; frac = d - d0; - ptr = buf + 1100; - *ptr = '\0'; + ptr2 = buf + 1100; /* ptr2 points to the end of the string */ + ptr = ptr2; /* ptr points to the beginning of the string */ if (d0 <= MAX_SAFE_INTEGER) { int64_t n = n0 = (int64_t)d0; while (n >= radix) { digit = n % radix; n = n / radix; - *--ptr = digits[digit]; + *--ptr = digits36[digit]; } - *--ptr = digits[(int)n]; + *--ptr = digits36[(size_t)n]; } else { /* no decimals */ while (d0 >= radix) { @@ -11719,66 +11721,77 @@ static JSValue js_dtoa_radix(JSContext *ctx, double d, int radix) d0 = trunc(d0 / radix); if (d0 >= MAX_SAFE_INTEGER) digit = 0; - *--ptr = digits[digit]; + *--ptr = digits36[digit]; } - *--ptr = digits[(int)d0]; + *--ptr = digits36[(size_t)d0]; goto done; } if (frac != 0) { double log2_radix = log2(radix); double prec = 1023 + 51; // handle subnormals - ptr2 = buf + 1100; *ptr2++ = '.'; while (frac != 0 && n0 <= MAX_SAFE_INTEGER/2 && prec > 0) { frac *= radix; digit = trunc(frac); frac -= digit; - *ptr2++ = digits[digit]; + *ptr2++ = digits36[digit]; n0 = n0 * radix + digit; prec -= log2_radix; } - *ptr2 = '\0'; if (frac * radix >= radix / 2) { - char nine = digits[radix - 1]; - // round to closest - while (ptr2[-1] == nine) - *--ptr2 = '\0'; + /* round up the string representation manually */ + char nine = digits36[radix - 1]; + while (ptr2[-1] == nine) { + /* strip trailing '9' or equivalent digits */ + ptr2--; + } if (ptr2[-1] == '.') { - *--ptr2 = '\0'; - while (ptr2[-1] == nine) - *--ptr2 = '0'; + /* strip the 'decimal' point */ + ptr2--; + /* increment the integral part */ + for (ptr3 = ptr2;;) { + if (ptr3[-1] != nine) { + ptr3[-1] = (ptr3[-1] == '9') ? 'a' : ptr3[-1] + 1; + break; + } + *--ptr3 = '0'; + if (ptr3 <= ptr) { + /* prepend a '1' if number was all nines */ + *--ptr = '1'; + break; + } + } + } else { + /* increment the last fractional digit */ + ptr2[-1] = (ptr2[-1] == '9') ? 'a' : ptr2[-1] + 1; } - if (ptr2 - 1 == ptr) - *--ptr = '1'; - else - ptr2[-1] += 1; } else { + /* strip trailing fractional zeros */ while (ptr2[-1] == '0') - *--ptr2 = '\0'; - if (ptr2[-1] == '.') - *--ptr2 = '\0'; + ptr2--; + /* strip the 'decimal' point if last */ + ptr2 -= (ptr2[-1] == '.'); } } done: ptr[-1] = '-'; ptr -= sign; - return JS_NewString(ctx, ptr); + return js_new_string8_len(ctx, ptr, ptr2 - ptr); } -JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val, BOOL is_ToPropertyKey) +JSValue JS_ToStringInternal(JSContext *ctx, JSValue val, bool is_ToPropertyKey) { uint32_t tag; - const char *str; char buf[32]; + size_t len; tag = JS_VALUE_GET_NORM_TAG(val); switch(tag) { case JS_TAG_STRING: - return JS_DupValue(ctx, val); + return js_dup(val); case JS_TAG_INT: - snprintf(buf, sizeof(buf), "%d", JS_VALUE_GET_INT(val)); - str = buf; - goto new_string; + len = i32toa(buf, JS_VALUE_GET_INT(val)); + return js_new_string8_len(ctx, buf, len); case JS_TAG_BOOL: return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ? JS_ATOM_true : JS_ATOM_false); @@ -11800,35 +11813,27 @@ JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val, BOOL is_ToProperty } break; case JS_TAG_FUNCTION_BYTECODE: - str = "[function bytecode]"; - goto new_string; + return js_new_string8(ctx, "[function bytecode]"); case JS_TAG_SYMBOL: if (is_ToPropertyKey) { - return JS_DupValue(ctx, val); + return js_dup(val); } else { return JS_ThrowTypeError(ctx, "cannot convert symbol to string"); } case JS_TAG_FLOAT64: - return js_dtoa(ctx, JS_VALUE_GET_FLOAT64(val), 10, 0, - JS_DTOA_VAR_FORMAT); + return js_dtoa(ctx, JS_VALUE_GET_FLOAT64(val), 0, JS_DTOA_TOSTRING); case JS_TAG_BIG_INT: - return ctx->rt->bigint_ops.to_string(ctx, val); -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: - return ctx->rt->bigfloat_ops.to_string(ctx, val); - case JS_TAG_BIG_DECIMAL: - return ctx->rt->bigdecimal_ops.to_string(ctx, val); -#endif + return js_bigint_to_string(ctx, val); + case JS_TAG_UNINITIALIZED: + return js_new_string8(ctx, "[uninitialized]"); default: - str = "[unsupported type]"; - new_string: - return JS_NewString(ctx, str); + return js_new_string8(ctx, "[unsupported type]"); } } -JSValue JS_ToString(JSContext *ctx, JSValueConst val) +JSValue JS_ToString(JSContext *ctx, JSValue val) { - return JS_ToStringInternal(ctx, val, FALSE); + return JS_ToStringInternal(ctx, val, false); } static JSValue JS_ToStringFree(JSContext *ctx, JSValue val) @@ -11846,12 +11851,12 @@ static JSValue JS_ToLocaleStringFree(JSContext *ctx, JSValue val) return JS_InvokeFree(ctx, val, JS_ATOM_toLocaleString, 0, NULL); } -JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val) +JSValue JS_ToPropertyKey(JSContext *ctx, JSValue val) { - return JS_ToStringInternal(ctx, val, TRUE); + return JS_ToStringInternal(ctx, val, true); } -static JSValue JS_ToStringCheckObject(JSContext *ctx, JSValueConst val) +static JSValue JS_ToStringCheckObject(JSContext *ctx, JSValue val) { uint32_t tag = JS_VALUE_GET_TAG(val); if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) @@ -11859,7 +11864,7 @@ static JSValue JS_ToStringCheckObject(JSContext *ctx, JSValueConst val) return JS_ToString(ctx, val); } -static JSValue JS_ToQuotedString(JSContext *ctx, JSValueConst val1) +static JSValue JS_ToQuotedString(JSContext *ctx, JSValue val1) { JSValue val; JSString *p; @@ -11907,7 +11912,7 @@ static JSValue JS_ToQuotedString(JSContext *ctx, JSValueConst val1) default: if (c < 32 || is_surrogate(c)) { snprintf(buf, sizeof(buf), "\\u%04x", c); - if (string_buffer_puts8(b, buf)) + if (string_buffer_write8(b, (uint8_t*)buf, 6)) goto fail; } else { if (string_buffer_putc(b, c)) @@ -11940,7 +11945,7 @@ static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p) JSShape *sh; JSShapeProperty *prs; JSProperty *pr; - BOOL is_first = TRUE; + bool is_first = true; /* XXX: should encode atoms with special characters */ sh = p->shape; /* the shape can be NULL while freeing an object */ @@ -11965,7 +11970,7 @@ static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p) switch (p->class_id) { case JS_CLASS_ARRAY: case JS_CLASS_ARGUMENTS: - JS_DumpValueShort(rt, p->u.array.u.values[i]); + JS_DumpValue(rt, p->u.array.u.values[i]); break; case JS_CLASS_UINT8C_ARRAY: case JS_CLASS_INT8_ARRAY: @@ -11976,6 +11981,7 @@ static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p) case JS_CLASS_UINT32_ARRAY: case JS_CLASS_BIG_INT64_ARRAY: case JS_CLASS_BIG_UINT64_ARRAY: + case JS_CLASS_FLOAT16_ARRAY: case JS_CLASS_FLOAT32_ARRAY: case JS_CLASS_FLOAT64_ARRAY: { @@ -12010,9 +12016,9 @@ static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p) js_autoinit_get_id(pr), (void *)pr->u.init.opaque); } else { - JS_DumpValueShort(rt, pr->u.value); + JS_DumpValue(rt, pr->u.value); } - is_first = FALSE; + is_first = false; } } printf(" }"); @@ -12026,11 +12032,11 @@ static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p) printf(" Closure:"); for(i = 0; i < b->closure_var_count; i++) { printf(" "); - JS_DumpValueShort(rt, var_refs[i]->value); + JS_DumpValue(rt, var_refs[i]->value); } if (p->u.func.home_object) { printf(" HomeObject: "); - JS_DumpValueShort(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object)); + JS_DumpValue(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object)); } } } @@ -12069,8 +12075,7 @@ static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p) } } -static __maybe_unused void JS_DumpValueShort(JSRuntime *rt, - JSValueConst val) +static __maybe_unused void JS_DumpValue(JSRuntime *rt, JSValue val) { uint32_t tag = JS_VALUE_GET_NORM_TAG(val); const char *str; @@ -12104,7 +12109,7 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt, break; case JS_TAG_BIG_INT: { - JSBigFloat *p = JS_VALUE_GET_PTR(val); + JSBigInt *p = JS_VALUE_GET_PTR(val); char *str; str = bf_ftoa(NULL, &p->num, 10, 0, BF_RNDZ | BF_FTOA_FORMAT_FRAC); @@ -12112,28 +12117,6 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt, bf_realloc(&rt->bf_ctx, str, 0); } break; -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: - { - JSBigFloat *p = JS_VALUE_GET_PTR(val); - char *str; - str = bf_ftoa(NULL, &p->num, 16, BF_PREC_INF, - BF_RNDZ | BF_FTOA_FORMAT_FREE | BF_FTOA_ADD_PREFIX); - printf("%sl", str); - bf_free(&rt->bf_ctx, str); - } - break; - case JS_TAG_BIG_DECIMAL: - { - JSBigDecimal *p = JS_VALUE_GET_PTR(val); - char *str; - str = bfdec_ftoa(NULL, &p->num, BF_PREC_INF, - BF_RNDZ | BF_FTOA_FORMAT_FREE); - printf("%sm", str); - bf_free(&rt->bf_ctx, str); - } - break; -#endif case JS_TAG_STRING: { JSString *p; @@ -12145,7 +12128,11 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt, { JSFunctionBytecode *b = JS_VALUE_GET_PTR(val); char buf[ATOM_GET_STR_BUF_SIZE]; - printf("[bytecode %s]", JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name)); + if (b->func_name) { + printf("[bytecode %s]", JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name)); + } else { + printf("[bytecode (anonymous)]"); + } } break; case JS_TAG_OBJECT: @@ -12174,36 +12161,22 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt, } } -static __maybe_unused void JS_DumpValue(JSContext *ctx, - JSValueConst val) -{ - JS_DumpValueShort(ctx->rt, val); -} - -static __maybe_unused void JS_PrintValue(JSContext *ctx, - const char *str, - JSValueConst val) -{ - printf("%s=", str); - JS_DumpValueShort(ctx->rt, val); - printf("\n"); -} - -/* return -1 if exception (proxy case) or TRUE/FALSE */ -// TODO: should take flags to make proxy resolution and exceptions optional -int JS_IsArray(JSContext *ctx, JSValueConst val) +/* return -1 if exception (proxy case) or true/false */ +int JS_IsArray(JSContext *ctx, JSValue val) { - if (js_resolve_proxy(ctx, &val, TRUE)) - return -1; + JSObject *p; if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) { - JSObject *p = JS_VALUE_GET_OBJ(val); - return p->class_id == JS_CLASS_ARRAY; + p = JS_VALUE_GET_OBJ(val); + if (unlikely(p->class_id == JS_CLASS_PROXY)) + return js_proxy_isArray(ctx, val); + else + return p->class_id == JS_CLASS_ARRAY; } else { - return FALSE; + return false; } } -static double js_pow(double a, double b) +static double js_math_pow(double a, double b) { if (unlikely(!isfinite(b)) && fabs(a) == 1) { /* not compatible with IEEE 754 */ @@ -12213,7 +12186,7 @@ static double js_pow(double a, double b) } } -JSValue JS_NewBigInt64_1(JSContext *ctx, int64_t v) +JSValue JS_NewBigInt64(JSContext *ctx, int64_t v) { JSValue val; bf_t *a; @@ -12228,39 +12201,69 @@ JSValue JS_NewBigInt64_1(JSContext *ctx, int64_t v) return val; } -JSValue JS_NewBigInt64(JSContext *ctx, int64_t v) +JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v) { - if (is_math_mode(ctx) && - v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) { - return JS_NewInt64(ctx, v); - } else { - return JS_NewBigInt64_1(ctx, v); + JSValue val; + bf_t *a; + val = JS_NewBigInt(ctx); + if (JS_IsException(val)) + return val; + a = JS_GetBigInt(val); + if (bf_set_ui(a, v)) { + JS_FreeValue(ctx, val); + return JS_ThrowOutOfMemory(ctx); } + + return val; } -JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v) +/* if the returned bigint is allocated it is equal to + 'buf'. Otherwise it is a pointer to the bigint in 'val'. Return + NULL in case of error. */ +// TODO(bnoordhuis) Merge with JS_ToBigInt() +static bf_t *JS_ToBigInt1(JSContext *ctx, bf_t *buf, JSValue val) { - JSValue val; - if (is_math_mode(ctx) && v <= MAX_SAFE_INTEGER) { - val = JS_NewInt64(ctx, v); - } else { - bf_t *a; - val = JS_NewBigInt(ctx); - if (JS_IsException(val)) - return val; - a = JS_GetBigInt(val); - if (bf_set_ui(a, v)) { - JS_FreeValue(ctx, val); - return JS_ThrowOutOfMemory(ctx); + uint32_t tag; + bf_t *r; + JSBigInt *p; + + tag = JS_VALUE_GET_NORM_TAG(val); + switch(tag) { + case JS_TAG_INT: + case JS_TAG_BOOL: + case JS_TAG_NULL: + r = buf; + bf_init(ctx->bf_ctx, r); + if (bf_set_si(r, JS_VALUE_GET_INT(val))) + goto fail; + break; + case JS_TAG_FLOAT64: + r = buf; + bf_init(ctx->bf_ctx, r); + if (bf_set_float64(r, JS_VALUE_GET_FLOAT64(val))) { + fail: + bf_delete(r); + return NULL; } + break; + case JS_TAG_BIG_INT: + p = JS_VALUE_GET_PTR(val); + r = &p->num; + break; + case JS_TAG_UNDEFINED: + default: + r = buf; + bf_init(ctx->bf_ctx, r); + bf_set_nan(r); + break; } - return val; + return r; } /* return NaN if bad bigint literal */ static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val) { - const char *str, *p; + const char *str; size_t len; int flags; @@ -12268,25 +12271,11 @@ static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val) JS_FreeValue(ctx, val); if (!str) return JS_EXCEPTION; - p = str; - p += skip_spaces(p); - if ((p - str) == len) { - val = JS_NewBigInt64(ctx, 0); - } else { - flags = ATOD_INT_ONLY | ATOD_ACCEPT_BIN_OCT | ATOD_TYPE_BIG_INT; -#ifdef CONFIG_BIGNUM - if (is_math_mode(ctx)) - flags |= ATOD_MODE_BIGINT; -#endif - val = js_atof(ctx, p, &p, 0, flags); - p += skip_spaces(p); - if (!JS_IsException(val)) { - if ((p - str) != len) { - JS_FreeValue(ctx, val); - val = JS_NAN; - } - } - } + flags = ATOD_WANT_BIG_INT | + ATOD_TRIM_SPACES | ATOD_ACCEPT_EMPTY | + ATOD_ACCEPT_HEX_PREFIX | ATOD_ACCEPT_BIN_OCT | + ATOD_DECIMAL_AFTER_SIGN | ATOD_NO_TRAILING_CHARS; + val = js_atof(ctx, str, len, NULL, 10, flags); JS_FreeCString(ctx, str); return val; } @@ -12295,17 +12284,17 @@ static JSValue JS_StringToBigIntErr(JSContext *ctx, JSValue val) { val = JS_StringToBigInt(ctx, val); if (JS_VALUE_IS_NAN(val)) - return JS_ThrowSyntaxError(ctx, "invalid bigint literal"); + return JS_ThrowSyntaxError(ctx, "invalid BigInt literal"); return val; } -/* if the returned bigfloat is allocated it is equal to - 'buf'. Otherwise it is a pointer to the bigfloat in 'val'. */ +/* if the returned bigint is allocated it is equal to + 'buf'. Otherwise it is a pointer to the bigint in 'val'. */ static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val) { uint32_t tag; bf_t *r; - JSBigFloat *p; + JSBigInt *p; redo: tag = JS_VALUE_GET_NORM_TAG(val); @@ -12313,45 +12302,17 @@ static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val) case JS_TAG_INT: case JS_TAG_NULL: case JS_TAG_UNDEFINED: - if (!is_math_mode(ctx)) - goto fail; - /* fall tru */ + case JS_TAG_FLOAT64: + goto fail; case JS_TAG_BOOL: r = buf; bf_init(ctx->bf_ctx, r); bf_set_si(r, JS_VALUE_GET_INT(val)); break; - case JS_TAG_FLOAT64: - { - double d = JS_VALUE_GET_FLOAT64(val); - if (!is_math_mode(ctx)) - goto fail; - if (!isfinite(d)) - goto fail; - r = buf; - bf_init(ctx->bf_ctx, r); - d = trunc(d); - bf_set_float64(r, d); - } - break; case JS_TAG_BIG_INT: p = JS_VALUE_GET_PTR(val); r = &p->num; break; -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: - if (!is_math_mode(ctx)) - goto fail; - p = JS_VALUE_GET_PTR(val); - if (!bf_is_finite(&p->num)) - goto fail; - r = buf; - bf_init(ctx->bf_ctx, r); - bf_set(r, &p->num); - bf_rint(r, BF_RNDZ); - JS_FreeValue(ctx, val); - break; -#endif case JS_TAG_STRING: val = JS_StringToBigIntErr(ctx, val); if (JS_IsException(val)) @@ -12365,15 +12326,15 @@ static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val) default: fail: JS_FreeValue(ctx, val); - JS_ThrowTypeError(ctx, "cannot convert to bigint"); + JS_ThrowTypeError(ctx, "cannot convert to BigInt"); return NULL; } return r; } -static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val) +static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValue val) { - return JS_ToBigIntFree(ctx, buf, JS_DupValue(ctx, val)); + return JS_ToBigIntFree(ctx, buf, js_dup(val)); } static __maybe_unused JSValue JS_ToBigIntValueFree(JSContext *ctx, JSValue val) @@ -12410,8 +12371,7 @@ static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf) if (a == buf) { bf_delete(a); } else { - JSBigFloat *p = (JSBigFloat *)((uint8_t *)a - - offsetof(JSBigFloat, num)); + JSBigInt *p = (JSBigInt *)((uint8_t *)a - offsetof(JSBigInt, num)); JS_FreeValue(ctx, JS_MKPTR(JS_TAG_BIG_INT, p)); } } @@ -12431,25 +12391,19 @@ static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val) return 0; } -int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val) +int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValue val) { - return JS_ToBigInt64Free(ctx, pres, JS_DupValue(ctx, val)); + return JS_ToBigInt64Free(ctx, pres, js_dup(val)); } -static JSBigFloat *js_new_bf(JSContext *ctx) +int JS_ToBigUint64(JSContext *ctx, uint64_t *pres, JSValue val) { - JSBigFloat *p; - p = js_malloc(ctx, sizeof(*p)); - if (!p) - return NULL; - p->header.ref_count = 1; - bf_init(ctx->bf_ctx, &p->num); - return p; + return JS_ToBigInt64Free(ctx, (int64_t *)pres, js_dup(val)); } static JSValue JS_NewBigInt(JSContext *ctx) { - JSBigFloat *p; + JSBigInt *p; p = js_malloc(ctx, sizeof(*p)); if (!p) return JS_EXCEPTION; @@ -12458,34 +12412,24 @@ static JSValue JS_NewBigInt(JSContext *ctx) return JS_MKPTR(JS_TAG_BIG_INT, p); } -static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val, - BOOL convert_to_safe_integer) +static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val) { - int64_t v; - bf_t *a; - if (JS_VALUE_GET_TAG(val) != JS_TAG_BIG_INT) return val; /* fail safe */ - a = JS_GetBigInt(val); - if (convert_to_safe_integer && bf_get_int64(&v, a, 0) == 0 && - v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) { - JS_FreeValue(ctx, val); - return JS_NewInt64(ctx, v); - } else if (a->expn == BF_EXP_ZERO && a->sign) { - JSBigFloat *p = JS_VALUE_GET_PTR(val); - assert(p->header.ref_count == 1); + bf_t *a = JS_GetBigInt(val); + if (a->expn == BF_EXP_ZERO && a->sign) { + assert(((JSBigInt*)JS_VALUE_GET_PTR(val))->header.ref_count == 1); a->sign = 0; } return val; } -/* Convert the big int to a safe integer if in math mode. normalize - the zero representation. Could also be used to convert the bigint +/* Nnormalize the zero representation. Could also be used to convert the bigint to a short bigint value. The reference count of the value must be 1. Cannot fail */ static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val) { - return JS_CompactBigInt1(ctx, val, is_math_mode(ctx)); + return JS_CompactBigInt1(ctx, val); } static JSValue throw_bf_exception(JSContext *ctx, int status) @@ -12503,526 +12447,6 @@ static JSValue throw_bf_exception(JSContext *ctx, int status) return JS_ThrowRangeError(ctx, "%s", str); } -/* if the returned bigfloat is allocated it is equal to - 'buf'. Otherwise it is a pointer to the bigfloat in 'val'. Return - NULL in case of error. */ -static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val) -{ - uint32_t tag; - bf_t *r; - JSBigFloat *p; - - tag = JS_VALUE_GET_NORM_TAG(val); - switch(tag) { - case JS_TAG_INT: - case JS_TAG_BOOL: - case JS_TAG_NULL: - r = buf; - bf_init(ctx->bf_ctx, r); - if (bf_set_si(r, JS_VALUE_GET_INT(val))) - goto fail; - break; - case JS_TAG_FLOAT64: - r = buf; - bf_init(ctx->bf_ctx, r); - if (bf_set_float64(r, JS_VALUE_GET_FLOAT64(val))) { - fail: - bf_delete(r); - return NULL; - } - break; - case JS_TAG_BIG_INT: -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: -#endif - p = JS_VALUE_GET_PTR(val); - r = &p->num; - break; - case JS_TAG_UNDEFINED: - default: - r = buf; - bf_init(ctx->bf_ctx, r); - bf_set_nan(r); - break; - } - return r; -} - -#ifdef CONFIG_BIGNUM -/* return NULL if invalid type */ -static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val) -{ - uint32_t tag; - JSBigDecimal *p; - bfdec_t *r; - - tag = JS_VALUE_GET_NORM_TAG(val); - switch(tag) { - case JS_TAG_BIG_DECIMAL: - p = JS_VALUE_GET_PTR(val); - r = &p->num; - break; - default: - JS_ThrowTypeError(ctx, "bigdecimal expected"); - r = NULL; - break; - } - return r; -} - -static JSValue JS_NewBigFloat(JSContext *ctx) -{ - JSBigFloat *p; - p = js_malloc(ctx, sizeof(*p)); - if (!p) - return JS_EXCEPTION; - p->header.ref_count = 1; - bf_init(ctx->bf_ctx, &p->num); - return JS_MKPTR(JS_TAG_BIG_FLOAT, p); -} - -static JSValue JS_NewBigDecimal(JSContext *ctx) -{ - JSBigDecimal *p; - p = js_malloc(ctx, sizeof(*p)); - if (!p) - return JS_EXCEPTION; - p->header.ref_count = 1; - bfdec_init(ctx->bf_ctx, &p->num); - return JS_MKPTR(JS_TAG_BIG_DECIMAL, p); -} - -/* must be kept in sync with JSOverloadableOperatorEnum */ -/* XXX: use atoms ? */ -static const char js_overloadable_operator_names[JS_OVOP_COUNT][4] = { - "+", - "-", - "*", - "/", - "%", - "**", - "|", - "&", - "^", - "<<", - ">>", - ">>>", - "==", - "<", - "pos", - "neg", - "++", - "--", - "~", -}; - -static int get_ovop_from_opcode(OPCodeEnum op) -{ - switch(op) { - case OP_add: - return JS_OVOP_ADD; - case OP_sub: - return JS_OVOP_SUB; - case OP_mul: - return JS_OVOP_MUL; - case OP_div: - return JS_OVOP_DIV; - case OP_mod: - case OP_math_mod: - return JS_OVOP_MOD; - case OP_pow: - return JS_OVOP_POW; - case OP_or: - return JS_OVOP_OR; - case OP_and: - return JS_OVOP_AND; - case OP_xor: - return JS_OVOP_XOR; - case OP_shl: - return JS_OVOP_SHL; - case OP_sar: - return JS_OVOP_SAR; - case OP_shr: - return JS_OVOP_SHR; - case OP_eq: - case OP_neq: - return JS_OVOP_EQ; - case OP_lt: - case OP_lte: - case OP_gt: - case OP_gte: - return JS_OVOP_LESS; - case OP_plus: - return JS_OVOP_POS; - case OP_neg: - return JS_OVOP_NEG; - case OP_inc: - return JS_OVOP_INC; - case OP_dec: - return JS_OVOP_DEC; - default: - abort(); - } -} - -/* return NULL if not present */ -static JSObject *find_binary_op(JSBinaryOperatorDef *def, - uint32_t operator_index, - JSOverloadableOperatorEnum op) -{ - JSBinaryOperatorDefEntry *ent; - int i; - for(i = 0; i < def->count; i++) { - ent = &def->tab[i]; - if (ent->operator_index == operator_index) - return ent->ops[op]; - } - return NULL; -} - -/* return -1 if exception, 0 if no operator overloading, 1 if - overloaded operator called */ -static __exception int js_call_binary_op_fallback(JSContext *ctx, - JSValue *pret, - JSValueConst op1, - JSValueConst op2, - OPCodeEnum op, - BOOL is_numeric, - int hint) -{ - JSValue opset1_obj, opset2_obj, method, ret, new_op1, new_op2; - JSOperatorSetData *opset1, *opset2; - JSOverloadableOperatorEnum ovop; - JSObject *p; - JSValueConst args[2]; - - if (!ctx->allow_operator_overloading) - return 0; - - opset2_obj = JS_UNDEFINED; - opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet); - if (JS_IsException(opset1_obj)) - goto exception; - if (JS_IsUndefined(opset1_obj)) - return 0; - opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET); - if (!opset1) - goto exception; - - opset2_obj = JS_GetProperty(ctx, op2, JS_ATOM_Symbol_operatorSet); - if (JS_IsException(opset2_obj)) - goto exception; - if (JS_IsUndefined(opset2_obj)) { - JS_FreeValue(ctx, opset1_obj); - return 0; - } - opset2 = JS_GetOpaque2(ctx, opset2_obj, JS_CLASS_OPERATOR_SET); - if (!opset2) - goto exception; - - if (opset1->is_primitive && opset2->is_primitive) { - JS_FreeValue(ctx, opset1_obj); - JS_FreeValue(ctx, opset2_obj); - return 0; - } - - ovop = get_ovop_from_opcode(op); - - if (opset1->operator_counter == opset2->operator_counter) { - p = opset1->self_ops[ovop]; - } else if (opset1->operator_counter > opset2->operator_counter) { - p = find_binary_op(&opset1->left, opset2->operator_counter, ovop); - } else { - p = find_binary_op(&opset2->right, opset1->operator_counter, ovop); - } - if (!p) { - JS_ThrowTypeError(ctx, "operator %s: no function defined", - js_overloadable_operator_names[ovop]); - goto exception; - } - - if (opset1->is_primitive) { - if (is_numeric) { - new_op1 = JS_ToNumeric(ctx, op1); - } else { - new_op1 = JS_ToPrimitive(ctx, op1, hint); - } - if (JS_IsException(new_op1)) - goto exception; - } else { - new_op1 = JS_DupValue(ctx, op1); - } - - if (opset2->is_primitive) { - if (is_numeric) { - new_op2 = JS_ToNumeric(ctx, op2); - } else { - new_op2 = JS_ToPrimitive(ctx, op2, hint); - } - if (JS_IsException(new_op2)) { - JS_FreeValue(ctx, new_op1); - goto exception; - } - } else { - new_op2 = JS_DupValue(ctx, op2); - } - - /* XXX: could apply JS_ToPrimitive() if primitive type so that the - operator function does not get a value object */ - - method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); - if (ovop == JS_OVOP_LESS && (op == OP_lte || op == OP_gt)) { - args[0] = new_op2; - args[1] = new_op1; - } else { - args[0] = new_op1; - args[1] = new_op2; - } - ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args); - JS_FreeValue(ctx, new_op1); - JS_FreeValue(ctx, new_op2); - if (JS_IsException(ret)) - goto exception; - if (ovop == JS_OVOP_EQ) { - BOOL res = JS_ToBoolFree(ctx, ret); - if (op == OP_neq) - res ^= 1; - ret = JS_NewBool(ctx, res); - } else if (ovop == JS_OVOP_LESS) { - if (JS_IsUndefined(ret)) { - ret = JS_FALSE; - } else { - BOOL res = JS_ToBoolFree(ctx, ret); - if (op == OP_lte || op == OP_gte) - res ^= 1; - ret = JS_NewBool(ctx, res); - } - } - JS_FreeValue(ctx, opset1_obj); - JS_FreeValue(ctx, opset2_obj); - *pret = ret; - return 1; - exception: - JS_FreeValue(ctx, opset1_obj); - JS_FreeValue(ctx, opset2_obj); - *pret = JS_UNDEFINED; - return -1; -} - -/* try to call the operation on the operatorSet field of 'obj'. Only - used for "/" and "**" on the BigInt prototype in math mode */ -static __exception int js_call_binary_op_simple(JSContext *ctx, - JSValue *pret, - JSValueConst obj, - JSValueConst op1, - JSValueConst op2, - OPCodeEnum op) -{ - JSValue opset1_obj, method, ret, new_op1, new_op2; - JSOperatorSetData *opset1; - JSOverloadableOperatorEnum ovop; - JSObject *p; - JSValueConst args[2]; - - opset1_obj = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet); - if (JS_IsException(opset1_obj)) - goto exception; - if (JS_IsUndefined(opset1_obj)) - return 0; - opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET); - if (!opset1) - goto exception; - ovop = get_ovop_from_opcode(op); - - p = opset1->self_ops[ovop]; - if (!p) { - JS_FreeValue(ctx, opset1_obj); - return 0; - } - - new_op1 = JS_ToNumeric(ctx, op1); - if (JS_IsException(new_op1)) - goto exception; - new_op2 = JS_ToNumeric(ctx, op2); - if (JS_IsException(new_op2)) { - JS_FreeValue(ctx, new_op1); - goto exception; - } - - method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); - args[0] = new_op1; - args[1] = new_op2; - ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args); - JS_FreeValue(ctx, new_op1); - JS_FreeValue(ctx, new_op2); - if (JS_IsException(ret)) - goto exception; - JS_FreeValue(ctx, opset1_obj); - *pret = ret; - return 1; - exception: - JS_FreeValue(ctx, opset1_obj); - *pret = JS_UNDEFINED; - return -1; -} - -/* return -1 if exception, 0 if no operator overloading, 1 if - overloaded operator called */ -static __exception int js_call_unary_op_fallback(JSContext *ctx, - JSValue *pret, - JSValueConst op1, - OPCodeEnum op) -{ - JSValue opset1_obj, method, ret; - JSOperatorSetData *opset1; - JSOverloadableOperatorEnum ovop; - JSObject *p; - - if (!ctx->allow_operator_overloading) - return 0; - - opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet); - if (JS_IsException(opset1_obj)) - goto exception; - if (JS_IsUndefined(opset1_obj)) - return 0; - opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET); - if (!opset1) - goto exception; - if (opset1->is_primitive) { - JS_FreeValue(ctx, opset1_obj); - return 0; - } - - ovop = get_ovop_from_opcode(op); - - p = opset1->self_ops[ovop]; - if (!p) { - JS_ThrowTypeError(ctx, "no overloaded operator %s", - js_overloadable_operator_names[ovop]); - goto exception; - } - method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); - ret = JS_CallFree(ctx, method, JS_UNDEFINED, 1, &op1); - if (JS_IsException(ret)) - goto exception; - JS_FreeValue(ctx, opset1_obj); - *pret = ret; - return 1; - exception: - JS_FreeValue(ctx, opset1_obj); - *pret = JS_UNDEFINED; - return -1; -} - -static int js_unary_arith_bigfloat(JSContext *ctx, - JSValue *pres, OPCodeEnum op, JSValue op1) -{ - bf_t a_s, *r, *a; - int ret, v; - JSValue res; - - if (op == OP_plus && !is_math_mode(ctx)) { - JS_ThrowTypeError(ctx, "bigfloat argument with unary +"); - JS_FreeValue(ctx, op1); - return -1; - } - - res = JS_NewBigFloat(ctx); - if (JS_IsException(res)) { - JS_FreeValue(ctx, op1); - return -1; - } - r = JS_GetBigFloat(res); - a = JS_ToBigFloat(ctx, &a_s, op1); - if (!a) { - JS_FreeValue(ctx, res); - JS_FreeValue(ctx, op1); - return -1; - } - ret = 0; - switch(op) { - case OP_inc: - case OP_dec: - v = 2 * (op - OP_dec) - 1; - ret = bf_add_si(r, a, v, ctx->fp_env.prec, ctx->fp_env.flags); - break; - case OP_plus: - ret = bf_set(r, a); - break; - case OP_neg: - ret = bf_set(r, a); - bf_neg(r); - break; - default: - abort(); - } - if (a == &a_s) - bf_delete(a); - JS_FreeValue(ctx, op1); - if (unlikely(ret & BF_ST_MEM_ERROR)) { - JS_FreeValue(ctx, res); - throw_bf_exception(ctx, ret); - return -1; - } - *pres = res; - return 0; -} - -static int js_unary_arith_bigdecimal(JSContext *ctx, - JSValue *pres, OPCodeEnum op, JSValue op1) -{ - bfdec_t *r, *a; - int ret, v; - JSValue res; - - if (op == OP_plus && !is_math_mode(ctx)) { - JS_ThrowTypeError(ctx, "bigdecimal argument with unary +"); - JS_FreeValue(ctx, op1); - return -1; - } - - res = JS_NewBigDecimal(ctx); - if (JS_IsException(res)) { - JS_FreeValue(ctx, op1); - return -1; - } - r = JS_GetBigDecimal(res); - a = JS_ToBigDecimal(ctx, op1); - if (!a) { - JS_FreeValue(ctx, res); - JS_FreeValue(ctx, op1); - return -1; - } - ret = 0; - switch(op) { - case OP_inc: - case OP_dec: - v = 2 * (op - OP_dec) - 1; - ret = bfdec_add_si(r, a, v, BF_PREC_INF, BF_RNDZ); - break; - case OP_plus: - ret = bfdec_set(r, a); - break; - case OP_neg: - ret = bfdec_set(r, a); - bfdec_neg(r); - break; - default: - abort(); - } - JS_FreeValue(ctx, op1); - if (unlikely(ret)) { - JS_FreeValue(ctx, res); - throw_bf_exception(ctx, ret); - return -1; - } - *pres = res; - return 0; -} - -#endif /* CONFIG_BIGNUM */ - static int js_unary_arith_bigint(JSContext *ctx, JSValue *pres, OPCodeEnum op, JSValue op1) { @@ -13030,8 +12454,8 @@ static int js_unary_arith_bigint(JSContext *ctx, int ret, v; JSValue res; - if (op == OP_plus && !is_math_mode(ctx)) { - JS_ThrowTypeError(ctx, "bigint argument with unary +"); + if (op == OP_plus) { + JS_ThrowTypeError(ctx, "BigInt argument with unary +"); JS_FreeValue(ctx, op1); return -1; } @@ -13041,12 +12465,7 @@ static int js_unary_arith_bigint(JSContext *ctx, return -1; } r = JS_GetBigInt(res); - a = JS_ToBigInt(ctx, &a_s, op1); - if (!a) { - JS_FreeValue(ctx, res); - JS_FreeValue(ctx, op1); - return -1; - } + a = JS_ToBigIntFree(ctx, &a_s, op1); // infallible, always a bigint ret = 0; switch(op) { case OP_inc: @@ -13069,7 +12488,6 @@ static int js_unary_arith_bigint(JSContext *ctx, abort(); } JS_FreeBigInt(ctx, a, &a_s); - JS_FreeValue(ctx, op1); if (unlikely(ret)) { JS_FreeValue(ctx, res); throw_bf_exception(ctx, ret); @@ -13092,19 +12510,7 @@ static no_inline __exception int js_unary_arith_slow(JSContext *ctx, /* fast path for float64 */ if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1))) goto handle_float64; -#ifdef CONFIG_BIGNUM - if (JS_IsObject(op1)) { - JSValue val; - int ret = js_call_unary_op_fallback(ctx, &val, op1, op); - if (ret < 0) - return -1; - if (ret) { - JS_FreeValue(ctx, op1); - sp[-1] = val; - return 0; - } - } -#endif + op1 = JS_ToNumericFree(ctx, op1); if (JS_IsException(op1)) goto exception; @@ -13124,7 +12530,7 @@ static no_inline __exception int js_unary_arith_slow(JSContext *ctx, break; case OP_neg: if (v64 == 0) { - sp[-1] = JS_NewFloat64(ctx, -0.0); + sp[-1] = js_float64(-0.0); return 0; } else { v64 = -v64; @@ -13133,31 +12539,17 @@ static no_inline __exception int js_unary_arith_slow(JSContext *ctx, default: abort(); } - sp[-1] = JS_NewInt64(ctx, v64); + sp[-1] = js_int64(v64); } break; case JS_TAG_BIG_INT: - handle_bigint: - if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, op, op1)) - goto exception; - break; -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: - if (ctx->rt->bigfloat_ops.unary_arith(ctx, sp - 1, op, op1)) + if (js_unary_arith_bigint(ctx, sp - 1, op, op1)) goto exception; break; - case JS_TAG_BIG_DECIMAL: - if (ctx->rt->bigdecimal_ops.unary_arith(ctx, sp - 1, op, op1)) - goto exception; - break; -#endif default: handle_float64: { - double d; - if (is_math_mode(ctx)) - goto handle_bigint; - d = JS_VALUE_GET_FLOAT64(op1); + double d = JS_VALUE_GET_FLOAT64(op1); switch(op) { case OP_inc: case OP_dec: @@ -13172,7 +12564,7 @@ static no_inline __exception int js_unary_arith_slow(JSContext *ctx, default: abort(); } - sp[-1] = JS_NewFloat64(ctx, d); + sp[-1] = js_float64(d); } break; } @@ -13195,7 +12587,7 @@ static __exception int js_post_inc_slow(JSContext *ctx, return -1; } sp[-1] = op1; - sp[0] = JS_DupValue(ctx, op1); + sp[0] = js_dup(op1); return js_unary_arith_slow(ctx, sp + 1, op - OP_post_dec + OP_dec); } @@ -13203,31 +12595,17 @@ static no_inline int js_not_slow(JSContext *ctx, JSValue *sp) { JSValue op1; - op1 = sp[-1]; -#ifdef CONFIG_BIGNUM - if (JS_IsObject(op1)) { - JSValue val; - int ret = js_call_unary_op_fallback(ctx, &val, op1, OP_not); - if (ret < 0) - return -1; - if (ret) { - JS_FreeValue(ctx, op1); - sp[-1] = val; - return 0; - } - } -#endif - op1 = JS_ToNumericFree(ctx, op1); + op1 = JS_ToNumericFree(ctx, sp[-1]); if (JS_IsException(op1)) goto exception; - if (is_math_mode(ctx) || JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) { - if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, OP_not, op1)) + if (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) { + if (js_unary_arith_bigint(ctx, sp - 1, OP_not, op1)) goto exception; } else { int32_t v1; if (unlikely(JS_ToInt32Free(ctx, &v1, op1))) goto exception; - sp[-1] = JS_NewInt32(ctx, ~v1); + sp[-1] = js_int32(~v1); } return 0; exception: @@ -13242,16 +12620,21 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, int ret; JSValue res; - res = JS_NewBigInt(ctx); - if (JS_IsException(res)) - goto fail; - a = JS_ToBigInt(ctx, &a_s, op1); - if (!a) - goto fail; - b = JS_ToBigInt(ctx, &b_s, op2); + a = JS_ToBigIntFree(ctx, &a_s, op1); + if (!a) { + JS_FreeValue(ctx, op2); + return -1; + } + b = JS_ToBigIntFree(ctx, &b_s, op2); if (!b) { JS_FreeBigInt(ctx, a, &a_s); - goto fail; + return -1; + } + res = JS_NewBigInt(ctx); + if (JS_IsException(res)) { + JS_FreeBigInt(ctx, a, &a_s); + JS_FreeBigInt(ctx, b, &b_s); + return -1; } r = JS_GetBigInt(res); ret = 0; @@ -13266,78 +12649,20 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, ret = bf_mul(r, a, b, BF_PREC_INF, BF_RNDZ); break; case OP_div: - if (!is_math_mode(ctx)) { + { bf_t rem_s, *rem = &rem_s; bf_init(ctx->bf_ctx, rem); - ret = bf_divrem(r, rem, a, b, BF_PREC_INF, BF_RNDZ, - BF_RNDZ); + ret = bf_divrem(r, rem, a, b, BF_PREC_INF, BF_RNDZ, BF_RNDZ); bf_delete(rem); - } else { - goto math_mode_div_pow; } break; -#ifdef CONFIG_BIGNUM - case OP_math_mod: - /* Euclidian remainder */ - ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ, - BF_DIVREM_EUCLIDIAN) & BF_ST_INVALID_OP; - break; -#endif case OP_mod: ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_RNDZ) & BF_ST_INVALID_OP; break; case OP_pow: if (b->sign) { - if (!is_math_mode(ctx)) { - ret = BF_ST_INVALID_OP; - } else { - math_mode_div_pow: -#ifdef CONFIG_BIGNUM - JS_FreeValue(ctx, res); - ret = js_call_binary_op_simple(ctx, &res, ctx->class_proto[JS_CLASS_BIG_INT], op1, op2, op); - if (ret != 0) { - JS_FreeBigInt(ctx, a, &a_s); - JS_FreeBigInt(ctx, b, &b_s); - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - if (ret < 0) { - return -1; - } else { - *pres = res; - return 0; - } - } - /* if no BigInt power operator defined, return a - bigfloat */ - res = JS_NewBigFloat(ctx); - if (JS_IsException(res)) { - JS_FreeBigInt(ctx, a, &a_s); - JS_FreeBigInt(ctx, b, &b_s); - goto fail; - } - r = JS_GetBigFloat(res); - if (op == OP_div) { - ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags) & BF_ST_MEM_ERROR; - } else { - ret = bf_pow(r, a, b, ctx->fp_env.prec, - ctx->fp_env.flags | BF_POW_JS_QUIRKS) & BF_ST_MEM_ERROR; - } - JS_FreeBigInt(ctx, a, &a_s); - JS_FreeBigInt(ctx, b, &b_s); - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - if (unlikely(ret)) { - JS_FreeValue(ctx, res); - throw_bf_exception(ctx, ret); - return -1; - } - *pres = res; - return 0; -#else - abort(); -#endif - } + ret = BF_ST_INVALID_OP; } else { ret = bf_pow(r, a, b, BF_PREC_INF, BF_RNDZ | BF_POW_JS_QUIRKS); } @@ -13380,8 +12705,6 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, } JS_FreeBigInt(ctx, a, &a_s); JS_FreeBigInt(ctx, b, &b_s); - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); if (unlikely(ret)) { JS_FreeValue(ctx, res); throw_bf_exception(ctx, ret); @@ -13389,173 +12712,7 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, } *pres = JS_CompactBigInt(ctx, res); return 0; - fail: - JS_FreeValue(ctx, res); - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - return -1; -} - -#ifdef CONFIG_BIGNUM -static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op, - JSValue *pres, JSValue op1, JSValue op2) -{ - bf_t a_s, b_s, *r, *a, *b; - int ret; - JSValue res; - - res = JS_NewBigFloat(ctx); - if (JS_IsException(res)) - goto fail; - r = JS_GetBigFloat(res); - a = JS_ToBigFloat(ctx, &a_s, op1); - if (!a) { - JS_FreeValue(ctx, res); - goto fail; - } - b = JS_ToBigFloat(ctx, &b_s, op2); - if (!b) { - if (a == &a_s) - bf_delete(a); - JS_FreeValue(ctx, res); - goto fail; - } - bf_init(ctx->bf_ctx, r); - switch(op) { - case OP_add: - ret = bf_add(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); - break; - case OP_sub: - ret = bf_sub(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); - break; - case OP_mul: - ret = bf_mul(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); - break; - case OP_div: - ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); - break; - case OP_math_mod: - /* Euclidian remainder */ - ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags, - BF_DIVREM_EUCLIDIAN); - break; - case OP_mod: - ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags, - BF_RNDZ); - break; - case OP_pow: - ret = bf_pow(r, a, b, ctx->fp_env.prec, - ctx->fp_env.flags | BF_POW_JS_QUIRKS); - break; - default: - abort(); - } - if (a == &a_s) - bf_delete(a); - if (b == &b_s) - bf_delete(b); - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - if (unlikely(ret & BF_ST_MEM_ERROR)) { - JS_FreeValue(ctx, res); - throw_bf_exception(ctx, ret); - return -1; - } - *pres = res; - return 0; - fail: - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - return -1; -} - -/* b must be a positive integer */ -static int js_bfdec_pow(bfdec_t *r, const bfdec_t *a, const bfdec_t *b) -{ - bfdec_t b1; - int32_t b2; - int ret; - - bfdec_init(b->ctx, &b1); - ret = bfdec_set(&b1, b); - if (ret) { - bfdec_delete(&b1); - return ret; - } - ret = bfdec_rint(&b1, BF_RNDZ); - if (ret) { - bfdec_delete(&b1); - return BF_ST_INVALID_OP; /* must be an integer */ - } - ret = bfdec_get_int32(&b2, &b1); - bfdec_delete(&b1); - if (ret) - return ret; /* overflow */ - if (b2 < 0) - return BF_ST_INVALID_OP; /* must be positive */ - return bfdec_pow_ui(r, a, b2); -} - -static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op, - JSValue *pres, JSValue op1, JSValue op2) -{ - bfdec_t *r, *a, *b; - int ret; - JSValue res; - - res = JS_NewBigDecimal(ctx); - if (JS_IsException(res)) - goto fail; - r = JS_GetBigDecimal(res); - - a = JS_ToBigDecimal(ctx, op1); - if (!a) - goto fail; - b = JS_ToBigDecimal(ctx, op2); - if (!b) - goto fail; - switch(op) { - case OP_add: - ret = bfdec_add(r, a, b, BF_PREC_INF, BF_RNDZ); - break; - case OP_sub: - ret = bfdec_sub(r, a, b, BF_PREC_INF, BF_RNDZ); - break; - case OP_mul: - ret = bfdec_mul(r, a, b, BF_PREC_INF, BF_RNDZ); - break; - case OP_div: - ret = bfdec_div(r, a, b, BF_PREC_INF, BF_RNDZ); - break; - case OP_math_mod: - /* Euclidian remainder */ - ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_DIVREM_EUCLIDIAN); - break; - case OP_mod: - ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_RNDZ); - break; - case OP_pow: - ret = js_bfdec_pow(r, a, b); - break; - default: - abort(); - } - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - if (unlikely(ret)) { - JS_FreeValue(ctx, res); - throw_bf_exception(ctx, ret); - return -1; - } - *pres = res; - return 0; - fail: - JS_FreeValue(ctx, res); - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - return -1; } -#endif /* CONFIG_BIGNUM */ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp, OPCodeEnum op) @@ -13575,27 +12732,6 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s goto handle_float64; } -#ifdef CONFIG_BIGNUM - /* try to call an overloaded operator */ - if ((tag1 == JS_TAG_OBJECT && - (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) || - (tag2 == JS_TAG_OBJECT && - (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) { - JSValue res; - int ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0); - if (ret != 0) { - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - if (ret < 0) { - goto exception; - } else { - sp[-2] = res; - return 0; - } - } - } -#endif - op1 = JS_ToNumericFree(ctx, op1); if (JS_IsException(op1)) { JS_FreeValue(ctx, op2); @@ -13620,67 +12756,31 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s break; case OP_mul: v = (int64_t)v1 * (int64_t)v2; - if (is_math_mode(ctx) && - (v < -MAX_SAFE_INTEGER || v > MAX_SAFE_INTEGER)) - goto handle_bigint; if (v == 0 && (v1 | v2) < 0) { - sp[-2] = JS_NewFloat64(ctx, -0.0); + sp[-2] = js_float64(-0.0); return 0; } break; case OP_div: - if (is_math_mode(ctx)) - goto handle_bigint; - sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2); + sp[-2] = js_float64((double)v1 / (double)v2); return 0; -#ifdef CONFIG_BIGNUM - case OP_math_mod: - if (unlikely(v2 == 0)) { - throw_bf_exception(ctx, BF_ST_DIVIDE_ZERO); - goto exception; - } - v = (int64_t)v1 % (int64_t)v2; - if (v < 0) { - if (v2 < 0) - v -= v2; - else - v += v2; - } - break; -#endif case OP_mod: if (v1 < 0 || v2 <= 0) { - sp[-2] = JS_NewFloat64(ctx, fmod(v1, v2)); + sp[-2] = js_number(fmod(v1, v2)); return 0; } else { v = (int64_t)v1 % (int64_t)v2; } break; case OP_pow: - if (!is_math_mode(ctx)) { - sp[-2] = JS_NewFloat64(ctx, js_pow(v1, v2)); - return 0; - } else { - goto handle_bigint; - } - break; + sp[-2] = js_number(js_math_pow(v1, v2)); + return 0; default: abort(); } - sp[-2] = JS_NewInt64(ctx, v); - } else -#ifdef CONFIG_BIGNUM - if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { - if (ctx->rt->bigdecimal_ops.binary_arith(ctx, op, sp - 2, op1, op2)) - goto exception; - } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) { - if (ctx->rt->bigfloat_ops.binary_arith(ctx, op, sp - 2, op1, op2)) - goto exception; - } else -#endif - if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { - handle_bigint: - if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2)) + sp[-2] = js_int64(v); + } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { + if (js_binary_arith_bigint(ctx, op, sp - 2, op1, op2)) goto exception; } else { double dr; @@ -13692,8 +12792,6 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s if (JS_ToFloat64Free(ctx, &d2, op2)) goto exception; handle_float64: - if (is_math_mode(ctx) && is_safe_integer(d1) && is_safe_integer(d2)) - goto handle_bigint; switch(op) { case OP_sub: dr = d1 - d2; @@ -13707,22 +12805,13 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s case OP_mod: dr = fmod(d1, d2); break; -#ifdef CONFIG_BIGNUM - case OP_math_mod: - d2 = fabs(d2); - dr = fmod(d1, d2); - /* XXX: loss of accuracy if dr < 0 */ - if (dr < 0) - dr += d2; - break; -#endif case OP_pow: - dr = js_pow(d1, d2); + dr = js_math_pow(d1, d2); break; default: abort(); } - sp[-2] = JS_NewFloat64(ctx, dr); + sp[-2] = js_float64(dr); } return 0; exception: @@ -13746,34 +12835,11 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp) double d1, d2; d1 = JS_VALUE_GET_FLOAT64(op1); d2 = JS_VALUE_GET_FLOAT64(op2); - sp[-2] = JS_NewFloat64(ctx, d1 + d2); + sp[-2] = js_float64(d1 + d2); return 0; } if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) { -#ifdef CONFIG_BIGNUM - /* try to call an overloaded operator */ - if ((tag1 == JS_TAG_OBJECT && - (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED && - tag2 != JS_TAG_STRING)) || - (tag2 == JS_TAG_OBJECT && - (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED && - tag1 != JS_TAG_STRING))) { - JSValue res; - int ret = js_call_binary_op_fallback(ctx, &res, op1, op2, OP_add, - FALSE, HINT_NONE); - if (ret != 0) { - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - if (ret < 0) { - goto exception; - } else { - sp[-2] = res; - return 0; - } - } - } -#endif op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE); if (JS_IsException(op1)) { JS_FreeValue(ctx, op2); @@ -13815,20 +12881,9 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp) v1 = JS_VALUE_GET_INT(op1); v2 = JS_VALUE_GET_INT(op2); v = (int64_t)v1 + (int64_t)v2; - sp[-2] = JS_NewInt64(ctx, v); - } else -#ifdef CONFIG_BIGNUM - if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { - if (ctx->rt->bigdecimal_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2)) - goto exception; - } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) { - if (ctx->rt->bigfloat_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2)) - goto exception; - } else -#endif - if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { - handle_bigint: - if (ctx->rt->bigint_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2)) + sp[-2] = js_int64(v); + } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { + if (js_binary_arith_bigint(ctx, OP_add, sp - 2, op1, op2)) goto exception; } else { double d1, d2; @@ -13839,9 +12894,7 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp) } if (JS_ToFloat64Free(ctx, &d2, op2)) goto exception; - if (is_math_mode(ctx) && is_safe_integer(d1) && is_safe_integer(d2)) - goto handle_bigint; - sp[-2] = JS_NewFloat64(ctx, d1 + d2); + sp[-2] = js_float64(d1 + d2); } return 0; exception: @@ -13863,27 +12916,6 @@ static no_inline __exception int js_binary_logic_slow(JSContext *ctx, tag1 = JS_VALUE_GET_NORM_TAG(op1); tag2 = JS_VALUE_GET_NORM_TAG(op2); -#ifdef CONFIG_BIGNUM - /* try to call an overloaded operator */ - if ((tag1 == JS_TAG_OBJECT && - (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) || - (tag2 == JS_TAG_OBJECT && - (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) { - JSValue res; - int ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0); - if (ret != 0) { - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - if (ret < 0) { - goto exception; - } else { - sp[-2] = res; - return 0; - } - } - } -#endif - op1 = JS_ToNumericFree(ctx, op1); if (JS_IsException(op1)) { JS_FreeValue(ctx, op2); @@ -13895,21 +12927,16 @@ static no_inline __exception int js_binary_logic_slow(JSContext *ctx, goto exception; } - if (is_math_mode(ctx)) - goto bigint_op; - tag1 = JS_VALUE_GET_TAG(op1); tag2 = JS_VALUE_GET_TAG(op2); if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { if (tag1 != tag2) { JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); - JS_ThrowTypeError(ctx, "both operands must be bigint"); + JS_ThrowTypeError(ctx, "both operands must be BigInt"); + goto exception; + } else if (js_binary_arith_bigint(ctx, op, sp - 2, op1, op2)) { goto exception; - } else { - bigint_op: - if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2)) - goto exception; } } else { if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) { @@ -13937,7 +12964,7 @@ static no_inline __exception int js_binary_logic_slow(JSContext *ctx, default: abort(); } - sp[-2] = JS_NewInt32(ctx, r); + sp[-2] = js_int32(r); } return 0; exception: @@ -13946,19 +12973,18 @@ static no_inline __exception int js_binary_logic_slow(JSContext *ctx, return -1; } -/* Note: also used for bigint */ -static int js_compare_bigfloat(JSContext *ctx, OPCodeEnum op, - JSValue op1, JSValue op2) +static int js_compare_bigint(JSContext *ctx, OPCodeEnum op, + JSValue op1, JSValue op2) { bf_t a_s, b_s, *a, *b; int res; - a = JS_ToBigFloat(ctx, &a_s, op1); + a = JS_ToBigInt1(ctx, &a_s, op1); if (!a) { JS_FreeValue(ctx, op2); return -1; } - b = JS_ToBigFloat(ctx, &b_s, op2); + b = JS_ToBigInt1(ctx, &b_s, op2); if (!b) { if (a == &a_s) bf_delete(a); @@ -13993,54 +13019,6 @@ static int js_compare_bigfloat(JSContext *ctx, OPCodeEnum op, return res; } -#ifdef CONFIG_BIGNUM -static int js_compare_bigdecimal(JSContext *ctx, OPCodeEnum op, - JSValue op1, JSValue op2) -{ - bfdec_t *a, *b; - int res; - - /* Note: binary floats are converted to bigdecimal with - toString(). It is not mathematically correct but is consistent - with the BigDecimal() constructor behavior */ - op1 = JS_ToBigDecimalFree(ctx, op1, TRUE); - if (JS_IsException(op1)) { - JS_FreeValue(ctx, op2); - return -1; - } - op2 = JS_ToBigDecimalFree(ctx, op2, TRUE); - if (JS_IsException(op2)) { - JS_FreeValue(ctx, op1); - return -1; - } - a = JS_ToBigDecimal(ctx, op1); /* cannot fail */ - b = JS_ToBigDecimal(ctx, op2); /* cannot fail */ - - switch(op) { - case OP_lt: - res = bfdec_cmp_lt(a, b); /* if NaN return false */ - break; - case OP_lte: - res = bfdec_cmp_le(a, b); /* if NaN return false */ - break; - case OP_gt: - res = bfdec_cmp_lt(b, a); /* if NaN return false */ - break; - case OP_gte: - res = bfdec_cmp_le(b, a); /* if NaN return false */ - break; - case OP_eq: - res = bfdec_cmp_eq(a, b); /* if NaN return false */ - break; - default: - abort(); - } - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - return res; -} -#endif /* !CONFIG_BIGNUM */ - static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, OPCodeEnum op) { @@ -14052,27 +13030,7 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, op2 = sp[-1]; tag1 = JS_VALUE_GET_NORM_TAG(op1); tag2 = JS_VALUE_GET_NORM_TAG(op2); -#ifdef CONFIG_BIGNUM - /* try to call an overloaded operator */ - if ((tag1 == JS_TAG_OBJECT && - (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) || - (tag2 == JS_TAG_OBJECT && - (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) { - JSValue ret; - res = js_call_binary_op_fallback(ctx, &ret, op1, op2, op, - FALSE, HINT_NUMBER); - if (res != 0) { - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - if (res < 0) { - goto exception; - } else { - sp[-2] = ret; - return 0; - } - } - } -#endif + op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER); if (JS_IsException(op1)) { JS_FreeValue(ctx, op2); @@ -14090,7 +13048,7 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, JSString *p1, *p2; p1 = JS_VALUE_GET_STRING(op1); p2 = JS_VALUE_GET_STRING(op2); - res = js_string_compare(ctx, p1, p2); + res = js_string_compare(p1, p2); switch(op) { case OP_lt: res = (res < 0); @@ -14114,8 +13072,7 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, goto float64_compare; } else { if (((tag1 == JS_TAG_BIG_INT && tag2 == JS_TAG_STRING) || - (tag2 == JS_TAG_BIG_INT && tag1 == JS_TAG_STRING)) && - !is_math_mode(ctx)) { + (tag2 == JS_TAG_BIG_INT && tag1 == JS_TAG_STRING))) { if (tag1 == JS_TAG_STRING) { op1 = JS_StringToBigInt(ctx, op1); if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT) @@ -14127,7 +13084,7 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, invalid_bigint_string: JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); - res = FALSE; + res = false; goto done; } } @@ -14147,19 +13104,8 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, tag1 = JS_VALUE_GET_NORM_TAG(op1); tag2 = JS_VALUE_GET_NORM_TAG(op2); -#ifdef CONFIG_BIGNUM - if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { - res = ctx->rt->bigdecimal_ops.compare(ctx, op, op1, op2); - if (res < 0) - goto exception; - } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) { - res = ctx->rt->bigfloat_ops.compare(ctx, op, op1, op2); - if (res < 0) - goto exception; - } else -#endif if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { - res = ctx->rt->bigint_ops.compare(ctx, op, op1, op2); + res = js_compare_bigint(ctx, op, op1, op2); if (res < 0) goto exception; } else { @@ -14195,7 +13141,7 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, } } done: - sp[-2] = JS_NewBool(ctx, res); + sp[-2] = js_bool(res); return 0; exception: sp[-2] = JS_UNDEFINED; @@ -14203,23 +13149,16 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, return -1; } -static BOOL tag_is_number(uint32_t tag) +static bool tag_is_number(uint32_t tag) { return (tag == JS_TAG_INT || tag == JS_TAG_BIG_INT || - tag == JS_TAG_FLOAT64 -#ifdef CONFIG_BIGNUM - || tag == JS_TAG_BIG_FLOAT || tag == JS_TAG_BIG_DECIMAL -#endif - ); + tag == JS_TAG_FLOAT64); } static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, - BOOL is_neq) + bool is_neq) { JSValue op1, op2; -#ifdef CONFIG_BIGNUM - JSValue ret; -#endif int res; uint32_t tag1, tag2; @@ -14247,51 +13186,20 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, d2 = JS_VALUE_GET_INT(op2); } res = (d1 == d2); - } else -#ifdef CONFIG_BIGNUM - if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { - res = ctx->rt->bigdecimal_ops.compare(ctx, OP_eq, op1, op2); - if (res < 0) - goto exception; - } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) { - res = ctx->rt->bigfloat_ops.compare(ctx, OP_eq, op1, op2); - if (res < 0) - goto exception; - } else -#endif - { - res = ctx->rt->bigint_ops.compare(ctx, OP_eq, op1, op2); + } else { + res = js_compare_bigint(ctx, OP_eq, op1, op2); if (res < 0) goto exception; } } else if (tag1 == tag2) { -#ifdef CONFIG_BIGNUM - if (tag1 == JS_TAG_OBJECT) { - /* try the fallback operator */ - res = js_call_binary_op_fallback(ctx, &ret, op1, op2, - is_neq ? OP_neq : OP_eq, - FALSE, HINT_NONE); - if (res != 0) { - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - if (res < 0) { - goto exception; - } else { - sp[-2] = ret; - return 0; - } - } - } -#endif res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT); } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) || (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) { - res = TRUE; + res = true; } else if ((tag1 == JS_TAG_STRING && tag_is_number(tag2)) || (tag2 == JS_TAG_STRING && tag_is_number(tag1))) { - if ((tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) && - !is_math_mode(ctx)) { + if ((tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT)) { if (tag1 == JS_TAG_STRING) { op1 = JS_StringToBigInt(ctx, op1); if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT) @@ -14303,7 +13211,7 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, invalid_bigint_string: JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); - res = FALSE; + res = false; goto done; } } @@ -14319,33 +13227,17 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, goto exception; } } - res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT); + res = js_strict_eq(ctx, op1, op2); } else if (tag1 == JS_TAG_BOOL) { - op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1)); + op1 = js_int32(JS_VALUE_GET_INT(op1)); goto redo; } else if (tag2 == JS_TAG_BOOL) { - op2 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op2)); + op2 = js_int32(JS_VALUE_GET_INT(op2)); goto redo; } else if ((tag1 == JS_TAG_OBJECT && (tag_is_number(tag2) || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) || (tag2 == JS_TAG_OBJECT && (tag_is_number(tag1) || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL))) { -#ifdef CONFIG_BIGNUM - /* try the fallback operator */ - res = js_call_binary_op_fallback(ctx, &ret, op1, op2, - is_neq ? OP_neq : OP_eq, - FALSE, HINT_NONE); - if (res != 0) { - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - if (res < 0) { - goto exception; - } else { - sp[-2] = ret; - return 0; - } - } -#endif op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE); if (JS_IsException(op1)) { JS_FreeValue(ctx, op2); @@ -14363,15 +13255,15 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) || (JS_IsHTMLDDA(ctx, op2) && (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) { - res = TRUE; + res = true; } else { - res = FALSE; + res = false; } JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); } done: - sp[-2] = JS_NewBool(ctx, res ^ is_neq); + sp[-2] = js_bool(res ^ is_neq); return 0; exception: sp[-2] = JS_UNDEFINED; @@ -14396,11 +13288,10 @@ static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp) JS_FreeValue(ctx, op1); goto exception; } - /* XXX: could forbid >>> in bignum mode */ - if (!is_math_mode(ctx) && - (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT || + + if ((JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT || JS_VALUE_GET_TAG(op2) == JS_TAG_BIG_INT)) { - JS_ThrowTypeError(ctx, "bigint operands are forbidden for >>>"); + JS_ThrowTypeError(ctx, "BigInt operands are forbidden for >>>"); JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); goto exception; @@ -14409,7 +13300,7 @@ static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp) JS_ToUint32Free(ctx, &v1, op1); JS_ToUint32Free(ctx, &v2, op2); r = v1 >> (v2 & 0x1f); - sp[-2] = JS_NewUint32(ctx, r); + sp[-2] = js_uint32(r); return 0; exception: sp[-2] = JS_UNDEFINED; @@ -14417,72 +13308,11 @@ static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp) return -1; } -#ifdef CONFIG_BIGNUM -static JSValue js_mul_pow10_to_float64(JSContext *ctx, const bf_t *a, - int64_t exponent) -{ - bf_t r_s, *r = &r_s; - double d; - int ret; - - /* always convert to Float64 */ - bf_init(ctx->bf_ctx, r); - ret = bf_mul_pow_radix(r, a, 10, exponent, - 53, bf_set_exp_bits(11) | BF_RNDN | - BF_FLAG_SUBNORMAL); - bf_get_float64(r, &d, BF_RNDN); - bf_delete(r); - if (ret & BF_ST_MEM_ERROR) - return JS_ThrowOutOfMemory(ctx); - else - return JS_NewFloat64(ctx, d); -} - -static no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp) -{ - bf_t a_s, *a, *r; - JSValue op1, op2, res; - int64_t e; - int ret; - - res = JS_NewBigFloat(ctx); - if (JS_IsException(res)) - return -1; - r = JS_GetBigFloat(res); - op1 = sp[-2]; - op2 = sp[-1]; - a = JS_ToBigFloat(ctx, &a_s, op1); - if (!a) { - JS_FreeValue(ctx, res); - return -1; - } - if (JS_IsBigInt(ctx, op2)) { - ret = JS_ToBigInt64(ctx, &e, op2); - } else { - ret = JS_ToInt64(ctx, &e, op2); - } - if (ret) { - if (a == &a_s) - bf_delete(a); - JS_FreeValue(ctx, res); - return -1; - } - - bf_mul_pow_radix(r, a, 10, e, ctx->fp_env.prec, ctx->fp_env.flags); - if (a == &a_s) - bf_delete(a); - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - sp[-2] = res; - return 0; -} -#endif - -/* XXX: Should take JSValueConst arguments */ -static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, +/* XXX: Should take JSValue arguments */ +static bool js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, JSStrictEqModeEnum eq_mode) { - BOOL res; + bool res; int tag1, tag2; double d1, d2; @@ -14491,7 +13321,7 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, switch(tag1) { case JS_TAG_BOOL: if (tag1 != tag2) { - res = FALSE; + res = false; } else { res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2); goto done_no_free; @@ -14505,11 +13335,11 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, { JSString *p1, *p2; if (tag1 != tag2) { - res = FALSE; + res = false; } else { p1 = JS_VALUE_GET_STRING(op1); p2 = JS_VALUE_GET_STRING(op2); - res = (js_string_compare(ctx, p1, p2) == 0); + res = js_string_eq(p1, p2); } } break; @@ -14517,7 +13347,7 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, { JSAtomStruct *p1, *p2; if (tag1 != tag2) { - res = FALSE; + res = false; } else { p1 = JS_VALUE_GET_PTR(op1); p2 = JS_VALUE_GET_PTR(op2); @@ -14527,7 +13357,7 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, break; case JS_TAG_OBJECT: if (tag1 != tag2) - res = FALSE; + res = false; else res = JS_VALUE_GET_OBJ(op1) == JS_VALUE_GET_OBJ(op2); break; @@ -14540,7 +13370,7 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, d2 = JS_VALUE_GET_FLOAT64(op2); goto number_test; } else { - res = FALSE; + res = false; } break; case JS_TAG_FLOAT64: @@ -14550,7 +13380,7 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, } else if (tag2 == JS_TAG_INT) { d2 = JS_VALUE_GET_INT(op2); } else { - res = FALSE; + res = false; break; } number_test: @@ -14574,11 +13404,11 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, { bf_t a_s, *a, b_s, *b; if (tag1 != tag2) { - res = FALSE; + res = false; break; } - a = JS_ToBigFloat(ctx, &a_s, op1); /* cannot fail */ - b = JS_ToBigFloat(ctx, &b_s, op2); /* cannot fail */ + a = JS_ToBigInt1(ctx, &a_s, op1); + b = JS_ToBigInt1(ctx, &b_s, op2); res = bf_cmp_eq(a, b); if (a == &a_s) bf_delete(a); @@ -14586,49 +13416,8 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, bf_delete(b); } break; -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: - { - JSBigFloat *p1, *p2; - const bf_t *a, *b; - if (tag1 != tag2) { - res = FALSE; - break; - } - p1 = JS_VALUE_GET_PTR(op1); - p2 = JS_VALUE_GET_PTR(op2); - a = &p1->num; - b = &p2->num; - if (unlikely(eq_mode >= JS_EQ_SAME_VALUE)) { - if (eq_mode == JS_EQ_SAME_VALUE_ZERO && - a->expn == BF_EXP_ZERO && b->expn == BF_EXP_ZERO) { - res = TRUE; - } else { - res = (bf_cmp_full(a, b) == 0); - } - } else { - res = bf_cmp_eq(a, b); - } - } - break; - case JS_TAG_BIG_DECIMAL: - { - JSBigDecimal *p1, *p2; - const bfdec_t *a, *b; - if (tag1 != tag2) { - res = FALSE; - break; - } - p1 = JS_VALUE_GET_PTR(op1); - p2 = JS_VALUE_GET_PTR(op2); - a = &p1->num; - b = &p2->num; - res = bfdec_cmp_eq(a, b); - } - break; -#endif default: - res = FALSE; + res = false; break; } JS_FreeValue(ctx, op1); @@ -14637,48 +13426,27 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, return res; } -static BOOL js_strict_eq(JSContext *ctx, JSValueConst op1, JSValueConst op2) +static bool js_strict_eq(JSContext *ctx, JSValue op1, JSValue op2) { - return js_strict_eq2(ctx, - JS_DupValue(ctx, op1), JS_DupValue(ctx, op2), - JS_EQ_STRICT); + return js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT); } -BOOL JS_StrictEq(JSContext *ctx, JSValueConst op1, JSValueConst op2) +static bool js_same_value(JSContext *ctx, JSValue op1, JSValue op2) { - return js_strict_eq(ctx, op1, op2); + return js_strict_eq2(ctx, js_dup(op1), js_dup(op2), JS_EQ_SAME_VALUE); } -static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2) +static bool js_same_value_zero(JSContext *ctx, JSValue op1, JSValue op2) { - return js_strict_eq2(ctx, - JS_DupValue(ctx, op1), JS_DupValue(ctx, op2), - JS_EQ_SAME_VALUE); -} - -BOOL JS_SameValue(JSContext *ctx, JSValueConst op1, JSValueConst op2) -{ - return js_same_value(ctx, op1, op2); -} - -static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2) -{ - return js_strict_eq2(ctx, - JS_DupValue(ctx, op1), JS_DupValue(ctx, op2), - JS_EQ_SAME_VALUE_ZERO); -} - -BOOL JS_SameValueZero(JSContext *ctx, JSValueConst op1, JSValueConst op2) -{ - return js_same_value_zero(ctx, op1, op2); + return js_strict_eq2(ctx, js_dup(op1), js_dup(op2), JS_EQ_SAME_VALUE_ZERO); } static no_inline int js_strict_eq_slow(JSContext *ctx, JSValue *sp, - BOOL is_neq) + bool is_neq) { - BOOL res; - res = js_strict_eq2(ctx, sp[-2], sp[-1], JS_EQ_STRICT); - sp[-2] = JS_NewBool(ctx, res ^ is_neq); + bool res; + res = js_strict_eq(ctx, sp[-2], sp[-1]); + sp[-2] = js_bool(res ^ is_neq); return 0; } @@ -14704,7 +13472,7 @@ static __exception int js_operator_in(JSContext *ctx, JSValue *sp) return -1; JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); - sp[-2] = JS_NewBool(ctx, ret); + sp[-2] = js_bool(ret); return 0; } @@ -14712,10 +13480,8 @@ static __exception int js_operator_private_in(JSContext *ctx, JSValue *sp) { JSValue op1, op2; int ret; - op1 = sp[-2]; /* object */ op2 = sp[-1]; /* field name or method function */ - if (JS_VALUE_GET_TAG(op1) != JS_TAG_OBJECT) { JS_ThrowTypeError(ctx, "invalid 'in' operand"); return -1; @@ -14745,7 +13511,7 @@ static __exception int js_operator_private_in(JSContext *ctx, JSValue *sp) return 0; } -static __exception int js_has_unscopable(JSContext *ctx, JSValueConst obj, +static __exception int js_has_unscopable(JSContext *ctx, JSValue obj, JSAtom atom) { JSValue arr, val; @@ -14766,7 +13532,7 @@ static __exception int js_has_unscopable(JSContext *ctx, JSValueConst obj, static __exception int js_operator_instanceof(JSContext *ctx, JSValue *sp) { JSValue op1, op2; - BOOL ret; + int ret; op1 = sp[-2]; op2 = sp[-1]; @@ -14775,11 +13541,11 @@ static __exception int js_operator_instanceof(JSContext *ctx, JSValue *sp) return ret; JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); - sp[-2] = JS_NewBool(ctx, ret); + sp[-2] = js_bool(ret); return 0; } -static __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1) +static __exception int js_operator_typeof(JSContext *ctx, JSValue op1) { JSAtom atom; uint32_t tag; @@ -14789,14 +13555,6 @@ static __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1) case JS_TAG_BIG_INT: atom = JS_ATOM_bigint; break; -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: - atom = JS_ATOM_bigfloat; - break; - case JS_TAG_BIG_DECIMAL: - atom = JS_ATOM_bigdecimal; - break; -#endif case JS_TAG_INT: case JS_TAG_FLOAT64: atom = JS_ATOM_number; @@ -14853,12 +13611,12 @@ static __exception int js_operator_delete(JSContext *ctx, JSValue *sp) return -1; JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); - sp[-2] = JS_NewBool(ctx, ret); + sp[-2] = js_bool(ret); return 0; } -static JSValue js_throw_type_error(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_throw_type_error(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { return JS_ThrowTypeError(ctx, "invalid property access"); } @@ -14866,40 +13624,42 @@ static JSValue js_throw_type_error(JSContext *ctx, JSValueConst this_val, /* XXX: not 100% compatible, but mozilla seems to use a similar implementation to ensure that caller in non strict mode does not throw (ES5 compatibility) */ -static JSValue js_function_proto_caller(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_function_proto_caller(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val); - if (!b || (b->js_mode & JS_MODE_STRICT) || !b->has_prototype) { + if (!b || b->is_strict_mode || !b->has_prototype) { return js_throw_type_error(ctx, this_val, 0, NULL); } return JS_UNDEFINED; } static JSValue js_function_proto_fileName(JSContext *ctx, - JSValueConst this_val) + JSValue this_val) { JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val); - if (b && b->has_debug) { - return JS_AtomToString(ctx, b->debug.filename); + if (b) { + return JS_AtomToString(ctx, b->filename); } return JS_UNDEFINED; } -static JSValue js_function_proto_lineNumber(JSContext *ctx, - JSValueConst this_val) +static JSValue js_function_proto_int32(JSContext *ctx, + JSValue this_val, + int magic) { JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val); - if (b && b->has_debug) { - return JS_NewInt32(ctx, b->debug.line_num); + if (b) { + int *field = (int *) ((char *)b + magic); + return js_int32(*field); } return JS_UNDEFINED; } static int js_arguments_define_own_property(JSContext *ctx, - JSValueConst this_obj, - JSAtom prop, JSValueConst val, - JSValueConst getter, JSValueConst setter, int flags) + JSValue this_obj, + JSAtom prop, JSValue val, + JSValue getter, JSValue setter, int flags) { JSObject *p; uint32_t idx; @@ -14919,7 +13679,7 @@ static const JSClassExoticMethods js_arguments_exotic_methods = { .define_own_property = js_arguments_define_own_property, }; -static JSValue js_build_arguments(JSContext *ctx, int argc, JSValueConst *argv) +static JSValue js_build_arguments(JSContext *ctx, int argc, JSValue *argv) { JSValue val, *tab; JSProperty *pr; @@ -14935,7 +13695,11 @@ static JSValue js_build_arguments(JSContext *ctx, int argc, JSValueConst *argv) /* add the length field (cannot fail) */ pr = add_property(ctx, p, JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - pr->u.value = JS_NewInt32(ctx, argc); + if (!pr) { + JS_FreeValue(ctx, val); + return JS_EXCEPTION; + } + pr->u.value = js_int32(argc); /* initialize the fast array part */ tab = NULL; @@ -14946,14 +13710,14 @@ static JSValue js_build_arguments(JSContext *ctx, int argc, JSValueConst *argv) return JS_EXCEPTION; } for(i = 0; i < argc; i++) { - tab[i] = JS_DupValue(ctx, argv[i]); + tab[i] = js_dup(argv[i]); } } p->u.array.u.values = tab; p->u.array.count = argc; JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator, - JS_DupValue(ctx, ctx->array_proto_values), + js_dup(ctx->array_proto_values), JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE); /* add callee property to throw a TypeError in strict mode */ JS_DefineProperty(ctx, val, JS_ATOM_callee, JS_UNDEFINED, @@ -14967,7 +13731,7 @@ static JSValue js_build_arguments(JSContext *ctx, int argc, JSValueConst *argv) /* legacy arguments object: add references to the function arguments */ static JSValue js_build_mapped_arguments(JSContext *ctx, int argc, - JSValueConst *argv, + JSValue *argv, JSStackFrame *sf, int arg_count) { JSValue val; @@ -14984,11 +13748,13 @@ static JSValue js_build_mapped_arguments(JSContext *ctx, int argc, /* add the length field (cannot fail) */ pr = add_property(ctx, p, JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - pr->u.value = JS_NewInt32(ctx, argc); + if (!pr) + goto fail; + pr->u.value = js_int32(argc); for(i = 0; i < arg_count; i++) { JSVarRef *var_ref; - var_ref = get_var_ref(ctx, sf, i, TRUE); + var_ref = get_var_ref(ctx, sf, i, true); if (!var_ref) goto fail; pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E | JS_PROP_VARREF); @@ -15003,17 +13769,17 @@ static JSValue js_build_mapped_arguments(JSContext *ctx, int argc, be normal properties */ for(i = arg_count; i < argc; i++) { if (JS_DefinePropertyValueUint32(ctx, val, i, - JS_DupValue(ctx, argv[i]), + js_dup(argv[i]), JS_PROP_C_W_E) < 0) goto fail; } JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator, - JS_DupValue(ctx, ctx->array_proto_values), + js_dup(ctx->array_proto_values), JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE); /* callee returns this function in non strict mode */ JS_DefinePropertyValue(ctx, val, JS_ATOM_callee, - JS_DupValue(ctx, ctx->rt->current_stack_frame->cur_func), + js_dup(ctx->rt->current_stack_frame->cur_func), JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE); return val; fail: @@ -15021,7 +13787,7 @@ static JSValue js_build_mapped_arguments(JSContext *ctx, int argc, return JS_EXCEPTION; } -static JSValue js_build_rest(JSContext *ctx, int first, int argc, JSValueConst *argv) +static JSValue js_build_rest(JSContext *ctx, int first, int argc, JSValue *argv) { JSValue val; int i, ret; @@ -15031,7 +13797,7 @@ static JSValue js_build_rest(JSContext *ctx, int first, int argc, JSValueConst * return val; for (i = first; i < argc; i++) { ret = JS_DefinePropertyValueUint32(ctx, val, i - first, - JS_DupValue(ctx, argv[i]), + js_dup(argv[i]), JS_PROP_C_W_E); if (ret < 0) { JS_FreeValue(ctx, val); @@ -15043,10 +13809,10 @@ static JSValue js_build_rest(JSContext *ctx, int first, int argc, JSValueConst * static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj) { - JSObject *p, *p1; + JSObject *p; JSPropertyEnum *tab_atom; int i; - JSValue enum_obj; + JSValue enum_obj, obj1; JSForInIterator *it; uint32_t tag, tab_atom_count; @@ -15066,19 +13832,43 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj) JS_FreeValue(ctx, obj); return JS_EXCEPTION; } - it->is_array = FALSE; + it->is_array = false; it->obj = obj; it->idx = 0; - it->tab_atom = NULL; - it->atom_count = 0; - it->in_prototype_chain = FALSE; - p1 = JS_VALUE_GET_OBJ(enum_obj); - p1->u.for_in_iterator = it; + p = JS_VALUE_GET_OBJ(enum_obj); + p->u.for_in_iterator = it; if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) return enum_obj; + /* fast path: assume no enumerable properties in the prototype chain */ + obj1 = js_dup(obj); + for(;;) { + obj1 = JS_GetPrototypeFree(ctx, obj1); + if (JS_IsNull(obj1)) + break; + if (JS_IsException(obj1)) + goto fail; + if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, + JS_VALUE_GET_OBJ(obj1), + JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) { + JS_FreeValue(ctx, obj1); + goto fail; + } + js_free_prop_enum(ctx, tab_atom, tab_atom_count); + if (tab_atom_count != 0) { + JS_FreeValue(ctx, obj1); + goto slow_path; + } + /* must check for timeout to avoid infinite loop */ + if (js_poll_interrupts(ctx)) { + JS_FreeValue(ctx, obj1); + goto fail; + } + } + p = JS_VALUE_GET_OBJ(obj); + if (p->fast_array) { JSShape *sh; JSShapeProperty *prs; @@ -15089,102 +13879,71 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj) goto normal_case; } /* for fast arrays, we only store the number of elements */ - it->is_array = TRUE; - it->atom_count = p->u.array.count; + it->is_array = true; + it->array_length = p->u.array.count; } else { normal_case: if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p, - JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) { - JS_FreeValue(ctx, enum_obj); - return JS_EXCEPTION; + JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) + goto fail; + for(i = 0; i < tab_atom_count; i++) { + JS_SetPropertyInternal(ctx, enum_obj, tab_atom[i].atom, JS_NULL, 0); } - it->tab_atom = tab_atom; - it->atom_count = tab_atom_count; + js_free_prop_enum(ctx, tab_atom, tab_atom_count); } return enum_obj; -} -/* obj -> enum_obj */ -static __exception int js_for_in_start(JSContext *ctx, JSValue *sp) -{ - sp[-1] = build_for_in_iterator(ctx, sp[-1]); - if (JS_IsException(sp[-1])) - return -1; - return 0; -} - -/* return -1 if exception, 0 if slow case, 1 if the enumeration is finished */ -static __exception int js_for_in_prepare_prototype_chain_enum(JSContext *ctx, - JSValueConst enum_obj) -{ - JSObject *p; - JSForInIterator *it; - JSPropertyEnum *tab_atom; - uint32_t tab_atom_count, i; - JSValue obj1; - - p = JS_VALUE_GET_OBJ(enum_obj); - it = p->u.for_in_iterator; - - /* check if there are enumerable properties in the prototype chain (fast path) */ - obj1 = JS_DupValue(ctx, it->obj); + slow_path: + /* non enumerable properties hide the enumerables ones in the + prototype chain */ + obj1 = js_dup(obj); for(;;) { - obj1 = JS_GetPrototypeFree(ctx, obj1); - if (JS_IsNull(obj1)) - break; - if (JS_IsException(obj1)) - goto fail; if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, JS_VALUE_GET_OBJ(obj1), - JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) { + JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) { JS_FreeValue(ctx, obj1); goto fail; } - js_free_prop_enum(ctx, tab_atom, tab_atom_count); - if (tab_atom_count != 0) { - JS_FreeValue(ctx, obj1); - goto slow_path; + for(i = 0; i < tab_atom_count; i++) { + JS_DefinePropertyValue(ctx, enum_obj, tab_atom[i].atom, JS_NULL, + (tab_atom[i].is_enumerable ? + JS_PROP_ENUMERABLE : 0)); } + js_free_prop_enum(ctx, tab_atom, tab_atom_count); + obj1 = JS_GetPrototypeFree(ctx, obj1); + if (JS_IsNull(obj1)) + break; + if (JS_IsException(obj1)) + goto fail; /* must check for timeout to avoid infinite loop */ if (js_poll_interrupts(ctx)) { JS_FreeValue(ctx, obj1); goto fail; } } - JS_FreeValue(ctx, obj1); - return 1; + return enum_obj; - slow_path: - /* add the visited properties, even if they are not enumerable */ - if (it->is_array) { - if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, - JS_VALUE_GET_OBJ(it->obj), - JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) { - goto fail; - } - it->is_array = FALSE; - it->tab_atom = tab_atom; - it->atom_count = tab_atom_count; - } + fail: + JS_FreeValue(ctx, enum_obj); + return JS_EXCEPTION; +} - for(i = 0; i < it->atom_count; i++) { - if (JS_DefinePropertyValue(ctx, enum_obj, it->tab_atom[i].atom, JS_NULL, JS_PROP_ENUMERABLE) < 0) - goto fail; - } +/* obj -> enum_obj */ +static __exception int js_for_in_start(JSContext *ctx, JSValue *sp) +{ + sp[-1] = build_for_in_iterator(ctx, sp[-1]); + if (JS_IsException(sp[-1])) + return -1; return 0; - fail: - return -1; } /* enum_obj -> enum_obj value done */ static __exception int js_for_in_next(JSContext *ctx, JSValue *sp) { - JSValueConst enum_obj; + JSValue enum_obj; JSObject *p; JSAtom prop; JSForInIterator *it; - JSPropertyEnum *tab_atom; - uint32_t tab_atom_count; int ret; enum_obj = sp[-1]; @@ -15197,68 +13956,34 @@ static __exception int js_for_in_next(JSContext *ctx, JSValue *sp) it = p->u.for_in_iterator; for(;;) { - if (it->idx >= it->atom_count) { - if (JS_IsNull(it->obj) || JS_IsUndefined(it->obj)) - goto done; /* not an object */ - /* no more property in the current object: look in the prototype */ - if (!it->in_prototype_chain) { - ret = js_for_in_prepare_prototype_chain_enum(ctx, enum_obj); - if (ret < 0) - return -1; - if (ret) - goto done; - it->in_prototype_chain = TRUE; - } - it->obj = JS_GetPrototypeFree(ctx, it->obj); - if (JS_IsException(it->obj)) - return -1; - if (JS_IsNull(it->obj)) - goto done; /* no more prototype */ - - /* must check for timeout to avoid infinite loop */ - if (js_poll_interrupts(ctx)) - return -1; - - if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, - JS_VALUE_GET_OBJ(it->obj), - JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) { - return -1; - } - js_free_prop_enum(ctx, it->tab_atom, it->atom_count); - it->tab_atom = tab_atom; - it->atom_count = tab_atom_count; - it->idx = 0; + if (it->is_array) { + if (it->idx >= it->array_length) + goto done; + prop = __JS_AtomFromUInt32(it->idx); + it->idx++; } else { - if (it->is_array) { - prop = __JS_AtomFromUInt32(it->idx); - it->idx++; - } else { - BOOL is_enumerable; - prop = it->tab_atom[it->idx].atom; - is_enumerable = it->tab_atom[it->idx].is_enumerable; - it->idx++; - if (it->in_prototype_chain) { - /* slow case: we are in the prototype chain */ - ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(enum_obj), prop); - if (ret < 0) - return ret; - if (ret) - continue; /* already visited */ - /* add to the visited property list */ - if (JS_DefinePropertyValue(ctx, enum_obj, prop, JS_NULL, - JS_PROP_ENUMERABLE) < 0) - return -1; - } - if (!is_enumerable) - continue; - } - /* check if the property was deleted */ - ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(it->obj), prop); - if (ret < 0) - return ret; - if (ret) + JSShape *sh = p->shape; + JSShapeProperty *prs; + if (it->idx >= sh->prop_count) + goto done; + prs = get_shape_prop(sh) + it->idx; + prop = prs->atom; + it->idx++; + if (prop == JS_ATOM_NULL || !(prs->flags & JS_PROP_ENUMERABLE)) + continue; + } + // check if the property was deleted unless we're dealing with a proxy + JSValue obj = it->obj; + if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { + JSObject *p = JS_VALUE_GET_OBJ(obj); + if (p->class_id == JS_CLASS_PROXY) break; } + ret = JS_HasProperty(ctx, obj, prop); + if (ret < 0) + return ret; + if (ret) + break; } /* return the property */ sp[0] = JS_AtomToValue(ctx, prop); @@ -15271,8 +13996,8 @@ static __exception int js_for_in_next(JSContext *ctx, JSValue *sp) return 0; } -static JSValue JS_GetIterator2(JSContext *ctx, JSValueConst obj, - JSValueConst method) +static JSValue JS_GetIterator2(JSContext *ctx, JSValue obj, + JSValue method) { JSValue enum_obj; @@ -15286,7 +14011,7 @@ static JSValue JS_GetIterator2(JSContext *ctx, JSValueConst obj, return enum_obj; } -static JSValue JS_GetIterator(JSContext *ctx, JSValueConst obj, BOOL is_async) +static JSValue JS_GetIterator(JSContext *ctx, JSValue obj, bool is_async) { JSValue method, ret, sync_iter; @@ -15321,9 +14046,9 @@ static JSValue JS_GetIterator(JSContext *ctx, JSValueConst obj, BOOL is_async) } /* return *pdone = 2 if the iterator object is not parsed */ -static JSValue JS_IteratorNext2(JSContext *ctx, JSValueConst enum_obj, - JSValueConst method, - int argc, JSValueConst *argv, int *pdone) +static JSValue JS_IteratorNext2(JSContext *ctx, JSValue enum_obj, + JSValue method, + int argc, JSValue *argv, int *pdone) { JSValue obj; @@ -15334,7 +14059,7 @@ static JSValue JS_IteratorNext2(JSContext *ctx, JSValueConst enum_obj, if (p->class_id == JS_CLASS_C_FUNCTION && p->u.cfunc.cproto == JS_CFUNC_iterator_next) { JSCFunctionType func; - JSValueConst args[1]; + JSValue args[1]; /* in case the function expects one argument */ if (argc == 0) { @@ -15357,13 +14082,13 @@ static JSValue JS_IteratorNext2(JSContext *ctx, JSValueConst enum_obj, *pdone = 2; return obj; fail: - *pdone = FALSE; + *pdone = false; return JS_EXCEPTION; } -static JSValue JS_IteratorNext(JSContext *ctx, JSValueConst enum_obj, - JSValueConst method, - int argc, JSValueConst *argv, BOOL *pdone) +static JSValue JS_IteratorNext(JSContext *ctx, JSValue enum_obj, + JSValue method, + int argc, JSValue *argv, int *pdone) { JSValue obj, value, done_val; int done; @@ -15388,20 +14113,20 @@ static JSValue JS_IteratorNext(JSContext *ctx, JSValueConst enum_obj, } fail: JS_FreeValue(ctx, obj); - *pdone = FALSE; + *pdone = false; return JS_EXCEPTION; } /* return < 0 in case of exception */ -static int JS_IteratorClose(JSContext *ctx, JSValueConst enum_obj, - BOOL is_exception_pending) +static int JS_IteratorClose(JSContext *ctx, JSValue enum_obj, + bool is_exception_pending) { JSValue method, ret, ex_obj; int res; if (is_exception_pending) { ex_obj = ctx->rt->current_exception; - ctx->rt->current_exception = JS_NULL; + ctx->rt->current_exception = JS_UNINITIALIZED; res = -1; } else { ex_obj = JS_UNDEFINED; @@ -15434,7 +14159,7 @@ static int JS_IteratorClose(JSContext *ctx, JSValueConst enum_obj, /* obj -> enum_rec (3 slots) */ static __exception int js_for_of_start(JSContext *ctx, JSValue *sp, - BOOL is_async) + bool is_async) { JSValue op1, obj, method; op1 = sp[-1]; @@ -15477,15 +14202,15 @@ static __exception int js_for_of_next(JSContext *ctx, JSValue *sp, int offset) } } sp[0] = value; - sp[1] = JS_NewBool(ctx, done); + sp[1] = js_bool(done); return 0; } -static JSValue JS_IteratorGetCompleteValue(JSContext *ctx, JSValueConst obj, - BOOL *pdone) +static JSValue JS_IteratorGetCompleteValue(JSContext *ctx, JSValue obj, + int *pdone) { JSValue done_val, value; - BOOL done; + int done; done_val = JS_GetProperty(ctx, obj, JS_ATOM_done); if (JS_IsException(done_val)) goto fail; @@ -15496,14 +14221,14 @@ static JSValue JS_IteratorGetCompleteValue(JSContext *ctx, JSValueConst obj, *pdone = done; return value; fail: - *pdone = FALSE; + *pdone = false; return JS_EXCEPTION; } static __exception int js_iterator_get_value_done(JSContext *ctx, JSValue *sp) { JSValue obj, value; - BOOL done; + int done; obj = sp[-1]; if (!JS_IsObject(obj)) { JS_ThrowTypeError(ctx, "iterator must return an object"); @@ -15514,13 +14239,13 @@ static __exception int js_iterator_get_value_done(JSContext *ctx, JSValue *sp) return -1; JS_FreeValue(ctx, obj); sp[-1] = value; - sp[0] = JS_NewBool(ctx, done); + sp[0] = js_bool(done); return 0; } static JSValue js_create_iterator_result(JSContext *ctx, JSValue val, - BOOL done) + bool done) { JSValue obj; obj = JS_NewObject(ctx); @@ -15533,7 +14258,7 @@ static JSValue js_create_iterator_result(JSContext *ctx, goto fail; } if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_done, - JS_NewBool(ctx, done), JS_PROP_C_W_E) < 0) { + js_bool(done), JS_PROP_C_W_E) < 0) { fail: JS_FreeValue(ctx, obj); return JS_EXCEPTION; @@ -15541,27 +14266,27 @@ static JSValue js_create_iterator_result(JSContext *ctx, return obj; } -static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, - BOOL *pdone, int magic); +static JSValue js_array_iterator_next(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, + int *pdone, int magic); -static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic); +static JSValue js_create_array_iterator(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic); -static BOOL js_is_fast_array(JSContext *ctx, JSValueConst obj) +static bool js_is_fast_array(JSContext *ctx, JSValue obj) { /* Try and handle fast arrays explicitly */ if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { JSObject *p = JS_VALUE_GET_OBJ(obj); if (p->class_id == JS_CLASS_ARRAY && p->fast_array) { - return TRUE; + return true; } } - return FALSE; + return false; } /* Access an Array's internal JSValue array if available */ -static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj, +static bool js_get_fast_array(JSContext *ctx, JSValue obj, JSValue **arrpp, uint32_t *countp) { /* Try and handle fast arrays explicitly */ @@ -15570,10 +14295,10 @@ static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj, if (p->class_id == JS_CLASS_ARRAY && p->fast_array) { *countp = p->u.array.count; *arrpp = p->u.array.u.values; - return TRUE; + return true; } } - return FALSE; + return false; } static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp) @@ -15599,12 +14324,14 @@ static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp) iterator = JS_GetProperty(ctx, sp[-1], JS_ATOM_Symbol_iterator); if (JS_IsException(iterator)) return -1; + /* Used to squelch a -Wcast-function-type warning. */ + JSCFunctionType ft = { .generic_magic = js_create_array_iterator }; is_array_iterator = JS_IsCFunction(ctx, iterator, - (JSCFunction *)js_create_array_iterator, + ft.generic, JS_ITERATOR_KIND_VALUE); JS_FreeValue(ctx, iterator); - enumobj = JS_GetIterator(ctx, sp[-1], FALSE); + enumobj = JS_GetIterator(ctx, sp[-1], false); if (JS_IsException(enumobj)) return -1; method = JS_GetProperty(ctx, enumobj, JS_ATOM_next); @@ -15612,9 +14339,11 @@ static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp) JS_FreeValue(ctx, enumobj); return -1; } + /* Used to squelch a -Wcast-function-type warning. */ + JSCFunctionType ft2 = { .iterator_next = js_array_iterator_next }; if (is_array_iterator - && JS_IsCFunction(ctx, method, (JSCFunction *)js_array_iterator_next, 0) - && js_get_fast_array(ctx, sp[-1], &arrp, &count32)) { + && JS_IsCFunction(ctx, method, ft2.generic, 0) + && js_get_fast_array(ctx, sp[-1], &arrp, &count32)) { uint32_t len; if (js_get_length32(ctx, &len, sp[-1])) goto exception; @@ -15625,13 +14354,13 @@ static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp) /* Handle fast arrays explicitly */ for (i = 0; i < count32; i++) { if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++, - JS_DupValue(ctx, arrp[i]), JS_PROP_C_W_E) < 0) + js_dup(arrp[i]), JS_PROP_C_W_E) < 0) goto exception; } } else { general_case: for (;;) { - BOOL done; + int done; value = JS_IteratorNext(ctx, enumobj, method, 0, NULL, &done); if (JS_IsException(value)) goto exception; @@ -15644,23 +14373,23 @@ static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp) } } /* Note: could raise an error if too many elements */ - sp[-2] = JS_NewInt32(ctx, pos); + sp[-2] = js_int32(pos); JS_FreeValue(ctx, enumobj); JS_FreeValue(ctx, method); return 0; exception: - JS_IteratorClose(ctx, enumobj, TRUE); + JS_IteratorClose(ctx, enumobj, true); JS_FreeValue(ctx, enumobj); JS_FreeValue(ctx, method); return -1; } static __exception int JS_CopyDataProperties(JSContext *ctx, - JSValueConst target, - JSValueConst source, - JSValueConst excluded, - BOOL setprop) + JSValue target, + JSValue source, + JSValue excluded, + bool setprop) { JSPropertyEnum *tab_atom; JSValue val; @@ -15669,7 +14398,7 @@ static __exception int JS_CopyDataProperties(JSContext *ctx, JSObject *pexcl = NULL; int ret, gpn_flags; JSPropertyDescriptor desc; - BOOL is_enumerable; + bool is_enumerable; if (JS_VALUE_GET_TAG(source) != JS_TAG_OBJECT) return 0; @@ -15732,19 +14461,19 @@ static __exception int JS_CopyDataProperties(JSContext *ctx, } /* only valid inside C functions */ -static JSValueConst JS_GetActiveFunction(JSContext *ctx) +static JSValue JS_GetActiveFunction(JSContext *ctx) { return ctx->rt->current_stack_frame->cur_func; } static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, - int var_idx, BOOL is_arg) + int var_idx, bool is_arg) { JSVarRef *var_ref; struct list_head *el; list_for_each(el, &sf->var_ref_list) { - var_ref = list_entry(el, JSVarRef, var_ref_link); + var_ref = list_entry(el, JSVarRef, header.link); if (var_ref->var_idx == var_idx && var_ref->is_arg == is_arg) { var_ref->header.ref_count++; return var_ref; @@ -15755,29 +14484,15 @@ static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, if (!var_ref) return NULL; var_ref->header.ref_count = 1; - add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF); - var_ref->is_detached = FALSE; + var_ref->is_detached = false; var_ref->is_arg = is_arg; var_ref->var_idx = var_idx; - list_add_tail(&var_ref->var_ref_link, &sf->var_ref_list); - if (sf->js_mode & JS_MODE_ASYNC) { - /* The stack frame is detached and may be destroyed at any - time so its reference count must be increased. Calling - close_var_refs() when destroying the stack frame is not - possible because it would change the graph between the GC - objects. Another solution could be to temporarily detach - the JSVarRef of async functions during the GC. It would - have the advantage of allowing the release of unused stack - frames in a cycle. */ - var_ref->async_func = container_of(sf, JSAsyncFunctionState, frame); - var_ref->async_func->header.ref_count++; - } else { - var_ref->async_func = NULL; - } + list_add_tail(&var_ref->header.link, &sf->var_ref_list); if (is_arg) var_ref->pvalue = &sf->arg_buf[var_idx]; else var_ref->pvalue = &sf->var_buf[var_idx]; + var_ref->value = JS_UNDEFINED; return var_ref; } @@ -15833,7 +14548,7 @@ static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom 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_dup(this_val), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); if (ret < 0) { JS_FreeValue(ctx, obj); @@ -15892,7 +14607,7 @@ static JSValue js_closure(JSContext *ctx, JSValue bfunc, /* add the 'prototype' property: delay instantiation to avoid creating cycles for every javascript function. The prototype object is created on the fly when first accessed */ - JS_SetConstructorBit(ctx, func_obj, TRUE); + JS_SetConstructorBit(ctx, func_obj, true); JS_DefineAutoInitProperty(ctx, func_obj, JS_ATOM_prototype, JS_AUTOINIT_ID_PROTOTYPE, NULL, JS_PROP_WRITABLE); @@ -15909,7 +14624,7 @@ static JSValue js_closure(JSContext *ctx, JSValue bfunc, static int js_op_define_class(JSContext *ctx, JSValue *sp, JSAtom class_name, int class_flags, JSVarRef **cur_var_refs, - JSStackFrame *sf, BOOL is_computed_name) + JSStackFrame *sf, bool is_computed_name) { JSValue bfunc, parent_class, proto = JS_UNDEFINED; JSValue ctor = JS_UNDEFINED, parent_proto = JS_UNDEFINED; @@ -15921,7 +14636,7 @@ static int js_op_define_class(JSContext *ctx, JSValue *sp, if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE) { if (JS_IsNull(parent_class)) { parent_proto = JS_NULL; - parent_class = JS_DupValue(ctx, ctx->function_proto); + parent_class = js_dup(ctx->function_proto); } else { if (!JS_IsConstructor(ctx, parent_class)) { JS_ThrowTypeError(ctx, "parent class must be constructor"); @@ -15937,8 +14652,8 @@ static int js_op_define_class(JSContext *ctx, JSValue *sp, } } else { /* parent_class is JS_UNDEFINED in this case */ - parent_proto = JS_DupValue(ctx, ctx->class_proto[JS_CLASS_OBJECT]); - parent_class = JS_DupValue(ctx, ctx->function_proto); + parent_proto = js_dup(ctx->class_proto[JS_CLASS_OBJECT]); + parent_class = js_dup(ctx->function_proto); } proto = JS_NewObjectProto(ctx, parent_proto); if (JS_IsException(proto)) @@ -15955,10 +14670,10 @@ static int js_op_define_class(JSContext *ctx, JSValue *sp, if (JS_IsException(ctor)) goto fail; js_method_set_home_object(ctx, ctor, proto); - JS_SetConstructorBit(ctx, ctor, TRUE); + JS_SetConstructorBit(ctx, ctor, true); JS_DefinePropertyValue(ctx, ctor, JS_ATOM_length, - JS_NewInt32(ctx, b->defined_arg_count), + js_int32(b->defined_arg_count), JS_PROP_CONFIGURABLE); if (is_computed_name) { @@ -15973,13 +14688,13 @@ static int js_op_define_class(JSContext *ctx, JSValue *sp, /* the constructor property must be first. It can be overriden by computed property names */ if (JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor, - JS_DupValue(ctx, ctor), + js_dup(ctor), JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE | JS_PROP_THROW) < 0) goto fail; /* set the prototype property */ if (JS_DefinePropertyValue(ctx, ctor, JS_ATOM_prototype, - JS_DupValue(ctx, proto), JS_PROP_THROW) < 0) + js_dup(proto), JS_PROP_THROW) < 0) goto fail; set_cycle_flag(ctx, ctor); set_cycle_flag(ctx, proto); @@ -16008,37 +14723,33 @@ static void close_var_refs(JSRuntime *rt, JSStackFrame *sf) int var_idx; list_for_each_safe(el, el1, &sf->var_ref_list) { - var_ref = list_entry(el, JSVarRef, var_ref_link); - /* no need to unlink var_ref->var_ref_link as the list is never used afterwards */ - if (var_ref->async_func) - async_func_free(rt, var_ref->async_func); + var_ref = list_entry(el, JSVarRef, header.link); var_idx = var_ref->var_idx; if (var_ref->is_arg) - var_ref->value = JS_DupValueRT(rt, sf->arg_buf[var_idx]); + var_ref->value = js_dup(sf->arg_buf[var_idx]); else - var_ref->value = JS_DupValueRT(rt, sf->var_buf[var_idx]); + var_ref->value = js_dup(sf->var_buf[var_idx]); var_ref->pvalue = &var_ref->value; /* the reference is no longer to a local variable */ - var_ref->is_detached = TRUE; + var_ref->is_detached = true; + add_gc_object(rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF); } } -static void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int idx, int is_arg) +static void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int var_idx) { struct list_head *el, *el1; JSVarRef *var_ref; - int var_idx = idx; list_for_each_safe(el, el1, &sf->var_ref_list) { - var_ref = list_entry(el, JSVarRef, var_ref_link); - if (var_idx == var_ref->var_idx && var_ref->is_arg == is_arg) { - list_del(&var_ref->var_ref_link); - if (var_ref->async_func) - async_func_free(ctx->rt, var_ref->async_func); - var_ref->value = JS_DupValue(ctx, sf->var_buf[var_idx]); + var_ref = list_entry(el, JSVarRef, header.link); + if (var_idx == var_ref->var_idx && !var_ref->is_arg) { + var_ref->value = js_dup(sf->var_buf[var_idx]); var_ref->pvalue = &var_ref->value; + list_del(&var_ref->header.link); /* the reference is no longer to a local variable */ - var_ref->is_detached = TRUE; + var_ref->is_detached = true; + add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF); } } } @@ -16046,16 +14757,16 @@ static void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int idx, int is_ #define JS_CALL_FLAG_COPY_ARGV (1 << 1) #define JS_CALL_FLAG_GENERATOR (1 << 2) -static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_obj, - int argc, JSValueConst *argv, int flags) +static JSValue js_call_c_function(JSContext *ctx, JSValue func_obj, + JSValue this_obj, + int argc, JSValue *argv, int flags) { JSRuntime *rt = ctx->rt; JSCFunctionType func; JSObject *p; JSStackFrame sf_s, *sf = &sf_s, *prev_sf; JSValue ret_val; - JSValueConst *arg_buf; + JSValue *arg_buf; int arg_count, i; JSCFunctionEnum cproto; @@ -16072,16 +14783,7 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj, rt->current_stack_frame = sf; ctx = p->u.cfunc.realm; /* change the current realm */ -#ifdef CONFIG_BIGNUM - /* we only propagate the bignum mode as some runtime functions - test it */ - if (prev_sf) - sf->js_mode = prev_sf->js_mode & JS_MODE_MATH; - else - sf->js_mode = 0; -#else - sf->js_mode = 0; -#endif + sf->is_strict_mode = false; sf->cur_func = func_obj; sf->arg_count = argc; arg_buf = argv; @@ -16095,7 +14797,7 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj, arg_buf[i] = JS_UNDEFINED; sf->arg_count = arg_count; } - sf->arg_buf = (JSValue*)arg_buf; + sf->arg_buf = arg_buf; func = p->u.cfunc.c_function; switch(cproto) { @@ -16149,7 +14851,7 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj, ret_val = JS_EXCEPTION; break; } - ret_val = JS_NewFloat64(ctx, func.f_f(d1)); + ret_val = js_number(func.f_f(d1)); } break; case JS_CFUNC_f_f_f: @@ -16164,7 +14866,7 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj, ret_val = JS_EXCEPTION; break; } - ret_val = JS_NewFloat64(ctx, func.f_f_f(d1, d2)); + ret_val = js_number(func.f_f_f(d1, d2)); } break; case JS_CFUNC_iterator_next: @@ -16185,13 +14887,13 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj, return ret_val; } -static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_obj, - int argc, JSValueConst *argv, int flags) +static JSValue js_call_bound_function(JSContext *ctx, JSValue func_obj, + JSValue this_obj, + int argc, JSValue *argv, int flags) { JSObject *p; JSBoundFunction *bf; - JSValueConst *arg_buf, new_target; + JSValue *arg_buf, new_target; int arg_count, i; p = JS_VALUE_GET_OBJ(func_obj); @@ -16229,14 +14931,19 @@ typedef enum { OP_SPECIAL_OBJECT_IMPORT_META, } OPSpecialObjectEnum; -#define FUNC_RET_AWAIT 0 -#define FUNC_RET_YIELD 1 -#define FUNC_RET_YIELD_STAR 2 -#define FUNC_RET_INITIAL_YIELD 3 +#define FUNC_RET_AWAIT 0 +#define FUNC_RET_YIELD 1 +#define FUNC_RET_YIELD_STAR 2 + +#ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_* +static void dump_single_byte_code(JSContext *ctx, const uint8_t *pc, + JSFunctionBytecode *b, int start_pos); +static void print_func_name(JSFunctionBytecode *b); +#endif /* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */ -static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, - JSValueConst this_obj, JSValueConst new_target, +static JSValue JS_CallInternal(JSContext *caller_ctx, JSValue func_obj, + JSValue this_obj, JSValue new_target, int argc, JSValue *argv, int flags) { JSRuntime *rt = caller_ctx->rt; @@ -16244,29 +14951,33 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JSObject *p; JSFunctionBytecode *b; JSStackFrame sf_s, *sf = &sf_s; - const uint8_t *pc; + uint8_t *pc; int opcode, arg_allocated_size, i; JSValue *local_buf, *stack_buf, *var_buf, *arg_buf, *sp, ret_val, *pval; JSVarRef **var_refs; size_t alloca_size; + JSInlineCache *ic; + +#ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_STEP +#define DUMP_BYTECODE_OR_DONT(pc) \ + if (check_dump_flag(ctx->rt, JS_DUMP_BYTECODE_STEP)) dump_single_byte_code(ctx, pc, b, 0); +#else +#define DUMP_BYTECODE_OR_DONT(pc) +#endif #if !DIRECT_DISPATCH -#define SWITCH(pc) switch (opcode = *pc++) +#define SWITCH(pc) DUMP_BYTECODE_OR_DONT(pc) switch (opcode = *pc++) #define CASE(op) case op #define DEFAULT default #define BREAK break #else - static const void * const dispatch_table[256] = { + __extension__ static const void * const dispatch_table[256] = { #define DEF(id, size, n_pop, n_push, f) && case_OP_ ## id, -#if SHORT_OPCODES #define def(id, size, n_pop, n_push, f) -#else -#define def(id, size, n_pop, n_push, f) && case_default, -#endif #include "quickjs-opcode.h" [ OP_COUNT ... 255 ] = &&case_default }; -#define SWITCH(pc) goto *dispatch_table[opcode = *pc++]; +#define SWITCH(pc) DUMP_BYTECODE_OR_DONT(pc) __extension__ ({ goto *dispatch_table[opcode = *pc++]; }); #define CASE(op) case_ ## op #define DEFAULT case_default #define BREAK SWITCH(pc) @@ -16292,6 +15003,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, pc = sf->cur_pc; sf->prev_frame = rt->current_stack_frame; rt->current_stack_frame = sf; + ic = b->ic; if (s->throw_flag) goto exception; else @@ -16309,7 +15021,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, return JS_ThrowTypeError(caller_ctx, "not a function"); } return call_func(caller_ctx, func_obj, this_obj, argc, - (JSValueConst *)argv, flags); + argv, flags); } b = p->u.func.function_bytecode; @@ -16324,7 +15036,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, if (js_check_stack_overflow(rt, alloca_size)) return JS_ThrowStackOverflow(caller_ctx); - sf->js_mode = b->js_mode; + sf->is_strict_mode = b->is_strict_mode; arg_buf = argv; sf->arg_count = argc; sf->cur_func = func_obj; @@ -16351,13 +15063,21 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, stack_buf = var_buf + b->var_count; sp = stack_buf; pc = b->byte_code_buf; + /* sf->cur_pc must we set to pc before any recursive calls to JS_CallInternal. */ + sf->cur_pc = NULL; sf->prev_frame = rt->current_stack_frame; rt->current_stack_frame = sf; ctx = b->realm; /* set the current realm */ + ic = b->ic; if (ctx->handleFunctionEntered) ctx->handleFunctionEntered(ctx, this_obj); +#ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_STEP + if (check_dump_flag(ctx->rt, JS_DUMP_BYTECODE_STEP)) + print_func_name(b); +#endif + restart: for(;;) { int call_argc; @@ -16365,14 +15085,13 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, SWITCH(pc) { CASE(OP_push_i32): - *sp++ = JS_NewInt32(ctx, get_u32(pc)); + *sp++ = js_int32(get_u32(pc)); pc += 4; BREAK; CASE(OP_push_const): - *sp++ = JS_DupValue(ctx, b->cpool[get_u32(pc)]); + *sp++ = js_dup(b->cpool[get_u32(pc)]); pc += 4; BREAK; -#if SHORT_OPCODES CASE(OP_push_minus1): CASE(OP_push_0): CASE(OP_push_1): @@ -16382,21 +15101,21 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, CASE(OP_push_5): CASE(OP_push_6): CASE(OP_push_7): - *sp++ = JS_NewInt32(ctx, opcode - OP_push_0); + *sp++ = js_int32(opcode - OP_push_0); BREAK; CASE(OP_push_i8): - *sp++ = JS_NewInt32(ctx, get_i8(pc)); + *sp++ = js_int32(get_i8(pc)); pc += 1; BREAK; CASE(OP_push_i16): - *sp++ = JS_NewInt32(ctx, get_i16(pc)); + *sp++ = js_int32(get_i16(pc)); pc += 2; BREAK; CASE(OP_push_const8): - *sp++ = JS_DupValue(ctx, b->cpool[*pc++]); + *sp++ = js_dup(b->cpool[*pc++]); BREAK; CASE(OP_fclosure8): - *sp++ = js_closure(ctx, JS_DupValue(ctx, b->cpool[*pc++]), var_refs, sf); + *sp++ = js_closure(ctx, js_dup(b->cpool[*pc++]), var_refs, sf); if (unlikely(JS_IsException(sp[-1]))) goto exception; BREAK; @@ -16407,6 +15126,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, { JSValue val; + sf->cur_pc = pc; val = JS_GetProperty(ctx, sp[-1], JS_ATOM_length); if (unlikely(JS_IsException(val))) goto exception; @@ -16414,7 +15134,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, sp[-1] = val; } BREAK; -#endif CASE(OP_push_atom_value): *sp++ = JS_AtomToValue(ctx, get_u32(pc)); pc += 4; @@ -16429,12 +15148,12 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, /* OP_push_this is only called at the start of a function */ { JSValue val; - if (!(b->js_mode & JS_MODE_STRICT)) { + if (!b->is_strict_mode) { uint32_t tag = JS_VALUE_GET_TAG(this_obj); if (likely(tag == JS_TAG_OBJECT)) goto normal_this; if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) { - val = JS_DupValue(ctx, ctx->global_obj); + val = js_dup(ctx->global_obj); } else { val = JS_ToObject(ctx, this_obj); if (JS_IsException(val)) @@ -16442,7 +15161,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, } } else { normal_this: - val = JS_DupValue(ctx, this_obj); + val = js_dup(this_obj); } *sp++ = val; } @@ -16463,21 +15182,21 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, int arg = *pc++; switch(arg) { case OP_SPECIAL_OBJECT_ARGUMENTS: - *sp++ = js_build_arguments(ctx, argc, (JSValueConst *)argv); + *sp++ = js_build_arguments(ctx, argc, argv); if (unlikely(JS_IsException(sp[-1]))) goto exception; break; case OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS: - *sp++ = js_build_mapped_arguments(ctx, argc, (JSValueConst *)argv, + *sp++ = js_build_mapped_arguments(ctx, argc, argv, sf, min_int(argc, b->arg_count)); if (unlikely(JS_IsException(sp[-1]))) goto exception; break; case OP_SPECIAL_OBJECT_THIS_FUNC: - *sp++ = JS_DupValue(ctx, sf->cur_func); + *sp++ = js_dup(sf->cur_func); break; case OP_SPECIAL_OBJECT_NEW_TARGET: - *sp++ = JS_DupValue(ctx, new_target); + *sp++ = js_dup(new_target); break; case OP_SPECIAL_OBJECT_HOME_OBJECT: { @@ -16486,7 +15205,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, if (unlikely(!p1)) *sp++ = JS_UNDEFINED; else - *sp++ = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1)); + *sp++ = js_dup(JS_MKPTR(JS_TAG_OBJECT, p1)); } break; case OP_SPECIAL_OBJECT_VAR_OBJECT: @@ -16508,7 +15227,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, { int first = get_u16(pc); pc += 2; - *sp++ = js_build_rest(ctx, first, argc, (JSValueConst *)argv); + *sp++ = js_build_rest(ctx, first, argc, argv); if (unlikely(JS_IsException(sp[-1]))) goto exception; } @@ -16530,36 +15249,36 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, sp--; BREAK; CASE(OP_dup): - sp[0] = JS_DupValue(ctx, sp[-1]); + sp[0] = js_dup(sp[-1]); sp++; BREAK; CASE(OP_dup2): /* a b -> a b a b */ - sp[0] = JS_DupValue(ctx, sp[-2]); - sp[1] = JS_DupValue(ctx, sp[-1]); + sp[0] = js_dup(sp[-2]); + sp[1] = js_dup(sp[-1]); sp += 2; BREAK; CASE(OP_dup3): /* a b c -> a b c a b c */ - sp[0] = JS_DupValue(ctx, sp[-3]); - sp[1] = JS_DupValue(ctx, sp[-2]); - sp[2] = JS_DupValue(ctx, sp[-1]); + sp[0] = js_dup(sp[-3]); + sp[1] = js_dup(sp[-2]); + sp[2] = js_dup(sp[-1]); sp += 3; BREAK; CASE(OP_dup1): /* a b -> a a b */ sp[0] = sp[-1]; - sp[-1] = JS_DupValue(ctx, sp[-2]); + sp[-1] = js_dup(sp[-2]); sp++; BREAK; CASE(OP_insert2): /* obj a -> a obj a (dup_x1) */ sp[0] = sp[-1]; sp[-1] = sp[-2]; - sp[-2] = JS_DupValue(ctx, sp[0]); + sp[-2] = js_dup(sp[0]); sp++; BREAK; CASE(OP_insert3): /* obj prop a -> a obj prop a (dup_x2) */ sp[0] = sp[-1]; sp[-1] = sp[-2]; sp[-2] = sp[-3]; - sp[-3] = JS_DupValue(ctx, sp[0]); + sp[-3] = js_dup(sp[0]); sp++; BREAK; CASE(OP_insert4): /* this obj prop a -> a this obj prop a */ @@ -16567,7 +15286,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, sp[-1] = sp[-2]; sp[-2] = sp[-3]; sp[-3] = sp[-4]; - sp[-4] = JS_DupValue(ctx, sp[0]); + sp[-4] = js_dup(sp[0]); sp++; BREAK; CASE(OP_perm3): /* obj a b -> a obj b (213) */ @@ -16658,21 +15377,19 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, CASE(OP_fclosure): { - JSValue bfunc = JS_DupValue(ctx, b->cpool[get_u32(pc)]); + JSValue bfunc = js_dup(b->cpool[get_u32(pc)]); pc += 4; *sp++ = js_closure(ctx, bfunc, var_refs, sf); if (unlikely(JS_IsException(sp[-1]))) goto exception; } BREAK; -#if SHORT_OPCODES CASE(OP_call0): CASE(OP_call1): CASE(OP_call2): CASE(OP_call3): call_argc = opcode - OP_call0; goto has_call_argc; -#endif CASE(OP_call): CASE(OP_tail_call): { @@ -16759,8 +15476,9 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, int magic; magic = get_u16(pc); pc += 2; + sf->cur_pc = pc; - ret_val = js_function_apply(ctx, sp[-3], 2, (JSValueConst *)&sp[-2], magic); + ret_val = js_function_apply(ctx, sp[-3], 2, &sp[-2], magic); if (unlikely(JS_IsException(ret_val))) goto exception; JS_FreeValue(ctx, sp[-3]); @@ -16778,7 +15496,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, goto done; CASE(OP_check_ctor_return): - /* return TRUE if 'this' should be returned */ + /* return true if 'this' should be returned */ if (!JS_IsObject(sp[-1])) { if (!JS_IsUndefined(sp[-1])) { JS_ThrowTypeError(caller_ctx, "derived class constructor must return an object or undefined"); @@ -16792,10 +15510,27 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, BREAK; CASE(OP_check_ctor): if (JS_IsUndefined(new_target)) { + non_ctor_call: JS_ThrowTypeError(ctx, "class constructors must be invoked with 'new'"); goto exception; } BREAK; + CASE(OP_init_ctor): + { + JSValue super, ret; + sf->cur_pc = pc; + if (JS_IsUndefined(new_target)) + goto non_ctor_call; + super = JS_GetPrototype(ctx, func_obj); + if (JS_IsException(super)) + goto exception; + ret = JS_CallConstructor2(ctx, super, new_target, argc, argv); + JS_FreeValue(ctx, super); + if (JS_IsException(ret)) + goto exception; + *sp++ = ret; + } + BREAK; CASE(OP_check_brand): { int ret = JS_CheckBrand(ctx, sp[-2], sp[-1]); @@ -16852,7 +15587,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, CASE(OP_eval): { - JSValueConst obj; + JSValue obj; int scope_idx; call_argc = get_u16(pc); scope_idx = get_u16(pc + 2) - 1; @@ -16884,10 +15619,11 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, int scope_idx; uint32_t len; JSValue *tab; - JSValueConst obj; + JSValue obj; scope_idx = get_u16(pc) - 1; pc += 2; + sf->cur_pc = pc; tab = build_arg_list(ctx, &len, sp[-1]); if (!tab) goto exception; @@ -16900,7 +15636,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JS_EVAL_TYPE_DIRECT, scope_idx); } else { ret_val = JS_Call(ctx, sp[-2], JS_UNDEFINED, len, - (JSValueConst *)tab); + tab); } free_arg_list(ctx, tab, len); if (unlikely(JS_IsException(ret_val))) @@ -16934,6 +15670,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, CASE(OP_import): { JSValue val; + sf->cur_pc = pc; val = js_dynamic_import(ctx, sp[-1]); if (JS_IsException(val)) goto exception; @@ -16952,7 +15689,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, ret = JS_CheckGlobalVar(ctx, atom); if (ret < 0) goto exception; - *sp++ = JS_NewBool(ctx, ret); + *sp++ = js_bool(ret); } BREAK; @@ -16963,6 +15700,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JSAtom atom; atom = get_u32(pc); pc += 4; + sf->cur_pc = pc; val = JS_GetGlobalVar(ctx, atom, opcode - OP_get_var_undef); if (unlikely(JS_IsException(val))) @@ -16978,6 +15716,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JSAtom atom; atom = get_u32(pc); pc += 4; + sf->cur_pc = pc; ret = JS_SetGlobalVar(ctx, atom, sp[-1], opcode - OP_put_var); sp--; @@ -16992,6 +15731,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JSAtom atom; atom = get_u32(pc); pc += 4; + sf->cur_pc = pc; /* sp[-2] is JS_TRUE or JS_FALSE */ if (unlikely(!JS_VALUE_GET_INT(sp[-2]))) { @@ -17046,7 +15786,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, int idx; idx = get_u16(pc); pc += 2; - sp[0] = JS_DupValue(ctx, var_buf[idx]); + sp[0] = js_dup(var_buf[idx]); sp++; } BREAK; @@ -17064,7 +15804,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, int idx; idx = get_u16(pc); pc += 2; - set_value(ctx, &var_buf[idx], JS_DupValue(ctx, sp[-1])); + set_value(ctx, &var_buf[idx], js_dup(sp[-1])); } BREAK; CASE(OP_get_arg): @@ -17072,7 +15812,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, int idx; idx = get_u16(pc); pc += 2; - sp[0] = JS_DupValue(ctx, arg_buf[idx]); + sp[0] = js_dup(arg_buf[idx]); sp++; } BREAK; @@ -17090,52 +15830,58 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, int idx; idx = get_u16(pc); pc += 2; - set_value(ctx, &arg_buf[idx], JS_DupValue(ctx, sp[-1])); + set_value(ctx, &arg_buf[idx], js_dup(sp[-1])); } BREAK; -#if SHORT_OPCODES - CASE(OP_get_loc8): *sp++ = JS_DupValue(ctx, var_buf[*pc++]); BREAK; + CASE(OP_get_loc8): *sp++ = js_dup(var_buf[*pc++]); BREAK; CASE(OP_put_loc8): set_value(ctx, &var_buf[*pc++], *--sp); BREAK; - CASE(OP_set_loc8): set_value(ctx, &var_buf[*pc++], JS_DupValue(ctx, sp[-1])); BREAK; + CASE(OP_set_loc8): set_value(ctx, &var_buf[*pc++], js_dup(sp[-1])); BREAK; + + // Observation: get_loc0 and get_loc1 are individually very + // frequent opcodes _and_ they are very often paired together, + // making them ideal candidates for opcode fusion. + CASE(OP_get_loc0_loc1): + *sp++ = js_dup(var_buf[0]); + *sp++ = js_dup(var_buf[1]); + BREAK; - CASE(OP_get_loc0): *sp++ = JS_DupValue(ctx, var_buf[0]); BREAK; - CASE(OP_get_loc1): *sp++ = JS_DupValue(ctx, var_buf[1]); BREAK; - CASE(OP_get_loc2): *sp++ = JS_DupValue(ctx, var_buf[2]); BREAK; - CASE(OP_get_loc3): *sp++ = JS_DupValue(ctx, var_buf[3]); BREAK; + CASE(OP_get_loc0): *sp++ = js_dup(var_buf[0]); BREAK; + CASE(OP_get_loc1): *sp++ = js_dup(var_buf[1]); BREAK; + CASE(OP_get_loc2): *sp++ = js_dup(var_buf[2]); BREAK; + CASE(OP_get_loc3): *sp++ = js_dup(var_buf[3]); BREAK; CASE(OP_put_loc0): set_value(ctx, &var_buf[0], *--sp); BREAK; CASE(OP_put_loc1): set_value(ctx, &var_buf[1], *--sp); BREAK; CASE(OP_put_loc2): set_value(ctx, &var_buf[2], *--sp); BREAK; CASE(OP_put_loc3): set_value(ctx, &var_buf[3], *--sp); BREAK; - CASE(OP_set_loc0): set_value(ctx, &var_buf[0], JS_DupValue(ctx, sp[-1])); BREAK; - CASE(OP_set_loc1): set_value(ctx, &var_buf[1], JS_DupValue(ctx, sp[-1])); BREAK; - CASE(OP_set_loc2): set_value(ctx, &var_buf[2], JS_DupValue(ctx, sp[-1])); BREAK; - CASE(OP_set_loc3): set_value(ctx, &var_buf[3], JS_DupValue(ctx, sp[-1])); BREAK; - CASE(OP_get_arg0): *sp++ = JS_DupValue(ctx, arg_buf[0]); BREAK; - CASE(OP_get_arg1): *sp++ = JS_DupValue(ctx, arg_buf[1]); BREAK; - CASE(OP_get_arg2): *sp++ = JS_DupValue(ctx, arg_buf[2]); BREAK; - CASE(OP_get_arg3): *sp++ = JS_DupValue(ctx, arg_buf[3]); BREAK; + CASE(OP_set_loc0): set_value(ctx, &var_buf[0], js_dup(sp[-1])); BREAK; + CASE(OP_set_loc1): set_value(ctx, &var_buf[1], js_dup(sp[-1])); BREAK; + CASE(OP_set_loc2): set_value(ctx, &var_buf[2], js_dup(sp[-1])); BREAK; + CASE(OP_set_loc3): set_value(ctx, &var_buf[3], js_dup(sp[-1])); BREAK; + CASE(OP_get_arg0): *sp++ = js_dup(arg_buf[0]); BREAK; + CASE(OP_get_arg1): *sp++ = js_dup(arg_buf[1]); BREAK; + CASE(OP_get_arg2): *sp++ = js_dup(arg_buf[2]); BREAK; + CASE(OP_get_arg3): *sp++ = js_dup(arg_buf[3]); BREAK; CASE(OP_put_arg0): set_value(ctx, &arg_buf[0], *--sp); BREAK; CASE(OP_put_arg1): set_value(ctx, &arg_buf[1], *--sp); BREAK; CASE(OP_put_arg2): set_value(ctx, &arg_buf[2], *--sp); BREAK; CASE(OP_put_arg3): set_value(ctx, &arg_buf[3], *--sp); BREAK; - CASE(OP_set_arg0): set_value(ctx, &arg_buf[0], JS_DupValue(ctx, sp[-1])); BREAK; - CASE(OP_set_arg1): set_value(ctx, &arg_buf[1], JS_DupValue(ctx, sp[-1])); BREAK; - CASE(OP_set_arg2): set_value(ctx, &arg_buf[2], JS_DupValue(ctx, sp[-1])); BREAK; - CASE(OP_set_arg3): set_value(ctx, &arg_buf[3], JS_DupValue(ctx, sp[-1])); BREAK; - CASE(OP_get_var_ref0): *sp++ = JS_DupValue(ctx, *var_refs[0]->pvalue); BREAK; - CASE(OP_get_var_ref1): *sp++ = JS_DupValue(ctx, *var_refs[1]->pvalue); BREAK; - CASE(OP_get_var_ref2): *sp++ = JS_DupValue(ctx, *var_refs[2]->pvalue); BREAK; - CASE(OP_get_var_ref3): *sp++ = JS_DupValue(ctx, *var_refs[3]->pvalue); BREAK; + CASE(OP_set_arg0): set_value(ctx, &arg_buf[0], js_dup(sp[-1])); BREAK; + CASE(OP_set_arg1): set_value(ctx, &arg_buf[1], js_dup(sp[-1])); BREAK; + CASE(OP_set_arg2): set_value(ctx, &arg_buf[2], js_dup(sp[-1])); BREAK; + CASE(OP_set_arg3): set_value(ctx, &arg_buf[3], js_dup(sp[-1])); BREAK; + CASE(OP_get_var_ref0): *sp++ = js_dup(*var_refs[0]->pvalue); BREAK; + CASE(OP_get_var_ref1): *sp++ = js_dup(*var_refs[1]->pvalue); BREAK; + CASE(OP_get_var_ref2): *sp++ = js_dup(*var_refs[2]->pvalue); BREAK; + CASE(OP_get_var_ref3): *sp++ = js_dup(*var_refs[3]->pvalue); BREAK; CASE(OP_put_var_ref0): set_value(ctx, var_refs[0]->pvalue, *--sp); BREAK; CASE(OP_put_var_ref1): set_value(ctx, var_refs[1]->pvalue, *--sp); BREAK; CASE(OP_put_var_ref2): set_value(ctx, var_refs[2]->pvalue, *--sp); BREAK; CASE(OP_put_var_ref3): set_value(ctx, var_refs[3]->pvalue, *--sp); BREAK; - CASE(OP_set_var_ref0): set_value(ctx, var_refs[0]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK; - CASE(OP_set_var_ref1): set_value(ctx, var_refs[1]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK; - CASE(OP_set_var_ref2): set_value(ctx, var_refs[2]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK; - CASE(OP_set_var_ref3): set_value(ctx, var_refs[3]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK; -#endif + CASE(OP_set_var_ref0): set_value(ctx, var_refs[0]->pvalue, js_dup(sp[-1])); BREAK; + CASE(OP_set_var_ref1): set_value(ctx, var_refs[1]->pvalue, js_dup(sp[-1])); BREAK; + CASE(OP_set_var_ref2): set_value(ctx, var_refs[2]->pvalue, js_dup(sp[-1])); BREAK; + CASE(OP_set_var_ref3): set_value(ctx, var_refs[3]->pvalue, js_dup(sp[-1])); BREAK; CASE(OP_get_var_ref): { @@ -17144,7 +15890,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, idx = get_u16(pc); pc += 2; val = *var_refs[idx]->pvalue; - sp[0] = JS_DupValue(ctx, val); + sp[0] = js_dup(val); sp++; } BREAK; @@ -17162,7 +15908,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, int idx; idx = get_u16(pc); pc += 2; - set_value(ctx, var_refs[idx]->pvalue, JS_DupValue(ctx, sp[-1])); + set_value(ctx, var_refs[idx]->pvalue, js_dup(sp[-1])); } BREAK; CASE(OP_get_var_ref_check): @@ -17173,10 +15919,10 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, pc += 2; val = *var_refs[idx]->pvalue; if (unlikely(JS_IsUninitialized(val))) { - JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE); + JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, true); goto exception; } - sp[0] = JS_DupValue(ctx, val); + sp[0] = js_dup(val); sp++; } BREAK; @@ -17186,7 +15932,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_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE); + JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, true); goto exception; } set_value(ctx, var_refs[idx]->pvalue, sp[-1]); @@ -17199,7 +15945,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_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE); + JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, true); goto exception; } set_value(ctx, var_refs[idx]->pvalue, sp[-1]); @@ -17220,23 +15966,11 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, idx = get_u16(pc); pc += 2; if (unlikely(JS_IsUninitialized(var_buf[idx]))) { - JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE); - goto exception; - } - sp[0] = JS_DupValue(ctx, var_buf[idx]); - sp++; - } - BREAK; - CASE(OP_get_loc_checkthis): - { - int idx; - idx = get_u16(pc); - pc += 2; - if (unlikely(JS_IsUninitialized(var_buf[idx]))) { - JS_ThrowReferenceErrorUninitialized2(caller_ctx, b, idx, FALSE); + JS_ThrowReferenceErrorUninitialized2(caller_ctx, b, idx, + false); goto exception; } - sp[0] = JS_DupValue(ctx, var_buf[idx]); + sp[0] = js_dup(var_buf[idx]); sp++; } BREAK; @@ -17246,7 +15980,8 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, idx = get_u16(pc); pc += 2; if (unlikely(JS_IsUninitialized(var_buf[idx]))) { - JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE); + JS_ThrowReferenceErrorUninitialized2(caller_ctx, b, idx, + false); goto exception; } set_value(ctx, &var_buf[idx], sp[-1]); @@ -17259,7 +15994,8 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, idx = get_u16(pc); pc += 2; if (unlikely(!JS_IsUninitialized(var_buf[idx]))) { - JS_ThrowReferenceError(ctx, "'this' can be initialized only once"); + JS_ThrowReferenceError(caller_ctx, + "'this' can be initialized only once"); goto exception; } set_value(ctx, &var_buf[idx], sp[-1]); @@ -17271,7 +16007,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, int idx; idx = get_u16(pc); pc += 2; - close_lexical_var(ctx, sf, idx, FALSE); + close_lexical_var(ctx, sf, idx); } BREAK; @@ -17324,7 +16060,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, if (unlikely(js_poll_interrupts(ctx))) goto exception; BREAK; -#if SHORT_OPCODES CASE(OP_goto16): pc += (int16_t)get_u16(pc); if (unlikely(js_poll_interrupts(ctx))) @@ -17335,7 +16070,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, if (unlikely(js_poll_interrupts(ctx))) goto exception; BREAK; -#endif CASE(OP_if_true): { int res; @@ -17363,7 +16097,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, op1 = sp[-1]; pc += 4; - /* quick and dirty test for JS_TAG_INT, JS_TAG_BOOL, JS_TAG_NULL and JS_TAG_UNDEFINED */ if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) { res = JS_VALUE_GET_INT(op1); } else { @@ -17377,7 +16110,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, goto exception; } BREAK; -#if SHORT_OPCODES CASE(OP_if_true8): { int res; @@ -17418,7 +16150,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, goto exception; } BREAK; -#endif CASE(OP_catch): { int32_t diff; @@ -17433,7 +16164,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, int32_t diff; diff = get_u32(pc); /* XXX: should have a different tag to avoid security flaw */ - sp[0] = JS_NewInt32(ctx, pc + 4 - b->byte_code_buf); + sp[0] = js_int32(pc + 4 - b->byte_code_buf); sp++; pc += diff; } @@ -17457,16 +16188,19 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, BREAK; CASE(OP_for_in_start): + sf->cur_pc = pc; if (js_for_in_start(ctx, sp)) goto exception; BREAK; CASE(OP_for_in_next): + sf->cur_pc = pc; if (js_for_in_next(ctx, sp)) goto exception; sp += 2; BREAK; CASE(OP_for_of_start): - if (js_for_of_start(ctx, sp, FALSE)) + sf->cur_pc = pc; + if (js_for_of_start(ctx, sp, false)) goto exception; sp += 1; *sp++ = JS_NewCatchOffset(ctx, 0); @@ -17475,18 +16209,21 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, { int offset = -3 - pc[0]; pc += 1; + sf->cur_pc = pc; if (js_for_of_next(ctx, sp, offset)) goto exception; sp += 2; } BREAK; CASE(OP_for_await_of_start): - if (js_for_of_start(ctx, sp, TRUE)) + sf->cur_pc = pc; + if (js_for_of_start(ctx, sp, true)) goto exception; sp += 1; *sp++ = JS_NewCatchOffset(ctx, 0); BREAK; CASE(OP_iterator_get_value_done): + sf->cur_pc = pc; if (js_iterator_get_value_done(ctx, sp)) goto exception; sp += 1; @@ -17504,7 +16241,8 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JS_FreeValue(ctx, sp[-1]); /* drop the next method */ sp--; if (!JS_IsUndefined(sp[-1])) { - if (JS_IteratorClose(ctx, sp[-1], FALSE)) + sf->cur_pc = pc; + if (JS_IteratorClose(ctx, sp[-1], false)) goto exception; JS_FreeValue(ctx, sp[-1]); } @@ -17532,8 +16270,8 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, /* stack: iter_obj next catch_offset val */ { JSValue ret; - ret = JS_Call(ctx, sp[-3], sp[-4], - 1, (JSValueConst *)(sp - 1)); + sf->cur_pc = pc; + ret = JS_Call(ctx, sp[-3], sp[-4], 1, (sp - 1)); if (JS_IsException(ret)) goto exception; JS_FreeValue(ctx, sp[-1]); @@ -17545,15 +16283,16 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, /* stack: iter_obj next catch_offset val */ { JSValue method, ret; - BOOL ret_flag; + bool ret_flag; int flags; flags = *pc++; + sf->cur_pc = pc; 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; + ret_flag = true; } else { if (flags & 2) { /* no argument */ @@ -17561,15 +16300,15 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, 0, NULL); } else { ret = JS_CallFree(ctx, method, sp[-4], - 1, (JSValueConst *)(sp - 1)); + 1, (sp - 1)); } if (JS_IsException(ret)) goto exception; JS_FreeValue(ctx, sp[-1]); sp[-1] = ret; - ret_flag = FALSE; + ret_flag = false; } - sp[0] = JS_NewBool(ctx, ret_flag); + sp[0] = js_bool(ret_flag); sp += 1; } BREAK; @@ -17585,7 +16324,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, } else { res = JS_ToBoolFree(ctx, op1); } - sp[-1] = JS_NewBool(ctx, !res); + sp[-1] = js_bool(!res); } BREAK; @@ -17593,12 +16332,39 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, { JSValue val; JSAtom atom; + JSInlineCacheUpdate icu; atom = get_u32(pc); pc += 4; + sf->cur_pc = pc; + icu = (JSInlineCacheUpdate){ic, INLINE_CACHE_MISS}; + val = JS_GetPropertyInternal2(ctx, sp[-1], atom, sp[-1], &icu, false); + if (unlikely(JS_IsException(val))) + goto exception; + if (icu.offset != INLINE_CACHE_MISS) { + put_u8(pc - 5, OP_get_field_ic); + put_u32(pc - 4, icu.offset); + JS_FreeAtom(ctx, atom); + } + JS_FreeValue(ctx, sp[-1]); + sp[-1] = val; + } + BREAK; - val = JS_GetProperty(ctx, sp[-1], atom); + CASE(OP_get_field_ic): + { + JSValue val; + JSAtom atom; + uint32_t ic_offset; + JSInlineCacheUpdate icu; + ic_offset = get_u32(pc); + atom = get_ic_atom(ic, ic_offset); + pc += 4; + sf->cur_pc = pc; + icu = (JSInlineCacheUpdate){ic, ic_offset}; + val = JS_GetPropertyInternalWithIC(ctx, sp[-1], atom, sp[-1], &icu, false); if (unlikely(JS_IsException(val))) goto exception; + assert(icu.offset == ic_offset); JS_FreeValue(ctx, sp[-1]); sp[-1] = val; } @@ -17608,12 +16374,38 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, { JSValue val; JSAtom atom; + JSInlineCacheUpdate icu; atom = get_u32(pc); pc += 4; + sf->cur_pc = pc; + icu = (JSInlineCacheUpdate){ic, INLINE_CACHE_MISS}; + val = JS_GetPropertyInternal2(ctx, sp[-1], atom, sp[-1], &icu, false); + if (unlikely(JS_IsException(val))) + goto exception; + if (icu.offset != INLINE_CACHE_MISS) { + put_u8(pc - 5, OP_get_field2_ic); + put_u32(pc - 4, icu.offset); + JS_FreeAtom(ctx, atom); + } + *sp++ = val; + } + BREAK; - val = JS_GetProperty(ctx, sp[-1], atom); + CASE(OP_get_field2_ic): + { + JSValue val; + JSAtom atom; + uint32_t ic_offset; + JSInlineCacheUpdate icu; + ic_offset = get_u32(pc); + atom = get_ic_atom(ic, ic_offset); + pc += 4; + sf->cur_pc = pc; + icu = (JSInlineCacheUpdate){ic, ic_offset}; + val = JS_GetPropertyInternalWithIC(ctx, sp[-1], atom, sp[-1], &icu, false); if (unlikely(JS_IsException(val))) goto exception; + assert(icu.offset == ic_offset); *sp++ = val; } BREAK; @@ -17622,15 +16414,45 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, { int ret; JSAtom atom; + JSInlineCacheUpdate icu; atom = get_u32(pc); pc += 4; + sf->cur_pc = pc; + icu = (JSInlineCacheUpdate){ic, INLINE_CACHE_MISS}; + ret = JS_SetPropertyInternal2(ctx, + sp[-2], atom, + sp[-1], sp[-2], + JS_PROP_THROW_STRICT, &icu); + JS_FreeValue(ctx, sp[-2]); + sp -= 2; + if (unlikely(ret < 0)) + goto exception; + if (icu.offset != INLINE_CACHE_MISS) { + put_u8(pc - 5, OP_put_field_ic); + put_u32(pc - 4, icu.offset); + JS_FreeAtom(ctx, atom); + } + } + BREAK; - ret = JS_SetPropertyInternal(ctx, sp[-2], atom, sp[-1], sp[-2], - JS_PROP_THROW_STRICT); + CASE(OP_put_field_ic): + { + int ret; + JSAtom atom; + uint32_t ic_offset; + JSInlineCacheUpdate icu; + ic_offset = get_u32(pc); + atom = get_ic_atom(ic, ic_offset); + pc += 4; + sf->cur_pc = pc; + icu = (JSInlineCacheUpdate){ic, ic_offset}; + ret = JS_SetPropertyInternalWithIC(ctx, sp[-2], atom, sp[-1], + JS_PROP_THROW_STRICT, &icu); JS_FreeValue(ctx, sp[-2]); sp -= 2; if (unlikely(ret < 0)) goto exception; + assert(icu.offset == ic_offset); } BREAK; @@ -17651,7 +16473,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, CASE(OP_get_private_field): { JSValue val; - + sf->cur_pc = pc; val = JS_GetPrivateField(ctx, sp[-2], sp[-1]); JS_FreeValue(ctx, sp[-1]); JS_FreeValue(ctx, sp[-2]); @@ -17665,6 +16487,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, CASE(OP_put_private_field): { int ret; + sf->cur_pc = pc; ret = JS_SetPrivateField(ctx, sp[-3], sp[-1], sp[-2]); JS_FreeValue(ctx, sp[-3]); JS_FreeValue(ctx, sp[-1]); @@ -17725,7 +16548,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JSValue proto; proto = sp[-1]; if (JS_IsObject(proto) || JS_IsNull(proto)) { - if (JS_SetPrototypeInternal(ctx, sp[-2], proto, TRUE) < 0) + if (JS_SetPrototypeInternal(ctx, sp[-2], proto, true) < 0) goto exception; } JS_FreeValue(ctx, proto); @@ -17739,10 +16562,10 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, CASE(OP_define_method_computed): { JSValue getter, setter, value; - JSValueConst obj; + JSValue obj; JSAtom atom; int flags, ret, op_flags; - BOOL is_computed; + bool is_computed; #define OP_DEFINE_METHOD_METHOD 0 #define OP_DEFINE_METHOD_GETTER 1 #define OP_DEFINE_METHOD_SETTER 2 @@ -17815,6 +16638,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, { JSValue val; + sf->cur_pc = pc; val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]); JS_FreeValue(ctx, sp[-2]); sp[-2] = val; @@ -17828,6 +16652,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, { JSValue val; + sf->cur_pc = pc; val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]); sp[-1] = val; if (unlikely(JS_IsException(val))) @@ -17838,6 +16663,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, CASE(OP_get_ref_value): { JSValue val; + sf->cur_pc = pc; if (unlikely(JS_IsUndefined(sp[-2]))) { JSAtom atom = JS_ValueToAtom(ctx, sp[-1]); if (atom != JS_ATOM_NULL) { @@ -17847,7 +16673,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, goto exception; } val = JS_GetPropertyValue(ctx, sp[-2], - JS_DupValue(ctx, sp[-1])); + js_dup(sp[-1])); if (unlikely(JS_IsException(val))) goto exception; sp[0] = val; @@ -17859,10 +16685,11 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, { JSValue val; JSAtom atom; + sf->cur_pc = pc; atom = JS_ValueToAtom(ctx, sp[-1]); if (unlikely(atom == JS_ATOM_NULL)) goto exception; - val = JS_GetPropertyInternal(ctx, sp[-2], atom, sp[-3], FALSE); + val = JS_GetPropertyInternal2(ctx, sp[-2], atom, sp[-3], NULL, false); JS_FreeAtom(ctx, atom); if (unlikely(JS_IsException(val))) goto exception; @@ -17877,7 +16704,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, CASE(OP_put_array_el): { int ret; - + sf->cur_pc = pc; ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], JS_PROP_THROW_STRICT); JS_FreeValue(ctx, sp[-3]); sp -= 3; @@ -17889,6 +16716,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, CASE(OP_put_ref_value): { int ret, flags; + sf->cur_pc = pc; flags = JS_PROP_THROW_STRICT; if (unlikely(JS_IsUndefined(sp[-3]))) { if (is_strict_mode(ctx)) { @@ -17899,7 +16727,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, } goto exception; } else { - sp[-3] = JS_DupValue(ctx, ctx->global_obj); + sp[-3] = js_dup(ctx->global_obj); } } else { if (is_strict_mode(ctx)) @@ -17917,6 +16745,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, { int ret; JSAtom atom; + sf->cur_pc = pc; if (JS_VALUE_GET_TAG(sp[-3]) != JS_TAG_OBJECT) { JS_ThrowTypeErrorNotAnObject(ctx); goto exception; @@ -17924,8 +16753,10 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, atom = JS_ValueToAtom(ctx, sp[-2]); if (unlikely(atom == JS_ATOM_NULL)) goto exception; - ret = JS_SetPropertyInternal(ctx, sp[-3], atom, sp[-1], sp[-4], - JS_PROP_THROW_STRICT); + ret = JS_SetPropertyInternal2(ctx, + sp[-3], atom, + sp[-1], sp[-4], + JS_PROP_THROW_STRICT, NULL); JS_FreeAtom(ctx, atom); JS_FreeValue(ctx, sp[-4]); JS_FreeValue(ctx, sp[-3]); @@ -17939,7 +16770,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, CASE(OP_define_array_el): { int ret; - ret = JS_DefinePropertyValueValue(ctx, sp[-3], JS_DupValue(ctx, sp[-2]), sp[-1], + ret = JS_DefinePropertyValueValue(ctx, sp[-3], js_dup(sp[-2]), sp[-1], JS_PROP_C_W_E | JS_PROP_THROW); sp -= 1; if (unlikely(ret < 0)) @@ -17949,6 +16780,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, CASE(OP_append): /* array pos enumobj -- array pos */ { + sf->cur_pc = pc; if (js_append_enumerate(ctx, sp)) goto exception; JS_FreeValue(ctx, *--sp); @@ -17964,6 +16796,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, int mask; mask = *pc++; + sf->cur_pc = pc; if (JS_CopyDataProperties(ctx, sp[-1 - (mask & 3)], sp[-1 - ((mask >> 2) & 7)], sp[-1 - ((mask >> 5) & 7)], 0)) @@ -17981,19 +16814,15 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, r = (int64_t)JS_VALUE_GET_INT(op1) + JS_VALUE_GET_INT(op2); if (unlikely((int)r != r)) goto add_slow; - sp[-2] = JS_NewInt32(ctx, r); + sp[-2] = js_int32(r); sp--; } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) { - sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) + - JS_VALUE_GET_FLOAT64(op2)); + sp[-2] = js_float64(JS_VALUE_GET_FLOAT64(op1) + + JS_VALUE_GET_FLOAT64(op2)); sp--; - } else if (JS_IsString(op1) && JS_IsString(op2)) { - sp[-2] = JS_ConcatString(ctx, op1, op2); - sp--; - if (JS_IsException(sp[-1])) - goto exception; } else { add_slow: + sf->cur_pc = pc; if (js_add_slow(ctx, sp)) goto exception; sp--; @@ -18002,45 +16831,40 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, BREAK; CASE(OP_add_loc): { - JSValue op2; JSValue *pv; int idx; idx = *pc; pc += 1; - op2 = sp[-1]; pv = &var_buf[idx]; - if (likely(JS_VALUE_IS_BOTH_INT(*pv, op2))) { + if (likely(JS_VALUE_IS_BOTH_INT(*pv, sp[-1]))) { int64_t r; - r = (int64_t)JS_VALUE_GET_INT(*pv) + JS_VALUE_GET_INT(op2); + r = (int64_t)JS_VALUE_GET_INT(*pv) + + JS_VALUE_GET_INT(sp[-1]); if (unlikely((int)r != r)) goto add_loc_slow; - *pv = JS_NewInt32(ctx, r); - sp--; - } else if (JS_VALUE_IS_BOTH_FLOAT(*pv, op2)) { - *pv = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(*pv) + - JS_VALUE_GET_FLOAT64(op2)); + *pv = js_int32(r); sp--; } else if (JS_VALUE_GET_TAG(*pv) == JS_TAG_STRING) { + JSValue op1; + op1 = sp[-1]; sp--; - op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE); - if (JS_IsException(op2)) + sf->cur_pc = pc; + op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE); + if (JS_IsException(op1)) goto exception; - if (JS_ConcatStringInPlace(ctx, JS_VALUE_GET_STRING(*pv), op2)) { - JS_FreeValue(ctx, op2); - } else { - op2 = JS_ConcatString(ctx, JS_DupValue(ctx, *pv), op2); - if (JS_IsException(op2)) - goto exception; - set_value(ctx, pv, op2); - } + op1 = JS_ConcatString(ctx, js_dup(*pv), op1); + if (JS_IsException(op1)) + goto exception; + set_value(ctx, pv, op1); } else { JSValue ops[2]; add_loc_slow: /* In case of exception, js_add_slow frees ops[0] and ops[1], so we must duplicate *pv */ - ops[0] = JS_DupValue(ctx, *pv); - ops[1] = op2; + sf->cur_pc = pc; + ops[0] = js_dup(*pv); + ops[1] = sp[-1]; sp--; if (js_add_slow(ctx, ops + 2)) goto exception; @@ -18058,11 +16882,11 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, r = (int64_t)JS_VALUE_GET_INT(op1) - JS_VALUE_GET_INT(op2); if (unlikely((int)r != r)) goto binary_arith_slow; - sp[-2] = JS_NewInt32(ctx, r); + sp[-2] = js_int32(r); sp--; } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) { - sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) - - JS_VALUE_GET_FLOAT64(op2)); + sp[-2] = js_float64(JS_VALUE_GET_FLOAT64(op1) - + JS_VALUE_GET_FLOAT64(op2)); sp--; } else { goto binary_arith_slow; @@ -18082,11 +16906,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, v2 = JS_VALUE_GET_INT(op2); r = (int64_t)v1 * v2; if (unlikely((int)r != r)) { -#ifdef CONFIG_BIGNUM - if (unlikely(sf->js_mode & JS_MODE_MATH) && - (r < -MAX_SAFE_INTEGER || r > MAX_SAFE_INTEGER)) - goto binary_arith_slow; -#endif d = (double)r; goto mul_fp_res; } @@ -18095,16 +16914,12 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, d = -0.0; goto mul_fp_res; } - sp[-2] = JS_NewInt32(ctx, r); + sp[-2] = js_int32(r); sp--; } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) { -#ifdef CONFIG_BIGNUM - if (unlikely(sf->js_mode & JS_MODE_MATH)) - goto binary_arith_slow; -#endif d = JS_VALUE_GET_FLOAT64(op1) * JS_VALUE_GET_FLOAT64(op2); mul_fp_res: - sp[-2] = __JS_NewFloat64(ctx, d); + sp[-2] = js_float64(d); sp--; } else { goto binary_arith_slow; @@ -18118,11 +16933,9 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, op2 = sp[-1]; if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { int v1, v2; - if (unlikely(sf->js_mode & JS_MODE_MATH)) - goto binary_arith_slow; v1 = JS_VALUE_GET_INT(op1); v2 = JS_VALUE_GET_INT(op2); - sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2); + sp[-2] = js_number((double)v1 / (double)v2); sp--; } else { goto binary_arith_slow; @@ -18130,9 +16943,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, } BREAK; CASE(OP_mod): -#ifdef CONFIG_BIGNUM - CASE(OP_math_mod): -#endif { JSValue op1, op2; op1 = sp[-2]; @@ -18146,7 +16956,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, if (unlikely(v1 < 0 || v2 <= 0)) goto binary_arith_slow; r = v1 % v2; - sp[-2] = JS_NewInt32(ctx, r); + sp[-2] = js_int32(r); sp--; } else { goto binary_arith_slow; @@ -18155,6 +16965,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, BREAK; CASE(OP_pow): binary_arith_slow: + sf->cur_pc = pc; if (js_binary_arith_slow(ctx, sp, opcode)) goto exception; sp--; @@ -18168,6 +16979,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, tag = JS_VALUE_GET_TAG(op1); if (tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag)) { } else { + sf->cur_pc = pc; if (js_unary_arith_slow(ctx, sp, opcode)) goto exception; } @@ -18192,12 +17004,13 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, d = -(double)val; goto neg_fp_res; } - sp[-1] = JS_NewInt32(ctx, -val); + sp[-1] = js_int32(-val); } else if (JS_TAG_IS_FLOAT64(tag)) { d = -JS_VALUE_GET_FLOAT64(op1); neg_fp_res: - sp[-1] = __JS_NewFloat64(ctx, d); + sp[-1] = js_float64(d); } else { + sf->cur_pc = pc; if (js_unary_arith_slow(ctx, sp, opcode)) goto exception; } @@ -18212,9 +17025,10 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, val = JS_VALUE_GET_INT(op1); if (unlikely(val == INT32_MAX)) goto inc_slow; - sp[-1] = JS_NewInt32(ctx, val + 1); + sp[-1] = js_int32(val + 1); } else { inc_slow: + sf->cur_pc = pc; if (js_unary_arith_slow(ctx, sp, opcode)) goto exception; } @@ -18229,9 +17043,10 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, val = JS_VALUE_GET_INT(op1); if (unlikely(val == INT32_MIN)) goto dec_slow; - sp[-1] = JS_NewInt32(ctx, val - 1); + sp[-1] = js_int32(val - 1); } else { dec_slow: + sf->cur_pc = pc; if (js_unary_arith_slow(ctx, sp, opcode)) goto exception; } @@ -18239,6 +17054,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, BREAK; CASE(OP_post_inc): CASE(OP_post_dec): + sf->cur_pc = pc; if (js_post_inc_slow(ctx, sp, opcode)) goto exception; sp++; @@ -18256,12 +17072,13 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, val = JS_VALUE_GET_INT(op1); if (unlikely(val == INT32_MAX)) goto inc_loc_slow; - var_buf[idx] = JS_NewInt32(ctx, val + 1); + var_buf[idx] = js_int32(val + 1); } else { inc_loc_slow: + sf->cur_pc = pc; /* must duplicate otherwise the variable value may be destroyed before JS code accesses it */ - op1 = JS_DupValue(ctx, op1); + op1 = js_dup(op1); if (js_unary_arith_slow(ctx, &op1 + 1, OP_inc)) goto exception; set_value(ctx, &var_buf[idx], op1); @@ -18281,12 +17098,13 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, val = JS_VALUE_GET_INT(op1); if (unlikely(val == INT32_MIN)) goto dec_loc_slow; - var_buf[idx] = JS_NewInt32(ctx, val - 1); + var_buf[idx] = js_int32(val - 1); } else { dec_loc_slow: + sf->cur_pc = pc; /* must duplicate otherwise the variable value may be destroyed before JS code accesses it */ - op1 = JS_DupValue(ctx, op1); + op1 = js_dup(op1); if (js_unary_arith_slow(ctx, &op1 + 1, OP_dec)) goto exception; set_value(ctx, &var_buf[idx], op1); @@ -18298,8 +17116,9 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JSValue op1; op1 = sp[-1]; if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) { - sp[-1] = JS_NewInt32(ctx, ~JS_VALUE_GET_INT(op1)); + sp[-1] = js_int32(~JS_VALUE_GET_INT(op1)); } else { + sf->cur_pc = pc; if (js_not_slow(ctx, sp)) goto exception; } @@ -18314,29 +17133,11 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { uint32_t v1, v2; v1 = JS_VALUE_GET_INT(op1); - v2 = JS_VALUE_GET_INT(op2); -#ifdef CONFIG_BIGNUM - { - int64_t r; - if (unlikely(sf->js_mode & JS_MODE_MATH)) { - if (v2 > 0x1f) - goto shl_slow; - r = (int64_t)v1 << v2; - if ((int)r != r) - goto shl_slow; - } else { - v2 &= 0x1f; - } - } -#else - v2 &= 0x1f; -#endif - sp[-2] = JS_NewInt32(ctx, v1 << v2); + v2 = JS_VALUE_GET_INT(op2) & 0x1f; + sp[-2] = js_int32(v1 << v2); sp--; } else { -#ifdef CONFIG_BIGNUM - shl_slow: -#endif + sf->cur_pc = pc; if (js_binary_logic_slow(ctx, sp, opcode)) goto exception; sp--; @@ -18351,13 +17152,11 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { uint32_t v2; v2 = JS_VALUE_GET_INT(op2); - /* v1 >>> v2 retains its JS semantics if CONFIG_BIGNUM */ v2 &= 0x1f; - sp[-2] = JS_NewUint32(ctx, - (uint32_t)JS_VALUE_GET_INT(op1) >> - v2); + sp[-2] = js_uint32((uint32_t)JS_VALUE_GET_INT(op1) >> v2); sp--; } else { + sf->cur_pc = pc; if (js_shr_slow(ctx, sp)) goto exception; sp--; @@ -18372,23 +17171,13 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { uint32_t v2; v2 = JS_VALUE_GET_INT(op2); -#ifdef CONFIG_BIGNUM if (unlikely(v2 > 0x1f)) { - if (unlikely(sf->js_mode & JS_MODE_MATH)) - goto sar_slow; - else - v2 &= 0x1f; + v2 &= 0x1f; } -#else - v2 &= 0x1f; -#endif - sp[-2] = JS_NewInt32(ctx, - (int)JS_VALUE_GET_INT(op1) >> v2); + sp[-2] = js_int32((int)JS_VALUE_GET_INT(op1) >> v2); sp--; } else { -#ifdef CONFIG_BIGNUM - sar_slow: -#endif + sf->cur_pc = pc; if (js_binary_logic_slow(ctx, sp, opcode)) goto exception; sp--; @@ -18401,11 +17190,10 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, op1 = sp[-2]; op2 = sp[-1]; if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { - sp[-2] = JS_NewInt32(ctx, - JS_VALUE_GET_INT(op1) & - JS_VALUE_GET_INT(op2)); + sp[-2] = js_int32(JS_VALUE_GET_INT(op1) & JS_VALUE_GET_INT(op2)); sp--; } else { + sf->cur_pc = pc; if (js_binary_logic_slow(ctx, sp, opcode)) goto exception; sp--; @@ -18418,11 +17206,10 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, op1 = sp[-2]; op2 = sp[-1]; if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { - sp[-2] = JS_NewInt32(ctx, - JS_VALUE_GET_INT(op1) | - JS_VALUE_GET_INT(op2)); + sp[-2] = js_int32(JS_VALUE_GET_INT(op1) | JS_VALUE_GET_INT(op2)); sp--; } else { + sf->cur_pc = pc; if (js_binary_logic_slow(ctx, sp, opcode)) goto exception; sp--; @@ -18435,11 +17222,10 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, op1 = sp[-2]; op2 = sp[-1]; if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { - sp[-2] = JS_NewInt32(ctx, - JS_VALUE_GET_INT(op1) ^ - JS_VALUE_GET_INT(op2)); + sp[-2] = js_int32(JS_VALUE_GET_INT(op1) ^ JS_VALUE_GET_INT(op2)); sp--; } else { + sf->cur_pc = pc; if (js_binary_logic_slow(ctx, sp, opcode)) goto exception; sp--; @@ -18455,9 +17241,10 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, op1 = sp[-2]; \ op2 = sp[-1]; \ if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { \ - sp[-2] = JS_NewBool(ctx, JS_VALUE_GET_INT(op1) binary_op JS_VALUE_GET_INT(op2)); \ + sp[-2] = js_bool(JS_VALUE_GET_INT(op1) binary_op JS_VALUE_GET_INT(op2)); \ sp--; \ } else { \ + sf->cur_pc = pc; \ if (slow_call) \ goto exception; \ sp--; \ @@ -18474,14 +17261,8 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, OP_CMP(OP_strict_eq, ==, js_strict_eq_slow(ctx, sp, 0)); OP_CMP(OP_strict_neq, !=, js_strict_eq_slow(ctx, sp, 1)); -#ifdef CONFIG_BIGNUM - CASE(OP_mul_pow10): - if (rt->bigfloat_ops.mul_pow10(ctx, sp)) - goto exception; - sp--; - BREAK; -#endif CASE(OP_in): + sf->cur_pc = pc; if (js_operator_in(ctx, sp)) goto exception; sp--; @@ -18492,6 +17273,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, sp--; BREAK; CASE(OP_instanceof): + sf->cur_pc = pc; if (js_operator_instanceof(ctx, sp)) goto exception; sp--; @@ -18508,6 +17290,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, } BREAK; CASE(OP_delete): + sf->cur_pc = pc; if (js_operator_delete(ctx, sp)) goto exception; sp--; @@ -18520,15 +17303,17 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, atom = get_u32(pc); pc += 4; + sf->cur_pc = pc; ret = JS_DeleteProperty(ctx, ctx->global_obj, atom, 0); if (unlikely(ret < 0)) goto exception; - *sp++ = JS_NewBool(ctx, ret); + *sp++ = js_bool(ret); } BREAK; CASE(OP_to_object): if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_OBJECT) { + sf->cur_pc = pc; ret_val = JS_ToObject(ctx, sp[-1]); if (JS_IsException(ret_val)) goto exception; @@ -18544,6 +17329,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, case JS_TAG_SYMBOL: break; default: + sf->cur_pc = pc; ret_val = JS_ToPropertyKey(ctx, sp[-1]); if (JS_IsException(ret_val)) goto exception; @@ -18565,6 +17351,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, case JS_TAG_SYMBOL: break; default: + sf->cur_pc = pc; ret_val = JS_ToPropertyKey(ctx, sp[-1]); if (JS_IsException(ret_val)) goto exception; @@ -18573,17 +17360,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, break; } BREAK; -#if 0 - CASE(OP_to_string): - if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_STRING) { - ret_val = JS_ToString(ctx, sp[-1]); - if (JS_IsException(ret_val)) - goto exception; - JS_FreeValue(ctx, sp[-1]); - sp[-1] = ret_val; - } - BREAK; -#endif CASE(OP_with_get_var): CASE(OP_with_put_var): CASE(OP_with_delete_var): @@ -18599,6 +17375,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, diff = get_u32(pc + 4); is_with = pc[8]; pc += 9; + sf->cur_pc = pc; obj = sp[-1]; ret = JS_HasProperty(ctx, obj, atom); @@ -18621,7 +17398,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, break; case OP_with_put_var: /* XXX: check if strict mode */ - ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2], obj, + ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2], JS_PROP_THROW_STRICT); JS_FreeValue(ctx, sp[-1]); sp -= 2; @@ -18633,7 +17410,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, if (unlikely(ret < 0)) goto exception; JS_FreeValue(ctx, sp[-1]); - sp[-1] = JS_NewBool(ctx, ret); + sp[-1] = js_bool(ret); break; case OP_with_make_ref: /* produce a pair object/propname on the stack */ @@ -18667,20 +17444,18 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, BREAK; CASE(OP_await): - ret_val = JS_NewInt32(ctx, FUNC_RET_AWAIT); + ret_val = js_int32(FUNC_RET_AWAIT); goto done_generator; CASE(OP_yield): - ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD); + ret_val = js_int32(FUNC_RET_YIELD); goto done_generator; CASE(OP_yield_star): CASE(OP_async_yield_star): - ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD_STAR); + ret_val = js_int32(FUNC_RET_YIELD_STAR); goto done_generator; CASE(OP_return_async): - ret_val = JS_UNDEFINED; - goto done_generator; CASE(OP_initial_yield): - ret_val = JS_NewInt32(ctx, FUNC_RET_INITIAL_YIELD); + ret_val = JS_UNDEFINED; goto done_generator; CASE(OP_nop): @@ -18692,7 +17467,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, } else { goto free_and_set_false; } -#if SHORT_OPCODES CASE(OP_is_undefined): if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED) { goto set_true; @@ -18721,7 +17495,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, } free_and_set_true: JS_FreeValue(ctx, sp[-1]); -#endif set_true: sp[-1] = JS_TRUE; BREAK; @@ -18737,20 +17510,8 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, } } exception: - if (JS_IsString(rt->current_exception)) { - JSValue error_obj = JS_NewError(ctx); - JSAtom msgProp = JS_NewAtom(ctx, "message"); - JS_DefinePropertyValue(ctx, error_obj, msgProp, rt->current_exception, 0); - rt->current_exception = error_obj; - JS_FreeAtom(ctx, msgProp); - } - if (is_backtrace_needed(ctx, rt->current_exception)) { - /* add the backtrace information now (it is not done - before if the exception happens in a bytecode - operation */ - sf->cur_pc = pc; - build_backtrace(ctx, rt->current_exception, NULL, 0, 0); - } + sf->cur_pc = pc; + build_backtrace(ctx, rt->current_exception, JS_UNDEFINED, NULL, 0, 0, 0); if (!JS_IsUncatchableError(ctx, rt->current_exception)) { while (sp > stack_buf) { JSValue val = *--sp; @@ -18761,10 +17522,12 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, /* enumerator: close it with a throw */ JS_FreeValue(ctx, sp[-1]); /* drop the next method */ sp--; - JS_IteratorClose(ctx, sp[-1], TRUE); + JS_IteratorClose(ctx, sp[-1], true); } else { *sp++ = rt->current_exception; - rt->current_exception = JS_NULL; + rt->current_exception = JS_UNINITIALIZED; + JS_FreeValueRT(rt, ctx->error_back_trace); + ctx->error_back_trace = JS_UNDEFINED; pc = b->byte_code_buf + pos; goto restart; } @@ -18796,25 +17559,25 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, return ret_val; } -JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, - int argc, JSValueConst *argv) +JSValue JS_Call(JSContext *ctx, JSValue func_obj, JSValue this_obj, + int argc, JSValue *argv) { return JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED, - argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV); + argc, argv, JS_CALL_FLAG_COPY_ARGV); } -static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj, - int argc, JSValueConst *argv) +static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValue this_obj, + int argc, JSValue *argv) { JSValue res = JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED, - argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV); + argc, argv, JS_CALL_FLAG_COPY_ARGV); JS_FreeValue(ctx, func_obj); return res; } /* warning: the refcount of the context is not incremented. Return NULL in case of exception (case of revoked proxy only) */ -static JSContext *JS_GetFunctionRealm(JSContext *ctx, JSValueConst func_obj) +static JSContext *JS_GetFunctionRealm(JSContext *ctx, JSValue func_obj) { JSObject *p; JSContext *realm; @@ -18862,14 +17625,14 @@ static JSContext *JS_GetFunctionRealm(JSContext *ctx, JSValueConst func_obj) return realm; } -static JSValue js_create_from_ctor(JSContext *ctx, JSValueConst ctor, +static JSValue js_create_from_ctor(JSContext *ctx, JSValue ctor, int class_id) { JSValue proto, obj; JSContext *realm; if (JS_IsUndefined(ctor)) { - proto = JS_DupValue(ctx, ctx->class_proto[class_id]); + proto = js_dup(ctx->class_proto[class_id]); } else { proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype); if (JS_IsException(proto)) @@ -18879,7 +17642,7 @@ static JSValue js_create_from_ctor(JSContext *ctx, JSValueConst ctor, realm = JS_GetFunctionRealm(ctx, ctor); if (!realm) return JS_EXCEPTION; - proto = JS_DupValue(ctx, realm->class_proto[class_id]); + proto = js_dup(realm->class_proto[class_id]); } } obj = JS_NewObjectProtoClass(ctx, proto, class_id); @@ -18889,8 +17652,8 @@ static JSValue js_create_from_ctor(JSContext *ctx, JSValueConst ctor, /* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */ static JSValue JS_CallConstructorInternal(JSContext *ctx, - JSValueConst func_obj, - JSValueConst new_target, + JSValue func_obj, + JSValue new_target, int argc, JSValue *argv, int flags) { JSObject *p; @@ -18912,7 +17675,7 @@ static JSValue JS_CallConstructorInternal(JSContext *ctx, return JS_ThrowTypeError(ctx, "not a function"); } return call_func(ctx, func_obj, new_target, argc, - (JSValueConst *)argv, flags); + argv, flags); } b = p->u.func.function_bytecode; @@ -18936,25 +17699,25 @@ static JSValue JS_CallConstructorInternal(JSContext *ctx, } } -JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj, - JSValueConst new_target, - int argc, JSValueConst *argv) +JSValue JS_CallConstructor2(JSContext *ctx, JSValue func_obj, + JSValue new_target, + int argc, JSValue *argv) { return JS_CallConstructorInternal(ctx, func_obj, new_target, - argc, (JSValue *)argv, + argc, argv, JS_CALL_FLAG_COPY_ARGV); } -JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj, - int argc, JSValueConst *argv) +JSValue JS_CallConstructor(JSContext *ctx, JSValue func_obj, + int argc, JSValue *argv) { return JS_CallConstructorInternal(ctx, func_obj, func_obj, - argc, (JSValue *)argv, + argc, argv, JS_CALL_FLAG_COPY_ARGV); } -JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom, - int argc, JSValueConst *argv) +JSValue JS_Invoke(JSContext *ctx, JSValue this_val, JSAtom atom, + int argc, JSValue *argv) { JSValue func_obj; func_obj = JS_GetProperty(ctx, this_val, atom); @@ -18964,7 +17727,7 @@ JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom, } static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom, - int argc, JSValueConst *argv) + int argc, JSValue *argv) { JSValue res = JS_Invoke(ctx, this_val, atom, argc, argv); JS_FreeValue(ctx, this_val); @@ -18972,57 +17735,69 @@ static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom, } /* JSAsyncFunctionState (used by generator and async functions) */ -static JSAsyncFunctionState *async_func_init(JSContext *ctx, - JSValueConst func_obj, JSValueConst this_obj, - int argc, JSValueConst *argv) +static __exception int async_func_init(JSContext *ctx, JSAsyncFunctionState *s, + JSValue func_obj, JSValue this_obj, + int argc, JSValue *argv) { - JSAsyncFunctionState *s; JSObject *p; JSFunctionBytecode *b; JSStackFrame *sf; int local_count, i, arg_buf_len, n; - s = js_mallocz(ctx, sizeof(*s)); - if (!s) - return NULL; - s->header.ref_count = 1; - add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION); - sf = &s->frame; init_list_head(&sf->var_ref_list); p = JS_VALUE_GET_OBJ(func_obj); b = p->u.func.function_bytecode; - sf->js_mode = b->js_mode | JS_MODE_ASYNC; + sf->is_strict_mode = b->is_strict_mode; sf->cur_pc = b->byte_code_buf; arg_buf_len = max_int(b->arg_count, argc); local_count = arg_buf_len + b->var_count + b->stack_size; sf->arg_buf = js_malloc(ctx, sizeof(JSValue) * max_int(local_count, 1)); - if (!sf->arg_buf) { - js_free(ctx, s); - return NULL; - } - sf->cur_func = JS_DupValue(ctx, func_obj); - s->this_val = JS_DupValue(ctx, this_obj); + if (!sf->arg_buf) + return -1; + sf->cur_func = js_dup(func_obj); + s->this_val = js_dup(this_obj); s->argc = argc; sf->arg_count = arg_buf_len; sf->var_buf = sf->arg_buf + arg_buf_len; sf->cur_sp = sf->var_buf + b->var_count; for(i = 0; i < argc; i++) - sf->arg_buf[i] = JS_DupValue(ctx, argv[i]); + sf->arg_buf[i] = js_dup(argv[i]); n = arg_buf_len + b->var_count; for(i = argc; i < n; i++) sf->arg_buf[i] = JS_UNDEFINED; - s->resolving_funcs[0] = JS_UNDEFINED; - s->resolving_funcs[1] = JS_UNDEFINED; - s->is_completed = FALSE; - return s; + return 0; } -static void async_func_free_frame(JSRuntime *rt, JSAsyncFunctionState *s) +static void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s, + JS_MarkFunc *mark_func) { - JSStackFrame *sf = &s->frame; + JSStackFrame *sf; JSValue *sp; + sf = &s->frame; + JS_MarkValue(rt, sf->cur_func, mark_func); + JS_MarkValue(rt, s->this_val, mark_func); + if (sf->cur_sp) { + /* if the function is running, cur_sp is not known so we + cannot mark the stack. Marking the variables is not needed + because a running function cannot be part of a removable + cycle */ + for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) + JS_MarkValue(rt, *sp, mark_func); + } +} + +static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s) +{ + JSStackFrame *sf; + JSValue *sp; + + sf = &s->frame; + + /* close the closure variables. */ + close_var_refs(rt, sf); + if (sf->arg_buf) { /* cannot free the function if it is running */ assert(sf->cur_sp != NULL); @@ -19030,7 +17805,6 @@ static void async_func_free_frame(JSRuntime *rt, JSAsyncFunctionState *s) JS_FreeValueRT(rt, *sp); } js_free_rt(rt, sf->arg_buf); - sf->arg_buf = NULL; } JS_FreeValueRT(rt, sf->cur_func); JS_FreeValueRT(rt, s->this_val); @@ -19038,66 +17812,17 @@ static void async_func_free_frame(JSRuntime *rt, JSAsyncFunctionState *s) static JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s) { - JSRuntime *rt = ctx->rt; - JSStackFrame *sf = &s->frame; - JSValue func_obj, ret; - - assert(!s->is_completed); - if (js_check_stack_overflow(ctx->rt, 0)) { - ret = JS_ThrowStackOverflow(ctx); - } else { - /* the tag does not matter provided it is not an object */ - func_obj = JS_MKPTR(JS_TAG_INT, s); - ret = JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED, - s->argc, sf->arg_buf, JS_CALL_FLAG_GENERATOR); - } - if (JS_IsException(ret) || JS_IsUndefined(ret)) { - if (JS_IsUndefined(ret)) { - ret = sf->cur_sp[-1]; - sf->cur_sp[-1] = JS_UNDEFINED; - } - /* end of execution */ - s->is_completed = TRUE; + JSValue func_obj; - /* close the closure variables. */ - close_var_refs(rt, sf); + if (js_check_stack_overflow(ctx->rt, 0)) + return JS_ThrowStackOverflow(ctx); - async_func_free_frame(rt, s); - } - return ret; + /* the tag does not matter provided it is not an object */ + func_obj = JS_MKPTR(JS_TAG_INT, s); + return JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED, + s->argc, s->frame.arg_buf, JS_CALL_FLAG_GENERATOR); } -static void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s) -{ - /* cannot close the closure variables here because it would - potentially modify the object graph */ - if (!s->is_completed) { - async_func_free_frame(rt, s); - } - - JS_FreeValueRT(rt, s->resolving_funcs[0]); - JS_FreeValueRT(rt, s->resolving_funcs[1]); - - remove_gc_object(&s->header); - if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && s->header.ref_count != 0) { - list_add_tail(&s->header.link, &rt->gc_zero_ref_count_list); - } else { - js_free_rt(rt, s); - } -} - -static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s) -{ - if (--s->header.ref_count == 0) { - if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) { - list_del(&s->header.link); - list_add(&s->header.link, &rt->gc_zero_ref_count_list); - if (rt->gc_phase == JS_GC_PHASE_NONE) { - free_zero_refcount(rt); - } - } - } -} /* Generators */ @@ -19111,17 +17836,14 @@ typedef enum JSGeneratorStateEnum { typedef struct JSGeneratorData { JSGeneratorStateEnum state; - JSAsyncFunctionState *func_state; + JSAsyncFunctionState func_state; } JSGeneratorData; static void free_generator_stack_rt(JSRuntime *rt, JSGeneratorData *s) { if (s->state == JS_GENERATOR_STATE_COMPLETED) return; - if (s->func_state) { - async_func_free(rt, s->func_state); - s->func_state = NULL; - } + async_func_free(rt, &s->func_state); s->state = JS_GENERATOR_STATE_COMPLETED; } @@ -19140,15 +17862,15 @@ static void free_generator_stack(JSContext *ctx, JSGeneratorData *s) free_generator_stack_rt(ctx->rt, s); } -static void js_generator_mark(JSRuntime *rt, JSValueConst val, +static void js_generator_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); JSGeneratorData *s = p->u.generator_data; - if (!s || !s->func_state) + if (!s || s->state == JS_GENERATOR_STATE_COMPLETED) return; - mark_func(rt, &s->func_state->header); + async_func_mark(rt, &s->func_state, mark_func); } /* XXX: use enum */ @@ -19156,21 +17878,21 @@ static void js_generator_mark(JSRuntime *rt, JSValueConst val, #define GEN_MAGIC_RETURN 1 #define GEN_MAGIC_THROW 2 -static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, - BOOL *pdone, int magic) +static JSValue js_generator_next(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, + int *pdone, int magic) { JSGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_GENERATOR); JSStackFrame *sf; JSValue ret, func_ret; - *pdone = TRUE; + *pdone = true; if (!s) return JS_ThrowTypeError(ctx, "not a generator"); + sf = &s->func_state.frame; switch(s->state) { default: case JS_GENERATOR_STATE_SUSPENDED_START: - sf = &s->func_state->frame; if (magic == GEN_MAGIC_NEXT) { goto exec_no_arg; } else { @@ -19180,29 +17902,28 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val, break; case JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR: case JS_GENERATOR_STATE_SUSPENDED_YIELD: - sf = &s->func_state->frame; /* cur_sp[-1] was set to JS_UNDEFINED in the previous call */ - ret = JS_DupValue(ctx, argv[0]); + ret = js_dup(argv[0]); if (magic == GEN_MAGIC_THROW && s->state == JS_GENERATOR_STATE_SUSPENDED_YIELD) { JS_Throw(ctx, ret); - s->func_state->throw_flag = TRUE; + s->func_state.throw_flag = true; } else { sf->cur_sp[-1] = ret; - sf->cur_sp[0] = JS_NewInt32(ctx, magic); + sf->cur_sp[0] = js_int32(magic); sf->cur_sp++; exec_no_arg: - s->func_state->throw_flag = FALSE; + s->func_state.throw_flag = false; } s->state = JS_GENERATOR_STATE_EXECUTING; - func_ret = async_func_resume(ctx, s->func_state); + func_ret = async_func_resume(ctx, &s->func_state); s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD; - if (s->func_state->is_completed) { - /* finalize the execution in case of exception or normal return */ + if (JS_IsException(func_ret)) { + /* finalize the execution in case of exception */ free_generator_stack(ctx, s); return func_ret; - } else { - assert(JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT); + } + 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; @@ -19211,8 +17932,14 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val, /* return (value, done) object */ *pdone = 2; } else { - *pdone = FALSE; + *pdone = false; } + } else { + /* end of iterator */ + ret = sf->cur_sp[-1]; + sf->cur_sp[-1] = JS_UNDEFINED; + JS_FreeValue(ctx, func_ret); + free_generator_stack(ctx, s); } break; case JS_GENERATOR_STATE_COMPLETED: @@ -19224,10 +17951,10 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val, ret = JS_UNDEFINED; break; case GEN_MAGIC_RETURN: - ret = JS_DupValue(ctx, argv[0]); + ret = js_dup(argv[0]); break; case GEN_MAGIC_THROW: - ret = JS_Throw(ctx, JS_DupValue(ctx, argv[0])); + ret = JS_Throw(ctx, js_dup(argv[0])); break; } break; @@ -19238,9 +17965,9 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val, return ret; } -static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_obj, - int argc, JSValueConst *argv, +static JSValue js_generator_function_call(JSContext *ctx, JSValue func_obj, + JSValue this_obj, + int argc, JSValue *argv, int flags) { JSValue obj, func_ret; @@ -19250,14 +17977,13 @@ static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj, if (!s) return JS_EXCEPTION; s->state = JS_GENERATOR_STATE_SUSPENDED_START; - s->func_state = async_func_init(ctx, func_obj, this_obj, argc, argv); - if (!s->func_state) { + if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) { s->state = JS_GENERATOR_STATE_COMPLETED; goto fail; } /* execute the function up to 'OP_initial_yield' */ - func_ret = async_func_resume(ctx, s->func_state); + func_ret = async_func_resume(ctx, &s->func_state); if (JS_IsException(func_ret)) goto fail; JS_FreeValue(ctx, func_ret); @@ -19265,7 +17991,7 @@ static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj, obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_GENERATOR); if (JS_IsException(obj)) goto fail; - JS_SetOpaque(obj, s); + JS_SetOpaqueInternal(obj, s); return obj; fail: free_generator_stack_rt(ctx->rt, s); @@ -19275,27 +18001,51 @@ static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj, /* AsyncFunction */ +static void js_async_function_terminate(JSRuntime *rt, JSAsyncFunctionData *s) +{ + if (s->is_active) { + async_func_free(rt, &s->func_state); + s->is_active = false; + } +} + +static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s) +{ + js_async_function_terminate(rt, s); + JS_FreeValueRT(rt, s->resolving_funcs[0]); + JS_FreeValueRT(rt, s->resolving_funcs[1]); + remove_gc_object(&s->header); + js_free_rt(rt, s); +} + +static void js_async_function_free(JSRuntime *rt, JSAsyncFunctionData *s) +{ + if (--s->header.ref_count == 0) { + js_async_function_free0(rt, s); + } +} + static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val) { JSObject *p = JS_VALUE_GET_OBJ(val); - JSAsyncFunctionState *s = p->u.async_function_data; + JSAsyncFunctionData *s = p->u.async_function_data; if (s) { - async_func_free(rt, s); + js_async_function_free(rt, s); } } -static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val, +static void js_async_function_resolve_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); - JSAsyncFunctionState *s = p->u.async_function_data; + JSAsyncFunctionData *s = p->u.async_function_data; if (s) { mark_func(rt, &s->header); } } static int js_async_function_resolve_create(JSContext *ctx, - JSAsyncFunctionState *s, + JSAsyncFunctionData *s, JSValue *resolving_funcs) { int i; @@ -19317,107 +18067,133 @@ static int js_async_function_resolve_create(JSContext *ctx, return 0; } -static void js_async_function_resume(JSContext *ctx, JSAsyncFunctionState *s) +static bool js_async_function_resume(JSContext *ctx, JSAsyncFunctionData *s) { + bool is_success = true; JSValue func_ret, ret2; - func_ret = async_func_resume(ctx, s); - if (s->is_completed) { - if (JS_IsException(func_ret)) { - JSValue error; - fail: - error = JS_GetException(ctx); - ret2 = JS_Call(ctx, s->resolving_funcs[1], JS_UNDEFINED, - 1, (JSValueConst *)&error); - JS_FreeValue(ctx, error); - JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */ + func_ret = async_func_resume(ctx, &s->func_state); + if (JS_IsException(func_ret)) { + fail: + if (unlikely(JS_IsUncatchableError(ctx, ctx->rt->current_exception))) { + is_success = false; } else { - /* normal return */ - ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED, - 1, (JSValueConst *)&func_ret); - JS_FreeValue(ctx, func_ret); - JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */ + JSValue error = JS_GetException(ctx); + ret2 = JS_Call(ctx, s->resolving_funcs[1], JS_UNDEFINED, 1, &error); + JS_FreeValue(ctx, error); + resolved: + if (unlikely(JS_IsException(ret2))) { + if (JS_IsUncatchableError(ctx, ctx->rt->current_exception)) { + is_success = false; + } else { + abort(); /* BUG */ + } + } + JS_FreeValue(ctx, ret2); } + js_async_function_terminate(ctx->rt, s); } else { - JSValue value, promise, resolving_funcs[2], resolving_funcs1[2]; - int i, res; + JSValue value; + value = s->func_state.frame.cur_sp[-1]; + s->func_state.frame.cur_sp[-1] = JS_UNDEFINED; + if (JS_IsUndefined(func_ret)) { + /* function returned */ + ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED, + 1, &value); + JS_FreeValue(ctx, value); + goto resolved; + } else { + JSValue promise, resolving_funcs[2], resolving_funcs1[2]; + int i, res; - value = s->frame.cur_sp[-1]; - s->frame.cur_sp[-1] = JS_UNDEFINED; + /* await */ + JS_FreeValue(ctx, func_ret); /* not used */ + promise = js_promise_resolve(ctx, ctx->promise_ctor, + 1, &value, 0); + JS_FreeValue(ctx, value); + if (JS_IsException(promise)) + goto fail; + if (js_async_function_resolve_create(ctx, s, resolving_funcs)) { + JS_FreeValue(ctx, promise); + goto fail; + } - /* await */ - JS_FreeValue(ctx, func_ret); /* not used */ - promise = js_promise_resolve(ctx, ctx->promise_ctor, - 1, (JSValueConst *)&value, 0); - JS_FreeValue(ctx, value); - if (JS_IsException(promise)) - goto fail; - if (js_async_function_resolve_create(ctx, s, resolving_funcs)) { + /* Note: no need to create 'thrownawayCapability' as in + the spec */ + for(i = 0; i < 2; i++) + resolving_funcs1[i] = JS_UNDEFINED; + res = perform_promise_then(ctx, promise, + resolving_funcs, + resolving_funcs1); JS_FreeValue(ctx, promise); - goto fail; + for(i = 0; i < 2; i++) + JS_FreeValue(ctx, resolving_funcs[i]); + if (res) + goto fail; } - - /* Note: no need to create 'thrownawayCapability' as in - the spec */ - for(i = 0; i < 2; i++) - resolving_funcs1[i] = JS_UNDEFINED; - res = perform_promise_then(ctx, promise, - (JSValueConst *)resolving_funcs, - (JSValueConst *)resolving_funcs1); - JS_FreeValue(ctx, promise); - for(i = 0; i < 2; i++) - JS_FreeValue(ctx, resolving_funcs[i]); - if (res) - goto fail; } + return is_success; } static JSValue js_async_function_resolve_call(JSContext *ctx, - JSValueConst func_obj, - JSValueConst this_obj, - int argc, JSValueConst *argv, + JSValue func_obj, + JSValue this_obj, + int argc, JSValue *argv, int flags) { JSObject *p = JS_VALUE_GET_OBJ(func_obj); - JSAsyncFunctionState *s = p->u.async_function_data; - BOOL is_reject = p->class_id - JS_CLASS_ASYNC_FUNCTION_RESOLVE; - JSValueConst arg; + JSAsyncFunctionData *s = p->u.async_function_data; + bool is_reject = p->class_id - JS_CLASS_ASYNC_FUNCTION_RESOLVE; + JSValue arg; if (argc > 0) arg = argv[0]; else arg = JS_UNDEFINED; - s->throw_flag = is_reject; + s->func_state.throw_flag = is_reject; if (is_reject) { - JS_Throw(ctx, JS_DupValue(ctx, arg)); + JS_Throw(ctx, js_dup(arg)); } else { /* return value of await */ - s->frame.cur_sp[-1] = JS_DupValue(ctx, arg); + s->func_state.frame.cur_sp[-1] = js_dup(arg); } - js_async_function_resume(ctx, s); + if (!js_async_function_resume(ctx, s)) + return JS_EXCEPTION; return JS_UNDEFINED; } -static JSValue js_async_function_call(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_obj, - int argc, JSValueConst *argv, int flags) +static JSValue js_async_function_call(JSContext *ctx, JSValue func_obj, + JSValue this_obj, + int argc, JSValue *argv, int flags) { JSValue promise; - JSAsyncFunctionState *s; + JSAsyncFunctionData *s; - s = async_func_init(ctx, func_obj, this_obj, argc, argv); + s = js_mallocz(ctx, sizeof(*s)); if (!s) return JS_EXCEPTION; + s->header.ref_count = 1; + add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION); + s->is_active = false; + s->resolving_funcs[0] = JS_UNDEFINED; + s->resolving_funcs[1] = JS_UNDEFINED; promise = JS_NewPromiseCapability(ctx, s->resolving_funcs); - if (JS_IsException(promise)) { - async_func_free(ctx->rt, s); + if (JS_IsException(promise)) + goto fail; + + if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) { + fail: + JS_FreeValue(ctx, promise); + js_async_function_free(ctx->rt, s); return JS_EXCEPTION; } + s->is_active = true; - js_async_function_resume(ctx, s); + if (!js_async_function_resume(ctx, s)) + goto fail; - async_func_free(ctx->rt, s); + js_async_function_free(ctx->rt, s); return promise; } @@ -19446,8 +18222,7 @@ typedef struct JSAsyncGeneratorRequest { typedef struct JSAsyncGeneratorData { JSObject *generator; /* back pointer to the object (const) */ JSAsyncGeneratorStateEnum state; - /* func_state is NULL is state AWAITING_RETURN and COMPLETED */ - JSAsyncFunctionState *func_state; + JSAsyncFunctionState func_state; struct list_head queue; /* list of JSAsyncGeneratorRequest.link */ } JSAsyncGeneratorData; @@ -19465,8 +18240,10 @@ static void js_async_generator_free(JSRuntime *rt, JS_FreeValueRT(rt, req->resolving_funcs[1]); js_free_rt(rt, req); } - if (s->func_state) - async_func_free(rt, s->func_state); + if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED && + s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) { + async_func_free(rt, &s->func_state); + } js_free_rt(rt, s); } @@ -19479,7 +18256,7 @@ static void js_async_generator_finalizer(JSRuntime *rt, JSValue obj) } } -static void js_async_generator_mark(JSRuntime *rt, JSValueConst val, +static void js_async_generator_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) { JSAsyncGeneratorData *s = JS_GetOpaque(val, JS_CLASS_ASYNC_GENERATOR); @@ -19493,21 +18270,22 @@ static void js_async_generator_mark(JSRuntime *rt, JSValueConst val, JS_MarkValue(rt, req->resolving_funcs[0], mark_func); JS_MarkValue(rt, req->resolving_funcs[1], mark_func); } - if (s->func_state) { - mark_func(rt, &s->func_state->header); + if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED && + s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) { + async_func_mark(rt, &s->func_state, mark_func); } } } static JSValue js_async_generator_resolve_function(JSContext *ctx, - JSValueConst this_obj, - int argc, JSValueConst *argv, + JSValue this_obj, + int argc, JSValue *argv, int magic, JSValue *func_data); static int js_async_generator_resolve_function_create(JSContext *ctx, - JSValueConst generator, + JSValue generator, JSValue *resolving_funcs, - BOOL is_resume_next) + bool is_resume_next) { int i; JSValue func; @@ -19527,7 +18305,7 @@ static int js_async_generator_resolve_function_create(JSContext *ctx, static int js_async_generator_await(JSContext *ctx, JSAsyncGeneratorData *s, - JSValueConst value) + JSValue value) { JSValue promise, resolving_funcs[2], resolving_funcs1[2]; int i, res; @@ -19538,7 +18316,7 @@ static int js_async_generator_await(JSContext *ctx, goto fail; if (js_async_generator_resolve_function_create(ctx, JS_MKPTR(JS_TAG_OBJECT, s->generator), - resolving_funcs, FALSE)) { + resolving_funcs, false)) { JS_FreeValue(ctx, promise); goto fail; } @@ -19548,8 +18326,8 @@ static int js_async_generator_await(JSContext *ctx, for(i = 0; i < 2; i++) resolving_funcs1[i] = JS_UNDEFINED; res = perform_promise_then(ctx, promise, - (JSValueConst *)resolving_funcs, - (JSValueConst *)resolving_funcs1); + resolving_funcs, + resolving_funcs1); JS_FreeValue(ctx, promise); for(i = 0; i < 2; i++) JS_FreeValue(ctx, resolving_funcs[i]); @@ -19562,7 +18340,7 @@ static int js_async_generator_await(JSContext *ctx, static void js_async_generator_resolve_or_reject(JSContext *ctx, JSAsyncGeneratorData *s, - JSValueConst result, + JSValue result, int is_reject) { JSAsyncGeneratorRequest *next; @@ -19582,11 +18360,11 @@ static void js_async_generator_resolve_or_reject(JSContext *ctx, static void js_async_generator_resolve(JSContext *ctx, JSAsyncGeneratorData *s, - JSValueConst value, - BOOL done) + JSValue value, + bool done) { JSValue result; - result = js_create_iterator_result(ctx, JS_DupValue(ctx, value), done); + result = js_create_iterator_result(ctx, js_dup(value), done); /* XXX: better exception handling ? */ js_async_generator_resolve_or_reject(ctx, s, result, 0); JS_FreeValue(ctx, result); @@ -19594,7 +18372,7 @@ static void js_async_generator_resolve(JSContext *ctx, static void js_async_generator_reject(JSContext *ctx, JSAsyncGeneratorData *s, - JSValueConst exception) + JSValue exception) { js_async_generator_resolve_or_reject(ctx, s, exception, 1); } @@ -19604,14 +18382,13 @@ static void js_async_generator_complete(JSContext *ctx, { if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED) { s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED; - async_func_free(ctx->rt, s->func_state); - s->func_state = NULL; + async_func_free(ctx->rt, &s->func_state); } } static int js_async_generator_completed_return(JSContext *ctx, JSAsyncGeneratorData *s, - JSValueConst value) + JSValue value) { JSValue promise, resolving_funcs[2], resolving_funcs1[2]; int res; @@ -19623,7 +18400,7 @@ static int js_async_generator_completed_return(JSContext *ctx, // exception should be delivered to the catch handler. if (JS_IsException(promise)) { JSValue err = JS_GetException(ctx); - promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, (JSValueConst *)&err, + promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, &err, /*is_reject*/1); JS_FreeValue(ctx, err); if (JS_IsException(promise)) @@ -19632,15 +18409,15 @@ static int js_async_generator_completed_return(JSContext *ctx, if (js_async_generator_resolve_function_create(ctx, JS_MKPTR(JS_TAG_OBJECT, s->generator), resolving_funcs1, - TRUE)) { + true)) { JS_FreeValue(ctx, promise); return -1; } resolving_funcs[0] = JS_UNDEFINED; resolving_funcs[1] = JS_UNDEFINED; res = perform_promise_then(ctx, promise, - (JSValueConst *)resolving_funcs1, - (JSValueConst *)resolving_funcs); + resolving_funcs1, + resolving_funcs); JS_FreeValue(ctx, resolving_funcs1[0]); JS_FreeValue(ctx, resolving_funcs1[1]); JS_FreeValue(ctx, promise); @@ -19672,7 +18449,7 @@ static void js_async_generator_resume_next(JSContext *ctx, break; case JS_ASYNC_GENERATOR_STATE_COMPLETED: if (next->completion_type == GEN_MAGIC_NEXT) { - js_async_generator_resolve(ctx, s, JS_UNDEFINED, TRUE); + js_async_generator_resolve(ctx, s, JS_UNDEFINED, true); } else if (next->completion_type == GEN_MAGIC_RETURN) { s->state = JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN; js_async_generator_completed_return(ctx, s, next->result); @@ -19682,42 +18459,34 @@ static void js_async_generator_resume_next(JSContext *ctx, goto done; case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD: case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR: - value = JS_DupValue(ctx, next->result); + value = js_dup(next->result); if (next->completion_type == GEN_MAGIC_THROW && s->state == JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD) { JS_Throw(ctx, value); - s->func_state->throw_flag = TRUE; + s->func_state.throw_flag = true; } else { /* 'yield' returns a value. 'yield *' also returns a value in case the 'throw' method is called */ - s->func_state->frame.cur_sp[-1] = value; - s->func_state->frame.cur_sp[0] = - JS_NewInt32(ctx, next->completion_type); - s->func_state->frame.cur_sp++; + s->func_state.frame.cur_sp[-1] = value; + s->func_state.frame.cur_sp[0] = + js_int32(next->completion_type); + s->func_state.frame.cur_sp++; exec_no_arg: - s->func_state->throw_flag = FALSE; + s->func_state.throw_flag = false; } s->state = JS_ASYNC_GENERATOR_STATE_EXECUTING; resume_exec: - func_ret = async_func_resume(ctx, s->func_state); - if (s->func_state->is_completed) { - if (JS_IsException(func_ret)) { - value = JS_GetException(ctx); - js_async_generator_complete(ctx, s); - js_async_generator_reject(ctx, s, value); - JS_FreeValue(ctx, value); - } else { - /* end of function */ - js_async_generator_complete(ctx, s); - js_async_generator_resolve(ctx, s, func_ret, TRUE); - JS_FreeValue(ctx, func_ret); - } - } else { + func_ret = async_func_resume(ctx, &s->func_state); + if (JS_IsException(func_ret)) { + value = JS_GetException(ctx); + js_async_generator_complete(ctx, s); + js_async_generator_reject(ctx, s, value); + JS_FreeValue(ctx, value); + } else if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) { int func_ret_code, ret; - assert(JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT); + value = s->func_state.frame.cur_sp[-1]; + s->func_state.frame.cur_sp[-1] = JS_UNDEFINED; func_ret_code = JS_VALUE_GET_INT(func_ret); - value = s->func_state->frame.cur_sp[-1]; - s->func_state->frame.cur_sp[-1] = JS_UNDEFINED; switch(func_ret_code) { case FUNC_RET_YIELD: case FUNC_RET_YIELD_STAR: @@ -19725,7 +18494,7 @@ static void js_async_generator_resume_next(JSContext *ctx, s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR; else s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD; - js_async_generator_resolve(ctx, s, value, FALSE); + js_async_generator_resolve(ctx, s, value, false); JS_FreeValue(ctx, value); break; case FUNC_RET_AWAIT: @@ -19733,13 +18502,21 @@ static void js_async_generator_resume_next(JSContext *ctx, JS_FreeValue(ctx, value); if (ret < 0) { /* exception: throw it */ - s->func_state->throw_flag = TRUE; + s->func_state.throw_flag = true; goto resume_exec; } goto done; default: abort(); } + } else { + assert(JS_IsUndefined(func_ret)); + /* end of function */ + value = s->func_state.frame.cur_sp[-1]; + s->func_state.frame.cur_sp[-1] = JS_UNDEFINED; + js_async_generator_complete(ctx, s); + js_async_generator_resolve(ctx, s, value, true); + JS_FreeValue(ctx, value); } break; default: @@ -19750,13 +18527,13 @@ static void js_async_generator_resume_next(JSContext *ctx, } static JSValue js_async_generator_resolve_function(JSContext *ctx, - JSValueConst this_obj, - int argc, JSValueConst *argv, + JSValue this_obj, + int argc, JSValue *argv, int magic, JSValue *func_data) { - BOOL is_reject = magic & 1; + bool is_reject = magic & 1; JSAsyncGeneratorData *s = JS_GetOpaque(func_data[0], JS_CLASS_ASYNC_GENERATOR); - JSValueConst arg = argv[0]; + JSValue arg = argv[0]; /* XXX: what if s == NULL */ @@ -19768,17 +18545,17 @@ static JSValue js_async_generator_resolve_function(JSContext *ctx, if (is_reject) { js_async_generator_reject(ctx, s, arg); } else { - js_async_generator_resolve(ctx, s, arg, TRUE); + js_async_generator_resolve(ctx, s, arg, true); } } else { /* restart function execution after await() */ assert(s->state == JS_ASYNC_GENERATOR_STATE_EXECUTING); - s->func_state->throw_flag = is_reject; + s->func_state.throw_flag = is_reject; if (is_reject) { - JS_Throw(ctx, JS_DupValue(ctx, arg)); + JS_Throw(ctx, js_dup(arg)); } else { /* return value of await */ - s->func_state->frame.cur_sp[-1] = JS_DupValue(ctx, arg); + s->func_state.frame.cur_sp[-1] = js_dup(arg); } js_async_generator_resume_next(ctx, s); } @@ -19786,8 +18563,8 @@ static JSValue js_async_generator_resolve_function(JSContext *ctx, } /* magic = GEN_MAGIC_x */ -static JSValue js_async_generator_next(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, +static JSValue js_async_generator_next(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { JSAsyncGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_GENERATOR); @@ -19802,7 +18579,7 @@ static JSValue js_async_generator_next(JSContext *ctx, JSValueConst this_val, JS_ThrowTypeError(ctx, "not an AsyncGenerator object"); err = JS_GetException(ctx); res2 = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, - 1, (JSValueConst *)&err); + 1, &err); JS_FreeValue(ctx, err); JS_FreeValue(ctx, res2); JS_FreeValue(ctx, resolving_funcs[0]); @@ -19813,8 +18590,8 @@ static JSValue js_async_generator_next(JSContext *ctx, JSValueConst this_val, if (!req) goto fail; req->completion_type = magic; - req->result = JS_DupValue(ctx, argv[0]); - req->promise = JS_DupValue(ctx, promise); + req->result = js_dup(argv[0]); + req->promise = js_dup(promise); req->resolving_funcs[0] = resolving_funcs[0]; req->resolving_funcs[1] = resolving_funcs[1]; list_add_tail(&req->link, &s->queue); @@ -19829,9 +18606,9 @@ static JSValue js_async_generator_next(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static JSValue js_async_generator_function_call(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_obj, - int argc, JSValueConst *argv, +static JSValue js_async_generator_function_call(JSContext *ctx, JSValue func_obj, + JSValue this_obj, + int argc, JSValue *argv, int flags) { JSValue obj, func_ret; @@ -19842,12 +18619,14 @@ static JSValue js_async_generator_function_call(JSContext *ctx, JSValueConst fun return JS_EXCEPTION; s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_START; init_list_head(&s->queue); - s->func_state = async_func_init(ctx, func_obj, this_obj, argc, argv); - if (!s->func_state) + if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) { + s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED; goto fail; + } + /* execute the function up to 'OP_initial_yield' (no yield nor await are possible) */ - func_ret = async_func_resume(ctx, s->func_state); + func_ret = async_func_resume(ctx, &s->func_state); if (JS_IsException(func_ret)) goto fail; JS_FreeValue(ctx, func_ret); @@ -19856,7 +18635,7 @@ static JSValue js_async_generator_function_call(JSContext *ctx, JSValueConst fun if (JS_IsException(obj)) goto fail; s->generator = JS_VALUE_GET_OBJ(obj); - JS_SetOpaque(obj, s); + JS_SetOpaqueInternal(obj, s); return obj; fail: js_async_generator_free(ctx->rt, s); @@ -19883,9 +18662,6 @@ enum { TOK_AND_ASSIGN, TOK_XOR_ASSIGN, TOK_OR_ASSIGN, -#ifdef CONFIG_BIGNUM - TOK_MATH_POW_ASSIGN, -#endif TOK_POW_ASSIGN, TOK_LAND_ASSIGN, TOK_LOR_ASSIGN, @@ -19905,9 +18681,6 @@ enum { TOK_STRICT_NEQ, TOK_LAND, TOK_LOR, -#ifdef CONFIG_BIGNUM - TOK_MATH_POW, -#endif TOK_POW, TOK_ARROW, TOK_ELLIPSIS, @@ -19986,7 +18759,8 @@ typedef struct BlockEnv { int drop_count; /* number of stack elements to drop */ int label_finally; /* -1 if none */ int scope_level; - int has_iterator; + uint8_t has_iterator : 1; + uint8_t is_regular_stmt : 1; // i.e. not a loop statement } BlockEnv; typedef struct JSGlobalVar { @@ -20020,10 +18794,11 @@ typedef struct LabelSlot { RelocEntry *first_reloc; } LabelSlot; -typedef struct LineNumberSlot { +typedef struct SourceLocSlot { uint32_t pc; int line_num; -} LineNumberSlot; + int col_num; +} SourceLocSlot; typedef enum JSParseFunctionEnum { JS_PARSE_FUNC_STATEMENT, @@ -20053,35 +18828,36 @@ typedef struct JSFunctionDef { struct list_head child_list; /* list of JSFunctionDef.link */ struct list_head link; - BOOL is_eval; /* TRUE if eval code */ - int eval_type; /* only valid if is_eval = TRUE */ - BOOL is_global_var; /* TRUE if variables are not defined locally: + bool is_eval; /* true if eval code */ + int eval_type; /* only valid if is_eval = true */ + bool is_global_var; /* true if variables are not defined locally: eval global, eval module or non strict eval */ - BOOL is_func_expr; /* TRUE if function expression */ - 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 + bool is_func_expr; /* true if function expression */ + 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 available in the function */ - BOOL has_this_binding; /* true if the 'this' and new.target binding are + bool has_this_binding; /* true if the 'this' and new.target binding are available in the function */ - BOOL new_target_allowed; /* true if the 'new.target' does not + bool new_target_allowed; /* true if the 'new.target' does not throw a syntax error */ - BOOL super_call_allowed; /* true if super() is allowed */ - BOOL super_allowed; /* true if super. or super[] is allowed */ - BOOL arguments_allowed; /* true if the 'arguments' identifier is allowed */ - BOOL is_derived_class_constructor; - BOOL in_function_body; - BOOL backtrace_barrier; + bool super_call_allowed; /* true if super() is allowed */ + bool super_allowed; /* true if super. or super[] is allowed */ + bool arguments_allowed; /* true if the 'arguments' identifier is allowed */ + bool is_derived_class_constructor; + bool in_function_body; + bool backtrace_barrier; JSFunctionKindEnum func_kind : 8; - JSParseFunctionEnum func_type : 8; - uint8_t js_mode; /* bitmap of JS_MODE_x */ + JSParseFunctionEnum func_type : 7; + uint8_t is_strict_mode : 1; JSAtom func_name; /* JS_ATOM_NULL if no name */ JSVarDef *vars; + uint32_t *vars_htab; // indexes into vars[] int var_size; /* allocated size for vars[] */ int var_count; JSVarDef *args; @@ -20100,7 +18876,7 @@ typedef struct JSFunctionDef { int new_target_var_idx; /* variable containg the 'new.target' value, -1 if none */ int this_active_func_var_idx; /* variable containg the 'this.active_func' value, -1 if none */ int home_object_var_idx; - BOOL need_home_object; + bool need_home_object; int scope_level; /* index into fd->scopes if the current lexical scope */ int scope_first; /* index into vd->vars of first lexically scoped variable */ @@ -20116,8 +18892,7 @@ typedef struct JSFunctionDef { DynBuf byte_code; int last_opcode_pos; /* -1 if no last opcode */ - int last_opcode_line_num; - BOOL use_short_opcodes; /* true if short opcodes are used in byte_code */ + bool use_short_opcodes; /* true if short opcodes are used in byte_code */ LabelSlot *label_slots; int label_size; /* allocated size for label_slots[] */ @@ -20138,27 +18913,31 @@ typedef struct JSFunctionDef { int jump_size; int jump_count; - LineNumberSlot *line_number_slots; - int line_number_size; - int line_number_count; + SourceLocSlot *source_loc_slots; + int source_loc_size; + int source_loc_count; int line_number_last; int line_number_last_pc; + int col_number_last; /* pc2line table */ JSAtom filename; int line_num; + int col_num; DynBuf pc2line; char *source; /* raw source, utf-8 encoded */ int source_len; JSModuleDef *module; /* != NULL when parsing a module */ - BOOL has_await; /* TRUE if await is used (used in module eval) */ + bool has_await; /* true if await is used (used in module eval) */ + JSInlineCache *ic; /* inline cache for field op */ } JSFunctionDef; typedef struct JSToken { int val; int line_num; /* line number of token start */ + int col_num; /* column number of token start */ const uint8_t *ptr; union { struct { @@ -20167,14 +18946,11 @@ typedef struct JSToken { } str; struct { JSValue val; -#ifdef CONFIG_BIGNUM - slimb_t exponent; /* may be != 0 only if val is a float */ -#endif } num; struct { JSAtom atom; - BOOL has_escape; - BOOL is_reserved; + bool has_escape; + bool is_reserved; } ident; struct { JSValue body; @@ -20186,23 +18962,27 @@ typedef struct JSToken { typedef struct JSParseState { JSContext *ctx; int last_line_num; /* line number of last token */ + int last_col_num; /* column number of last token */ int line_num; /* line number of current offset */ + int col_num; /* column number of current offset */ const char *filename; JSToken token; - BOOL got_lf; /* true if got line feed before the current token */ + bool got_lf; /* true if got line feed before the current token */ const uint8_t *last_ptr; + const uint8_t *buf_start; const uint8_t *buf_ptr; const uint8_t *buf_end; + const uint8_t *eol; // most recently seen end-of-line character + const uint8_t *mark; // first token character, invariant: eol < mark /* current function code */ JSFunctionDef *cur_func; - BOOL is_module; /* parsing a module */ - BOOL allow_html_comments; - BOOL ext_json; /* true if accepting JSON superset */ + bool is_module; /* parsing a module */ + bool allow_html_comments; } JSParseState; typedef struct JSOpCode { -#ifdef DUMP_BYTECODE +#ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_* const char *name; #endif uint8_t size; /* in bytes */ @@ -20215,7 +18995,7 @@ typedef struct JSOpCode { static const JSOpCode opcode_info[OP_COUNT + (OP_TEMP_END - OP_TEMP_START)] = { #define FMT(f) -#ifdef DUMP_BYTECODE +#ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_* #define DEF(id, size, n_pop, n_push, f) { #id, size, n_pop, n_push, OP_FMT_ ## f }, #else #define DEF(id, size, n_pop, n_push, f) { size, n_pop, n_push, OP_FMT_ ## f }, @@ -20225,7 +19005,6 @@ static const JSOpCode opcode_info[OP_COUNT + (OP_TEMP_END - OP_TEMP_START)] = { #undef FMT }; -#if SHORT_OPCODES /* After the final compilation pass, short opcodes are used. Their opcodes overlap with the temporary opcodes which cannot appear in the final bytecode. Their description is after the temporary @@ -20233,9 +19012,6 @@ static const JSOpCode opcode_info[OP_COUNT + (OP_TEMP_END - OP_TEMP_START)] = { #define short_opcode_info(op) \ opcode_info[(op) >= OP_TEMP_START ? \ (op) + (OP_TEMP_END - OP_TEMP_START) : (op)] -#else -#define short_opcode_info(op) opcode_info[op] -#endif static __exception int next_token(JSParseState *s); @@ -20266,9 +19042,10 @@ static void free_token(JSParseState *s, JSToken *token) } } -static void __maybe_unused dump_token(JSParseState *s, +static void __attribute((unused)) dump_token(JSParseState *s, const JSToken *token) { + printf("%d:%d ", token->line_num, token->col_num); switch(token->val) { case TOK_NUMBER: { @@ -20327,30 +19104,52 @@ static void __maybe_unused dump_token(JSParseState *s, } } -int FORMAT_ATTR(2, 3) js_parse_error(JSParseState *s, const char *fmt, ...) +int JS_PRINTF_FORMAT_ATTR(2, 3) js_parse_error(JSParseState *s, JS_PRINTF_FORMAT const char *fmt, ...) { JSContext *ctx = s->ctx; va_list ap; int backtrace_flags; va_start(ap, fmt); - JS_ThrowError2(ctx, JS_SYNTAX_ERROR, fmt, ap, FALSE); + JS_ThrowError2(ctx, JS_SYNTAX_ERROR, fmt, ap, false); va_end(ap); backtrace_flags = 0; if (s->cur_func && s->cur_func->backtrace_barrier) backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL; - build_backtrace(ctx, ctx->rt->current_exception, s->filename, s->line_num, - backtrace_flags); + build_backtrace(ctx, ctx->rt->current_exception, JS_UNDEFINED, s->filename, + s->line_num, s->col_num, backtrace_flags); return -1; } static int js_parse_expect(JSParseState *s, int tok) { - if (s->token.val != tok) { - /* XXX: dump token correctly in all cases */ - return js_parse_error(s, "expecting '%c'", tok); + char buf[ATOM_GET_STR_BUF_SIZE]; + + if (s->token.val == tok) + return next_token(s); + + switch(s->token.val) { + case TOK_EOF: + return js_parse_error(s, "Unexpected end of input"); + case TOK_NUMBER: + return js_parse_error(s, "Unexpected number"); + case TOK_STRING: + return js_parse_error(s, "Unexpected string"); + case TOK_TEMPLATE: + return js_parse_error(s, "Unexpected string template"); + case TOK_REGEXP: + return js_parse_error(s, "Unexpected regexp"); + case TOK_IDENT: + return js_parse_error(s, "Unexpected identifier '%s'", + JS_AtomGetStr(s->ctx, buf, sizeof(buf), + s->token.u.ident.atom)); + case TOK_ERROR: + return js_parse_error(s, "Invalid or unexpected token"); + default: + return js_parse_error(s, "Unexpected token '%.*s'", + (int)(s->buf_ptr - s->token.ptr), + (const char *)s->token.ptr); } - return next_token(s); } static int js_parse_expect_semi(JSParseState *s) @@ -20373,8 +19172,10 @@ static int js_parse_error_reserved_identifier(JSParseState *s) s->token.u.ident.atom)); } -static __exception int js_parse_template_part(JSParseState *s, const uint8_t *p) +static __exception int js_parse_template_part(JSParseState *s, + const uint8_t *p) { + const uint8_t *p_next; uint32_t c; StringBuffer b_s, *b = &b_s; @@ -20409,10 +19210,11 @@ static __exception int js_parse_template_part(JSParseState *s, const uint8_t *p) } if (c == '\n') { s->line_num++; + s->eol = &p[-1]; + s->mark = p; } else if (c >= 0x80) { - const uint8_t *p_next; - c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next); - if (c > 0x10FFFF) { + c = utf8_decode(p - 1, &p_next); + if (p_next == p) { js_parse_error(s, "invalid UTF-8 sequence"); goto fail; } @@ -20435,9 +19237,10 @@ static __exception int js_parse_template_part(JSParseState *s, const uint8_t *p) } static __exception int js_parse_string(JSParseState *s, int sep, - BOOL do_throw, const uint8_t *p, + bool do_throw, const uint8_t *p, JSToken *token, const uint8_t **pp) { + const uint8_t *p_next; int ret; uint32_t c; StringBuffer b_s, *b = &b_s; @@ -20450,11 +19253,6 @@ static __exception int js_parse_string(JSParseState *s, int sep, goto invalid_char; c = *p; if (c < 0x20) { - if (!s->cur_func) { - if (do_throw) - js_parse_error(s, "invalid character in a JSON string"); - goto fail; - } if (sep == '`') { if (c == '\r') { if (p[1] == '\n') @@ -20475,12 +19273,15 @@ static __exception int js_parse_string(JSParseState *s, int sep, } if (c == '\\') { c = *p; - /* XXX: need a specific JSON case to avoid - accepting invalid escapes */ switch(c) { case '\0': - if (p >= s->buf_end) - goto invalid_char; + if (p >= s->buf_end) { + if (sep != '`') + goto invalid_char; + if (do_throw) + js_parse_error(s, "Unexpected end of input"); + goto fail; + } p++; break; case '\'': @@ -20496,33 +19297,29 @@ static __exception int js_parse_string(JSParseState *s, int sep, case '\n': /* ignore escaped newline sequence */ p++; - if (sep != '`') + if (sep != '`') { s->line_num++; + s->eol = &p[-1]; + s->mark = p; + } continue; default: - if (c >= '0' && c <= '9') { - if (!s->cur_func) - goto invalid_escape; /* JSON case */ - if (!(s->cur_func->js_mode & JS_MODE_STRICT) && sep != '`') - goto parse_escape; - if (c == '0' && !(p[1] >= '0' && p[1] <= '9')) { - p++; - c = '\0'; - } else { - if (c >= '8' || sep == '`') { - /* Note: according to ES2021, \8 and \9 are not - accepted in strict mode or in templates. */ - goto invalid_escape; - } else { - if (do_throw) - js_parse_error(s, "octal escape sequences are not allowed in strict mode"); - } - goto fail; + if (c == '0' && !(p[1] >= '0' && p[1] <= '9')) { + /* accept isolated \0 */ + p++; + c = '\0'; + } else + if ((c >= '0' && c <= '9') + && (s->cur_func->is_strict_mode || sep == '`')) { + if (do_throw) { + js_parse_error(s, "%s are not allowed in %s", + (c >= '8') ? "\\8 and \\9" : "Octal escape sequences", + (sep == '`') ? "template strings" : "strict mode"); } + goto fail; } else if (c >= 0x80) { - const uint8_t *p_next; - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next); - if (c > 0x10FFFF) { + c = utf8_decode(p, &p_next); + if (p_next == p + 1) { goto invalid_utf8; } p = p_next; @@ -20530,12 +19327,12 @@ static __exception int js_parse_string(JSParseState *s, int sep, if (c == CP_LS || c == CP_PS) continue; } else { - parse_escape: - ret = lre_parse_escape(&p, TRUE); + ret = lre_parse_escape(&p, true); if (ret == -1) { - invalid_escape: - if (do_throw) - js_parse_error(s, "malformed escape sequence in string literal"); + if (do_throw) { + js_parse_error(s, "Invalid %s escape sequence", + c == 'u' ? "Unicode" : "hexadecimal"); + } goto fail; } else if (ret < 0) { /* ignore the '\' (could output a warning) */ @@ -20547,9 +19344,8 @@ static __exception int js_parse_string(JSParseState *s, int sep, break; } } else if (c >= 0x80) { - const uint8_t *p_next; - c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next); - if (c > 0x10FFFF) + c = utf8_decode(p - 1, &p_next); + if (p_next == p) goto invalid_utf8; p = p_next; } @@ -20574,22 +19370,22 @@ static __exception int js_parse_string(JSParseState *s, int sep, return -1; } -static inline BOOL token_is_pseudo_keyword(JSParseState *s, JSAtom atom) { +static inline bool token_is_pseudo_keyword(JSParseState *s, JSAtom atom) { return s->token.val == TOK_IDENT && s->token.u.ident.atom == atom && !s->token.u.ident.has_escape; } static __exception int js_parse_regexp(JSParseState *s) { - const uint8_t *p; - BOOL in_class; + const uint8_t *p, *p_next; + bool in_class; StringBuffer b_s, *b = &b_s; StringBuffer b2_s, *b2 = &b2_s; uint32_t c; p = s->buf_ptr; p++; - in_class = FALSE; + in_class = false; if (string_buffer_init(s->ctx, b, 32)) return -1; if (string_buffer_init(s->ctx, b2, 1)) @@ -20607,10 +19403,10 @@ static __exception int js_parse_regexp(JSParseState *s) if (!in_class) break; } else if (c == '[') { - in_class = TRUE; + in_class = true; } else if (c == ']') { /* XXX: incorrect as the first character in a class */ - in_class = FALSE; + in_class = false; } else if (c == '\\') { if (string_buffer_putc8(b, c)) goto fail; @@ -20620,9 +19416,8 @@ static __exception int js_parse_regexp(JSParseState *s) else if (c == '\0' && p >= s->buf_end) goto eof_error; else if (c >= 0x80) { - const uint8_t *p_next; - c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next); - if (c > 0x10FFFF) { + c = utf8_decode(p - 1, &p_next); + if (p_next == p) { goto invalid_utf8; } p = p_next; @@ -20630,9 +19425,8 @@ static __exception int js_parse_regexp(JSParseState *s) goto eol_error; } } else if (c >= 0x80) { - const uint8_t *p_next; - c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next); - if (c > 0x10FFFF) { + c = utf8_decode(p - 1, &p_next); + if (p_next == p) { invalid_utf8: js_parse_error(s, "invalid UTF-8 sequence"); goto fail; @@ -20651,14 +19445,8 @@ static __exception int js_parse_regexp(JSParseState *s) /* flags */ for(;;) { - const uint8_t *p_next = p; - c = *p_next++; - if (c >= 0x80) { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next); - if (c > 0x10FFFF) { - goto invalid_utf8; - } - } + c = utf8_decode(p, &p_next); + /* no need to test for invalid UTF-8, 0xFFFD is not ident_next */ if (!lre_js_is_ident_next(c)) break; if (string_buffer_putc(b2, c)) @@ -20678,7 +19466,7 @@ static __exception int js_parse_regexp(JSParseState *s) } static __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize, - const char *static_buf) + char *static_buf) { char *buf, *new_buf; size_t size, new_size; @@ -20709,7 +19497,7 @@ static void update_token_ident(JSParseState *s) { if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD || (s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD && - (s->cur_func->js_mode & JS_MODE_STRICT)) || + s->cur_func->is_strict_mode) || (s->token.u.ident.atom == JS_ATOM_yield && ((s->cur_func->func_kind & JS_FUNC_GENERATOR) || (s->cur_func->func_type == JS_PARSE_FUNC_ARROW && @@ -20724,7 +19512,7 @@ static void update_token_ident(JSParseState *s) ((s->cur_func->parent->func_kind & JS_FUNC_ASYNC) || s->cur_func->parent->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))))) { if (s->token.u.ident.has_escape) { - s->token.u.ident.is_reserved = TRUE; + s->token.u.ident.is_reserved = true; s->token.val = TOK_IDENT; } else { /* The keywords atoms are pre allocated */ @@ -20741,19 +19529,19 @@ static void reparse_ident_token(JSParseState *s) (s->token.val >= TOK_FIRST_KEYWORD && s->token.val <= TOK_LAST_KEYWORD)) { s->token.val = TOK_IDENT; - s->token.u.ident.is_reserved = FALSE; + s->token.u.ident.is_reserved = false; update_token_ident(s); } } /* 'c' is the first character. Return JS_ATOM_NULL in case of error */ static JSAtom parse_ident(JSParseState *s, const uint8_t **pp, - BOOL *pident_has_escape, int c, BOOL is_private) + bool *pident_has_escape, int c, bool is_private) { - const uint8_t *p, *p1; + const uint8_t *p, *p_next; char ident_buf[128], *buf; size_t ident_size, ident_pos; - JSAtom atom; + JSAtom atom = JS_ATOM_NULL; p = *pp; buf = ident_buf; @@ -20762,30 +19550,29 @@ static JSAtom parse_ident(JSParseState *s, const uint8_t **pp, if (is_private) buf[ident_pos++] = '#'; for(;;) { - p1 = p; - - if (c < 128) { + if (c < 0x80) { buf[ident_pos++] = c; } else { - ident_pos += unicode_to_utf8((uint8_t*)buf + ident_pos, c); + ident_pos += utf8_encode((uint8_t*)buf + ident_pos, c); } - c = *p1++; - if (c == '\\' && *p1 == 'u') { - c = lre_parse_escape(&p1, TRUE); - *pident_has_escape = TRUE; - } else if (c >= 128) { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1); + c = *p; + p_next = p + 1; + if (c == '\\' && *p_next == 'u') { + c = lre_parse_escape(&p_next, true); + *pident_has_escape = true; + } else if (c >= 0x80) { + c = utf8_decode(p, &p_next); + /* no need to test for invalid UTF-8, 0xFFFD is not ident_next */ } if (!lre_js_is_ident_next(c)) break; - p = p1; + p = p_next; if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) { - if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) { - atom = JS_ATOM_NULL; + if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) goto done; - } } } + /* buf is pure ASCII or UTF-8 encoded */ atom = JS_NewAtomLen(s->ctx, buf, ident_pos); done: if (unlikely(buf != ident_buf)) @@ -20797,22 +19584,26 @@ static JSAtom parse_ident(JSParseState *s, const uint8_t **pp, static __exception int next_token(JSParseState *s) { - const uint8_t *p; + const uint8_t *p, *p_next; int c; - BOOL ident_has_escape; + bool ident_has_escape; JSAtom atom; + int flags, radix; - if (js_check_stack_overflow(s->ctx->rt, 0)) { - return js_parse_error(s, "stack overflow"); + if (js_check_stack_overflow(s->ctx->rt, 1000)) { + JS_ThrowStackOverflow(s->ctx); + return -1; } free_token(s, &s->token); p = s->last_ptr = s->buf_ptr; - s->got_lf = FALSE; + s->got_lf = false; s->last_line_num = s->token.line_num; + s->last_col_num = s->token.col_num; redo: s->token.line_num = s->line_num; + s->token.col_num = s->col_num; s->token.ptr = p; c = *p; switch(c) { @@ -20830,7 +19621,7 @@ static __exception int next_token(JSParseState *s) break; case '\'': case '\"': - if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p)) + if (js_parse_string(s, c, true, p + 1, &s->token, &p)) goto fail; break; case '\r': /* accept DOS and MAC newline sequences */ @@ -20841,14 +19632,16 @@ static __exception int next_token(JSParseState *s) case '\n': p++; line_terminator: - s->got_lf = TRUE; + s->eol = &p[-1]; + s->mark = p; + s->got_lf = true; s->line_num++; goto redo; case '\f': case '\v': case ' ': case '\t': - p++; + s->mark = ++p; goto redo; case '/': if (p[1] == '*') { @@ -20865,22 +19658,23 @@ static __exception int next_token(JSParseState *s) } if (*p == '\n') { s->line_num++; - s->got_lf = TRUE; /* considered as LF for ASI */ - p++; + s->got_lf = true; /* considered as LF for ASI */ + s->eol = p++; + s->mark = p; } else if (*p == '\r') { - s->got_lf = TRUE; /* considered as LF for ASI */ + s->got_lf = true; /* considered as LF for ASI */ p++; } else if (*p >= 0x80) { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); + c = utf8_decode(p, &p); + /* ignore invalid UTF-8 in comments */ if (c == CP_LS || c == CP_PS) { - s->got_lf = TRUE; /* considered as LF for ASI */ - } else if (c == -1) { - p++; /* skip invalid UTF-8 */ + s->got_lf = true; /* considered as LF for ASI */ } } else { p++; } } + s->mark = p; goto redo; } else if (p[1] == '/') { /* line comment */ @@ -20892,17 +19686,17 @@ static __exception int next_token(JSParseState *s) if (*p == '\r' || *p == '\n') break; if (*p >= 0x80) { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); + c = utf8_decode(p, &p); + /* ignore invalid UTF-8 in comments */ /* LS or PS are considered as line terminator */ if (c == CP_LS || c == CP_PS) { break; - } else if (c == -1) { - p++; /* skip invalid UTF-8 */ } } else { p++; } } + s->mark = p; goto redo; } else if (p[1] == '=') { p += 2; @@ -20915,11 +19709,11 @@ static __exception int next_token(JSParseState *s) case '\\': if (p[1] == 'u') { const uint8_t *p1 = p + 1; - int c1 = lre_parse_escape(&p1, TRUE); + int c1 = lre_parse_escape(&p1, true); if (c1 >= 0 && lre_js_is_ident_first(c1)) { c = c1; p = p1; - ident_has_escape = TRUE; + ident_has_escape = true; goto has_ident; } else { /* XXX: syntax error? */ @@ -20943,37 +19737,39 @@ static __exception int next_token(JSParseState *s) case '_': case '$': /* identifier */ + s->mark = p; p++; - ident_has_escape = FALSE; + ident_has_escape = false; has_ident: - atom = parse_ident(s, &p, &ident_has_escape, c, FALSE); + atom = parse_ident(s, &p, &ident_has_escape, c, false); if (atom == JS_ATOM_NULL) goto fail; s->token.u.ident.atom = atom; s->token.u.ident.has_escape = ident_has_escape; - s->token.u.ident.is_reserved = FALSE; + s->token.u.ident.is_reserved = false; s->token.val = TOK_IDENT; update_token_ident(s); break; case '#': /* private name */ { - const uint8_t *p1; p++; - p1 = p; - c = *p1++; - if (c == '\\' && *p1 == 'u') { - c = lre_parse_escape(&p1, TRUE); - } else if (c >= 128) { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1); + c = *p; + p_next = p + 1; + if (c == '\\' && *p_next == 'u') { + c = lre_parse_escape(&p_next, true); + } else if (c >= 0x80) { + c = utf8_decode(p, &p_next); + if (p_next == p + 1) + goto invalid_utf8; } if (!lre_js_is_ident_first(c)) { js_parse_error(s, "invalid first character of private name"); goto fail; } - p = p1; - ident_has_escape = FALSE; /* not used */ - atom = parse_ident(s, &p, &ident_has_escape, c, TRUE); + p = p_next; + ident_has_escape = false; /* not used */ + atom = parse_ident(s, &p, &ident_has_escape, c, true); if (atom == JS_ATOM_NULL) goto fail; s->token.u.ident.atom = atom; @@ -20987,51 +19783,56 @@ static __exception int next_token(JSParseState *s) break; } if (p[1] >= '0' && p[1] <= '9') { + flags = ATOD_ACCEPT_UNDERSCORES | ATOD_ACCEPT_FLOAT; + radix = 10; goto parse_number; - } else { - goto def_token; } - break; + goto def_token; case '0': - /* in strict mode, octal literals are not accepted */ - if (is_digit(p[1]) && (s->cur_func->js_mode & JS_MODE_STRICT)) { - js_parse_error(s, "octal literals are deprecated in strict mode"); + if (is_digit(p[1])) { /* handle legacy octal */ + if (s->cur_func->is_strict_mode) { + js_parse_error(s, "Octal literals are not allowed in strict mode"); + goto fail; + } + /* Legacy octal: no separators, no suffix, no floats, + base 8 unless non octal digits are detected */ + flags = 0; + radix = 8; + while (is_digit(*p)) { + if (*p >= '8' && *p <= '9') + radix = 10; + p++; + } + p = s->token.ptr; + goto parse_number; + } + if (p[1] == '_') { + js_parse_error(s, "Numeric separator can not be used after leading 0"); goto fail; } + flags = ATOD_ACCEPT_HEX_PREFIX | ATOD_ACCEPT_BIN_OCT | + ATOD_ACCEPT_FLOAT | ATOD_ACCEPT_UNDERSCORES | ATOD_ACCEPT_SUFFIX; + radix = 10; goto parse_number; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* number */ - parse_number: { JSValue ret; - const uint8_t *p1; - int flags, radix; - flags = ATOD_ACCEPT_BIN_OCT | ATOD_ACCEPT_LEGACY_OCTAL | - ATOD_ACCEPT_UNDERSCORES; - flags |= ATOD_ACCEPT_SUFFIX; -#ifdef CONFIG_BIGNUM - if (s->cur_func->js_mode & JS_MODE_MATH) { - flags |= ATOD_MODE_BIGINT; - if (s->cur_func->js_mode & JS_MODE_MATH) - flags |= ATOD_TYPE_BIG_FLOAT; - } -#endif - radix = 0; -#ifdef CONFIG_BIGNUM - s->token.u.num.exponent = 0; - ret = js_atof2(s->ctx, (const char *)p, (const char **)&p, radix, - flags, &s->token.u.num.exponent); -#else - ret = js_atof(s->ctx, (const char *)p, (const char **)&p, radix, - flags); -#endif + const char *p1; + + flags = ATOD_ACCEPT_FLOAT | ATOD_ACCEPT_UNDERSCORES | ATOD_ACCEPT_SUFFIX; + radix = 10; + parse_number: + p1 = (const char *)p; + ret = js_atof(s->ctx, p1, s->buf_end - p, &p1, radix, flags); + p = (const uint8_t *)p1; if (JS_IsException(ret)) goto fail; /* reject `10instanceof Number` */ if (JS_VALUE_IS_NAN(ret) || - lre_js_is_ident_next(unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1))) { + lre_js_is_ident_next(utf8_decode(p, &p_next))) { JS_FreeValue(s->ctx, ret); js_parse_error(s, "invalid number literal"); goto fail; @@ -21080,8 +19881,8 @@ static __exception int next_token(JSParseState *s) p += 2; s->token.val = TOK_MINUS_ASSIGN; } else if (p[1] == '-') { - if (s->allow_html_comments && - p[2] == '>' && s->last_line_num != s->line_num) { + if (s->allow_html_comments && p[2] == '>' && + (s->got_lf || s->last_ptr == s->buf_start)) { /* Annex B: `-->` at beginning of line is an html comment end. It extends to the end of the line. */ @@ -21182,33 +19983,6 @@ static __exception int next_token(JSParseState *s) goto def_token; } break; -#ifdef CONFIG_BIGNUM - /* in math mode, '^' is the power operator. '^^' is always the - xor operator and '**' is always the power operator */ - case '^': - if (p[1] == '=') { - p += 2; - if (s->cur_func->js_mode & JS_MODE_MATH) - s->token.val = TOK_MATH_POW_ASSIGN; - else - s->token.val = TOK_XOR_ASSIGN; - } else if (p[1] == '^') { - if (p[2] == '=') { - p += 3; - s->token.val = TOK_XOR_ASSIGN; - } else { - p += 2; - s->token.val = '^'; - } - } else { - p++; - if (s->cur_func->js_mode & JS_MODE_MATH) - s->token.val = TOK_MATH_POW; - else - s->token.val = '^'; - } - break; -#else case '^': if (p[1] == '=') { p += 2; @@ -21217,7 +19991,6 @@ static __exception int next_token(JSParseState *s) goto def_token; } break; -#endif case '|': if (p[1] == '=') { p += 2; @@ -21251,9 +20024,11 @@ static __exception int next_token(JSParseState *s) } break; default: - if (c >= 128) { - /* unicode value */ - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); + if (c >= 0x80) { /* non-ASCII code-point */ + c = utf8_decode(p, &p_next); + if (p_next == p + 1) + goto invalid_utf8; + p = p_next; switch(c) { case CP_PS: case CP_LS: @@ -21262,9 +20037,10 @@ static __exception int next_token(JSParseState *s) goto line_terminator; default: if (lre_is_space(c)) { + s->mark = p; goto redo; } else if (lre_js_is_ident_first(c)) { - ident_has_escape = FALSE; + ident_has_escape = false; goto has_ident; } else { js_parse_error(s, "unexpected character"); @@ -21277,16 +20053,150 @@ static __exception int next_token(JSParseState *s) p++; break; } + s->token.col_num = max_int(1, s->mark - s->eol); s->buf_ptr = p; // dump_token(s, &s->token); return 0; + invalid_utf8: + js_parse_error(s, "invalid UTF-8 sequence"); fail: s->token.val = TOK_ERROR; return -1; } +static int json_parse_error(JSParseState *s, const uint8_t *curp, const char *msg) +{ + const uint8_t *p, *line_start; + int position = curp - s->buf_start; + int line = 1; + for (line_start = p = s->buf_start; p < curp; p++) { + /* column count does not account for TABs nor wide characters */ + if (*p == '\r' || *p == '\n') { + p += 1 + (p[0] == '\r' && p[1] == '\n'); + line++; + line_start = p; + } + } + return js_parse_error(s, "%s in JSON at position %d (line %d column %d)", + msg, position, line, (int)(p - line_start) + 1); +} + +static int json_parse_string(JSParseState *s, const uint8_t **pp) +{ + const uint8_t *p, *p_next; + int i; + uint32_t c; + StringBuffer b_s, *b = &b_s; + + if (string_buffer_init(s->ctx, b, 32)) + goto fail; + + p = *pp; + for(;;) { + if (p >= s->buf_end) { + goto end_of_input; + } + c = *p++; + if (c == '"') + break; + if (c < 0x20) { + json_parse_error(s, p - 1, "Bad control character in string literal"); + goto fail; + } + if (c == '\\') { + c = *p++; + switch(c) { + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case '\"': break; + case '\\': break; + case '/': break; /* for v8 compatibility */ + case 'u': + c = 0; + for(i = 0; i < 4; i++) { + int h = from_hex(*p++); + if (h < 0) { + json_parse_error(s, p - 1, "Bad Unicode escape"); + goto fail; + } + c = (c << 4) | h; + } + break; + default: + if (p > s->buf_end) + goto end_of_input; + json_parse_error(s, p - 1, "Bad escaped character"); + goto fail; + } + } else + if (c >= 0x80) { + c = utf8_decode(p - 1, &p_next); + if (p_next == p) { + json_parse_error(s, p - 1, "Bad UTF-8 sequence"); + goto fail; + } + p = p_next; + } + if (string_buffer_putc(b, c)) + goto fail; + } + s->token.val = TOK_STRING; + s->token.u.str.sep = '"'; + s->token.u.str.str = string_buffer_end(b); + *pp = p; + return 0; + + end_of_input: + js_parse_error(s, "Unexpected end of JSON input"); + fail: + string_buffer_free(b); + return -1; +} + +static int json_parse_number(JSParseState *s, const uint8_t **pp) +{ + const uint8_t *p = *pp; + const uint8_t *p_start = p; + + if (*p == '+' || *p == '-') + p++; + + if (!is_digit(*p)) + return js_parse_error(s, "Unexpected token '%c'", *p_start); + + if (p[0] == '0' && is_digit(p[1])) + return json_parse_error(s, p, "Unexpected number"); + + while (is_digit(*p)) + p++; + + if (*p == '.') { + p++; + if (!is_digit(*p)) + return json_parse_error(s, p, "Unterminated fractional number"); + while (is_digit(*p)) + p++; + } + if (*p == 'e' || *p == 'E') { + p++; + if (*p == '+' || *p == '-') + p++; + if (!is_digit(*p)) + return json_parse_error(s, p, "Exponent part is missing a number"); + while (is_digit(*p)) + p++; + } + s->token.val = TOK_NUMBER; + s->token.u.num.val = js_float64(safe_strtod((const char *)p_start, NULL)); + *pp = p; + return 0; +} + /* 'c' is the first character. Return JS_ATOM_NULL in case of error */ static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c) { @@ -21302,7 +20212,8 @@ static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c) for(;;) { buf[ident_pos++] = c; c = *p; - if (c >= 128 || !lre_is_id_continue_byte(c)) + if (c >= 128 || + !((lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1)) break; p++; if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) { @@ -21312,6 +20223,7 @@ static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c) } } } + /* buf contains pure ASCII */ atom = JS_NewAtomLen(s->ctx, buf, ident_pos); done: if (unlikely(buf != ident_buf)) @@ -21322,20 +20234,23 @@ static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c) static __exception int json_next_token(JSParseState *s) { - const uint8_t *p; + const uint8_t *p, *p_next; int c; JSAtom atom; - if (js_check_stack_overflow(s->ctx->rt, 0)) { - return js_parse_error(s, "stack overflow"); + if (js_check_stack_overflow(s->ctx->rt, 1000)) { + JS_ThrowStackOverflow(s->ctx); + return -1; } free_token(s, &s->token); p = s->last_ptr = s->buf_ptr; s->last_line_num = s->token.line_num; + s->last_col_num = s->token.col_num; redo: s->token.line_num = s->line_num; + s->token.col_num = s->col_num; s->token.ptr = p; c = *p; switch(c) { @@ -21347,13 +20262,11 @@ static __exception int json_next_token(JSParseState *s) } break; case '\'': - if (!s->ext_json) { - /* JSON does not accept single quoted strings */ - goto def_token; - } - /* fall through */ + /* JSON does not accept single quoted strings */ + goto def_token; case '\"': - if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p)) + p++; + if (json_parse_string(s, &p)) goto fail; break; case '\r': /* accept DOS and MAC newline sequences */ @@ -21362,77 +20275,22 @@ static __exception int json_next_token(JSParseState *s) } /* fall thru */ case '\n': - p++; s->line_num++; + s->eol = p++; + s->mark = p; goto redo; case '\f': case '\v': - if (!s->ext_json) { - /* JSONWhitespace does not match , nor */ - goto def_token; - } - /* fall through */ + /* JSONWhitespace does not match , nor */ + goto def_token; case ' ': case '\t': p++; + s->mark = p; goto redo; case '/': - if (!s->ext_json) { - /* JSON does not accept comments */ - goto def_token; - } - if (p[1] == '*') { - /* comment */ - p += 2; - for(;;) { - if (*p == '\0' && p >= s->buf_end) { - js_parse_error(s, "unexpected end of comment"); - goto fail; - } - if (p[0] == '*' && p[1] == '/') { - p += 2; - break; - } - if (*p == '\n') { - s->line_num++; - p++; - } else if (*p == '\r') { - p++; - } else if (*p >= 0x80) { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); - if (c == -1) { - p++; /* skip invalid UTF-8 */ - } - } else { - p++; - } - } - goto redo; - } else if (p[1] == '/') { - /* line comment */ - p += 2; - for(;;) { - if (*p == '\0' && p >= s->buf_end) - break; - if (*p == '\r' || *p == '\n') - break; - if (*p >= 0x80) { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); - /* LS or PS are considered as line terminator */ - if (c == CP_LS || c == CP_PS) { - break; - } else if (c == -1) { - p++; /* skip invalid UTF-8 */ - } - } else { - p++; - } - } - goto redo; - } else { - goto def_token; - } - break; + /* JSON does not accept comments */ + goto def_token; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': @@ -21455,48 +20313,41 @@ static __exception int json_next_token(JSParseState *s) if (atom == JS_ATOM_NULL) goto fail; s->token.u.ident.atom = atom; - s->token.u.ident.has_escape = FALSE; - s->token.u.ident.is_reserved = FALSE; + s->token.u.ident.has_escape = false; + s->token.u.ident.is_reserved = false; s->token.val = TOK_IDENT; break; - case '+': - if (!s->ext_json || !is_digit(p[1])) - goto def_token; + case '-': + if (!is_digit(p[1])) { + json_parse_error(s, p, "No number after minus sign"); + goto fail; + } goto parse_number; case '0': - if (is_digit(p[1])) - goto def_token; - goto parse_number; - case '-': - if (!is_digit(p[1])) - goto def_token; + if (is_digit(p[1])) { + json_parse_error(s, p, "Unexpected number"); + goto fail; + } goto parse_number; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* number */ parse_number: - { - JSValue ret; - int flags, radix; - if (!s->ext_json) { - flags = 0; - radix = 10; - } else { - flags = ATOD_ACCEPT_BIN_OCT; - radix = 0; - } - ret = js_atof(s->ctx, (const char *)p, (const char **)&p, radix, - flags); - if (JS_IsException(ret)) - goto fail; - s->token.val = TOK_NUMBER; - s->token.u.num.val = ret; - } + if (json_parse_number(s, &p)) + goto fail; break; default: - if (c >= 128) { - js_parse_error(s, "unexpected character"); + if (c >= 0x80) { + c = utf8_decode(p, &p_next); + if (p_next == p + 1) { + js_parse_error(s, "Unexpected token '\\x%02x' in JSON", *p); + } else { + if (c > 0xFFFF) { + c = get_hi_surrogate(c); + } + js_parse_error(s, "Unexpected token '\\u%04x' in JSON", c); + } goto fail; } def_token: @@ -21504,6 +20355,7 @@ static __exception int json_next_token(JSParseState *s) p++; break; } + s->token.col_num = s->mark - s->eol; s->buf_ptr = p; // dump_token(s, &s->token); @@ -21514,30 +20366,10 @@ static __exception int json_next_token(JSParseState *s) return -1; } -static int match_identifier(const uint8_t *p, const char *s) { - uint32_t c; - while (*s) { - if ((uint8_t)*s++ != *p++) - return 0; - } - c = *p; - if (c >= 128) - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); - return !lre_js_is_ident_next(c); -} - -/* simple_next_token() is used to check for the next token in simple cases. - It is only used for ':' and '=>', 'let' or 'function' look-ahead. - (*pp) is only set if TOK_IMPORT is returned for JS_DetectModule() - Whitespace and comments are skipped correctly. - Then the next token is analyzed, only for specific words. - Return values: - - '\n' if !no_line_terminator - - TOK_ARROW, TOK_IN, TOK_IMPORT, TOK_OF, TOK_EXPORT, TOK_FUNCTION - - TOK_IDENT is returned for other identifiers and keywords - - otherwise the next character or unicode codepoint is returned. - */ -static int simple_next_token(const uint8_t **pp, BOOL no_line_terminator) +/* only used for ':' and '=>', 'let' or 'function' look-ahead. *pp is + only set if TOK_IMPORT is returned */ +/* XXX: handle all unicode cases */ +static int simple_next_token(const uint8_t **pp, bool no_line_terminator) { const uint8_t *p; uint32_t c; @@ -21580,49 +20412,43 @@ static int simple_next_token(const uint8_t **pp, BOOL no_line_terminator) if (*p == '>') return TOK_ARROW; break; - case 'i': - if (match_identifier(p, "n")) - return TOK_IN; - if (match_identifier(p, "mport")) { - *pp = p + 5; - return TOK_IMPORT; - } - return TOK_IDENT; - case 'o': - if (match_identifier(p, "f")) - return TOK_OF; - return TOK_IDENT; - case 'e': - if (match_identifier(p, "xport")) - return TOK_EXPORT; - return TOK_IDENT; - case 'f': - if (match_identifier(p, "unction")) - return TOK_FUNCTION; - return TOK_IDENT; - case '\\': - if (*p == 'u') { - if (lre_js_is_ident_first(lre_parse_escape(&p, TRUE))) - return TOK_IDENT; - } - break; default: - if (c >= 128) { - c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p); - if (no_line_terminator && (c == CP_PS || c == CP_LS)) - return '\n'; - } - if (lre_is_space(c)) - continue; - if (lre_js_is_ident_first(c)) + if (lre_js_is_ident_first(c)) { + if (c == 'i') { + if (p[0] == 'n' && !lre_js_is_ident_next(p[1])) { + return TOK_IN; + } + if (p[0] == 'm' && p[1] == 'p' && p[2] == 'o' && + p[3] == 'r' && p[4] == 't' && + !lre_js_is_ident_next(p[5])) { + *pp = p + 5; + return TOK_IMPORT; + } + } else if (c == 'o' && *p == 'f' && !lre_js_is_ident_next(p[1])) { + return TOK_OF; + } else if (c == 'e' && + p[0] == 'x' && p[1] == 'p' && p[2] == 'o' && + p[3] == 'r' && p[4] == 't' && + !lre_js_is_ident_next(p[5])) { + *pp = p + 5; + return TOK_EXPORT; + } else if (c == 'f' && p[0] == 'u' && p[1] == 'n' && + p[2] == 'c' && p[3] == 't' && p[4] == 'i' && + p[5] == 'o' && p[6] == 'n' && !lre_js_is_ident_next(p[7])) { + return TOK_FUNCTION; + } else if (c == 'a' && p[0] == 'w' && p[1] == 'a' && + p[2] == 'i' && p[3] == 't' && !lre_js_is_ident_next(p[4])) { + return TOK_AWAIT; + } return TOK_IDENT; + } break; } return c; } } -static int peek_token(JSParseState *s, BOOL no_line_terminator) +static int peek_token(JSParseState *s, bool no_line_terminator) { const uint8_t *p = s->buf_ptr; return simple_next_token(&p, no_line_terminator); @@ -21639,12 +20465,10 @@ static void skip_shebang(const uint8_t **pp, const uint8_t *buf_end) if (*p == '\n' || *p == '\r') { break; } else if (*p >= 0x80) { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); - if (c == CP_LS || c == CP_PS) { + c = utf8_decode(p, &p); + /* purposely ignore UTF-8 encoding errors in this comment line */ + if (c == CP_LS || c == CP_PS) break; - } else if (c == -1) { - p++; /* skip invalid UTF-8 */ - } } else { p++; } @@ -21653,29 +20477,6 @@ static void skip_shebang(const uint8_t **pp, const uint8_t *buf_end) } } -/* return true if 'input' contains the source of a module - (heuristic). 'input' must be a zero terminated. - - Heuristic: skip comments and expect 'import' keyword not followed - by '(' or '.' or export keyword. -*/ -BOOL JS_DetectModule(const char *input, size_t input_len) -{ - const uint8_t *p = (const uint8_t *)input; - int tok; - - skip_shebang(&p, p + input_len); - switch(simple_next_token(&p, FALSE)) { - case TOK_IMPORT: - tok = simple_next_token(&p, FALSE); - return (tok != '.' && tok != '('); - case TOK_EXPORT: - return TRUE; - default: - return FALSE; - } -} - static inline int get_prev_opcode(JSFunctionDef *fd) { if (fd->last_opcode_pos < 0) return OP_invalid; @@ -21683,7 +20484,7 @@ static inline int get_prev_opcode(JSFunctionDef *fd) { return fd->byte_code.buf[fd->last_opcode_pos]; } -static BOOL js_is_live_code(JSParseState *s) { +static bool js_is_live_code(JSParseState *s) { switch (get_prev_opcode(s->cur_func)) { case OP_tail_call: case OP_tail_call_method: @@ -21693,14 +20494,12 @@ static BOOL js_is_live_code(JSParseState *s) { case OP_throw: case OP_throw_error: case OP_goto: -#if SHORT_OPCODES case OP_goto8: case OP_goto16: -#endif case OP_ret: - return FALSE; + return false; default: - return TRUE; + return true; } } @@ -21719,19 +20518,21 @@ static void emit_u32(JSParseState *s, uint32_t val) dbuf_put_u32(&s->cur_func->byte_code, val); } +static void emit_source_loc(JSParseState *s) +{ + JSFunctionDef *fd = s->cur_func; + DynBuf *bc = &fd->byte_code; + + dbuf_putc(bc, OP_source_loc); + dbuf_put_u32(bc, s->token.line_num); + dbuf_put_u32(bc, s->token.col_num); +} + static void emit_op(JSParseState *s, uint8_t val) { JSFunctionDef *fd = s->cur_func; DynBuf *bc = &fd->byte_code; - /* Use the line number of the last token used, not the next token, - nor the current offset in the source file. - */ - if (unlikely(fd->last_opcode_line_num != s->last_line_num)) { - dbuf_putc(bc, OP_line_num); - dbuf_put_u32(bc, s->last_line_num); - fd->last_opcode_line_num = s->last_line_num; - } fd->last_opcode_pos = bc->size; dbuf_putc(bc, val); } @@ -21741,6 +20542,36 @@ static void emit_atom(JSParseState *s, JSAtom name) emit_u32(s, JS_DupAtom(s->ctx, name)); } +static force_inline uint32_t get_index_hash(JSAtom atom, int hash_bits) +{ + return (atom * 0x9e370001) >> (32 - hash_bits); +} + +static void emit_ic(JSParseState *s, JSAtom atom) +{ + uint32_t h; + JSContext *ctx; + JSInlineCache *ic; + JSInlineCacheHashSlot *ch; + + ic = s->cur_func->ic; + ctx = s->ctx; + if (ic->count + 1 >= ic->capacity && resize_ic_hash(ctx, ic)) + return; + h = get_index_hash(atom, ic->hash_bits); + for (ch = ic->hash[h]; ch != NULL; ch = ch->next) + if (ch->atom == atom) + return; + ch = js_malloc(ctx, sizeof(*ch)); + if (unlikely(!ch)) + return; + ch->atom = JS_DupAtom(ctx, atom); + ch->index = 0; + ch->next = ic->hash[h]; + ic->hash[h] = ch; + ic->count += 1; +} + static int update_label(JSFunctionDef *s, int label, int delta) { LabelSlot *ls; @@ -21824,8 +20655,8 @@ static int cpool_add(JSParseState *s, JSValue val) return fd->cpool_count - 1; } -static __exception int emit_push_const(JSParseState *s, JSValueConst val, - BOOL as_atom) +static __exception int emit_push_const(JSParseState *s, JSValue val, + bool as_atom) { int idx; @@ -21849,6 +20680,86 @@ static __exception int emit_push_const(JSParseState *s, JSValueConst val, return 0; } +// perl hash; variation of k&r hash with a different magic multiplier +// and a final shuffle to improve distribution of the low-order bits +static uint32_t hash_bytes(uint32_t h, const void *b, size_t n) +{ + const char *p; + + for (p = b; p < (char *)b + n; p++) + h = 33*h + *p; + h += h >> 5; + return h; +} + +static uint32_t hash_atom(JSAtom atom) +{ + return hash_bytes(0, &atom, sizeof(atom)); +} + +// caveat emptor: the table size must be a power of two in order for +// masking to work, and the load factor constant must be an odd number (5) +// +// f(n)=n+n/t is used to estimate the load factor but changing t to an +// even number introduces gaps in the output of f, sometimes "jumping" +// over the next power of two; it's at powers of two when the hash table +// must be resized +static int update_var_htab(JSContext *ctx, JSFunctionDef *fd) +{ + uint32_t i, j, k, m, *p; + + if (fd->var_count < 27) // 27 + 27/5 == 32 + return 0; + k = fd->var_count - 1; + m = fd->var_count + fd->var_count/5; + if (m & (m - 1)) // unless power of two + goto insert; + m *= 2; + p = js_realloc(ctx, fd->vars_htab, m * sizeof(*fd->vars_htab)); + if (!p) + return -1; + for (i = 0; i < m; i++) + p[i] = UINT32_MAX; + fd->vars_htab = p; + k = 0; + m--; +insert: + m = UINT32_MAX >> clz32(m); + do { + i = hash_atom(fd->vars[k].var_name); + j = 1; + for (;;) { + p = &fd->vars_htab[i & m]; + if (*p == UINT32_MAX) + break; + i += j; + j += 1; // quadratic probing + } + *p = k++; + } while (k < (uint32_t)fd->var_count); + return 0; +} + +static int find_var_htab(JSFunctionDef *fd, JSAtom var_name) +{ + uint32_t i, j, m, *p; + + i = hash_atom(var_name); + j = 1; + m = fd->var_count + fd->var_count/5; + m = UINT32_MAX >> clz32(m); + for (;;) { + p = &fd->vars_htab[i & m]; + if (*p == UINT32_MAX) + return -1; + if (fd->vars[*p].var_name == var_name) + return *p; + i += j; + j += 1; // quadratic probing + } + return -1; // pacify compiler +} + /* return the variable index or -1 if not found, add ARGUMENT_VAR_OFFSET for argument variables */ static int find_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name) @@ -21863,11 +20774,24 @@ static int find_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name) static int find_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name) { + JSVarDef *vd; int i; - for(i = fd->var_count; i-- > 0;) { - if (fd->vars[i].var_name == name && fd->vars[i].scope_level == 0) + + if (fd->vars_htab) { + i = find_var_htab(fd, name); + if (i == -1) + goto not_found; + vd = &fd->vars[i]; + if (fd->vars[i].scope_level == 0) return i; } + for(i = fd->var_count; i-- > 0;) { + vd = &fd->vars[i]; + if (vd->var_name == name) + if (vd->scope_level == 0) + return i; + } +not_found: return find_arg(ctx, fd, name); } @@ -21888,15 +20812,15 @@ static int find_var_in_scope(JSContext *ctx, JSFunctionDef *fd, /* return true if scope == parent_scope or if scope is a child of parent_scope */ -static BOOL is_child_scope(JSContext *ctx, JSFunctionDef *fd, +static bool is_child_scope(JSContext *ctx, JSFunctionDef *fd, int scope, int parent_scope) { while (scope >= 0) { if (scope == parent_scope) - return TRUE; + return true; scope = fd->scopes[scope].parent; } - return FALSE; + return false; } /* find a 'var' declaration in the same scope or a child scope */ @@ -21938,7 +20862,7 @@ static JSGlobalVar *find_lexical_global_var(JSFunctionDef *fd, JSAtom name) } static int find_lexical_decl(JSContext *ctx, JSFunctionDef *fd, JSAtom name, - int scope_idx, BOOL check_catch_var) + int scope_idx, bool check_catch_var) { while (scope_idx >= 0) { JSVarDef *vd = &fd->vars[scope_idx]; @@ -22030,7 +20954,9 @@ static int add_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name) /* the local variable indexes are currently stored on 16 bits */ if (fd->var_count >= JS_MAX_LOCAL_VARS) { - JS_ThrowInternalError(ctx, "too many local variables"); + // XXX: add_var() should take JSParseState *s and use js_parse_error + JS_ThrowSyntaxError(ctx, "too many variables declared (only %d allowed)", + JS_MAX_LOCAL_VARS - 1); return -1; } if (js_resize_array(ctx, (void **)&fd->vars, sizeof(fd->vars[0]), @@ -22040,6 +20966,8 @@ static int add_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name) memset(vd, 0, sizeof(*vd)); vd->var_name = JS_DupAtom(ctx, name); vd->func_pool_idx = -1; + if (update_var_htab(ctx, fd)) + return -1; return fd->var_count - 1; } @@ -22064,8 +20992,8 @@ static int add_func_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name) if (idx < 0 && (idx = add_var(ctx, fd, name)) >= 0) { fd->func_var_idx = idx; fd->vars[idx].var_kind = JS_VAR_FUNCTION_NAME; - if (fd->js_mode & JS_MODE_STRICT) - fd->vars[idx].is_const = TRUE; + if (fd->is_strict_mode) + fd->vars[idx].is_const = true; } return idx; } @@ -22096,7 +21024,7 @@ static int add_arguments_arg(JSContext *ctx, JSFunctionDef *fd) 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->vars[idx].is_lexical = true; fd->arguments_arg_idx = idx; } @@ -22110,7 +21038,9 @@ static int add_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name) /* the local variable indexes are currently stored on 16 bits */ if (fd->arg_count >= JS_MAX_LOCAL_VARS) { - JS_ThrowInternalError(ctx, "too many arguments"); + // XXX: add_arg() should take JSParseState *s and use js_parse_error + JS_ThrowSyntaxError(ctx, "too many parameters in function definition (only %d allowed)", + JS_MAX_LOCAL_VARS - 1); return -1; } if (js_resize_array(ctx, (void **)&fd->args, sizeof(fd->args[0]), @@ -22135,9 +21065,9 @@ static JSGlobalVar *add_global_var(JSContext *ctx, JSFunctionDef *s, return NULL; 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->force_init = false; + hf->is_lexical = false; + hf->is_const = false; hf->scope_level = s->scope_level; hf->var_name = JS_DupAtom(ctx, name); return hf; @@ -22169,13 +21099,13 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name, case JS_VAR_DEF_CONST: case JS_VAR_DEF_FUNCTION_DECL: case JS_VAR_DEF_NEW_FUNCTION_DECL: - idx = find_lexical_decl(ctx, fd, name, fd->scope_first, TRUE); + idx = find_lexical_decl(ctx, fd, name, fd->scope_first, true); if (idx >= 0) { if (idx < GLOBAL_VAR_OFFSET) { if (fd->vars[idx].scope_level == fd->scope_level) { /* same scope: in non strict mode, functions can be redefined (annex B.3.3.4). */ - if (!(!(fd->js_mode & JS_MODE_STRICT) && + if (!(!fd->is_strict_mode && var_def_type == JS_VAR_DEF_FUNCTION_DECL && fd->vars[idx].var_kind == JS_VAR_FUNCTION_DECL)) { goto redef_lex_error; @@ -22220,7 +21150,7 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name, hf = add_global_var(s->ctx, fd, name); if (!hf) return -1; - hf->is_lexical = TRUE; + hf->is_lexical = true; hf->is_const = (var_def_type == JS_VAR_DEF_CONST); idx = GLOBAL_VAR_OFFSET; } else { @@ -22246,7 +21176,7 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name, case JS_VAR_DEF_VAR: if (find_lexical_decl(ctx, fd, name, fd->scope_first, - FALSE) >= 0) { + false) >= 0) { invalid_lexical_redefinition: /* error to redefine a var that inside a lexical scope */ return js_parse_error(s, "invalid redefinition of lexical identifier"); @@ -22283,7 +21213,7 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name, /* add a private field variable in the current scope */ static int add_private_class_field(JSParseState *s, JSFunctionDef *fd, - JSAtom name, JSVarKindEnum var_kind, BOOL is_static) + JSAtom name, JSVarKindEnum var_kind, bool is_static) { JSContext *ctx = s->ctx; JSVarDef *vd; @@ -22304,7 +21234,7 @@ static __exception int js_parse_function_decl(JSParseState *s, JSParseFunctionEnum func_type, JSFunctionKindEnum func_kind, JSAtom func_name, const uint8_t *ptr, - int start_line); + int start_line, int start_col); static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s); static __exception int js_parse_function_decl2(JSParseState *s, JSParseFunctionEnum func_type, @@ -22312,6 +21242,7 @@ static __exception int js_parse_function_decl2(JSParseState *s, JSAtom func_name, const uint8_t *ptr, int function_line_num, + int function_col_num, JSParseExportEnum export_flag, JSFunctionDef **pfd); static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags); @@ -22327,7 +21258,7 @@ static JSExportEntry *add_export_entry(JSParseState *s, JSModuleDef *m, JSExportTypeEnum export_type); /* Note: all the fields are already sealed except length */ -static int seal_template_obj(JSContext *ctx, JSValueConst obj) +static int seal_template_obj(JSContext *ctx, JSValue obj) { JSObject *p; JSShapeProperty *prs; @@ -22339,7 +21270,7 @@ static int seal_template_obj(JSContext *ctx, JSValueConst obj) prs->flags & ~(JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE))) return -1; } - p->extensible = FALSE; + p->extensible = false; return 0; } @@ -22378,14 +21309,14 @@ static __exception int js_parse_template(JSParseState *s, int call, int *argc) cooked = s->token; if (call) { if (JS_DefinePropertyValueUint32(ctx, raw_array, depth, - JS_DupValue(ctx, s->token.u.str.str), + js_dup(s->token.u.str.str), JS_PROP_ENUMERABLE | JS_PROP_THROW) < 0) { return -1; } /* re-parse the string with escape sequences but do not throw a syntax error if it contains invalid sequences */ - if (js_parse_string(s, '`', FALSE, p, &cooked, &p)) { + if (js_parse_string(s, '`', false, p, &cooked, &p)) { cooked.u.str.str = JS_UNDEFINED; } if (JS_DefinePropertyValueUint32(ctx, template_object, depth, @@ -22400,7 +21331,7 @@ static __exception int js_parse_template(JSParseState *s, int call, int *argc) */ JS_FreeValue(ctx, s->token.u.str.str); s->token.u.str.str = JS_UNDEFINED; - if (js_parse_string(s, '`', TRUE, p, &cooked, &p)) + if (js_parse_string(s, '`', true, p, &cooked, &p)) return -1; str = JS_VALUE_GET_STRING(cooked.u.str.str); if (str->len != 0 || depth == 0) { @@ -22413,6 +21344,7 @@ static __exception int js_parse_template(JSParseState *s, int call, int *argc) goto done1; emit_op(s, OP_get_field2); emit_atom(s, JS_ATOM_concat); + emit_ic(s, JS_ATOM_concat); } depth++; } else { @@ -22433,8 +21365,9 @@ static __exception int js_parse_template(JSParseState *s, int call, int *argc) free_token(s, &s->token); /* Resume TOK_TEMPLATE parsing (s->token.line_num and * s->token.ptr are OK) */ - s->got_lf = FALSE; + s->got_lf = false; s->last_line_num = s->token.line_num; + s->last_col_num = s->token.col_num; if (js_parse_template_part(s, s->buf_ptr)) return -1; } @@ -22465,7 +21398,7 @@ static __exception int js_parse_template(JSParseState *s, int call, int *argc) #define PROP_TYPE_PRIVATE (1 << 4) -static BOOL token_is_ident(int tok) +static bool token_is_ident(int tok) { /* Accept keywords and reserved words as property names */ return (tok == TOK_IDENT || @@ -22476,11 +21409,11 @@ static BOOL token_is_ident(int tok) /* if the property is an expression, name = JS_ATOM_NULL */ static int __exception js_parse_property_name(JSParseState *s, JSAtom *pname, - BOOL allow_method, BOOL allow_var, - BOOL allow_private) + bool allow_method, bool allow_var, + bool allow_private) { int is_private = 0; - BOOL is_non_reserved_ident; + bool is_non_reserved_ident; JSAtom name; int prop_type; @@ -22494,8 +21427,8 @@ static int __exception js_parse_property_name(JSParseState *s, goto fail1; if (s->token.val == ':' || s->token.val == ',' || s->token.val == '}' || s->token.val == '(' || - s->token.val == '=') { - is_non_reserved_ident = TRUE; + s->token.val == '=' || s->token.val == ';') { + is_non_reserved_ident = true; goto ident_found; } prop_type = PROP_TYPE_GET + (name == JS_ATOM_set); @@ -22505,14 +21438,14 @@ static int __exception js_parse_property_name(JSParseState *s, goto fail; prop_type = PROP_TYPE_STAR; } else if (token_is_pseudo_keyword(s, JS_ATOM_async) && - peek_token(s, TRUE) != '\n') { + peek_token(s, true) != '\n') { name = JS_DupAtom(s->ctx, s->token.u.ident.atom); if (next_token(s)) goto fail1; if (s->token.val == ':' || s->token.val == ',' || s->token.val == '}' || s->token.val == '(' || - s->token.val == '=') { - is_non_reserved_ident = TRUE; + s->token.val == '=' || s->token.val == ';') { + is_non_reserved_ident = true; goto ident_found; } JS_FreeAtom(s->ctx, name); @@ -22551,21 +21484,7 @@ static int __exception js_parse_property_name(JSParseState *s, } else if (s->token.val == TOK_NUMBER) { JSValue val; val = s->token.u.num.val; -#ifdef CONFIG_BIGNUM - if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) { - JSBigFloat *p = JS_VALUE_GET_PTR(val); - val = s->ctx->rt->bigfloat_ops. - mul_pow10_to_float64(s->ctx, &p->num, - s->token.u.num.exponent); - if (JS_IsException(val)) - goto fail; - name = JS_ValueToAtom(s->ctx, val); - JS_FreeValue(s->ctx, val); - } else -#endif - { - name = JS_ValueToAtom(s->ctx, val); - } + name = JS_ValueToAtom(s->ctx, val); if (name == JS_ATOM_NULL) goto fail; if (next_token(s)) @@ -22604,16 +21523,24 @@ static int __exception js_parse_property_name(JSParseState *s, typedef struct JSParsePos { int last_line_num; + int last_col_num; int line_num; - BOOL got_lf; + int col_num; + bool got_lf; const uint8_t *ptr; + const uint8_t *eol; + const uint8_t *mark; } JSParsePos; static int js_parse_get_pos(JSParseState *s, JSParsePos *sp) { sp->last_line_num = s->last_line_num; + sp->last_col_num = s->last_col_num; sp->line_num = s->token.line_num; + sp->col_num = s->token.col_num; sp->ptr = s->token.ptr; + sp->eol = s->eol; + sp->mark = s->mark; sp->got_lf = s->got_lf; return 0; } @@ -22621,14 +21548,18 @@ static int js_parse_get_pos(JSParseState *s, JSParsePos *sp) static __exception int js_parse_seek_token(JSParseState *s, const JSParsePos *sp) { s->token.line_num = sp->last_line_num; + s->token.col_num = sp->last_col_num; s->line_num = sp->line_num; + s->col_num = sp->col_num; s->buf_ptr = sp->ptr; + s->eol = sp->eol; + s->mark = sp->mark; s->got_lf = sp->got_lf; return next_token(s); } -/* return TRUE if a regexp literal is allowed after this token */ -static BOOL is_regexp_allowed(int tok) +/* return true if a regexp literal is allowed after this token */ +static bool is_regexp_allowed(int tok) { switch (tok) { case TOK_NUMBER: @@ -22644,9 +21575,9 @@ static BOOL is_regexp_allowed(int tok) case ']': case '}': /* XXX: regexp may occur after */ case TOK_IDENT: - return FALSE; + return false; default: - return TRUE; + return true; } } @@ -22657,14 +21588,13 @@ static BOOL is_regexp_allowed(int tok) /* XXX: improve speed with early bailout */ /* XXX: no longer works if regexps are present. Could use previous regexp parsing heuristics to handle most cases */ -static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_terminator) +static int js_parse_skip_parens_token(JSParseState *s, int *pbits, bool no_line_terminator) { char state[256]; size_t level = 0; JSParsePos pos; int last_tok, tok = TOK_EOF; - int tok_len, bits = 0; - char c; + int c, tok_len, bits = 0; /* protect from underflow */ state[level++] = 0; @@ -22695,8 +21625,9 @@ static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_ free_token(s, &s->token); /* Resume TOK_TEMPLATE parsing (s->token.line_num and * s->token.ptr are OK) */ - s->got_lf = FALSE; + s->got_lf = false; s->last_line_num = s->token.line_num; + s->last_col_num = s->token.col_num; if (js_parse_template_part(s, s->buf_ptr)) goto done; goto handle_template; @@ -22828,18 +21759,19 @@ static __exception int js_parse_object_literal(JSParseState *s) { JSAtom name = JS_ATOM_NULL; const uint8_t *start_ptr; - int start_line, prop_type; - BOOL has_proto; + int start_line, start_col, prop_type; + bool has_proto; if (next_token(s)) goto fail; /* XXX: add an initial length that will be patched back */ emit_op(s, OP_object); - has_proto = FALSE; + has_proto = false; while (s->token.val != '}') { /* specific case for getter/setter */ start_ptr = s->token.ptr; start_line = s->token.line_num; + start_col = s->token.col_num; if (s->token.val == TOK_ELLIPSIS) { if (next_token(s)) @@ -22854,7 +21786,7 @@ static __exception int js_parse_object_literal(JSParseState *s) goto next; } - prop_type = js_parse_property_name(s, &name, TRUE, TRUE, FALSE); + prop_type = js_parse_property_name(s, &name, true, true, false); if (prop_type < 0) goto fail; @@ -22866,7 +21798,7 @@ static __exception int js_parse_object_literal(JSParseState *s) emit_op(s, OP_define_field); emit_atom(s, name); } else if (s->token.val == '(') { - BOOL is_getset = (prop_type == PROP_TYPE_GET || + bool is_getset = (prop_type == PROP_TYPE_GET || prop_type == PROP_TYPE_SET); JSParseFunctionEnum func_type; JSFunctionKindEnum func_kind; @@ -22885,7 +21817,7 @@ static __exception int js_parse_object_literal(JSParseState *s) func_kind = JS_FUNC_ASYNC_GENERATOR; } if (js_parse_function_decl(s, func_type, func_kind, JS_ATOM_NULL, - start_ptr, start_line)) + start_ptr, start_line, start_col)) goto fail; if (name == JS_ATOM_NULL) { emit_op(s, OP_define_method_computed); @@ -22915,7 +21847,7 @@ static __exception int js_parse_object_literal(JSParseState *s) goto fail; } emit_op(s, OP_set_proto); - has_proto = TRUE; + has_proto = true; } else { set_object_name(s, name); emit_op(s, OP_define_field); @@ -22954,41 +21886,6 @@ static __exception int js_parse_left_hand_side_expr(JSParseState *s) return js_parse_postfix_expr(s, PF_POSTFIX_CALL); } -/* XXX: could generate specific bytecode */ -static __exception int js_parse_class_default_ctor(JSParseState *s, - BOOL has_super, - JSFunctionDef **pfd) -{ - JSParsePos pos; - const char *str; - int ret, line_num; - JSParseFunctionEnum func_type; - const uint8_t *saved_buf_end; - - js_parse_get_pos(s, &pos); - if (has_super) { - /* spec change: no argument evaluation */ - str = "(){super(...arguments);}"; - func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR; - } else { - str = "(){}"; - func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR; - } - line_num = s->token.line_num; - saved_buf_end = s->buf_end; - s->buf_ptr = (uint8_t *)str; - s->buf_end = (uint8_t *)(str + strlen(str)); - ret = next_token(s); - if (!ret) { - ret = js_parse_function_decl2(s, func_type, JS_FUNC_NORMAL, - JS_ATOM_NULL, (uint8_t *)str, - line_num, JS_PARSE_EXPORT_NONE, pfd); - } - s->buf_end = saved_buf_end; - ret |= js_parse_seek_token(s, &pos); - return ret; -} - /* find field in the current scope */ static int find_private_class_field(JSContext *ctx, JSFunctionDef *fd, JSAtom name, int scope_level) @@ -23042,9 +21939,9 @@ static JSAtom get_private_setter_name(JSContext *ctx, JSAtom name) typedef struct { JSFunctionDef *fields_init_fd; int computed_fields_count; - BOOL need_brand; + bool need_brand; int brand_push_pos; - BOOL is_static; + bool is_static; } ClassFieldsDef; static __exception int emit_class_init_start(JSParseState *s, @@ -23097,8 +21994,74 @@ static void emit_class_init_end(JSParseState *s, ClassFieldsDef *cf) emit_op(s, OP_set_home_object); } +static void emit_return(JSParseState *s, bool hasval); + +static JSFunctionDef *js_new_function_def(JSContext *ctx, + JSFunctionDef *parent, + bool is_eval, + bool is_func_expr, + const char *filename, + int line_num, + int col_num); + +static __exception int js_parse_class_default_ctor(JSParseState *s, + bool has_super, + JSFunctionDef **pfd) +{ + JSParseFunctionEnum func_type; + JSFunctionDef *fd = s->cur_func; + + fd = js_new_function_def(s->ctx, fd, false, false, s->filename, + s->token.line_num, s->token.col_num); + if (!fd) + return -1; + + s->cur_func = fd; + fd->has_home_object = true; + fd->super_allowed = true; + fd->has_prototype = false; + fd->has_this_binding = true; + fd->new_target_allowed = true; + + push_scope(s); /* enter body scope */ + fd->body_scope = fd->scope_level; + if (has_super) { + fd->is_derived_class_constructor = true; + fd->super_call_allowed = true; + fd->arguments_allowed = true; + fd->has_arguments_binding = true; + func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR; + emit_op(s, OP_init_ctor); + // TODO(bnoordhuis) roll into OP_init_ctor + emit_op(s, OP_scope_put_var_init); + emit_atom(s, JS_ATOM_this); + emit_u16(s, 0); + emit_class_field_init(s); + } else { + func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR; + /* error if not invoked as a constructor */ + emit_op(s, OP_check_ctor); + emit_class_field_init(s); + } + + fd->func_kind = JS_FUNC_NORMAL; + fd->func_type = func_type; + emit_return(s, false); + + s->cur_func = fd->parent; + if (pfd) + *pfd = fd; + + int idx; + /* the real object will be set at the end of the compilation */ + idx = cpool_add(s, JS_NULL); + fd->parent_cpool_idx = idx; + + return 0; +} + -static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, +static __exception int js_parse_class(JSParseState *s, bool is_class_expr, JSParseExportEnum export_flag) { JSContext *ctx = s->ctx; @@ -23106,16 +22069,16 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, JSAtom name = JS_ATOM_NULL, class_name = JS_ATOM_NULL, class_name1; JSAtom class_var_name = JS_ATOM_NULL; JSFunctionDef *method_fd, *ctor_fd; - int saved_js_mode, class_name_var_idx, prop_type, ctor_cpool_offset; + int class_name_var_idx, prop_type, ctor_cpool_offset; int class_flags = 0, i, define_class_offset; - BOOL is_static, is_private; + bool is_static, is_private, is_strict_mode; const uint8_t *class_start_ptr = s->token.ptr; const uint8_t *start_ptr; ClassFieldsDef class_fields[2]; /* classes are parsed and executed in strict mode */ - saved_js_mode = fd->js_mode; - fd->js_mode |= JS_MODE_STRICT; + is_strict_mode = fd->is_strict_mode; + fd->is_strict_mode = true; if (next_token(s)) goto fail; if (s->token.val == TOK_IDENT) { @@ -23185,7 +22148,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, ClassFieldsDef *cf = &class_fields[i]; cf->fields_init_fd = NULL; cf->computed_fields_count = 0; - cf->need_brand = FALSE; + cf->need_brand = false; cf->is_static = i; } @@ -23196,11 +22159,11 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, goto fail; continue; } - is_static = FALSE; + is_static = false; if (s->token.val == TOK_STATIC) { - int next = peek_token(s, TRUE); + int next = peek_token(s, true); if (!(next == ';' || next == '}' || next == '(' || next == '=')) - is_static = TRUE; + is_static = true; } prop_type = -1; if (is_static) { @@ -23208,19 +22171,17 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, goto fail; if (s->token.val == '{') { ClassFieldsDef *cf = &class_fields[is_static]; - JSFunctionDef *init; - if (!cf->fields_init_fd) { + if (!cf->fields_init_fd) if (emit_class_init_start(s, cf)) goto fail; - } s->cur_func = cf->fields_init_fd; - /* XXX: could try to avoid creating a new function and - reuse 'fields_init_fd' with a specific 'var' - scope */ // stack is now: + JSFunctionDef *init; if (js_parse_function_decl2(s, JS_PARSE_FUNC_CLASS_STATIC_INIT, JS_FUNC_NORMAL, JS_ATOM_NULL, - s->token.ptr, s->token.line_num, + s->token.ptr, + s->token.line_num, + s->token.col_num, JS_PARSE_EXPORT_NONE, &init) < 0) { goto fail; } @@ -23230,6 +22191,13 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, emit_atom(s, JS_ATOM_this); emit_u16(s, 0); // stack is now: fclosure this + if (class_name != JS_ATOM_NULL) { + // TODO(bnoordhuis) pass as argument to init method? + emit_op(s, OP_dup); + emit_op(s, OP_scope_put_var_init); + emit_atom(s, class_name); + emit_u16(s, s->cur_func->scope_level); + } emit_op(s, OP_swap); // stack is now: this fclosure emit_op(s, OP_call_method); @@ -23243,7 +22211,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, } /* allow "static" field name */ if (s->token.val == ';' || s->token.val == '=') { - is_static = FALSE; + is_static = false; name = JS_DupAtom(ctx, JS_ATOM_static); prop_type = PROP_TYPE_IDENT; } @@ -23252,7 +22220,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, emit_op(s, OP_swap); start_ptr = s->token.ptr; if (prop_type < 0) { - prop_type = js_parse_property_name(s, &name, TRUE, FALSE, TRUE); + prop_type = js_parse_property_name(s, &name, true, false, true); if (prop_type < 0) goto fail; } @@ -23267,7 +22235,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, goto fail; } if (prop_type == PROP_TYPE_GET || prop_type == PROP_TYPE_SET) { - BOOL is_set = prop_type - PROP_TYPE_GET; + bool is_set = prop_type - PROP_TYPE_GET; JSFunctionDef *method_fd; if (is_private) { @@ -23290,16 +22258,18 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, JS_VAR_PRIVATE_GETTER + is_set, is_static) < 0) goto fail; } - class_fields[is_static].need_brand = TRUE; + class_fields[is_static].need_brand = true; } if (js_parse_function_decl2(s, JS_PARSE_FUNC_GETTER + is_set, JS_FUNC_NORMAL, JS_ATOM_NULL, - start_ptr, s->token.line_num, + start_ptr, + s->token.line_num, + s->token.col_num, JS_PARSE_EXPORT_NONE, &method_fd)) goto fail; if (is_private) { - method_fd->need_home_object = TRUE; /* needed for brand check */ + method_fd->need_home_object = true; /* needed for brand check */ emit_op(s, OP_set_home_object); /* XXX: missing function name */ emit_op(s, OP_scope_put_var_init); @@ -23379,6 +22349,14 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, emit_atom(s, JS_ATOM_this); emit_u16(s, 0); + // expose class name to static initializers + if (is_static && class_name != JS_ATOM_NULL) { + emit_op(s, OP_dup); + emit_op(s, OP_scope_put_var_init); + emit_atom(s, class_name); + emit_u16(s, s->cur_func->scope_level); + } + if (name == JS_ATOM_NULL) { emit_op(s, OP_scope_get_var); emit_atom(s, field_var_name); @@ -23437,15 +22415,19 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR; } if (is_private) { - class_fields[is_static].need_brand = TRUE; + class_fields[is_static].need_brand = true; } - if (js_parse_function_decl2(s, func_type, func_kind, JS_ATOM_NULL, start_ptr, s->token.line_num, JS_PARSE_EXPORT_NONE, &method_fd)) + if (js_parse_function_decl2(s, func_type, func_kind, JS_ATOM_NULL, + start_ptr, + s->token.line_num, + s->token.col_num, + JS_PARSE_EXPORT_NONE, &method_fd)) goto fail; if (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR || func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) { ctor_fd = method_fd; } else if (is_private) { - method_fd->need_home_object = TRUE; /* needed for brand check */ + method_fd->need_home_object = true; /* needed for brand check */ if (find_private_class_field(ctx, fd, name, fd->scope_level) >= 0) { private_field_already_defined: @@ -23490,14 +22472,11 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, put_u32(fd->byte_code.buf + ctor_cpool_offset, ctor_fd->parent_cpool_idx); /* store the class source code in the constructor. */ - if (!(fd->js_mode & JS_MODE_STRIP)) { - js_free(ctx, ctor_fd->source); - ctor_fd->source_len = s->buf_ptr - class_start_ptr; - ctor_fd->source = js_strndup(ctx, (const char *)class_start_ptr, - ctor_fd->source_len); - if (!ctor_fd->source) - goto fail; - } + js_free(ctx, ctor_fd->source); + ctor_fd->source_len = s->buf_ptr - class_start_ptr; + ctor_fd->source = js_strndup(ctx, (const char *)class_start_ptr, ctor_fd->source_len); + if (!ctor_fd->source) + goto fail; /* consume the '}' */ if (next_token(s)) @@ -23550,16 +22529,6 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, emit_op(s, OP_add_brand); } - if (class_name != JS_ATOM_NULL) { - /* store the class name in the scoped class name variable (it - is independent from the class statement variable - definition) */ - emit_op(s, OP_dup); - emit_op(s, OP_scope_put_var_init); - emit_atom(s, class_name); - emit_u16(s, fd->scope_level); - } - /* initialize the static fields */ if (class_fields[1].fields_init_fd != NULL) { ClassFieldsDef *cf = &class_fields[1]; @@ -23570,6 +22539,15 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, emit_op(s, OP_drop); } + if (class_name != JS_ATOM_NULL) { + /* store the class name in the scoped class name variable (it + is independent from the class statement variable + definition) */ + emit_op(s, OP_dup); + emit_op(s, OP_scope_put_var_init); + emit_atom(s, class_name); + emit_u16(s, fd->scope_level); + } pop_scope(s); pop_scope(s); @@ -23600,20 +22578,20 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, JS_FreeAtom(ctx, class_name); JS_FreeAtom(ctx, class_var_name); - fd->js_mode = saved_js_mode; + fd->is_strict_mode = is_strict_mode; return 0; fail: JS_FreeAtom(ctx, name); JS_FreeAtom(ctx, class_name); JS_FreeAtom(ctx, class_var_name); - fd->js_mode = saved_js_mode; + fd->is_strict_mode = is_strict_mode; return -1; } static __exception int js_parse_array_literal(JSParseState *s) { uint32_t idx; - BOOL need_length; + bool need_length; if (next_token(s)) return -1; @@ -23637,17 +22615,17 @@ static __exception int js_parse_array_literal(JSParseState *s) emit_u16(s, idx); /* larger arrays and holes are handled with explicit indices */ - need_length = FALSE; + need_length = false; while (s->token.val != ']' && idx < 0x7fffffff) { if (s->token.val == TOK_ELLIPSIS) break; - need_length = TRUE; + need_length = true; if (s->token.val != ',') { if (js_parse_assign_expr(s)) return -1; emit_op(s, OP_define_field); emit_u32(s, __JS_AtomFromUInt32(idx)); - need_length = FALSE; + need_length = false; } idx++; /* accept trailing comma */ @@ -23665,6 +22643,7 @@ static __exception int js_parse_array_literal(JSParseState *s) emit_u32(s, idx); emit_op(s, OP_put_field); emit_atom(s, JS_ATOM_length); + emit_ic(s, JS_ATOM_length); } goto done; } @@ -23680,41 +22659,15 @@ static __exception int js_parse_array_literal(JSParseState *s) return -1; if (js_parse_assign_expr(s)) return -1; -#if 1 emit_op(s, OP_append); -#else - int label_next, label_done; - label_next = new_label(s); - label_done = new_label(s); - /* enumerate object */ - emit_op(s, OP_for_of_start); - emit_op(s, OP_rot5l); - emit_op(s, OP_rot5l); - emit_label(s, label_next); - /* on stack: enum_rec array idx */ - emit_op(s, OP_for_of_next); - emit_u8(s, 2); - emit_goto(s, OP_if_true, label_done); - /* append element */ - /* enum_rec array idx val -> enum_rec array new_idx */ - emit_op(s, OP_define_array_el); - emit_op(s, OP_inc); - emit_goto(s, OP_goto, label_next); - emit_label(s, label_done); - /* close enumeration */ - emit_op(s, OP_drop); /* drop undef val */ - emit_op(s, OP_nip1); /* drop enum_rec */ - emit_op(s, OP_nip1); - emit_op(s, OP_nip1); -#endif } else { - need_length = TRUE; + need_length = true; if (s->token.val != ',') { if (js_parse_assign_expr(s)) return -1; /* a idx val */ emit_op(s, OP_define_array_el); - need_length = FALSE; + need_length = false; } emit_op(s, OP_inc); } @@ -23729,6 +22682,7 @@ static __exception int js_parse_array_literal(JSParseState *s) emit_op(s, OP_dup1); /* array length - array array length */ emit_op(s, OP_put_field); emit_atom(s, JS_ATOM_length); + emit_ic(s, JS_ATOM_length); } else { emit_op(s, OP_drop); /* array length - array */ } @@ -23737,7 +22691,7 @@ static __exception int js_parse_array_literal(JSParseState *s) } /* XXX: remove */ -static BOOL has_with_scope(JSFunctionDef *s, int scope_level) +static bool has_with_scope(JSFunctionDef *s, int scope_level) { /* check if scope chain contains a with statement */ while (s) { @@ -23746,18 +22700,18 @@ static BOOL has_with_scope(JSFunctionDef *s, int scope_level) JSVarDef *vd = &s->vars[scope_idx]; if (vd->var_name == JS_ATOM__with_) - return TRUE; + return true; scope_idx = vd->scope_next; } /* check parent scopes */ scope_level = s->parent_scope_level; s = s->parent; } - return FALSE; + return false; } static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope, - JSAtom *pname, int *plabel, int *pdepth, BOOL keep, + JSAtom *pname, int *plabel, int *pdepth, bool keep, int tok) { JSFunctionDef *fd; @@ -23775,7 +22729,7 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope, name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1); scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5); if ((name == JS_ATOM_arguments || name == JS_ATOM_eval) && - (fd->js_mode & JS_MODE_STRICT)) { + fd->is_strict_mode) { return js_parse_error(s, "invalid lvalue in strict mode"); } if (name == JS_ATOM_this || name == JS_ATOM_new_target) @@ -23829,6 +22783,7 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope, case OP_get_field: emit_op(s, OP_get_field2); emit_atom(s, name); + emit_ic(s, name); break; case OP_scope_get_private_field: emit_op(s, OP_scope_get_private_field2); @@ -23893,7 +22848,7 @@ typedef enum { OP_scope_get_var which is never generated by get_lvalue(). */ static void put_lvalue(JSParseState *s, int opcode, int scope, JSAtom name, int label, PutLValueEnum special, - BOOL is_let) + bool is_let) { switch(opcode) { case OP_get_field: @@ -23976,6 +22931,7 @@ static void put_lvalue(JSParseState *s, int opcode, int scope, case OP_get_field: emit_op(s, OP_put_field); emit_u32(s, name); /* name has refcount */ + emit_ic(s, name); break; case OP_scope_get_private_field: emit_op(s, OP_scope_put_private_field); @@ -24023,12 +22979,20 @@ static __exception int js_define_var(JSParseState *s, JSAtom name, int tok) return js_parse_error(s, "yield is a reserved identifier"); } if ((name == JS_ATOM_arguments || name == JS_ATOM_eval) - && (fd->js_mode & JS_MODE_STRICT)) { + && fd->is_strict_mode) { return js_parse_error(s, "invalid variable name in strict mode"); } - if ((name == JS_ATOM_let || name == JS_ATOM_undefined) - && (tok == TOK_LET || tok == TOK_CONST)) { - return js_parse_error(s, "invalid lexical variable name"); + if (tok == TOK_LET || tok == TOK_CONST) { + if (name == JS_ATOM_let) + return js_parse_error(s, "invalid lexical variable name 'let'"); + // |undefined| is allowed as an identifier except at the global + // scope of a classic script; sloppy or strict doesn't matter + if (name == JS_ATOM_undefined + && fd->scope_level == 1 + && fd->is_global_var + && !fd->module) { + return js_parse_error(s, "'undefined' already declared"); + } } switch(tok) { case TOK_LET: @@ -24093,7 +23057,7 @@ static int js_parse_check_duplicate_parameter(JSParseState *s, JSAtom name) return 0; duplicate: - return js_parse_error(s, "duplicate parameter names not allowed in this context"); + return js_parse_error(s, "Duplicate parameter name not allowed in this context"); } static JSAtom js_parse_destructuring_var(JSParseState *s, int tok, int is_arg) @@ -24101,7 +23065,7 @@ static JSAtom js_parse_destructuring_var(JSParseState *s, int tok, int is_arg) JSAtom name; if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved) - || ((s->cur_func->js_mode & JS_MODE_STRICT) && + || (s->cur_func->is_strict_mode && (s->token.u.ident.atom == JS_ATOM_eval || s->token.u.ident.atom == JS_ATOM_arguments))) { js_parse_error(s, "invalid destructuring target"); return JS_ATOM_NULL; @@ -24122,17 +23086,19 @@ static JSAtom js_parse_destructuring_var(JSParseState *s, int tok, int is_arg) 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) + bool allow_initializer, bool export_flag) { int label_parse, label_assign, label_done, label_lvalue, depth_lvalue; int start_addr, assign_addr; JSAtom prop_name, var_name; int opcode, scope, tok1, skip_bits; - BOOL has_initializer; + bool has_initializer; + + label_lvalue = -1; if (has_ellipsis < 0) { /* pre-parse destructuration target for spread detection */ - js_parse_skip_parens_token(s, &skip_bits, FALSE); + js_parse_skip_parens_token(s, &skip_bits, false); has_ellipsis = skip_bits & SKIP_HAS_ELLIPSIS; } @@ -24186,7 +23152,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, return -1; if (get_lvalue(s, &opcode, &scope, &var_name, - &label_lvalue, &depth_lvalue, FALSE, '{')) + &label_lvalue, &depth_lvalue, false, '{')) return -1; } if (s->token.val != '}') { @@ -24198,7 +23164,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, emit_u8(s, 0 | ((depth_lvalue + 1) << 2) | ((depth_lvalue + 2) << 5)); goto set_val; } - prop_type = js_parse_property_name(s, &prop_name, FALSE, TRUE, FALSE); + prop_type = js_parse_property_name(s, &prop_name, false, true, false); if (prop_type < 0) return -1; var_name = JS_ATOM_NULL; @@ -24210,7 +23176,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, if (next_token(s)) goto prop_error; if ((s->token.val == '[' || s->token.val == '{') - && ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == ',' || + && ((tok1 = js_parse_skip_parens_token(s, &skip_bits, false)) == ',' || tok1 == '=' || tok1 == '}')) { if (prop_name == JS_ATOM_NULL) { /* computed property name on stack */ @@ -24237,8 +23203,9 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, /* get the named property from the source object */ emit_op(s, OP_get_field2); emit_u32(s, prop_name); + emit_ic(s, prop_name); } - if (js_parse_destructuring_element(s, tok, is_arg, TRUE, -1, TRUE) < 0) + if (js_parse_destructuring_element(s, tok, is_arg, true, -1, true, export_flag) < 0) return -1; if (s->token.val == '}') break; @@ -24279,7 +23246,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, goto prop_error; lvalue: if (get_lvalue(s, &opcode, &scope, &var_name, - &label_lvalue, &depth_lvalue, FALSE, '{')) + &label_lvalue, &depth_lvalue, false, '{')) goto prop_error; /* swap ref and lvalue object if any */ if (prop_name == JS_ATOM_NULL) { @@ -24326,12 +23293,13 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, /* source -- val */ emit_op(s, OP_get_field); emit_u32(s, prop_name); + emit_ic(s, prop_name); } } else { /* prop_type = PROP_TYPE_VAR, cannot be a computed property */ if (is_arg && js_parse_check_duplicate_parameter(s, prop_name)) goto prop_error; - if ((s->cur_func->js_mode & JS_MODE_STRICT) && + if (s->cur_func->is_strict_mode && (prop_name == JS_ATOM_eval || prop_name == JS_ATOM_arguments)) { js_parse_error(s, "invalid destructuring target"); goto prop_error; @@ -24357,11 +23325,17 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, /* source -- source val */ emit_op(s, OP_get_field2); emit_u32(s, prop_name); + emit_ic(s, prop_name); } set_val: if (tok) { if (js_define_var(s, var_name, tok)) goto var_error; + if (export_flag) { + if (!add_export_entry(s, s->cur_func->module, var_name, var_name, + JS_EXPORT_TYPE_LOCAL)) + goto var_error; + } scope = s->cur_func->scope_level; } if (s->token.val == '=') { /* handle optional default value */ @@ -24397,7 +23371,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, if (next_token(s)) return -1; } else if (s->token.val == '[') { - BOOL has_spread; + bool has_spread; int enum_depth; BlockEnv block_env; @@ -24407,9 +23381,9 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, 'yield' triggers a 'return' */ push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL, -1, -1, 2); - block_env.has_iterator = TRUE; + block_env.has_iterator = true; emit_op(s, OP_for_of_start); - has_spread = FALSE; + has_spread = false; while (s->token.val != ']') { /* get the next value */ if (s->token.val == TOK_ELLIPSIS) { @@ -24417,7 +23391,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, return -1; if (s->token.val == ',' || s->token.val == ']') return js_parse_error(s, "missing binding pattern..."); - has_spread = TRUE; + has_spread = true; } if (s->token.val == ',') { /* do nothing, skip the value, has_spread is false */ @@ -24426,7 +23400,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, emit_op(s, OP_drop); emit_op(s, OP_drop); } else if ((s->token.val == '[' || s->token.val == '{') - && ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == ',' || + && ((tok1 = js_parse_skip_parens_token(s, &skip_bits, false)) == ',' || tok1 == '=' || tok1 == ']')) { if (has_spread) { if (tok1 == '=') @@ -24437,7 +23411,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) < 0) + if (js_parse_destructuring_element(s, tok, is_arg, true, skip_bits & SKIP_HAS_ELLIPSIS, true, export_flag) < 0) return -1; } else { var_name = JS_ATOM_NULL; @@ -24454,7 +23428,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, if (js_parse_left_hand_side_expr(s)) return -1; if (get_lvalue(s, &opcode, &scope, &var_name, - &label_lvalue, &enum_depth, FALSE, '[')) { + &label_lvalue, &enum_depth, false, '[')) { return -1; } } @@ -24514,7 +23488,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, return -1; emit_goto(s, OP_goto, label_assign); emit_label(s, label_done); - has_initializer = TRUE; + has_initializer = true; } else { /* normally hasval is true except if js_parse_skip_parens_token() was wrong in the parsing */ @@ -24527,7 +23501,7 @@ 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; + has_initializer = false; } return has_initializer; @@ -24567,7 +23541,7 @@ 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; + bool accept_lparen = (parse_flags & PF_POSTFIX_CALL) != 0; call_type = FUNC_CALL_NORMAL; switch(s->token.val) { @@ -24579,34 +23553,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) { emit_op(s, OP_push_i32); emit_u32(s, JS_VALUE_GET_INT(val)); - } else -#ifdef CONFIG_BIGNUM - if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) { - slimb_t e; - int ret; - - /* need a runtime conversion */ - /* XXX: could add a cache and/or do it once at - the start of the function */ - if (emit_push_const(s, val, 0) < 0) - return -1; - e = s->token.u.num.exponent; - if (e == (int32_t)e) { - emit_op(s, OP_push_i32); - emit_u32(s, e); - } else { - val = JS_NewBigInt64_1(s->ctx, e); - if (JS_IsException(val)) - return -1; - ret = emit_push_const(s, val, 0); - JS_FreeValue(s->ctx, val); - if (ret < 0) - return -1; - } - emit_op(s, OP_mul_pow10); - } else -#endif - { + } else { if (emit_push_const(s, val, 0) < 0) return -1; } @@ -24647,8 +23594,10 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) backtrace_flags = 0; if (s->cur_func && s->cur_func->backtrace_barrier) backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL; - build_backtrace(s->ctx, s->ctx->rt->current_exception, - s->filename, s->token.line_num, + build_backtrace(s->ctx, s->ctx->rt->current_exception, JS_UNDEFINED, + s->filename, + s->token.line_num, + s->token.col_num, backtrace_flags); return -1; } @@ -24671,11 +23620,13 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) case TOK_FUNCTION: if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR, JS_FUNC_NORMAL, JS_ATOM_NULL, - s->token.ptr, s->token.line_num)) + s->token.ptr, + s->token.line_num, + s->token.col_num)) return -1; break; case TOK_CLASS: - if (js_parse_class(s, TRUE, JS_PARSE_EXPORT_NONE)) + if (js_parse_class(s, true, JS_PARSE_EXPORT_NONE)) return -1; break; case TOK_NULL: @@ -24707,18 +23658,22 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) return js_parse_error_reserved_identifier(s); } if (token_is_pseudo_keyword(s, JS_ATOM_async) && - peek_token(s, TRUE) != '\n') { + peek_token(s, true) != '\n') { const uint8_t *source_ptr; int source_line_num; + int source_col_num; source_ptr = s->token.ptr; source_line_num = s->token.line_num; + source_col_num = s->token.col_num; if (next_token(s)) return -1; if (s->token.val == TOK_FUNCTION) { if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR, JS_FUNC_ASYNC, JS_ATOM_NULL, - source_ptr, source_line_num)) + source_ptr, + source_line_num, + source_col_num)) return -1; } else { name = JS_DupAtom(s->ctx, JS_ATOM_async); @@ -24731,7 +23686,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) return -1; } name = JS_DupAtom(s->ctx, s->token.u.ident.atom); - if (next_token(s)) { /* update line number before emitting code */ + if (next_token(s)) { /* update line number before emitting code */ JS_FreeAtom(s->ctx, name); return -1; } @@ -24746,8 +23701,8 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) case '[': { 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) < 0) + 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, false) < 0) return -1; } else { if (s->token.val == '{') { @@ -24776,9 +23731,10 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) emit_atom(s, JS_ATOM_new_target); emit_u16(s, 0); } else { + emit_source_loc(s); if (js_parse_postfix_expr(s, 0)) return -1; - accept_lparen = TRUE; + accept_lparen = true; if (s->token.val != '(') { /* new operator on an object */ emit_op(s, OP_dup); @@ -24844,13 +23800,13 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) optional_chaining_label = -1; for(;;) { JSFunctionDef *fd = s->cur_func; - BOOL has_optional_chain = FALSE; + bool has_optional_chain = false; if (s->token.val == TOK_QUESTION_MARK_DOT) { /* optional chaining */ if (next_token(s)) return -1; - has_optional_chain = TRUE; + has_optional_chain = true; if (s->token.val == '(' && accept_lparen) { goto parse_func_call; } else if (s->token.val == '[') { @@ -24875,6 +23831,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) if (call_type == FUNC_CALL_NORMAL) { parse_func_call2: + emit_source_loc(s); switch(opcode = get_prev_opcode(fd)) { case OP_get_field: /* keep the object on the stack */ @@ -24996,7 +23953,8 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) arg_count = 0; while (s->token.val != ')') { if (arg_count >= 65535) { - return js_parse_error(s, "Too many call arguments"); + return js_parse_error(s, "Too many arguments in function call (only %d allowed)", + 65535 - 1); } if (s->token.val == TOK_ELLIPSIS) break; @@ -25022,34 +23980,8 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) return -1; if (js_parse_assign_expr(s)) return -1; -#if 1 /* XXX: could pass is_last indicator? */ emit_op(s, OP_append); -#else - int label_next, label_done; - label_next = new_label(s); - label_done = new_label(s); - /* push enumerate object below array/idx pair */ - emit_op(s, OP_for_of_start); - emit_op(s, OP_rot5l); - emit_op(s, OP_rot5l); - emit_label(s, label_next); - /* on stack: enum_rec array idx */ - emit_op(s, OP_for_of_next); - emit_u8(s, 2); - emit_goto(s, OP_if_true, label_done); - /* append element */ - /* enum_rec array idx val -> enum_rec array new_idx */ - emit_op(s, OP_define_array_el); - emit_op(s, OP_inc); - emit_goto(s, OP_goto, label_next); - emit_label(s, label_done); - /* close enumeration, drop enum_rec and idx */ - emit_op(s, OP_drop); /* drop undef */ - emit_op(s, OP_nip1); /* drop enum_rec */ - emit_op(s, OP_nip1); - emit_op(s, OP_nip1); -#endif } else { if (js_parse_assign_expr(s)) return -1; @@ -25082,7 +24014,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) case OP_eval: emit_op(s, OP_apply_eval); emit_u16(s, fd->scope_level); - fd->has_eval_call = TRUE; + fd->has_eval_call = true; break; default: if (call_type == FUNC_CALL_SUPER_CTOR) { @@ -25125,7 +24057,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) emit_op(s, OP_eval); emit_u16(s, arg_count); emit_u16(s, fd->scope_level); - fd->has_eval_call = TRUE; + fd->has_eval_call = true; break; default: if (call_type == FUNC_CALL_SUPER_CTOR) { @@ -25184,6 +24116,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) } emit_op(s, OP_get_field); emit_atom(s, s->token.u.ident.atom); + emit_ic(s, s->token.u.ident.atom); } } if (next_token(s)) @@ -25299,7 +24232,7 @@ static __exception int js_parse_delete(JSParseState *s) name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1); if (name == JS_ATOM_this || name == JS_ATOM_new_target) goto ret_true; - if (fd->js_mode & JS_MODE_STRICT) { + if (fd->is_strict_mode) { return js_parse_error(s, "cannot delete a direct reference in strict mode"); } else { fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_delete_var; @@ -25371,11 +24304,11 @@ static __exception int js_parse_unary(JSParseState *s, int parse_flags) return -1; if (js_parse_unary(s, 0)) return -1; - if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op)) + if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, true, op)) return -1; emit_op(s, OP_dec + op - TOK_DEC); put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP, - FALSE); + false); } break; case TOK_TYPEOF: @@ -25409,7 +24342,7 @@ static __exception int js_parse_unary(JSParseState *s, int parse_flags) return -1; if (js_parse_unary(s, PF_POW_FORBIDDEN)) return -1; - s->cur_func->has_await = TRUE; + s->cur_func->has_await = true; emit_op(s, OP_await); parse_flags = 0; break; @@ -25421,52 +24354,31 @@ static __exception int js_parse_unary(JSParseState *s, int parse_flags) int opcode, op, scope, label; JSAtom name; op = s->token.val; - if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op)) + if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, true, op)) return -1; emit_op(s, OP_post_dec + op - TOK_DEC); put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_SECOND, - FALSE); + false); if (next_token(s)) return -1; } break; } 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 (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, PF_POW_ALLOWED)) - return -1; - emit_op(s, OP_pow); - } -#else if (s->token.val == TOK_POW) { /* Strict ES7 exponentiation syntax rules: To solve conficting semantics between different implementations regarding the precedence of prefix operators and the postifx exponential, ES7 specifies that -2**2 is a syntax error. */ - 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 (parse_flags & PF_POW_FORBIDDEN) + return js_parse_error(s, "unparenthesized unary expression can't appear on the left-hand side of '**'"); if (next_token(s)) return -1; if (js_parse_unary(s, PF_POW_ALLOWED)) return -1; emit_op(s, OP_pow); } -#endif } return 0; } @@ -25481,9 +24393,8 @@ static __exception int js_parse_expr_binary(JSParseState *s, int level, return js_parse_unary(s, PF_POW_ALLOWED); } else if (s->token.val == TOK_PRIVATE_NAME && (parse_flags & PF_IN_ACCEPTED) && level == 4 && - peek_token(s, FALSE) == TOK_IN) { + peek_token(s, false) == TOK_IN) { JSAtom atom; - atom = JS_DupAtom(s->ctx, s->token.u.ident.atom); if (next_token(s)) goto fail_private_in; @@ -25517,12 +24428,7 @@ static __exception int js_parse_expr_binary(JSParseState *s, int level, opcode = OP_div; break; case '%': -#ifdef CONFIG_BIGNUM - if (s->cur_func->js_mode & JS_MODE_MATH) - opcode = OP_math_mod; - else -#endif - opcode = OP_mod; + opcode = OP_mod; break; default: return 0; @@ -25633,6 +24539,7 @@ static __exception int js_parse_expr_binary(JSParseState *s, int level, } if (next_token(s)) return -1; + emit_source_loc(s); if (js_parse_expr_binary(s, level - 1, parse_flags)) return -1; emit_op(s, opcode); @@ -25667,8 +24574,7 @@ static __exception int js_parse_logical_and_or(JSParseState *s, int op, if (js_parse_expr_binary(s, 8, parse_flags)) return -1; } else { - if (js_parse_logical_and_or(s, TOK_LAND, - parse_flags)) + if (js_parse_logical_and_or(s, TOK_LAND, parse_flags)) return -1; } if (s->token.val != op) { @@ -25739,8 +24645,6 @@ static __exception int js_parse_cond_expr(JSParseState *s, int parse_flags) return 0; } -static void emit_return(JSParseState *s, BOOL hasval); - /* allowed parse_flags: PF_IN_ACCEPTED */ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags) { @@ -25749,7 +24653,7 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags) JSAtom name; if (s->token.val == TOK_YIELD) { - BOOL is_star = FALSE, is_async; + bool is_star = false, is_async; if (!(s->cur_func->func_kind & JS_FUNC_GENERATOR)) return js_parse_error(s, "unexpected 'yield' keyword"); @@ -25763,7 +24667,7 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags) s->token.val != ']' && s->token.val != '}' && s->token.val != ',' && s->token.val != ':' && !s->got_lf) { if (s->token.val == '*') { - is_star = TRUE; + is_star = true; if (next_token(s)) return -1; } @@ -25798,12 +24702,14 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags) emit_op(s, OP_iterator_check_object); emit_op(s, OP_get_field2); emit_atom(s, JS_ATOM_done); + emit_ic(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_ic(s, JS_ATOM_value); emit_op(s, OP_async_yield_star); } else { /* OP_yield_star takes (value, done) as parameter */ @@ -25831,16 +24737,18 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags) emit_op(s, OP_iterator_check_object); emit_op(s, OP_get_field2); emit_atom(s, JS_ATOM_done); + emit_ic(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_ic(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); + emit_return(s, true); /* throw handling */ emit_label(s, label_throw); @@ -25852,6 +24760,7 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags) emit_op(s, OP_iterator_check_object); emit_op(s, OP_get_field2); emit_atom(s, JS_ATOM_done); + emit_ic(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 */ @@ -25870,6 +24779,7 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags) emit_label(s, label_next); emit_op(s, OP_get_field); emit_atom(s, JS_ATOM_value); + emit_ic(s, JS_ATOM_value); emit_op(s, OP_nip); /* keep the value associated with done = true */ emit_op(s, OP_nip); @@ -25881,47 +24791,51 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags) emit_op(s, OP_await); emit_op(s, OP_yield); label_next = emit_goto(s, OP_if_false, -1); - emit_return(s, TRUE); + emit_return(s, true); emit_label(s, label_next); } return 0; } else if (s->token.val == '(' && - js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) { + js_parse_skip_parens_token(s, NULL, true) == TOK_ARROW) { return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW, JS_FUNC_NORMAL, JS_ATOM_NULL, - s->token.ptr, s->token.line_num); + s->token.ptr, s->token.line_num, + s->token.col_num); } else if (token_is_pseudo_keyword(s, JS_ATOM_async)) { const uint8_t *source_ptr; - int source_line_num, tok; + int tok, source_line_num, source_col_num; JSParsePos pos; /* fast test */ - tok = peek_token(s, TRUE); + tok = peek_token(s, true); if (tok == TOK_FUNCTION || tok == '\n') goto next; source_ptr = s->token.ptr; source_line_num = s->token.line_num; + source_col_num = s->token.col_num; js_parse_get_pos(s, &pos); if (next_token(s)) return -1; if ((s->token.val == '(' && - js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) || + 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)) { + peek_token(s, true) == TOK_ARROW)) { return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW, JS_FUNC_ASYNC, JS_ATOM_NULL, - source_ptr, source_line_num); + source_ptr, source_line_num, + source_col_num); } else { /* undo the token parsing */ if (js_parse_seek_token(s, &pos)) return -1; } } else if (s->token.val == TOK_IDENT && - peek_token(s, TRUE) == TOK_ARROW) { + peek_token(s, true) == TOK_ARROW) { return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW, JS_FUNC_NORMAL, JS_ATOM_NULL, - s->token.ptr, s->token.line_num); + s->token.ptr, s->token.line_num, + s->token.col_num); } next: if (s->token.val == TOK_IDENT) { @@ -25939,41 +24853,55 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags) if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, (op != '='), op) < 0) return -1; + // comply with rather obtuse evaluation order of computed properties: + // obj[key]=val evaluates val->obj->key when obj is null/undefined + // but key->obj->val when an object + // FIXME(bnoordhuis) less stack shuffling; don't to_propkey twice in + // happy path; replace `dup is_undefined_or_null if_true` with new + // opcode if_undefined_or_null? replace `swap dup` with over? + if (op == '=' && opcode == OP_get_array_el) { + int label_next = -1; + JSFunctionDef *fd = s->cur_func; + assert(OP_to_propkey2 == fd->byte_code.buf[fd->last_opcode_pos]); + fd->byte_code.size = fd->last_opcode_pos; + fd->last_opcode_pos = -1; + emit_op(s, OP_swap); // obj key -> key obj + 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_swap); + emit_op(s, OP_to_propkey); + emit_op(s, OP_swap); + emit_label(s, label_next); + emit_op(s, OP_swap); + } + if (js_parse_assign_expr2(s, parse_flags)) { JS_FreeAtom(s->ctx, name); return -1; } + if (op == '=' && opcode == OP_get_array_el) { + emit_op(s, OP_swap); // obj key val -> obj val key + emit_op(s, OP_to_propkey); + emit_op(s, OP_swap); + } + if (op == '=') { if (opcode == OP_get_ref_value && name == name0) { set_object_name(s, name); } } else { - static const uint8_t assign_opcodes[] = { - OP_mul, OP_div, OP_mod, OP_add, OP_sub, - OP_shl, OP_sar, OP_shr, OP_and, OP_xor, OP_or, -#ifdef CONFIG_BIGNUM - OP_pow, -#endif - OP_pow, - }; - op = assign_opcodes[op - TOK_MUL_ASSIGN]; -#ifdef CONFIG_BIGNUM - if (s->cur_func->js_mode & JS_MODE_MATH) { - if (op == OP_mod) - op = OP_math_mod; - } -#endif - emit_op(s, op); + emit_op(s, op - TOK_MUL_ASSIGN + OP_mul); } - put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP, FALSE); + put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP, false); } else if (op >= TOK_LAND_ASSIGN && op <= TOK_DOUBLE_QUESTION_MARK_ASSIGN) { int label, label1, depth_lvalue, label2; if (next_token(s)) return -1; if (get_lvalue(s, &opcode, &scope, &name, &label, - &depth_lvalue, TRUE, op) < 0) + &depth_lvalue, true, op) < 0) return -1; emit_op(s, OP_dup); @@ -26009,7 +24937,7 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags) /* XXX: we disable the OP_put_ref_value optimization by not using put_lvalue() otherwise depth_lvalue is not correct */ put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_NOKEEP_DEPTH, - FALSE); + false); label2 = emit_goto(s, OP_goto, -1); emit_label(s, label1); @@ -26033,7 +24961,7 @@ static __exception int js_parse_assign_expr(JSParseState *s) /* allowed parse_flags: PF_IN_ACCEPTED */ static __exception int js_parse_expr2(JSParseState *s, int parse_flags) { - BOOL comma = FALSE; + bool comma = false; for(;;) { if (js_parse_assign_expr2(s, parse_flags)) return -1; @@ -26047,7 +24975,7 @@ static __exception int js_parse_expr2(JSParseState *s, int parse_flags) } if (s->token.val != ',') break; - comma = TRUE; + comma = true; if (next_token(s)) return -1; emit_op(s, OP_drop); @@ -26073,7 +25001,8 @@ static void push_break_entry(JSFunctionDef *fd, BlockEnv *be, be->drop_count = drop_count; be->label_finally = -1; be->scope_level = fd->scope_level; - be->has_iterator = FALSE; + be->has_iterator = false; + be->is_regular_stmt = false; } static void pop_break_entry(JSFunctionDef *fd) @@ -26100,11 +25029,12 @@ static __exception int emit_break(JSParseState *s, JSAtom name, int is_cont) emit_goto(s, OP_goto, top->label_cont); return 0; } - if (!is_cont && - top->label_break != -1 && - (name == JS_ATOM_NULL || top->label_name == name)) { - emit_goto(s, OP_goto, top->label_break); - return 0; + if (!is_cont && top->label_break != -1) { + if (top->label_name == name || + (name == JS_ATOM_NULL && !top->is_regular_stmt)) { + emit_goto(s, OP_goto, top->label_break); + return 0; + } } i = 0; if (top->has_iterator) { @@ -26132,7 +25062,7 @@ static __exception int emit_break(JSParseState *s, JSAtom name, int is_cont) } /* execute the finally blocks before return */ -static void emit_return(JSParseState *s, BOOL hasval) +static void emit_return(JSParseState *s, bool hasval) { BlockEnv *top; @@ -26140,7 +25070,7 @@ static void emit_return(JSParseState *s, BOOL hasval) if (!hasval) { /* no value: direct return in case of async generator */ emit_op(s, OP_undefined); - hasval = TRUE; + hasval = true; } else if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) { /* the await must be done before handling the "finally" in case it raises an exception */ @@ -26153,7 +25083,7 @@ static void emit_return(JSParseState *s, BOOL hasval) if (top->has_iterator || top->label_finally != -1) { if (!hasval) { emit_op(s, OP_undefined); - hasval = TRUE; + hasval = true; } /* Remove the stack elements up to and including the catch offset. When 'yield' is used in an expression we have @@ -26168,6 +25098,7 @@ static void emit_return(JSParseState *s, BOOL hasval) emit_op(s, OP_swap); emit_op(s, OP_get_field2); emit_atom(s, JS_ATOM_return); + emit_ic(s, JS_ATOM_return); /* stack: iter_obj return_func */ emit_op(s, OP_dup); emit_op(s, OP_is_undefined_or_null); @@ -26206,9 +25137,9 @@ static void emit_return(JSParseState *s, BOOL hasval) label_return = -1; } - /* The error should be raised in the caller context, so we use - a specific opcode */ - emit_op(s, OP_scope_get_var_checkthis); + /* XXX: if this is not initialized, should throw the + ReferenceError in the caller realm */ + emit_op(s, OP_scope_get_var); emit_atom(s, JS_ATOM_this); emit_u16(s, 0); @@ -26256,7 +25187,7 @@ static __exception int js_parse_block(JSParseState *s) /* allowed parse_flags: PF_IN_ACCEPTED */ static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok, - BOOL export_flag) + bool export_flag) { JSContext *ctx = s->ctx; JSFunctionDef *fd = s->cur_func; @@ -26293,7 +25224,7 @@ static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok, emit_op(s, OP_scope_get_var); emit_atom(s, name); emit_u16(s, fd->scope_level); - if (get_lvalue(s, &opcode, &scope, &name1, &label, NULL, FALSE, '=') < 0) + if (get_lvalue(s, &opcode, &scope, &name1, &label, NULL, false, '=') < 0) goto var_error; if (js_parse_assign_expr2(s, parse_flags)) { JS_FreeAtom(ctx, name1); @@ -26301,7 +25232,7 @@ static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok, } set_object_name(s, name); put_lvalue(s, opcode, scope, name1, label, - PUT_LVALUE_NOKEEP, FALSE); + PUT_LVALUE_NOKEEP, false); } else { if (js_parse_assign_expr2(s, parse_flags)) goto var_error; @@ -26328,9 +25259,9 @@ static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok, } else { int skip_bits; if ((s->token.val == '[' || s->token.val == '{') - && js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') { + && 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) < 0) + if (js_parse_destructuring_element(s, tok, 0, true, skip_bits & SKIP_HAS_ELLIPSIS, true, export_flag) < 0) return -1; } else { return js_parse_error(s, "variable name expected"); @@ -26349,16 +25280,16 @@ static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok, } /* test if the current token is a label. Use simplistic look-ahead scanner */ -static BOOL is_label(JSParseState *s) +static bool is_label(JSParseState *s) { return (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved && - peek_token(s, FALSE) == ':'); + peek_token(s, false) == ':'); } /* test if the current token is a let keyword. Use simplistic look-ahead scanner */ static int is_let(JSParseState *s, int decl_mask) { - int res = FALSE; + int res = false; if (token_is_pseudo_keyword(s, JS_ATOM_let)) { JSParsePos pos; @@ -26371,7 +25302,7 @@ static int is_let(JSParseState *s, int decl_mask) if (s->token.val == '[') { /* let [ is a syntax restriction: it never introduces an ExpressionStatement */ - res = TRUE; + res = true; break; } if (s->token.val == '{' || @@ -26383,7 +25314,7 @@ static int is_let(JSParseState *s, int decl_mask) /* XXX: should also check that `{` introduces a BindingPattern, but Firefox does not and rejects eval("let=1;let\n{if(1)2;}") */ if (s->last_line_num == s->token.line_num || (decl_mask & DECL_MASK_OTHER)) { - res = TRUE; + res = true; break; } break; @@ -26400,20 +25331,20 @@ static int is_let(JSParseState *s, int decl_mask) /* XXX: handle IteratorClose when exiting the loop before the enumeration is done */ static __exception int js_parse_for_in_of(JSParseState *s, int label_name, - BOOL is_async) + bool is_async) { JSContext *ctx = s->ctx; JSFunctionDef *fd = s->cur_func; JSAtom var_name; - BOOL has_initializer, is_for_of, has_destructuring; + bool has_initializer, is_for_of, has_destructuring; int tok, tok1, opcode, scope, block_scope_level; int label_next, label_expr, label_cont, label_body, label_break; int pos_next, pos_expr; BlockEnv break_entry; - has_initializer = FALSE; - has_destructuring = FALSE; - is_for_of = FALSE; + has_initializer = false; + has_destructuring = false; + is_for_of = false; block_scope_level = fd->scope_level; label_cont = new_label(s); label_body = new_label(s); @@ -26438,10 +25369,10 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name, tok = s->token.val; switch (is_let(s, DECL_MASK_OTHER)) { - case TRUE: + case true: tok = TOK_LET; break; - case FALSE: + case false: break; default: return -1; @@ -26452,9 +25383,9 @@ 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) < 0) + if (js_parse_destructuring_element(s, tok, 0, true, -1, false, false) < 0) return -1; - has_destructuring = TRUE; + has_destructuring = true; } else { return js_parse_error(s, "variable name expected"); } @@ -26474,24 +25405,23 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name, emit_atom(s, var_name); emit_u16(s, fd->scope_level); } - } else if (!is_async && token_is_pseudo_keyword(s, JS_ATOM_async) && - peek_token(s, FALSE) == TOK_OF) { + } else if (!is_async && token_is_pseudo_keyword(s, JS_ATOM_async) && peek_token(s, false) == TOK_OF) { return js_parse_error(s, "'for of' expression cannot start with 'async'"); } else { 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) < 0) + && ((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, false) < 0) return -1; } else { int lvalue_label; if (js_parse_left_hand_side_expr(s)) return -1; if (get_lvalue(s, &opcode, &scope, &var_name, &lvalue_label, - NULL, FALSE, TOK_FOR)) + NULL, false, TOK_FOR)) return -1; put_lvalue(s, opcode, scope, var_name, lvalue_label, - PUT_LVALUE_NOKEEP_BOTTOM, FALSE); + PUT_LVALUE_NOKEEP_BOTTOM, false); } var_name = JS_ATOM_NULL; } @@ -26501,7 +25431,7 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name, emit_label(s, label_expr); if (s->token.val == '=') { /* XXX: potential scoping issue if inside `with` statement */ - has_initializer = TRUE; + has_initializer = true; /* parse and evaluate initializer prior to evaluating the object (only used with "for in" with a non lexical variable in non strict mode */ @@ -26518,7 +25448,8 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name, JS_FreeAtom(ctx, var_name); if (token_is_pseudo_keyword(s, JS_ATOM_of)) { - break_entry.has_iterator = is_for_of = TRUE; + is_for_of = true; + break_entry.has_iterator = true; break_entry.drop_count += 2; if (has_initializer) goto initializer_error; @@ -26526,8 +25457,7 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name, if (is_async) return js_parse_error(s, "'for await' loop should be used with 'of'"); if (has_initializer && - (tok != TOK_VAR || (fd->js_mode & JS_MODE_STRICT) || - has_destructuring)) { + (tok != TOK_VAR || fd->is_strict_mode || has_destructuring)) { initializer_error: return js_parse_error(s, "a declaration in the head of a for-%s loop can't have an initializer", is_for_of ? "of" : "in"); @@ -26562,7 +25492,7 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name, if (js_parse_expect(s, ')')) return -1; - if (OPTIMIZE) { + { /* move the `next` code here */ DynBuf *bc = &s->cur_func->byte_code; int chunk_size = pos_expr - pos_next; @@ -26663,13 +25593,14 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, && s->token.val != TOK_DO && s->token.val != TOK_WHILE) { /* labelled regular statement */ + JSFunctionDef *fd = s->cur_func; int label_break, mask; BlockEnv break_entry; label_break = new_label(s); - push_break_entry(s->cur_func, &break_entry, - label_name, label_break, -1, 0); - if (!(s->cur_func->js_mode & JS_MODE_STRICT) && + push_break_entry(fd, &break_entry, label_name, label_break, -1, 0); + fd->top_break->is_regular_stmt = 1; + if (!fd->is_strict_mode && (decl_mask & DECL_MASK_FUNC_WITH_LABEL)) { mask = DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL; } else { @@ -26678,7 +25609,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, if (js_parse_statement_or_decl(s, mask)) goto fail; emit_label(s, label_break); - pop_break_entry(s->cur_func); + pop_break_entry(fd); goto done; } } @@ -26702,9 +25633,9 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, if (s->token.val != ';' && s->token.val != '}' && !s->got_lf) { if (js_parse_expr(s)) goto fail; - emit_return(s, TRUE); + emit_return(s, true); } else { - emit_return(s, FALSE); + emit_return(s, false); } if (js_parse_expect_semi(s)) goto fail; @@ -26716,6 +25647,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, js_parse_error(s, "line terminator not allowed after throw"); goto fail; } + emit_source_loc(s); if (js_parse_expr(s)) goto fail; emit_op(s, OP_throw); @@ -26733,7 +25665,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, case TOK_VAR: if (next_token(s)) goto fail; - if (js_parse_var(s, TRUE, tok, FALSE)) + if (js_parse_var(s, true, tok, false)) goto fail; if (js_parse_expect_semi(s)) goto fail; @@ -26749,7 +25681,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, if (js_parse_expr_paren(s)) goto fail; label1 = emit_goto(s, OP_if_false, -1); - if (s->cur_func->js_mode & JS_MODE_STRICT) + if (s->cur_func->is_strict_mode) mask = 0; else mask = DECL_MASK_FUNC; /* Annex B.3.4 */ @@ -26847,25 +25779,25 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, int pos_cont, pos_body, block_scope_level; BlockEnv break_entry; int tok, bits; - BOOL is_async; + bool is_async; if (next_token(s)) goto fail; set_eval_ret_undefined(s); bits = 0; - is_async = FALSE; + is_async = false; if (s->token.val == '(') { - js_parse_skip_parens_token(s, &bits, FALSE); + js_parse_skip_parens_token(s, &bits, false); } else if (s->token.val == TOK_AWAIT) { if (!(s->cur_func->func_kind & JS_FUNC_ASYNC)) { js_parse_error(s, "for await is only valid in asynchronous functions"); goto fail; } - is_async = TRUE; + is_async = true; if (next_token(s)) goto fail; - s->cur_func->has_await = TRUE; + s->cur_func->has_await = true; } if (js_parse_expect(s, '(')) goto fail; @@ -26885,10 +25817,10 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, tok = s->token.val; if (tok != ';') { switch (is_let(s, DECL_MASK_OTHER)) { - case TRUE: + case true: tok = TOK_LET; break; - case FALSE: + case false: break; default: goto fail; @@ -26896,10 +25828,10 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_CONST) { if (next_token(s)) goto fail; - if (js_parse_var(s, FALSE, tok, FALSE)) + if (js_parse_var(s, false, tok, false)) goto fail; } else { - if (js_parse_expr2(s, FALSE)) + if (js_parse_expr2(s, false)) goto fail; emit_op(s, OP_drop); } @@ -26959,7 +25891,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, /* XXX: check continue case */ close_scopes(s, s->cur_func->scope_level, block_scope_level); - if (OPTIMIZE && label_test != label_body && label_cont != label_test) { + if (label_test != label_body && label_cont != label_test) { /* move the increment code here */ DynBuf *bc = &s->cur_func->byte_code; int chunk_size = pos_body - pos_cont; @@ -27158,7 +26090,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) < 0) + if (js_parse_destructuring_element(s, TOK_LET, 0, true, -1, true, false) < 0) goto fail; } else { js_parse_error(s, "identifier expected"); @@ -27267,7 +26199,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, goto fail; break; case TOK_WITH: - if (s->cur_func->js_mode & JS_MODE_STRICT) { + if (s->cur_func->is_strict_mode) { js_parse_error(s, "invalid keyword: with"); goto fail; } else { @@ -27300,7 +26232,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, /* ES6 Annex B.3.2 and B.3.3 semantics */ if (!(decl_mask & DECL_MASK_FUNC)) goto func_decl_error; - if (!(decl_mask & DECL_MASK_OTHER) && peek_token(s, FALSE) == '*') + if (!(decl_mask & DECL_MASK_OTHER) && peek_token(s, false) == '*') goto func_decl_error; goto parse_func_var; case TOK_IDENT: @@ -27310,16 +26242,16 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, } /* Determine if `let` introduces a Declaration or an ExpressionStatement */ switch (is_let(s, decl_mask)) { - case TRUE: + case true: tok = TOK_LET; goto haslet; - case FALSE: + case false: break; default: goto fail; } if (token_is_pseudo_keyword(s, JS_ATOM_async) && - peek_token(s, TRUE) == TOK_FUNCTION) { + peek_token(s, true) == TOK_FUNCTION) { if (!(decl_mask & DECL_MASK_OTHER)) { func_decl_error: js_parse_error(s, "function declarations can't appear in single-statement context"); @@ -27328,7 +26260,9 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, parse_func_var: if (js_parse_function_decl(s, JS_PARSE_FUNC_VAR, JS_FUNC_NORMAL, JS_ATOM_NULL, - s->token.ptr, s->token.line_num)) + s->token.ptr, + s->token.line_num, + s->token.col_num)) goto fail; break; } @@ -27339,7 +26273,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, js_parse_error(s, "class declarations can't appear in single-statement context"); goto fail; } - if (js_parse_class(s, FALSE, JS_PARSE_EXPORT_NONE)) + if (js_parse_class(s, false, JS_PARSE_EXPORT_NONE)) return -1; break; @@ -27359,6 +26293,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, default: hasexpr: + emit_source_loc(s); if (js_parse_expr(s)) goto fail; if (s->cur_func->eval_ret_idx >= 0) { @@ -27490,7 +26425,7 @@ static int add_req_module_entry(JSContext *ctx, JSModuleDef *m, return i; } -static JSExportEntry *find_export_entry(JSContext *ctx, JSModuleDef *m, +static JSExportEntry *find_export_entry(JSContext *ctx, const JSModuleDef *m, JSAtom export_name) { JSExportEntry *me; @@ -27558,6 +26493,7 @@ static int add_star_export_entry(JSContext *ctx, JSModuleDef *m, } /* create a C module */ +/* `name_str` may be pure ASCII or UTF-8 encoded */ JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str, JSModuleInitFunc *func) { @@ -27571,6 +26507,7 @@ JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str, return m; } +/* `export_name` may be pure ASCII or UTF-8 encoded */ int JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name) { JSExportEntry *me; @@ -27587,6 +26524,7 @@ int JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name) return 0; } +/* `export_name` may be pure ASCII or UTF-8 encoded */ int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name, JSValue val) { @@ -27669,8 +26607,8 @@ static char *js_default_module_normalize_name(JSContext *ctx, } } if (filename[0] != '\0') - pstrcat(filename, cap, "/"); - pstrcat(filename, cap, r); + js__pstrcat(filename, cap, "/"); + js__pstrcat(filename, cap, r); // printf("normalize: %s %s -> %s\n", base_name, name, filename); return filename; } @@ -27690,6 +26628,7 @@ static JSModuleDef *js_find_loaded_module(JSContext *ctx, JSAtom name) } /* return NULL in case of exception (e.g. module could not be loaded) */ +/* `base_cname` and `cname1` may be pure ASCII or UTF-8 encoded */ static JSModuleDef *js_host_resolve_imported_module(JSContext *ctx, const char *base_cname, const char *cname1) @@ -27727,6 +26666,7 @@ static JSModuleDef *js_host_resolve_imported_module(JSContext *ctx, /* load the module */ if (!rt->module_loader_func) { /* XXX: use a syntax error ? */ + // XXX: update JS_DetectModule when you change this JS_ThrowReferenceError(ctx, "could not load module '%s'", cname); js_free(ctx, cname); @@ -27972,7 +26912,7 @@ static int find_exported_name(GetExportNamesState *s, JSAtom name) static __exception int get_exported_names(JSContext *ctx, GetExportNamesState *s, - JSModuleDef *m, BOOL from_star) + JSModuleDef *m, bool from_star) { ExportedNameEntry *en; int i, j; @@ -28013,14 +26953,14 @@ static __exception int get_exported_names(JSContext *ctx, JSStarExportEntry *se = &m->star_export_entries[i]; JSModuleDef *m1; m1 = m->req_module_entries[se->req_module_idx].module; - if (get_exported_names(ctx, s, m1, TRUE)) + if (get_exported_names(ctx, s, m1, true)) return -1; } return 0; } /* Unfortunately, the spec gives a different behavior from GetOwnProperty ! */ -static int js_module_ns_has(JSContext *ctx, JSValueConst obj, JSAtom atom) +static int js_module_ns_has(JSContext *ctx, JSValue obj, JSAtom atom) { return (find_own_property1(JS_VALUE_GET_OBJ(obj), atom) != NULL); } @@ -28044,7 +26984,7 @@ static int exported_names_cmp(const void *p1, const void *p2, void *opaque) /* XXX: raise an error ? */ ret = 0; } else { - ret = js_string_compare(ctx, JS_VALUE_GET_STRING(str1), + ret = js_string_compare(JS_VALUE_GET_STRING(str1), JS_VALUE_GET_STRING(str2)); } JS_FreeValue(ctx, str1); @@ -28073,7 +27013,7 @@ static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m) p = JS_VALUE_GET_OBJ(obj); memset(s, 0, sizeof(*s)); - ret = get_exported_names(ctx, s, m, FALSE); + ret = get_exported_names(ctx, s, m, false); js_free(ctx, s->modules); if (ret) goto fail; @@ -28109,6 +27049,7 @@ static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m) en->u.var_ref = res_me->u.local.var_ref; } else { JSObject *p1 = JS_VALUE_GET_OBJ(res_m->func_obj); + p1 = JS_VALUE_GET_OBJ(res_m->func_obj); en->u.var_ref = p1->u.func.var_refs[res_me->u.local.var_idx]; } } @@ -28125,6 +27066,11 @@ static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m) case EXPORTED_NAME_NORMAL: { JSVarRef *var_ref = en->u.var_ref; + if (!var_ref) { + js_resolve_export_throw_error(ctx, JS_RESOLVE_RES_CIRCULAR, + m, en->export_name); + goto fail; + } pr = add_property(ctx, p, en->export_name, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_VARREF); @@ -28153,7 +27099,7 @@ static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m) JS_AtomToString(ctx, JS_ATOM_Module), 0); - p->extensible = FALSE; + p->extensible = false; return obj; fail: js_free(ctx, s->exported_names); @@ -28170,9 +27116,19 @@ JSValue JS_GetModuleNamespace(JSContext *ctx, JSModuleDef *m) return JS_EXCEPTION; m->module_ns = val; } - return JS_DupValue(ctx, m->module_ns); + return js_dup(m->module_ns); } +#ifdef ENABLE_DUMPS // JS_DUMP_MODULE_RESOLVE +#define module_trace(ctx, ...) \ + do { \ + if (check_dump_flag(ctx->rt, JS_DUMP_MODULE_RESOLVE)) \ + printf(__VA_ARGS__); \ + } while (0) +#else +#define module_trace(...) +#endif + /* Load all the required modules for module 'm' */ static int js_resolve_module(JSContext *ctx, JSModuleDef *m) { @@ -28181,13 +27137,13 @@ static int js_resolve_module(JSContext *ctx, JSModuleDef *m) if (m->resolved) return 0; -#ifdef DUMP_MODULE_RESOLVE - { +#ifdef ENABLE_DUMPS // JS_DUMP_MODULE_RESOLVE + if (check_dump_flag(ctx->rt, JS_DUMP_MODULE_RESOLVE)) { char buf1[ATOM_GET_STR_BUF_SIZE]; printf("resolving module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); } #endif - m->resolved = TRUE; + m->resolved = true; /* resolve each requested module */ for(i = 0; i < m->req_module_entries_count; i++) { JSReqModuleEntry *rme = &m->req_module_entries[i]; @@ -28204,7 +27160,7 @@ static int js_resolve_module(JSContext *ctx, JSModuleDef *m) return 0; } -static JSVarRef *js_create_module_var(JSContext *ctx, BOOL is_lexical) +static JSVarRef *js_create_module_var(JSContext *ctx, bool is_lexical) { JSVarRef *var_ref; var_ref = js_malloc(ctx, sizeof(JSVarRef)); @@ -28216,7 +27172,7 @@ static JSVarRef *js_create_module_var(JSContext *ctx, BOOL is_lexical) else var_ref->value = JS_UNDEFINED; var_ref->pvalue = &var_ref->value; - var_ref->is_detached = TRUE; + var_ref->is_detached = true; add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF); return var_ref; } @@ -28258,9 +27214,9 @@ static int js_create_module_bytecode_function(JSContext *ctx, JSModuleDef *m) var_ref = js_create_module_var(ctx, cv->is_lexical); if (!var_ref) goto fail; -#ifdef DUMP_MODULE_RESOLVE - printf("local %d: %p\n", i, var_ref); -#endif + + module_trace(ctx, "local %d: %p\n", i, var_ref); + var_refs[i] = var_ref; } } @@ -28276,7 +27232,7 @@ static int js_create_module_bytecode_function(JSContext *ctx, JSModuleDef *m) /* 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; + bool is_c_module; int i; JSVarRef *var_ref; @@ -28290,7 +27246,7 @@ static int js_create_module_function(JSContext *ctx, JSModuleDef *m) for(i = 0; i < m->export_entries_count; i++) { JSExportEntry *me = &m->export_entries[i]; if (me->export_type == JS_EXPORT_TYPE_LOCAL) { - var_ref = js_create_module_var(ctx, FALSE); + var_ref = js_create_module_var(ctx, false); if (!var_ref) return -1; me->u.local.var_ref = var_ref; @@ -28300,7 +27256,7 @@ static int js_create_module_function(JSContext *ctx, JSModuleDef *m) if (js_create_module_bytecode_function(ctx, m)) return -1; } - m->func_created = TRUE; + m->func_created = true; /* do it on the dependencies */ @@ -28324,7 +27280,7 @@ static int js_inner_module_linking(JSContext *ctx, JSModuleDef *m, JSModuleDef *m1; JSVarRef **var_refs, *var_ref; JSObject *p; - BOOL is_c_module; + bool is_c_module; JSValue ret_val; if (js_check_stack_overflow(ctx->rt, 0)) { @@ -28332,8 +27288,8 @@ static int js_inner_module_linking(JSContext *ctx, JSModuleDef *m, return -1; } -#ifdef DUMP_MODULE_RESOLVE - { +#ifdef ENABLE_DUMPS // JS_DUMP_MODULE_RESOLVE + if (check_dump_flag(ctx->rt, JS_DUMP_MODULE_RESOLVE)) { char buf1[ATOM_GET_STR_BUF_SIZE]; printf("js_inner_module_linking '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); } @@ -28370,8 +27326,8 @@ static int js_inner_module_linking(JSContext *ctx, JSModuleDef *m, } } -#ifdef DUMP_MODULE_RESOLVE - { +#ifdef ENABLE_DUMPS // JS_DUMP_MODULE_RESOLVE + if (check_dump_flag(ctx->rt, JS_DUMP_MODULE_RESOLVE)) { char buf1[ATOM_GET_STR_BUF_SIZE]; printf("instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); } @@ -28393,8 +27349,8 @@ static int js_inner_module_linking(JSContext *ctx, JSModuleDef *m, } } -#ifdef DUMP_MODULE_RESOLVE - { +#ifdef ENABLE_DUMPS // JS_DUMP_MODULE_RESOLVE + if (check_dump_flag(ctx->rt, JS_DUMP_MODULE_RESOLVE)) { printf("exported bindings:\n"); for(i = 0; i < m->export_entries_count; i++) { JSExportEntry *me = &m->export_entries[i]; @@ -28413,10 +27369,12 @@ static int js_inner_module_linking(JSContext *ctx, JSModuleDef *m, for(i = 0; i < m->import_entries_count; i++) { mi = &m->import_entries[i]; -#ifdef DUMP_MODULE_RESOLVE - printf("import var_idx=%d name=", mi->var_idx); - print_atom(ctx, mi->import_name); - printf(": "); +#ifdef ENABLE_DUMPS // JS_DUMP_MODULE_RESOLVE + if (check_dump_flag(ctx->rt, JS_DUMP_MODULE_RESOLVE)) { + printf("import var_idx=%d name=", mi->var_idx); + print_atom(ctx, mi->import_name); + printf(": "); + } #endif m1 = m->req_module_entries[mi->req_module_idx].module; if (mi->import_name == JS_ATOM__star_) { @@ -28426,9 +27384,9 @@ static int js_inner_module_linking(JSContext *ctx, JSModuleDef *m, if (JS_IsException(val)) goto fail; set_value(ctx, &var_refs[mi->var_idx]->value, val); -#ifdef DUMP_MODULE_RESOLVE - printf("namespace\n"); -#endif + + module_trace(ctx, "namespace\n"); + } else { JSResolveResultEnum ret; JSExportEntry *res_me; @@ -28449,16 +27407,16 @@ static int js_inner_module_linking(JSContext *ctx, JSModuleDef *m, val = JS_GetModuleNamespace(ctx, m2); if (JS_IsException(val)) goto fail; - var_ref = js_create_module_var(ctx, TRUE); + var_ref = js_create_module_var(ctx, true); if (!var_ref) { JS_FreeValue(ctx, val); goto fail; } set_value(ctx, &var_ref->value, val); var_refs[mi->var_idx] = var_ref; -#ifdef DUMP_MODULE_RESOLVE - printf("namespace from\n"); -#endif + + module_trace(ctx, "namespace from\n"); + } else { var_ref = res_me->u.local.var_ref; if (!var_ref) { @@ -28467,9 +27425,8 @@ static int js_inner_module_linking(JSContext *ctx, JSModuleDef *m, } var_ref->header.ref_count++; var_refs[mi->var_idx] = var_ref; -#ifdef DUMP_MODULE_RESOLVE - printf("local export (var_ref=%p)\n", var_ref); -#endif + + module_trace(ctx, "local export (var_ref=%p)\n", var_ref); } } } @@ -28505,8 +27462,10 @@ static int js_inner_module_linking(JSContext *ctx, JSModuleDef *m, } } -#ifdef DUMP_MODULE_RESOLVE - printf("js_inner_module_linking done\n"); +#ifdef ENABLE_DUMPS // JS_DUMP_MODULE_RESOLVE + if (check_dump_flag(ctx->rt, JS_DUMP_MODULE_RESOLVE)) { + printf("js_inner_module_linking done\n"); + } #endif return index; fail: @@ -28519,8 +27478,8 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m) { JSModuleDef *stack_top, *m1; -#ifdef DUMP_MODULE_RESOLVE - { +#ifdef ENABLE_DUMPS // JS_DUMP_MODULE_RESOLVE + if (check_dump_flag(ctx->rt, JS_DUMP_MODULE_RESOLVE)) { char buf1[ATOM_GET_STR_BUF_SIZE]; printf("js_link_module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); } @@ -28554,8 +27513,8 @@ JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels) JSFunctionBytecode *b; JSObject *p; /* XXX: currently we just use the filename of the englobing - function from the debug info. May need to add a ScriptOrModule - info in JSFunctionBytecode. */ + function. It does not work for eval(). Need to add a + ScriptOrModule info in JSFunctionBytecode */ sf = ctx->rt->current_stack_frame; if (!sf) return JS_ATOM_NULL; @@ -28564,23 +27523,13 @@ JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels) if (!sf) return JS_ATOM_NULL; } - for(;;) { - if (JS_VALUE_GET_TAG(sf->cur_func) != JS_TAG_OBJECT) - return JS_ATOM_NULL; - p = JS_VALUE_GET_OBJ(sf->cur_func); - if (!js_class_has_bytecode(p->class_id)) - return JS_ATOM_NULL; - b = p->u.func.function_bytecode; - if (!b->is_direct_or_indirect_eval) { - if (!b->has_debug) - return JS_ATOM_NULL; - return JS_DupAtom(ctx, b->debug.filename); - } else { - sf = sf->prev_frame; - if (!sf) - return JS_ATOM_NULL; - } - } + if (JS_VALUE_GET_TAG(sf->cur_func) != JS_TAG_OBJECT) + return JS_ATOM_NULL; + p = JS_VALUE_GET_OBJ(sf->cur_func); + if (!js_class_has_bytecode(p->class_id)) + return JS_ATOM_NULL; + b = p->u.func.function_bytecode; + return JS_DupAtom(ctx, b->filename); } JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m) @@ -28599,7 +27548,7 @@ JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m) return JS_EXCEPTION; m->meta_obj = obj; } - return JS_DupValue(ctx, obj); + return js_dup(obj); } static JSValue js_import_meta(JSContext *ctx) @@ -28730,11 +27679,11 @@ JSValue JS_LoadModule(JSContext *ctx, const char *basename, } static JSValue js_dynamic_import_job(JSContext *ctx, - int argc, JSValueConst *argv) + int argc, JSValue *argv) { - JSValueConst *resolving_funcs = argv; - JSValueConst basename_val = argv[2]; - JSValueConst specifier = argv[3]; + JSValue *resolving_funcs = argv; + JSValue basename_val = argv[2]; + JSValue specifier = argv[3]; const char *basename = NULL, *filename; JSValue ret, err; @@ -28758,18 +27707,18 @@ static JSValue js_dynamic_import_job(JSContext *ctx, exception: err = JS_GetException(ctx); ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, - 1, (JSValueConst *)&err); + 1, &err); JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */ JS_FreeValue(ctx, err); JS_FreeCString(ctx, basename); return JS_UNDEFINED; } -static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier) +static JSValue js_dynamic_import(JSContext *ctx, JSValue specifier) { JSAtom basename; JSValue promise, resolving_funcs[2], basename_val; - JSValueConst args[4]; + JSValue args[4]; basename = JS_GetScriptOrModuleName(ctx, 0); if (basename == JS_ATOM_NULL) @@ -28821,14 +27770,14 @@ typedef struct { } ExecModuleList; /* XXX: slow. Could use a linked list instead of ExecModuleList */ -static BOOL find_in_exec_module_list(ExecModuleList *exec_list, JSModuleDef *m) +static bool find_in_exec_module_list(ExecModuleList *exec_list, JSModuleDef *m) { int i; for(i = 0; i < exec_list->count; i++) { if (exec_list->tab[i] == m) - return TRUE; + return true; } - return FALSE; + return false; } static int gather_available_ancestors(JSContext *ctx, JSModuleDef *module, @@ -28895,7 +27844,7 @@ static JSValue js_async_module_execution_rejected(JSContext *ctx, JSValueConst t assert(!module->eval_has_exception); assert(module->async_evaluation); - module->eval_has_exception = TRUE; + module->eval_has_exception = true; module->eval_exception = JS_DupValue(ctx, error); module->status = JS_MODULE_STATUS_EVALUATED; @@ -28931,7 +27880,7 @@ static JSValue js_async_module_execution_fulfilled(JSContext *ctx, JSValueConst assert(module->status == JS_MODULE_STATUS_EVALUATING_ASYNC); assert(!module->eval_has_exception); assert(module->async_evaluation); - module->async_evaluation = FALSE; + module->async_evaluation = false; js_set_module_evaluated(ctx, module); exec_list->tab = NULL; @@ -29039,8 +27988,8 @@ static int js_inner_module_evaluation(JSContext *ctx, JSModuleDef *m, return -1; } -#ifdef DUMP_MODULE_RESOLVE - { +#ifdef ENABLE_DUMPS // JS_DUMP_MODULE_RESOLVE + if (check_dump_flag(ctx->rt, JS_DUMP_MODULE_RESOLVE)) { char buf1[ATOM_GET_STR_BUF_SIZE]; printf("js_inner_module_evaluation '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); } @@ -29104,12 +28053,12 @@ static int js_inner_module_evaluation(JSContext *ctx, JSModuleDef *m, if (m->pending_async_dependencies > 0) { assert(!m->async_evaluation); - m->async_evaluation = TRUE; + m->async_evaluation = true; m->async_evaluation_timestamp = ctx->rt->module_async_evaluation_next_timestamp++; } else if (m->has_tla) { assert(!m->async_evaluation); - m->async_evaluation = TRUE; + m->async_evaluation = true; m->async_evaluation_timestamp = ctx->rt->module_async_evaluation_next_timestamp++; js_execute_async_module(ctx, m); @@ -29166,7 +28115,7 @@ static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m) m1 = stack_top; assert(m1->status == JS_MODULE_STATUS_EVALUATING); m1->status = JS_MODULE_STATUS_EVALUATED; - m1->eval_has_exception = TRUE; + m1->eval_has_exception = true; m1->eval_exception = JS_DupValue(ctx, result); m1->cycle_root = m; /* spec bug: should be present */ stack_top = m1->stack_prev; @@ -29231,13 +28180,15 @@ static __exception int js_parse_export(JSParseState *s) tok = s->token.val; if (tok == TOK_CLASS) { - return js_parse_class(s, FALSE, JS_PARSE_EXPORT_NAMED); + return js_parse_class(s, false, JS_PARSE_EXPORT_NAMED); } else if (tok == TOK_FUNCTION || (token_is_pseudo_keyword(s, JS_ATOM_async) && - peek_token(s, TRUE) == TOK_FUNCTION)) { + peek_token(s, true) == TOK_FUNCTION)) { return js_parse_function_decl2(s, JS_PARSE_FUNC_STATEMENT, JS_FUNC_NORMAL, JS_ATOM_NULL, - s->token.ptr, s->token.line_num, + s->token.ptr, + s->token.line_num, + s->token.col_num, JS_PARSE_EXPORT_NAMED, NULL); } @@ -29341,13 +28292,15 @@ static __exception int js_parse_export(JSParseState *s) break; case TOK_DEFAULT: if (s->token.val == TOK_CLASS) { - return js_parse_class(s, FALSE, JS_PARSE_EXPORT_DEFAULT); + return js_parse_class(s, false, JS_PARSE_EXPORT_DEFAULT); } else if (s->token.val == TOK_FUNCTION || (token_is_pseudo_keyword(s, JS_ATOM_async) && - peek_token(s, TRUE) == TOK_FUNCTION)) { + peek_token(s, true) == TOK_FUNCTION)) { return js_parse_function_decl2(s, JS_PARSE_FUNC_STATEMENT, JS_FUNC_NORMAL, JS_ATOM_NULL, - s->token.ptr, s->token.line_num, + s->token.ptr, + s->token.line_num, + s->token.col_num, JS_PARSE_EXPORT_DEFAULT, NULL); } else { if (js_parse_assign_expr(s)) @@ -29372,7 +28325,7 @@ static __exception int js_parse_export(JSParseState *s) case TOK_VAR: case TOK_LET: case TOK_CONST: - return js_parse_var(s, TRUE, tok, TRUE); + return js_parse_var(s, true, tok, true); default: return js_parse_error(s, "invalid export syntax"); } @@ -29380,9 +28333,9 @@ static __exception int js_parse_export(JSParseState *s) } static int add_closure_var(JSContext *ctx, JSFunctionDef *s, - BOOL is_local, BOOL is_arg, + bool is_local, bool is_arg, int var_idx, JSAtom var_name, - BOOL is_const, BOOL is_lexical, + bool is_const, bool is_lexical, JSVarKindEnum var_kind); static int add_import(JSParseState *s, JSModuleDef *m, @@ -29391,7 +28344,7 @@ static int add_import(JSParseState *s, JSModuleDef *m, JSContext *ctx = s->ctx; int i, var_idx; JSImportEntry *mi; - BOOL is_local; + bool is_local; if (local_name == JS_ATOM_arguments || local_name == JS_ATOM_eval) return js_parse_error(s, "invalid import binding"); @@ -29404,9 +28357,9 @@ static int add_import(JSParseState *s, JSModuleDef *m, } is_local = (import_name == JS_ATOM__star_); - var_idx = add_closure_var(ctx, s->cur_func, is_local, FALSE, + var_idx = add_closure_var(ctx, s->cur_func, is_local, false, m->import_entries_count, - local_name, TRUE, TRUE, FALSE); + local_name, true, true, JS_VAR_NORMAL); if (var_idx < 0) return -1; if (js_resize_array(ctx, (void **)&m->import_entries, @@ -29542,16 +28495,18 @@ static __exception int js_parse_source_element(JSParseState *s) if (s->token.val == TOK_FUNCTION || (token_is_pseudo_keyword(s, JS_ATOM_async) && - peek_token(s, TRUE) == TOK_FUNCTION)) { + peek_token(s, true) == TOK_FUNCTION)) { if (js_parse_function_decl(s, JS_PARSE_FUNC_STATEMENT, JS_FUNC_NORMAL, JS_ATOM_NULL, - s->token.ptr, s->token.line_num)) + s->token.ptr, + s->token.line_num, + s->token.col_num)) return -1; } else if (s->token.val == TOK_EXPORT && fd->module) { if (js_parse_export(s)) return -1; } else if (s->token.val == TOK_IMPORT && fd->module && - ((tok = peek_token(s, FALSE)) != '(' && tok != '.')) { + ((tok = peek_token(s, false)) != '(' && tok != '.')) { /* the peek_token is needed to avoid confusion with ImportCall (dynamic import) or import.meta */ if (js_parse_import(s)) @@ -29563,11 +28518,14 @@ static __exception int js_parse_source_element(JSParseState *s) return 0; } +/* `filename` may be pure ASCII or UTF-8 encoded */ static JSFunctionDef *js_new_function_def(JSContext *ctx, JSFunctionDef *parent, - BOOL is_eval, - BOOL is_func_expr, - const char *filename, int line_num) + bool is_eval, + bool is_func_expr, + const char *filename, + int line_num, + int col_num) { JSFunctionDef *fd; @@ -29583,7 +28541,7 @@ static JSFunctionDef *js_new_function_def(JSContext *ctx, fd->parent_cpool_idx = -1; if (parent) { list_add_tail(&fd->link, &parent->child_list); - fd->js_mode = parent->js_mode; + fd->is_strict_mode = parent->is_strict_mode; fd->parent_scope_level = parent->scope_level; } @@ -29615,18 +28573,19 @@ static JSFunctionDef *js_new_function_def(JSContext *ctx, fd->filename = JS_NewAtom(ctx, filename); fd->line_num = line_num; + fd->col_num = col_num; js_dbuf_init(ctx, &fd->pc2line); //fd->pc2line_last_line_num = line_num; //fd->pc2line_last_pc = 0; - fd->last_opcode_line_num = line_num; + fd->ic = init_ic(ctx); return fd; } static void free_bytecode_atoms(JSRuntime *rt, const uint8_t *bc_buf, int bc_len, - BOOL use_short_opcodes) + bool use_short_opcodes) { int pos, len, op; JSAtom atom; @@ -29674,7 +28633,11 @@ static void js_free_function_def(JSContext *ctx, JSFunctionDef *fd) dbuf_free(&fd->byte_code); js_free(ctx, fd->jump_slots); js_free(ctx, fd->label_slots); - js_free(ctx, fd->line_number_slots); + js_free(ctx, fd->source_loc_slots); + + /* free ic */ + if (fd->ic) + free_ic(ctx->rt, fd->ic); for(i = 0; i < fd->cpool_count; i++) { JS_FreeValue(ctx, fd->cpool[i]); @@ -29687,6 +28650,7 @@ static void js_free_function_def(JSContext *ctx, JSFunctionDef *fd) JS_FreeAtom(ctx, fd->vars[i].var_name); } js_free(ctx, fd->vars); + js_free(ctx, fd->vars_htab); // XXX can probably be freed earlier? for(i = 0; i < fd->arg_count; i++) { JS_FreeAtom(ctx, fd->args[i].var_name); } @@ -29718,9 +28682,9 @@ static void js_free_function_def(JSContext *ctx, JSFunctionDef *fd) js_free(ctx, fd); } -#ifdef DUMP_BYTECODE +#ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_* static const char *skip_lines(const char *p, int n) { - while (n-- > 0 && *p) { + while (p && n-- > 0 && *p) { while (*p && *p++ != '\n') continue; } @@ -29730,7 +28694,7 @@ static const char *skip_lines(const char *p, int n) { static void print_lines(const char *source, int line, int line1) { const char *s = source; const char *p = skip_lines(s, line); - if (*p) { + if (p && *p) { while (line++ < line1) { p = skip_lines(s = p, 1); printf(";; %.*s", (int)(p - s), s); @@ -29750,12 +28714,16 @@ static void dump_byte_code(JSContext *ctx, int pass, const JSClosureVar *closure_var, int closure_var_count, const JSValue *cpool, uint32_t cpool_count, const char *source, int line_num, - const LabelSlot *label_slots, JSFunctionBytecode *b) + const LabelSlot *label_slots, JSFunctionBytecode *b, + int start_pos) { const JSOpCode *oi; int pos, pos_next, op, size, idx, addr, line, line1, in_source; uint8_t *bits = js_mallocz(ctx, len * sizeof(*bits)); - BOOL use_short_opcodes = (b != NULL); + bool use_short_opcodes = (b != NULL); + + if (start_pos != 0 || bits == NULL) + goto no_labels; /* scan for jump targets */ for (pos = 0; pos < len; pos = pos_next) { @@ -29767,7 +28735,6 @@ static void dump_byte_code(JSContext *ctx, int pass, pos_next = pos + oi->size; if (op < OP_COUNT) { switch (oi->fmt) { -#if SHORT_OPCODES case OP_FMT_label8: pos++; addr = (int8_t)tab[pos]; @@ -29776,7 +28743,6 @@ static void dump_byte_code(JSContext *ctx, int pass, pos++; addr = (int16_t)get_u16(tab + pos); goto has_addr; -#endif case OP_FMT_atom_label_u8: case OP_FMT_atom_label_u16: pos += 4; @@ -29799,6 +28765,7 @@ static void dump_byte_code(JSContext *ctx, int pass, } } } + no_labels: in_source = 0; if (source) { /* Always print first line: needed if single line */ @@ -29811,8 +28778,9 @@ static void dump_byte_code(JSContext *ctx, int pass, op = tab[pos]; if (source) { if (b) { - line1 = find_line_num(ctx, b, pos) - line_num + 1; - } else if (op == OP_line_num) { + int col1; + line1 = find_line_num(ctx, b, pos, &col1) - line_num + 1; + } else if (op == OP_source_loc) { line1 = get_u32(tab + pos + 1) - line_num + 1; } if (line1 > line) { @@ -29841,8 +28809,8 @@ static void dump_byte_code(JSContext *ctx, int pass, printf("truncated opcode (0x%02x)\n", op); break; } -#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 16) - { +#ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_HEX + if (check_dump_flag(ctx->rt, JS_DUMP_BYTECODE_HEX)) { int i, x, x0; x = x0 = printf("%5d ", pos); for (i = 0; i < size; i++) { @@ -29854,12 +28822,12 @@ static void dump_byte_code(JSContext *ctx, int pass, printf("%*s", x0 + 20 - x, ""); } #endif - if (bits[pos]) { + if (bits && bits[pos]) { printf("%5d: ", pos); } else { printf(" "); } - printf("%s", oi->name); + printf("%-15s", oi->name); /* align opcode arguments */ pos++; switch(oi->fmt) { case OP_FMT_none_int: @@ -29890,47 +28858,42 @@ static void dump_byte_code(JSContext *ctx, int pass, case OP_FMT_u32: printf(" %u", get_u32(tab + pos)); break; -#if SHORT_OPCODES + case OP_FMT_u32x2: + printf(" %u:%u", get_u32(tab + pos), get_u32(tab + pos + 4)); + break; case OP_FMT_label8: addr = get_i8(tab + pos); goto has_addr1; case OP_FMT_label16: addr = get_i16(tab + pos); goto has_addr1; -#endif case OP_FMT_label: - addr = get_u32(tab + pos); - goto has_addr1; - has_addr1: - if (pass == 1) - printf(" %u:%u", addr, label_slots[addr].pos); - if (pass == 2) - printf(" %u:%u", addr, label_slots[addr].pos2); - if (pass == 3) - printf(" %u", addr + pos); - break; case OP_FMT_label_u16: addr = get_u32(tab + pos); + has_addr1: if (pass == 1) - printf(" %u:%u", addr, label_slots[addr].pos); + printf(" %d:%u", addr, label_slots[addr].pos); if (pass == 2) - printf(" %u:%u", addr, label_slots[addr].pos2); - if (pass == 3) - printf(" %u", addr + pos); - printf(",%u", get_u16(tab + pos + 4)); + printf(" %d:%u", addr, label_slots[addr].pos2); + if (pass == 3) { + if (start_pos) + printf(" %04x", addr + pos + start_pos); + else + printf(" %d", addr + pos); + } + if (oi->fmt == OP_FMT_label_u16) + printf(",%u", get_u16(tab + pos + 4)); break; -#if SHORT_OPCODES case OP_FMT_const8: idx = get_u8(tab + pos); goto has_pool_idx; -#endif case OP_FMT_const: idx = get_u32(tab + pos); goto has_pool_idx; has_pool_idx: - printf(" %u: ", idx); + printf(" %-4u ; ", idx); if (idx < cpool_count) { - JS_DumpValue(ctx, cpool[idx]); + JS_DumpValue(ctx->rt, cpool[idx]); } break; case OP_FMT_atom: @@ -29964,15 +28927,24 @@ static void dump_byte_code(JSContext *ctx, int pass, printf(",%u", get_u16(tab + pos + 8)); break; case OP_FMT_none_loc: - idx = (op - OP_get_loc0) % 4; - goto has_loc; + if (op == OP_get_loc0_loc1) { + printf(" 0, 1 ; "); + if (var_count > 0) + print_atom(ctx, vars[0].var_name); + if (var_count > 1) + print_atom(ctx, vars[1].var_name); + } else { + idx = (op - OP_get_loc0) % 4; + goto has_loc; + } + break; case OP_FMT_loc8: idx = get_u8(tab + pos); goto has_loc; case OP_FMT_loc: idx = get_u16(tab + pos); has_loc: - printf(" %d: ", idx); + printf(" %-4d ; ", idx); if (idx < var_count) { print_atom(ctx, vars[idx].var_name); } @@ -29983,7 +28955,7 @@ static void dump_byte_code(JSContext *ctx, int pass, case OP_FMT_arg: idx = get_u16(tab + pos); has_arg: - printf(" %d: ", idx); + printf(" %-4d ; ", idx); if (idx < arg_count) { print_atom(ctx, args[idx].var_name); } @@ -29994,7 +28966,7 @@ static void dump_byte_code(JSContext *ctx, int pass, case OP_FMT_var_ref: idx = get_u16(tab + pos); has_var_ref: - printf(" %d: ", idx); + printf(" %-4d ; ", idx); if (idx < closure_var_count) { print_atom(ctx, closure_var[idx].var_name); } @@ -30013,8 +28985,35 @@ static void dump_byte_code(JSContext *ctx, int pass, js_free(ctx, bits); } -static __maybe_unused void dump_pc2line(JSContext *ctx, const uint8_t *buf, int len, - int line_num) +// caveat emptor: intended to be called during execution of bytecode +// and only works for pass3 bytecode +static __maybe_unused void dump_single_byte_code(JSContext *ctx, + const uint8_t *pc, + JSFunctionBytecode *b, + int start_pos) +{ + JSVarDef *args, *vars; + + args = vars = b->vardefs; + if (vars) + vars = &vars[b->arg_count]; + + dump_byte_code(ctx, /*pass*/3, pc, short_opcode_info(*pc).size, + args, b->arg_count, vars, b->var_count, + b->closure_var, b->closure_var_count, + b->cpool, b->cpool_count, + NULL, b->line_num, + NULL, b, start_pos); +} + +static __maybe_unused void print_func_name(JSFunctionBytecode *b) +{ + print_lines(b->source, 0, 1); +} + +static __maybe_unused void dump_pc2line(JSContext *ctx, + const uint8_t *buf, int len, + int line_num, int col_num) { const uint8_t *p_end, *p_next, *p; int pc, v; @@ -30023,7 +29022,7 @@ static __maybe_unused void dump_pc2line(JSContext *ctx, const uint8_t *buf, int if (len <= 0) return; - printf("%5s %5s\n", "PC", "LINE"); + printf("%5s %5s %5s\n", "PC", "LINE", "COLUMN"); p = buf; p_end = buf + len; @@ -30031,21 +29030,18 @@ static __maybe_unused void dump_pc2line(JSContext *ctx, const uint8_t *buf, int while (p < p_end) { op = *p++; if (op == 0) { - v = unicode_from_utf8(p, p_end - p, &p_next); + v = utf8_decode_len(p, p_end - p, &p_next); if (v < 0) goto fail; pc += v; p = p_next; - v = unicode_from_utf8(p, p_end - p, &p_next); - if (v < 0) { - fail: - printf("invalid pc2line encode pos=%d\n", (int)(p - buf)); - return; - } - if (!(v & 1)) { - v = v >> 1; - } else { + v = utf8_decode_len(p, p_end - p, &p_next); + if (v < 0) + goto fail; + if (v & 1) { v = -(v >> 1) - 1; + } else { + v = v >> 1; } line_num += v; p = p_next; @@ -30054,8 +29050,21 @@ static __maybe_unused void dump_pc2line(JSContext *ctx, const uint8_t *buf, int pc += (op / PC2LINE_RANGE); line_num += (op % PC2LINE_RANGE) + PC2LINE_BASE; } - printf("%5d %5d\n", pc, line_num); + v = utf8_decode_len(p, p_end - p, &p_next); + if (v < 0) + goto fail; + if (v & 1) { + v = -(v >> 1) - 1; + } else { + v = v >> 1; + } + col_num += v; + p = p_next; + printf("%5d %5d %5d\n", pc, line_num, col_num); } + return; +fail: + printf("invalid pc2line encode pos=%d\n", (int)(p - buf)); } static __maybe_unused void js_dump_function_bytecode(JSContext *ctx, JSFunctionBytecode *b) @@ -30064,23 +29073,14 @@ static __maybe_unused void js_dump_function_bytecode(JSContext *ctx, JSFunctionB char atom_buf[ATOM_GET_STR_BUF_SIZE]; const char *str; - if (b->has_debug && b->debug.filename != JS_ATOM_NULL) { - str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->debug.filename); - printf("%s:%d: ", str, b->debug.line_num); + if (b->filename != JS_ATOM_NULL) { + str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->filename); + printf("%s:%d:%d: ", str, b->line_num, b->col_num); } str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->func_name); printf("function: %s%s\n", &"*"[b->func_kind != JS_FUNC_GENERATOR], str); - if (b->js_mode) { - printf(" mode:"); - if (b->js_mode & JS_MODE_STRICT) - printf(" strict"); -#ifdef CONFIG_BIGNUM - if (b->js_mode & JS_MODE_MATH) - printf(" math"); -#endif - printf("\n"); - } + printf(" mode: %s\n", b->is_strict_mode ? "strict" : "sloppy"); if (b->arg_count && b->vardefs) { printf(" args:"); for(i = 0; i < b->arg_count; i++) { @@ -30124,27 +29124,28 @@ static __maybe_unused void js_dump_function_bytecode(JSContext *ctx, JSFunctionB b->vardefs ? b->vardefs + b->arg_count : NULL, b->var_count, b->closure_var, b->closure_var_count, b->cpool, b->cpool_count, - b->has_debug ? b->debug.source : NULL, - b->has_debug ? b->debug.line_num : -1, NULL, b); -#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 32) - if (b->has_debug) - dump_pc2line(ctx, b->debug.pc2line_buf, b->debug.pc2line_len, b->debug.line_num); + b->source, b->line_num, NULL, b, 0); +#ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_PC2LINE + if (check_dump_flag(ctx->rt, JS_DUMP_BYTECODE_PC2LINE)) + dump_pc2line(ctx, b->pc2line_buf, b->pc2line_len, b->line_num, b->col_num); #endif printf("\n"); } #endif static int add_closure_var(JSContext *ctx, JSFunctionDef *s, - BOOL is_local, BOOL is_arg, + bool is_local, bool is_arg, int var_idx, JSAtom var_name, - BOOL is_const, BOOL is_lexical, + bool is_const, bool is_lexical, JSVarKindEnum var_kind) { JSClosureVar *cv; /* the closure variable indexes are currently stored on 16 bits */ if (s->closure_var_count >= JS_MAX_LOCAL_VARS) { - JS_ThrowInternalError(ctx, "too many closure variables"); + // XXX: add_closure_var() should take JSParseState *s and use js_parse_error + JS_ThrowSyntaxError(ctx, "too many closure variables used (only %d allowed)", + JS_MAX_LOCAL_VARS - 1); return -1; } @@ -30176,12 +29177,12 @@ static int find_closure_var(JSContext *ctx, JSFunctionDef *s, } /* 'fd' must be a parent of 's'. Create in 's' a closure referencing a - local variable (is_local = TRUE) or a closure (is_local = FALSE) in + local variable (is_local = true) or a closure (is_local = false) in 'fd' */ static int get_closure_var2(JSContext *ctx, JSFunctionDef *s, - JSFunctionDef *fd, BOOL is_local, - BOOL is_arg, int var_idx, JSAtom var_name, - BOOL is_const, BOOL is_lexical, + JSFunctionDef *fd, bool is_local, + bool is_arg, int var_idx, JSAtom var_name, + bool is_const, bool is_lexical, JSVarKindEnum var_kind) { int i; @@ -30192,7 +29193,7 @@ static int get_closure_var2(JSContext *ctx, JSFunctionDef *s, is_const, is_lexical, var_kind); if (var_idx < 0) return -1; - is_local = FALSE; + is_local = false; } for(i = 0; i < s->closure_var_count; i++) { JSClosureVar *cv = &s->closure_var[i]; @@ -30205,12 +29206,12 @@ static int get_closure_var2(JSContext *ctx, JSFunctionDef *s, } static int get_closure_var(JSContext *ctx, JSFunctionDef *s, - JSFunctionDef *fd, BOOL is_arg, + JSFunctionDef *fd, bool is_arg, int var_idx, JSAtom var_name, - BOOL is_const, BOOL is_lexical, + bool is_const, bool is_lexical, JSVarKindEnum var_kind) { - return get_closure_var2(ctx, s, fd, TRUE, is_arg, + return get_closure_var2(ctx, s, fd, true, is_arg, var_idx, var_name, is_const, is_lexical, var_kind); } @@ -30223,7 +29224,7 @@ static int get_with_scope_opcode(int op) return OP_with_get_var + (op - OP_scope_get_var); } -static BOOL can_opt_put_ref_value(const uint8_t *bc_buf, int pos) +static bool can_opt_put_ref_value(const uint8_t *bc_buf, int pos) { int opcode = bc_buf[pos]; return (bc_buf[pos + 1] == OP_put_ref_value && @@ -30233,7 +29234,7 @@ static BOOL can_opt_put_ref_value(const uint8_t *bc_buf, int pos) opcode == OP_rot3l)); } -static BOOL can_opt_put_global_ref_value(const uint8_t *bc_buf, int pos) +static bool can_opt_put_global_ref_value(const uint8_t *bc_buf, int pos) { int opcode = bc_buf[pos]; return (bc_buf[pos + 1] == OP_put_ref_value && @@ -30293,12 +29294,11 @@ static int optimize_scope_make_global_ref(JSContext *ctx, JSFunctionDef *s, JSAtom var_name) { int label_pos, end_pos, pos, op; - BOOL is_strict; - is_strict = ((s->js_mode & JS_MODE_STRICT) != 0); + bool is_strict_mode = s->is_strict_mode; /* replace the reference get/put with normal variable accesses */ - if (is_strict) { + if (is_strict_mode) { /* need to check if the variable exists before evaluating the right expression */ /* XXX: need an extra OP_true if destructuring an array */ @@ -30320,7 +29320,7 @@ static int optimize_scope_make_global_ref(JSContext *ctx, JSFunctionDef *s, assert(bc_buf[pos] == OP_label); end_pos = label_pos + 2; op = bc_buf[label_pos]; - if (is_strict) { + if (is_strict_mode) { if (op != OP_nop) { switch(op) { case OP_insert3: @@ -30341,7 +29341,7 @@ static int optimize_scope_make_global_ref(JSContext *ctx, JSFunctionDef *s, if (op == OP_insert3) bc_buf[pos++] = OP_dup; } - if (is_strict) { + if (is_strict_mode) { bc_buf[pos] = OP_put_var_strict; /* XXX: need 1 extra OP_drop if destructuring an array */ } else { @@ -30412,7 +29412,7 @@ static int resolve_pseudo_var(JSContext *ctx, JSFunctionDef *s, 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) + int *plabel_done, bool is_with) { dbuf_putc(bc, get_with_scope_opcode(op)); dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); @@ -30433,7 +29433,7 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, int label_done; JSFunctionDef *fd; JSVarDef *vd; - BOOL is_pseudo_var, is_arg_scope; + bool is_pseudo_var, is_arg_scope; label_done = -1; @@ -30545,7 +29545,6 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, case OP_scope_get_ref: dbuf_putc(bc, OP_undefined); /* fall thru */ - case OP_scope_get_var_checkthis: case OP_scope_get_var_undef: case OP_scope_get_var: case OP_scope_put_var: @@ -30571,12 +29570,7 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, } } else { if (s->vars[var_idx].is_lexical) { - if (op == OP_scope_get_var_checkthis) { - /* only used for 'this' return in derived class constructors */ - dbuf_putc(bc, OP_get_loc_checkthis); - } else { - dbuf_putc(bc, OP_get_loc_check); - } + dbuf_putc(bc, OP_get_loc_check); } else { dbuf_putc(bc, OP_get_loc); } @@ -30622,7 +29616,7 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, break; } else if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) { vd->is_captured = 1; - idx = get_closure_var(ctx, s, fd, FALSE, idx, vd->var_name, FALSE, FALSE, JS_VAR_NORMAL); + idx = get_closure_var(ctx, s, fd, false, idx, vd->var_name, false, false, JS_VAR_NORMAL); if (idx >= 0) { dbuf_putc(bc, OP_get_var_ref); dbuf_put_u16(bc, idx); @@ -30659,9 +29653,9 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, 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, + idx = get_closure_var(ctx, s, fd, false, fd->var_object_idx, vd->var_name, - FALSE, FALSE, JS_VAR_NORMAL); + 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); @@ -30671,9 +29665,9 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, 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, + idx = get_closure_var(ctx, s, fd, false, fd->arg_var_object_idx, vd->var_name, - FALSE, FALSE, JS_VAR_NORMAL); + 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); @@ -30694,7 +29688,7 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, if (var_name == cv->var_name) { if (fd != s) { idx = get_closure_var2(ctx, s, fd, - FALSE, + false, cv->is_arg, idx1, cv->var_name, cv->is_const, cv->is_lexical, cv->var_kind); @@ -30708,9 +29702,9 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, int is_with = (cv->var_name == JS_ATOM__with_); if (fd != s) { idx = get_closure_var2(ctx, s, fd, - FALSE, + false, cv->is_arg, idx1, - cv->var_name, FALSE, FALSE, + cv->var_name, false, false, JS_VAR_NORMAL); } else { idx = idx1; @@ -30727,12 +29721,12 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, if (var_idx & ARGUMENT_VAR_OFFSET) { fd->args[var_idx - ARGUMENT_VAR_OFFSET].is_captured = 1; idx = get_closure_var(ctx, s, fd, - TRUE, var_idx - ARGUMENT_VAR_OFFSET, - var_name, FALSE, FALSE, JS_VAR_NORMAL); + true, var_idx - ARGUMENT_VAR_OFFSET, + var_name, false, false, JS_VAR_NORMAL); } else { fd->vars[var_idx].is_captured = 1; idx = get_closure_var(ctx, s, fd, - FALSE, var_idx, + false, var_idx, var_name, fd->vars[var_idx].is_const, fd->vars[var_idx].is_lexical, @@ -30877,7 +29871,7 @@ static int find_private_class_field_all(JSContext *ctx, JSFunctionDef *fd, return -1; } -static void get_loc_or_ref(DynBuf *bc, BOOL is_ref, int idx) +static void get_loc_or_ref(DynBuf *bc, bool is_ref, int idx) { /* if the field is not initialized, the error is catched when accessing it */ @@ -30889,23 +29883,23 @@ static void get_loc_or_ref(DynBuf *bc, BOOL is_ref, int idx) } static int resolve_scope_private_field1(JSContext *ctx, - BOOL *pis_ref, int *pvar_kind, + bool *pis_ref, int *pvar_kind, JSFunctionDef *s, JSAtom var_name, int scope_level) { int idx, var_kind; JSFunctionDef *fd; - BOOL is_ref; + bool is_ref; fd = s; - is_ref = FALSE; + is_ref = false; for(;;) { idx = find_private_class_field_all(ctx, fd, var_name, scope_level); if (idx >= 0) { var_kind = fd->vars[idx].var_kind; if (is_ref) { - idx = get_closure_var(ctx, s, fd, FALSE, idx, var_name, - TRUE, TRUE, JS_VAR_NORMAL); + idx = get_closure_var(ctx, s, fd, false, idx, var_name, + true, true, JS_VAR_NORMAL); if (idx < 0) return -1; } @@ -30919,10 +29913,10 @@ static int resolve_scope_private_field1(JSContext *ctx, JSClosureVar *cv = &fd->closure_var[idx]; if (cv->var_name == var_name) { var_kind = cv->var_kind; - is_ref = TRUE; + is_ref = true; if (fd != s) { idx = get_closure_var2(ctx, s, fd, - FALSE, + false, cv->is_arg, idx, cv->var_name, cv->is_const, cv->is_lexical, @@ -30935,13 +29929,14 @@ static int resolve_scope_private_field1(JSContext *ctx, } } /* XXX: no line number info */ + // XXX: resolve_scope_private_field1() should take JSParseState *s and use js_parse_error_atom JS_ThrowSyntaxErrorAtom(ctx, "undefined private field '%s'", var_name); return -1; } else { fd = fd->parent; } - is_ref = TRUE; + is_ref = true; } done: *pis_ref = is_ref; @@ -30955,7 +29950,7 @@ static int resolve_scope_private_field(JSContext *ctx, JSFunctionDef *s, DynBuf *bc) { int idx, var_kind; - BOOL is_ref; + bool is_ref; idx = resolve_scope_private_field1(ctx, &is_ref, &var_kind, s, var_name, scope_level); @@ -31064,7 +30059,7 @@ 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) +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 || @@ -31079,11 +30074,11 @@ 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, is_arg_scope; + 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)) { + if (!s->is_eval && !s->is_strict_mode) { s->var_object_idx = add_var(ctx, s, JS_ATOM__var_); if (s->has_parameter_expressions) { /* an additional variable object is needed for the @@ -31110,7 +30105,7 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *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)) + if (s->has_parameter_expressions && !s->is_strict_mode) add_arguments_arg(ctx, s); } if (s->is_func_expr && s->func_name != JS_ATOM_NULL) @@ -31139,12 +30134,12 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s) fd->this_active_func_var_idx = add_var(ctx, fd, JS_ATOM_this_active_func); if (fd->has_home_object && fd->home_object_var_idx < 0) fd->home_object_var_idx = add_var(ctx, fd, JS_ATOM_home_object); - has_this_binding = TRUE; + has_this_binding = true; } /* add 'arguments' if it was not previously added */ if (!has_arguments_binding && fd->has_arguments_binding) { add_arguments_var(ctx, fd); - has_arguments_binding = TRUE; + has_arguments_binding = true; } /* add function name */ if (fd->is_func_expr && fd->func_name != JS_ATOM_NULL) @@ -31155,7 +30150,7 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s) while (scope_idx >= 0) { vd = &fd->vars[scope_idx]; vd->is_captured = 1; - get_closure_var(ctx, s, fd, FALSE, scope_idx, + get_closure_var(ctx, s, fd, false, scope_idx, vd->var_name, vd->is_const, vd->is_lexical, vd->var_kind); scope_idx = vd->scope_next; } @@ -31167,7 +30162,7 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s) vd = &fd->args[i]; if (vd->var_name != JS_ATOM_NULL) { get_closure_var(ctx, s, fd, - TRUE, i, vd->var_name, FALSE, + true, i, vd->var_name, false, vd->is_lexical, JS_VAR_NORMAL); } } @@ -31178,7 +30173,7 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s) 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, i, vd->var_name, false, vd->is_lexical, JS_VAR_NORMAL); } } @@ -31188,7 +30183,7 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s) /* 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, i, vd->var_name, false, vd->is_lexical, JS_VAR_NORMAL); } } @@ -31200,7 +30195,7 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s) for (idx = 0; idx < fd->closure_var_count; idx++) { JSClosureVar *cv = &fd->closure_var[idx]; get_closure_var2(ctx, s, fd, - FALSE, cv->is_arg, + false, cv->is_arg, idx, cv->var_name, cv->is_const, cv->is_lexical, cv->var_kind); } @@ -31211,8 +30206,8 @@ 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_local = true; + cv->is_arg = false; cv->is_const = vd->is_const; cv->is_lexical = vd->is_lexical; cv->var_kind = vd->var_kind; @@ -31227,7 +30222,7 @@ static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s, { int i, count; JSVarDef *vd; - BOOL is_arg_scope; + bool is_arg_scope; count = b->arg_count + b->var_count + b->closure_var_count; s->closure_var = NULL; @@ -31253,10 +30248,10 @@ static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s, 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->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); @@ -31282,7 +30277,7 @@ static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s, for(i = 0; i < b->closure_var_count; i++) { JSClosureVar *cv0 = &b->closure_var[i]; JSClosureVar *cv = &s->closure_var[s->closure_var_count++]; - cv->is_local = FALSE; + cv->is_local = false; cv->is_arg = cv0->is_arg; cv->is_const = cv0->is_const; cv->is_lexical = cv0->is_lexical; @@ -31297,7 +30292,8 @@ typedef struct CodeContext { const uint8_t *bc_buf; /* code buffer */ int bc_len; /* length of the code buffer */ int pos; /* position past the matched code pattern */ - int line_num; /* last visited OP_line_num parameter or -1 */ + int line_num; /* last visited OP_source_loc parameter or -1 */ + int col_num; /* last visited OP_source_loc parameter or -1 */ int op; int idx; int label; @@ -31305,18 +30301,19 @@ typedef struct CodeContext { JSAtom atom; } CodeContext; -#define M2(op1, op2) ((op1) | ((op2) << 8)) -#define M3(op1, op2, op3) ((op1) | ((op2) << 8) | ((op3) << 16)) -#define M4(op1, op2, op3, op4) ((op1) | ((op2) << 8) | ((op3) << 16) | ((op4) << 24)) +#define M2(op1, op2) ((uint32_t)(op1) | ((uint32_t)(op2) << 8)) +#define M3(op1, op2, op3) ((uint32_t)(op1) | ((uint32_t)(op2) << 8) | ((uint32_t)(op3) << 16)) +#define M4(op1, op2, op3, op4) ((uint32_t)(op1) | ((uint32_t)(op2) << 8) | ((uint32_t)(op3) << 16) | ((uint32_t)(op4) << 24)) -static BOOL code_match(CodeContext *s, int pos, ...) +static bool code_match(CodeContext *s, int pos, ...) { const uint8_t *tab = s->bc_buf; - int op, len, op1, line_num, pos_next; + int op, len, op1, line_num, col_num, pos_next; va_list ap; - BOOL ret = FALSE; + bool ret = false; line_num = -1; + col_num = -1; va_start(ap, pos); for(;;) { @@ -31324,7 +30321,8 @@ static BOOL code_match(CodeContext *s, int pos, ...) if (op1 == -1) { s->pos = pos; s->line_num = line_num; - ret = TRUE; + s->col_num = col_num; + ret = true; break; } for (;;) { @@ -31335,8 +30333,9 @@ static BOOL code_match(CodeContext *s, int pos, ...) pos_next = pos + len; if (pos_next > s->bc_len) goto done; - if (op == OP_line_num) { + if (op == OP_source_loc) { line_num = get_u32(tab + pos + 1); + col_num = get_u32(tab + pos + 5); pos = pos_next; } else { break; @@ -31476,7 +30475,7 @@ static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, Dy 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; + bool force_init = hf->force_init; /* we are in an eval, so the closure contains all the enclosing variables */ /* If the outer function has a variable environment, @@ -31485,7 +30484,7 @@ static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, Dy JSClosureVar *cv = &s->closure_var[idx]; if (cv->var_name == hf->var_name) { has_closure = 2; - force_init = FALSE; + force_init = false; break; } if (cv->var_name == JS_ATOM__var_ || @@ -31493,7 +30492,7 @@ static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, Dy dbuf_putc(bc, OP_get_var_ref); dbuf_put_u16(bc, idx); has_closure = 1; - force_init = TRUE; + force_init = true; break; } } @@ -31568,26 +30567,20 @@ static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, Dy } static int skip_dead_code(JSFunctionDef *s, const uint8_t *bc_buf, int bc_len, - int pos, int *linep) + int pos, int *linep, int *colp) { int op, len, label; for (; pos < bc_len; pos += len) { op = bc_buf[pos]; len = opcode_info[op].size; - if (op == OP_line_num) { + if (op == OP_source_loc) { *linep = get_u32(bc_buf + pos + 1); - } else - if (op == OP_label) { + *colp = get_u32(bc_buf + pos + 5); + } else if (op == OP_label) { label = get_u32(bc_buf + pos + 1); if (update_label(s, label, 0) > 0) break; -#if 0 - if (s->label_slots[label].first_reloc) { - printf("line %d: unreferenced label %d:%d has relocations\n", - *linep, label, s->label_slots[label].pos2); - } -#endif assert(s->label_slots[label].first_reloc == NULL); } else { /* XXX: output a warning for unreachable code? */ @@ -31624,7 +30617,9 @@ static int get_label_pos(JSFunctionDef *s, int label) pos = s->label_slots[label].pos; for (;;) { switch (s->byte_code.buf[pos]) { - case OP_line_num: + case OP_source_loc: + pos += 9; + continue; case OP_label: pos += 5; continue; @@ -31644,7 +30639,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, line_num; + int pos, pos_next, bc_len, op, len, i, idx, line_num, col_num; uint8_t *bc_buf; JSAtom var_name; DynBuf bc_out; @@ -31695,14 +30690,16 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) } line_num = 0; /* avoid warning */ + col_num = 0; for (pos = 0; pos < bc_len; pos = pos_next) { op = bc_buf[pos]; len = opcode_info[op].size; pos_next = pos + len; switch(op) { - case OP_line_num: + case OP_source_loc: line_num = get_u32(bc_buf + pos + 1); - s->line_number_size++; + col_num = get_u32(bc_buf + pos + 5); + s->source_loc_size++; goto no_change; case OP_eval: /* convert scope index to adjusted variable index */ @@ -31721,7 +30718,6 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) dbuf_putc(&bc_out, op); dbuf_put_u16(&bc_out, s->scopes[scope].first + 1); break; - case OP_scope_get_var_checkthis: case OP_scope_get_var_undef: case OP_scope_get_var: case OP_scope_put_var: @@ -31764,7 +30760,7 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) break; case OP_gosub: s->jump_size++; - if (OPTIMIZE) { + { /* remove calls to empty finalizers */ int label; LabelSlot *ls; @@ -31778,43 +30774,22 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) } } goto no_change; - case OP_drop: - if (0) { - /* remove drops before return_undef */ - /* do not perform this optimization in pass2 because - it breaks patterns recognised in resolve_labels */ - int pos1 = pos_next; - int line1 = line_num; - while (code_match(&cc, pos1, OP_drop, -1)) { - if (cc.line_num >= 0) line1 = cc.line_num; - pos1 = cc.pos; - } - if (code_match(&cc, pos1, OP_return_undef, -1)) { - pos_next = pos1; - if (line1 != -1 && line1 != line_num) { - line_num = line1; - s->line_number_size++; - dbuf_putc(&bc_out, OP_line_num); - dbuf_put_u32(&bc_out, line_num); - } - break; - } - } - goto no_change; case OP_insert3: - if (OPTIMIZE) { - /* Transformation: insert3 put_array_el|put_ref_value drop -> put_array_el|put_ref_value */ - if (code_match(&cc, pos_next, M2(OP_put_array_el, OP_put_ref_value), OP_drop, -1)) { - dbuf_putc(&bc_out, cc.op); - pos_next = cc.pos; - if (cc.line_num != -1 && cc.line_num != line_num) { - line_num = cc.line_num; - s->line_number_size++; - dbuf_putc(&bc_out, OP_line_num); - dbuf_put_u32(&bc_out, line_num); - } + /* Transformation: insert3 put_array_el|put_ref_value drop -> put_array_el|put_ref_value */ + if (code_match(&cc, pos_next, M2(OP_put_array_el, OP_put_ref_value), OP_drop, -1)) { + dbuf_putc(&bc_out, cc.op); + pos_next = cc.pos; + if (cc.line_num == -1) break; + if (cc.line_num != line_num || cc.col_num != col_num) { + line_num = cc.line_num; + col_num = cc.col_num; + s->source_loc_size++; + dbuf_putc(&bc_out, OP_source_loc); + dbuf_put_u32(&bc_out, line_num); + dbuf_put_u32(&bc_out, col_num); } + break; } goto no_change; @@ -31828,17 +30803,23 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) case OP_throw: case OP_throw_error: case OP_ret: - if (OPTIMIZE) { + { /* remove dead code */ int line = -1; + int col = -1; dbuf_put(&bc_out, bc_buf + pos, len); - pos = skip_dead_code(s, bc_buf, bc_len, pos + len, &line); + pos = skip_dead_code(s, bc_buf, bc_len, pos + len, + &line, &col); pos_next = pos; - if (pos < bc_len && line >= 0 && line_num != line) { + if (line < 0 || pos >= bc_len) + break; + if (line_num != line || col_num != col) { line_num = line; - s->line_number_size++; - dbuf_putc(&bc_out, OP_line_num); + col_num = col; + s->source_loc_size++; + dbuf_putc(&bc_out, OP_source_loc); dbuf_put_u32(&bc_out, line_num); + dbuf_put_u32(&bc_out, col_num); } break; } @@ -31925,34 +30906,37 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) goto no_change; case OP_dup: - if (OPTIMIZE) { - /* Transformation: dup if_false(l1) drop, l1: if_false(l2) -> if_false(l2) */ - /* Transformation: dup if_true(l1) drop, l1: if_true(l2) -> if_true(l2) */ - if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), OP_drop, -1)) { - int lab0, lab1, op1, pos1, line1, pos2; - lab0 = lab1 = cc.label; - assert(lab1 >= 0 && lab1 < s->label_count); - op1 = cc.op; - pos1 = cc.pos; - line1 = cc.line_num; - while (code_match(&cc, (pos2 = get_label_pos(s, lab1)), OP_dup, op1, OP_drop, -1)) { - lab1 = cc.label; - } - if (code_match(&cc, pos2, op1, -1)) { - s->jump_size++; - update_label(s, lab0, -1); - update_label(s, cc.label, +1); - dbuf_putc(&bc_out, op1); - dbuf_put_u32(&bc_out, cc.label); - pos_next = pos1; - if (line1 != -1 && line1 != line_num) { - line_num = line1; - s->line_number_size++; - dbuf_putc(&bc_out, OP_line_num); - dbuf_put_u32(&bc_out, line_num); - } + /* Transformation: dup if_false(l1) drop, l1: if_false(l2) -> if_false(l2) */ + /* Transformation: dup if_true(l1) drop, l1: if_true(l2) -> if_true(l2) */ + if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), OP_drop, -1)) { + int lab0, lab1, op1, pos1, line1, col1, pos2; + lab0 = lab1 = cc.label; + assert(lab1 >= 0 && lab1 < s->label_count); + op1 = cc.op; + pos1 = cc.pos; + line1 = cc.line_num; + col1 = cc.col_num; + while (code_match(&cc, (pos2 = get_label_pos(s, lab1)), OP_dup, op1, OP_drop, -1)) { + lab1 = cc.label; + } + if (code_match(&cc, pos2, op1, -1)) { + s->jump_size++; + update_label(s, lab0, -1); + update_label(s, cc.label, +1); + dbuf_putc(&bc_out, op1); + dbuf_put_u32(&bc_out, cc.label); + pos_next = pos1; + if (line1 == -1) break; + if (line1 != line_num || col1 != col_num) { + line_num = line1; + col_num = col1; + s->source_loc_size++; + dbuf_putc(&bc_out, OP_source_loc); + dbuf_put_u32(&bc_out, line_num); + dbuf_put_u32(&bc_out, col_num); } + break; } } goto no_change; @@ -32005,39 +30989,52 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) } /* the pc2line table gives a line number for each PC value */ -static void add_pc2line_info(JSFunctionDef *s, uint32_t pc, int line_num) +static void add_pc2line_info(JSFunctionDef *s, uint32_t pc, + int line_num, int col_num) { - if (s->line_number_slots != NULL - && s->line_number_count < s->line_number_size - && pc >= s->line_number_last_pc - && line_num != s->line_number_last) { - s->line_number_slots[s->line_number_count].pc = pc; - s->line_number_slots[s->line_number_count].line_num = line_num; - s->line_number_count++; - s->line_number_last_pc = pc; - s->line_number_last = line_num; - } + if (s->source_loc_slots == NULL) + return; + if (s->source_loc_count >= s->source_loc_size) + return; + if (pc < s->line_number_last_pc) + return; + if (line_num == s->line_number_last) + if (col_num == s->col_number_last) + return; + s->source_loc_slots[s->source_loc_count].pc = pc; + s->source_loc_slots[s->source_loc_count].line_num = line_num; + s->source_loc_slots[s->source_loc_count].col_num = col_num; + s->source_loc_count++; + s->line_number_last_pc = pc; + s->line_number_last = line_num; + s->col_number_last = col_num; } static void compute_pc2line_info(JSFunctionDef *s) { - if (!(s->js_mode & JS_MODE_STRIP) && s->line_number_slots) { + if (s->source_loc_slots) { int last_line_num = s->line_num; + int last_col_num = s->col_num; uint32_t last_pc = 0; int i; js_dbuf_init(s->ctx, &s->pc2line); - for (i = 0; i < s->line_number_count; i++) { - uint32_t pc = s->line_number_slots[i].pc; - int line_num = s->line_number_slots[i].line_num; - int diff_pc, diff_line; + for (i = 0; i < s->source_loc_count; i++) { + uint32_t pc = s->source_loc_slots[i].pc; + int line_num = s->source_loc_slots[i].line_num; + int col_num = s->source_loc_slots[i].col_num; + int diff_pc, diff_line, diff_col; if (line_num < 0) continue; diff_pc = pc - last_pc; + if (diff_pc < 0) + continue; + diff_line = line_num - last_line_num; - if (diff_line == 0 || diff_pc < 0) + diff_col = col_num - last_col_num; + if (diff_line == 0 && diff_col == 0) continue; if (diff_line >= PC2LINE_BASE && @@ -32051,8 +31048,11 @@ static void compute_pc2line_info(JSFunctionDef *s) dbuf_put_leb128(&s->pc2line, diff_pc); dbuf_put_sleb128(&s->pc2line, diff_line); } + dbuf_put_sleb128(&s->pc2line, diff_col); + last_pc = pc; last_line_num = line_num; + last_col_num = col_num; } } } @@ -32070,35 +31070,35 @@ static RelocEntry *add_reloc(JSContext *ctx, LabelSlot *ls, uint32_t addr, int s return re; } -static BOOL code_has_label(CodeContext *s, int pos, int label) +static bool code_has_label(CodeContext *s, int pos, int label) { while (pos < s->bc_len) { int op = s->bc_buf[pos]; - if (op == OP_line_num) { - pos += 5; + if (op == OP_source_loc) { + pos += 9; continue; } if (op == OP_label) { int lab = get_u32(s->bc_buf + pos + 1); if (lab == label) - return TRUE; + return true; pos += 5; continue; } if (op == OP_goto) { int lab = get_u32(s->bc_buf + pos + 1); if (lab == label) - return TRUE; + return true; } break; } - return FALSE; + return false; } /* return the target label, following the OP_goto jumps the first opcode at destination is stored in *pop */ -static int find_jump_target(JSFunctionDef *s, int label, int *pop, int *pline) +static int find_jump_target(JSFunctionDef *s, int label, int *pop) { int i, pos, op; @@ -32108,10 +31108,7 @@ static int find_jump_target(JSFunctionDef *s, int label, int *pop, int *pline) pos = s->label_slots[label].pos2; for (;;) { switch(op = s->byte_code.buf[pos]) { - case OP_line_num: - if (pline) - *pline = get_u32(s->byte_code.buf + pos + 1); - /* fall thru */ + case OP_source_loc: case OP_label: pos += opcode_info[op].size; continue; @@ -32140,7 +31137,6 @@ static int find_jump_target(JSFunctionDef *s, int label, int *pop, int *pline) static void push_short_int(DynBuf *bc_out, int val) { -#if SHORT_OPCODES if (val >= -1 && val <= 7) { dbuf_putc(bc_out, OP_push_0 + val); return; @@ -32155,14 +31151,12 @@ static void push_short_int(DynBuf *bc_out, int val) dbuf_put_u16(bc_out, val); return; } -#endif dbuf_putc(bc_out, OP_push_i32); dbuf_put_u32(bc_out, val); } static void put_short_code(DynBuf *bc_out, int op, int idx) { -#if SHORT_OPCODES if (idx < 4) { switch (op) { case OP_get_loc: @@ -32213,7 +31207,6 @@ static void put_short_code(DynBuf *bc_out, int op, int idx) return; } } -#endif dbuf_putc(bc_out, op); dbuf_put_u16(bc_out, idx); } @@ -32221,38 +31214,36 @@ static void put_short_code(DynBuf *bc_out, int op, int idx) /* peephole optimizations and resolve goto/labels */ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) { - int pos, pos_next, bc_len, op, op1, len, i, line_num; + int pos, pos_next, bc_len, op, op1, len, i, line_num, col_num, patch_offsets; const uint8_t *bc_buf; DynBuf bc_out; LabelSlot *label_slots, *ls; RelocEntry *re, *re_next; CodeContext cc; int label; -#if SHORT_OPCODES JumpSlot *jp; -#endif label_slots = s->label_slots; line_num = s->line_num; + col_num = s->col_num; cc.bc_buf = bc_buf = s->byte_code.buf; cc.bc_len = bc_len = s->byte_code.size; js_dbuf_init(ctx, &bc_out); -#if SHORT_OPCODES if (s->jump_size) { s->jump_slots = js_mallocz(s->ctx, sizeof(*s->jump_slots) * s->jump_size); if (s->jump_slots == NULL) return -1; } -#endif - /* XXX: Should skip this phase if not generating SHORT_OPCODES */ - if (s->line_number_size && !(s->js_mode & JS_MODE_STRIP)) { - s->line_number_slots = js_mallocz(s->ctx, sizeof(*s->line_number_slots) * s->line_number_size); - if (s->line_number_slots == NULL) + + if (s->source_loc_size) { + s->source_loc_slots = js_mallocz(s->ctx, sizeof(*s->source_loc_slots) * s->source_loc_size); + if (s->source_loc_slots == NULL) return -1; s->line_number_last = s->line_num; + s->col_number_last = s->col_num; s->line_number_last_pc = 0; } @@ -32287,7 +31278,7 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) } /* initialize the 'arguments' variable if needed */ if (s->arguments_var_idx >= 0) { - if ((s->js_mode & JS_MODE_STRICT) || !s->has_simple_parameter_list) { + if (s->is_strict_mode || !s->has_simple_parameter_list) { dbuf_putc(&bc_out, OP_special_object); dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_ARGUMENTS); } else { @@ -32322,11 +31313,12 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) len = opcode_info[op].size; pos_next = pos + len; switch(op) { - case OP_line_num: + case OP_source_loc: /* line number info (for debug). We put it in a separate compressed table to reduce memory usage and get better performance */ line_num = get_u32(bc_buf + pos + 1); + col_num = get_u32(bc_buf + pos + 5); break; case OP_label: @@ -32367,12 +31359,14 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) argc = get_u16(bc_buf + pos + 1); if (code_match(&cc, pos_next, OP_return, -1)) { if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); + if (cc.col_num >= 0) col_num = cc.col_num; + add_pc2line_info(s, bc_out.size, line_num, col_num); put_short_code(&bc_out, op + 1, argc); - pos_next = skip_dead_code(s, bc_buf, bc_len, cc.pos, &line_num); + pos_next = skip_dead_code(s, bc_buf, bc_len, cc.pos, + &line_num, &col_num); break; } - add_pc2line_info(s, bc_out.size, line_num); + add_pc2line_info(s, bc_out.size, line_num, col_num); put_short_code(&bc_out, op, argc); break; } @@ -32383,16 +31377,16 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) case OP_return_async: case OP_throw: case OP_throw_error: - pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num); + pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, + &line_num, &col_num); goto no_change; case OP_goto: label = get_u32(bc_buf + pos + 1); has_goto: - if (OPTIMIZE) { - int line1 = -1; + { /* Use custom matcher because multiple labels can follow */ - label = find_jump_target(s, label, &op1, &line1); + label = find_jump_target(s, label, &op1); if (code_has_label(&cc, pos_next, label)) { /* jump to next instruction: remove jump */ update_label(s, label, -1); @@ -32401,11 +31395,11 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) if (op1 == OP_return || op1 == OP_return_undef || op1 == OP_throw) { /* jump to return/throw: remove jump, append return/throw */ /* updating the line number obfuscates assembly listing */ - //if (line1 >= 0) line_num = line1; update_label(s, label, -1); - add_pc2line_info(s, bc_out.size, line_num); + add_pc2line_info(s, bc_out.size, line_num, col_num); dbuf_putc(&bc_out, op1); - pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num); + pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, + &line_num, &col_num); break; } /* XXX: should duplicate single instructions followed by goto or return */ @@ -32419,14 +31413,6 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) case OP_gosub: label = get_u32(bc_buf + pos + 1); - if (0 && OPTIMIZE) { - label = find_jump_target(s, label, &op1, NULL); - if (op1 == OP_ret) { - update_label(s, label, -1); - /* empty finally clause: remove gosub */ - break; - } - } goto has_label; case OP_catch: @@ -32436,35 +31422,35 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) case OP_if_true: case OP_if_false: label = get_u32(bc_buf + pos + 1); - if (OPTIMIZE) { - label = find_jump_target(s, label, &op1, NULL); - /* transform if_false/if_true(l1) label(l1) -> drop label(l1) */ - if (code_has_label(&cc, pos_next, label)) { + label = find_jump_target(s, label, &op1); + /* transform if_false/if_true(l1) label(l1) -> drop label(l1) */ + if (code_has_label(&cc, pos_next, label)) { + update_label(s, label, -1); + dbuf_putc(&bc_out, OP_drop); + break; + } + /* transform if_false(l1) goto(l2) label(l1) -> if_false(l2) label(l1) */ + if (code_match(&cc, pos_next, OP_goto, -1)) { + int pos1 = cc.pos; + int line1 = cc.line_num; + int col1 = cc.col_num; + if (code_has_label(&cc, pos1, label)) { + if (line1 >= 0) line_num = line1; + if (col1 >= 0) col_num = col1; + pos_next = pos1; update_label(s, label, -1); - dbuf_putc(&bc_out, OP_drop); - break; - } - /* transform if_false(l1) goto(l2) label(l1) -> if_false(l2) label(l1) */ - if (code_match(&cc, pos_next, OP_goto, -1)) { - int pos1 = cc.pos; - int line1 = cc.line_num; - if (code_has_label(&cc, pos1, label)) { - if (line1 >= 0) line_num = line1; - pos_next = pos1; - update_label(s, label, -1); - label = cc.label; - op ^= OP_if_true ^ OP_if_false; - } + label = cc.label; + op ^= OP_if_true ^ OP_if_false; } } has_label: - add_pc2line_info(s, bc_out.size, line_num); + add_pc2line_info(s, bc_out.size, line_num, col_num); if (op == OP_goto) { - pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num); + pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, + &line_num, &col_num); } assert(label >= 0 && label < s->label_count); ls = &label_slots[label]; -#if SHORT_OPCODES jp = &s->jump_slots[s->jump_count++]; jp->op = op; jp->size = 4; @@ -32508,7 +31494,6 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) break; } } -#endif dbuf_putc(&bc_out, op); dbuf_put_u32(&bc_out, ls->addr - bc_out.size); if (ls->addr == -1) { @@ -32530,19 +31515,15 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) atom = get_u32(bc_buf + pos + 1); label = get_u32(bc_buf + pos + 5); is_with = bc_buf[pos + 9]; - if (OPTIMIZE) { - label = find_jump_target(s, label, &op1, NULL); - } + label = find_jump_target(s, label, &op1); assert(label >= 0 && label < s->label_count); ls = &label_slots[label]; - add_pc2line_info(s, bc_out.size, line_num); -#if SHORT_OPCODES + add_pc2line_info(s, bc_out.size, line_num, col_num); jp = &s->jump_slots[s->jump_count++]; jp->op = op; jp->size = 4; jp->pos = bc_out.size + 5; jp->label = label; -#endif dbuf_putc(&bc_out, op); dbuf_put_u32(&bc_out, atom); dbuf_put_u32(&bc_out, ls->addr - bc_out.size); @@ -32556,106 +31537,101 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) break; case OP_drop: - if (OPTIMIZE) { - /* remove useless drops before return */ - if (code_match(&cc, pos_next, OP_return_undef, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - break; - } + /* remove useless drops before return */ + if (code_match(&cc, pos_next, OP_return_undef, -1)) { + if (cc.line_num >= 0) line_num = cc.line_num; + if (cc.col_num >= 0) col_num = cc.col_num; + break; } goto no_change; case OP_null: -#if SHORT_OPCODES - if (OPTIMIZE) { - /* transform null strict_eq into is_null */ - if (code_match(&cc, pos_next, OP_strict_eq, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, OP_is_null); - pos_next = cc.pos; - break; - } - /* transform null strict_neq if_false/if_true -> is_null if_true/if_false */ - if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, OP_is_null); - pos_next = cc.pos; - label = cc.label; - op = cc.op ^ OP_if_false ^ OP_if_true; - goto has_label; - } + /* transform null strict_eq into is_null */ + if (code_match(&cc, pos_next, OP_strict_eq, -1)) { + if (cc.line_num >= 0) line_num = cc.line_num; + if (cc.col_num >= 0) col_num = cc.col_num; + add_pc2line_info(s, bc_out.size, line_num, col_num); + dbuf_putc(&bc_out, OP_is_null); + pos_next = cc.pos; + break; + } + /* transform null strict_neq if_false/if_true -> is_null if_true/if_false */ + if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) { + if (cc.line_num >= 0) line_num = cc.line_num; + if (cc.col_num >= 0) col_num = cc.col_num; + add_pc2line_info(s, bc_out.size, line_num, col_num); + dbuf_putc(&bc_out, OP_is_null); + pos_next = cc.pos; + label = cc.label; + op = cc.op ^ OP_if_false ^ OP_if_true; + goto has_label; } -#endif /* fall thru */ case OP_push_false: case OP_push_true: - if (OPTIMIZE) { - val = (op == OP_push_true); - if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) { - has_constant_test: - if (cc.line_num >= 0) line_num = cc.line_num; - if (val == cc.op - OP_if_false) { - /* transform null if_false(l1) -> goto l1 */ - /* transform false if_false(l1) -> goto l1 */ - /* transform true if_true(l1) -> goto l1 */ - pos_next = cc.pos; - op = OP_goto; - label = cc.label; - goto has_goto; - } else { - /* transform null if_true(l1) -> nop */ - /* transform false if_true(l1) -> nop */ - /* transform true if_false(l1) -> nop */ - pos_next = cc.pos; - update_label(s, cc.label, -1); - break; - } + val = (op == OP_push_true); + if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) { + has_constant_test: + if (cc.line_num >= 0) line_num = cc.line_num; + if (cc.col_num >= 0) col_num = cc.col_num; + if (val == cc.op - OP_if_false) { + /* transform null if_false(l1) -> goto l1 */ + /* transform false if_false(l1) -> goto l1 */ + /* transform true if_true(l1) -> goto l1 */ + pos_next = cc.pos; + op = OP_goto; + label = cc.label; + goto has_goto; + } else { + /* transform null if_true(l1) -> nop */ + /* transform false if_true(l1) -> nop */ + /* transform true if_false(l1) -> nop */ + pos_next = cc.pos; + update_label(s, cc.label, -1); + break; } } goto no_change; case OP_push_i32: - if (OPTIMIZE) { - /* transform i32(val) neg -> i32(-val) */ - val = get_i32(bc_buf + pos + 1); - if ((val != INT32_MIN && val != 0) - && code_match(&cc, pos_next, OP_neg, -1)) { + /* transform i32(val) neg -> i32(-val) */ + val = get_i32(bc_buf + pos + 1); + if ((val != INT32_MIN && val != 0) + && code_match(&cc, pos_next, OP_neg, -1)) { + if (cc.line_num >= 0) line_num = cc.line_num; + if (cc.col_num >= 0) col_num = cc.col_num; + if (code_match(&cc, cc.pos, OP_drop, -1)) { if (cc.line_num >= 0) line_num = cc.line_num; - if (code_match(&cc, cc.pos, OP_drop, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - } else { - add_pc2line_info(s, bc_out.size, line_num); - push_short_int(&bc_out, -val); - } - pos_next = cc.pos; - break; - } - /* remove push/drop pairs generated by the parser */ - if (code_match(&cc, pos_next, OP_drop, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - pos_next = cc.pos; - break; - } - /* Optimize constant tests: `if (0)`, `if (1)`, `if (!0)`... */ - if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) { - val = (val != 0); - goto has_constant_test; + if (cc.col_num >= 0) col_num = cc.col_num; + } else { + add_pc2line_info(s, bc_out.size, line_num, col_num); + push_short_int(&bc_out, -val); } - add_pc2line_info(s, bc_out.size, line_num); - push_short_int(&bc_out, val); + pos_next = cc.pos; break; } - goto no_change; + /* remove push/drop pairs generated by the parser */ + if (code_match(&cc, pos_next, OP_drop, -1)) { + if (cc.line_num >= 0) line_num = cc.line_num; + if (cc.col_num >= 0) col_num = cc.col_num; + pos_next = cc.pos; + break; + } + /* Optimize constant tests: `if (0)`, `if (1)`, `if (!0)`... */ + if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) { + val = (val != 0); + goto has_constant_test; + } + add_pc2line_info(s, bc_out.size, line_num, col_num); + push_short_int(&bc_out, val); + break; -#if SHORT_OPCODES case OP_push_const: case OP_fclosure: - if (OPTIMIZE) { + { int idx = get_u32(bc_buf + pos + 1); if (idx < 256) { - add_pc2line_info(s, bc_out.size, line_num); + add_pc2line_info(s, bc_out.size, line_num, col_num); dbuf_putc(&bc_out, OP_push_const8 + op - OP_push_const); dbuf_putc(&bc_out, idx); break; @@ -32664,122 +31640,120 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) goto no_change; case OP_get_field: - if (OPTIMIZE) { + { JSAtom atom = get_u32(bc_buf + pos + 1); if (atom == JS_ATOM_length) { JS_FreeAtom(ctx, atom); - add_pc2line_info(s, bc_out.size, line_num); + add_pc2line_info(s, bc_out.size, line_num, col_num); dbuf_putc(&bc_out, OP_get_length); break; } } goto no_change; -#endif + case OP_push_atom_value: - if (OPTIMIZE) { + { JSAtom atom = get_u32(bc_buf + pos + 1); /* remove push/drop pairs generated by the parser */ if (code_match(&cc, pos_next, OP_drop, -1)) { JS_FreeAtom(ctx, atom); if (cc.line_num >= 0) line_num = cc.line_num; + if (cc.col_num >= 0) col_num = cc.col_num; pos_next = cc.pos; break; } -#if SHORT_OPCODES if (atom == JS_ATOM_empty_string) { JS_FreeAtom(ctx, atom); - add_pc2line_info(s, bc_out.size, line_num); + add_pc2line_info(s, bc_out.size, line_num, col_num); dbuf_putc(&bc_out, OP_push_empty_string); break; } -#endif } goto no_change; case OP_to_propkey: case OP_to_propkey2: - if (OPTIMIZE) { - /* remove redundant to_propkey/to_propkey2 opcodes when storing simple data */ - if (code_match(&cc, pos_next, M3(OP_get_loc, OP_get_arg, OP_get_var_ref), -1, OP_put_array_el, -1) - || code_match(&cc, pos_next, M3(OP_push_i32, OP_push_const, OP_push_atom_value), OP_put_array_el, -1) - || code_match(&cc, pos_next, M4(OP_undefined, OP_null, OP_push_true, OP_push_false), OP_put_array_el, -1)) { - break; - } + /* remove redundant to_propkey/to_propkey2 opcodes when storing simple data */ + if (code_match(&cc, pos_next, M3(OP_get_loc, OP_get_arg, OP_get_var_ref), -1, OP_put_array_el, -1) + || code_match(&cc, pos_next, M3(OP_push_i32, OP_push_const, OP_push_atom_value), OP_put_array_el, -1) + || code_match(&cc, pos_next, M4(OP_undefined, OP_null, OP_push_true, OP_push_false), OP_put_array_el, -1)) { + break; } goto no_change; case OP_undefined: - if (OPTIMIZE) { - /* remove push/drop pairs generated by the parser */ - if (code_match(&cc, pos_next, OP_drop, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - pos_next = cc.pos; - break; - } - /* transform undefined return -> return_undefined */ - if (code_match(&cc, pos_next, OP_return, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, OP_return_undef); - pos_next = cc.pos; - break; - } - /* transform undefined if_true(l1)/if_false(l1) -> nop/goto(l1) */ - if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) { - val = 0; - goto has_constant_test; - } -#if SHORT_OPCODES - /* transform undefined strict_eq -> is_undefined */ - if (code_match(&cc, pos_next, OP_strict_eq, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, OP_is_undefined); - pos_next = cc.pos; - break; - } - /* transform undefined strict_neq if_false/if_true -> is_undefined if_true/if_false */ - if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, OP_is_undefined); - pos_next = cc.pos; - label = cc.label; - op = cc.op ^ OP_if_false ^ OP_if_true; - goto has_label; - } -#endif + /* remove push/drop pairs generated by the parser */ + if (code_match(&cc, pos_next, OP_drop, -1)) { + if (cc.line_num >= 0) line_num = cc.line_num; + if (cc.col_num >= 0) col_num = cc.col_num; + pos_next = cc.pos; + break; + } + /* transform undefined return -> return_undefined */ + if (code_match(&cc, pos_next, OP_return, -1)) { + if (cc.line_num >= 0) line_num = cc.line_num; + if (cc.col_num >= 0) col_num = cc.col_num; + add_pc2line_info(s, bc_out.size, line_num, col_num); + dbuf_putc(&bc_out, OP_return_undef); + pos_next = cc.pos; + break; + } + /* transform undefined if_true(l1)/if_false(l1) -> nop/goto(l1) */ + if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) { + val = 0; + goto has_constant_test; + } + /* transform undefined strict_eq -> is_undefined */ + if (code_match(&cc, pos_next, OP_strict_eq, -1)) { + if (cc.line_num >= 0) line_num = cc.line_num; + if (cc.col_num >= 0) col_num = cc.col_num; + add_pc2line_info(s, bc_out.size, line_num, col_num); + dbuf_putc(&bc_out, OP_is_undefined); + pos_next = cc.pos; + break; + } + /* transform undefined strict_neq if_false/if_true -> is_undefined if_true/if_false */ + if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) { + if (cc.line_num >= 0) line_num = cc.line_num; + if (cc.col_num >= 0) col_num = cc.col_num; + add_pc2line_info(s, bc_out.size, line_num, col_num); + dbuf_putc(&bc_out, OP_is_undefined); + pos_next = cc.pos; + label = cc.label; + op = cc.op ^ OP_if_false ^ OP_if_true; + goto has_label; } goto no_change; case OP_insert2: - if (OPTIMIZE) { - /* Transformation: - insert2 put_field(a) drop -> put_field(a) - insert2 put_var_strict(a) drop -> put_var_strict(a) - */ - if (code_match(&cc, pos_next, M2(OP_put_field, OP_put_var_strict), OP_drop, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, cc.op); - dbuf_put_u32(&bc_out, cc.atom); - pos_next = cc.pos; - break; - } + /* Transformation: + insert2 put_field(a) drop -> put_field(a) + insert2 put_var_strict(a) drop -> put_var_strict(a) + */ + if (code_match(&cc, pos_next, M2(OP_put_field, OP_put_var_strict), OP_drop, -1)) { + if (cc.line_num >= 0) line_num = cc.line_num; + if (cc.col_num >= 0) col_num = cc.col_num; + add_pc2line_info(s, bc_out.size, line_num, col_num); + dbuf_putc(&bc_out, cc.op); + dbuf_put_u32(&bc_out, cc.atom); + pos_next = cc.pos; + break; } goto no_change; case OP_dup: - if (OPTIMIZE) { + { /* Transformation: dup put_x(n) drop -> put_x(n) */ int op1, line2 = -1; /* Transformation: dup put_x(n) -> set_x(n) */ if (code_match(&cc, pos_next, M3(OP_put_loc, OP_put_arg, OP_put_var_ref), -1, -1)) { if (cc.line_num >= 0) line_num = cc.line_num; + if (cc.col_num >= 0) col_num = cc.col_num; op1 = cc.op + 1; /* put_x -> set_x */ pos_next = cc.pos; if (code_match(&cc, cc.pos, OP_drop, -1)) { if (cc.line_num >= 0) line_num = cc.line_num; + if (cc.col_num >= 0) col_num = cc.col_num; op1 -= 1; /* set_x drop -> put_x */ pos_next = cc.pos; if (code_match(&cc, cc.pos, op1 - 1, cc.idx, -1)) { @@ -32788,7 +31762,7 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) pos_next = cc.pos; } } - add_pc2line_info(s, bc_out.size, line_num); + add_pc2line_info(s, bc_out.size, line_num, col_num); put_short_code(&bc_out, op1, cc.idx); if (line2 >= 0) line_num = line2; break; @@ -32796,8 +31770,18 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) } goto no_change; + case OP_swap: + // transformation: swap swap -> nothing! + if (code_match(&cc, pos_next, OP_swap, -1, -1)) { + if (cc.line_num >= 0) line_num = cc.line_num; + if (cc.col_num >= 0) col_num = cc.col_num; + pos_next = cc.pos; + break; + } + goto no_change; + case OP_get_loc: - if (OPTIMIZE) { + { /* transformation: get_loc(n) post_dec put_loc(n) drop -> dec_loc(n) get_loc(n) post_inc put_loc(n) drop -> inc_loc(n) @@ -32811,7 +31795,8 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) if (code_match(&cc, pos_next, M2(OP_post_dec, OP_post_inc), OP_put_loc, idx, OP_drop, -1) || code_match(&cc, pos_next, M2(OP_dec, OP_inc), OP_dup, OP_put_loc, idx, OP_drop, -1)) { if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); + if (cc.col_num >= 0) col_num = cc.col_num; + add_pc2line_info(s, bc_out.size, line_num, col_num); dbuf_putc(&bc_out, (cc.op == OP_inc || cc.op == OP_post_inc) ? OP_inc_loc : OP_dec_loc); dbuf_putc(&bc_out, idx); pos_next = cc.pos; @@ -32822,14 +31807,12 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) */ if (code_match(&cc, pos_next, OP_push_atom_value, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) { if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); -#if SHORT_OPCODES + if (cc.col_num >= 0) col_num = cc.col_num; + add_pc2line_info(s, bc_out.size, line_num, col_num); if (cc.atom == JS_ATOM_empty_string) { JS_FreeAtom(ctx, cc.atom); dbuf_putc(&bc_out, OP_push_empty_string); - } else -#endif - { + } else { dbuf_putc(&bc_out, OP_push_atom_value); dbuf_put_u32(&bc_out, cc.atom); } @@ -32843,7 +31826,8 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) */ if (code_match(&cc, pos_next, OP_push_i32, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) { if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); + if (cc.col_num >= 0) col_num = cc.col_num; + add_pc2line_info(s, bc_out.size, line_num, col_num); push_short_int(&bc_out, cc.label); dbuf_putc(&bc_out, OP_add_loc); dbuf_putc(&bc_out, idx); @@ -32857,53 +31841,59 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) */ if (code_match(&cc, pos_next, M3(OP_get_loc, OP_get_arg, OP_get_var_ref), -1, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) { if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); + if (cc.col_num >= 0) col_num = cc.col_num; + add_pc2line_info(s, bc_out.size, line_num, col_num); put_short_code(&bc_out, cc.op, cc.idx); dbuf_putc(&bc_out, OP_add_loc); dbuf_putc(&bc_out, idx); pos_next = cc.pos; break; } - add_pc2line_info(s, bc_out.size, line_num); + /* transformation: get_loc(0) get_loc(1) -> get_loc0_loc1 */ + if (idx == 0 && code_match(&cc, pos_next, OP_get_loc, 1, -1)) { + if (cc.line_num >= 0) line_num = cc.line_num; + if (cc.col_num >= 0) col_num = cc.col_num; + add_pc2line_info(s, bc_out.size, line_num, col_num); + dbuf_putc(&bc_out, OP_get_loc0_loc1); + pos_next = cc.pos; + break; + } + add_pc2line_info(s, bc_out.size, line_num, col_num); put_short_code(&bc_out, op, idx); - break; } - goto no_change; -#if SHORT_OPCODES + break; case OP_get_arg: case OP_get_var_ref: - if (OPTIMIZE) { + { int idx; idx = get_u16(bc_buf + pos + 1); - add_pc2line_info(s, bc_out.size, line_num); + add_pc2line_info(s, bc_out.size, line_num, col_num); put_short_code(&bc_out, op, idx); - break; } - goto no_change; -#endif + break; case OP_put_loc: case OP_put_arg: case OP_put_var_ref: - if (OPTIMIZE) { + { /* transformation: put_x(n) get_x(n) -> set_x(n) */ int idx; idx = get_u16(bc_buf + pos + 1); if (code_match(&cc, pos_next, op - 1, idx, -1)) { if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); + if (cc.col_num >= 0) col_num = cc.col_num; + add_pc2line_info(s, bc_out.size, line_num, col_num); put_short_code(&bc_out, op + 1, idx); pos_next = cc.pos; break; } - add_pc2line_info(s, bc_out.size, line_num); + add_pc2line_info(s, bc_out.size, line_num, col_num); put_short_code(&bc_out, op, idx); - break; } - goto no_change; + break; case OP_post_inc: case OP_post_dec: - if (OPTIMIZE) { + { /* transformation: post_inc put_x drop -> inc put_x post_inc perm3 put_field drop -> inc put_field @@ -32913,22 +31903,25 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) int op1, idx; if (code_match(&cc, pos_next, M3(OP_put_loc, OP_put_arg, OP_put_var_ref), -1, OP_drop, -1)) { if (cc.line_num >= 0) line_num = cc.line_num; + if (cc.col_num >= 0) col_num = cc.col_num; op1 = cc.op; idx = cc.idx; pos_next = cc.pos; if (code_match(&cc, cc.pos, op1 - 1, idx, -1)) { if (cc.line_num >= 0) line_num = cc.line_num; + if (cc.col_num >= 0) col_num = cc.col_num; op1 += 1; /* put_x(n) get_x(n) -> set_x(n) */ pos_next = cc.pos; } - add_pc2line_info(s, bc_out.size, line_num); + add_pc2line_info(s, bc_out.size, line_num, col_num); dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec)); put_short_code(&bc_out, op1, idx); break; } if (code_match(&cc, pos_next, OP_perm3, M2(OP_put_field, OP_put_var_strict), OP_drop, -1)) { if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); + if (cc.col_num >= 0) col_num = cc.col_num; + add_pc2line_info(s, bc_out.size, line_num, col_num); dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec)); dbuf_putc(&bc_out, cc.op); dbuf_put_u32(&bc_out, cc.atom); @@ -32937,7 +31930,8 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) } if (code_match(&cc, pos_next, OP_perm4, OP_put_array_el, OP_drop, -1)) { if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); + if (cc.col_num >= 0) col_num = cc.col_num; + add_pc2line_info(s, bc_out.size, line_num, col_num); dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec)); dbuf_putc(&bc_out, OP_put_array_el); pos_next = cc.pos; @@ -32946,51 +31940,49 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) } goto no_change; -#if SHORT_OPCODES case OP_typeof: - if (OPTIMIZE) { - /* simplify typeof tests */ - if (code_match(&cc, pos_next, OP_push_atom_value, M4(OP_strict_eq, OP_strict_neq, OP_eq, OP_neq), -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - int op1 = (cc.op == OP_strict_eq || cc.op == OP_eq) ? OP_strict_eq : OP_strict_neq; - int op2 = -1; - switch (cc.atom) { - case JS_ATOM_undefined: - op2 = OP_typeof_is_undefined; - break; - case JS_ATOM_function: - op2 = OP_typeof_is_function; + /* simplify typeof tests */ + if (code_match(&cc, pos_next, OP_push_atom_value, M4(OP_strict_eq, OP_strict_neq, OP_eq, OP_neq), -1)) { + if (cc.line_num >= 0) line_num = cc.line_num; + if (cc.col_num >= 0) col_num = cc.col_num; + int op1 = (cc.op == OP_strict_eq || cc.op == OP_eq) ? OP_strict_eq : OP_strict_neq; + int op2 = -1; + switch (cc.atom) { + case JS_ATOM_undefined: + op2 = OP_typeof_is_undefined; + break; + case JS_ATOM_function: + op2 = OP_typeof_is_function; + break; + } + if (op2 >= 0) { + /* transform typeof(s) == "" into is_ */ + if (op1 == OP_strict_eq) { + add_pc2line_info(s, bc_out.size, line_num, col_num); + dbuf_putc(&bc_out, op2); + JS_FreeAtom(ctx, cc.atom); + pos_next = cc.pos; break; } - if (op2 >= 0) { - /* transform typeof(s) == "" into is_ */ - if (op1 == OP_strict_eq) { - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, op2); - JS_FreeAtom(ctx, cc.atom); - pos_next = cc.pos; - break; - } - if (op1 == OP_strict_neq && code_match(&cc, cc.pos, OP_if_false, -1)) { - /* transform typeof(s) != "" if_false into is_ if_true */ - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, op2); - JS_FreeAtom(ctx, cc.atom); - pos_next = cc.pos; - label = cc.label; - op = OP_if_true; - goto has_label; - } + if (op1 == OP_strict_neq && code_match(&cc, cc.pos, OP_if_false, -1)) { + /* transform typeof(s) != "" if_false into is_ if_true */ + if (cc.line_num >= 0) line_num = cc.line_num; + if (cc.col_num >= 0) col_num = cc.col_num; + add_pc2line_info(s, bc_out.size, line_num, col_num); + dbuf_putc(&bc_out, op2); + JS_FreeAtom(ctx, cc.atom); + pos_next = cc.pos; + label = cc.label; + op = OP_if_true; + goto has_label; } } } goto no_change; -#endif default: no_change: - add_pc2line_info(s, bc_out.size, line_num); + add_pc2line_info(s, bc_out.size, line_num, col_num); dbuf_put(&bc_out, bc_buf + pos, len); break; } @@ -33000,95 +31992,94 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) for(i = 0; i < s->label_count; i++) { assert(label_slots[i].first_reloc == NULL); } -#if SHORT_OPCODES - if (OPTIMIZE) { - /* more jump optimizations */ - int patch_offsets = 0; - for (i = 0, jp = s->jump_slots; i < s->jump_count; i++, jp++) { - LabelSlot *ls; - JumpSlot *jp1; - int j, pos, diff, delta; - - delta = 3; - switch (op = jp->op) { - case OP_goto16: - delta = 1; - /* fall thru */ - case OP_if_false: - case OP_if_true: - case OP_goto: - pos = jp->pos; - diff = s->label_slots[jp->label].addr - pos; - if (diff >= -128 && diff <= 127 + delta) { - //put_u8(bc_out.buf + pos, diff); - jp->size = 1; - if (op == OP_goto16) { - bc_out.buf[pos - 1] = jp->op = OP_goto8; - } else { - bc_out.buf[pos - 1] = jp->op = OP_if_false8 + (op - OP_if_false); - } - goto shrink; - } else - if (diff == (int16_t)diff && op == OP_goto) { - //put_u16(bc_out.buf + pos, diff); - jp->size = 2; - delta = 2; - bc_out.buf[pos - 1] = jp->op = OP_goto16; - shrink: - /* XXX: should reduce complexity, using 2 finger copy scheme */ - memmove(bc_out.buf + pos + jp->size, bc_out.buf + pos + jp->size + delta, - bc_out.size - pos - jp->size - delta); - bc_out.size -= delta; - patch_offsets++; - for (j = 0, ls = s->label_slots; j < s->label_count; j++, ls++) { - if (ls->addr > pos) - ls->addr -= delta; - } - for (j = i + 1, jp1 = jp + 1; j < s->jump_count; j++, jp1++) { - if (jp1->pos > pos) - jp1->pos -= delta; - } - for (j = 0; j < s->line_number_count; j++) { - if (s->line_number_slots[j].pc > pos) - s->line_number_slots[j].pc -= delta; - } - continue; + + /* more jump optimizations */ + patch_offsets = 0; + for (i = 0, jp = s->jump_slots; i < s->jump_count; i++, jp++) { + LabelSlot *ls; + JumpSlot *jp1; + int j, pos, diff, delta; + + delta = 3; + switch (op = jp->op) { + case OP_goto16: + delta = 1; + /* fall thru */ + case OP_if_false: + case OP_if_true: + case OP_goto: + pos = jp->pos; + diff = s->label_slots[jp->label].addr - pos; + if (diff >= -128 && diff <= 127 + delta) { + //put_u8(bc_out.buf + pos, diff); + jp->size = 1; + if (op == OP_goto16) { + bc_out.buf[pos - 1] = jp->op = OP_goto8; + } else { + bc_out.buf[pos - 1] = jp->op = OP_if_false8 + (op - OP_if_false); } - break; + goto shrink; + } else + if (diff == (int16_t)diff && op == OP_goto) { + //put_u16(bc_out.buf + pos, diff); + jp->size = 2; + delta = 2; + bc_out.buf[pos - 1] = jp->op = OP_goto16; + shrink: + /* XXX: should reduce complexity, using 2 finger copy scheme */ + memmove(bc_out.buf + pos + jp->size, bc_out.buf + pos + jp->size + delta, + bc_out.size - pos - jp->size - delta); + bc_out.size -= delta; + patch_offsets++; + for (j = 0, ls = s->label_slots; j < s->label_count; j++, ls++) { + if (ls->addr > pos) + ls->addr -= delta; + } + for (j = i + 1, jp1 = jp + 1; j < s->jump_count; j++, jp1++) { + if (jp1->pos > pos) + jp1->pos -= delta; + } + for (j = 0; j < s->source_loc_count; j++) { + if (s->source_loc_slots[j].pc > pos) + s->source_loc_slots[j].pc -= delta; + } + continue; } + break; } - if (patch_offsets) { - JumpSlot *jp1; - int j; - for (j = 0, jp1 = s->jump_slots; j < s->jump_count; j++, jp1++) { - int diff1 = s->label_slots[jp1->label].addr - jp1->pos; - switch (jp1->size) { - case 1: - put_u8(bc_out.buf + jp1->pos, diff1); - break; - case 2: - put_u16(bc_out.buf + jp1->pos, diff1); - break; - case 4: - put_u32(bc_out.buf + jp1->pos, diff1); - break; - } + } + + if (patch_offsets) { + JumpSlot *jp1; + int j; + for (j = 0, jp1 = s->jump_slots; j < s->jump_count; j++, jp1++) { + int diff1 = s->label_slots[jp1->label].addr - jp1->pos; + switch (jp1->size) { + case 1: + put_u8(bc_out.buf + jp1->pos, diff1); + break; + case 2: + put_u16(bc_out.buf + jp1->pos, diff1); + break; + case 4: + put_u32(bc_out.buf + jp1->pos, diff1); + break; } } } + js_free(ctx, s->jump_slots); s->jump_slots = NULL; -#endif js_free(ctx, s->label_slots); s->label_slots = NULL; /* XXX: should delay until copying to runtime bytecode function */ compute_pc2line_info(s); - js_free(ctx, s->line_number_slots); - s->line_number_slots = NULL; + js_free(ctx, s->source_loc_slots); + s->source_loc_slots = NULL; /* set the new byte code */ dbuf_free(&s->byte_code); s->byte_code = bc_out; - s->use_short_opcodes = TRUE; + s->use_short_opcodes = true; if (dbuf_error(&s->byte_code)) { JS_ThrowOutOfMemory(ctx); return -1; @@ -33173,8 +32164,7 @@ static __exception int compute_stack_size(JSContext *ctx, for(i = 0; i < s->bc_len; i++) s->stack_level_tab[i] = 0xffff; s->pc_stack = NULL; - s->catch_pos_tab = js_malloc(ctx, sizeof(s->catch_pos_tab[0]) * - s->bc_len); + s->catch_pos_tab = js_malloc(ctx, sizeof(s->catch_pos_tab[0]) * s->bc_len); if (!s->catch_pos_tab) goto fail; @@ -33196,8 +32186,9 @@ static __exception int compute_stack_size(JSContext *ctx, goto fail; } oi = &short_opcode_info(op); -#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 64) - printf("%5d: %10s %5d %5d\n", pos, oi->name, stack_len, catch_pos); +#ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_STACK + if (check_dump_flag(ctx->rt, JS_DUMP_BYTECODE_STACK)) + printf("%5d: %10s %5d %5d\n", pos, oi->name, stack_len, catch_pos); #endif pos_next = pos + oi->size; if (pos_next > s->bc_len) { @@ -33208,12 +32199,8 @@ static __exception int compute_stack_size(JSContext *ctx, /* call pops a variable number of arguments */ if (oi->fmt == OP_FMT_npop || oi->fmt == OP_FMT_npop_u16) { n_pop += get_u16(bc_buf + pos + 1); - } else { -#if SHORT_OPCODES - if (oi->fmt == OP_FMT_npopx) { - n_pop += op - OP_call0; - } -#endif + } else if (oi->fmt == OP_FMT_npopx) { + n_pop += op - OP_call0; } if (stack_len < n_pop) { @@ -33242,7 +32229,6 @@ static __exception int compute_stack_size(JSContext *ctx, diff = get_u32(bc_buf + pos + 1); pos_next = pos + 1 + diff; break; -#if SHORT_OPCODES case OP_goto16: diff = (int16_t)get_u16(bc_buf + pos + 1); pos_next = pos + 1 + diff; @@ -33257,7 +32243,6 @@ static __exception int compute_stack_size(JSContext *ctx, if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos)) goto fail; break; -#endif case OP_if_true: case OP_if_false: diff = get_u32(bc_buf + pos + 1); @@ -33369,8 +32354,8 @@ static int add_module_variables(JSContext *ctx, JSFunctionDef *fd) 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) + if (add_closure_var(ctx, fd, true, false, i, hf->var_name, hf->is_const, + hf->is_lexical, JS_VAR_NORMAL) < 0) return -1; } @@ -33380,6 +32365,7 @@ static int add_module_variables(JSContext *ctx, JSFunctionDef *fd) if (me->export_type == JS_EXPORT_TYPE_LOCAL) { idx = find_closure_var(ctx, fd, me->local_name); if (idx < 0) { + // XXX: add_module_variables() should take JSParseState *s and use js_parse_error_atom JS_ThrowSyntaxErrorAtom(ctx, "exported variable '%s' does not exist", me->local_name); return -1; @@ -33456,14 +32442,14 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd) fd->cpool[cpool_idx] = func_obj; } -#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 4) - if (!(fd->js_mode & JS_MODE_STRIP)) { +#ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_PASS1 + if (check_dump_flag(ctx->rt, JS_DUMP_BYTECODE_PASS1)) { printf("pass 1\n"); dump_byte_code(ctx, 1, fd->byte_code.buf, fd->byte_code.size, fd->args, fd->arg_count, fd->vars, fd->var_count, fd->closure_var, fd->closure_var_count, fd->cpool, fd->cpool_count, fd->source, fd->line_num, - fd->label_slots, NULL); + fd->label_slots, NULL, 0); printf("\n"); } #endif @@ -33471,14 +32457,14 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd) if (resolve_variables(ctx, fd)) goto fail; -#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 2) - if (!(fd->js_mode & JS_MODE_STRIP)) { +#ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_PASS2 + if (check_dump_flag(ctx->rt, JS_DUMP_BYTECODE_PASS2)) { printf("pass 2\n"); dump_byte_code(ctx, 2, fd->byte_code.buf, fd->byte_code.size, fd->args, fd->arg_count, fd->vars, fd->var_count, fd->closure_var, fd->closure_var_count, fd->cpool, fd->cpool_count, fd->source, fd->line_num, - fd->label_slots, NULL); + fd->label_slots, NULL, 0); printf("\n"); } #endif @@ -33489,17 +32475,11 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd) if (compute_stack_size(ctx, fd, &stack_size) < 0) goto fail; - if (fd->js_mode & JS_MODE_STRIP) { - function_size = offsetof(JSFunctionBytecode, debug); - } else { - function_size = sizeof(*b); - } + function_size = sizeof(*b); cpool_offset = function_size; function_size += fd->cpool_count * sizeof(*fd->cpool); vardefs_offset = function_size; - if (!(fd->js_mode & JS_MODE_STRIP) || fd->has_eval_call) { - function_size += (fd->arg_count + fd->var_count) * sizeof(*b->vardefs); - } + function_size += (fd->arg_count + fd->var_count) * sizeof(*b->vardefs); closure_var_offset = function_size; function_size += fd->closure_var_count * sizeof(*fd->closure_var); byte_code_offset = function_size; @@ -33518,29 +32498,17 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd) b->func_name = fd->func_name; if (fd->arg_count + fd->var_count > 0) { - if ((fd->js_mode & JS_MODE_STRIP) && !fd->has_eval_call) { - /* Strip variable definitions not needed at runtime */ - int i; - for(i = 0; i < fd->var_count; i++) { - JS_FreeAtom(ctx, fd->vars[i].var_name); - } - for(i = 0; i < fd->arg_count; i++) { - JS_FreeAtom(ctx, fd->args[i].var_name); - } - for(i = 0; i < fd->closure_var_count; i++) { - JS_FreeAtom(ctx, fd->closure_var[i].var_name); - fd->closure_var[i].var_name = JS_ATOM_NULL; - } - } else { - b->vardefs = (void *)((uint8_t*)b + vardefs_offset); - memcpy_no_ub(b->vardefs, fd->args, fd->arg_count * sizeof(fd->args[0])); - memcpy_no_ub(b->vardefs + fd->arg_count, fd->vars, fd->var_count * sizeof(fd->vars[0])); - } + b->vardefs = (void *)((uint8_t*)b + vardefs_offset); + if (fd->arg_count > 0) + memcpy(b->vardefs, fd->args, fd->arg_count * sizeof(fd->args[0])); + if (fd->var_count > 0) + memcpy(b->vardefs + fd->arg_count, fd->vars, fd->var_count * sizeof(fd->vars[0])); b->var_count = fd->var_count; b->arg_count = fd->arg_count; b->defined_arg_count = fd->defined_arg_count; js_free(ctx, fd->args); js_free(ctx, fd->vars); + js_free(ctx, fd->vars_htab); } b->cpool_count = fd->cpool_count; if (b->cpool_count) { @@ -33552,27 +32520,20 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd) b->stack_size = stack_size; - if (fd->js_mode & JS_MODE_STRIP) { - JS_FreeAtom(ctx, fd->filename); - dbuf_free(&fd->pc2line); // probably useless - } else { - /* XXX: source and pc2line info should be packed at the end of the - JSFunctionBytecode structure, avoiding allocation overhead - */ - b->has_debug = 1; - b->debug.filename = fd->filename; - b->debug.line_num = fd->line_num; - - //DynBuf pc2line; - //compute_pc2line_info(fd, &pc2line); - //js_free(ctx, fd->line_number_slots) - b->debug.pc2line_buf = js_realloc(ctx, fd->pc2line.buf, fd->pc2line.size); - if (!b->debug.pc2line_buf) - b->debug.pc2line_buf = fd->pc2line.buf; - b->debug.pc2line_len = fd->pc2line.size; - b->debug.source = fd->source; - b->debug.source_len = fd->source_len; - } + /* XXX: source and pc2line info should be packed at the end of the + JSFunctionBytecode structure, avoiding allocation overhead + */ + b->filename = fd->filename; + b->line_num = fd->line_num; + b->col_num = fd->col_num; + + b->pc2line_buf = js_realloc(ctx, fd->pc2line.buf, fd->pc2line.size); + if (!b->pc2line_buf) + b->pc2line_buf = fd->pc2line.buf; + b->pc2line_len = fd->pc2line.size; + b->source = fd->source; + b->source_len = fd->source_len; + if (fd->scopes != fd->def_scope_array) js_free(ctx, fd->scopes); @@ -33586,7 +32547,7 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd) b->has_prototype = fd->has_prototype; b->has_simple_parameter_list = fd->has_simple_parameter_list; - b->js_mode = fd->js_mode; + b->is_strict_mode = fd->is_strict_mode; b->is_derived_class_constructor = fd->is_derived_class_constructor; b->func_kind = fd->func_kind; b->need_home_object = (fd->home_object_var_idx >= 0 || @@ -33596,16 +32557,20 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd) b->super_allowed = fd->super_allowed; b->arguments_allowed = fd->arguments_allowed; b->backtrace_barrier = fd->backtrace_barrier; - b->is_direct_or_indirect_eval = (fd->eval_type == JS_EVAL_TYPE_DIRECT || - fd->eval_type == JS_EVAL_TYPE_INDIRECT); b->realm = JS_DupContext(ctx); + b->ic = fd->ic; + fd->ic = NULL; + rebuild_ic(ctx, b->ic); + if (b->ic->count == 0) { + free_ic(ctx->rt, b->ic); + b->ic = NULL; + } add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE); -#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 1) - if (!(fd->js_mode & JS_MODE_STRIP)) { +#ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_FINAL + if (check_dump_flag(ctx->rt, JS_DUMP_BYTECODE_FINAL)) js_dump_function_bytecode(ctx, b); - } #endif if (fd->parent) { @@ -33624,14 +32589,10 @@ static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b) { int i; -#if 0 - { - char buf[ATOM_GET_STR_BUF_SIZE]; - printf("freeing %s\n", - JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name)); - } -#endif - free_bytecode_atoms(rt, b->byte_code_buf, b->byte_code_len, TRUE); + free_bytecode_atoms(rt, b->byte_code_buf, b->byte_code_len, true); + + if (b->ic) + free_ic(rt, b->ic); if (b->vardefs) { for(i = 0; i < b->arg_count + b->var_count; i++) { @@ -33649,11 +32610,9 @@ static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b) JS_FreeContext(b->realm); JS_FreeAtomRT(rt, b->func_name); - if (b->has_debug) { - JS_FreeAtomRT(rt, b->debug.filename); - js_free_rt(rt, b->debug.pc2line_buf); - js_free_rt(rt, b->debug.source); - } + JS_FreeAtomRT(rt, b->filename); + js_free_rt(rt, b->pc2line_buf); + js_free_rt(rt, b->source); remove_gc_object(&b->header); if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && b->header.ref_count != 0) { @@ -33667,7 +32626,7 @@ static __exception int js_parse_directives(JSParseState *s) { char str[20]; JSParsePos pos; - BOOL has_semi; + bool has_semi; if (s->token.val != TOK_STRING) return 0; @@ -33682,16 +32641,16 @@ static __exception int js_parse_directives(JSParseState *s) if (next_token(s)) return -1; - has_semi = FALSE; + has_semi = false; switch (s->token.val) { case ';': if (next_token(s)) return -1; - has_semi = TRUE; + has_semi = true; break; case '}': case TOK_EOF: - has_semi = TRUE; + has_semi = true; break; case TOK_NUMBER: case TOK_STRING: @@ -33734,7 +32693,7 @@ static __exception int js_parse_directives(JSParseState *s) case TOK_STATIC: /* automatic insertion of ';' */ if (s->got_lf) - has_semi = TRUE; + has_semi = true; break; default: break; @@ -33742,46 +32701,54 @@ static __exception int js_parse_directives(JSParseState *s) if (!has_semi) break; if (!strcmp(str, "use strict")) { - s->cur_func->has_use_strict = TRUE; - s->cur_func->js_mode |= JS_MODE_STRICT; + s->cur_func->has_use_strict = true; + s->cur_func->is_strict_mode = true; } -#if !defined(DUMP_BYTECODE) || !(DUMP_BYTECODE & 8) - else if (!strcmp(str, "use strip")) { - s->cur_func->js_mode |= JS_MODE_STRIP; - } -#endif -#ifdef CONFIG_BIGNUM - else if (s->ctx->bignum_ext && !strcmp(str, "use math")) { - s->cur_func->js_mode |= JS_MODE_MATH; - } -#endif } return js_parse_seek_token(s, &pos); } +static bool js_invalid_strict_name(JSAtom name) { + switch (name) { + case JS_ATOM_eval: + case JS_ATOM_arguments: + case JS_ATOM_implements: // future strict reserved words + case JS_ATOM_interface: + case JS_ATOM_let: + case JS_ATOM_package: + case JS_ATOM_private: + case JS_ATOM_protected: + case JS_ATOM_public: + case JS_ATOM_static: + case JS_ATOM_yield: + return true; + default: + return false; + } +} + static int js_parse_function_check_names(JSParseState *s, JSFunctionDef *fd, JSAtom func_name) { JSAtom name; int i, idx; - if (fd->js_mode & JS_MODE_STRICT) { + if (fd->is_strict_mode) { if (!fd->has_simple_parameter_list && fd->has_use_strict) { return js_parse_error(s, "\"use strict\" not allowed in function with default or destructuring parameter"); } - if (func_name == JS_ATOM_eval || func_name == JS_ATOM_arguments) { + if (js_invalid_strict_name(func_name)) { return js_parse_error(s, "invalid function name in strict code"); } for (idx = 0; idx < fd->arg_count; idx++) { name = fd->args[idx].var_name; - - if (name == JS_ATOM_eval || name == JS_ATOM_arguments) { + if (js_invalid_strict_name(name)) { return js_parse_error(s, "invalid argument name in strict code"); } } } /* check async_generator case */ - if ((fd->js_mode & JS_MODE_STRICT) + if (fd->is_strict_mode || !fd->has_simple_parameter_list || (fd->func_type == JS_PARSE_FUNC_METHOD && fd->func_kind == JS_FUNC_ASYNC) || fd->func_type == JS_PARSE_FUNC_ARROW @@ -33806,7 +32773,7 @@ static int js_parse_function_check_names(JSParseState *s, JSFunctionDef *fd, return 0; duplicate: - return js_parse_error(s, "duplicate argument names not allowed in this context"); + return js_parse_error(s, "Duplicate parameter name not allowed in this context"); } /* create a function to initialize class fields */ @@ -33814,21 +32781,21 @@ static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s) { JSFunctionDef *fd; - fd = js_new_function_def(s->ctx, s->cur_func, FALSE, FALSE, - s->filename, 0); + fd = js_new_function_def(s->ctx, s->cur_func, false, false, + s->filename, 0, 0); if (!fd) return NULL; fd->func_name = JS_ATOM_NULL; - fd->has_prototype = FALSE; - fd->has_home_object = TRUE; - - fd->has_arguments_binding = FALSE; - fd->has_this_binding = TRUE; - fd->is_derived_class_constructor = FALSE; - fd->new_target_allowed = TRUE; - fd->super_call_allowed = FALSE; + fd->has_prototype = false; + fd->has_home_object = true; + + fd->has_arguments_binding = false; + fd->has_this_binding = true; + fd->is_derived_class_constructor = false; + fd->new_target_allowed = true; + fd->super_call_allowed = false; fd->super_allowed = fd->has_home_object; - fd->arguments_allowed = FALSE; + fd->arguments_allowed = false; fd->func_kind = JS_FUNC_NORMAL; fd->func_type = JS_PARSE_FUNC_METHOD; @@ -33843,15 +32810,16 @@ static __exception int js_parse_function_decl2(JSParseState *s, JSAtom func_name, const uint8_t *ptr, int function_line_num, + int function_col_num, JSParseExportEnum export_flag, JSFunctionDef **pfd) { JSContext *ctx = s->ctx; JSFunctionDef *fd = s->cur_func; - BOOL is_expr; + bool is_expr; int func_idx, lexical_func_idx = -1; - BOOL has_opt_arg; - BOOL create_func_var = FALSE; + bool has_opt_arg; + bool create_func_var = false; is_expr = (func_type != JS_PARSE_FUNC_STATEMENT && func_type != JS_PARSE_FUNC_VAR); @@ -33861,7 +32829,7 @@ static __exception int js_parse_function_decl2(JSParseState *s, func_type == JS_PARSE_FUNC_EXPR) { if (func_kind == JS_FUNC_NORMAL && token_is_pseudo_keyword(s, JS_ATOM_async) && - peek_token(s, TRUE) != '\n') { + peek_token(s, true) != '\n') { if (next_token(s)) return -1; func_kind = JS_FUNC_ASYNC; @@ -33887,7 +32855,7 @@ static __exception int js_parse_function_decl2(JSParseState *s, } } if (s->token.val == TOK_IDENT || - (((s->token.val == TOK_YIELD && !(fd->js_mode & JS_MODE_STRICT)) || + (((s->token.val == TOK_YIELD && !fd->is_strict_mode) || (s->token.val == TOK_AWAIT && !s->is_module)) && func_type == JS_PARSE_FUNC_EXPR)) { func_name = JS_DupAtom(ctx, s->token.u.ident.atom); @@ -33918,12 +32886,12 @@ static __exception int js_parse_function_decl2(JSParseState *s, } if (func_type == JS_PARSE_FUNC_VAR) { - if (!(fd->js_mode & JS_MODE_STRICT) + if (!fd->is_strict_mode && func_kind == JS_FUNC_NORMAL - && find_lexical_decl(ctx, fd, func_name, fd->scope_first, FALSE) < 0 + && 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_func_var = true; } /* Create the lexical name here so that the function closure contains it */ @@ -33956,8 +32924,8 @@ static __exception int js_parse_function_decl2(JSParseState *s, } } - fd = js_new_function_def(ctx, fd, FALSE, is_expr, - s->filename, function_line_num); + fd = js_new_function_def(ctx, fd, false, is_expr, s->filename, + function_line_num, function_col_num); if (!fd) { JS_FreeAtom(ctx, func_name); return -1; @@ -33986,18 +32954,18 @@ static __exception int js_parse_function_decl2(JSParseState *s, fd->super_allowed = fd->parent->super_allowed; fd->arguments_allowed = fd->parent->arguments_allowed; } else if (func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT) { - fd->new_target_allowed = TRUE; // although new.target === undefined - fd->super_call_allowed = FALSE; - fd->super_allowed = TRUE; - fd->arguments_allowed = FALSE; + fd->new_target_allowed = true; // although new.target === undefined + fd->super_call_allowed = false; + fd->super_allowed = true; + fd->arguments_allowed = false; } else { - fd->new_target_allowed = TRUE; + fd->new_target_allowed = true; fd->super_call_allowed = fd->is_derived_class_constructor; fd->super_allowed = fd->has_home_object; - fd->arguments_allowed = TRUE; + fd->arguments_allowed = true; } - /* fd->in_function_body == FALSE prevents yield/await during the parsing + /* fd->in_function_body == false prevents yield/await during the parsing of the arguments in generator/async functions. They are parsed as regular identifiers for other function kinds. */ fd->func_kind = func_kind; @@ -34014,9 +32982,9 @@ 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; + 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; if (s->token.u.ident.is_reserved) { @@ -34032,9 +33000,9 @@ static __exception int js_parse_function_decl2(JSParseState *s, 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); + js_parse_skip_parens_token(s, &skip_bits, false); if (skip_bits & SKIP_HAS_ASSIGNMENT) - fd->has_parameter_expressions = TRUE; + fd->has_parameter_expressions = true; if (next_token(s)) goto fail; } else { @@ -34050,17 +33018,17 @@ static __exception int js_parse_function_decl2(JSParseState *s, while (s->token.val != ')') { JSAtom name; - BOOL rest = FALSE; + bool rest = false; int idx, has_initializer; if (s->token.val == TOK_ELLIPSIS) { - fd->has_simple_parameter_list = FALSE; - rest = TRUE; + fd->has_simple_parameter_list = false; + rest = true; if (next_token(s)) goto fail; } if (s->token.val == '[' || s->token.val == '{') { - fd->has_simple_parameter_list = FALSE; + fd->has_simple_parameter_list = false; if (rest) { emit_op(s, OP_rest); emit_u16(s, fd->arg_count); @@ -34070,11 +33038,11 @@ static __exception int js_parse_function_decl2(JSParseState *s, emit_op(s, OP_get_arg); emit_u16(s, idx); } - has_initializer = js_parse_destructuring_element(s, fd->has_parameter_expressions ? TOK_LET : 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, false); if (has_initializer < 0) goto fail; if (has_initializer) - has_opt_arg = TRUE; + has_opt_arg = true; if (!has_opt_arg) fd->defined_arg_count++; } else if (s->token.val == TOK_IDENT) { @@ -34110,13 +33078,13 @@ static __exception int js_parse_function_decl2(JSParseState *s, } emit_op(s, OP_put_arg); emit_u16(s, idx); - fd->has_simple_parameter_list = FALSE; - has_opt_arg = TRUE; + 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; + fd->has_simple_parameter_list = false; + has_opt_arg = true; if (next_token(s)) goto fail; @@ -34217,7 +33185,7 @@ 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; + fd->in_function_body = true; push_scope(s); /* enter body scope */ fd->body_scope = fd->scope_level; @@ -34237,23 +33205,22 @@ static __exception int js_parse_function_decl2(JSParseState *s, else emit_op(s, OP_return); - if (!(fd->js_mode & JS_MODE_STRIP)) { - /* save the function source code */ - /* the end of the function source code is after the last - token of the function source stored into s->last_ptr */ - fd->source_len = s->last_ptr - ptr; - fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len); - if (!fd->source) - goto fail; - } + /* save the function source code */ + /* the end of the function source code is after the last + token of the function source stored into s->last_ptr */ + fd->source_len = s->last_ptr - ptr; + fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len); + if (!fd->source) + goto fail; + goto done; } } - if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) { + // js_parse_class() already consumed the '{' + if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) if (js_parse_expect(s, '{')) goto fail; - } if (js_parse_directives(s)) goto fail; @@ -34266,13 +33233,12 @@ static __exception int js_parse_function_decl2(JSParseState *s, if (js_parse_source_element(s)) goto fail; } - if (!(fd->js_mode & JS_MODE_STRIP)) { - /* save the function source code */ - fd->source_len = s->buf_ptr - ptr; - fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len); - if (!fd->source) - goto fail; - } + + /* save the function source code */ + fd->source_len = s->buf_ptr - ptr; + fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len); + if (!fd->source) + goto fail; if (next_token(s)) { /* consume the '}' */ @@ -34281,9 +33247,9 @@ static __exception int js_parse_function_decl2(JSParseState *s, /* in case there is no return, add one */ if (js_is_live_code(s)) { - emit_return(s, FALSE); + emit_return(s, false); } - done: +done: s->cur_func = fd->parent; /* Reparse identifiers after the function is terminated so that @@ -34329,7 +33295,7 @@ static __exception int js_parse_function_decl2(JSParseState *s, (needed for annex B.3.3.4 and B.3.3.5 checks) */ hf->scope_level = 0; - hf->force_init = ((s->cur_func->js_mode & JS_MODE_STRICT) != 0); + hf->force_init = s->cur_func->is_strict_mode; /* store directly into global var, bypass lexical scope */ emit_op(s, OP_dup); emit_op(s, OP_scope_put_var); @@ -34407,11 +33373,12 @@ static __exception int js_parse_function_decl(JSParseState *s, JSFunctionKindEnum func_kind, JSAtom func_name, const uint8_t *ptr, - int function_line_num) + int start_line, + int start_col) { return js_parse_function_decl2(s, func_type, func_kind, func_name, ptr, - function_line_num, JS_PARSE_EXPORT_NONE, - NULL); + start_line, start_col, + JS_PARSE_EXPORT_NONE, NULL); } static __exception int js_parse_program(JSParseState *s) @@ -34427,7 +33394,7 @@ static __exception int js_parse_program(JSParseState *s) fd->is_global_var = (fd->eval_type == JS_EVAL_TYPE_GLOBAL) || (fd->eval_type == JS_EVAL_TYPE_MODULE) || - !(fd->js_mode & JS_MODE_STRICT); + !fd->is_strict_mode; if (!s->is_module) { /* hidden variable for the return value */ @@ -34458,9 +33425,9 @@ static __exception int js_parse_program(JSParseState *s) emit_op(s, OP_get_loc); emit_u16(s, fd->eval_ret_idx); } - emit_return(s, TRUE); + emit_return(s, true); } else { - emit_return(s, FALSE); + emit_return(s, false); } return 0; @@ -34474,14 +33441,18 @@ static void js_parse_init(JSContext *ctx, JSParseState *s, s->ctx = ctx; s->filename = filename; s->line_num = line; - s->buf_ptr = (const uint8_t *)input; + s->col_num = 1; + s->buf_start = s->buf_ptr = (const uint8_t *)input; s->buf_end = s->buf_ptr + input_len; + s->mark = s->buf_ptr + min_int(1, input_len); + s->eol = s->buf_ptr; s->token.val = ' '; s->token.line_num = 1; + s->token.col_num = 1; } static JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj, - JSValueConst this_obj, + JSValue this_obj, JSVarRef **var_refs, JSStackFrame *sf) { JSValue ret_val; @@ -34518,18 +33489,20 @@ JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj) } /* 'input' must be zero terminated i.e. input[input_len] = '\0'. */ -static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, +/* `export_name` and `input` may be pure ASCII or UTF-8 encoded */ +static JSValue __JS_EvalInternal(JSContext *ctx, JSValue this_obj, const char *input, size_t input_len, const char *filename, int line, int flags, int scope_idx) { JSParseState s1, *s = &s1; - int err, js_mode, eval_type; + int err, eval_type; JSValue fun_obj, ret_val; JSStackFrame *sf; JSVarRef **var_refs; JSFunctionBytecode *b; JSFunctionDef *fd; JSModuleDef *m; + bool is_strict_mode; js_parse_init(ctx, s, input, input_len, filename, line); skip_shebang(&s->buf_ptr, s->buf_end); @@ -34545,16 +33518,12 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, assert(js_class_has_bytecode(p->class_id)); b = p->u.func.function_bytecode; var_refs = p->u.func.var_refs; - js_mode = b->js_mode; + is_strict_mode = b->is_strict_mode; } else { sf = NULL; b = NULL; var_refs = NULL; - js_mode = 0; - if (flags & JS_EVAL_FLAG_STRICT) - js_mode |= JS_MODE_STRICT; - if (flags & JS_EVAL_FLAG_STRIP) - js_mode |= JS_MODE_STRIP; + is_strict_mode = (flags & JS_EVAL_FLAG_STRICT) != 0; if (eval_type == JS_EVAL_TYPE_MODULE) { JSAtom module_name = JS_NewAtom(ctx, filename); if (module_name == JS_ATOM_NULL) @@ -34562,10 +33531,10 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, m = js_new_module_def(ctx, module_name); if (!m) return JS_EXCEPTION; - js_mode |= JS_MODE_STRICT; + is_strict_mode = true; } } - fd = js_new_function_def(ctx, NULL, TRUE, FALSE, filename, line); + fd = js_new_function_def(ctx, NULL, true, false, filename, line, 1); if (!fd) goto fail1; s->cur_func = fd; @@ -34578,12 +33547,12 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, fd->super_allowed = b->super_allowed; fd->arguments_allowed = b->arguments_allowed; } else { - fd->new_target_allowed = FALSE; - fd->super_call_allowed = FALSE; - fd->super_allowed = FALSE; - fd->arguments_allowed = TRUE; + fd->new_target_allowed = false; + fd->super_call_allowed = false; + fd->super_allowed = false; + fd->arguments_allowed = true; } - fd->js_mode = js_mode; + fd->is_strict_mode = is_strict_mode; fd->func_name = JS_DupAtom(ctx, JS_ATOM__eval_); if (b) { if (add_closure_variables(ctx, fd, b, scope_idx)) @@ -34591,7 +33560,7 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, } fd->module = m; if (m != NULL || (flags & JS_EVAL_FLAG_ASYNC)) { - fd->in_function_body = TRUE; + fd->in_function_body = true; fd->func_kind = JS_FUNC_ASYNC; } s->is_module = (m != NULL); @@ -34636,7 +33605,7 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, } /* the indirection is needed to make 'eval' optional */ -static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, +static JSValue JS_EvalInternal(JSContext *ctx, JSValue this_obj, const char *input, size_t input_len, const char *filename, int line, int flags, int scope_idx) { @@ -34647,15 +33616,15 @@ static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, flags, scope_idx); } -static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj, - JSValueConst val, int flags, int scope_idx) +static JSValue JS_EvalObject(JSContext *ctx, JSValue this_obj, + JSValue val, int flags, int scope_idx) { JSValue ret; const char *str; size_t len; if (!JS_IsString(val)) - return JS_DupValue(ctx, val); + return js_dup(val); str = JS_ToCStringLen(ctx, &len, val); if (!str) return JS_EXCEPTION; @@ -34665,15 +33634,36 @@ static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj, } -JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj, +JSValue JS_EvalThis(JSContext *ctx, JSValue this_obj, const char *input, size_t input_len, - const char *filename, int line, int eval_flags) + const char *filename, int eval_flags) { - int eval_type = eval_flags & JS_EVAL_TYPE_MASK; + JSEvalOptions options = { + .version = JS_EVAL_OPTIONS_VERSION, + .filename = filename, + .line_num = 1, + .eval_flags = eval_flags + }; + return JS_EvalThis2(ctx, this_obj, input, input_len, &options); +} + +JSValue JS_EvalThis2(JSContext *ctx, JSValue this_obj, + const char *input, size_t input_len, + JSEvalOptions *options) +{ + const char *filename = ""; + int line = 1; + int eval_flags = 0; + if (options) { + if (options->filename) + filename = options->filename; + line = options->line_num; + eval_flags = options->eval_flags; + } JSValue ret; - assert(eval_type == JS_EVAL_TYPE_GLOBAL || - eval_type == JS_EVAL_TYPE_MODULE); + assert((eval_flags & JS_EVAL_TYPE_MASK) == JS_EVAL_TYPE_GLOBAL || + (eval_flags & JS_EVAL_TYPE_MASK) == JS_EVAL_TYPE_MODULE); ret = JS_EvalInternal(ctx, this_obj, input, input_len, filename, line, eval_flags, -1); return ret; @@ -34682,11 +33672,21 @@ JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj, 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, 1, - eval_flags); + JSEvalOptions options = { + .version = JS_EVAL_OPTIONS_VERSION, + .filename = filename, + .line_num = 1, + .eval_flags = eval_flags + }; + return JS_EvalThis2(ctx, ctx->global_obj, input, input_len, &options); +} + +JSValue JS_Eval2(JSContext *ctx, const char *input, size_t input_len, JSEvalOptions *options) +{ + return JS_EvalThis2(ctx, ctx->global_obj, input, input_len, options); } -int JS_ResolveModule(JSContext *ctx, JSValueConst obj) +int JS_ResolveModule(JSContext *ctx, JSValue obj) { if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) { JSModuleDef *m = JS_VALUE_GET_PTR(obj); @@ -34822,27 +33822,25 @@ typedef enum BCTagEnum { BC_TAG_TYPED_ARRAY, BC_TAG_ARRAY_BUFFER, BC_TAG_SHARED_ARRAY_BUFFER, + BC_TAG_REGEXP, BC_TAG_DATE, BC_TAG_OBJECT_VALUE, BC_TAG_OBJECT_REFERENCE, -#ifdef CONFIG_BIGNUM - BC_TAG_BIG_FLOAT, - BC_TAG_BIG_DECIMAL, -#endif + BC_TAG_MAP, + BC_TAG_SET, + BC_TAG_SYMBOL, } BCTagEnum; -#ifdef CONFIG_BIGNUM -#define BC_VERSION 0x43 -#else -#define BC_VERSION 3 -#endif +#define BC_VERSION 19 typedef struct BCWriterState { JSContext *ctx; DynBuf dbuf; - BOOL allow_bytecode : 8; - BOOL allow_sab : 8; - BOOL allow_reference : 8; + bool allow_bytecode; + bool allow_sab; + bool allow_reference; + bool allow_source; + bool allow_debug; uint32_t first_atom; uint32_t *atom_to_idx; int atom_to_idx_size; @@ -34852,11 +33850,11 @@ typedef struct BCWriterState { uint8_t **sab_tab; int sab_tab_len; int sab_tab_size; - /* list of referenced objects (used if allow_reference = TRUE) */ + /* list of referenced objects (used if allow_reference = true) */ JSObjectList object_list; } BCWriterState; -#ifdef DUMP_READ_OBJECT +#ifdef ENABLE_DUMPS // JS_DUMP_READ_OBJECT static const char * const bc_tag_str[] = { "invalid", "null", @@ -34868,32 +33866,23 @@ static const char * const bc_tag_str[] = { "string", "object", "array", - "bigint", + "BigInt", "template", "function", "module", "TypedArray", "ArrayBuffer", "SharedArrayBuffer", + "RegExp", "Date", "ObjectValue", "ObjectReference", -#ifdef CONFIG_BIGNUM - "bigfloat", - "bigdecimal", -#endif + "Map", + "Set", + "Symbol", }; #endif -static inline BOOL is_be(void) -{ - union { - uint16_t a; - uint8_t b; - } u = {0x100}; - return u.b; -} - static void bc_put_u8(BCWriterState *s, uint8_t v) { dbuf_putc(&s->dbuf, v); @@ -35051,18 +34040,24 @@ static void bc_byte_swap(uint8_t *bc_buf, int bc_len) } } +static bool is_ic_op(uint8_t op) +{ + return op >= OP_get_field_ic && op <= OP_put_field_ic; +} + static int JS_WriteFunctionBytecode(BCWriterState *s, - const uint8_t *bc_buf1, int bc_len) + const JSFunctionBytecode *b) { - int pos, len, op; + int pos, len, bc_len, op; JSAtom atom; uint8_t *bc_buf; uint32_t val; + bc_len = b->byte_code_len; bc_buf = js_malloc(s->ctx, bc_len); if (!bc_buf) return -1; - memcpy(bc_buf, bc_buf1, bc_len); + memcpy(bc_buf, b->byte_code_buf, bc_len); pos = 0; while (pos < bc_len) { @@ -35080,6 +34075,16 @@ static int JS_WriteFunctionBytecode(BCWriterState *s, put_u32(bc_buf + pos + 1, val); break; default: + // IC (inline cache) opcodes should not end up in the serialized + // bytecode; translate them to their non-IC counterparts here + if (is_ic_op(op)) { + val = get_u32(bc_buf + pos + 1); + atom = get_ic_atom(b->ic, val); + if (bc_atom_to_idx(s, &val, atom)) + goto fail; + put_u32(bc_buf + pos + 1, val); + bc_buf[pos] -= (OP_get_field_ic - OP_get_field); + } break; } pos += len; @@ -35109,11 +34114,11 @@ static void JS_WriteString(BCWriterState *s, JSString *p) } } -static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj) +static int JS_WriteBigInt(BCWriterState *s, JSValue obj) { uint32_t tag, tag1; int64_t e; - JSBigFloat *bf = JS_VALUE_GET_PTR(obj); + JSBigInt *bf = JS_VALUE_GET_PTR(obj); bf_t *a = &bf->num; size_t len, i, n1, j; limb_t v; @@ -35123,14 +34128,6 @@ static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj) case JS_TAG_BIG_INT: tag1 = BC_TAG_BIG_INT; break; -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: - tag1 = BC_TAG_BIG_FLOAT; - break; - case JS_TAG_BIG_DECIMAL: - tag1 = BC_TAG_BIG_DECIMAL; - break; -#endif default: abort(); } @@ -35149,100 +34146,49 @@ static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj) e = a->expn; e = (e * 2) | a->sign; if (e < INT32_MIN || e > INT32_MAX) { - JS_ThrowInternalError(s->ctx, "bignum exponent is too large"); + JS_ThrowRangeError(s->ctx, "maximum BigInt size exceeded"); return -1; } bc_put_sleb128(s, e); /* mantissa */ if (a->len != 0) { - if (tag != JS_TAG_BIG_DECIMAL) { - i = 0; - while (i < a->len && a->tab[i] == 0) - i++; - assert(i < a->len); - v = a->tab[i]; - n1 = sizeof(limb_t); - while ((v & 0xff) == 0) { - n1--; - v >>= 8; - } + i = 0; + while (i < a->len && a->tab[i] == 0) i++; - len = (a->len - i) * sizeof(limb_t) + n1; - if (len > INT32_MAX) { - JS_ThrowInternalError(s->ctx, "bignum is too large"); - return -1; - } - bc_put_leb128(s, len); - /* always saved in byte based little endian representation */ - for(j = 0; j < n1; j++) { - bc_put_u8(s, v >> (j * 8)); - } - for(; i < a->len; i++) { - limb_t v = a->tab[i]; + assert(i < a->len); + v = a->tab[i]; + n1 = sizeof(limb_t); + while ((v & 0xff) == 0) { + n1--; + v >>= 8; + } + i++; + len = (a->len - i) * sizeof(limb_t) + n1; + if (len > INT32_MAX) { + JS_ThrowRangeError(s->ctx, "maximum BigInt size exceeded"); + return -1; + } + bc_put_leb128(s, len); + /* always saved in byte based little endian representation */ + for(j = 0; j < n1; j++) { + bc_put_u8(s, v >> (j * 8)); + } + for(; i < a->len; i++) { + limb_t v = a->tab[i]; #if LIMB_BITS == 32 - bc_put_u32(s, v); + bc_put_u32(s, v); #else - bc_put_u64(s, v); + bc_put_u64(s, v); #endif - } - } else { - int bpos, d; - uint8_t v8; - size_t i0; - - /* little endian BCD */ - i = 0; - while (i < a->len && a->tab[i] == 0) - i++; - assert(i < a->len); - len = a->len * LIMB_DIGITS; - v = a->tab[i]; - j = 0; - while ((v % 10) == 0) { - j++; - v /= 10; - } - len -= j; - assert(len > 0); - if (len > INT32_MAX) { - JS_ThrowInternalError(s->ctx, "bignum is too large"); - return -1; - } - bc_put_leb128(s, len); - - bpos = 0; - v8 = 0; - i0 = i; - for(; i < a->len; i++) { - if (i != i0) { - v = a->tab[i]; - j = 0; - } - for(; j < LIMB_DIGITS; j++) { - d = v % 10; - v /= 10; - if (bpos == 0) { - v8 = d; - bpos = 1; - } else { - bc_put_u8(s, v8 | (d << 4)); - bpos = 0; - } - } - } - /* flush the last digit */ - if (bpos) { - bc_put_u8(s, v8); - } } } return 0; } -static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj); +static int JS_WriteObjectRec(BCWriterState *s, JSValue obj); -static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj) +static int JS_WriteFunctionTag(BCWriterState *s, JSValue obj) { JSFunctionBytecode *b = JS_VALUE_GET_PTR(obj); uint32_t flags; @@ -35259,12 +34205,11 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj) bc_set_flags(&flags, &idx, b->super_call_allowed, 1); bc_set_flags(&flags, &idx, b->super_allowed, 1); bc_set_flags(&flags, &idx, b->arguments_allowed, 1); - bc_set_flags(&flags, &idx, b->has_debug, 1); bc_set_flags(&flags, &idx, b->backtrace_barrier, 1); - bc_set_flags(&flags, &idx, b->is_direct_or_indirect_eval, 1); + bc_set_flags(&flags, &idx, s->allow_debug, 1); assert(idx <= 16); bc_put_u16(s, flags); - bc_put_u8(s, b->js_mode); + bc_put_u8(s, b->is_strict_mode); bc_put_atom(s, b->func_name); bc_put_leb128(s, b->arg_count); @@ -35308,26 +34253,35 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj) bc_put_u8(s, flags); } - if (JS_WriteFunctionBytecode(s, b->byte_code_buf, b->byte_code_len)) - goto fail; - - if (b->has_debug) { - bc_put_atom(s, b->debug.filename); - bc_put_leb128(s, b->debug.line_num); - bc_put_leb128(s, b->debug.pc2line_len); - dbuf_put(&s->dbuf, b->debug.pc2line_buf, b->debug.pc2line_len); - } - + // write constant pool before code so code can be disassembled + // on the fly at read time for(i = 0; i < b->cpool_count; i++) { if (JS_WriteObjectRec(s, b->cpool[i])) goto fail; } + + if (JS_WriteFunctionBytecode(s, b)) + goto fail; + + if (s->allow_debug) { + bc_put_atom(s, b->filename); + bc_put_leb128(s, b->line_num); + bc_put_leb128(s, b->col_num); + bc_put_leb128(s, b->pc2line_len); + dbuf_put(&s->dbuf, b->pc2line_buf, b->pc2line_len); + if (s->allow_source && b->source) { + bc_put_leb128(s, b->source_len); + dbuf_put(&s->dbuf, b->source, b->source_len); + } else { + bc_put_leb128(s, 0); + } + } return 0; fail: return -1; } -static int JS_WriteModule(BCWriterState *s, JSValueConst obj) +static int JS_WriteModule(BCWriterState *s, JSValue obj) { JSModuleDef *m = JS_VALUE_GET_PTR(obj); int i; @@ -35377,22 +34331,22 @@ static int JS_WriteModule(BCWriterState *s, JSValueConst obj) return -1; } -static int JS_WriteArray(BCWriterState *s, JSValueConst obj) +static int JS_WriteArray(BCWriterState *s, JSValue obj) { JSObject *p = JS_VALUE_GET_OBJ(obj); uint32_t i, len; JSValue val; int ret; - BOOL is_template; + bool is_template; if (s->allow_bytecode && !p->extensible) { /* not extensible array: we consider it is a template when we are saving bytecode */ bc_put_u8(s, BC_TAG_TEMPLATE_OBJECT); - is_template = TRUE; + is_template = true; } else { bc_put_u8(s, BC_TAG_ARRAY); - is_template = FALSE; + is_template = false; } if (js_get_length32(s->ctx, &len, obj)) goto fail1; @@ -35420,7 +34374,7 @@ static int JS_WriteArray(BCWriterState *s, JSValueConst obj) return -1; } -static int JS_WriteObjectTag(BCWriterState *s, JSValueConst obj) +static int JS_WriteObjectTag(BCWriterState *s, JSValue obj) { JSObject *p = JS_VALUE_GET_OBJ(obj); uint32_t i, prop_count; @@ -35437,9 +34391,7 @@ static int JS_WriteObjectTag(BCWriterState *s, JSValueConst obj) bc_put_leb128(s, prop_count); for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) { atom = pr->atom; - if (atom != JS_ATOM_NULL && - JS_AtomIsString(s->ctx, atom) && - (pr->flags & JS_PROP_ENUMERABLE)) { + if (atom != JS_ATOM_NULL && (pr->flags & JS_PROP_ENUMERABLE)) { if (pr->flags & JS_PROP_TMASK) { JS_ThrowTypeError(s->ctx, "only value properties are supported"); goto fail; @@ -35459,7 +34411,7 @@ static int JS_WriteObjectTag(BCWriterState *s, JSValueConst obj) return -1; } -static int JS_WriteTypedArray(BCWriterState *s, JSValueConst obj) +static int JS_WriteTypedArray(BCWriterState *s, JSValue obj) { JSObject *p = JS_VALUE_GET_OBJ(obj); JSTypedArray *ta = p->u.typed_array; @@ -35473,7 +34425,7 @@ static int JS_WriteTypedArray(BCWriterState *s, JSValueConst obj) return 0; } -static int JS_WriteArrayBuffer(BCWriterState *s, JSValueConst obj) +static int JS_WriteArrayBuffer(BCWriterState *s, JSValue obj) { JSObject *p = JS_VALUE_GET_OBJ(obj); JSArrayBuffer *abuf = p->u.array_buffer; @@ -35483,17 +34435,19 @@ static int JS_WriteArrayBuffer(BCWriterState *s, JSValueConst obj) } bc_put_u8(s, BC_TAG_ARRAY_BUFFER); bc_put_leb128(s, abuf->byte_length); + bc_put_leb128(s, abuf->max_byte_length); dbuf_put(&s->dbuf, abuf->data, abuf->byte_length); return 0; } -static int JS_WriteSharedArrayBuffer(BCWriterState *s, JSValueConst obj) +static int JS_WriteSharedArrayBuffer(BCWriterState *s, JSValue obj) { JSObject *p = JS_VALUE_GET_OBJ(obj); JSArrayBuffer *abuf = p->u.array_buffer; assert(!abuf->detached); /* SharedArrayBuffer are never detached */ bc_put_u8(s, BC_TAG_SHARED_ARRAY_BUFFER); bc_put_leb128(s, abuf->byte_length); + bc_put_leb128(s, abuf->max_byte_length); bc_put_u64(s, (uintptr_t)abuf->data); if (js_resize_array(s->ctx, (void **)&s->sab_tab, sizeof(s->sab_tab[0]), &s->sab_tab_size, s->sab_tab_len + 1)) @@ -35503,7 +34457,28 @@ static int JS_WriteSharedArrayBuffer(BCWriterState *s, JSValueConst obj) return 0; } -static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj) +static int JS_WriteRegExp(BCWriterState *s, JSRegExp regexp) +{ + JSString *bc = regexp.bytecode; + assert(!bc->is_wide_char); + + JS_WriteString(s, regexp.pattern); + + if (is_be()) + lre_byte_swap(bc->u.str8, bc->len, /*is_byte_swapped*/false); + + JS_WriteString(s, bc); + + if (is_be()) + lre_byte_swap(bc->u.str8, bc->len, /*is_byte_swapped*/true); + + return 0; +} + +static int JS_WriteMap(BCWriterState *s, struct JSMapState *map_state); +static int JS_WriteSet(BCWriterState *s, struct JSMapState *map_state); + +static int JS_WriteObjectRec(BCWriterState *s, JSValue obj) { uint32_t tag; @@ -35591,6 +34566,10 @@ static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj) goto invalid_tag; ret = JS_WriteSharedArrayBuffer(s, obj); break; + case JS_CLASS_REGEXP: + bc_put_u8(s, BC_TAG_REGEXP); + ret = JS_WriteRegExp(s, p->u.regexp); + break; case JS_CLASS_DATE: bc_put_u8(s, BC_TAG_DATE); ret = JS_WriteObjectRec(s, p->u.object_data); @@ -35599,16 +34578,19 @@ static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj) case JS_CLASS_STRING: case JS_CLASS_BOOLEAN: case JS_CLASS_BIG_INT: -#ifdef CONFIG_BIGNUM - case JS_CLASS_BIG_FLOAT: - case JS_CLASS_BIG_DECIMAL: -#endif bc_put_u8(s, BC_TAG_OBJECT_VALUE); ret = JS_WriteObjectRec(s, p->u.object_data); break; + case JS_CLASS_MAP: + bc_put_u8(s, BC_TAG_MAP); + ret = JS_WriteMap(s, p->u.map_state); + break; + case JS_CLASS_SET: + bc_put_u8(s, BC_TAG_SET); + ret = JS_WriteSet(s, p->u.map_state); + break; default: - if (p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_FLOAT64_ARRAY) { + if (is_typed_array(p->class_id)) { ret = JS_WriteTypedArray(s, obj); } else { JS_ThrowTypeError(s->ctx, "unsupported object class"); @@ -35622,13 +34604,21 @@ static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj) } break; case JS_TAG_BIG_INT: -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: - case JS_TAG_BIG_DECIMAL: -#endif - if (JS_WriteBigNum(s, obj)) + if (JS_WriteBigInt(s, obj)) goto fail; break; + case JS_TAG_SYMBOL: + { + JSAtomStruct *p = JS_VALUE_GET_PTR(obj); + if (p->atom_type != JS_ATOM_TYPE_GLOBAL_SYMBOL && p->atom_type != JS_ATOM_TYPE_SYMBOL) { + JS_ThrowTypeError(s->ctx, "unsupported symbol type"); + goto fail; + } + JSAtom atom = js_get_atom_index(s->ctx->rt, p); + bc_put_u8(s, BC_TAG_SYMBOL); + bc_put_atom(s, atom); + } + break; default: invalid_tag: JS_ThrowInternalError(s->ctx, "unsupported tag (%d)", tag); @@ -35653,8 +34643,19 @@ static int JS_WriteObjectAtoms(BCWriterState *s) bc_put_leb128(s, s->idx_to_atom_count); for(i = 0; i < s->idx_to_atom_count; i++) { - JSAtomStruct *p = rt->atom_array[s->idx_to_atom[i]]; - JS_WriteString(s, p); + JSAtom atom = s->idx_to_atom[i]; + if (__JS_AtomIsConst(atom)) { + bc_put_u8(s, 0 /* the type */); + /* TODO(saghul): encoding for tagged integers and keyword-ish atoms could be + more efficient. */ + bc_put_u32(s, atom); + } else { + JSAtomStruct *p = rt->atom_array[atom]; + uint8_t type = p->atom_type; + assert(type != JS_ATOM_TYPE_PRIVATE); + bc_put_u8(s, type); + JS_WriteString(s, p); + } } /* XXX: should check for OOM in above phase */ @@ -35675,8 +34676,8 @@ static int JS_WriteObjectAtoms(BCWriterState *s) return -1; } -uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj, - int flags, uint8_t ***psab_tab, size_t *psab_tab_len) +uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValue obj, + int flags, JSSABTab *psab_tab) { BCWriterState ss, *s = &ss; @@ -35685,6 +34686,8 @@ uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj, s->allow_bytecode = ((flags & JS_WRITE_OBJ_BYTECODE) != 0); s->allow_sab = ((flags & JS_WRITE_OBJ_SAB) != 0); s->allow_reference = ((flags & JS_WRITE_OBJ_REFERENCE) != 0); + s->allow_source = ((flags & JS_WRITE_OBJ_STRIP_SOURCE) == 0); + s->allow_debug = ((flags & JS_WRITE_OBJ_STRIP_DEBUG) == 0); /* XXX: could use a different version when bytecode is included */ if (s->allow_bytecode) s->first_atom = JS_ATOM_END; @@ -35701,10 +34704,12 @@ uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj, js_free(ctx, s->atom_to_idx); js_free(ctx, s->idx_to_atom); *psize = s->dbuf.size; - if (psab_tab) - *psab_tab = s->sab_tab; - if (psab_tab_len) - *psab_tab_len = s->sab_tab_len; + if (psab_tab) { + psab_tab->tab = s->sab_tab; + psab_tab->len = s->sab_tab_len; + } else { + js_free(ctx, s->sab_tab); + } return s->dbuf.buf; fail: js_object_list_end(ctx, &s->object_list); @@ -35712,17 +34717,17 @@ uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj, js_free(ctx, s->idx_to_atom); dbuf_free(&s->dbuf); *psize = 0; - if (psab_tab) - *psab_tab = NULL; - if (psab_tab_len) - *psab_tab_len = 0; + if (psab_tab) { + psab_tab->tab = NULL; + psab_tab->len = 0; + } return NULL; } -uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj, +uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValue obj, int flags) { - return JS_WriteObject2(ctx, psize, obj, flags, NULL, NULL); + return JS_WriteObject2(ctx, psize, obj, flags, NULL); } typedef struct BCReaderState { @@ -35732,26 +34737,30 @@ typedef struct BCReaderState { uint32_t idx_to_atom_count; JSAtom *idx_to_atom; int error_state; - BOOL allow_sab : 8; - BOOL allow_bytecode : 8; - BOOL is_rom_data : 8; - BOOL allow_reference : 8; + bool allow_sab; + bool allow_bytecode; + bool allow_reference; /* object references */ JSObject **objects; int objects_count; int objects_size; - -#ifdef DUMP_READ_OBJECT + /* SAB references */ + uint8_t **sab_tab; + int sab_tab_len; + int sab_tab_size; + /* used for JS_DUMP_READ_OBJECT */ const uint8_t *ptr_last; int level; -#endif } BCReaderState; -#ifdef DUMP_READ_OBJECT -static void FORMAT_ATTR(2, 3) bc_read_trace(BCReaderState *s, const char *fmt, ...) { +#ifdef ENABLE_DUMPS // JS_DUMP_READ_OBJECT +static void JS_PRINTF_FORMAT_ATTR(2, 3) bc_read_trace(BCReaderState *s, JS_PRINTF_FORMAT const char *fmt, ...) { va_list ap; int i, n, n0; + if (!check_dump_flag(s->ctx->rt, JS_DUMP_READ_OBJECT)) + return; + if (!s->ptr_last) s->ptr_last = s->buf_start; @@ -35882,7 +34891,7 @@ static int bc_get_leb128_u16(BCReaderState *s, uint16_t *pval) return 0; } -static int bc_get_buf(BCReaderState *s, uint8_t *buf, uint32_t buf_len) +static int bc_get_buf(BCReaderState *s, void *buf, uint32_t buf_len) { if (buf_len != 0) { if (unlikely(!buf || s->buf_end - s->ptr < buf_len)) @@ -35932,7 +34941,7 @@ static JSString *JS_ReadString(BCReaderState *s) { uint32_t len; size_t size; - BOOL is_wide_char; + bool is_wide_char; JSString *p; if (bc_get_leb128(s, &len)) @@ -35961,8 +34970,12 @@ static JSString *JS_ReadString(BCReaderState *s) } else { p->u.str8[size] = '\0'; /* add the trailing zero for 8 bit strings */ } -#ifdef DUMP_READ_OBJECT - JS_DumpString(s->ctx->rt, p); printf("\n"); +#ifdef ENABLE_DUMPS // JS_DUMP_READ_OBJECT + if (check_dump_flag(s->ctx->rt, JS_DUMP_READ_OBJECT)) { + bc_read_trace(s, "%s", ""); // hex dump and indentation + JS_DumpString(s->ctx->rt, p); + printf("\n"); + } #endif return p; } @@ -35984,17 +34997,9 @@ static int JS_ReadFunctionBytecode(BCReaderState *s, JSFunctionBytecode *b, JSAtom atom; uint32_t idx; - if (s->is_rom_data) { - /* directly use the input buffer */ - if (unlikely(s->buf_end - s->ptr < bc_len)) - return bc_read_error_end(s); - bc_buf = (uint8_t *)s->ptr; - s->ptr += bc_len; - } else { - bc_buf = (void *)((uint8_t*)b + byte_code_offset); - if (bc_get_buf(s, bc_buf, bc_len)) - return -1; - } + bc_buf = (uint8_t*)b + byte_code_offset; + if (bc_get_buf(s, bc_buf, bc_len)) + return -1; b->byte_code_buf = bc_buf; if (is_be()) @@ -36011,64 +35016,53 @@ static int JS_ReadFunctionBytecode(BCReaderState *s, JSFunctionBytecode *b, case OP_FMT_atom_label_u8: case OP_FMT_atom_label_u16: idx = get_u32(bc_buf + pos + 1); - if (s->is_rom_data) { - /* just increment the reference count of the atom */ - JS_DupAtom(s->ctx, (JSAtom)idx); - } else { - if (bc_idx_to_atom(s, &atom, idx)) { - /* Note: the atoms will be freed up to this position */ - b->byte_code_len = pos; - return -1; - } - put_u32(bc_buf + pos + 1, atom); -#ifdef DUMP_READ_OBJECT - bc_read_trace(s, "at %d, fixup atom: ", pos + 1); print_atom(s->ctx, atom); printf("\n"); -#endif + if (bc_idx_to_atom(s, &atom, idx)) { + /* Note: the atoms will be freed up to this position */ + b->byte_code_len = pos; + return -1; } + put_u32(bc_buf + pos + 1, atom); break; default: + assert(!is_ic_op(op)); // should not end up in serialized bytecode break; } +#ifdef ENABLE_DUMPS // JS_DUMP_READ_OBJECT + if (check_dump_flag(s->ctx->rt, JS_DUMP_READ_OBJECT)) { + const uint8_t *save_ptr = s->ptr; + s->ptr = s->ptr_last + len; + s->level -= 4; + bc_read_trace(s, "%s", ""); // hex dump + indent + dump_single_byte_code(s->ctx, bc_buf + pos, b, + s->ptr - s->buf_start - len); + s->level += 4; + s->ptr = save_ptr; + } +#endif pos += len; } return 0; } -static JSValue JS_ReadBigNum(BCReaderState *s, int tag) +static JSValue JS_ReadBigInt(BCReaderState *s) { - JSValue obj = JS_UNDEFINED; + JSValue obj; uint8_t v8; int32_t e; uint32_t len; limb_t l, i, n; - JSBigFloat *p; limb_t v; bf_t *a; - p = js_new_bf(s->ctx); - if (!p) + obj = JS_NewBigInt(s->ctx); + if (JS_IsException(obj)) goto fail; - switch(tag) { - case BC_TAG_BIG_INT: - obj = JS_MKPTR(JS_TAG_BIG_INT, p); - break; -#ifdef CONFIG_BIGNUM - case BC_TAG_BIG_FLOAT: - obj = JS_MKPTR(JS_TAG_BIG_FLOAT, p); - break; - case BC_TAG_BIG_DECIMAL: - obj = JS_MKPTR(JS_TAG_BIG_DECIMAL, p); - break; -#endif - default: - abort(); - } /* sign + exponent */ if (bc_get_sleb128(s, &e)) goto fail; - a = &p->num; + a = JS_GetBigInt(obj); a->sign = e & 1; e >>= 1; if (e == 0) @@ -36090,81 +35084,38 @@ static JSValue JS_ReadBigNum(BCReaderState *s, int tag) goto fail; bc_read_trace(s, "len=%" PRId64 "\n", (int64_t)len); if (len == 0) { - JS_ThrowInternalError(s->ctx, "invalid bignum length"); + JS_ThrowRangeError(s->ctx, "maximum BigInt size exceeded"); goto fail; } -#ifdef CONFIG_BIGNUM - if (tag == BC_TAG_BIG_DECIMAL) { - l = (len + LIMB_DIGITS - 1) / LIMB_DIGITS; - } else -#endif - { - l = (len + sizeof(limb_t) - 1) / sizeof(limb_t); - } + l = (len + sizeof(limb_t) - 1) / sizeof(limb_t); if (bf_resize(a, l)) { JS_ThrowOutOfMemory(s->ctx); goto fail; } -#ifdef CONFIG_BIGNUM - if (tag == BC_TAG_BIG_DECIMAL) { - limb_t j; - int bpos, d; - - bpos = 0; - for(i = 0; i < l; i++) { - if (i == 0 && (n = len % LIMB_DIGITS) != 0) { - j = LIMB_DIGITS - n; - } else { - j = 0; - } - v = 0; - for(; j < LIMB_DIGITS; j++) { - if (bpos == 0) { - if (bc_get_u8(s, &v8)) - goto fail; - d = v8 & 0xf; - bpos = 1; - } else { - d = v8 >> 4; - bpos = 0; - } - if (d >= 10) { - JS_ThrowInternalError(s->ctx, "invalid digit"); - goto fail; - } - v += mp_pow_dec[j] * d; - } - a->tab[i] = v; - } - } else -#endif /* CONFIG_BIGNUM */ - { - n = len & (sizeof(limb_t) - 1); - if (n != 0) { - v = 0; - for(i = 0; i < n; i++) { - if (bc_get_u8(s, &v8)) - goto fail; - v |= (limb_t)v8 << ((sizeof(limb_t) - n + i) * 8); - } - a->tab[0] = v; - i = 1; - } else { - i = 0; + n = len & (sizeof(limb_t) - 1); + if (n != 0) { + v = 0; + for(i = 0; i < n; i++) { + if (bc_get_u8(s, &v8)) + goto fail; + v |= (limb_t)v8 << ((sizeof(limb_t) - n + i) * 8); } - for(; i < l; i++) { + a->tab[0] = v; + i = 1; + } else { + i = 0; + } + for(; i < l; i++) { #if LIMB_BITS == 32 - if (bc_get_u32(s, &v)) - goto fail; + if (bc_get_u32(s, &v)) + goto fail; #else - if (bc_get_u64(s, &v)) - goto fail; + if (bc_get_u64(s, &v)) + goto fail; #endif - a->tab[i] = v; - } + a->tab[i] = v; } } - bc_read_trace(s, "}\n"); return obj; fail: JS_FreeValue(s->ctx, obj); @@ -36185,7 +35136,7 @@ static int BC_add_object_ref1(BCReaderState *s, JSObject *p) return 0; } -static int BC_add_object_ref(BCReaderState *s, JSValueConst obj) +static int BC_add_object_ref(BCReaderState *s, JSValue obj) { return BC_add_object_ref1(s, JS_VALUE_GET_OBJ(obj)); } @@ -36197,7 +35148,7 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s) JSValue obj = JS_UNDEFINED; uint16_t v16; uint8_t v8; - int idx, i, local_count; + int idx, i, local_count, has_debug_info; int function_size, cpool_offset, byte_code_offset; int closure_var_offset, vardefs_offset; @@ -36217,14 +35168,12 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s) bc.super_call_allowed = bc_get_flags(v16, &idx, 1); bc.super_allowed = bc_get_flags(v16, &idx, 1); bc.arguments_allowed = bc_get_flags(v16, &idx, 1); - bc.has_debug = bc_get_flags(v16, &idx, 1); bc.backtrace_barrier = bc_get_flags(v16, &idx, 1); - bc.is_direct_or_indirect_eval = bc_get_flags(v16, &idx, 1); - bc.read_only_bytecode = s->is_rom_data; + has_debug_info = bc_get_flags(v16, &idx, 1); if (bc_get_u8(s, &v8)) goto fail; - bc.js_mode = v8; - if (bc_get_atom(s, &bc.func_name)) //@ atom leak if failure + bc.is_strict_mode = (v8 > 0); + if (bc_get_atom(s, &bc.func_name)) goto fail; if (bc_get_leb128_u16(s, &bc.arg_count)) goto fail; @@ -36243,11 +35192,7 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s) if (bc_get_leb128_int(s, &local_count)) goto fail; - if (bc.has_debug) { - function_size = sizeof(*b); - } else { - function_size = offsetof(JSFunctionBytecode, debug); - } + function_size = sizeof(*b); cpool_offset = function_size; function_size += bc.cpool_count * sizeof(*bc.cpool); vardefs_offset = function_size; @@ -36255,15 +35200,14 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s) closure_var_offset = function_size; function_size += bc.closure_var_count * sizeof(*bc.closure_var); byte_code_offset = function_size; - if (!bc.read_only_bytecode) { - function_size += bc.byte_code_len; - } + function_size += bc.byte_code_len; b = js_mallocz(ctx, function_size); if (!b) - return JS_EXCEPTION; + goto fail; - memcpy(b, &bc, offsetof(JSFunctionBytecode, debug)); + memcpy(b, &bc, sizeof(*b)); + bc.func_name = JS_ATOM_NULL; b->header.ref_count = 1; if (local_count != 0) { b->vardefs = (void *)((uint8_t*)b + vardefs_offset); @@ -36279,8 +35223,14 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s) obj = JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b); -#ifdef DUMP_READ_OBJECT - bc_read_trace(s, "name: "); print_atom(s->ctx, b->func_name); printf("\n"); +#ifdef ENABLE_DUMPS // JS_DUMP_READ_OBJECT + if (check_dump_flag(s->ctx->rt, JS_DUMP_READ_OBJECT)) { + if (b->func_name) { + bc_read_trace(s, "name: "); + print_atom(s->ctx, b->func_name); + printf("\n"); + } + } #endif bc_read_trace(s, "args=%d vars=%d defargs=%d closures=%d cpool=%d\n", b->arg_count, b->var_count, b->defined_arg_count, @@ -36290,6 +35240,7 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s) if (local_count != 0) { bc_read_trace(s, "vars {\n"); + bc_read_trace(s, "off flags scope name\n"); for(i = 0; i < local_count; i++) { JSVarDef *vd = &b->vardefs[i]; if (bc_get_atom(s, &vd->var_name)) @@ -36306,14 +35257,24 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s) 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); -#ifdef DUMP_READ_OBJECT - bc_read_trace(s, "name: "); print_atom(s->ctx, vd->var_name); printf("\n"); +#ifdef ENABLE_DUMPS // JS_DUMP_READ_OBJECT + if (check_dump_flag(s->ctx->rt, JS_DUMP_READ_OBJECT)) { + bc_read_trace(s, "%3d %d%c%c%c %4d ", + i, vd->var_kind, + vd->is_const ? 'C' : '.', + vd->is_lexical ? 'L' : '.', + vd->is_captured ? 'X' : '.', + vd->scope_level); + print_atom(s->ctx, vd->var_name); + printf("\n"); + } #endif } bc_read_trace(s, "}\n"); } if (b->closure_var_count != 0) { bc_read_trace(s, "closure vars {\n"); + bc_read_trace(s, "off flags idx name\n"); for(i = 0; i < b->closure_var_count; i++) { JSClosureVar *cv = &b->closure_var[i]; int var_idx; @@ -36330,39 +35291,22 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s) cv->is_const = bc_get_flags(v8, &idx, 1); cv->is_lexical = bc_get_flags(v8, &idx, 1); cv->var_kind = bc_get_flags(v8, &idx, 4); -#ifdef DUMP_READ_OBJECT - bc_read_trace(s, "name: "); print_atom(s->ctx, cv->var_name); printf("\n"); +#ifdef ENABLE_DUMPS // JS_DUMP_READ_OBJECT + if (check_dump_flag(s->ctx->rt, JS_DUMP_READ_OBJECT)) { + bc_read_trace(s, "%3d %d%c%c%c%c %3d ", + i, cv->var_kind, + cv->is_local ? 'L' : '.', + cv->is_arg ? 'A' : '.', + cv->is_const ? 'C' : '.', + cv->is_lexical ? 'X' : '.', + cv->var_idx); + print_atom(s->ctx, cv->var_name); + printf("\n"); + } #endif } bc_read_trace(s, "}\n"); } - { - bc_read_trace(s, "bytecode {\n"); - if (JS_ReadFunctionBytecode(s, b, byte_code_offset, b->byte_code_len)) - goto fail; - bc_read_trace(s, "}\n"); - } - if (b->has_debug) { - /* read optional debug information */ - bc_read_trace(s, "debug {\n"); - if (bc_get_atom(s, &b->debug.filename)) - goto fail; - if (bc_get_leb128_int(s, &b->debug.line_num)) - goto fail; - if (bc_get_leb128_int(s, &b->debug.pc2line_len)) - goto fail; - if (b->debug.pc2line_len) { - b->debug.pc2line_buf = js_mallocz(ctx, b->debug.pc2line_len); - if (!b->debug.pc2line_buf) - goto fail; - if (bc_get_buf(s, b->debug.pc2line_buf, b->debug.pc2line_len)) - goto fail; - } -#ifdef DUMP_READ_OBJECT - bc_read_trace(s, "filename: "); print_atom(s->ctx, b->debug.filename); printf("\n"); -#endif - bc_read_trace(s, "}\n"); - } if (b->cpool_count != 0) { bc_read_trace(s, "cpool {\n"); for(i = 0; i < b->cpool_count; i++) { @@ -36374,9 +35318,61 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s) } bc_read_trace(s, "}\n"); } + { + bc_read_trace(s, "bytecode {\n"); + if (JS_ReadFunctionBytecode(s, b, byte_code_offset, b->byte_code_len)) + goto fail; + bc_read_trace(s, "}\n"); + } + if (!has_debug_info) + goto nodebug; + + /* read optional debug information */ + bc_read_trace(s, "debug {\n"); + if (bc_get_atom(s, &b->filename)) + goto fail; + if (bc_get_leb128_int(s, &b->line_num)) + goto fail; + if (bc_get_leb128_int(s, &b->col_num)) + goto fail; +#ifdef ENABLE_DUMPS // JS_DUMP_READ_OBJECT + if (check_dump_flag(s->ctx->rt, JS_DUMP_READ_OBJECT)) { + bc_read_trace(s, "filename: "); + print_atom(s->ctx, b->filename); + printf(", line: %d, column: %d\n", b->line_num, b->col_num); + } +#endif + if (bc_get_leb128_int(s, &b->pc2line_len)) + goto fail; + if (b->pc2line_len) { + bc_read_trace(s, "positions: %d bytes\n", b->pc2line_len); + b->pc2line_buf = js_mallocz(ctx, b->pc2line_len); + if (!b->pc2line_buf) + goto fail; + if (bc_get_buf(s, b->pc2line_buf, b->pc2line_len)) + goto fail; + } + if (bc_get_leb128_int(s, &b->source_len)) + goto fail; + if (b->source_len) { + bc_read_trace(s, "source: %d bytes\n", b->source_len); + if (s->ptr_last) + s->ptr_last += b->source_len; // omit source code hex dump + /* b->source is a UTF-8 encoded null terminated C string */ + b->source = js_mallocz(ctx, b->source_len + 1); + if (!b->source) + goto fail; + if (bc_get_buf(s, b->source, b->source_len)) + goto fail; + } + bc_read_trace(s, "}\n"); + + nodebug: b->realm = JS_DupContext(ctx); return obj; + fail: + JS_FreeAtom(ctx, bc.func_name); JS_FreeValue(ctx, obj); return JS_EXCEPTION; } @@ -36392,15 +35388,20 @@ static JSValue JS_ReadModule(BCReaderState *s) if (bc_get_atom(s, &module_name)) goto fail; -#ifdef DUMP_READ_OBJECT - bc_read_trace(s, "name: "); print_atom(s->ctx, module_name); printf("\n"); +#ifdef ENABLE_DUMPS // JS_DUMP_READ_OBJECT + if (check_dump_flag(s->ctx->rt, JS_DUMP_READ_OBJECT)) { + bc_read_trace(s, "name: "); + print_atom(s->ctx, module_name); + printf("\n"); + } #endif m = js_new_module_def(ctx, module_name); if (!m) goto fail; - obj = JS_NewModuleValue(ctx, m); + obj = js_dup(JS_MKPTR(JS_TAG_MODULE, m)); if (bc_get_leb128_int(s, &m->req_module_entries_count)) goto fail; + obj = JS_NewModuleValue(ctx, m); if (m->req_module_entries_count != 0) { m->req_module_entries_size = m->req_module_entries_count; m->req_module_entries = js_mallocz(ctx, sizeof(m->req_module_entries[0]) * m->req_module_entries_size); @@ -36503,8 +35504,12 @@ static JSValue JS_ReadObjectTag(BCReaderState *s) for(i = 0; i < prop_count; i++) { if (bc_get_atom(s, &atom)) goto fail; -#ifdef DUMP_READ_OBJECT - bc_read_trace(s, "propname: "); print_atom(s->ctx, atom); printf("\n"); +#ifdef ENABLE_DUMPS // JS_DUMP_READ_OBJECT + if (check_dump_flag(s->ctx->rt, JS_DUMP_READ_OBJECT)) { + bc_read_trace(s, "propname: "); + print_atom(s->ctx, atom); + printf("\n"); + } #endif val = JS_ReadObjectRec(s); if (JS_IsException(val)) { @@ -36529,7 +35534,7 @@ static JSValue JS_ReadArray(BCReaderState *s, int tag) uint32_t len, i; JSValue val; int ret, prop_flags; - BOOL is_template; + bool is_template; obj = JS_NewArray(ctx); if (BC_add_object_ref(s, obj)) @@ -36572,7 +35577,7 @@ static JSValue JS_ReadTypedArray(BCReaderState *s) JSContext *ctx = s->ctx; JSValue obj = JS_UNDEFINED, array_buffer = JS_UNDEFINED; uint8_t array_tag; - JSValueConst args[3]; + JSValue args[3]; uint32_t offset, len, idx; if (bc_get_u8(s, &array_tag)) @@ -36596,8 +35601,8 @@ static JSValue JS_ReadTypedArray(BCReaderState *s) return JS_EXCEPTION; } args[0] = array_buffer; - args[1] = JS_NewInt64(ctx, offset); - args[2] = JS_NewInt64(ctx, len); + args[1] = js_int64(offset); + args[2] = js_int64(len); obj = js_typed_array_constructor(ctx, JS_UNDEFINED, 3, args, JS_CLASS_UINT8C_ARRAY + array_tag); @@ -36617,16 +35622,31 @@ static JSValue JS_ReadTypedArray(BCReaderState *s) static JSValue JS_ReadArrayBuffer(BCReaderState *s) { JSContext *ctx = s->ctx; - uint32_t byte_length; + uint32_t byte_length, max_byte_length; + uint64_t max_byte_length_u64, *pmax_byte_length = NULL; JSValue obj; if (bc_get_leb128(s, &byte_length)) return JS_EXCEPTION; + if (bc_get_leb128(s, &max_byte_length)) + return JS_EXCEPTION; + if (max_byte_length < byte_length) + return JS_ThrowTypeError(ctx, "invalid array buffer"); + if (max_byte_length != UINT32_MAX) { + max_byte_length_u64 = max_byte_length; + pmax_byte_length = &max_byte_length_u64; + } if (unlikely(s->buf_end - s->ptr < byte_length)) { bc_read_error_end(s); return JS_EXCEPTION; } - obj = JS_NewArrayBufferCopy(ctx, s->ptr, byte_length); + // makes a copy of the input + obj = js_array_buffer_constructor3(ctx, JS_UNDEFINED, + byte_length, pmax_byte_length, + JS_CLASS_ARRAY_BUFFER, + (uint8_t*)s->ptr, + js_array_buffer_free, NULL, + /*alloc_flag*/true); if (JS_IsException(obj)) goto fail; if (BC_add_object_ref(s, obj)) @@ -36641,21 +35661,36 @@ static JSValue JS_ReadArrayBuffer(BCReaderState *s) static JSValue JS_ReadSharedArrayBuffer(BCReaderState *s) { JSContext *ctx = s->ctx; - uint32_t byte_length; + uint32_t byte_length, max_byte_length; + uint64_t max_byte_length_u64, *pmax_byte_length = NULL; uint8_t *data_ptr; JSValue obj; uint64_t u64; if (bc_get_leb128(s, &byte_length)) return JS_EXCEPTION; + if (bc_get_leb128(s, &max_byte_length)) + return JS_EXCEPTION; + if (max_byte_length < byte_length) + return JS_ThrowTypeError(ctx, "invalid array buffer"); + if (max_byte_length != UINT32_MAX) { + max_byte_length_u64 = max_byte_length; + pmax_byte_length = &max_byte_length_u64; + } if (bc_get_u64(s, &u64)) return JS_EXCEPTION; data_ptr = (uint8_t *)(uintptr_t)u64; + if (js_resize_array(s->ctx, (void **)&s->sab_tab, sizeof(s->sab_tab[0]), + &s->sab_tab_size, s->sab_tab_len + 1)) + return JS_EXCEPTION; + /* keep the SAB pointer so that the user can clone it or free it */ + s->sab_tab[s->sab_tab_len++] = data_ptr; /* the SharedArrayBuffer is cloned */ - obj = js_array_buffer_constructor3(ctx, JS_UNDEFINED, byte_length, + obj = js_array_buffer_constructor3(ctx, JS_UNDEFINED, + byte_length, pmax_byte_length, JS_CLASS_SHARED_ARRAY_BUFFER, data_ptr, - NULL, NULL, FALSE); + NULL, NULL, false); if (JS_IsException(obj)) goto fail; if (BC_add_object_ref(s, obj)) @@ -36666,6 +35701,36 @@ static JSValue JS_ReadSharedArrayBuffer(BCReaderState *s) return JS_EXCEPTION; } +static JSValue JS_ReadRegExp(BCReaderState *s) +{ + JSContext *ctx = s->ctx; + JSString *pattern; + JSString *bc; + + pattern = JS_ReadString(s); + if (!pattern) + return JS_EXCEPTION; + + bc = JS_ReadString(s); + if (!bc) { + js_free_string(ctx->rt, pattern); + return JS_EXCEPTION; + } + + if (bc->is_wide_char) { + js_free_string(ctx->rt, pattern); + js_free_string(ctx->rt, bc); + return JS_ThrowInternalError(ctx, "bad regexp bytecode"); + } + + if (is_be()) + lre_byte_swap(bc->u.str8, bc->len, /*is_byte_swapped*/true); + + return js_regexp_constructor_internal(ctx, JS_UNDEFINED, + JS_MKPTR(JS_TAG_STRING, pattern), + JS_MKPTR(JS_TAG_STRING, bc)); +} + static JSValue JS_ReadDate(BCReaderState *s) { JSContext *ctx = s->ctx; @@ -36713,6 +35778,9 @@ static JSValue JS_ReadObjectValue(BCReaderState *s) return JS_EXCEPTION; } +static JSValue JS_ReadMap(BCReaderState *s); +static JSValue JS_ReadSet(BCReaderState *s); + static JSValue JS_ReadObjectRec(BCReaderState *s) { JSContext *ctx = s->ctx; @@ -36736,7 +35804,7 @@ static JSValue JS_ReadObjectRec(BCReaderState *s) break; case BC_TAG_BOOL_FALSE: case BC_TAG_BOOL_TRUE: - obj = JS_NewBool(ctx, tag - BC_TAG_BOOL_FALSE); + obj = js_bool(tag - BC_TAG_BOOL_FALSE); break; case BC_TAG_INT32: { @@ -36744,7 +35812,7 @@ static JSValue JS_ReadObjectRec(BCReaderState *s) if (bc_get_sleb128(s, &val)) return JS_EXCEPTION; bc_read_trace(s, "%d\n", val); - obj = JS_NewInt32(ctx, val); + obj = js_int32(val); } break; case BC_TAG_FLOAT64: @@ -36753,7 +35821,7 @@ static JSValue JS_ReadObjectRec(BCReaderState *s) if (bc_get_u64(s, &u.u64)) return JS_EXCEPTION; bc_read_trace(s, "%g\n", u.d); - obj = __JS_NewFloat64(ctx, u.d); + obj = js_float64(u.d); } break; case BC_TAG_STRING: @@ -36767,12 +35835,14 @@ static JSValue JS_ReadObjectRec(BCReaderState *s) break; case BC_TAG_FUNCTION_BYTECODE: if (!s->allow_bytecode) - goto invalid_tag; + goto no_allow_bytecode; obj = JS_ReadFunctionTag(s); break; case BC_TAG_MODULE: - if (!s->allow_bytecode) - goto invalid_tag; + if (!s->allow_bytecode) { + no_allow_bytecode: + return JS_ThrowSyntaxError(ctx, "no bytecode allowed"); + } obj = JS_ReadModule(s); break; case BC_TAG_OBJECT: @@ -36793,6 +35863,9 @@ static JSValue JS_ReadObjectRec(BCReaderState *s) goto invalid_tag; obj = JS_ReadSharedArrayBuffer(s); break; + case BC_TAG_REGEXP: + obj = JS_ReadRegExp(s); + break; case BC_TAG_DATE: obj = JS_ReadDate(s); break; @@ -36800,11 +35873,7 @@ static JSValue JS_ReadObjectRec(BCReaderState *s) obj = JS_ReadObjectValue(s); break; case BC_TAG_BIG_INT: -#ifdef CONFIG_BIGNUM - case BC_TAG_BIG_FLOAT: - case BC_TAG_BIG_DECIMAL: -#endif - obj = JS_ReadBigNum(s, tag); + obj = JS_ReadBigInt(s); break; case BC_TAG_OBJECT_REFERENCE: { @@ -36818,7 +35887,26 @@ static JSValue JS_ReadObjectRec(BCReaderState *s) return JS_ThrowSyntaxError(ctx, "invalid object reference (%u >= %u)", val, s->objects_count); } - obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, s->objects[val])); + obj = js_dup(JS_MKPTR(JS_TAG_OBJECT, s->objects[val])); + } + break; + case BC_TAG_MAP: + obj = JS_ReadMap(s); + break; + case BC_TAG_SET: + obj = JS_ReadSet(s); + break; + case BC_TAG_SYMBOL: + { + JSAtom atom; + if (bc_get_atom(s, &atom)) + return JS_EXCEPTION; + if (__JS_AtomIsConst(atom)) { + obj = JS_AtomToValue(s->ctx, atom); + } else { + JSAtomStruct *p = s->ctx->rt->atom_array[atom]; + obj = JS_NewSymbolFromAtom(s->ctx, atom, p->atom_type); + } } break; default: @@ -36832,7 +35920,7 @@ static JSValue JS_ReadObjectRec(BCReaderState *s) static int JS_ReadObjectAtoms(BCReaderState *s) { - uint8_t v8; + uint8_t v8, type; JSString *p; int i; JSAtom atom; @@ -36846,8 +35934,13 @@ static int JS_ReadObjectAtoms(BCReaderState *s) } if (bc_get_leb128(s, &s->idx_to_atom_count)) return -1; + if (s->idx_to_atom_count > 1000*1000) { + JS_ThrowInternalError(s->ctx, "unreasonable atom count: %u", + s->idx_to_atom_count); + return -1; + } - bc_read_trace(s, "%d atom indexes {\n", s->idx_to_atom_count); + bc_read_trace(s, "%u atom indexes {\n", s->idx_to_atom_count); if (s->idx_to_atom_count != 0) { s->idx_to_atom = js_mallocz(s->ctx, s->idx_to_atom_count * @@ -36856,15 +35949,29 @@ static int JS_ReadObjectAtoms(BCReaderState *s) return s->error_state = -1; } for(i = 0; i < s->idx_to_atom_count; i++) { - p = JS_ReadString(s); - if (!p) + if (bc_get_u8(s, &type)) { return -1; - atom = JS_NewAtomStr(s->ctx, p); + } + if (type == 0) { + if (bc_get_u32(s, &atom)) + return -1; + if (!__JS_AtomIsConst(atom)) { + JS_ThrowInternalError(s->ctx, "out of range atom"); + return -1; + } + } else { + if (type < JS_ATOM_TYPE_STRING || type >= JS_ATOM_TYPE_PRIVATE) { + JS_ThrowInternalError(s->ctx, "invalid symbol type %d", type); + return -1; + } + p = JS_ReadString(s); + if (!p) + return -1; + atom = __JS_NewAtom(s->ctx->rt, p, type); + } if (atom == JS_ATOM_NULL) return s->error_state = -1; s->idx_to_atom[i] = atom; - if (s->is_rom_data && (atom != (i + s->first_atom))) - s->is_rom_data = FALSE; /* atoms must be relocated */ } bc_read_trace(s, "}\n"); return 0; @@ -36882,8 +35989,8 @@ static void bc_reader_free(BCReaderState *s) js_free(s->ctx, s->objects); } -JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, - int flags) +JSValue JS_ReadObject2(JSContext *ctx, const uint8_t *buf, size_t buf_len, + int flags, JSSABTab *psab_tab) { BCReaderState ss, *s = &ss; JSValue obj; @@ -36897,7 +36004,6 @@ JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, s->buf_end = buf + buf_len; s->ptr = buf; s->allow_bytecode = ((flags & JS_READ_OBJ_BYTECODE) != 0); - s->is_rom_data = ((flags & JS_READ_OBJ_ROM_DATA) != 0); s->allow_sab = ((flags & JS_READ_OBJ_SAB) != 0); s->allow_reference = ((flags & JS_READ_OBJ_REFERENCE) != 0); if (s->allow_bytecode) @@ -36909,21 +36015,33 @@ JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, } else { obj = JS_ReadObjectRec(s); } + if (psab_tab) { + psab_tab->tab = s->sab_tab; + psab_tab->len = s->sab_tab_len; + } else { + js_free(ctx, s->sab_tab); + } bc_reader_free(s); return obj; } +JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, + int flags) +{ + return JS_ReadObject2(ctx, buf, buf_len, flags, NULL); +} + /*******************************************************************/ /* runtime functions & objects */ -static JSValue js_string_constructor(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv); -static JSValue js_boolean_constructor(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv); -static JSValue js_number_constructor(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv); +static JSValue js_string_constructor(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv); +static JSValue js_boolean_constructor(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv); +static JSValue js_number_constructor(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv); -static int check_function(JSContext *ctx, JSValueConst obj) +static int check_function(JSContext *ctx, JSValue obj) { if (likely(JS_IsFunction(ctx, obj))) return 0; @@ -36937,6 +36055,7 @@ static int check_exception_free(JSContext *ctx, JSValue obj) return JS_IsException(obj); } +/* `export_name` may be pure ASCII or UTF-8 encoded */ static JSAtom find_atom(JSContext *ctx, const char *name) { JSAtom atom; @@ -36984,7 +36103,7 @@ static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p, return val; } -static int JS_InstantiateFunctionListItem(JSContext *ctx, JSValueConst obj, +static int JS_InstantiateFunctionListItem(JSContext *ctx, JSValue obj, JSAtom atom, const JSCFunctionListEntry *e) { @@ -37054,13 +36173,13 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSValueConst obj, } break; case JS_DEF_PROP_INT32: - val = JS_NewInt32(ctx, e->u.i32); + val = js_int32(e->u.i32); break; case JS_DEF_PROP_INT64: - val = JS_NewInt64(ctx, e->u.i64); + val = js_int64(e->u.i64); break; case JS_DEF_PROP_DOUBLE: - val = __JS_NewFloat64(ctx, e->u.f64); + val = js_float64(e->u.f64); break; case JS_DEF_PROP_UNDEFINED: val = JS_UNDEFINED; @@ -37077,7 +36196,7 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSValueConst obj, return 0; } -void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj, +void JS_SetPropertyFunctionList(JSContext *ctx, JSValue obj, const JSCFunctionListEntry *tab, int len) { int i; @@ -37115,16 +36234,17 @@ int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m, e->name, e->u.func.length, e->u.func.cproto, e->magic); break; case JS_DEF_PROP_STRING: + /* `e->u.str` may be pure ASCII or UTF-8 encoded */ val = JS_NewString(ctx, e->u.str); break; case JS_DEF_PROP_INT32: - val = JS_NewInt32(ctx, e->u.i32); + val = js_int32(e->u.i32); break; case JS_DEF_PROP_INT64: - val = JS_NewInt64(ctx, e->u.i64); + val = js_int64(e->u.i64); break; case JS_DEF_PROP_DOUBLE: - val = __JS_NewFloat64(ctx, e->u.f64); + val = js_float64(e->u.f64); break; case JS_DEF_OBJECT: val = JS_NewObject(ctx); @@ -37141,21 +36261,20 @@ int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m, /* Note: 'func_obj' is not necessarily a constructor */ static void JS_SetConstructor2(JSContext *ctx, - JSValueConst func_obj, - JSValueConst proto, + JSValue func_obj, + JSValue proto, int proto_flags, int ctor_flags) { JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype, - JS_DupValue(ctx, proto), proto_flags); + js_dup(proto), proto_flags); JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor, - JS_DupValue(ctx, func_obj), - ctor_flags); + js_dup(func_obj), ctor_flags); set_cycle_flag(ctx, func_obj); set_cycle_flag(ctx, proto); } -void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj, - JSValueConst proto) +void JS_SetConstructor(JSContext *ctx, JSValue func_obj, + JSValue proto) { JS_SetConstructor2(ctx, func_obj, proto, 0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); @@ -37164,18 +36283,18 @@ void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj, static void JS_NewGlobalCConstructor2(JSContext *ctx, JSValue func_obj, const char *name, - JSValueConst proto) + JSValue proto) { JS_DefinePropertyValueStr(ctx, ctx->global_obj, name, - JS_DupValue(ctx, func_obj), + js_dup(func_obj), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); JS_SetConstructor(ctx, func_obj, proto); JS_FreeValue(ctx, func_obj); } -static JSValueConst JS_NewGlobalCConstructor(JSContext *ctx, const char *name, +static JSValue JS_NewGlobalCConstructor(JSContext *ctx, const char *name, JSCFunction *func, int length, - JSValueConst proto) + JSValue proto) { JSValue func_obj; func_obj = JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_constructor_or_func, 0); @@ -37183,9 +36302,9 @@ static JSValueConst JS_NewGlobalCConstructor(JSContext *ctx, const char *name, return func_obj; } -static JSValueConst JS_NewGlobalCConstructorOnly(JSContext *ctx, const char *name, +static JSValue JS_NewGlobalCConstructorOnly(JSContext *ctx, const char *name, JSCFunction *func, int length, - JSValueConst proto) + JSValue proto) { JSValue func_obj; func_obj = JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_constructor, 0); @@ -37193,35 +36312,52 @@ static JSValueConst JS_NewGlobalCConstructorOnly(JSContext *ctx, const char *nam return func_obj; } -static JSValue js_global_eval(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_global_eval(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { return JS_EvalObject(ctx, ctx->global_obj, argv[0], JS_EVAL_TYPE_INDIRECT, -1); } -static JSValue js_global_isNaN(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_global_isNaN(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { double d; - /* XXX: does this work for bigfloat? */ if (unlikely(JS_ToFloat64(ctx, &d, argv[0]))) return JS_EXCEPTION; - return JS_NewBool(ctx, isnan(d)); + return js_bool(isnan(d)); } -static JSValue js_global_isFinite(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_global_isFinite(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { + bool res; double d; if (unlikely(JS_ToFloat64(ctx, &d, argv[0]))) return JS_EXCEPTION; - return JS_NewBool(ctx, isfinite(d)); + res = isfinite(d); + return js_bool(res); +} + +static JSValue js_microtask_job(JSContext *ctx, + int argc, JSValue *argv) +{ + return JS_Call(ctx, argv[0], ctx->global_obj, 0, NULL); +} + +static JSValue js_global_queueMicrotask(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + if (check_function(ctx, argv[0])) + return JS_EXCEPTION; + if (JS_EnqueueJob(ctx, js_microtask_job, 1, &argv[0])) + return JS_EXCEPTION; + return JS_UNDEFINED; } /* Object class */ -static JSValue JS_ToObject(JSContext *ctx, JSValueConst val) +JSValue JS_ToObject(JSContext *ctx, JSValue val) { int tag = JS_VALUE_GET_NORM_TAG(val); JSValue obj; @@ -37230,21 +36366,13 @@ static JSValue JS_ToObject(JSContext *ctx, JSValueConst val) default: case JS_TAG_NULL: case JS_TAG_UNDEFINED: - return JS_ThrowTypeError(ctx, "cannot convert to object"); + return JS_ThrowTypeError(ctx, "Cannot convert undefined or null to object"); case JS_TAG_OBJECT: case JS_TAG_EXCEPTION: - return JS_DupValue(ctx, val); + return js_dup(val); case JS_TAG_BIG_INT: obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT); goto set_value; -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: - obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_FLOAT); - goto set_value; - case JS_TAG_BIG_DECIMAL: - obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_DECIMAL); - goto set_value; -#endif case JS_TAG_INT: case JS_TAG_FLOAT64: obj = JS_NewObjectClass(ctx, JS_CLASS_NUMBER); @@ -37254,7 +36382,7 @@ static JSValue JS_ToObject(JSContext *ctx, JSValueConst val) { JSString *p1 = JS_VALUE_GET_STRING(val); obj = JS_NewObjectClass(ctx, JS_CLASS_STRING); - JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, JS_NewInt32(ctx, p1->len), 0); + JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, js_int32(p1->len), 0); } goto set_value; case JS_TAG_BOOL: @@ -37264,7 +36392,7 @@ static JSValue JS_ToObject(JSContext *ctx, JSValueConst val) obj = JS_NewObjectClass(ctx, JS_CLASS_SYMBOL); set_value: if (!JS_IsException(obj)) - JS_SetObjectData(ctx, obj, JS_DupValue(ctx, val)); + JS_SetObjectData(ctx, obj, js_dup(val)); return obj; } } @@ -37277,20 +36405,35 @@ static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val) } static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d, - JSValueConst desc) + JSValue desc) { JSValue val, getter, setter; + int present; int flags; if (!JS_IsObject(desc)) { - JS_ThrowTypeErrorNotAnObject(ctx); + JS_ThrowTypeError(ctx, "Property description must be an object"); return -1; } flags = 0; val = JS_UNDEFINED; getter = JS_UNDEFINED; setter = JS_UNDEFINED; - if (JS_HasProperty(ctx, desc, JS_ATOM_configurable)) { + present = JS_HasProperty(ctx, desc, JS_ATOM_enumerable); + if (present < 0) + goto fail; + if (present) { + JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_enumerable); + if (JS_IsException(prop)) + goto fail; + flags |= JS_PROP_HAS_ENUMERABLE; + if (JS_ToBoolFree(ctx, prop)) + flags |= JS_PROP_ENUMERABLE; + } + present = JS_HasProperty(ctx, desc, JS_ATOM_configurable); + if (present < 0) + goto fail; + if (present) { JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_configurable); if (JS_IsException(prop)) goto fail; @@ -37298,7 +36441,19 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d, if (JS_ToBoolFree(ctx, prop)) flags |= JS_PROP_CONFIGURABLE; } - if (JS_HasProperty(ctx, desc, JS_ATOM_writable)) { + present = JS_HasProperty(ctx, desc, JS_ATOM_value); + if (present < 0) + goto fail; + if (present) { + flags |= JS_PROP_HAS_VALUE; + val = JS_GetProperty(ctx, desc, JS_ATOM_value); + if (JS_IsException(val)) + goto fail; + } + present = JS_HasProperty(ctx, desc, JS_ATOM_writable); + if (present < 0) + goto fail; + if (present) { JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_writable); if (JS_IsException(prop)) goto fail; @@ -37306,41 +36461,33 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d, if (JS_ToBoolFree(ctx, prop)) flags |= JS_PROP_WRITABLE; } - if (JS_HasProperty(ctx, desc, JS_ATOM_enumerable)) { - JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_enumerable); - if (JS_IsException(prop)) - goto fail; - flags |= JS_PROP_HAS_ENUMERABLE; - if (JS_ToBoolFree(ctx, prop)) - flags |= JS_PROP_ENUMERABLE; - } - if (JS_HasProperty(ctx, desc, JS_ATOM_value)) { - flags |= JS_PROP_HAS_VALUE; - val = JS_GetProperty(ctx, desc, JS_ATOM_value); - if (JS_IsException(val)) - goto fail; - } - if (JS_HasProperty(ctx, desc, JS_ATOM_get)) { + present = JS_HasProperty(ctx, desc, JS_ATOM_get); + if (present < 0) + goto fail; + if (present) { flags |= JS_PROP_HAS_GET; getter = JS_GetProperty(ctx, desc, JS_ATOM_get); if (JS_IsException(getter) || !(JS_IsUndefined(getter) || JS_IsFunction(ctx, getter))) { - JS_ThrowTypeError(ctx, "invalid getter"); + JS_ThrowTypeError(ctx, "Getter must be a function"); goto fail; } } - if (JS_HasProperty(ctx, desc, JS_ATOM_set)) { + present = JS_HasProperty(ctx, desc, JS_ATOM_set); + if (present < 0) + goto fail; + if (present) { flags |= JS_PROP_HAS_SET; setter = JS_GetProperty(ctx, desc, JS_ATOM_set); if (JS_IsException(setter) || !(JS_IsUndefined(setter) || JS_IsFunction(ctx, setter))) { - JS_ThrowTypeError(ctx, "invalid setter"); + JS_ThrowTypeError(ctx, "Setter must be a function"); goto fail; } } if ((flags & (JS_PROP_HAS_SET | JS_PROP_HAS_GET)) && (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE))) { - JS_ThrowTypeError(ctx, "cannot have setter/getter and value or writable"); + JS_ThrowTypeError(ctx, "Invalid property descriptor. Cannot both specify accessors and a value or writable attribute"); goto fail; } d->flags = flags; @@ -37355,8 +36502,8 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d, return -1; } -static __exception int JS_DefinePropertyDesc(JSContext *ctx, JSValueConst obj, - JSAtom prop, JSValueConst desc, +static __exception int JS_DefinePropertyDesc(JSContext *ctx, JSValue obj, + JSAtom prop, JSValue desc, int flags) { JSPropertyDescriptor d; @@ -37372,8 +36519,8 @@ static __exception int JS_DefinePropertyDesc(JSContext *ctx, JSValueConst obj, } static __exception int JS_ObjectDefineProperties(JSContext *ctx, - JSValueConst obj, - JSValueConst properties) + JSValue obj, + JSValue properties) { JSValue props, desc; JSObject *p; @@ -37382,7 +36529,7 @@ static __exception int JS_ObjectDefineProperties(JSContext *ctx, int ret = -1; if (!JS_IsObject(obj)) { - JS_ThrowTypeErrorNotAnObject(ctx); + JS_ThrowTypeError(ctx, "Object.defineProperties called on non-object"); return -1; } desc = JS_UNDEFINED; @@ -37392,12 +36539,16 @@ static __exception int JS_ObjectDefineProperties(JSContext *ctx, p = JS_VALUE_GET_OBJ(props); if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK) < 0) goto exception; + // XXX: ECMA specifies that all descriptions should be validated before + // modifying the object. This would require allocating an array + // JSPropertyDescriptor and use 2 separate loops. for(i = 0; i < len; i++) { JS_FreeValue(ctx, desc); desc = JS_GetProperty(ctx, props, atoms[i].atom); if (JS_IsException(desc)) goto exception; - if (JS_DefinePropertyDesc(ctx, obj, atoms[i].atom, desc, JS_PROP_THROW) < 0) + if (JS_DefinePropertyDesc(ctx, obj, atoms[i].atom, desc, + JS_PROP_THROW | JS_PROP_DEFINE_PROPERTY) < 0) goto exception; } ret = 0; @@ -37409,8 +36560,8 @@ static __exception int JS_ObjectDefineProperties(JSContext *ctx, return ret; } -static JSValue js_object_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) +static JSValue js_object_constructor(JSContext *ctx, JSValue new_target, + int argc, JSValue *argv) { JSValue ret; if (!JS_IsUndefined(new_target) && @@ -37432,15 +36583,15 @@ static JSValue js_object_constructor(JSContext *ctx, JSValueConst new_target, return ret; } -static JSValue js_object_create(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_object_create(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - JSValueConst proto, props; + JSValue proto, props; JSValue obj; proto = argv[0]; if (!JS_IsObject(proto) && !JS_IsNull(proto)) - return JS_ThrowTypeError(ctx, "not a prototype"); + return JS_ThrowTypeError(ctx, "object prototype may only be an Object or null"); obj = JS_NewObjectProto(ctx, proto); if (JS_IsException(obj)) return JS_EXCEPTION; @@ -37454,10 +36605,10 @@ static JSValue js_object_create(JSContext *ctx, JSValueConst this_val, return obj; } -static JSValue js_object_getPrototypeOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) +static JSValue js_object_getPrototypeOf(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { - JSValueConst val; + JSValue val; val = argv[0]; if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) { @@ -37470,21 +36621,21 @@ static JSValue js_object_getPrototypeOf(JSContext *ctx, JSValueConst this_val, return JS_GetPrototype(ctx, val); } -static JSValue js_object_setPrototypeOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_object_setPrototypeOf(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - JSValueConst obj; + JSValue obj; obj = argv[0]; - if (JS_SetPrototypeInternal(ctx, obj, argv[1], TRUE) < 0) + if (JS_SetPrototypeInternal(ctx, obj, argv[1], true) < 0) return JS_EXCEPTION; - return JS_DupValue(ctx, obj); + return js_dup(obj); } /* magic = 1 if called as Reflect.defineProperty */ -static JSValue js_object_defineProperty(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) +static JSValue js_object_defineProperty(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { - JSValueConst obj, prop, desc; + JSValue obj, prop, desc; int ret, flags; JSAtom atom; @@ -37497,38 +36648,38 @@ static JSValue js_object_defineProperty(JSContext *ctx, JSValueConst this_val, atom = JS_ValueToAtom(ctx, prop); if (unlikely(atom == JS_ATOM_NULL)) return JS_EXCEPTION; - flags = 0; - if (!magic) - flags |= JS_PROP_THROW; + flags = JS_PROP_THROW | JS_PROP_DEFINE_PROPERTY; + if (magic) + flags = JS_PROP_REFLECT_DEFINE_PROPERTY; ret = JS_DefinePropertyDesc(ctx, obj, atom, desc, flags); JS_FreeAtom(ctx, atom); if (ret < 0) { return JS_EXCEPTION; } else if (magic) { - return JS_NewBool(ctx, ret); + return js_bool(ret); } else { - return JS_DupValue(ctx, obj); + return js_dup(obj); } } -static JSValue js_object_defineProperties(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_object_defineProperties(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { // defineProperties(obj, properties) - JSValueConst obj = argv[0]; + JSValue obj = argv[0]; if (JS_ObjectDefineProperties(ctx, obj, argv[1])) return JS_EXCEPTION; else - return JS_DupValue(ctx, obj); + return js_dup(obj); } /* magic = 1 if called as __defineSetter__ */ -static JSValue js_object___defineGetter__(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) +static JSValue js_object___defineGetter__(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { JSValue obj; - JSValueConst prop, value, get, set; + JSValue prop, value, get, set; int ret, flags; JSAtom atom; @@ -37570,10 +36721,10 @@ static JSValue js_object___defineGetter__(JSContext *ctx, JSValueConst this_val, } } -static JSValue js_object_getOwnPropertyDescriptor(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) +static JSValue js_object_getOwnPropertyDescriptor(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { - JSValueConst prop; + JSValue prop; JSAtom atom; JSValue ret, obj; JSPropertyDescriptor desc; @@ -37583,7 +36734,7 @@ static JSValue js_object_getOwnPropertyDescriptor(JSContext *ctx, JSValueConst t /* Reflect.getOwnPropertyDescriptor case */ if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT) return JS_ThrowTypeErrorNotAnObject(ctx); - obj = JS_DupValue(ctx, argv[0]); + obj = js_dup(argv[0]); } else { obj = JS_ToObject(ctx, argv[0]); if (JS_IsException(obj)) @@ -37604,19 +36755,22 @@ static JSValue js_object_getOwnPropertyDescriptor(JSContext *ctx, JSValueConst t goto exception1; flags = JS_PROP_C_W_E | JS_PROP_THROW; if (desc.flags & JS_PROP_GETSET) { - if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, JS_DupValue(ctx, desc.getter), flags) < 0 - || JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, JS_DupValue(ctx, desc.setter), flags) < 0) + if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, js_dup(desc.getter), flags) < 0 + || JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, js_dup(desc.setter), flags) < 0) goto exception1; } else { - if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, desc.value), flags) < 0 + if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, js_dup(desc.value), flags) < 0 || JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable, - JS_NewBool(ctx, desc.flags & JS_PROP_WRITABLE), flags) < 0) + js_bool(desc.flags & JS_PROP_WRITABLE), + flags) < 0) goto exception1; } if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable, - JS_NewBool(ctx, desc.flags & JS_PROP_ENUMERABLE), flags) < 0 + js_bool(desc.flags & JS_PROP_ENUMERABLE), + flags) < 0 || JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable, - JS_NewBool(ctx, desc.flags & JS_PROP_CONFIGURABLE), flags) < 0) + js_bool(desc.flags & JS_PROP_CONFIGURABLE), + flags) < 0) goto exception1; js_free_desc(ctx, &desc); } @@ -37634,8 +36788,8 @@ static JSValue js_object_getOwnPropertyDescriptor(JSContext *ctx, JSValueConst t return JS_EXCEPTION; } -static JSValue js_object_getOwnPropertyDescriptors(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_object_getOwnPropertyDescriptors(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { //getOwnPropertyDescriptors(obj) JSValue obj, r; @@ -37657,7 +36811,7 @@ static JSValue js_object_getOwnPropertyDescriptors(JSContext *ctx, JSValueConst goto exception; for(i = 0; i < len; i++) { JSValue atomValue, desc; - JSValueConst args[2]; + JSValue args[2]; atomValue = JS_AtomToValue(ctx, props[i].atom); if (JS_IsException(atomValue)) @@ -37685,7 +36839,7 @@ static JSValue js_object_getOwnPropertyDescriptors(JSContext *ctx, JSValueConst return JS_EXCEPTION; } -static JSValue JS_GetOwnPropertyNames2(JSContext *ctx, JSValueConst obj1, +static JSValue JS_GetOwnPropertyNames2(JSContext *ctx, JSValue obj1, int flags, int kind) { JSValue obj, r, val, key, value; @@ -37764,31 +36918,121 @@ static JSValue JS_GetOwnPropertyNames2(JSContext *ctx, JSValueConst obj1, return r; } -static JSValue js_object_getOwnPropertyNames(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_object_getOwnPropertyNames(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { return JS_GetOwnPropertyNames2(ctx, argv[0], JS_GPN_STRING_MASK, JS_ITERATOR_KIND_KEY); } -static JSValue js_object_getOwnPropertySymbols(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_object_getOwnPropertySymbols(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { return JS_GetOwnPropertyNames2(ctx, argv[0], JS_GPN_SYMBOL_MASK, JS_ITERATOR_KIND_KEY); } -static JSValue js_object_keys(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int kind) +static JSValue js_object_groupBy(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + JSValue cb, res, iter, next, groups, k, v, prop; + JSValue args[2]; + int64_t idx; + int done; + + // "is function?" check must be observed before argv[0] is accessed + cb = argv[1]; + if (check_function(ctx, cb)) + return JS_EXCEPTION; + + // TODO(bnoordhuis) add fast path for arrays but as groupBy() is + // defined in terms of iterators, the fast path must check that + // this[Symbol.iterator] is the built-in array iterator + iter = JS_GetIterator(ctx, argv[0], /*is_async*/false); + if (JS_IsException(iter)) + return JS_EXCEPTION; + + k = JS_UNDEFINED; + v = JS_UNDEFINED; + prop = JS_UNDEFINED; + groups = JS_UNDEFINED; + + next = JS_GetProperty(ctx, iter, JS_ATOM_next); + if (JS_IsException(next)) + goto exception; + + groups = JS_NewObjectProto(ctx, JS_NULL); + if (JS_IsException(groups)) + goto exception; + + for (idx = 0; ; idx++) { + v = JS_IteratorNext(ctx, iter, next, 0, NULL, &done); + if (JS_IsException(v)) + goto exception; + if (done) + break; // v is JS_UNDEFINED + + args[0] = v; + args[1] = js_int64(idx); + k = JS_Call(ctx, cb, ctx->global_obj, 2, args); + if (JS_IsException(k)) + goto exception; + + k = js_dup(k); + prop = JS_GetPropertyValue(ctx, groups, k); + if (JS_IsException(prop)) + goto exception; + + if (JS_IsUndefined(prop)) { + prop = JS_NewArray(ctx); + if (JS_IsException(prop)) + goto exception; + k = js_dup(k); + prop = js_dup(prop); + if (JS_SetPropertyValue(ctx, groups, k, prop, + JS_PROP_C_W_E|JS_PROP_THROW) < 0) { + goto exception; + } + } + + res = js_array_push(ctx, prop, 1, &v, /*unshift*/0); + if (JS_IsException(res)) + goto exception; + // res is an int64 + + JS_FreeValue(ctx, prop); + JS_FreeValue(ctx, k); + JS_FreeValue(ctx, v); + prop = JS_UNDEFINED; + k = JS_UNDEFINED; + v = JS_UNDEFINED; + } + + JS_FreeValue(ctx, iter); + JS_FreeValue(ctx, next); + return groups; + +exception: + JS_FreeValue(ctx, prop); + JS_FreeValue(ctx, k); + JS_FreeValue(ctx, v); + JS_FreeValue(ctx, groups); + JS_FreeValue(ctx, iter); + JS_FreeValue(ctx, next); + return JS_EXCEPTION; +} + +static JSValue js_object_keys(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int kind) { return JS_GetOwnPropertyNames2(ctx, argv[0], JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK, kind); } -static JSValue js_object_isExtensible(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int reflect) +static JSValue js_object_isExtensible(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int reflect) { - JSValueConst obj; + JSValue obj; int ret; obj = argv[0]; @@ -37802,13 +37046,13 @@ static JSValue js_object_isExtensible(JSContext *ctx, JSValueConst this_val, if (ret < 0) return JS_EXCEPTION; else - return JS_NewBool(ctx, ret); + return js_bool(ret); } -static JSValue js_object_preventExtensions(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int reflect) +static JSValue js_object_preventExtensions(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int reflect) { - JSValueConst obj; + JSValue obj; int ret; obj = argv[0]; @@ -37816,27 +37060,27 @@ static JSValue js_object_preventExtensions(JSContext *ctx, JSValueConst this_val if (reflect) return JS_ThrowTypeErrorNotAnObject(ctx); else - return JS_DupValue(ctx, obj); + return js_dup(obj); } ret = JS_PreventExtensions(ctx, obj); if (ret < 0) return JS_EXCEPTION; if (reflect) { - return JS_NewBool(ctx, ret); + return js_bool(ret); } else { if (!ret) return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false"); - return JS_DupValue(ctx, obj); + return js_dup(obj); } } -static JSValue js_object_hasOwnProperty(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_object_hasOwnProperty(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue obj; JSAtom atom; JSObject *p; - BOOL ret; + int ret; atom = JS_ValueToAtom(ctx, argv[0]); /* must be done first */ if (unlikely(atom == JS_ATOM_NULL)) @@ -37853,16 +37097,16 @@ static JSValue js_object_hasOwnProperty(JSContext *ctx, JSValueConst this_val, if (ret < 0) return JS_EXCEPTION; else - return JS_NewBool(ctx, ret); + return js_bool(ret); } -static JSValue js_object_hasOwn(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_object_hasOwn(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue obj; JSAtom atom; JSObject *p; - BOOL ret; + int ret; obj = JS_ToObject(ctx, argv[0]); if (JS_IsException(obj)) @@ -37879,17 +37123,17 @@ static JSValue js_object_hasOwn(JSContext *ctx, JSValueConst this_val, if (ret < 0) return JS_EXCEPTION; else - return JS_NewBool(ctx, ret); + return js_bool(ret); } -static JSValue js_object_valueOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_object_valueOf(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { return JS_ToObject(ctx, this_val); } -static JSValue js_object_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_object_toString(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue obj, tag; int is_array; @@ -37897,9 +37141,9 @@ static JSValue js_object_toString(JSContext *ctx, JSValueConst this_val, JSObject *p; if (JS_IsNull(this_val)) { - tag = JS_NewString(ctx, "Null"); + tag = js_new_string8(ctx, "Null"); } else if (JS_IsUndefined(this_val)) { - tag = JS_NewString(ctx, "Undefined"); + tag = js_new_string8(ctx, "Undefined"); } else { obj = JS_ToObject(ctx, this_val); if (JS_IsException(obj)) @@ -37943,14 +37187,19 @@ static JSValue js_object_toString(JSContext *ctx, JSValueConst this_val, return JS_ConcatString3(ctx, "[object ", tag, "]"); } -static JSValue js_object_toLocaleString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +JSValue JS_ToObjectString(JSContext *ctx, JSValue val) +{ + return js_object_toString(ctx, val, 0, NULL); +} + +static JSValue js_object_toLocaleString(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { return JS_Invoke(ctx, this_val, JS_ATOM_toString, 0, NULL); } -static JSValue js_object_assign(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_object_assign(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { // Object.assign(obj, source1) JSValue obj, s; @@ -37965,7 +37214,7 @@ static JSValue js_object_assign(JSContext *ctx, JSValueConst this_val, s = JS_ToObject(ctx, argv[i]); if (JS_IsException(s)) goto exception; - if (JS_CopyDataProperties(ctx, obj, s, JS_UNDEFINED, TRUE)) + if (JS_CopyDataProperties(ctx, obj, s, JS_UNDEFINED, true)) goto exception; JS_FreeValue(ctx, s); } @@ -37977,17 +37226,25 @@ static JSValue js_object_assign(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static JSValue js_object_seal(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int freeze_flag) +static JSValue js_object_seal(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int freeze_flag) { - JSValueConst obj = argv[0]; + JSValue obj = argv[0]; JSObject *p; + JSTypedArray *ta; + JSArrayBuffer *abuf; JSPropertyEnum *props; uint32_t len, i; int flags, desc_flags, res; if (!JS_IsObject(obj)) - return JS_DupValue(ctx, obj); + return js_dup(obj); + + p = JS_VALUE_GET_OBJ(obj); + if (p->class_id == JS_CLASS_MODULE_NS) { + return JS_ThrowTypeError(ctx, "cannot %s module namespace", + freeze_flag ? "freeze" : "seal"); + } res = JS_PreventExtensions(ctx, obj); if (res < 0) @@ -37996,7 +37253,13 @@ static JSValue js_object_seal(JSContext *ctx, JSValueConst this_val, return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false"); } - p = JS_VALUE_GET_OBJ(obj); + if (freeze_flag && is_typed_array(p->class_id)) { + ta = p->u.typed_array; + abuf = ta->buffer->u.array_buffer; + if (array_buffer_is_resizable(abuf) || typed_array_is_oob(p)) + return JS_ThrowTypeError(ctx, "cannot freeze resizable typed array"); + } + flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK; if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags)) return JS_EXCEPTION; @@ -38021,17 +37284,17 @@ static JSValue js_object_seal(JSContext *ctx, JSValueConst this_val, goto exception; } js_free_prop_enum(ctx, props, len); - return JS_DupValue(ctx, obj); + return js_dup(obj); exception: js_free_prop_enum(ctx, props, len); return JS_EXCEPTION; } -static JSValue js_object_isSealed(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int is_frozen) +static JSValue js_object_isSealed(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int is_frozen) { - JSValueConst obj = argv[0]; + JSValue obj = argv[0]; JSObject *p; JSPropertyEnum *props; uint32_t len, i; @@ -38056,7 +37319,7 @@ static JSValue js_object_isSealed(JSContext *ctx, JSValueConst this_val, js_free_desc(ctx, &desc); if ((desc.flags & JS_PROP_CONFIGURABLE) || (is_frozen && (desc.flags & JS_PROP_WRITABLE))) { - res = FALSE; + res = false; goto done; } } @@ -38067,26 +37330,35 @@ static JSValue js_object_isSealed(JSContext *ctx, JSValueConst this_val, res ^= 1; done: js_free_prop_enum(ctx, props, len); - return JS_NewBool(ctx, res); + return js_bool(res); exception: js_free_prop_enum(ctx, props, len); return JS_EXCEPTION; } -JSValue JS_ObjectSeal(JSContext *ctx, JSValueConst obj, int freeze) +int JS_SealObject(JSContext *ctx, JSValue obj) { - JSValueConst argv[] = {obj}; - JS_FreeValue(ctx, js_object_seal(ctx, JS_UNDEFINED, 1, argv, freeze)); - return obj; + JSValue value = js_object_seal(ctx, JS_UNDEFINED, 1, &obj, 0); + int result = JS_IsException(value) ? -1 : true; + JS_FreeValue(ctx, value); + return result; +} + +int JS_FreezeObject(JSContext *ctx, JSValue obj) +{ + JSValue value = js_object_seal(ctx, JS_UNDEFINED, 1, &obj, 1); + int result = JS_IsException(value) ? -1 : true; + JS_FreeValue(ctx, value); + return result; } -static JSValue js_object_fromEntries(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_object_fromEntries(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue obj, iter, next_method = JS_UNDEFINED; - JSValueConst iterable; - BOOL done; + JSValue iterable; + int done; /* RequireObjectCoercible() not necessary because it is tested in JS_GetIterator() by JS_GetProperty() */ @@ -38096,7 +37368,7 @@ static JSValue js_object_fromEntries(JSContext *ctx, JSValueConst this_val, if (JS_IsException(obj)) return obj; - iter = JS_GetIterator(ctx, iterable, FALSE); + iter = JS_GetIterator(ctx, iterable, false); if (JS_IsException(iter)) goto fail; next_method = JS_GetProperty(ctx, iter, JS_ATOM_next); @@ -38141,7 +37413,7 @@ static JSValue js_object_fromEntries(JSContext *ctx, JSValueConst this_val, fail: if (JS_IsObject(iter)) { /* close the iterator object, preserving pending exception */ - JS_IteratorClose(ctx, iter, TRUE); + JS_IteratorClose(ctx, iter, true); } JS_FreeValue(ctx, next_method); JS_FreeValue(ctx, iter); @@ -38149,109 +37421,14 @@ static JSValue js_object_fromEntries(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -#if 0 -/* Note: corresponds to ECMA spec: CreateDataPropertyOrThrow() */ -static JSValue js_object___setOwnProperty(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_object_is(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - int ret; - ret = JS_DefinePropertyValueValue(ctx, argv[0], JS_DupValue(ctx, argv[1]), - JS_DupValue(ctx, argv[2]), - JS_PROP_C_W_E | JS_PROP_THROW); - if (ret < 0) - return JS_EXCEPTION; - else - return JS_NewBool(ctx, ret); -} - -static JSValue js_object___toObject(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_ToObject(ctx, argv[0]); -} - -static JSValue js_object___toPrimitive(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int hint = HINT_NONE; - - if (JS_VALUE_GET_TAG(argv[1]) == JS_TAG_INT) - hint = JS_VALUE_GET_INT(argv[1]); - - return JS_ToPrimitive(ctx, argv[0], hint); -} -#endif - -/* return an empty string if not an object */ -static JSValue js_object___getClass(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSAtom atom; - JSObject *p; - uint32_t tag; - int class_id; - - tag = JS_VALUE_GET_NORM_TAG(argv[0]); - if (tag == JS_TAG_OBJECT) { - p = JS_VALUE_GET_OBJ(argv[0]); - class_id = p->class_id; - if (class_id == JS_CLASS_PROXY && JS_IsFunction(ctx, argv[0])) - class_id = JS_CLASS_BYTECODE_FUNCTION; - atom = ctx->rt->class_array[class_id].class_name; - } else { - atom = JS_ATOM_empty_string; - } - return JS_AtomToString(ctx, atom); -} - -static JSValue js_object_is(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_NewBool(ctx, js_same_value(ctx, argv[0], argv[1])); -} - -#if 0 -static JSValue js_object___getObjectData(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_GetObjectData(ctx, argv[0]); -} - -static JSValue js_object___setObjectData(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - if (JS_SetObjectData(ctx, argv[0], JS_DupValue(ctx, argv[1]))) - return JS_EXCEPTION; - return JS_DupValue(ctx, argv[1]); -} - -static JSValue js_object___toPropertyKey(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_ToPropertyKey(ctx, argv[0]); -} - -static JSValue js_object___isObject(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_NewBool(ctx, JS_IsObject(argv[0])); -} - -static JSValue js_object___isSameValueZero(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_NewBool(ctx, js_same_value_zero(ctx, argv[0], argv[1])); + return js_bool(js_same_value(ctx, argv[0], argv[1])); } -static JSValue js_object___isConstructor(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_NewBool(ctx, JS_IsConstructor(ctx, argv[0])); -} -#endif - -static JSValue JS_SpeciesConstructor(JSContext *ctx, JSValueConst obj, - JSValueConst defaultConstructor) +static JSValue JS_SpeciesConstructor(JSContext *ctx, JSValue obj, + JSValue defaultConstructor) { JSValue ctor, species; @@ -38261,7 +37438,7 @@ static JSValue JS_SpeciesConstructor(JSContext *ctx, JSValueConst obj, if (JS_IsException(ctor)) return ctor; if (JS_IsUndefined(ctor)) - return JS_DupValue(ctx, defaultConstructor); + return js_dup(defaultConstructor); if (!JS_IsObject(ctor)) { JS_FreeValue(ctx, ctor); return JS_ThrowTypeErrorNotAnObject(ctx); @@ -38271,7 +37448,7 @@ static JSValue JS_SpeciesConstructor(JSContext *ctx, JSValueConst obj, if (JS_IsException(species)) return species; if (JS_IsUndefined(species) || JS_IsNull(species)) - return JS_DupValue(ctx, defaultConstructor); + return js_dup(defaultConstructor); if (!JS_IsConstructor(ctx, species)) { JS_FreeValue(ctx, species); return JS_ThrowTypeError(ctx, "not a constructor"); @@ -38279,15 +37456,7 @@ static JSValue JS_SpeciesConstructor(JSContext *ctx, JSValueConst obj, return species; } -#if 0 -static JSValue js_object___speciesConstructor(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_SpeciesConstructor(ctx, argv[0], argv[1]); -} -#endif - -static JSValue js_object_get___proto__(JSContext *ctx, JSValueConst this_val) +static JSValue js_object_get___proto__(JSContext *ctx, JSValue this_val) { JSValue val, ret; @@ -38299,24 +37468,24 @@ static JSValue js_object_get___proto__(JSContext *ctx, JSValueConst this_val) return ret; } -static JSValue js_object_set___proto__(JSContext *ctx, JSValueConst this_val, - JSValueConst proto) +static JSValue js_object_set___proto__(JSContext *ctx, JSValue this_val, + JSValue proto) { if (JS_IsUndefined(this_val) || JS_IsNull(this_val)) return JS_ThrowTypeErrorNotAnObject(ctx); if (!JS_IsObject(proto) && !JS_IsNull(proto)) return JS_UNDEFINED; - if (JS_SetPrototypeInternal(ctx, this_val, proto, TRUE) < 0) + if (JS_SetPrototypeInternal(ctx, this_val, proto, true) < 0) return JS_EXCEPTION; else return JS_UNDEFINED; } -static JSValue js_object_isPrototypeOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_object_isPrototypeOf(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue obj, v1; - JSValueConst v; + JSValue v; int res; v = argv[0]; @@ -38325,17 +37494,17 @@ static JSValue js_object_isPrototypeOf(JSContext *ctx, JSValueConst this_val, obj = JS_ToObject(ctx, this_val); if (JS_IsException(obj)) return JS_EXCEPTION; - v1 = JS_DupValue(ctx, v); + v1 = js_dup(v); for(;;) { v1 = JS_GetPrototypeFree(ctx, v1); if (JS_IsException(v1)) goto exception; if (JS_IsNull(v1)) { - res = FALSE; + res = false; break; } if (JS_VALUE_GET_OBJ(obj) == JS_VALUE_GET_OBJ(v1)) { - res = TRUE; + res = true; break; } /* avoid infinite loop (possible with proxies) */ @@ -38344,7 +37513,7 @@ static JSValue js_object_isPrototypeOf(JSContext *ctx, JSValueConst this_val, } JS_FreeValue(ctx, v1); JS_FreeValue(ctx, obj); - return JS_NewBool(ctx, res); + return js_bool(res); exception: JS_FreeValue(ctx, v1); @@ -38352,8 +37521,8 @@ static JSValue js_object_isPrototypeOf(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static JSValue js_object_propertyIsEnumerable(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_object_propertyIsEnumerable(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue obj, res = JS_EXCEPTION; JSAtom prop = JS_ATOM_NULL; @@ -38371,7 +37540,7 @@ static JSValue js_object_propertyIsEnumerable(JSContext *ctx, JSValueConst this_ if (has_prop < 0) goto exception; if (has_prop) { - res = JS_NewBool(ctx, desc.flags & JS_PROP_ENUMERABLE); + res = js_bool(desc.flags & JS_PROP_ENUMERABLE); js_free_desc(ctx, &desc); } else { res = JS_FALSE; @@ -38383,8 +37552,8 @@ static JSValue js_object_propertyIsEnumerable(JSContext *ctx, JSValueConst this_ return res; } -static JSValue js_object___lookupGetter__(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int setter) +static JSValue js_object___lookupGetter__(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int setter) { JSValue obj, res = JS_EXCEPTION; JSAtom prop = JS_ATOM_NULL; @@ -38404,7 +37573,7 @@ static JSValue js_object___lookupGetter__(JSContext *ctx, JSValueConst this_val, goto exception; if (has_prop) { if (desc.flags & JS_PROP_GETSET) - res = JS_DupValue(ctx, setter ? desc.setter : desc.getter); + res = js_dup(setter ? desc.setter : desc.getter); else res = JS_UNDEFINED; js_free_desc(ctx, &desc); @@ -38436,7 +37605,7 @@ static const JSCFunctionListEntry js_object_funcs[] = { JS_CFUNC_DEF("defineProperties", 2, js_object_defineProperties ), JS_CFUNC_DEF("getOwnPropertyNames", 1, js_object_getOwnPropertyNames ), JS_CFUNC_DEF("getOwnPropertySymbols", 1, js_object_getOwnPropertySymbols ), - JS_CFUNC_MAGIC_DEF("groupBy", 2, js_object_groupBy, 0 ), + JS_CFUNC_DEF("groupBy", 2, js_object_groupBy ), JS_CFUNC_MAGIC_DEF("keys", 1, js_object_keys, JS_ITERATOR_KIND_KEY ), JS_CFUNC_MAGIC_DEF("values", 1, js_object_keys, JS_ITERATOR_KIND_VALUE ), JS_CFUNC_MAGIC_DEF("entries", 1, js_object_keys, JS_ITERATOR_KIND_KEY_AND_VALUE ), @@ -38450,17 +37619,6 @@ static const JSCFunctionListEntry js_object_funcs[] = { JS_CFUNC_MAGIC_DEF("freeze", 1, js_object_seal, 1 ), JS_CFUNC_MAGIC_DEF("isSealed", 1, js_object_isSealed, 0 ), JS_CFUNC_MAGIC_DEF("isFrozen", 1, js_object_isSealed, 1 ), - JS_CFUNC_DEF("__getClass", 1, js_object___getClass ), - //JS_CFUNC_DEF("__isObject", 1, js_object___isObject ), - //JS_CFUNC_DEF("__isConstructor", 1, js_object___isConstructor ), - //JS_CFUNC_DEF("__toObject", 1, js_object___toObject ), - //JS_CFUNC_DEF("__setOwnProperty", 3, js_object___setOwnProperty ), - //JS_CFUNC_DEF("__toPrimitive", 2, js_object___toPrimitive ), - //JS_CFUNC_DEF("__toPropertyKey", 1, js_object___toPropertyKey ), - //JS_CFUNC_DEF("__speciesConstructor", 2, js_object___speciesConstructor ), - //JS_CFUNC_DEF("__isSameValueZero", 2, js_object___isSameValueZero ), - //JS_CFUNC_DEF("__getObjectData", 1, js_object___getObjectData ), - //JS_CFUNC_DEF("__setObjectData", 2, js_object___setObjectData ), JS_CFUNC_DEF("fromEntries", 1, js_object_fromEntries ), JS_CFUNC_DEF("hasOwn", 2, js_object_hasOwn ), }; @@ -38481,15 +37639,15 @@ static const JSCFunctionListEntry js_object_proto_funcs[] = { /* Function class */ -static JSValue js_function_proto(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_function_proto(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { return JS_UNDEFINED; } /* XXX: add a specific eval mode so that Function("}), ({") is rejected */ -static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv, int magic) +static JSValue js_function_constructor(JSContext *ctx, JSValue new_target, + int argc, JSValue *argv, int magic) { JSFunctionKindEnum func_kind = magic; int i, n, ret; @@ -38542,9 +37700,9 @@ static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target, realm = JS_GetFunctionRealm(ctx, new_target); if (!realm) goto fail1; - proto = JS_DupValue(ctx, realm->class_proto[func_kind_to_class_id[func_kind]]); + proto = js_dup(realm->class_proto[func_kind_to_class_id[func_kind]]); } - ret = JS_SetPrototypeInternal(ctx, obj, proto, TRUE); + ret = JS_SetPrototypeInternal(ctx, obj, proto, true); JS_FreeValue(ctx, proto); if (ret < 0) goto fail1; @@ -38559,7 +37717,7 @@ static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target, } static __exception int js_get_length32(JSContext *ctx, uint32_t *pres, - JSValueConst obj) + JSValue obj) { JSValue len_val; len_val = JS_GetProperty(ctx, obj, JS_ATOM_length); @@ -38571,7 +37729,7 @@ static __exception int js_get_length32(JSContext *ctx, uint32_t *pres, } static __exception int js_get_length64(JSContext *ctx, int64_t *pres, - JSValueConst obj) + JSValue obj) { JSValue len_val; len_val = JS_GetProperty(ctx, obj, JS_ATOM_length); @@ -38582,6 +37740,11 @@ static __exception int js_get_length64(JSContext *ctx, int64_t *pres, return JS_ToLengthFree(ctx, pres, len_val); } +static __exception int js_set_length64(JSContext *ctx, JSValue obj, int64_t len) +{ + return JS_SetProperty(ctx, obj, JS_ATOM_length, js_int64(len)); +} + static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len) { uint32_t i; @@ -38593,7 +37756,7 @@ static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len) /* XXX: should use ValueArray */ static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen, - JSValueConst array_arg) + JSValue array_arg) { uint32_t len, i; JSValue *tab, ret; @@ -38620,7 +37783,7 @@ static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen, p->fast_array && len == p->u.array.count) { for(i = 0; i < len; i++) { - tab[i] = JS_DupValue(ctx, p->u.array.u.values[i]); + tab[i] = js_dup(p->u.array.u.values[i]); } } else { for(i = 0; i < len; i++) { @@ -38638,10 +37801,10 @@ static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen, /* 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) +static JSValue js_function_apply(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { - JSValueConst this_arg, array_arg; + JSValue this_arg, array_arg; uint32_t len; JSValue *tab, ret; @@ -38657,16 +37820,16 @@ static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val, if (!tab) return JS_EXCEPTION; if (magic & 1) { - ret = JS_CallConstructor2(ctx, this_val, this_arg, len, (JSValueConst *)tab); + ret = JS_CallConstructor2(ctx, this_val, this_arg, len, tab); } else { - ret = JS_Call(ctx, this_val, this_arg, len, (JSValueConst *)tab); + ret = JS_Call(ctx, this_val, this_arg, len, tab); } free_arg_list(ctx, tab, len); return ret; } -static JSValue js_function_call(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_function_call(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { if (argc <= 0) { return JS_Call(ctx, this_val, JS_UNDEFINED, 0, NULL); @@ -38675,8 +37838,8 @@ static JSValue js_function_call(JSContext *ctx, JSValueConst this_val, } } -static JSValue js_function_bind(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_function_bind(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSBoundFunction *bf; JSValue func_obj, name1, len_val; @@ -38696,11 +37859,11 @@ static JSValue js_function_bind(JSContext *ctx, JSValueConst this_val, bf = js_malloc(ctx, sizeof(*bf) + arg_count * sizeof(JSValue)); if (!bf) goto exception; - bf->func_obj = JS_DupValue(ctx, this_val); - bf->this_val = JS_DupValue(ctx, argv[0]); + bf->func_obj = js_dup(this_val); + bf->this_val = js_dup(argv[0]); bf->argc = arg_count; for(i = 0; i < arg_count; i++) { - bf->argv[i] = JS_DupValue(ctx, argv[i + 1]); + bf->argv[i] = js_dup(argv[i + 1]); } p->u.bound_function = bf; @@ -38709,7 +37872,7 @@ static JSValue js_function_bind(JSContext *ctx, JSValueConst this_val, if (ret < 0) goto exception; if (!ret) { - len_val = JS_NewInt32(ctx, 0); + len_val = js_int32(0); } else { len_val = JS_GetProperty(ctx, this_val, JS_ATOM_length); if (JS_IsException(len_val)) @@ -38721,7 +37884,7 @@ static JSValue js_function_bind(JSContext *ctx, JSValueConst this_val, len1 = 0; else len1 -= arg_count; - len_val = JS_NewInt32(ctx, len1); + len_val = js_int32(len1); } else if (JS_VALUE_GET_NORM_TAG(len_val) == JS_TAG_FLOAT64) { double d = JS_VALUE_GET_FLOAT64(len_val); if (isnan(d)) { @@ -38733,10 +37896,10 @@ static JSValue js_function_bind(JSContext *ctx, JSValueConst this_val, else d -= (double)arg_count; /* also converts -0 to +0 */ } - len_val = JS_NewFloat64(ctx, d); + len_val = js_number(d); } else { JS_FreeValue(ctx, len_val); - len_val = JS_NewInt32(ctx, 0); + len_val = js_int32(0); } } JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length, @@ -38760,8 +37923,8 @@ static JSValue js_function_bind(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static JSValue js_function_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_function_toString(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSObject *p; JSFunctionKindEnum func_kind = JS_FUNC_NORMAL; @@ -38772,10 +37935,9 @@ static JSValue js_function_toString(JSContext *ctx, JSValueConst this_val, p = JS_VALUE_GET_OBJ(this_val); if (js_class_has_bytecode(p->class_id)) { JSFunctionBytecode *b = p->u.func.function_bytecode; - if (b->has_debug && b->debug.source) { - return JS_NewStringLen(ctx, b->debug.source, b->debug.source_len); - } - func_kind = b->func_kind; + /* `b->source` must be pure ASCII or UTF-8 encoded */ + if (b->source) + return JS_NewStringLen(ctx, b->source, b->source_len); } { JSValue name; @@ -38804,15 +37966,15 @@ static JSValue js_function_toString(JSContext *ctx, JSValueConst this_val, } } -static JSValue js_function_hasInstance(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_function_hasInstance(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { int ret; ret = JS_OrdinaryIsInstanceOf(ctx, argv[0], this_val); if (ret < 0) return JS_EXCEPTION; else - return JS_NewBool(ctx, ret); + return js_bool(ret); } static const JSCFunctionListEntry js_function_proto_funcs[] = { @@ -38822,19 +37984,22 @@ static const JSCFunctionListEntry js_function_proto_funcs[] = { JS_CFUNC_DEF("toString", 0, js_function_toString ), JS_CFUNC_DEF("[Symbol.hasInstance]", 1, js_function_hasInstance ), JS_CGETSET_DEF("fileName", js_function_proto_fileName, NULL ), - JS_CGETSET_DEF("lineNumber", js_function_proto_lineNumber, NULL ), + JS_CGETSET_MAGIC_DEF("lineNumber", js_function_proto_int32, NULL, + offsetof(JSFunctionBytecode, line_num)), + JS_CGETSET_MAGIC_DEF("columnNumber", js_function_proto_int32, NULL, + offsetof(JSFunctionBytecode, col_num)), }; /* Error class */ -static JSValue iterator_to_array(JSContext *ctx, JSValueConst items) +static JSValue iterator_to_array(JSContext *ctx, JSValue items) { JSValue iter, next_method = JS_UNDEFINED; JSValue v, r = JS_UNDEFINED; int64_t k; - BOOL done; + int done; - iter = JS_GetIterator(ctx, items, FALSE); + iter = JS_GetIterator(ctx, items, false); if (JS_IsException(iter)) goto exception; next_method = JS_GetProperty(ctx, iter, JS_ATOM_next); @@ -38858,19 +38023,19 @@ static JSValue iterator_to_array(JSContext *ctx, JSValueConst items) JS_FreeValue(ctx, iter); return r; exception_close: - JS_IteratorClose(ctx, iter, TRUE); + JS_IteratorClose(ctx, iter, true); exception: JS_FreeValue(ctx, r); r = JS_EXCEPTION; goto done; } -static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv, int magic) +static JSValue js_error_constructor(JSContext *ctx, JSValue new_target, + int argc, JSValue *argv, int magic) { - JSValue obj, msg, proto; - JSValueConst message, options; - int arg_index; + JSValue obj, msg, proto, cause; + JSValue message; + int present, opts; if (JS_IsUndefined(new_target)) new_target = JS_GetActiveFunction(ctx); @@ -38879,7 +38044,7 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target, return proto; if (!JS_IsObject(proto)) { JSContext *realm; - JSValueConst proto1; + JSValue proto1; JS_FreeValue(ctx, proto); realm = JS_GetFunctionRealm(ctx, new_target); @@ -38890,15 +38055,20 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target, } else { proto1 = realm->native_error_proto[magic]; } - proto = JS_DupValue(ctx, proto1); + proto = js_dup(proto1); } obj = JS_NewObjectProtoClass(ctx, proto, JS_CLASS_ERROR); JS_FreeValue(ctx, proto); if (JS_IsException(obj)) return obj; - arg_index = (magic == JS_AGGREGATE_ERROR); + if (magic == JS_AGGREGATE_ERROR) { + message = argv[1]; + opts = 2; + } else { + message = argv[0]; + opts = 1; + } - message = argv[arg_index++]; if (!JS_IsUndefined(message)) { msg = JS_ToString(ctx, message); if (unlikely(JS_IsException(msg))) @@ -38907,19 +38077,16 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); } - if (arg_index < argc) { - options = argv[arg_index]; - if (JS_IsObject(options)) { - int present = JS_HasProperty(ctx, options, JS_ATOM_cause); - if (present < 0) + if (argc > opts && JS_VALUE_GET_TAG(argv[opts]) == JS_TAG_OBJECT) { + present = JS_HasProperty(ctx, argv[opts], JS_ATOM_cause); + if (unlikely(present < 0)) + goto exception; + if (present) { + cause = JS_GetProperty(ctx, argv[opts], JS_ATOM_cause); + if (unlikely(JS_IsException(cause))) goto exception; - if (present) { - JSValue cause = JS_GetProperty(ctx, options, JS_ATOM_cause); - if (JS_IsException(cause)) - goto exception; - JS_DefinePropertyValue(ctx, obj, JS_ATOM_cause, cause, - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - } + JS_DefinePropertyValue(ctx, obj, JS_ATOM_cause, cause, + JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); } } @@ -38932,15 +38099,15 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target, } /* skip the Error() function in the backtrace */ - build_backtrace(ctx, obj, NULL, 0, JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL); + build_backtrace(ctx, obj, JS_UNDEFINED, NULL, 0, 0, JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL); return obj; exception: JS_FreeValue(ctx, obj); return JS_EXCEPTION; } -static JSValue js_error_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_error_toString(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue name, msg; @@ -38974,11 +38141,76 @@ static const JSCFunctionListEntry js_error_proto_funcs[] = { JS_PROP_STRING_DEF("message", "", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ), }; +static JSValue js_error_isError(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + return js_bool(JS_IsError(ctx, argv[0])); +} + +static JSValue js_error_get_stackTraceLimit(JSContext *ctx, JSValue this_val) +{ + JSValue val; + + val = JS_ToObject(ctx, this_val); + if (JS_IsException(val)) + return val; + JS_FreeValue(ctx, val); + return js_int32(ctx->error_stack_trace_limit); +} + +static JSValue js_error_set_stackTraceLimit(JSContext *ctx, JSValue this_val, JSValue value) +{ + if (JS_IsUndefined(this_val) || JS_IsNull(this_val)) + return JS_ThrowTypeErrorNotAnObject(ctx); + int limit; + if (JS_ToInt32(ctx, &limit, value) < 0) + return JS_EXCEPTION; + ctx->error_stack_trace_limit = limit; + return JS_UNDEFINED; +} + +static JSValue js_error_get_prepareStackTrace(JSContext *ctx, JSValue this_val) +{ + JSValue val; + + val = JS_ToObject(ctx, this_val); + if (JS_IsException(val)) + return val; + JS_FreeValue(ctx, val); + return js_dup(ctx->error_prepare_stack); +} + +static JSValue js_error_set_prepareStackTrace(JSContext *ctx, JSValue this_val, JSValue value) +{ + if (JS_IsUndefined(this_val) || JS_IsNull(this_val)) + return JS_ThrowTypeErrorNotAnObject(ctx); + JS_FreeValue(ctx, ctx->error_prepare_stack); + ctx->error_prepare_stack = js_dup(value); + return JS_UNDEFINED; +} + +static JSValue js_error_capture_stack_trace(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + JSValue v = argv[0]; + if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT) + return JS_ThrowTypeErrorNotAnObject(ctx); + build_backtrace(ctx, v, argv[1], NULL, 0, 0, JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL|JS_BACKTRACE_FLAG_FILTER_FUNC); + return JS_UNDEFINED; +} + +static const JSCFunctionListEntry js_error_funcs[] = { + JS_CFUNC_DEF("isError", 1, js_error_isError ), + JS_CFUNC_DEF("captureStackTrace", 2, js_error_capture_stack_trace), + JS_CGETSET_DEF("stackTraceLimit", js_error_get_stackTraceLimit, js_error_set_stackTraceLimit ), + JS_CGETSET_DEF("prepareStackTrace", js_error_get_prepareStackTrace, js_error_set_prepareStackTrace ), +}; + /* AggregateError */ /* used by C code. */ static JSValue js_aggregate_error_constructor(JSContext *ctx, - JSValueConst errors) + JSValue errors) { JSValue obj; @@ -38987,7 +38219,7 @@ static JSValue js_aggregate_error_constructor(JSContext *ctx, JS_CLASS_ERROR); if (JS_IsException(obj)) return obj; - JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, JS_DupValue(ctx, errors), + JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, js_dup(errors), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); return obj; } @@ -38995,7 +38227,7 @@ static JSValue js_aggregate_error_constructor(JSContext *ctx, /* Array */ static int JS_CopySubArray(JSContext *ctx, - JSValueConst obj, int64_t to_pos, + JSValue obj, int64_t to_pos, int64_t from_pos, int64_t count, int dir) { JSObject *p; @@ -39032,14 +38264,14 @@ static int JS_CopySubArray(JSContext *ctx, l = min_int64(l, to + 1); for(j = 0; j < l; j++) { set_value(ctx, &p->u.array.u.values[to - j], - JS_DupValue(ctx, p->u.array.u.values[from - j])); + js_dup(p->u.array.u.values[from - j])); } } else { l = min_int64(l, len - from); l = min_int64(l, len - to); for(j = 0; j < l; j++) { set_value(ctx, &p->u.array.u.values[to + j], - JS_DupValue(ctx, p->u.array.u.values[from + j])); + js_dup(p->u.array.u.values[from + j])); } } i += l; @@ -39064,8 +38296,8 @@ static int JS_CopySubArray(JSContext *ctx, return -1; } -static JSValue js_array_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) +static JSValue js_array_constructor(JSContext *ctx, JSValue new_target, + int argc, JSValue *argv) { JSValue obj; int i; @@ -39075,13 +38307,13 @@ 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]), TRUE)) + if (JS_ToArrayLengthFree(ctx, &len, js_dup(argv[0]), true)) goto fail; - if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, len)) < 0) + if (JS_SetProperty(ctx, obj, JS_ATOM_length, js_uint32(len)) < 0) goto fail; } else { for(i = 0; i < argc; i++) { - if (JS_SetPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i])) < 0) + if (JS_SetPropertyUint32(ctx, obj, i, js_dup(argv[i])) < 0) goto fail; } } @@ -39091,18 +38323,18 @@ static JSValue js_array_constructor(JSContext *ctx, JSValueConst new_target, return JS_EXCEPTION; } -static JSValue js_array_from(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_array_from(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { // from(items, mapfn = void 0, this_arg = void 0) - JSValueConst items = argv[0], mapfn, this_arg; - JSValueConst args[2]; + JSValue items = argv[0], mapfn, this_arg; + JSValue args[2]; JSValue stack[2]; JSValue iter, r, v, v2, arrayLike; int64_t k, len; int done, mapping; - mapping = FALSE; + mapping = false; mapfn = JS_UNDEFINED; this_arg = JS_UNDEFINED; r = JS_UNDEFINED; @@ -39131,8 +38363,8 @@ static JSValue js_array_from(JSContext *ctx, JSValueConst this_val, r = JS_NewArray(ctx); if (JS_IsException(r)) goto exception; - stack[0] = JS_DupValue(ctx, items); - if (js_for_of_start(ctx, &stack[1], FALSE)) + stack[0] = js_dup(items); + if (js_for_of_start(ctx, &stack[1], false)) goto exception; for (k = 0;; k++) { v = JS_IteratorNext(ctx, stack[0], stack[1], 0, NULL, &done); @@ -39142,7 +38374,7 @@ static JSValue js_array_from(JSContext *ctx, JSValueConst this_val, break; if (mapping) { args[0] = v; - args[1] = JS_NewInt32(ctx, k); + args[1] = js_int32(k); v2 = JS_Call(ctx, mapfn, this_arg, 2, args); JS_FreeValue(ctx, v); v = v2; @@ -39159,7 +38391,7 @@ static JSValue js_array_from(JSContext *ctx, JSValueConst this_val, goto exception; if (js_get_length64(ctx, &len, arrayLike) < 0) goto exception; - v = JS_NewInt64(ctx, len); + v = js_int64(len); args[0] = v; if (JS_IsConstructor(ctx, this_val)) { r = JS_CallConstructor(ctx, this_val, 1, args); @@ -39175,7 +38407,7 @@ static JSValue js_array_from(JSContext *ctx, JSValueConst this_val, goto exception; if (mapping) { args[0] = v; - args[1] = JS_NewInt32(ctx, k); + args[1] = js_int32(k); v2 = JS_Call(ctx, mapfn, this_arg, 2, args); JS_FreeValue(ctx, v); v = v2; @@ -39187,13 +38419,13 @@ static JSValue js_array_from(JSContext *ctx, JSValueConst this_val, goto exception; } } - if (JS_SetProperty(ctx, r, JS_ATOM_length, JS_NewUint32(ctx, k)) < 0) + if (JS_SetProperty(ctx, r, JS_ATOM_length, js_uint32(k)) < 0) goto exception; goto done; exception_close: if (!JS_IsUndefined(stack[0])) - JS_IteratorClose(ctx, stack[0], TRUE); + JS_IteratorClose(ctx, stack[0], true); exception: JS_FreeValue(ctx, r); r = JS_EXCEPTION; @@ -39204,27 +38436,27 @@ static JSValue js_array_from(JSContext *ctx, JSValueConst this_val, return r; } -static JSValue js_array_of(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_array_of(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue obj, args[1]; int i; if (JS_IsConstructor(ctx, this_val)) { - args[0] = JS_NewInt32(ctx, argc); - obj = JS_CallConstructor(ctx, this_val, 1, (JSValueConst *)args); + args[0] = js_int32(argc); + obj = JS_CallConstructor(ctx, this_val, 1, args); } else { obj = JS_NewArray(ctx); } if (JS_IsException(obj)) return JS_EXCEPTION; for(i = 0; i < argc; i++) { - if (JS_CreateDataPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i]), + if (JS_CreateDataPropertyUint32(ctx, obj, i, js_dup(argv[i]), JS_PROP_THROW) < 0) { goto fail; } } - if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, argc)) < 0) { + if (JS_SetProperty(ctx, obj, JS_ATOM_length, js_uint32(argc)) < 0) { fail: JS_FreeValue(ctx, obj); return JS_EXCEPTION; @@ -39232,25 +38464,25 @@ static JSValue js_array_of(JSContext *ctx, JSValueConst this_val, return obj; } -static JSValue js_array_isArray(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_array_isArray(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { int ret; ret = JS_IsArray(ctx, argv[0]); if (ret < 0) return JS_EXCEPTION; else - return JS_NewBool(ctx, ret); + return js_bool(ret); } static JSValue js_get_this(JSContext *ctx, - JSValueConst this_val) + JSValue this_val) { - return JS_DupValue(ctx, this_val); + return js_dup(this_val); } -static JSValue JS_ArraySpeciesCreate(JSContext *ctx, JSValueConst obj, - JSValueConst len_val) +static JSValue JS_ArraySpeciesCreate(JSContext *ctx, JSValue obj, + JSValue len_val) { JSValue ctor, ret, species; int res; @@ -39302,12 +38534,12 @@ static const JSCFunctionListEntry js_array_funcs[] = { JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ), }; -static int JS_isConcatSpreadable(JSContext *ctx, JSValueConst obj) +static int JS_isConcatSpreadable(JSContext *ctx, JSValue obj) { JSValue val; if (!JS_IsObject(obj)) - return FALSE; + return false; val = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_isConcatSpreadable); if (JS_IsException(val)) return -1; @@ -39316,14 +38548,13 @@ static int JS_isConcatSpreadable(JSContext *ctx, JSValueConst obj) return JS_IsArray(ctx, obj); } -static JSValue js_array_at(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_array_at(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue obj, ret; int64_t len, idx; - JSValue *arrp; - uint32_t count; + ret = JS_EXCEPTION; obj = JS_ToObject(ctx, this_val); if (js_get_length64(ctx, &len, obj)) goto exception; @@ -39333,26 +38564,20 @@ static JSValue js_array_at(JSContext *ctx, JSValueConst this_val, if (idx < 0) idx = len + idx; + if (idx < 0 || idx >= len) { ret = JS_UNDEFINED; - } else if (js_get_fast_array(ctx, obj, &arrp, &count) && idx < count) { - ret = JS_DupValue(ctx, arrp[idx]); } else { - int present = JS_TryGetPropertyInt64(ctx, obj, idx, &ret); - if (present < 0) - goto exception; - if (!present) - ret = JS_UNDEFINED; + ret = JS_GetPropertyInt64(ctx, obj, idx); } - JS_FreeValue(ctx, obj); - return ret; + exception: JS_FreeValue(ctx, obj); - return JS_EXCEPTION; + return ret; } -static JSValue js_array_with(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_array_with(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue arr, obj, ret, *arrp, *pval; JSObject *p; @@ -39365,6 +38590,11 @@ static JSValue js_array_with(JSContext *ctx, JSValueConst this_val, if (js_get_length64(ctx, &len, obj)) goto exception; + if (len > UINT32_MAX) { + JS_ThrowRangeError(ctx, "invalid array length"); + goto exception; + } + if (JS_ToInt64Sat(ctx, &idx, argv[0])) goto exception; @@ -39376,24 +38606,28 @@ static JSValue js_array_with(JSContext *ctx, JSValueConst this_val, goto exception; } - arr = js_allocate_fast_array(ctx, len); + arr = JS_NewArray(ctx); if (JS_IsException(arr)) goto exception; p = JS_VALUE_GET_OBJ(arr); + if (expand_fast_array(ctx, p, len) < 0) + goto exception; + p->u.array.count = len; + i = 0; pval = p->u.array.u.values; if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) { for (; i < idx; i++, pval++) - *pval = JS_DupValue(ctx, arrp[i]); - *pval = JS_DupValue(ctx, argv[1]); + *pval = js_dup(arrp[i]); + *pval = js_dup(argv[1]); for (i++, pval++; i < len; i++, pval++) - *pval = JS_DupValue(ctx, arrp[i]); + *pval = js_dup(arrp[i]); } else { for (; i < idx; i++, pval++) if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) goto fill_and_fail; - *pval = JS_DupValue(ctx, argv[1]); + *pval = js_dup(argv[1]); for (i++, pval++; i < len; i++, pval++) { if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) { fill_and_fail: @@ -39404,7 +38638,7 @@ static JSValue js_array_with(JSContext *ctx, JSValueConst this_val, } } - if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0) + if (JS_SetProperty(ctx, arr, JS_ATOM_length, js_int64(len)) < 0) goto exception; ret = arr; @@ -39416,11 +38650,11 @@ static JSValue js_array_with(JSContext *ctx, JSValueConst this_val, return ret; } -static JSValue js_array_concat(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_array_concat(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue obj, arr, val; - JSValueConst e; + JSValue e; int64_t len, k, n; int i, res; @@ -39429,7 +38663,7 @@ static JSValue js_array_concat(JSContext *ctx, JSValueConst this_val, if (JS_IsException(obj)) goto exception; - arr = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0)); + arr = JS_ArraySpeciesCreate(ctx, obj, js_int32(0)); if (JS_IsException(arr)) goto exception; n = 0; @@ -39464,13 +38698,13 @@ static JSValue js_array_concat(JSContext *ctx, JSValueConst this_val, JS_ThrowTypeError(ctx, "Array loo long"); goto exception; } - if (JS_DefinePropertyValueInt64(ctx, arr, n, JS_DupValue(ctx, e), + if (JS_DefinePropertyValueInt64(ctx, arr, n, js_dup(e), JS_PROP_C_W_E | JS_PROP_THROW) < 0) goto exception; n++; } } - if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0) + if (JS_SetProperty(ctx, arr, JS_ATOM_length, js_int64(n)) < 0) goto exception; JS_FreeValue(ctx, obj); @@ -39489,26 +38723,59 @@ static JSValue js_array_concat(JSContext *ctx, JSValueConst this_val, #define special_filter 4 #define special_TA 8 -static int js_typed_array_get_length_internal(JSContext *ctx, JSValueConst obj); +static JSObject *get_typed_array(JSContext *ctx, JSValue this_val) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT) + goto fail; + p = JS_VALUE_GET_OBJ(this_val); + if (!is_typed_array(p->class_id)) { + fail: + JS_ThrowTypeError(ctx, "not a TypedArray"); + return NULL; + } + return p; +} + +// Be *very* careful if you touch the typed array's memory directly: +// the length is only valid until the next call into JS land because +// JS code can detach or resize the backing array buffer. Functions +// like JS_GetProperty and JS_ToIndex call JS code. +// +// Exclusively reading or writing elements with JS_GetProperty, +// JS_GetPropertyInt64, JS_SetProperty, etc. is safe because they +// perform bounds checks, as does js_get_fast_array_element. +static int js_typed_array_get_length_unsafe(JSContext *ctx, JSValue obj) +{ + JSObject *p; + p = get_typed_array(ctx, obj); + if (!p) + return -1; + if (typed_array_is_oob(p)) { + JS_ThrowTypeErrorArrayBufferOOB(ctx); + return -1; + } + return p->u.array.count; +} static JSValue js_typed_array___speciesCreate(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv); + JSValue this_val, + int argc, JSValue *argv); -static JSValue js_array_every(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int special) +static JSValue js_array_every(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int special) { JSValue obj, val, index_val, res, ret; - JSValueConst args[3]; - JSValueConst func, this_arg; + JSValue args[3]; + JSValue func, this_arg; int64_t len, k, n; int present; ret = JS_UNDEFINED; val = JS_UNDEFINED; if (special & special_TA) { - obj = JS_DupValue(ctx, this_val); - len = js_typed_array_get_length_internal(ctx, obj); + obj = js_dup(this_val); + len = js_typed_array_get_length_unsafe(ctx, obj); if (len < 0) goto exception; } else { @@ -39535,18 +38802,18 @@ static JSValue js_array_every(JSContext *ctx, JSValueConst this_val, break; case special_map: /* XXX: JS_ArraySpeciesCreate should take int64_t */ - ret = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt64(ctx, len)); + ret = JS_ArraySpeciesCreate(ctx, obj, js_int64(len)); if (JS_IsException(ret)) goto exception; break; case special_filter: - ret = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0)); + ret = JS_ArraySpeciesCreate(ctx, obj, js_int32(0)); if (JS_IsException(ret)) goto exception; break; case special_map | special_TA: args[0] = obj; - args[1] = JS_NewInt32(ctx, len); + args[1] = js_int32(len); ret = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args); if (JS_IsException(ret)) goto exception; @@ -39564,16 +38831,14 @@ static JSValue js_array_every(JSContext *ctx, JSValueConst this_val, val = JS_GetPropertyInt64(ctx, obj, k); if (JS_IsException(val)) goto exception; - present = TRUE; + present = true; } else { present = JS_TryGetPropertyInt64(ctx, obj, k, &val); if (present < 0) goto exception; } if (present) { - index_val = JS_NewInt64(ctx, k); - if (JS_IsException(index_val)) - goto exception; + index_val = js_int64(k); args[0] = val; args[1] = index_val; args[2] = obj; @@ -39602,13 +38867,13 @@ static JSValue js_array_every(JSContext *ctx, JSValueConst this_val, goto exception; break; case special_map | special_TA: - if (JS_SetPropertyValue(ctx, ret, JS_NewInt32(ctx, k), res, JS_PROP_THROW) < 0) + if (JS_SetPropertyValue(ctx, ret, js_int32(k), res, JS_PROP_THROW) < 0) goto exception; break; case special_filter: case special_filter | special_TA: if (JS_ToBoolFree(ctx, res)) { - if (JS_DefinePropertyValueInt64(ctx, ret, n++, JS_DupValue(ctx, val), + if (JS_DefinePropertyValueInt64(ctx, ret, n++, js_dup(val), JS_PROP_C_W_E | JS_PROP_THROW) < 0) goto exception; } @@ -39625,7 +38890,7 @@ static JSValue js_array_every(JSContext *ctx, JSValueConst this_val, if (special == (special_filter | special_TA)) { JSValue arr; args[0] = obj; - args[1] = JS_NewInt32(ctx, n); + args[1] = js_int32(n); arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args); if (JS_IsException(arr)) goto exception; @@ -39650,20 +38915,20 @@ static JSValue js_array_every(JSContext *ctx, JSValueConst this_val, #define special_reduce 0 #define special_reduceRight 1 -static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int special) +static JSValue js_array_reduce(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int special) { JSValue obj, val, index_val, acc, acc1; - JSValueConst args[4]; - JSValueConst func; + JSValue args[4]; + JSValue func; int64_t len, k, k1; int present; acc = JS_UNDEFINED; val = JS_UNDEFINED; if (special & special_TA) { - obj = JS_DupValue(ctx, this_val); - len = js_typed_array_get_length_internal(ctx, obj); + obj = js_dup(this_val); + len = js_typed_array_get_length_unsafe(ctx, obj); if (len < 0) goto exception; } else { @@ -39678,7 +38943,7 @@ static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val, k = 0; if (argc > 1) { - acc = JS_DupValue(ctx, argv[1]); + acc = js_dup(argv[1]); } else { for(;;) { if (k >= len) { @@ -39707,16 +38972,14 @@ static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val, val = JS_GetPropertyInt64(ctx, obj, k1); if (JS_IsException(val)) goto exception; - present = TRUE; + present = true; } else { present = JS_TryGetPropertyInt64(ctx, obj, k1, &val); if (present < 0) goto exception; } if (present) { - index_val = JS_NewInt64(ctx, k1); - if (JS_IsException(index_val)) - goto exception; + index_val = js_int64(k1); args[0] = acc; args[1] = val; args[2] = index_val; @@ -39741,8 +39004,8 @@ static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static JSValue js_array_fill(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_array_fill(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue obj; int64_t len, start, end; @@ -39765,8 +39028,7 @@ static JSValue js_array_fill(JSContext *ctx, JSValueConst this_val, /* XXX: should special case fast arrays */ while (start < end) { - if (JS_SetPropertyInt64(ctx, obj, start, - JS_DupValue(ctx, argv[0])) < 0) + if (JS_SetPropertyInt64(ctx, obj, start, js_dup(argv[0])) < 0) goto exception; start++; } @@ -39777,8 +39039,8 @@ static JSValue js_array_fill(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static JSValue js_array_includes(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_array_includes(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue obj, val; int64_t len, n; @@ -39790,7 +39052,7 @@ static JSValue js_array_includes(JSContext *ctx, JSValueConst this_val, if (js_get_length64(ctx, &len, obj)) goto exception; - res = FALSE; + res = true; if (len > 0) { n = 0; if (argc > 1) { @@ -39799,10 +39061,8 @@ static JSValue js_array_includes(JSContext *ctx, JSValueConst this_val, } if (js_get_fast_array(ctx, obj, &arrp, &count)) { for (; n < count; n++) { - if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), - JS_DupValue(ctx, arrp[n]), + if (js_strict_eq2(ctx, js_dup(argv[0]), js_dup(arrp[n]), JS_EQ_SAME_VALUE_ZERO)) { - res = TRUE; goto done; } } @@ -39811,27 +39071,27 @@ static JSValue js_array_includes(JSContext *ctx, JSValueConst this_val, val = JS_GetPropertyInt64(ctx, obj, n); if (JS_IsException(val)) goto exception; - if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, + if (js_strict_eq2(ctx, js_dup(argv[0]), val, JS_EQ_SAME_VALUE_ZERO)) { - res = TRUE; - break; + goto done; } } } + res = false; done: JS_FreeValue(ctx, obj); - return JS_NewBool(ctx, res); + return js_bool(res); exception: JS_FreeValue(ctx, obj); return JS_EXCEPTION; } -static JSValue js_array_indexOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_array_indexOf(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue obj, val; - int64_t len, n, res; + int64_t len, n; JSValue *arrp; uint32_t count; @@ -39839,7 +39099,6 @@ static JSValue js_array_indexOf(JSContext *ctx, JSValueConst this_val, if (js_get_length64(ctx, &len, obj)) goto exception; - res = -1; if (len > 0) { n = 0; if (argc > 1) { @@ -39848,9 +39107,8 @@ static JSValue js_array_indexOf(JSContext *ctx, JSValueConst this_val, } if (js_get_fast_array(ctx, obj, &arrp, &count)) { for (; n < count; n++) { - if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), - JS_DupValue(ctx, arrp[n]), JS_EQ_STRICT)) { - res = n; + if (js_strict_eq2(ctx, js_dup(argv[0]), js_dup(arrp[n]), + JS_EQ_STRICT)) { goto done; } } @@ -39860,55 +39118,63 @@ static JSValue js_array_indexOf(JSContext *ctx, JSValueConst this_val, if (present < 0) goto exception; if (present) { - if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, JS_EQ_STRICT)) { - res = n; - break; + if (js_strict_eq2(ctx, js_dup(argv[0]), val, JS_EQ_STRICT)) { + goto done; } } } } + n = -1; done: JS_FreeValue(ctx, obj); - return JS_NewInt64(ctx, res); + return js_int64(n); exception: JS_FreeValue(ctx, obj); return JS_EXCEPTION; } -static JSValue js_array_lastIndexOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_array_lastIndexOf(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue obj, val; - int64_t len, n, res; - int present; + int64_t len, n; + JSValue *arrp; + uint32_t count; obj = JS_ToObject(ctx, this_val); if (js_get_length64(ctx, &len, obj)) goto exception; - res = -1; if (len > 0) { n = len - 1; if (argc > 1) { if (JS_ToInt64Clamp(ctx, &n, argv[1], -1, len - 1, len)) goto exception; } - /* XXX: should special case fast arrays */ + if (js_get_fast_array(ctx, obj, &arrp, &count) && count == len) { + for (; n >= 0; n--) { + if (js_strict_eq2(ctx, js_dup(argv[0]), js_dup(arrp[n]), + JS_EQ_STRICT)) { + goto done; + } + } + } for (; n >= 0; n--) { - present = JS_TryGetPropertyInt64(ctx, obj, n, &val); + int present = JS_TryGetPropertyInt64(ctx, obj, n, &val); if (present < 0) goto exception; if (present) { - if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, JS_EQ_STRICT)) { - res = n; - break; + if (js_strict_eq2(ctx, js_dup(argv[0]), val, JS_EQ_STRICT)) { + goto done; } } } } + n = -1; + done: JS_FreeValue(ctx, obj); - return JS_NewInt64(ctx, res); + return js_int64(n); exception: JS_FreeValue(ctx, obj); @@ -39922,11 +39188,11 @@ enum { ArrayFindLastIndex, }; -static JSValue js_array_find(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int mode) +static JSValue js_array_find(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int mode) { - JSValueConst func, this_arg; - JSValueConst args[3]; + JSValue func, this_arg; + JSValue args[3]; JSValue obj, val, index_val, res; int64_t len, k, end; int dir; @@ -39956,9 +39222,7 @@ static JSValue js_array_find(JSContext *ctx, JSValueConst this_val, // TODO(bnoordhuis) add fast path for fast arrays for(; k != end; k += dir) { - index_val = JS_NewInt64(ctx, k); - if (JS_IsException(index_val)) - goto exception; + index_val = js_int64(k); val = JS_GetPropertyValue(ctx, obj, index_val); if (JS_IsException(val)) goto exception; @@ -39984,7 +39248,7 @@ static JSValue js_array_find(JSContext *ctx, JSValueConst this_val, } JS_FreeValue(ctx, obj); if (mode == ArrayFindIndex || mode == ArrayFindLastIndex) - return JS_NewInt32(ctx, -1); + return js_int32(-1); else return JS_UNDEFINED; @@ -39995,8 +39259,8 @@ static JSValue js_array_find(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static JSValue js_array_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_array_toString(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue obj, method, ret; @@ -40018,8 +39282,8 @@ static JSValue js_array_toString(JSContext *ctx, JSValueConst this_val, return ret; } -static JSValue js_array_join(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int toLocaleString) +static JSValue js_array_join(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int toLocaleString) { JSValue obj, sep = JS_UNDEFINED, el; StringBuffer b_s, *b = &b_s; @@ -40075,8 +39339,8 @@ static JSValue js_array_join(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static JSValue js_array_pop(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int shift) +static JSValue js_array_pop(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int shift) { JSValue obj, res = JS_UNDEFINED; int64_t len, newLen; @@ -40116,7 +39380,7 @@ static JSValue js_array_pop(JSContext *ctx, JSValueConst this_val, goto exception; } } - if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0) + if (JS_SetProperty(ctx, obj, JS_ATOM_length, js_int64(newLen)) < 0) goto exception; JS_FreeValue(ctx, obj); @@ -40128,8 +39392,8 @@ static JSValue js_array_pop(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static JSValue js_array_push(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int unshift) +static JSValue js_array_push(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int unshift) { JSValue obj; int i; @@ -40150,23 +39414,22 @@ static JSValue js_array_push(JSContext *ctx, JSValueConst this_val, from = 0; } for(i = 0; i < argc; i++) { - if (JS_SetPropertyInt64(ctx, obj, from + i, - JS_DupValue(ctx, argv[i])) < 0) + if (JS_SetPropertyInt64(ctx, obj, from + i, js_dup(argv[i])) < 0) goto exception; } - if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0) + if (JS_SetProperty(ctx, obj, JS_ATOM_length, js_int64(newLen)) < 0) goto exception; JS_FreeValue(ctx, obj); - return JS_NewInt64(ctx, newLen); + return js_int64(newLen); exception: JS_FreeValue(ctx, obj); return JS_EXCEPTION; } -static JSValue js_array_reverse(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_array_reverse(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue obj, lval, hval; JSValue *arrp; @@ -40238,8 +39501,8 @@ static JSValue js_array_reverse(JSContext *ctx, JSValueConst this_val, // leaves holes in sparse arrays intact whereas a.toReversed() replaces them // with undefined, thus in effect creating a dense array. // Does not use Array[@@species], always returns a base Array. -static JSValue js_array_toReversed(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_array_toReversed(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue arr, obj, ret, *arrp, *pval; JSObject *p; @@ -40252,18 +39515,26 @@ static JSValue js_array_toReversed(JSContext *ctx, JSValueConst this_val, if (js_get_length64(ctx, &len, obj)) goto exception; - arr = js_allocate_fast_array(ctx, len); + if (len > UINT32_MAX) { + JS_ThrowRangeError(ctx, "invalid array length"); + goto exception; + } + + arr = JS_NewArray(ctx); if (JS_IsException(arr)) goto exception; if (len > 0) { p = JS_VALUE_GET_OBJ(arr); + if (expand_fast_array(ctx, p, len) < 0) + goto exception; + p->u.array.count = len; i = len - 1; pval = p->u.array.u.values; if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) { for (; i >= 0; i--, pval++) - *pval = JS_DupValue(ctx, arrp[i]); + *pval = js_dup(arrp[i]); } else { // Query order is observable; test262 expects descending order. for (; i >= 0; i--, pval++) { @@ -40276,7 +39547,7 @@ static JSValue js_array_toReversed(JSContext *ctx, JSValueConst this_val, } } - if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0) + if (JS_SetProperty(ctx, arr, JS_ATOM_length, js_int64(len)) < 0) goto exception; } @@ -40289,8 +39560,8 @@ static JSValue js_array_toReversed(JSContext *ctx, JSValueConst this_val, return ret; } -static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int splice) +static JSValue js_array_slice(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int splice) { JSValue obj, arr, val, len_val; int64_t len, start, k, final, n, count, del_count, new_len; @@ -40310,8 +39581,7 @@ static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val, if (argc == 0) { item_count = 0; del_count = 0; - } else - if (argc == 1) { + } else if (argc == 1) { item_count = 0; del_count = len - start; } else { @@ -40333,7 +39603,7 @@ static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val, } count = max_int64(final - start, 0); } - len_val = JS_NewInt64(ctx, count); + len_val = js_int64(count); arr = JS_ArraySpeciesCreate(ctx, obj, len_val); JS_FreeValue(ctx, len_val); if (JS_IsException(arr)) @@ -40350,7 +39620,7 @@ static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val, js_is_fast_array(ctx, arr)) { /* XXX: should share code with fast array constructor */ for (; k < final && k < count32; k++, n++) { - if (JS_CreateDataPropertyUint32(ctx, arr, n, JS_DupValue(ctx, arrp[k]), JS_PROP_THROW) < 0) + if (JS_CreateDataPropertyUint32(ctx, arr, n, js_dup(arrp[k]), JS_PROP_THROW) < 0) goto exception; } } @@ -40364,7 +39634,7 @@ static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val, goto exception; } } - if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0) + if (JS_SetProperty(ctx, arr, JS_ATOM_length, js_int64(n)) < 0) goto exception; if (splice) { @@ -40381,10 +39651,10 @@ static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val, } } for (i = 0; i < item_count; i++) { - if (JS_SetPropertyInt64(ctx, obj, start + i, JS_DupValue(ctx, argv[i + 2])) < 0) + if (JS_SetPropertyInt64(ctx, obj, start + i, js_dup(argv[i + 2])) < 0) goto exception; } - if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, new_len)) < 0) + if (JS_SetProperty(ctx, obj, JS_ATOM_length, js_int64(new_len)) < 0) goto exception; } JS_FreeValue(ctx, obj); @@ -40396,8 +39666,8 @@ static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static JSValue js_array_toSpliced(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_array_toSpliced(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue arr, obj, ret, *arrp, *pval, *last; JSObject *p; @@ -40430,12 +39700,17 @@ static JSValue js_array_toSpliced(JSContext *ctx, JSValueConst this_val, add = argc - 2; newlen = len + add - del; - if (newlen > MAX_SAFE_INTEGER) { - JS_ThrowTypeError(ctx, "invalid array length"); + if (newlen > UINT32_MAX) { + // Per spec: TypeError if newlen >= 2**53, RangeError below + if (newlen > MAX_SAFE_INTEGER) { + JS_ThrowTypeError(ctx, "invalid array length"); + } else { + JS_ThrowRangeError(ctx, "invalid array length"); + } goto exception; } - arr = js_allocate_fast_array(ctx, newlen); + arr = JS_NewArray(ctx); if (JS_IsException(arr)) goto exception; @@ -40443,22 +39718,26 @@ static JSValue js_array_toSpliced(JSContext *ctx, JSValueConst this_val, goto done; p = JS_VALUE_GET_OBJ(arr); + if (expand_fast_array(ctx, p, newlen) < 0) + goto exception; + + p->u.array.count = newlen; pval = &p->u.array.u.values[0]; last = &p->u.array.u.values[newlen]; if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) { for (i = 0; i < start; i++, pval++) - *pval = JS_DupValue(ctx, arrp[i]); + *pval = js_dup(arrp[i]); for (j = 0; j < add; j++, pval++) - *pval = JS_DupValue(ctx, argv[2 + j]); + *pval = js_dup(argv[2 + j]); for (i += del; i < len; i++, pval++) - *pval = JS_DupValue(ctx, arrp[i]); + *pval = js_dup(arrp[i]); } else { for (i = 0; i < start; i++, pval++) if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) goto exception; for (j = 0; j < add; j++, pval++) - *pval = JS_DupValue(ctx, argv[2 + j]); + *pval = js_dup(argv[2 + j]); for (i += del; i < len; i++, pval++) if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) goto exception; @@ -40466,7 +39745,7 @@ static JSValue js_array_toSpliced(JSContext *ctx, JSValueConst this_val, assert(pval == last); - if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, newlen)) < 0) + if (JS_SetProperty(ctx, arr, JS_ATOM_length, js_int64(newlen)) < 0) goto exception; done: @@ -40482,8 +39761,8 @@ static JSValue js_array_toSpliced(JSContext *ctx, JSValueConst this_val, return ret; } -static JSValue js_array_copyWithin(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_array_copyWithin(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue obj; int64_t len, from, to, final, count; @@ -40517,11 +39796,11 @@ static JSValue js_array_copyWithin(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static int64_t JS_FlattenIntoArray(JSContext *ctx, JSValueConst target, - JSValueConst source, int64_t sourceLen, +static int64_t JS_FlattenIntoArray(JSContext *ctx, JSValue target, + JSValue source, int64_t sourceLen, int64_t targetIndex, int depth, - JSValueConst mapperFunction, - JSValueConst thisArg) + JSValue mapperFunction, + JSValue thisArg) { JSValue element; int64_t sourceIndex, elementLen; @@ -40539,7 +39818,7 @@ static int64_t JS_FlattenIntoArray(JSContext *ctx, JSValueConst target, if (!present) continue; if (!JS_IsUndefined(mapperFunction)) { - JSValueConst args[3] = { element, JS_NewInt64(ctx, sourceIndex), source }; + JSValue args[3] = { element, js_int64(sourceIndex), source }; element = JS_Call(ctx, mapperFunction, thisArg, 3, args); JS_FreeValue(ctx, args[0]); JS_FreeValue(ctx, args[1]); @@ -40579,11 +39858,11 @@ static int64_t JS_FlattenIntoArray(JSContext *ctx, JSValueConst target, return -1; } -static JSValue js_array_flatten(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int map) +static JSValue js_array_flatten(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int map) { JSValue obj, arr; - JSValueConst mapperFunction, thisArg; + JSValue mapperFunction, thisArg; int64_t sourceLen; int depthNum; @@ -40608,7 +39887,7 @@ static JSValue js_array_flatten(JSContext *ctx, JSValueConst this_val, goto exception; } } - arr = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0)); + arr = JS_ArraySpeciesCreate(ctx, obj, js_int32(0)); if (JS_IsException(arr)) goto exception; if (JS_FlattenIntoArray(ctx, arr, obj, sourceLen, 0, depthNum, @@ -40635,13 +39914,13 @@ struct array_sort_context { JSContext *ctx; int exception; int has_method; - JSValueConst method; + JSValue method; }; static int js_array_cmp_generic(const void *a, const void *b, void *opaque) { struct array_sort_context *psc = opaque; JSContext *ctx = psc->ctx; - JSValueConst argv[2]; + JSValue argv[2]; JSValue res; ValueSlot *ap = (ValueSlot *)(void *)a; ValueSlot *bp = (ValueSlot *)(void *)b; @@ -40686,7 +39965,7 @@ static int js_array_cmp_generic(const void *a, const void *b, void *opaque) { goto exception; bp->str = JS_VALUE_GET_STRING(str); } - cmp = js_string_compare(ctx, ap->str, bp->str); + cmp = js_string_compare(ap->str, bp->str); } if (cmp != 0) return cmp; @@ -40699,8 +39978,8 @@ static int js_array_cmp_generic(const void *a, const void *b, void *opaque) { return 0; } -static JSValue js_array_sort(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_array_sort(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { struct array_sort_context asc = { ctx, 0, 0, argv[0] }; JSValue obj = JS_UNDEFINED; @@ -40789,8 +40068,8 @@ static JSValue js_array_sort(JSContext *ctx, JSValueConst this_val, // leaves holes in sparse arrays intact whereas a.toSorted() replaces them // with undefined, thus in effect creating a dense array. // Does not use Array[@@species], always returns a base Array. -static JSValue js_array_toSorted(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_array_toSorted(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue arr, obj, ret, *arrp, *pval; JSObject *p; @@ -40808,17 +40087,26 @@ static JSValue js_array_toSorted(JSContext *ctx, JSValueConst this_val, if (js_get_length64(ctx, &len, obj)) goto exception; - arr = js_allocate_fast_array(ctx, len); + if (len > UINT32_MAX) { + JS_ThrowRangeError(ctx, "invalid array length"); + goto exception; + } + + arr = JS_NewArray(ctx); if (JS_IsException(arr)) goto exception; if (len > 0) { p = JS_VALUE_GET_OBJ(arr); + if (expand_fast_array(ctx, p, len) < 0) + goto exception; + p->u.array.count = len; + i = 0; pval = p->u.array.u.values; if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) { for (; i < len; i++, pval++) - *pval = JS_DupValue(ctx, arrp[i]); + *pval = js_dup(arrp[i]); } else { for (; i < len; i++, pval++) { if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) { @@ -40829,7 +40117,7 @@ static JSValue js_array_toSorted(JSContext *ctx, JSValueConst this_val, } } - if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0) + if (JS_SetProperty(ctx, arr, JS_ATOM_length, js_int64(len)) < 0) goto exception; } @@ -40863,7 +40151,7 @@ static void js_array_iterator_finalizer(JSRuntime *rt, JSValue val) } } -static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val, +static void js_array_iterator_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); @@ -40873,7 +40161,7 @@ static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val, } } -static JSValue js_create_array(JSContext *ctx, int len, JSValueConst *tab) +static JSValue js_create_array(JSContext *ctx, int len, JSValue *tab) { JSValue obj; int i; @@ -40882,7 +40170,7 @@ static JSValue js_create_array(JSContext *ctx, int len, JSValueConst *tab) if (JS_IsException(obj)) return JS_EXCEPTION; for(i = 0; i < len; i++) { - if (JS_CreateDataPropertyUint32(ctx, obj, i, JS_DupValue(ctx, tab[i]), 0) < 0) { + if (JS_CreateDataPropertyUint32(ctx, obj, i, js_dup(tab[i]), 0) < 0) { JS_FreeValue(ctx, obj); return JS_EXCEPTION; } @@ -40890,8 +40178,8 @@ static JSValue js_create_array(JSContext *ctx, int len, JSValueConst *tab) return obj; } -static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) +static JSValue js_create_array_iterator(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { JSValue enum_obj, arr; JSArrayIteratorData *it; @@ -40918,7 +40206,7 @@ static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val, it->obj = arr; it->kind = kind; it->idx = 0; - JS_SetOpaque(enum_obj, it); + JS_SetOpaqueInternal(enum_obj, it); return enum_obj; fail1: JS_FreeValue(ctx, enum_obj); @@ -40927,9 +40215,9 @@ static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, - BOOL *pdone, int magic) +static JSValue js_array_iterator_next(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, + int *pdone, int magic) { JSArrayIteratorData *it; uint32_t len, idx; @@ -40942,17 +40230,16 @@ static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val, if (JS_IsUndefined(it->obj)) goto done; p = JS_VALUE_GET_OBJ(it->obj); - if (p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_FLOAT64_ARRAY) { - if (typed_array_is_detached(ctx, p)) { - JS_ThrowTypeErrorDetachedArrayBuffer(ctx); + if (is_typed_array(p->class_id)) { + if (typed_array_is_oob(p)) { + JS_ThrowTypeErrorArrayBufferOOB(ctx); goto fail1; } len = p->u.array.count; } else { if (js_get_length32(ctx, &len, it->obj)) { fail1: - *pdone = FALSE; + *pdone = false; return JS_EXCEPTION; } } @@ -40961,13 +40248,13 @@ static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val, JS_FreeValue(ctx, it->obj); it->obj = JS_UNDEFINED; done: - *pdone = TRUE; + *pdone = true; return JS_UNDEFINED; } it->idx = idx + 1; - *pdone = FALSE; + *pdone = false; if (it->kind == JS_ITERATOR_KIND_KEY) { - return JS_NewUint32(ctx, idx); + return js_uint32(idx); } else { val = JS_GetPropertyUint32(ctx, it->obj, idx); if (JS_IsException(val)) @@ -40975,9 +40262,9 @@ static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val, if (it->kind == JS_ITERATOR_KIND_VALUE) { return val; } else { - JSValueConst args[2]; + JSValue args[2]; JSValue num; - num = JS_NewUint32(ctx, idx); + num = js_uint32(idx); args[0] = num; args[1] = val; obj = js_create_array(ctx, 2, args); @@ -40988,607 +40275,1395 @@ static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val, } } -static JSValue js_iterator_proto_iterator(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_DupValue(ctx, this_val); -} - -static const JSCFunctionListEntry js_iterator_proto_funcs[] = { - JS_CFUNC_DEF("[Symbol.iterator]", 0, js_iterator_proto_iterator ), -}; - -static const JSCFunctionListEntry js_array_proto_funcs[] = { - JS_CFUNC_DEF("at", 1, js_array_at ), - JS_CFUNC_DEF("with", 2, js_array_with ), - JS_CFUNC_DEF("concat", 1, js_array_concat ), - JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, special_every ), - JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, special_some ), - JS_CFUNC_MAGIC_DEF("forEach", 1, js_array_every, special_forEach ), - JS_CFUNC_MAGIC_DEF("map", 1, js_array_every, special_map ), - JS_CFUNC_MAGIC_DEF("filter", 1, js_array_every, special_filter ), - JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce ), - JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight ), - JS_CFUNC_DEF("fill", 1, js_array_fill ), - JS_CFUNC_MAGIC_DEF("find", 1, js_array_find, ArrayFind ), - JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, ArrayFindIndex ), - JS_CFUNC_MAGIC_DEF("findLast", 1, js_array_find, ArrayFindLast ), - JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_array_find, ArrayFindLastIndex ), - JS_CFUNC_DEF("indexOf", 1, js_array_indexOf ), - JS_CFUNC_DEF("lastIndexOf", 1, js_array_lastIndexOf ), - JS_CFUNC_DEF("includes", 1, js_array_includes ), - JS_CFUNC_MAGIC_DEF("join", 1, js_array_join, 0 ), - JS_CFUNC_DEF("toString", 0, js_array_toString ), - JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_array_join, 1 ), - JS_CFUNC_MAGIC_DEF("pop", 0, js_array_pop, 0 ), - JS_CFUNC_MAGIC_DEF("push", 1, js_array_push, 0 ), - JS_CFUNC_MAGIC_DEF("shift", 0, js_array_pop, 1 ), - JS_CFUNC_MAGIC_DEF("unshift", 1, js_array_push, 1 ), - JS_CFUNC_DEF("reverse", 0, js_array_reverse ), - JS_CFUNC_DEF("toReversed", 0, js_array_toReversed ), - JS_CFUNC_DEF("sort", 1, js_array_sort ), - JS_CFUNC_DEF("toSorted", 1, js_array_toSorted ), - JS_CFUNC_MAGIC_DEF("slice", 2, js_array_slice, 0 ), - JS_CFUNC_MAGIC_DEF("splice", 2, js_array_slice, 1 ), - JS_CFUNC_DEF("toSpliced", 2, js_array_toSpliced ), - JS_CFUNC_DEF("copyWithin", 2, js_array_copyWithin ), - JS_CFUNC_MAGIC_DEF("flatMap", 1, js_array_flatten, 1 ), - JS_CFUNC_MAGIC_DEF("flat", 0, js_array_flatten, 0 ), - JS_CFUNC_MAGIC_DEF("values", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE ), - JS_ALIAS_DEF("[Symbol.iterator]", "values" ), - JS_CFUNC_MAGIC_DEF("keys", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY ), - JS_CFUNC_MAGIC_DEF("entries", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY_AND_VALUE ), -}; - -static const JSCFunctionListEntry js_array_iterator_proto_funcs[] = { - JS_ITERATOR_NEXT_DEF("next", 0, js_array_iterator_next, 0 ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Array Iterator", JS_PROP_CONFIGURABLE ), -}; - -/* Number */ +typedef struct JSIteratorWrapData { + JSValue wrapped_iter; + JSValue wrapped_next; +} JSIteratorWrapData; -static JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) +static void js_iterator_wrap_finalizer(JSRuntime *rt, JSValue val) { - JSValue val, obj; - if (argc == 0) { - val = JS_NewInt32(ctx, 0); - } else { - val = JS_ToNumeric(ctx, argv[0]); - if (JS_IsException(val)) - return val; - switch(JS_VALUE_GET_TAG(val)) { - case JS_TAG_BIG_INT: -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: -#endif - { - JSBigFloat *p = JS_VALUE_GET_PTR(val); - double d; - bf_get_float64(&p->num, &d, BF_RNDN); - JS_FreeValue(ctx, val); - val = JS_NewFloat64(ctx, d); - } - break; -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_DECIMAL: - val = JS_ToStringFree(ctx, val); - if (JS_IsException(val)) - return val; - val = JS_ToNumberFree(ctx, val); - if (JS_IsException(val)) - return val; - break; -#endif - default: - break; - } - } - if (!JS_IsUndefined(new_target)) { - obj = js_create_from_ctor(ctx, new_target, JS_CLASS_NUMBER); - if (!JS_IsException(obj)) - JS_SetObjectData(ctx, obj, val); - return obj; - } else { - return val; + JSObject *p = JS_VALUE_GET_OBJ(val); + JSIteratorWrapData *it = p->u.iterator_wrap_data; + if (it) { + JS_FreeValueRT(rt, it->wrapped_iter); + JS_FreeValueRT(rt, it->wrapped_next); + js_free_rt(rt, it); } } -#if 0 -static JSValue js_number___toInteger(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static void js_iterator_wrap_mark(JSRuntime *rt, JSValue val, + JS_MarkFunc *mark_func) { - return JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[0])); + JSObject *p = JS_VALUE_GET_OBJ(val); + JSIteratorWrapData *it = p->u.iterator_wrap_data; + if (it) { + JS_MarkValue(rt, it->wrapped_iter, mark_func); + JS_MarkValue(rt, it->wrapped_next, mark_func); + } } -static JSValue js_number___toLength(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_iterator_wrap_next(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, + int *pdone, int magic) { - int64_t v; - if (JS_ToLengthFree(ctx, &v, JS_DupValue(ctx, argv[0]))) + JSIteratorWrapData *it; + JSValue method, ret; + it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ITERATOR_WRAP); + if (!it) + return JS_EXCEPTION; + if (magic == GEN_MAGIC_NEXT) + return JS_IteratorNext(ctx, it->wrapped_iter, it->wrapped_next, argc, argv, pdone); + method = JS_GetProperty(ctx, it->wrapped_iter, JS_ATOM_return); + if (JS_IsException(method)) return JS_EXCEPTION; - return JS_NewInt64(ctx, v); + if (JS_IsNull(method) || JS_IsUndefined(method)) { + *pdone = true; + return JS_UNDEFINED; + } + ret = JS_IteratorNext2(ctx, it->wrapped_iter, method, argc, argv, pdone); + JS_FreeValue(ctx, method); + return ret; } -#endif -static JSValue js_number_isNaN(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - if (!JS_IsNumber(argv[0])) - return JS_FALSE; - return js_global_isNaN(ctx, this_val, argc, argv); -} +static const JSCFunctionListEntry js_iterator_wrap_proto_funcs[] = { + JS_ITERATOR_NEXT_DEF("next", 0, js_iterator_wrap_next, GEN_MAGIC_NEXT ), + JS_ITERATOR_NEXT_DEF("return", 0, js_iterator_wrap_next, GEN_MAGIC_RETURN ), +}; -static JSValue js_number_isFinite(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_iterator_constructor(JSContext *ctx, JSValue new_target, + int argc, JSValue *argv) { - if (!JS_IsNumber(argv[0])) - return JS_FALSE; - return js_global_isFinite(ctx, this_val, argc, argv); + JSObject *p; + + if (JS_TAG_OBJECT != JS_VALUE_GET_TAG(new_target)) + return JS_ThrowTypeError(ctx, "constructor requires 'new'"); + p = JS_VALUE_GET_OBJ(new_target); + if (p->class_id == JS_CLASS_C_FUNCTION) + if (p->u.cfunc.c_function.generic == js_iterator_constructor) + return JS_ThrowTypeError(ctx, "abstract class not constructable"); + return js_create_from_ctor(ctx, new_target, JS_CLASS_ITERATOR); } -static JSValue js_number_isInteger(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_iterator_from(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { + JSValue obj, method, iter; + JSIteratorWrapData *it; int ret; - ret = JS_NumberIsInteger(ctx, argv[0]); + + obj = argv[0]; + if (JS_IsString(obj)) { + method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator); + if (JS_IsException(method)) + return JS_EXCEPTION; + return JS_CallFree(ctx, method, obj, 0, NULL); + } + if (!JS_IsObject(obj)) + return JS_ThrowTypeError(ctx, "Iterator.from called on non-object"); + ret = JS_OrdinaryIsInstanceOf(ctx, obj, ctx->iterator_ctor); if (ret < 0) return JS_EXCEPTION; - else - return JS_NewBool(ctx, ret); -} - -static JSValue js_number_isSafeInteger(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - double d; - if (!JS_IsNumber(argv[0])) - return JS_FALSE; - if (unlikely(JS_ToFloat64(ctx, &d, argv[0]))) + if (ret) + return js_dup(obj); + method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator); + if (JS_IsException(method)) return JS_EXCEPTION; - return JS_NewBool(ctx, is_safe_integer(d)); -} - -static const JSCFunctionListEntry js_number_funcs[] = { - /* global ParseInt and parseFloat should be defined already or delayed */ - JS_ALIAS_BASE_DEF("parseInt", "parseInt", 0 ), - JS_ALIAS_BASE_DEF("parseFloat", "parseFloat", 0 ), - JS_CFUNC_DEF("isNaN", 1, js_number_isNaN ), - JS_CFUNC_DEF("isFinite", 1, js_number_isFinite ), - JS_CFUNC_DEF("isInteger", 1, js_number_isInteger ), - JS_CFUNC_DEF("isSafeInteger", 1, js_number_isSafeInteger ), - JS_PROP_DOUBLE_DEF("MAX_VALUE", 1.7976931348623157e+308, 0 ), - JS_PROP_DOUBLE_DEF("MIN_VALUE", 5e-324, 0 ), - JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ), - JS_PROP_DOUBLE_DEF("NEGATIVE_INFINITY", -INFINITY, 0 ), - JS_PROP_DOUBLE_DEF("POSITIVE_INFINITY", INFINITY, 0 ), - JS_PROP_DOUBLE_DEF("EPSILON", 2.220446049250313e-16, 0 ), /* ES6 */ - JS_PROP_DOUBLE_DEF("MAX_SAFE_INTEGER", 9007199254740991.0, 0 ), /* ES6 */ - JS_PROP_DOUBLE_DEF("MIN_SAFE_INTEGER", -9007199254740991.0, 0 ), /* ES6 */ - //JS_CFUNC_DEF("__toInteger", 1, js_number___toInteger ), - //JS_CFUNC_DEF("__toLength", 1, js_number___toLength ), -}; - -static JSValue js_thisNumberValue(JSContext *ctx, JSValueConst this_val) -{ - if (JS_IsNumber(this_val)) - return JS_DupValue(ctx, this_val); - - if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) { - JSObject *p = JS_VALUE_GET_OBJ(this_val); - if (p->class_id == JS_CLASS_NUMBER) { - if (JS_IsNumber(p->u.object_data)) - return JS_DupValue(ctx, p->u.object_data); - } + if (JS_IsNull(method) || JS_IsUndefined(method)) { + method = JS_GetProperty(ctx, obj, JS_ATOM_next); + if (JS_IsException(method)) + return JS_EXCEPTION; + iter = JS_NewObjectClass(ctx, JS_CLASS_ITERATOR_WRAP); + if (JS_IsException(iter)) + goto fail; + it = js_malloc(ctx, sizeof(*it)); + if (!it) + goto fail; + it->wrapped_iter = js_dup(obj); + it->wrapped_next = method; + JS_SetOpaqueInternal(iter, it); + } else { + iter = JS_GetIterator2(ctx, obj, method); + JS_FreeValue(ctx, method); + if (JS_IsException(iter)) + return JS_EXCEPTION; } - return JS_ThrowTypeError(ctx, "not a number"); -} - -static JSValue js_number_valueOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return js_thisNumberValue(ctx, this_val); + return iter; +fail: + JS_FreeValue(ctx, method); + JS_FreeValue(ctx, iter); + return JS_EXCEPTION; } -static int js_get_radix(JSContext *ctx, JSValueConst val) +static int check_iterator(JSContext *ctx, JSValue obj) { - int radix; - if (JS_ToInt32Sat(ctx, &radix, val)) - return -1; - if (radix < 2 || radix > 36) { - JS_ThrowRangeError(ctx, "radix must be between 2 and 36"); + if (!JS_IsObject(obj)) { + JS_ThrowTypeErrorNotAnObject(ctx); return -1; } - return radix; + return 0; } -static JSValue js_number_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSValue val; - int base; - double d; - - val = js_thisNumberValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (magic || JS_IsUndefined(argv[0])) { - base = 10; - } else { - base = js_get_radix(ctx, argv[0]); - if (base < 0) - goto fail; - } - if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) { - char buf1[70], *ptr; - ptr = i64toa(buf1 + sizeof(buf1), JS_VALUE_GET_INT(val), base); - return JS_NewString(ctx, ptr); - } - if (JS_ToFloat64Free(ctx, &d, val)) - return JS_EXCEPTION; - if (base != 10 && isfinite(d)) { - return js_dtoa_radix(ctx, d, base); - } - return js_dtoa(ctx, d, base, 0, JS_DTOA_VAR_FORMAT); - fail: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} +typedef struct JSIteratorHelperData { + JSValue obj; + JSValue next; + JSValue func; // predicate (filter) or mapper (flatMap, map) + JSValue inner; // innerValue (flatMap) + int64_t count; // limit (drop, take) or counter (filter, map, flatMap) + JSIteratorHelperKindEnum kind : 8; + uint8_t executing : 1; + uint8_t done : 1; +} JSIteratorHelperData; -static JSValue js_number_toFixed(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_create_iterator_helper(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { - JSValue val; - int f; - double d; + JSValue func, obj, method; + int64_t count; + JSIteratorHelperData *it; - val = js_thisNumberValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (JS_ToFloat64Free(ctx, &d, val)) - return JS_EXCEPTION; - if (JS_ToInt32Sat(ctx, &f, argv[0])) + if (check_iterator(ctx, this_val) < 0) return JS_EXCEPTION; - if (f < 0 || f > 100) - return JS_ThrowRangeError(ctx, "invalid number of digits"); - if (fabs(d) >= 1e21) { - return JS_ToStringFree(ctx, __JS_NewFloat64(ctx, d)); - } else { - return js_dtoa(ctx, d, 10, f, JS_DTOA_FRAC_FORMAT); - } -} + func = JS_UNDEFINED; + count = 0; -static JSValue js_number_toExponential(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val; - int f, flags; - double d; + switch(magic) { + case JS_ITERATOR_HELPER_KIND_DROP: + case JS_ITERATOR_HELPER_KIND_TAKE: + { + JSValue v; + double dlimit; + v = JS_ToNumber(ctx, argv[0]); + if (JS_IsException(v)) + return JS_EXCEPTION; + // Check for Infinity. + if (JS_ToFloat64(ctx, &dlimit, v)) { + JS_FreeValue(ctx, v); + return JS_EXCEPTION; + } + if (isnan(dlimit)) { + JS_FreeValue(ctx, v); + goto fail; + } + if (!isfinite(dlimit)) { + JS_FreeValue(ctx, v); + if (dlimit < 0) + goto fail; + else + count = MAX_SAFE_INTEGER; + } else { + v = JS_ToIntegerFree(ctx, v); + if (JS_IsException(v)) + return JS_EXCEPTION; + if (JS_ToInt64Free(ctx, &count, v)) + return JS_EXCEPTION; + } + if (count < 0) { + fail: + return JS_ThrowRangeError(ctx, "must be positive"); + } + } + break; + case JS_ITERATOR_HELPER_KIND_FILTER: + case JS_ITERATOR_HELPER_KIND_FLAT_MAP: + case JS_ITERATOR_HELPER_KIND_MAP: + { + func = argv[0]; + if (check_function(ctx, func)) + return JS_EXCEPTION; + } + break; + default: + abort(); + break; + } - val = js_thisNumberValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (JS_ToFloat64Free(ctx, &d, val)) + method = JS_GetProperty(ctx, this_val, JS_ATOM_next); + if (JS_IsException(method)) return JS_EXCEPTION; - if (JS_ToInt32Sat(ctx, &f, argv[0])) + obj = JS_NewObjectClass(ctx, JS_CLASS_ITERATOR_HELPER); + if (JS_IsException(obj)) { + JS_FreeValue(ctx, method); return JS_EXCEPTION; - if (!isfinite(d)) { - return JS_ToStringFree(ctx, __JS_NewFloat64(ctx, d)); - } - if (JS_IsUndefined(argv[0])) { - flags = 0; - f = 0; - } else { - if (f < 0 || f > 100) - return JS_ThrowRangeError(ctx, "invalid number of digits"); - f++; - flags = JS_DTOA_FIXED_FORMAT; } - return js_dtoa(ctx, d, 10, f, flags | JS_DTOA_FORCE_EXP); -} - -static JSValue js_number_toPrecision(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val; - int p; - double d; - - val = js_thisNumberValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (JS_ToFloat64Free(ctx, &d, val)) - return JS_EXCEPTION; - if (JS_IsUndefined(argv[0])) - goto to_string; - if (JS_ToInt32Sat(ctx, &p, argv[0])) + it = js_malloc(ctx, sizeof(*it)); + if (!it) { + JS_FreeValue(ctx, obj); + JS_FreeValue(ctx, method); return JS_EXCEPTION; - if (!isfinite(d)) { - to_string: - return JS_ToStringFree(ctx, __JS_NewFloat64(ctx, d)); } - if (p < 1 || p > 100) - return JS_ThrowRangeError(ctx, "invalid number of digits"); - return js_dtoa(ctx, d, 10, p, JS_DTOA_FIXED_FORMAT); + it->kind = magic; + it->obj = js_dup(this_val); + it->func = js_dup(func); + it->next = method; + it->inner = JS_UNDEFINED; + it->count = count; + it->executing = 0; + it->done = 0; + JS_SetOpaqueInternal(obj, it); + return obj; } -static const JSCFunctionListEntry js_number_proto_funcs[] = { - JS_CFUNC_DEF("toExponential", 1, js_number_toExponential ), - JS_CFUNC_DEF("toFixed", 1, js_number_toFixed ), - JS_CFUNC_DEF("toPrecision", 1, js_number_toPrecision ), - JS_CFUNC_MAGIC_DEF("toString", 1, js_number_toString, 0 ), - JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_number_toString, 1 ), - JS_CFUNC_DEF("valueOf", 0, js_number_valueOf ), -}; - -static JSValue js_parseInt(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_iterator_proto_func(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { - const char *str, *p; - int radix, flags; - JSValue ret; + JSValue item, method, ret, func, index_val, r; + JSValue args[2]; + int64_t idx; + int done; - str = JS_ToCString(ctx, argv[0]); - if (!str) + if (check_iterator(ctx, this_val) < 0) return JS_EXCEPTION; - if (JS_ToInt32(ctx, &radix, argv[1])) { - JS_FreeCString(ctx, str); + if (check_function(ctx, argv[0])) return JS_EXCEPTION; - } - if (radix != 0 && (radix < 2 || radix > 36)) { - ret = JS_NAN; - } else { - p = str; - p += skip_spaces(p); - flags = ATOD_INT_ONLY | ATOD_ACCEPT_PREFIX_AFTER_SIGN; - ret = js_atof(ctx, p, NULL, radix, flags); - } - JS_FreeCString(ctx, str); - return ret; -} + func = js_dup(argv[0]); + method = JS_GetProperty(ctx, this_val, JS_ATOM_next); + if (JS_IsException(method)) + goto fail; -static JSValue js_parseFloat(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *str, *p; - JSValue ret; + r = JS_UNDEFINED; - str = JS_ToCString(ctx, argv[0]); - if (!str) - return JS_EXCEPTION; - p = str; - p += skip_spaces(p); - ret = js_atof(ctx, p, NULL, 10, 0); - JS_FreeCString(ctx, str); - return ret; + switch(magic) { + case JS_ITERATOR_HELPER_KIND_EVERY: + { + r = JS_TRUE; + for (idx = 0; /*empty*/; idx++) { + item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done); + if (JS_IsException(item)) + goto fail; + if (done) + break; + index_val = js_int64(idx); + args[0] = item; + args[1] = index_val; + ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args); + JS_FreeValue(ctx, item); + JS_FreeValue(ctx, index_val); + if (JS_IsException(ret)) + goto fail; + if (!JS_ToBoolFree(ctx, ret)) { + if (JS_IteratorClose(ctx, this_val, false) < 0) + r = JS_EXCEPTION; + else + r = JS_FALSE; + break; + } + index_val = JS_UNDEFINED; + ret = JS_UNDEFINED; + item = JS_UNDEFINED; + } + } + break; + case JS_ITERATOR_HELPER_KIND_FIND: + { + for (idx = 0; /*empty*/; idx++) { + item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done); + if (JS_IsException(item)) + goto fail; + if (done) + break; + index_val = js_int64(idx); + args[0] = item; + args[1] = index_val; + ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args); + JS_FreeValue(ctx, index_val); + if (JS_IsException(ret)) { + JS_FreeValue(ctx, item); + goto fail; + } + if (JS_ToBoolFree(ctx, ret)) { + if (JS_IteratorClose(ctx, this_val, false) < 0) { + JS_FreeValue(ctx, item); + r = JS_EXCEPTION; + } else { + r = item; + } + break; + } + index_val = JS_UNDEFINED; + ret = JS_UNDEFINED; + item = JS_UNDEFINED; + } + } + break; + case JS_ITERATOR_HELPER_KIND_FOR_EACH: + { + for (idx = 0; /*empty*/; idx++) { + item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done); + if (JS_IsException(item)) + goto fail; + if (done) + break; + index_val = js_int64(idx); + args[0] = item; + args[1] = index_val; + ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args); + JS_FreeValue(ctx, item); + JS_FreeValue(ctx, index_val); + if (JS_IsException(ret)) + goto fail; + JS_FreeValue(ctx, ret); + index_val = JS_UNDEFINED; + ret = JS_UNDEFINED; + item = JS_UNDEFINED; + } + } + break; + case JS_ITERATOR_HELPER_KIND_SOME: + { + r = JS_FALSE; + for (idx = 0; /*empty*/; idx++) { + item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done); + if (JS_IsException(item)) + goto fail; + if (done) + break; + index_val = js_int64(idx); + args[0] = item; + args[1] = index_val; + ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args); + JS_FreeValue(ctx, item); + JS_FreeValue(ctx, index_val); + if (JS_IsException(ret)) + goto fail; + if (JS_ToBoolFree(ctx, ret)) { + if (JS_IteratorClose(ctx, this_val, false) < 0) + r = JS_EXCEPTION; + else + r = JS_TRUE; + break; + } + index_val = JS_UNDEFINED; + ret = JS_UNDEFINED; + item = JS_UNDEFINED; + } + } + break; + default: + abort(); + break; + } + + JS_FreeValue(ctx, func); + JS_FreeValue(ctx, method); + return r; +fail: + JS_IteratorClose(ctx, this_val, true); + JS_FreeValue(ctx, func); + JS_FreeValue(ctx, method); + return JS_EXCEPTION; } -/* Boolean */ -static JSValue js_boolean_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) +static JSValue js_iterator_proto_reduce(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - JSValue val, obj; - val = JS_NewBool(ctx, JS_ToBool(ctx, argv[0])); - if (!JS_IsUndefined(new_target)) { - obj = js_create_from_ctor(ctx, new_target, JS_CLASS_BOOLEAN); - if (!JS_IsException(obj)) - JS_SetObjectData(ctx, obj, val); - return obj; + JSValue item, method, ret, func, index_val, acc; + JSValue args[3]; + int64_t idx; + int done; + + if (check_iterator(ctx, this_val) < 0) + return JS_EXCEPTION; + if (check_function(ctx, argv[0])) + return JS_EXCEPTION; + acc = JS_UNDEFINED; + func = js_dup(argv[0]); + method = JS_GetProperty(ctx, this_val, JS_ATOM_next); + if (JS_IsException(method)) + goto exception; + if (argc > 1) { + acc = js_dup(argv[1]); + idx = 0; } else { - return val; + acc = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done); + if (JS_IsException(acc)) + goto exception; + if (done) { + JS_ThrowTypeError(ctx, "empty iterator"); + goto exception; + } + idx = 1; + } + for (/* empty */; /*empty*/; idx++) { + item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done); + if (JS_IsException(item)) + goto exception; + if (done) + break; + index_val = js_int64(idx); + args[0] = acc; + args[1] = item; + args[2] = index_val; + ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args); + JS_FreeValue(ctx, item); + JS_FreeValue(ctx, index_val); + if (JS_IsException(ret)) + goto exception; + JS_FreeValue(ctx, acc); + acc = ret; + index_val = JS_UNDEFINED; + ret = JS_UNDEFINED; + item = JS_UNDEFINED; } + JS_FreeValue(ctx, func); + JS_FreeValue(ctx, method); + return acc; +exception: + JS_IteratorClose(ctx, this_val, true); + JS_FreeValue(ctx, acc); + JS_FreeValue(ctx, func); + JS_FreeValue(ctx, method); + return JS_EXCEPTION; } -static JSValue js_thisBooleanValue(JSContext *ctx, JSValueConst this_val) +static JSValue js_iterator_proto_toArray(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - if (JS_VALUE_GET_TAG(this_val) == JS_TAG_BOOL) - return JS_DupValue(ctx, this_val); + JSValue item, method, result; + int64_t idx; + int done; - if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) { - JSObject *p = JS_VALUE_GET_OBJ(this_val); - if (p->class_id == JS_CLASS_BOOLEAN) { - if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_BOOL) - return p->u.object_data; - } + result = JS_UNDEFINED; + if (check_iterator(ctx, this_val) < 0) + return JS_EXCEPTION; + method = JS_GetProperty(ctx, this_val, JS_ATOM_next); + if (JS_IsException(method)) + return JS_EXCEPTION; + result = JS_NewArray(ctx); + if (JS_IsException(result)) + goto exception; + for (idx = 0; /*empty*/; idx++) { + item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done); + if (JS_IsException(item)) + goto exception; + if (done) + break; + if (JS_DefinePropertyValueInt64(ctx, result, idx, item, + JS_PROP_C_W_E | JS_PROP_THROW) < 0) + goto exception; } - return JS_ThrowTypeError(ctx, "not a boolean"); + if (JS_SetProperty(ctx, result, JS_ATOM_length, js_uint32(idx)) < 0) + goto exception; + JS_FreeValue(ctx, method); + return result; +exception: + JS_FreeValue(ctx, result); + JS_FreeValue(ctx, method); + return JS_EXCEPTION; } -static JSValue js_boolean_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_iterator_proto_iterator(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - JSValue val = js_thisBooleanValue(ctx, this_val); - if (JS_IsException(val)) - return val; - return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ? - JS_ATOM_true : JS_ATOM_false); + return js_dup(this_val); } -static JSValue js_boolean_valueOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_iterator_proto_get_toStringTag(JSContext *ctx, JSValue this_val) { - return js_thisBooleanValue(ctx, this_val); + return JS_AtomToString(ctx, JS_ATOM_Iterator); } -static const JSCFunctionListEntry js_boolean_proto_funcs[] = { - JS_CFUNC_DEF("toString", 0, js_boolean_toString ), - JS_CFUNC_DEF("valueOf", 0, js_boolean_valueOf ), -}; +static JSValue js_iterator_proto_set_toStringTag(JSContext *ctx, JSValue this_val, JSValue val) +{ + int res; -/* String */ + if (check_iterator(ctx, this_val) < 0) + return JS_EXCEPTION; + if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_ITERATOR])) + return JS_ThrowTypeError(ctx, "Cannot assign to read only property"); + res = JS_GetOwnProperty(ctx, NULL, this_val, JS_ATOM_Symbol_toStringTag); + if (res < 0) + return JS_EXCEPTION; + if (res) { + if (JS_SetProperty(ctx, this_val, JS_ATOM_Symbol_toStringTag, js_dup(val)) < 0) + return JS_EXCEPTION; + } else { + if (JS_DefinePropertyValue(ctx, this_val, JS_ATOM_Symbol_toStringTag, js_dup(val), JS_PROP_C_W_E) < 0) + return JS_EXCEPTION; + } + return JS_UNDEFINED; +} -static int js_string_get_own_property(JSContext *ctx, - JSPropertyDescriptor *desc, - JSValueConst obj, JSAtom prop) +static void js_iterator_helper_finalizer(JSRuntime *rt, JSValue val) { - JSObject *p; - JSString *p1; - uint32_t idx, ch; + JSObject *p = JS_VALUE_GET_OBJ(val); + JSIteratorHelperData *it = p->u.iterator_helper_data; + if (it) { + JS_FreeValueRT(rt, it->obj); + JS_FreeValueRT(rt, it->func); + JS_FreeValueRT(rt, it->next); + JS_FreeValueRT(rt, it->inner); + js_free_rt(rt, it); + } +} - /* This is a class exotic method: obj class_id is JS_CLASS_STRING */ - if (__JS_AtomIsTaggedInt(prop)) { - 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); - idx = __JS_AtomToUInt32(prop); - if (idx < p1->len) { - if (desc) { - ch = string_get(p1, idx); - desc->flags = JS_PROP_ENUMERABLE; - desc->value = js_new_string_char(ctx, ch); - desc->getter = JS_UNDEFINED; - desc->setter = JS_UNDEFINED; - } - return TRUE; - } - } +static void js_iterator_helper_mark(JSRuntime *rt, JSValue val, + JS_MarkFunc *mark_func) +{ + JSObject *p = JS_VALUE_GET_OBJ(val); + JSIteratorHelperData *it = p->u.iterator_helper_data; + if (it) { + JS_MarkValue(rt, it->obj, mark_func); + JS_MarkValue(rt, it->func, mark_func); + JS_MarkValue(rt, it->next, mark_func); + JS_MarkValue(rt, it->inner, mark_func); } - return FALSE; } -static int js_string_define_own_property(JSContext *ctx, - JSValueConst this_obj, - JSAtom prop, JSValueConst val, - JSValueConst getter, - JSValueConst setter, int flags) +static JSValue js_iterator_helper_next(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, + int *pdone, int magic) { - uint32_t idx; - JSObject *p; - JSString *p1, *p2; + JSIteratorHelperData *it; + JSValue ret; - if (__JS_AtomIsTaggedInt(prop)) { - idx = __JS_AtomToUInt32(prop); - p = JS_VALUE_GET_OBJ(this_obj); - if (JS_VALUE_GET_TAG(p->u.object_data) != JS_TAG_STRING) - goto def; - p1 = JS_VALUE_GET_STRING(p->u.object_data); - if (idx >= p1->len) - goto def; - if (!check_define_prop_flags(JS_PROP_ENUMERABLE, flags)) - goto fail; - /* check that the same value is configured */ - if (flags & JS_PROP_HAS_VALUE) { - if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING) + *pdone = false; + + it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ITERATOR_HELPER); + if (!it) + return JS_EXCEPTION; + if (it->executing) + return JS_ThrowTypeError(ctx, "cannot invoke a running iterator"); + if (it->done) { + *pdone = true; + return JS_UNDEFINED; + } + + it->executing = 1; + + switch (it->kind) { + case JS_ITERATOR_HELPER_KIND_DROP: + { + JSValue item, method; + if (magic == GEN_MAGIC_NEXT) { + method = js_dup(it->next); + } else { + method = JS_GetProperty(ctx, it->obj, JS_ATOM_return); + if (JS_IsException(method)) + goto fail; + } + while (it->count > 0) { + it->count--; + item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone); + if (JS_IsException(item)) { + JS_FreeValue(ctx, method); + goto fail; + } + JS_FreeValue(ctx, item); + if (magic == GEN_MAGIC_RETURN) + *pdone = true; + if (*pdone) { + JS_FreeValue(ctx, method); + ret = JS_UNDEFINED; + goto done; + } + } + + item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone); + JS_FreeValue(ctx, method); + if (JS_IsException(item)) goto fail; - p2 = JS_VALUE_GET_STRING(val); - if (p2->len != 1) + ret = item; + goto done; + } + break; + case JS_ITERATOR_HELPER_KIND_FILTER: + { + JSValue item, method, selected, index_val, args[2]; + if (magic == GEN_MAGIC_NEXT) { + method = js_dup(it->next); + } else { + method = JS_GetProperty(ctx, it->obj, JS_ATOM_return); + if (JS_IsException(method)) + goto fail; + } + filter_again: + item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone); + if (JS_IsException(item)) { + JS_FreeValue(ctx, method); + goto fail; + } + if (*pdone || magic == GEN_MAGIC_RETURN) { + JS_FreeValue(ctx, method); + ret = item; + goto done; + } + index_val = js_int64(it->count++); + args[0] = item; + args[1] = index_val; + selected = JS_Call(ctx, it->func, JS_UNDEFINED, countof(args), args); + JS_FreeValue(ctx, index_val); + if (JS_IsException(selected)) { + JS_FreeValue(ctx, method); goto fail; - if (string_get(p1, idx) != string_get(p2, 0)) { - fail: - return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable"); } + if (JS_ToBoolFree(ctx, selected)) { + JS_FreeValue(ctx, method); + ret = item; + goto done; + } + goto filter_again; } - return TRUE; - } else { - def: - return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter, - flags | JS_PROP_NO_EXOTIC); - } -} + break; + case JS_ITERATOR_HELPER_KIND_FLAT_MAP: + { + JSValue item, method, index_val, args[2], iter; + flat_map_again: + if (JS_IsUndefined(it->inner)) { + if (magic == GEN_MAGIC_NEXT) { + method = js_dup(it->next); + } else { + method = JS_GetProperty(ctx, it->obj, JS_ATOM_return); + if (JS_IsException(method)) + goto fail; + } + item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone); + JS_FreeValue(ctx, method); + if (JS_IsException(item)) + goto fail; + if (*pdone || magic == GEN_MAGIC_RETURN) { + ret = item; + goto done; + } + index_val = js_int64(it->count++); + args[0] = item; + args[1] = index_val; + ret = JS_Call(ctx, it->func, JS_UNDEFINED, countof(args), args); + JS_FreeValue(ctx, item); + JS_FreeValue(ctx, index_val); + if (JS_IsException(ret)) + goto fail; + if (!JS_IsObject(ret)) { + JS_FreeValue(ctx, ret); + JS_ThrowTypeError(ctx, "not an object"); + goto fail; + } + method = JS_GetProperty(ctx, ret, JS_ATOM_Symbol_iterator); + if (JS_IsException(method)) { + JS_FreeValue(ctx, ret); + goto fail; + } + if (JS_IsNull(method) || JS_IsUndefined(method)) { + JS_FreeValue(ctx, method); + iter = ret; + } else { + iter = JS_GetIterator2(ctx, ret, method); + JS_FreeValue(ctx, method); + JS_FreeValue(ctx, ret); + if (JS_IsException(iter)) + goto fail; + } -static int js_string_delete_property(JSContext *ctx, - JSValueConst obj, JSAtom prop) -{ - uint32_t idx; + it->inner = iter; + } - if (__JS_AtomIsTaggedInt(prop)) { - idx = __JS_AtomToUInt32(prop); - if (idx < js_string_obj_get_length(ctx, obj)) { - return FALSE; + if (magic == GEN_MAGIC_NEXT) + method = JS_GetProperty(ctx, it->inner, JS_ATOM_next); + else + method = JS_GetProperty(ctx, it->inner, JS_ATOM_return); + if (JS_IsException(method)) { + inner_fail: + JS_IteratorClose(ctx, it->inner, false); + JS_FreeValue(ctx, it->inner); + it->inner = JS_UNDEFINED; + goto fail; + } + if (magic == GEN_MAGIC_RETURN && (JS_IsUndefined(method) || JS_IsNull(method))) { + goto inner_end; + } else { + item = JS_IteratorNext(ctx, it->inner, method, 0, NULL, pdone); + JS_FreeValue(ctx, method); + if (JS_IsException(item)) + goto inner_fail; + } + if (*pdone) { + inner_end: + *pdone = false; // The outer iterator must continue. + JS_IteratorClose(ctx, it->inner, false); + JS_FreeValue(ctx, it->inner); + it->inner = JS_UNDEFINED; + goto flat_map_again; + } + ret = item; + goto done; + } + break; + case JS_ITERATOR_HELPER_KIND_MAP: + { + JSValue item, method, index_val, args[2]; + if (magic == GEN_MAGIC_NEXT) { + method = js_dup(it->next); + } else { + method = JS_GetProperty(ctx, it->obj, JS_ATOM_return); + if (JS_IsException(method)) + goto fail; + } + item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone); + JS_FreeValue(ctx, method); + if (JS_IsException(item)) + goto fail; + if (*pdone || magic == GEN_MAGIC_RETURN) { + ret = item; + goto done; + } + index_val = js_int64(it->count++); + args[0] = item; + args[1] = index_val; + ret = JS_Call(ctx, it->func, JS_UNDEFINED, countof(args), args); + JS_FreeValue(ctx, index_val); + if (JS_IsException(ret)) + goto fail; + goto done; } + break; + case JS_ITERATOR_HELPER_KIND_TAKE: + { + JSValue item, method; + if (it->count > 0) { + if (magic == GEN_MAGIC_NEXT) { + method = js_dup(it->next); + } else { + method = JS_GetProperty(ctx, it->obj, JS_ATOM_return); + if (JS_IsException(method)) + goto fail; + } + it->count--; + item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone); + JS_FreeValue(ctx, method); + if (JS_IsException(item)) + goto fail; + ret = item; + goto done; + } + + *pdone = true; + if (JS_IteratorClose(ctx, it->obj, false)) + ret = JS_EXCEPTION; + else + ret = JS_UNDEFINED; + goto done; + } + break; + default: + abort(); } - return TRUE; + +done: + it->done = magic == GEN_MAGIC_NEXT ? *pdone : 1; + it->executing = 0; + return ret; +fail: + /* close the iterator object, preserving pending exception */ + JS_IteratorClose(ctx, it->obj, true); + ret = JS_EXCEPTION; + goto done; } -static const JSClassExoticMethods js_string_exotic_methods = { - .get_own_property = js_string_get_own_property, - .define_own_property = js_string_define_own_property, - .delete_property = js_string_delete_property, +static const JSCFunctionListEntry js_iterator_funcs[] = { + JS_CFUNC_DEF("from", 1, js_iterator_from ), +}; + +static const JSCFunctionListEntry js_iterator_proto_funcs[] = { + JS_CFUNC_MAGIC_DEF("drop", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_DROP ), + JS_CFUNC_MAGIC_DEF("filter", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_FILTER ), + JS_CFUNC_MAGIC_DEF("flatMap", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_FLAT_MAP ), + JS_CFUNC_MAGIC_DEF("map", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_MAP ), + JS_CFUNC_MAGIC_DEF("take", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_TAKE ), + JS_CFUNC_MAGIC_DEF("every", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_EVERY ), + JS_CFUNC_MAGIC_DEF("find", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_FIND), + JS_CFUNC_MAGIC_DEF("forEach", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_FOR_EACH ), + JS_CFUNC_MAGIC_DEF("some", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_SOME ), + JS_CFUNC_DEF("reduce", 1, js_iterator_proto_reduce ), + JS_CFUNC_DEF("toArray", 0, js_iterator_proto_toArray ), + JS_CFUNC_DEF("[Symbol.iterator]", 0, js_iterator_proto_iterator ), + JS_CGETSET_DEF("[Symbol.toStringTag]", js_iterator_proto_get_toStringTag, js_iterator_proto_set_toStringTag), +}; + +static const JSCFunctionListEntry js_iterator_helper_proto_funcs[] = { + JS_ITERATOR_NEXT_DEF("next", 0, js_iterator_helper_next, GEN_MAGIC_NEXT ), + JS_ITERATOR_NEXT_DEF("return", 0, js_iterator_helper_next, GEN_MAGIC_RETURN ), + JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Iterator Helper", JS_PROP_CONFIGURABLE ), +}; + +static const JSCFunctionListEntry js_array_proto_funcs[] = { + JS_CFUNC_DEF("at", 1, js_array_at ), + JS_CFUNC_DEF("with", 2, js_array_with ), + JS_CFUNC_DEF("concat", 1, js_array_concat ), + JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, special_every ), + JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, special_some ), + JS_CFUNC_MAGIC_DEF("forEach", 1, js_array_every, special_forEach ), + JS_CFUNC_MAGIC_DEF("map", 1, js_array_every, special_map ), + JS_CFUNC_MAGIC_DEF("filter", 1, js_array_every, special_filter ), + JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce ), + JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight ), + JS_CFUNC_DEF("fill", 1, js_array_fill ), + JS_CFUNC_MAGIC_DEF("find", 1, js_array_find, ArrayFind ), + JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, ArrayFindIndex ), + JS_CFUNC_MAGIC_DEF("findLast", 1, js_array_find, ArrayFindLast ), + JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_array_find, ArrayFindLastIndex ), + JS_CFUNC_DEF("indexOf", 1, js_array_indexOf ), + JS_CFUNC_DEF("lastIndexOf", 1, js_array_lastIndexOf ), + JS_CFUNC_DEF("includes", 1, js_array_includes ), + JS_CFUNC_MAGIC_DEF("join", 1, js_array_join, 0 ), + JS_CFUNC_DEF("toString", 0, js_array_toString ), + JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_array_join, 1 ), + JS_CFUNC_MAGIC_DEF("pop", 0, js_array_pop, 0 ), + JS_CFUNC_MAGIC_DEF("push", 1, js_array_push, 0 ), + JS_CFUNC_MAGIC_DEF("shift", 0, js_array_pop, 1 ), + JS_CFUNC_MAGIC_DEF("unshift", 1, js_array_push, 1 ), + JS_CFUNC_DEF("reverse", 0, js_array_reverse ), + JS_CFUNC_DEF("toReversed", 0, js_array_toReversed ), + JS_CFUNC_DEF("sort", 1, js_array_sort ), + JS_CFUNC_DEF("toSorted", 1, js_array_toSorted ), + JS_CFUNC_MAGIC_DEF("slice", 2, js_array_slice, 0 ), + JS_CFUNC_MAGIC_DEF("splice", 2, js_array_slice, 1 ), + JS_CFUNC_DEF("toSpliced", 2, js_array_toSpliced ), + JS_CFUNC_DEF("copyWithin", 2, js_array_copyWithin ), + JS_CFUNC_MAGIC_DEF("flatMap", 1, js_array_flatten, 1 ), + JS_CFUNC_MAGIC_DEF("flat", 0, js_array_flatten, 0 ), + JS_CFUNC_MAGIC_DEF("values", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE ), + JS_ALIAS_DEF("[Symbol.iterator]", "values" ), + JS_CFUNC_MAGIC_DEF("keys", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY ), + JS_CFUNC_MAGIC_DEF("entries", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY_AND_VALUE ), +}; + +static const JSCFunctionListEntry js_array_iterator_proto_funcs[] = { + JS_ITERATOR_NEXT_DEF("next", 0, js_array_iterator_next, 0 ), + JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Array Iterator", JS_PROP_CONFIGURABLE ), }; -static JSValue js_string_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) +/* Number */ + +static JSValue js_number_constructor(JSContext *ctx, JSValue new_target, + int argc, JSValue *argv) { JSValue val, obj; if (argc == 0) { - val = JS_AtomToString(ctx, JS_ATOM_empty_string); + val = js_int32(0); } else { - if (JS_IsUndefined(new_target) && JS_IsSymbol(argv[0])) { - JSAtomStruct *p = JS_VALUE_GET_PTR(argv[0]); - val = JS_ConcatString3(ctx, "Symbol(", JS_AtomToString(ctx, js_get_atom_index(ctx->rt, p)), ")"); - } else { - val = JS_ToString(ctx, argv[0]); - } + val = JS_ToNumeric(ctx, argv[0]); if (JS_IsException(val)) return val; + switch(JS_VALUE_GET_TAG(val)) { + case JS_TAG_BIG_INT: + { + JSBigInt *p = JS_VALUE_GET_PTR(val); + double d; + bf_get_float64(&p->num, &d, BF_RNDN); + JS_FreeValue(ctx, val); + val = js_float64(d); + } + break; + default: + break; + } } if (!JS_IsUndefined(new_target)) { - JSString *p1 = JS_VALUE_GET_STRING(val); - - obj = js_create_from_ctor(ctx, new_target, JS_CLASS_STRING); - if (!JS_IsException(obj)) { + obj = js_create_from_ctor(ctx, new_target, JS_CLASS_NUMBER); + if (!JS_IsException(obj)) JS_SetObjectData(ctx, obj, val); - JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, JS_NewInt32(ctx, p1->len), 0); - } return obj; } else { return val; } } -static JSValue js_thisStringValue(JSContext *ctx, JSValueConst this_val) +static JSValue js_number_isNaN(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - if (JS_VALUE_GET_TAG(this_val) == JS_TAG_STRING) - return JS_DupValue(ctx, this_val); + if (!JS_IsNumber(argv[0])) + return JS_FALSE; + return js_global_isNaN(ctx, this_val, argc, argv); +} + +static JSValue js_number_isFinite(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + if (!JS_IsNumber(argv[0])) + return JS_FALSE; + return js_global_isFinite(ctx, this_val, argc, argv); +} + +static JSValue js_number_isInteger(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + int ret; + ret = JS_NumberIsInteger(ctx, argv[0]); + if (ret < 0) + return JS_EXCEPTION; + else + return js_bool(ret); +} + +static JSValue js_number_isSafeInteger(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + double d; + if (!JS_IsNumber(argv[0])) + return JS_FALSE; + if (unlikely(JS_ToFloat64(ctx, &d, argv[0]))) + return JS_EXCEPTION; + return js_bool(is_safe_integer(d)); +} + +static const JSCFunctionListEntry js_number_funcs[] = { + /* global ParseInt and parseFloat should be defined already or delayed */ + JS_ALIAS_BASE_DEF("parseInt", "parseInt", 0 ), + JS_ALIAS_BASE_DEF("parseFloat", "parseFloat", 0 ), + JS_CFUNC_DEF("isNaN", 1, js_number_isNaN ), + JS_CFUNC_DEF("isFinite", 1, js_number_isFinite ), + JS_CFUNC_DEF("isInteger", 1, js_number_isInteger ), + JS_CFUNC_DEF("isSafeInteger", 1, js_number_isSafeInteger ), + JS_PROP_DOUBLE_DEF("MAX_VALUE", 1.7976931348623157e+308, 0 ), + JS_PROP_DOUBLE_DEF("MIN_VALUE", 5e-324, 0 ), + JS_PROP_U2D_DEF("NaN", 0x7FF8ull<<48, 0 ), // workaround for msvc + JS_PROP_DOUBLE_DEF("NEGATIVE_INFINITY", -INFINITY, 0 ), + JS_PROP_DOUBLE_DEF("POSITIVE_INFINITY", INFINITY, 0 ), + JS_PROP_DOUBLE_DEF("EPSILON", 2.220446049250313e-16, 0 ), /* ES6 */ + JS_PROP_DOUBLE_DEF("MAX_SAFE_INTEGER", 9007199254740991.0, 0 ), /* ES6 */ + JS_PROP_DOUBLE_DEF("MIN_SAFE_INTEGER", -9007199254740991.0, 0 ), /* ES6 */ +}; + +static JSValue js_thisNumberValue(JSContext *ctx, JSValue this_val) +{ + if (JS_IsNumber(this_val)) + return js_dup(this_val); if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) { JSObject *p = JS_VALUE_GET_OBJ(this_val); - if (p->class_id == JS_CLASS_STRING) { - if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) - return JS_DupValue(ctx, p->u.object_data); + if (p->class_id == JS_CLASS_NUMBER) { + if (JS_IsNumber(p->u.object_data)) + return js_dup(p->u.object_data); } } - return JS_ThrowTypeError(ctx, "not a string"); + return JS_ThrowTypeError(ctx, "not a number"); } -static JSValue js_string_fromCharCode(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_number_valueOf(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - int i; - StringBuffer b_s, *b = &b_s; + return js_thisNumberValue(ctx, this_val); +} - string_buffer_init(ctx, b, argc); +static int js_get_radix(JSContext *ctx, JSValue val) +{ + int radix; + if (JS_ToInt32Sat(ctx, &radix, val)) + return -1; + if (radix < 2 || radix > 36) { + JS_ThrowRangeError(ctx, "toString() radix argument must be between 2 and 36"); + return -1; + } + return radix; +} - for(i = 0; i < argc; i++) { - int32_t c; - if (JS_ToInt32(ctx, &c, argv[i]) || string_buffer_putc16(b, c & 0xffff)) { - string_buffer_free(b); +static JSValue js_number_toString(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) +{ + char buf[72]; + JSValue val; + int base; + double d; + + val = js_thisNumberValue(ctx, this_val); + if (JS_IsException(val)) + return val; + if (magic || JS_IsUndefined(argv[0])) { + if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) { + size_t len = i32toa(buf, JS_VALUE_GET_INT(val)); + return js_new_string8_len(ctx, buf, len); + } + base = 10; + } else { + base = js_get_radix(ctx, argv[0]); + if (base < 0) { + JS_FreeValue(ctx, val); return JS_EXCEPTION; } } - return string_buffer_end(b); + if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) { + size_t len = i32toa_radix(buf, JS_VALUE_GET_INT(val), base); + return js_new_string8_len(ctx, buf, len); + } + if (JS_ToFloat64Free(ctx, &d, val)) + return JS_EXCEPTION; + if (base != 10) + return js_dtoa_radix(ctx, d, base); + + return js_dtoa(ctx, d, 0, JS_DTOA_TOSTRING); } -static JSValue js_string_fromCodePoint(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_number_toFixed(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { + JSValue val; + int f; double d; - int i, c; - StringBuffer b_s, *b = &b_s; - - /* XXX: could pre-compute string length if all arguments are JS_TAG_INT */ - if (string_buffer_init(ctx, b, argc)) - goto fail; - for(i = 0; i < argc; i++) { - if (JS_VALUE_GET_TAG(argv[i]) == JS_TAG_INT) { + val = js_thisNumberValue(ctx, this_val); + if (JS_IsException(val)) + return val; + if (JS_ToFloat64Free(ctx, &d, val)) + return JS_EXCEPTION; + if (JS_ToInt32Sat(ctx, &f, argv[0])) + return JS_EXCEPTION; + if (f < 0 || f > 100) { + return JS_ThrowRangeError(ctx, "toFixed() digits argument must be between 0 and 100"); + } + if (fabs(d) >= 1e21) { + // use ToString(d) + return js_dtoa(ctx, d, 0, JS_DTOA_TOSTRING); + } else { + return js_dtoa(ctx, d, f, JS_DTOA_FIXED); + } +} + +static JSValue js_number_toExponential(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + JSValue val; + double d; + int f; + + val = js_thisNumberValue(ctx, this_val); + if (JS_IsException(val)) + return val; + if (JS_ToFloat64Free(ctx, &d, val)) + return JS_EXCEPTION; + if (JS_ToInt32Sat(ctx, &f, argv[0])) + return JS_EXCEPTION; + if (!isfinite(d)) + return js_dtoa_infinite(ctx, d); + if (!JS_IsUndefined(argv[0])) { + if (f < 0 || f > 100) { + return JS_ThrowRangeError(ctx, "toExponential() argument must be between 0 and 100"); + } + f += 1; /* number of significant digits between 1 and 101 */ + } + return js_dtoa(ctx, d, f, JS_DTOA_EXPONENTIAL); +} + +static JSValue js_number_toPrecision(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + JSValue val; + int p; + double d; + + val = js_thisNumberValue(ctx, this_val); + if (JS_IsException(val)) + return val; + if (JS_ToFloat64Free(ctx, &d, val)) + return JS_EXCEPTION; + if (JS_IsUndefined(argv[0])) + return js_dtoa(ctx, d, 0, JS_DTOA_TOSTRING); + if (JS_ToInt32Sat(ctx, &p, argv[0])) + return JS_EXCEPTION; + if (!isfinite(d)) + return js_dtoa_infinite(ctx, d); + if (p < 1 || p > 100) { + return JS_ThrowRangeError(ctx, "toPrecision() argument must be between 1 and 100"); + } + return js_dtoa(ctx, d, p, JS_DTOA_PRECISION); +} + +static const JSCFunctionListEntry js_number_proto_funcs[] = { + JS_CFUNC_DEF("toExponential", 1, js_number_toExponential ), + JS_CFUNC_DEF("toFixed", 1, js_number_toFixed ), + JS_CFUNC_DEF("toPrecision", 1, js_number_toPrecision ), + JS_CFUNC_MAGIC_DEF("toString", 1, js_number_toString, 0 ), + JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_number_toString, 1 ), + JS_CFUNC_DEF("valueOf", 0, js_number_valueOf ), +}; + +static JSValue js_parseInt(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + const char *str; + int radix, flags; + JSValue ret; + size_t len; + + str = JS_ToCStringLen(ctx, &len, argv[0]); + if (!str) + return JS_EXCEPTION; + if (JS_ToInt32(ctx, &radix, argv[1])) { + JS_FreeCString(ctx, str); + return JS_EXCEPTION; + } + flags = ATOD_TRIM_SPACES; + if (radix == 0) { + flags |= ATOD_ACCEPT_HEX_PREFIX; // Only 0x and 0X are supported + radix = 10; + } + ret = js_atof(ctx, str, len, NULL, radix, flags); + JS_FreeCString(ctx, str); + return ret; +} + +static JSValue js_parseFloat(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + const char *str; + JSValue ret; + int flags; + size_t len; + + str = JS_ToCStringLen(ctx, &len, argv[0]); + if (!str) + return JS_EXCEPTION; + flags = ATOD_TRIM_SPACES | ATOD_ACCEPT_FLOAT | ATOD_ACCEPT_INFINITY; + ret = js_atof(ctx, str, len, NULL, 10, flags); + JS_FreeCString(ctx, str); + return ret; +} + +/* Boolean */ +static JSValue js_boolean_constructor(JSContext *ctx, JSValue new_target, + int argc, JSValue *argv) +{ + JSValue val, obj; + val = js_bool(JS_ToBool(ctx, argv[0])); + if (!JS_IsUndefined(new_target)) { + obj = js_create_from_ctor(ctx, new_target, JS_CLASS_BOOLEAN); + if (!JS_IsException(obj)) + JS_SetObjectData(ctx, obj, val); + return obj; + } else { + return val; + } +} + +static JSValue js_thisBooleanValue(JSContext *ctx, JSValue this_val) +{ + if (JS_VALUE_GET_TAG(this_val) == JS_TAG_BOOL) + return js_dup(this_val); + + if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) { + JSObject *p = JS_VALUE_GET_OBJ(this_val); + if (p->class_id == JS_CLASS_BOOLEAN) { + if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_BOOL) + return p->u.object_data; + } + } + return JS_ThrowTypeError(ctx, "not a boolean"); +} + +static JSValue js_boolean_toString(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + JSValue val = js_thisBooleanValue(ctx, this_val); + if (JS_IsException(val)) + return val; + return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ? + JS_ATOM_true : JS_ATOM_false); +} + +static JSValue js_boolean_valueOf(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + return js_thisBooleanValue(ctx, this_val); +} + +static const JSCFunctionListEntry js_boolean_proto_funcs[] = { + JS_CFUNC_DEF("toString", 0, js_boolean_toString ), + JS_CFUNC_DEF("valueOf", 0, js_boolean_valueOf ), +}; + +/* String */ + +static int js_string_get_own_property(JSContext *ctx, + JSPropertyDescriptor *desc, + JSValue obj, JSAtom prop) +{ + JSObject *p; + JSString *p1; + uint32_t idx, ch; + + /* This is a class exotic method: obj class_id is JS_CLASS_STRING */ + if (__JS_AtomIsTaggedInt(prop)) { + 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); + idx = __JS_AtomToUInt32(prop); + if (idx < p1->len) { + if (desc) { + ch = string_get(p1, idx); + desc->flags = JS_PROP_ENUMERABLE; + desc->value = js_new_string_char(ctx, ch); + desc->getter = JS_UNDEFINED; + desc->setter = JS_UNDEFINED; + } + return true; + } + } + } + return false; +} + +static int js_string_define_own_property(JSContext *ctx, + JSValue this_obj, + JSAtom prop, JSValue val, + JSValue getter, + JSValue setter, int flags) +{ + uint32_t idx; + JSObject *p; + JSString *p1, *p2; + + if (__JS_AtomIsTaggedInt(prop)) { + idx = __JS_AtomToUInt32(prop); + p = JS_VALUE_GET_OBJ(this_obj); + if (JS_VALUE_GET_TAG(p->u.object_data) != JS_TAG_STRING) + goto def; + p1 = JS_VALUE_GET_STRING(p->u.object_data); + if (idx >= p1->len) + goto def; + if (!check_define_prop_flags(JS_PROP_ENUMERABLE, flags)) + goto fail; + /* check that the same value is configured */ + if (flags & JS_PROP_HAS_VALUE) { + if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING) + goto fail; + p2 = JS_VALUE_GET_STRING(val); + if (p2->len != 1) + goto fail; + if (string_get(p1, idx) != string_get(p2, 0)) { + fail: + return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable"); + } + } + return true; + } else { + def: + return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter, + flags | JS_PROP_NO_EXOTIC); + } +} + +static int js_string_delete_property(JSContext *ctx, + JSValue obj, JSAtom prop) +{ + uint32_t idx; + + if (__JS_AtomIsTaggedInt(prop)) { + idx = __JS_AtomToUInt32(prop); + if (idx < js_string_obj_get_length(ctx, obj)) { + return false; + } + } + return true; +} + +static const JSClassExoticMethods js_string_exotic_methods = { + .get_own_property = js_string_get_own_property, + .define_own_property = js_string_define_own_property, + .delete_property = js_string_delete_property, +}; + +static JSValue js_string_constructor(JSContext *ctx, JSValue new_target, + int argc, JSValue *argv) +{ + JSValue val, obj; + if (argc == 0) { + val = JS_AtomToString(ctx, JS_ATOM_empty_string); + } else { + if (JS_IsUndefined(new_target) && JS_IsSymbol(argv[0])) { + JSAtomStruct *p = JS_VALUE_GET_PTR(argv[0]); + val = JS_ConcatString3(ctx, "Symbol(", JS_AtomToString(ctx, js_get_atom_index(ctx->rt, p)), ")"); + } else { + val = JS_ToString(ctx, argv[0]); + } + if (JS_IsException(val)) + return val; + } + if (!JS_IsUndefined(new_target)) { + JSString *p1 = JS_VALUE_GET_STRING(val); + + obj = js_create_from_ctor(ctx, new_target, JS_CLASS_STRING); + if (!JS_IsException(obj)) { + JS_SetObjectData(ctx, obj, val); + JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, js_int32(p1->len), 0); + } + return obj; + } else { + return val; + } +} + +static JSValue js_thisStringValue(JSContext *ctx, JSValue this_val) +{ + if (JS_VALUE_GET_TAG(this_val) == JS_TAG_STRING) + return js_dup(this_val); + + if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) { + JSObject *p = JS_VALUE_GET_OBJ(this_val); + if (p->class_id == JS_CLASS_STRING) { + if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) + return js_dup(p->u.object_data); + } + } + return JS_ThrowTypeError(ctx, "not a string"); +} + +static JSValue js_string_fromCharCode(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + int i; + StringBuffer b_s, *b = &b_s; + + // shortcut for single argument common case + if (argc == 1 && JS_VALUE_GET_TAG(argv[0]) == JS_TAG_INT) { + uint16_t c16 = JS_VALUE_GET_INT(argv[0]); + return js_new_string_char(ctx, c16); + } + + string_buffer_init(ctx, b, argc); + + for(i = 0; i < argc; i++) { + int32_t c; + if (JS_ToInt32(ctx, &c, argv[i]) || string_buffer_putc16(b, c & 0xffff)) { + string_buffer_free(b); + return JS_EXCEPTION; + } + } + return string_buffer_end(b); +} + +static JSValue js_string_fromCodePoint(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + double d; + int i, c; + StringBuffer b_s, *b = NULL; + + // shortcut for single argument common case + if (argc == 1 && JS_VALUE_GET_TAG(argv[0]) == JS_TAG_INT) { + c = JS_VALUE_GET_INT(argv[0]); + if (c < 0 || c > 0x10ffff) + goto range_error; + if (c <= 0xffff) { + return js_new_string_char(ctx, c); + } else { + uint16_t c16[2]; + c16[0] = get_hi_surrogate(c); + c16[1] = get_lo_surrogate(c); + return js_new_string16_len(ctx, c16, 2); + } + } + + /* XXX: could pre-compute string length if all arguments are JS_TAG_INT */ + b = &b_s; + if (string_buffer_init(ctx, b, argc)) + goto fail; + for(i = 0; i < argc; i++) { + if (JS_VALUE_GET_TAG(argv[i]) == JS_TAG_INT) { c = JS_VALUE_GET_INT(argv[i]); if (c < 0 || c > 0x10ffff) goto range_error; } else { if (JS_ToFloat64(ctx, &d, argv[i])) goto fail; - if (isnan(d) || d < 0 || d > 0x10ffff || (c = (int)d) != d) + if (!(d >= 0 && d <= 0x10ffff) || (c = (int)d) != d) goto range_error; } if (string_buffer_putc(b, c)) @@ -41599,12 +41674,12 @@ static JSValue js_string_fromCodePoint(JSContext *ctx, JSValueConst this_val, range_error: JS_ThrowRangeError(ctx, "invalid code point"); fail: - string_buffer_free(b); + if (b) string_buffer_free(b); return JS_EXCEPTION; } -static JSValue js_string_raw(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_string_raw(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { // raw(temp,...a) JSValue cooked, val, raw; @@ -41644,8 +41719,8 @@ static JSValue js_string_raw(JSContext *ctx, JSValueConst this_val, } /* only used in test262 */ -JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +JSValue js_string_codePointRange(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { uint32_t start, end, i, n; StringBuffer b_s, *b = &b_s; @@ -41670,19 +41745,35 @@ JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val, return string_buffer_end(b); } -#if 0 -static JSValue js_string___isSpace(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_string_at(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - int c; - if (JS_ToInt32(ctx, &c, argv[0])) + JSValue val, ret; + JSString *p; + int idx, c; + + val = JS_ToStringCheckObject(ctx, this_val); + if (JS_IsException(val)) + return val; + p = JS_VALUE_GET_STRING(val); + if (JS_ToInt32Sat(ctx, &idx, argv[0])) { + JS_FreeValue(ctx, val); return JS_EXCEPTION; - return JS_NewBool(ctx, lre_is_space(c)); + } + if (idx < 0) + idx = p->len + idx; + if (idx < 0 || idx >= p->len) { + ret = JS_UNDEFINED; + } else { + c = string_get(p, idx); + ret = js_new_string_char(ctx, c); + } + JS_FreeValue(ctx, val); + return ret; } -#endif -static JSValue js_string_charCodeAt(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_string_charCodeAt(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue val, ret; JSString *p; @@ -41700,14 +41791,14 @@ static JSValue js_string_charCodeAt(JSContext *ctx, JSValueConst this_val, ret = JS_NAN; } else { c = string_get(p, idx); - ret = JS_NewInt32(ctx, c); + ret = js_int32(c); } JS_FreeValue(ctx, val); return ret; } -static JSValue js_string_charAt(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int is_at) +static JSValue js_string_charAt(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue val, ret; JSString *p; @@ -41721,13 +41812,8 @@ static JSValue js_string_charAt(JSContext *ctx, JSValueConst this_val, JS_FreeValue(ctx, val); return JS_EXCEPTION; } - if (idx < 0 && is_at) - idx += p->len; if (idx < 0 || idx >= p->len) { - if (is_at) - ret = JS_UNDEFINED; - else - ret = js_new_string8(ctx, NULL, 0); + ret = JS_AtomToString(ctx, JS_ATOM_empty_string); } else { c = string_get(p, idx); ret = js_new_string_char(ctx, c); @@ -41736,8 +41822,8 @@ static JSValue js_string_charAt(JSContext *ctx, JSValueConst this_val, return ret; } -static JSValue js_string_codePointAt(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_string_codePointAt(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue val, ret; JSString *p; @@ -41755,14 +41841,14 @@ static JSValue js_string_codePointAt(JSContext *ctx, JSValueConst this_val, ret = JS_UNDEFINED; } else { c = string_getc(p, &idx); - ret = JS_NewInt32(ctx, c); + ret = js_int32(c); } JS_FreeValue(ctx, val); return ret; } -static JSValue js_string_concat(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_string_concat(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue r; int i; @@ -41774,7 +41860,7 @@ static JSValue js_string_concat(JSContext *ctx, JSValueConst this_val, for (i = 0; i < argc; i++) { if (JS_IsException(r)) break; - r = JS_ConcatString(ctx, r, JS_DupValue(ctx, argv[i])); + r = JS_ConcatString(ctx, r, js_dup(argv[i])); } return r; } @@ -41825,7 +41911,7 @@ static int string_indexof(JSString *p1, JSString *p2, int from) return -1; } -static int64_t string_advance_index(JSString *p, int64_t index, BOOL unicode) +static int64_t string_advance_index(JSString *p, int64_t index, bool unicode) { if (!unicode || index >= p->len || !p->is_wide_char) { index++; @@ -41837,82 +41923,83 @@ static int64_t string_advance_index(JSString *p, int64_t index, BOOL unicode) return index; } -/* return the position of the first invalid character in the string or - -1 if none */ -static int js_string_find_invalid_codepoint(JSString *p) -{ - int i; - if (!p->is_wide_char) - return -1; - for(i = 0; i < p->len; i++) { - uint32_t c = p->u.str16[i]; - if (is_surrogate(c)) { - if (is_hi_surrogate(c) && (i + 1) < p->len - && is_lo_surrogate(p->u.str16[i + 1])) { - i++; - } else { - return i; - } - } - } - return -1; -} - -static JSValue js_string_isWellFormed(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_string_isWellFormed(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue str; + JSValue ret; JSString *p; - BOOL ret; + uint32_t c, i, n; + ret = JS_TRUE; str = JS_ToStringCheckObject(ctx, this_val); if (JS_IsException(str)) return JS_EXCEPTION; + p = JS_VALUE_GET_STRING(str); - ret = (js_string_find_invalid_codepoint(p) < 0); + if (!p->is_wide_char || p->len == 0) + goto done; // by definition well-formed + + for (i = 0, n = p->len; i < n; i++) { + c = p->u.str16[i]; + if (!is_surrogate(c)) + continue; + if (is_lo_surrogate(c) || i + 1 == n) + break; + c = p->u.str16[++i]; + if (!is_lo_surrogate(c)) + break; + } + + if (i < n) + ret = JS_FALSE; + +done: JS_FreeValue(ctx, str); - return JS_NewBool(ctx, ret); + return ret; } -static JSValue js_string_toWellFormed(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_string_toWellFormed(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - JSValue str, ret; + JSValue str; + JSValue ret; JSString *p; - int i; + uint32_t c, i, n; str = JS_ToStringCheckObject(ctx, this_val); if (JS_IsException(str)) return JS_EXCEPTION; p = JS_VALUE_GET_STRING(str); - /* avoid reallocating the string if it is well-formed */ - i = js_string_find_invalid_codepoint(p); - if (i < 0) - return str; + if (!p->is_wide_char || p->len == 0) + return str; // by definition well-formed - ret = js_new_string16(ctx, p->u.str16, p->len); + // TODO(bnoordhuis) don't clone when input is well-formed + ret = js_new_string16_len(ctx, p->u.str16, p->len); JS_FreeValue(ctx, str); if (JS_IsException(ret)) return JS_EXCEPTION; p = JS_VALUE_GET_STRING(ret); - for (; i < p->len; i++) { - uint32_t c = p->u.str16[i]; - if (is_surrogate(c)) { - if (is_hi_surrogate(c) && (i + 1) < p->len - && is_lo_surrogate(p->u.str16[i + 1])) { - i++; - } else { - p->u.str16[i] = 0xFFFD; - } + for (i = 0, n = p->len; i < n; i++) { + c = p->u.str16[i]; + if (!is_surrogate(c)) + continue; + if (is_lo_surrogate(c) || i + 1 == n) { + p->u.str16[i] = 0xFFFD; + continue; } + c = p->u.str16[++i]; + if (!is_lo_surrogate(c)) + p->u.str16[--i] = 0xFFFD; } + return ret; } -static JSValue js_string_indexOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int lastIndexOf) +static JSValue js_string_indexOf(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int lastIndexOf) { JSValue str, v; int i, len, v_len, pos, start, stop, ret, inc; @@ -41968,7 +42055,7 @@ static JSValue js_string_indexOf(JSContext *ctx, JSValueConst this_val, } JS_FreeValue(ctx, str); JS_FreeValue(ctx, v); - return JS_NewInt32(ctx, ret); + return js_int32(ret); fail: JS_FreeValue(ctx, str); @@ -41976,11 +42063,11 @@ static JSValue js_string_indexOf(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -/* return < 0 if exception or TRUE/FALSE */ -static int js_is_regexp(JSContext *ctx, JSValueConst obj); +/* return < 0 if exception or true/false */ +static int js_is_regexp(JSContext *ctx, JSValue obj); -static JSValue js_string_includes(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) +static JSValue js_string_includes(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { JSValue str, v = JS_UNDEFINED; int i, len, v_len, pos, start, stop, ret; @@ -42035,7 +42122,7 @@ static JSValue js_string_includes(JSContext *ctx, JSValueConst this_val, done: JS_FreeValue(ctx, str); JS_FreeValue(ctx, v); - return JS_NewBool(ctx, ret); + return js_bool(ret); fail: JS_FreeValue(ctx, str); @@ -42043,7 +42130,7 @@ static JSValue js_string_includes(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static int check_regexp_g_flag(JSContext *ctx, JSValueConst regexp) +static int check_regexp_g_flag(JSContext *ctx, JSValue regexp) { int ret; JSValue flags; @@ -42072,12 +42159,12 @@ static int check_regexp_g_flag(JSContext *ctx, JSValueConst regexp) return 0; } -static JSValue js_string_match(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int atom) +static JSValue js_string_match(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int atom) { // match(rx), search(rx), matchAll(rx) // atom is JS_ATOM_Symbol_match, JS_ATOM_Symbol_search, or JS_ATOM_Symbol_matchAll - JSValueConst O = this_val, regexp = argv[0], args[2]; + JSValue O = this_val, regexp = argv[0], args[2]; JSValue matcher, S, rx, result, str; int args_len; @@ -42105,7 +42192,7 @@ static JSValue js_string_match(JSContext *ctx, JSValueConst this_val, args[0] = regexp; str = JS_UNDEFINED; if (atom == JS_ATOM_Symbol_matchAll) { - str = JS_NewString(ctx, "g"); + str = js_new_string8(ctx, "g"); if (JS_IsException(str)) goto fail; args[args_len++] = str; @@ -42117,16 +42204,16 @@ static JSValue js_string_match(JSContext *ctx, JSValueConst this_val, JS_FreeValue(ctx, S); return JS_EXCEPTION; } - result = JS_InvokeFree(ctx, rx, atom, 1, (JSValueConst *)&S); + result = JS_InvokeFree(ctx, rx, atom, 1, &S); JS_FreeValue(ctx, S); return result; } -static JSValue js_string___GetSubstitution(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_string___GetSubstitution(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { // GetSubstitution(matched, str, position, captures, namedCaptures, rep) - JSValueConst matched, str, captures, namedCaptures, rep; + JSValue matched, str, captures, namedCaptures, rep; JSValue capture, name, s; uint32_t position, len, matched_len, captures_len; int i, j, j0, k, k1; @@ -42230,18 +42317,18 @@ static JSValue js_string___GetSubstitution(JSContext *ctx, JSValueConst this_val return JS_EXCEPTION; } -static JSValue js_string_replace(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, +static JSValue js_string_replace(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int is_replaceAll) { // replace(rx, rep) - JSValueConst O = this_val, searchValue = argv[0], replaceValue = argv[1]; - JSValueConst args[6]; + JSValue O = this_val, searchValue = argv[0], replaceValue = argv[1]; + JSValue args[6]; JSValue str, search_str, replaceValue_str, repl_str; JSString *sp, *searchp; StringBuffer b_s, *b = &b_s; int pos, functionalReplace, endOfLastMatch; - BOOL is_first; + bool is_first; if (JS_IsUndefined(O) || JS_IsNull(O)) return JS_ThrowTypeError(ctx, "cannot convert to object"); @@ -42283,7 +42370,7 @@ static JSValue js_string_replace(JSContext *ctx, JSValueConst this_val, sp = JS_VALUE_GET_STRING(str); searchp = JS_VALUE_GET_STRING(search_str); endOfLastMatch = 0; - is_first = TRUE; + is_first = true; for(;;) { if (unlikely(searchp->len == 0)) { if (is_first) @@ -42307,13 +42394,13 @@ static JSValue js_string_replace(JSContext *ctx, JSValueConst this_val, } if (functionalReplace) { args[0] = search_str; - args[1] = JS_NewInt32(ctx, pos); + args[1] = js_int32(pos); args[2] = str; repl_str = JS_ToStringFree(ctx, JS_Call(ctx, replaceValue, JS_UNDEFINED, 3, args)); } else { args[0] = search_str; args[1] = str; - args[2] = JS_NewInt32(ctx, pos); + args[2] = js_int32(pos); args[3] = JS_UNDEFINED; args[4] = JS_UNDEFINED; args[5] = replaceValue_str; @@ -42325,7 +42412,7 @@ static JSValue js_string_replace(JSContext *ctx, JSValueConst this_val, string_buffer_concat(b, sp, endOfLastMatch, pos); string_buffer_concat_value_free(b, repl_str); endOfLastMatch = pos + searchp->len; - is_first = FALSE; + is_first = false; if (!is_replaceAll) break; } @@ -42343,12 +42430,12 @@ static JSValue js_string_replace(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static JSValue js_string_split(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_string_split(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { // split(sep, limit) - JSValueConst O = this_val, separator = argv[0], limit = argv[1]; - JSValueConst args[2]; + JSValue O = this_val, separator = argv[0], limit = argv[1]; + JSValue args[2]; JSValue S, A, R, T; uint32_t lim, lengthA; int64_t p, q, s, r, e; @@ -42433,8 +42520,8 @@ static JSValue js_string_split(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static JSValue js_string_substring(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_string_substring(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue str, ret; int a, b, start, end; @@ -42467,8 +42554,8 @@ static JSValue js_string_substring(JSContext *ctx, JSValueConst this_val, return ret; } -static JSValue js_string_substr(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_string_substr(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue str, ret; int a, len, n; @@ -42495,8 +42582,8 @@ static JSValue js_string_substr(JSContext *ctx, JSValueConst this_val, return ret; } -static JSValue js_string_slice(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_string_slice(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue str, ret; int len, start, end; @@ -42523,8 +42610,8 @@ static JSValue js_string_slice(JSContext *ctx, JSValueConst this_val, return ret; } -static JSValue js_string_pad(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int padEnd) +static JSValue js_string_pad(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int padEnd) { JSValue str, v = JS_UNDEFINED; StringBuffer b_s, *b = &b_s; @@ -42594,8 +42681,8 @@ static JSValue js_string_pad(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static JSValue js_string_repeat(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_string_repeat(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue str; StringBuffer b_s, *b = &b_s; @@ -42617,7 +42704,6 @@ static JSValue js_string_repeat(JSContext *ctx, JSValueConst this_val, len = p->len; if (len == 0 || n == 1) return str; - // XXX: potential arithmetic overflow if (val * len > JS_STRING_LEN_MAX) { JS_ThrowRangeError(ctx, "invalid string length"); goto fail; @@ -42639,8 +42725,8 @@ static JSValue js_string_repeat(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static JSValue js_string_trim(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) +static JSValue js_string_trim(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { JSValue str, ret; int a, b, len; @@ -42665,12 +42751,6 @@ static JSValue js_string_trim(JSContext *ctx, JSValueConst this_val, return ret; } -static JSValue js_string___quote(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_ToQuotedString(ctx, this_val); -} - /* return 0 if before the first char */ static int string_prevc(JSString *p, int *pidx) { @@ -42696,7 +42776,7 @@ static int string_prevc(JSString *p, int *pidx) return c; } -static BOOL test_final_sigma(JSString *p, int sigma_pos) +static bool test_final_sigma(JSString *p, int sigma_pos) { int k, c1; @@ -42709,14 +42789,14 @@ static BOOL test_final_sigma(JSString *p, int sigma_pos) break; } if (!lre_is_cased(c1)) - return FALSE; + return false; /* after C: skip case ignorable chars and check there is no cased letter */ k = sigma_pos + 1; for(;;) { if (k >= p->len) - return TRUE; + return true; c1 = string_getc(p, &k); if (!lre_is_case_ignorable(c1)) break; @@ -42724,8 +42804,84 @@ static BOOL test_final_sigma(JSString *p, int sigma_pos) return !lre_is_cased(c1); } -static JSValue js_string_toLowerCase(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int to_lower) +static int to_utf32_buf(JSContext *ctx, JSString *p, uint32_t **pbuf) +{ + uint32_t *b; + int i, j, n; + + j = -1; + n = p->len; + b = js_malloc(ctx, max_int(1, n) * sizeof(*b)); + if (b) + for (i = j = 0; i < n;) + b[j++] = string_getc(p, &i); + *pbuf = b; + return j; +} + +static JSValue js_string_localeCompare(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + int i, n, an, bn, cmp; + uint32_t *as, *bs, *ts; + JSValue a, b, ret; + + ret = JS_EXCEPTION; + as = NULL; + bs = NULL; + + a = JS_ToStringCheckObject(ctx, this_val); + if (JS_IsException(a)) + return JS_EXCEPTION; + + b = JS_ToString(ctx, argv[0]); + if (JS_IsException(b)) + goto exception; + + an = to_utf32_buf(ctx, JS_VALUE_GET_STRING(a), &as); + if (an == -1) + goto exception; + + bn = to_utf32_buf(ctx, JS_VALUE_GET_STRING(b), &bs); + if (bn == -1) + goto exception; + + // TODO(bnoordhuis) skip normalization when input is latin1 + an = unicode_normalize(&ts, as, an, UNICODE_NFC, ctx, + (DynBufReallocFunc *)js_realloc); + if (an == -1) + goto exception; + js_free(ctx, as); + as = ts; + + // TODO(bnoordhuis) skip normalization when input is latin1 + bn = unicode_normalize(&ts, bs, bn, UNICODE_NFC, ctx, + (DynBufReallocFunc *)js_realloc); + if (bn == -1) + goto exception; + js_free(ctx, bs); + bs = ts; + + n = min_int(an, bn); + for (i = 0; i < n; i++) + if (as[i] != bs[i]) + break; + if (i < n) + cmp = compare_u32(as[i], bs[i]); + else + cmp = compare_u32(an, bn); + ret = js_int32(cmp); + +exception: + JS_FreeValue(ctx, a); + JS_FreeValue(ctx, b); + js_free(ctx, as); + js_free(ctx, bs); + return ret; +} + +static JSValue js_string_toLowerCase(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int to_lower) { JSValue val; StringBuffer b_s, *b = &b_s; @@ -42762,35 +42918,18 @@ static JSValue js_string_toLowerCase(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -#ifdef CONFIG_ALL_UNICODE - /* return (-1, NULL) if exception, otherwise (len, buf) */ -static int JS_ToUTF32String(JSContext *ctx, uint32_t **pbuf, JSValueConst val1) +static int JS_ToUTF32String(JSContext *ctx, uint32_t **pbuf, JSValue val1) { JSValue val; - JSString *p; - uint32_t *buf; - int i, j, len; + int len; val = JS_ToString(ctx, val1); if (JS_IsException(val)) return -1; - p = JS_VALUE_GET_STRING(val); - len = p->len; - /* UTF32 buffer length is len minus the number of correct surrogates pairs */ - buf = js_malloc(ctx, sizeof(buf[0]) * max_int(len, 1)); - if (!buf) { - JS_FreeValue(ctx, val); - goto fail; - } - for(i = j = 0; i < len;) - buf[j++] = string_getc(p, &i); + len = to_utf32_buf(ctx, JS_VALUE_GET_STRING(val), pbuf); JS_FreeValue(ctx, val); - *pbuf = buf; - return j; - fail: - *pbuf = NULL; - return -1; + return len; } static JSValue JS_NewUTF32String(JSContext *ctx, const uint32_t *buf, int len) @@ -42809,38 +42948,23 @@ static JSValue JS_NewUTF32String(JSContext *ctx, const uint32_t *buf, int len) return JS_EXCEPTION; } -static int js_string_normalize1(JSContext *ctx, uint32_t **pout_buf, - JSValueConst val, - UnicodeNormalizationEnum n_type) -{ - int buf_len, out_len; - uint32_t *buf, *out_buf; - - buf_len = JS_ToUTF32String(ctx, &buf, val); - if (buf_len < 0) - return -1; - out_len = unicode_normalize(&out_buf, buf, buf_len, n_type, - ctx->rt, (DynBufReallocFunc *)js_realloc_rt); - js_free(ctx, buf); - if (out_len < 0) - return -1; - *pout_buf = out_buf; - return out_len; -} - -static JSValue js_string_normalize(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_string_normalize(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { const char *form, *p; size_t form_len; - int is_compat, out_len; + int is_compat, buf_len, out_len; UnicodeNormalizationEnum n_type; JSValue val; - uint32_t *out_buf; + uint32_t *buf, *out_buf; val = JS_ToStringCheckObject(ctx, this_val); if (JS_IsException(val)) return val; + buf_len = JS_ToUTF32String(ctx, &buf, val); + JS_FreeValue(ctx, val); + if (buf_len < 0) + return JS_EXCEPTION; if (argc == 0 || JS_IsUndefined(argv[0])) { n_type = UNICODE_NFC; @@ -42852,9 +42976,9 @@ static JSValue js_string_normalize(JSContext *ctx, JSValueConst this_val, if (p[0] != 'N' || p[1] != 'F') goto bad_form; p += 2; - is_compat = FALSE; + is_compat = false; if (*p == 'K') { - is_compat = TRUE; + is_compat = true; p++; } if (*p == 'C' || *p == 'D') { @@ -42866,14 +42990,15 @@ static JSValue js_string_normalize(JSContext *ctx, JSValueConst this_val, JS_FreeCString(ctx, form); JS_ThrowRangeError(ctx, "bad normalization form"); fail1: - JS_FreeValue(ctx, val); + js_free(ctx, buf); return JS_EXCEPTION; } JS_FreeCString(ctx, form); } - out_len = js_string_normalize1(ctx, &out_buf, val, n_type); - JS_FreeValue(ctx, val); + out_len = unicode_normalize(&out_buf, buf, buf_len, n_type, + ctx->rt, (DynBufReallocFunc *)js_realloc_rt); + js_free(ctx, buf); if (out_len < 0) return JS_EXCEPTION; val = JS_NewUTF32String(ctx, out_buf, out_len); @@ -42881,135 +43006,18 @@ static JSValue js_string_normalize(JSContext *ctx, JSValueConst this_val, return val; } -/* return < 0, 0 or > 0 */ -static int js_UTF32_compare(const uint32_t *buf1, int buf1_len, - const uint32_t *buf2, int buf2_len) -{ - int i, len, c, res; - len = min_int(buf1_len, buf2_len); - for(i = 0; i < len; i++) { - /* Note: range is limited so a subtraction is valid */ - c = buf1[i] - buf2[i]; - if (c != 0) - return c; - } - if (buf1_len == buf2_len) - res = 0; - else if (buf1_len < buf2_len) - res = -1; - else - res = 1; - return res; -} - -static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue a, b; - int cmp, a_len, b_len; - uint32_t *a_buf, *b_buf; - - a = JS_ToStringCheckObject(ctx, this_val); - if (JS_IsException(a)) - return JS_EXCEPTION; - b = JS_ToString(ctx, argv[0]); - if (JS_IsException(b)) { - JS_FreeValue(ctx, a); - return JS_EXCEPTION; - } - a_len = js_string_normalize1(ctx, &a_buf, a, UNICODE_NFC); - JS_FreeValue(ctx, a); - if (a_len < 0) { - JS_FreeValue(ctx, b); - return JS_EXCEPTION; - } - - b_len = js_string_normalize1(ctx, &b_buf, b, UNICODE_NFC); - JS_FreeValue(ctx, b); - if (b_len < 0) { - js_free(ctx, a_buf); - return JS_EXCEPTION; - } - cmp = js_UTF32_compare(a_buf, a_len, b_buf, b_len); - js_free(ctx, a_buf); - js_free(ctx, b_buf); - return JS_NewInt32(ctx, cmp); -} -#else /* CONFIG_ALL_UNICODE */ -static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue a, b; - int cmp; - - a = JS_ToStringCheckObject(ctx, this_val); - if (JS_IsException(a)) - return JS_EXCEPTION; - b = JS_ToString(ctx, argv[0]); - if (JS_IsException(b)) { - JS_FreeValue(ctx, a); - return JS_EXCEPTION; - } - cmp = js_string_compare(ctx, JS_VALUE_GET_STRING(a), JS_VALUE_GET_STRING(b)); - JS_FreeValue(ctx, a); - JS_FreeValue(ctx, b); - return JS_NewInt32(ctx, cmp); -} -#endif /* !CONFIG_ALL_UNICODE */ - /* also used for String.prototype.valueOf */ -static JSValue js_string_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_string_toString(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { return js_thisStringValue(ctx, this_val); } -#if 0 -static JSValue js_string___toStringCheckObject(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_ToStringCheckObject(ctx, argv[0]); -} - -static JSValue js_string___toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_ToString(ctx, argv[0]); -} - -static JSValue js_string___advanceStringIndex(JSContext *ctx, JSValueConst - this_val, - int argc, JSValueConst *argv) -{ - JSValue str; - int idx; - BOOL is_unicode; - JSString *p; - - str = JS_ToString(ctx, argv[0]); - if (JS_IsException(str)) - return str; - if (JS_ToInt32Sat(ctx, &idx, argv[1])) { - JS_FreeValue(ctx, str); - return JS_EXCEPTION; - } - is_unicode = JS_ToBool(ctx, argv[2]); - p = JS_VALUE_GET_STRING(str); - if (!is_unicode || (unsigned)idx >= p->len || !p->is_wide_char) { - idx++; - } else { - string_getc(p, &idx); - } - JS_FreeValue(ctx, str); - return JS_NewInt32(ctx, idx); -} -#endif - /* String Iterator */ -static JSValue js_string_iterator_next(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, - BOOL *pdone, int magic) +static JSValue js_string_iterator_next(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, + int *pdone, int magic) { JSArrayIteratorData *it; uint32_t idx, c, start; @@ -43017,7 +43025,7 @@ static JSValue js_string_iterator_next(JSContext *ctx, JSValueConst this_val, it = JS_GetOpaque2(ctx, this_val, JS_CLASS_STRING_ITERATOR); if (!it) { - *pdone = FALSE; + *pdone = false; return JS_EXCEPTION; } if (JS_IsUndefined(it->obj)) @@ -43028,18 +43036,18 @@ static JSValue js_string_iterator_next(JSContext *ctx, JSValueConst this_val, JS_FreeValue(ctx, it->obj); it->obj = JS_UNDEFINED; done: - *pdone = TRUE; + *pdone = true; return JS_UNDEFINED; } start = idx; c = string_getc(p, (int *)&idx); it->idx = idx; - *pdone = FALSE; + *pdone = false; if (c <= 0xffff) { return js_new_string_char(ctx, c); } else { - return js_new_string16(ctx, p->u.str16 + start, 2); + return js_new_string16_len(ctx, p->u.str16 + start, 2); } } @@ -43060,8 +43068,8 @@ enum { magic_string_sup, }; -static JSValue js_string_CreateHTML(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) +static JSValue js_string_CreateHTML(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { JSValue str; const JSString *p; @@ -43118,18 +43126,13 @@ static const JSCFunctionListEntry js_string_funcs[] = { JS_CFUNC_DEF("fromCharCode", 1, js_string_fromCharCode ), JS_CFUNC_DEF("fromCodePoint", 1, js_string_fromCodePoint ), JS_CFUNC_DEF("raw", 1, js_string_raw ), - //JS_CFUNC_DEF("__toString", 1, js_string___toString ), - //JS_CFUNC_DEF("__isSpace", 1, js_string___isSpace ), - //JS_CFUNC_DEF("__toStringCheckObject", 1, js_string___toStringCheckObject ), - //JS_CFUNC_DEF("__advanceStringIndex", 3, js_string___advanceStringIndex ), - //JS_CFUNC_DEF("__GetSubstitution", 6, js_string___GetSubstitution ), }; static const JSCFunctionListEntry js_string_proto_funcs[] = { JS_PROP_INT32_DEF("length", 0, JS_PROP_CONFIGURABLE ), - JS_CFUNC_MAGIC_DEF("at", 1, js_string_charAt, 1 ), + JS_CFUNC_DEF("at", 1, js_string_at ), JS_CFUNC_DEF("charCodeAt", 1, js_string_charCodeAt ), - JS_CFUNC_MAGIC_DEF("charAt", 1, js_string_charAt, 0 ), + JS_CFUNC_DEF("charAt", 1, js_string_charAt ), JS_CFUNC_DEF("concat", 1, js_string_concat ), JS_CFUNC_DEF("codePointAt", 1, js_string_codePointAt ), JS_CFUNC_DEF("isWellFormed", 0, js_string_isWellFormed ), @@ -43158,8 +43161,8 @@ static const JSCFunctionListEntry js_string_proto_funcs[] = { JS_ALIAS_DEF("trimLeft", "trimStart" ), JS_CFUNC_DEF("toString", 0, js_string_toString ), JS_CFUNC_DEF("valueOf", 0, js_string_toString ), - JS_CFUNC_DEF("__quote", 1, js_string___quote ), JS_CFUNC_DEF("localeCompare", 1, js_string_localeCompare ), + JS_CFUNC_DEF("normalize", 0, js_string_normalize ), JS_CFUNC_MAGIC_DEF("toLowerCase", 0, js_string_toLowerCase, 1 ), JS_CFUNC_MAGIC_DEF("toUpperCase", 0, js_string_toLowerCase, 0 ), JS_CFUNC_MAGIC_DEF("toLocaleLowerCase", 0, js_string_toLowerCase, 1 ), @@ -43186,19 +43189,6 @@ static const JSCFunctionListEntry js_string_iterator_proto_funcs[] = { JS_PROP_STRING_DEF("[Symbol.toStringTag]", "String Iterator", JS_PROP_CONFIGURABLE ), }; -#ifdef CONFIG_ALL_UNICODE -static const JSCFunctionListEntry js_string_proto_normalize[] = { - JS_CFUNC_DEF("normalize", 0, js_string_normalize ), -}; -#endif - -void JS_AddIntrinsicStringNormalize(JSContext *ctx) -{ -#ifdef CONFIG_ALL_UNICODE - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING], js_string_proto_normalize, - countof(js_string_proto_normalize)); -#endif -} /* Math */ @@ -43230,16 +43220,16 @@ static double js_fmax(double a, double b) } } -static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) +static JSValue js_math_min_max(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { - BOOL is_max = magic; + bool is_max = magic; double r, a; int i; uint32_t tag; if (unlikely(argc == 0)) { - return __JS_NewFloat64(ctx, is_max ? INFINITY : -INFINITY); + return js_float64(is_max ? NEG_INF : INF); } tag = JS_VALUE_GET_TAG(argv[0]); @@ -43258,7 +43248,7 @@ static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val, r1 = min_int(r1, a1); } - return JS_NewInt32(ctx, r1); + return js_int32(r1); } else { if (JS_ToFloat64(ctx, &r, argv[0])) return JS_EXCEPTION; @@ -43279,7 +43269,7 @@ static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val, } i++; } - return JS_NewFloat64(ctx, r); + return js_number(r); } } @@ -43321,8 +43311,8 @@ static double js_math_round(double a) return u.d; } -static JSValue js_math_hypot(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_math_hypot(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { double r, a; int i; @@ -43342,7 +43332,12 @@ static JSValue js_math_hypot(JSContext *ctx, JSValueConst this_val, } } } - return JS_NewFloat64(ctx, r); + return js_float64(r); +} + +static double js_math_f16round(double a) +{ + return fromfp16(tofp16(a)); } static double js_math_fround(double a) @@ -43350,8 +43345,8 @@ static double js_math_fround(double a) return (float)a; } -static JSValue js_math_imul(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_math_imul(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { uint32_t a, b, c; int32_t d; @@ -43362,11 +43357,11 @@ static JSValue js_math_imul(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; c = a * b; memcpy(&d, &c, sizeof(d)); - return JS_NewInt32(ctx, d); + return js_int32(d); } -static JSValue js_math_clz32(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_math_clz32(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { uint32_t a, r; @@ -43376,7 +43371,65 @@ static JSValue js_math_clz32(JSContext *ctx, JSValueConst this_val, r = 32; else r = clz32(a); - return JS_NewInt32(ctx, r); + return js_int32(r); +} + +static JSValue js_math_sumPrecise(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + JSValue iter, next, item, ret; + bf_t a, b; + int done; + double d; + int r; + + iter = JS_GetIterator(ctx, argv[0], /*async*/false); + if (JS_IsException(iter)) + return JS_EXCEPTION; + bf_init(ctx->bf_ctx, &a); + bf_init(ctx->bf_ctx, &b); + ret = JS_EXCEPTION; + next = JS_GetProperty(ctx, iter, JS_ATOM_next); + if (JS_IsException(next)) + goto fail; + bf_set_zero(&a, /*is_neg*/true); + for (;;) { + item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done); + if (JS_IsException(item)) + goto fail; + if (done) + break; // item == JS_UNDEFINED + switch (JS_VALUE_GET_TAG(item)) { + default: + JS_FreeValue(ctx, item); + JS_ThrowTypeError(ctx, "not a number"); + goto fail; + case JS_TAG_INT: + d = JS_VALUE_GET_INT(item); + break; + case JS_TAG_FLOAT64: + d = JS_VALUE_GET_FLOAT64(item); + break; + } + if (bf_set_float64(&b, d)) + goto oom; + // Infinity + -Infinity results in BF_ST_INVALID_OP, sets |a| to nan + if ((r = bf_add(&a, &a, &b, BF_PREC_INF, BF_RNDN))) + if (r != BF_ST_INVALID_OP) + goto oom; + } + bf_get_float64(&a, &d, BF_RNDN); // return value deliberately ignored + ret = js_float64(d); +fail: + JS_IteratorClose(ctx, iter, JS_IsException(ret)); + JS_FreeValue(ctx, iter); + JS_FreeValue(ctx, next); + bf_delete(&a); + bf_delete(&b); + return ret; +oom: + JS_ThrowOutOfMemory(ctx); + goto fail; } /* xorshift* random number generator by Marsaglia */ @@ -43393,20 +43446,14 @@ static uint64_t xorshift64star(uint64_t *pstate) static void js_random_init(JSContext *ctx) { -#ifdef _MSC_VER - ctx->random_state = time(NULL); -#else - struct timeval tv; - gettimeofday(&tv, NULL); - ctx->random_state = ((int64_t)tv.tv_sec * 1000000) + tv.tv_usec; -#endif + ctx->random_state = js__gettimeofday_us(); /* the state must be non zero */ if (ctx->random_state == 0) ctx->random_state = 1; } -static JSValue js_math_random(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_math_random(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSFloat64Union u; uint64_t v; @@ -43414,53 +43461,79 @@ static JSValue js_math_random(JSContext *ctx, JSValueConst this_val, v = xorshift64star(&ctx->random_state); /* 1.0 <= u.d < 2 */ u.u64 = ((uint64_t)0x3ff << 52) | (v >> 12); - return __JS_NewFloat64(ctx, u.d - 1.0); + return js_float64(u.d - 1.0); } -// MSVC inexplicably refuses to initialize the array below with -// these functions, so use wrappers. -static double floorWrapper(double x) { return floor(x); } -static double ceilWrapper(double x) { return ceil(x); } -static double log2Wrapper(double x) { return log2(x); } +/* use local wrappers for math functions to + - avoid initializing data with dynamic library entry points. + - avoid some overhead if the call can be inlined at compile or link time. + */ +static double js_math_fabs(double d) { return fabs(d); } +static double js_math_floor(double d) { return floor(d); } +static double js_math_ceil(double d) { return ceil(d); } +static double js_math_sqrt(double d) { return sqrt(d); } +static double js_math_acos(double d) { return acos(d); } +static double js_math_asin(double d) { return asin(d); } +static double js_math_atan(double d) { return atan(d); } +static double js_math_atan2(double a, double b) { return atan2(a, b); } +static double js_math_cos(double d) { return cos(d); } +static double js_math_exp(double d) { return exp(d); } +static double js_math_log(double d) { return log(d); } +static double js_math_sin(double d) { return sin(d); } +static double js_math_tan(double d) { return tan(d); } +static double js_math_trunc(double d) { return trunc(d); } +static double js_math_cosh(double d) { return cosh(d); } +static double js_math_sinh(double d) { return sinh(d); } +static double js_math_tanh(double d) { return tanh(d); } +static double js_math_acosh(double d) { return acosh(d); } +static double js_math_asinh(double d) { return asinh(d); } +static double js_math_atanh(double d) { return atanh(d); } +static double js_math_expm1(double d) { return expm1(d); } +static double js_math_log1p(double d) { return log1p(d); } +static double js_math_log2(double d) { return log2(d); } +static double js_math_log10(double d) { return log10(d); } +static double js_math_cbrt(double d) { return cbrt(d); } static const JSCFunctionListEntry js_math_funcs[] = { JS_CFUNC_MAGIC_DEF("min", 2, js_math_min_max, 0 ), JS_CFUNC_MAGIC_DEF("max", 2, js_math_min_max, 1 ), - JS_CFUNC_SPECIAL_DEF("abs", 1, f_f, fabs ), - JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, floorWrapper ), - JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, ceilWrapper ), + JS_CFUNC_SPECIAL_DEF("abs", 1, f_f, js_math_fabs ), + JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, js_math_floor ), + JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, js_math_ceil ), JS_CFUNC_SPECIAL_DEF("round", 1, f_f, js_math_round ), - JS_CFUNC_SPECIAL_DEF("sqrt", 1, f_f, sqrt ), - - JS_CFUNC_SPECIAL_DEF("acos", 1, f_f, acos ), - JS_CFUNC_SPECIAL_DEF("asin", 1, f_f, asin ), - JS_CFUNC_SPECIAL_DEF("atan", 1, f_f, atan ), - JS_CFUNC_SPECIAL_DEF("atan2", 2, f_f_f, atan2 ), - JS_CFUNC_SPECIAL_DEF("cos", 1, f_f, cos ), - JS_CFUNC_SPECIAL_DEF("exp", 1, f_f, exp ), - JS_CFUNC_SPECIAL_DEF("log", 1, f_f, log ), - JS_CFUNC_SPECIAL_DEF("pow", 2, f_f_f, js_pow ), - JS_CFUNC_SPECIAL_DEF("sin", 1, f_f, sin ), - JS_CFUNC_SPECIAL_DEF("tan", 1, f_f, tan ), + JS_CFUNC_SPECIAL_DEF("sqrt", 1, f_f, js_math_sqrt ), + + JS_CFUNC_SPECIAL_DEF("acos", 1, f_f, js_math_acos ), + JS_CFUNC_SPECIAL_DEF("asin", 1, f_f, js_math_asin ), + JS_CFUNC_SPECIAL_DEF("atan", 1, f_f, js_math_atan ), + JS_CFUNC_SPECIAL_DEF("atan2", 2, f_f_f, js_math_atan2 ), + JS_CFUNC_SPECIAL_DEF("cos", 1, f_f, js_math_cos ), + JS_CFUNC_SPECIAL_DEF("exp", 1, f_f, js_math_exp ), + JS_CFUNC_SPECIAL_DEF("log", 1, f_f, js_math_log ), + JS_CFUNC_SPECIAL_DEF("pow", 2, f_f_f, js_math_pow ), + JS_CFUNC_SPECIAL_DEF("sin", 1, f_f, js_math_sin ), + JS_CFUNC_SPECIAL_DEF("tan", 1, f_f, js_math_tan ), /* ES6 */ - JS_CFUNC_SPECIAL_DEF("trunc", 1, f_f, trunc ), + JS_CFUNC_SPECIAL_DEF("trunc", 1, f_f, js_math_trunc ), JS_CFUNC_SPECIAL_DEF("sign", 1, f_f, js_math_sign ), - JS_CFUNC_SPECIAL_DEF("cosh", 1, f_f, cosh ), - JS_CFUNC_SPECIAL_DEF("sinh", 1, f_f, sinh ), - JS_CFUNC_SPECIAL_DEF("tanh", 1, f_f, tanh ), - JS_CFUNC_SPECIAL_DEF("acosh", 1, f_f, acosh ), - JS_CFUNC_SPECIAL_DEF("asinh", 1, f_f, asinh ), - JS_CFUNC_SPECIAL_DEF("atanh", 1, f_f, atanh ), - JS_CFUNC_SPECIAL_DEF("expm1", 1, f_f, expm1 ), - JS_CFUNC_SPECIAL_DEF("log1p", 1, f_f, log1p ), - JS_CFUNC_SPECIAL_DEF("log2", 1, f_f, log2Wrapper ), - JS_CFUNC_SPECIAL_DEF("log10", 1, f_f, log10 ), - JS_CFUNC_SPECIAL_DEF("cbrt", 1, f_f, cbrt ), + JS_CFUNC_SPECIAL_DEF("cosh", 1, f_f, js_math_cosh ), + JS_CFUNC_SPECIAL_DEF("sinh", 1, f_f, js_math_sinh ), + JS_CFUNC_SPECIAL_DEF("tanh", 1, f_f, js_math_tanh ), + JS_CFUNC_SPECIAL_DEF("acosh", 1, f_f, js_math_acosh ), + JS_CFUNC_SPECIAL_DEF("asinh", 1, f_f, js_math_asinh ), + JS_CFUNC_SPECIAL_DEF("atanh", 1, f_f, js_math_atanh ), + JS_CFUNC_SPECIAL_DEF("expm1", 1, f_f, js_math_expm1 ), + JS_CFUNC_SPECIAL_DEF("log1p", 1, f_f, js_math_log1p ), + JS_CFUNC_SPECIAL_DEF("log2", 1, f_f, js_math_log2 ), + JS_CFUNC_SPECIAL_DEF("log10", 1, f_f, js_math_log10 ), + JS_CFUNC_SPECIAL_DEF("cbrt", 1, f_f, js_math_cbrt ), JS_CFUNC_DEF("hypot", 2, js_math_hypot ), JS_CFUNC_DEF("random", 0, js_math_random ), + JS_CFUNC_SPECIAL_DEF("f16round", 1, f_f, js_math_f16round ), JS_CFUNC_SPECIAL_DEF("fround", 1, f_f, js_math_fround ), JS_CFUNC_DEF("imul", 2, js_math_imul ), JS_CFUNC_DEF("clz32", 1, js_math_clz32 ), + JS_CFUNC_DEF("sumPrecise", 1, js_math_sumPrecise ), JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Math", JS_PROP_CONFIGURABLE ), JS_PROP_DOUBLE_DEF("E", 2.718281828459045, 0 ), JS_PROP_DOUBLE_DEF("LN10", 2.302585092994046, 0 ), @@ -43480,10 +43553,19 @@ static const JSCFunctionListEntry js_math_obj[] = { /* OS dependent. d = argv[0] is in ms from 1970. Return the difference between UTC time and local time 'd' in minutes */ -static int getTimezoneOffset(int64_t time) -{ +static int getTimezoneOffset(int64_t time) { +#if defined(_WIN32) + DWORD r; + TIME_ZONE_INFORMATION t; + r = GetTimeZoneInformation(&t); + if (r == TIME_ZONE_ID_INVALID) + return 0; + if (r == TIME_ZONE_ID_DAYLIGHT) + return (int)(t.Bias + t.DaylightBias); + return (int)t.Bias; +#else time_t ti; - int res; + struct tm tm; time /= 1000; /* convert to seconds */ if (sizeof(time_t) == 4) { @@ -43507,73 +43589,21 @@ static int getTimezoneOffset(int64_t time) } } ti = time; -#if defined(_WIN32) - { - struct tm *tm; - time_t gm_ti, loc_ti; + localtime_r(&ti, &tm); +#ifdef NO_TM_GMTOFF + struct tm gmt; + gmtime_r(&ti, &gmt); - tm = gmtime(&ti); - gm_ti = mktime(tm); + /* disable DST adjustment on the local tm struct */ + tm.tm_isdst = 0; - tm = localtime(&ti); - loc_ti = mktime(tm); - - res = (gm_ti - loc_ti) / 60; - } + return (int)difftime(mktime(&gmt), mktime(&tm)) / 60; #else - { - struct tm tm; - localtime_r(&ti, &tm); - res = -tm.tm_gmtoff / 60; - } + return -tm.tm_gmtoff / 60; +#endif /* NO_TM_GMTOFF */ #endif - return res; } -#if 0 -static JSValue js___date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - double dd; - - if (JS_ToFloat64(ctx, &dd, argv[0])) - return JS_EXCEPTION; - if (isnan(dd)) - return JS_NewFloat64(ctx, dd); - else - return JS_NewInt32(ctx, getTimezoneOffset((int64_t)dd)); -} - -static JSValue js_get_prototype_from_ctor(JSContext *ctx, JSValueConst ctor, - JSValueConst def_proto) -{ - JSValue proto; - proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype); - if (JS_IsException(proto)) - return proto; - if (!JS_IsObject(proto)) { - JS_FreeValue(ctx, proto); - proto = JS_DupValue(ctx, def_proto); - } - return proto; -} - -/* create a new date object */ -static JSValue js___date_create(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue obj, proto; - proto = js_get_prototype_from_ctor(ctx, argv[0], argv[1]); - if (JS_IsException(proto)) - return proto; - obj = JS_NewObjectProtoClass(ctx, proto, JS_CLASS_DATE); - JS_FreeValue(ctx, proto); - if (!JS_IsException(obj)) - JS_SetObjectData(ctx, obj, JS_DupValue(ctx, argv[2])); - return obj; -} -#endif - /* RegExp */ static void js_regexp_finalizer(JSRuntime *rt, JSValue val) @@ -43585,8 +43615,8 @@ static void js_regexp_finalizer(JSRuntime *rt, JSValue val) } /* create a string containing the RegExp bytecode */ -static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern, - JSValueConst flags) +static JSValue js_compile_regexp(JSContext *ctx, JSValue pattern, + JSValue flags) { const char *str; int re_flags, mask; @@ -43622,6 +43652,9 @@ static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern, case 'u': mask = LRE_FLAG_UNICODE; break; + case 'v': + mask = LRE_FLAG_UNICODE_SETS; + break; case 'y': mask = LRE_FLAG_STICKY; break; @@ -43638,6 +43671,10 @@ static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern, JS_FreeCString(ctx, str); } + if (re_flags & LRE_FLAG_UNICODE) + if (re_flags & LRE_FLAG_UNICODE_SETS) + return JS_ThrowSyntaxError(ctx, "invalid regular expression flags"); + str = JS_ToCStringLen2(ctx, &len, pattern, !(re_flags & LRE_FLAG_UNICODE)); if (!str) return JS_EXCEPTION; @@ -43649,14 +43686,14 @@ static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern, return JS_EXCEPTION; } - ret = js_new_string8(ctx, re_bytecode_buf, re_bytecode_len); + ret = js_new_string8_len(ctx, (char *)re_bytecode_buf, re_bytecode_len); js_free(ctx, re_bytecode_buf); return ret; } /* create a RegExp object from a string containing the RegExp bytecode and the source pattern */ -static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor, +static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValue ctor, JSValue pattern, JSValue bc) { JSValue obj; @@ -43680,12 +43717,12 @@ static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor, re = &p->u.regexp; re->pattern = JS_VALUE_GET_STRING(pattern); re->bytecode = JS_VALUE_GET_STRING(bc); - JS_DefinePropertyValue(ctx, obj, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0), + JS_DefinePropertyValue(ctx, obj, JS_ATOM_lastIndex, js_int32(0), JS_PROP_WRITABLE); return obj; } -static JSRegExp *js_get_regexp(JSContext *ctx, JSValueConst obj, BOOL throw_error) +static JSRegExp *js_get_regexp(JSContext *ctx, JSValue obj, bool throw_error) { if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { JSObject *p = JS_VALUE_GET_OBJ(obj); @@ -43698,26 +43735,26 @@ static JSRegExp *js_get_regexp(JSContext *ctx, JSValueConst obj, BOOL throw_erro return NULL; } -/* return < 0 if exception or TRUE/FALSE */ -static int js_is_regexp(JSContext *ctx, JSValueConst obj) +/* return < 0 if exception or true/false */ +static int js_is_regexp(JSContext *ctx, JSValue obj) { JSValue m; if (!JS_IsObject(obj)) - return FALSE; + return false; m = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_match); if (JS_IsException(m)) return -1; if (!JS_IsUndefined(m)) return JS_ToBoolFree(ctx, m); - return js_get_regexp(ctx, obj, FALSE) != NULL; + return js_get_regexp(ctx, obj, false) != NULL; } -static JSValue js_regexp_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) +static JSValue js_regexp_constructor(JSContext *ctx, JSValue new_target, + int argc, JSValue *argv) { JSValue pattern, flags, bc, val; - JSValueConst pat, flags1; + JSValue pat, flags1; JSRegExp *re; int pat_is_regexp; @@ -43731,21 +43768,21 @@ static JSValue js_regexp_constructor(JSContext *ctx, JSValueConst new_target, new_target = JS_GetActiveFunction(ctx); if (pat_is_regexp && JS_IsUndefined(flags1)) { JSValue ctor; - BOOL res; + bool res; ctor = JS_GetProperty(ctx, pat, JS_ATOM_constructor); if (JS_IsException(ctor)) return ctor; res = js_same_value(ctx, ctor, new_target); JS_FreeValue(ctx, ctor); if (res) - return JS_DupValue(ctx, pat); + return js_dup(pat); } } - re = js_get_regexp(ctx, pat, FALSE); + re = js_get_regexp(ctx, pat, false); if (re) { - pattern = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern)); + pattern = js_dup(JS_MKPTR(JS_TAG_STRING, re->pattern)); if (JS_IsUndefined(flags1)) { - bc = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->bytecode)); + bc = js_dup(JS_MKPTR(JS_TAG_STRING, re->bytecode)); goto no_compilation; } else { flags = JS_ToString(ctx, flags1); @@ -43763,11 +43800,11 @@ static JSValue js_regexp_constructor(JSContext *ctx, JSValueConst new_target, if (JS_IsException(flags)) goto fail; } else { - flags = JS_DupValue(ctx, flags1); + flags = js_dup(flags1); } } else { - pattern = JS_DupValue(ctx, pat); - flags = JS_DupValue(ctx, flags1); + pattern = js_dup(pat); + flags = js_dup(flags1); } if (JS_IsUndefined(pattern)) { pattern = JS_AtomToString(ctx, JS_ATOM_empty_string); @@ -43791,24 +43828,24 @@ static JSValue js_regexp_constructor(JSContext *ctx, JSValueConst new_target, return JS_EXCEPTION; } -static JSValue js_regexp_compile(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_regexp_compile(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSRegExp *re1, *re; - JSValueConst pattern1, flags1; + JSValue pattern1, flags1; JSValue bc, pattern; - re = js_get_regexp(ctx, this_val, TRUE); + re = js_get_regexp(ctx, this_val, true); if (!re) return JS_EXCEPTION; pattern1 = argv[0]; flags1 = argv[1]; - re1 = js_get_regexp(ctx, pattern1, FALSE); + re1 = js_get_regexp(ctx, pattern1, false); if (re1) { if (!JS_IsUndefined(flags1)) return JS_ThrowTypeError(ctx, "flags must be undefined"); - pattern = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re1->pattern)); - bc = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re1->bytecode)); + pattern = js_dup(JS_MKPTR(JS_TAG_STRING, re1->pattern)); + bc = js_dup(JS_MKPTR(JS_TAG_STRING, re1->bytecode)); } else { bc = JS_UNDEFINED; if (JS_IsUndefined(pattern1)) @@ -43826,37 +43863,16 @@ static JSValue js_regexp_compile(JSContext *ctx, JSValueConst this_val, re->pattern = JS_VALUE_GET_STRING(pattern); re->bytecode = JS_VALUE_GET_STRING(bc); if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex, - JS_NewInt32(ctx, 0)) < 0) + js_int32(0)) < 0) return JS_EXCEPTION; - return JS_DupValue(ctx, this_val); + return js_dup(this_val); fail: JS_FreeValue(ctx, pattern); JS_FreeValue(ctx, bc); return JS_EXCEPTION; } -#if 0 -static JSValue js_regexp_get___source(JSContext *ctx, JSValueConst this_val) -{ - JSRegExp *re = js_get_regexp(ctx, this_val, TRUE); - if (!re) - return JS_EXCEPTION; - return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern)); -} - -static JSValue js_regexp_get___flags(JSContext *ctx, JSValueConst this_val) -{ - JSRegExp *re = js_get_regexp(ctx, this_val, TRUE); - int flags; - - if (!re) - return JS_EXCEPTION; - flags = lre_get_flags(re->bytecode->u.str8); - return JS_NewInt32(ctx, flags); -} -#endif - -static JSValue js_regexp_get_source(JSContext *ctx, JSValueConst this_val) +static JSValue js_regexp_get_source(JSContext *ctx, JSValue this_val) { JSRegExp *re; JSString *p; @@ -43869,7 +43885,7 @@ static JSValue js_regexp_get_source(JSContext *ctx, JSValueConst this_val) if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP])) goto empty_regex; - re = js_get_regexp(ctx, this_val, TRUE); + re = js_get_regexp(ctx, this_val, true); if (!re) return JS_EXCEPTION; @@ -43877,7 +43893,7 @@ static JSValue js_regexp_get_source(JSContext *ctx, JSValueConst this_val) if (p->len == 0) { empty_regex: - return JS_NewString(ctx, "(?:)"); + return js_new_string8(ctx, "(?:)"); } string_buffer_init2(ctx, b, p->len, p->is_wide_char); @@ -43922,7 +43938,7 @@ static JSValue js_regexp_get_source(JSContext *ctx, JSValueConst this_val) return string_buffer_end(b); } -static JSValue js_regexp_get_flag(JSContext *ctx, JSValueConst this_val, int mask) +static JSValue js_regexp_get_flag(JSContext *ctx, JSValue this_val, int mask) { JSRegExp *re; int flags; @@ -43930,7 +43946,7 @@ static JSValue js_regexp_get_flag(JSContext *ctx, JSValueConst this_val, int mas if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT) return JS_ThrowTypeErrorNotAnObject(ctx); - re = js_get_regexp(ctx, this_val, FALSE); + re = js_get_regexp(ctx, this_val, false); if (!re) { if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP])) return JS_UNDEFINED; @@ -43939,10 +43955,10 @@ static JSValue js_regexp_get_flag(JSContext *ctx, JSValueConst this_val, int mas } flags = lre_get_flags(re->bytecode->u.str8); - return JS_NewBool(ctx, flags & mask); + return js_bool(flags & mask); } -static JSValue js_regexp_get_flags(JSContext *ctx, JSValueConst this_val) +static JSValue js_regexp_get_flags(JSContext *ctx, JSValue this_val) { char str[8], *p = str; int res; @@ -43980,19 +43996,26 @@ static JSValue js_regexp_get_flags(JSContext *ctx, JSValueConst this_val) goto exception; if (res) *p++ = 'u'; + res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "unicodeSets")); + if (res < 0) + goto exception; + if (res) + *p++ = 'v'; res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "sticky")); if (res < 0) goto exception; if (res) *p++ = 'y'; - return JS_NewStringLen(ctx, str, p - str); + if (p == str) + return JS_AtomToString(ctx, JS_ATOM_empty_string); + return js_new_string8_len(ctx, str, p - str); exception: return JS_EXCEPTION; } -static JSValue js_regexp_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_regexp_toString(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue pattern, flags; StringBuffer b_s, *b = &b_s; @@ -44016,7 +44039,7 @@ static JSValue js_regexp_toString(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size) +bool lre_check_stack_overflow(void *opaque, size_t alloca_size) { JSContext *ctx = opaque; return js_check_stack_overflow(ctx->rt, alloca_size); @@ -44029,10 +44052,57 @@ void *lre_realloc(void *opaque, void *ptr, size_t size) return js_realloc_rt(ctx->rt, ptr, size); } -static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_regexp_escape(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + StringBuffer b_s, *b = &b_s; + JSString *p; + uint32_t c, i; + char s[16]; + + if (!JS_IsString(argv[0])) + return JS_ThrowTypeError(ctx, "not a string"); + p = JS_VALUE_GET_STRING(argv[0]); + string_buffer_init2(ctx, b, 0, p->is_wide_char); + for (i = 0; i < p->len; i++) { + c = p->is_wide_char ? (uint32_t)p->u.str16[i] : (uint32_t)p->u.str8[i]; + if (c < 33) { + if (c >= 9 && c <= 13) { + string_buffer_putc8(b, '\\'); + string_buffer_putc8(b, "tnvfr"[c - 9]); + } else { + goto hex2; + } + } else if (c < 128) { + if ((c >= '0' && c <= '9') + || (c >= 'A' && c <= 'Z') + || (c >= 'a' && c <= 'z')) { + if (i == 0) + goto hex2; + } else if (strchr(",-=<>#&!%:;@~'`\"", c)) { + goto hex2; + } else if (c != '_') { + string_buffer_putc8(b, '\\'); + } + string_buffer_putc8(b, c); + } else if (c < 256) { + hex2: + snprintf(s, sizeof(s), "\\x%02x", c); + string_buffer_puts8(b, s); + } else if (is_surrogate(c) || lre_is_white_space(c) || c == 0xFEFF) { + snprintf(s, sizeof(s), "\\u%04x", c); + string_buffer_puts8(b, s); + } else { + string_buffer_putc16(b, c); + } + } + return string_buffer_end(b); +} + +static JSValue js_regexp_exec(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - JSRegExp *re = js_get_regexp(ctx, this_val, TRUE); + JSRegExp *re = js_get_regexp(ctx, this_val, true); JSString *str; JSValue t, ret, str_val, obj, val, groups; JSValue indices, indices_groups; @@ -44085,7 +44155,7 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val, if (rc >= 0) { if (rc == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) { if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex, - JS_NewInt32(ctx, 0)) < 0) + js_int32(0)) < 0) goto fail; } } else { @@ -44096,7 +44166,7 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val, int prop_flags; if (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) { if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex, - JS_NewInt32(ctx, (capture[1] - str_buf) >> shift)) < 0) + js_int32((capture[1] - str_buf) >> shift)) < 0) goto fail; } obj = JS_NewArray(ctx); @@ -44125,7 +44195,6 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val, uint8_t **match = &capture[2 * i]; int start = -1; int end = -1; - JSValue val; if (group_name_ptr && i > 0) { if (*group_name_ptr) name = group_name_ptr; @@ -44138,26 +44207,26 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val, } if (!JS_IsUndefined(indices)) { - val = JS_UNDEFINED; + JSValue val = JS_UNDEFINED; if (start != -1) { val = JS_NewArray(ctx); if (JS_IsException(val)) goto fail; if (JS_DefinePropertyValueUint32(ctx, val, 0, - JS_NewInt32(ctx, start), + js_int32(start), prop_flags) < 0) { JS_FreeValue(ctx, val); goto fail; } if (JS_DefinePropertyValueUint32(ctx, val, 1, - JS_NewInt32(ctx, end), + js_int32(end), prop_flags) < 0) { JS_FreeValue(ctx, val); goto fail; } } if (name && !JS_IsUndefined(indices_groups)) { - val = JS_DupValue(ctx, val); + val = js_dup(val); if (JS_DefinePropertyValueStr(ctx, indices_groups, name, val, prop_flags) < 0) { JS_FreeValue(ctx, val); @@ -44170,7 +44239,7 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val, } } - val = JS_UNDEFINED; + JSValue val = JS_UNDEFINED; if (start != -1) { val = js_sub_string(ctx, str, start, end); if (JS_IsException(val)) @@ -44179,7 +44248,7 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val, if (name) { if (JS_DefinePropertyValueStr(ctx, groups, name, - JS_DupValue(ctx, val), + js_dup(val), prop_flags) < 0) { JS_FreeValue(ctx, val); goto fail; @@ -44196,7 +44265,7 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val, goto fail; } - t = JS_NewInt32(ctx, (capture[0] - str_buf) >> shift); + t = js_int32((capture[0] - str_buf) >> shift); if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_index, t, prop_flags) < 0) goto fail; @@ -44230,9 +44299,9 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val, } /* delete portions of a string that match a given regex */ -static JSValue JS_RegExpDelete(JSContext *ctx, JSValueConst this_val, JSValueConst arg) +static JSValue JS_RegExpDelete(JSContext *ctx, JSValue this_val, JSValue arg) { - JSRegExp *re = js_get_regexp(ctx, this_val, TRUE); + JSRegExp *re = js_get_regexp(ctx, this_val, true); JSString *str; JSValue str_val, val; uint8_t *re_bytecode; @@ -44281,7 +44350,7 @@ static JSValue JS_RegExpDelete(JSContext *ctx, JSValueConst this_val, JSValueCon if (ret >= 0) { if (ret == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) { if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex, - JS_NewInt32(ctx, 0)) < 0) + js_int32(0)) < 0) goto fail; } } else { @@ -44300,7 +44369,7 @@ static JSValue JS_RegExpDelete(JSContext *ctx, JSValueConst this_val, JSValueCon next_src_pos = end; if (!(re_flags & LRE_FLAG_GLOBAL)) { if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex, - JS_NewInt32(ctx, end)) < 0) + js_int32(end)) < 0) goto fail; break; } @@ -44325,7 +44394,7 @@ static JSValue JS_RegExpDelete(JSContext *ctx, JSValueConst this_val, JSValueCon return JS_EXCEPTION; } -static JSValue JS_RegExpExec(JSContext *ctx, JSValueConst r, JSValueConst s) +static JSValue JS_RegExpExec(JSContext *ctx, JSValue r, JSValue s) { JSValue method, ret; @@ -44346,38 +44415,25 @@ static JSValue JS_RegExpExec(JSContext *ctx, JSValueConst r, JSValueConst s) return js_regexp_exec(ctx, r, 1, &s); } -#if 0 -static JSValue js_regexp___RegExpExec(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_RegExpExec(ctx, argv[0], argv[1]); -} -static JSValue js_regexp___RegExpDelete(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_RegExpDelete(ctx, argv[0], argv[1]); -} -#endif - -static JSValue js_regexp_test(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_regexp_test(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue val; - BOOL ret; + bool ret; val = JS_RegExpExec(ctx, this_val, argv[0]); if (JS_IsException(val)) return JS_EXCEPTION; ret = !JS_IsNull(val); JS_FreeValue(ctx, val); - return JS_NewBool(ctx, ret); + return js_bool(ret); } -static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { // [Symbol.match](str) - JSValueConst rx = this_val; + JSValue rx = this_val; JSValue A, S, flags, result, matchStr; int global, n, fullUnicode, isEmpty; JSString *p; @@ -44410,7 +44466,7 @@ static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val, if (fullUnicode < 0) goto exception; - if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0) + if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, js_int32(0)) < 0) goto exception; A = JS_NewArray(ctx); if (JS_IsException(A)) @@ -44436,7 +44492,7 @@ static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val, goto exception; p = JS_VALUE_GET_STRING(S); nextIndex = string_advance_index(p, thisIndex, fullUnicode); - if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0) + if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, js_int64(nextIndex)) < 0) goto exception; } } @@ -44461,9 +44517,9 @@ static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val, typedef struct JSRegExpStringIteratorData { JSValue iterating_regexp; JSValue iterated_string; - BOOL global; - BOOL unicode; - BOOL done; + bool global; + bool unicode; + int done; } JSRegExpStringIteratorData; static void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val) @@ -44477,7 +44533,7 @@ static void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val) } } -static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val, +static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); @@ -44489,12 +44545,12 @@ static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val, } static JSValue js_regexp_string_iterator_next(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv, - BOOL *pdone, int magic) + JSValue this_val, + int argc, JSValue *argv, + int *pdone, int magic) { JSRegExpStringIteratorData *it; - JSValueConst R, S; + JSValue R, S; JSValue matchStr = JS_UNDEFINED, match = JS_UNDEFINED; JSString *sp; @@ -44502,7 +44558,7 @@ static JSValue js_regexp_string_iterator_next(JSContext *ctx, if (!it) goto exception; if (it->done) { - *pdone = TRUE; + *pdone = true; return JS_UNDEFINED; } R = it->iterating_regexp; @@ -44511,8 +44567,8 @@ static JSValue js_regexp_string_iterator_next(JSContext *ctx, if (JS_IsException(match)) goto exception; if (JS_IsNull(match)) { - it->done = TRUE; - *pdone = TRUE; + it->done = true; + *pdone = true; return JS_UNDEFINED; } else if (it->global) { matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, match, 0)); @@ -44525,30 +44581,29 @@ static JSValue js_regexp_string_iterator_next(JSContext *ctx, goto exception; sp = JS_VALUE_GET_STRING(S); nextIndex = string_advance_index(sp, thisIndex, it->unicode); - if (JS_SetProperty(ctx, R, JS_ATOM_lastIndex, - JS_NewInt64(ctx, nextIndex)) < 0) + if (JS_SetProperty(ctx, R, JS_ATOM_lastIndex, js_int64(nextIndex)) < 0) goto exception; } JS_FreeValue(ctx, matchStr); } else { - it->done = TRUE; + it->done = true; } - *pdone = FALSE; + *pdone = false; return match; exception: JS_FreeValue(ctx, match); JS_FreeValue(ctx, matchStr); - *pdone = FALSE; + *pdone = false; return JS_EXCEPTION; } -static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { // [Symbol.matchAll](str) - JSValueConst R = this_val; + JSValue R = this_val; JSValue S, C, flags, matcher, iter; - JSValueConst args[2]; + JSValue args[2]; JSString *strp; int64_t lastIndex; JSRegExpStringIteratorData *it; @@ -44578,8 +44633,7 @@ static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val, if (JS_ToLengthFree(ctx, &lastIndex, JS_GetProperty(ctx, R, JS_ATOM_lastIndex))) goto exception; - if (JS_SetProperty(ctx, matcher, JS_ATOM_lastIndex, - JS_NewInt64(ctx, lastIndex)) < 0) + if (JS_SetProperty(ctx, matcher, JS_ATOM_lastIndex, js_int64(lastIndex)) < 0) goto exception; iter = JS_NewObjectClass(ctx, JS_CLASS_REGEXP_STRING_ITERATOR); @@ -44593,8 +44647,8 @@ static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val, strp = JS_VALUE_GET_STRING(flags); it->global = string_indexof_char(strp, 'g', 0) >= 0; it->unicode = string_indexof_char(strp, 'u', 0) >= 0; - it->done = FALSE; - JS_SetOpaque(iter, it); + it->done = false; + JS_SetOpaqueInternal(iter, it); JS_FreeValue(ctx, C); JS_FreeValue(ctx, flags); @@ -44668,7 +44722,7 @@ static int value_buffer_append(ValueBuffer *b, JSValue val) return 0; } -static int js_is_standard_regexp(JSContext *ctx, JSValueConst rx) +static int js_is_standard_regexp(JSContext *ctx, JSValue rx) { JSValue val; int res; @@ -44690,12 +44744,12 @@ static int js_is_standard_regexp(JSContext *ctx, JSValueConst rx) return res; } -static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { // [Symbol.replace](str, rep) - JSValueConst rx = this_val, rep = argv[1]; - JSValueConst args[6]; + JSValue rx = this_val, rep = argv[1]; + JSValue args[6]; JSValue flags, str, rep_val, matched, tab, rep_str, namedCaptures, res; JSString *p, *sp, *rp; StringBuffer b_s, *b = &b_s; @@ -44746,7 +44800,7 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val, fullUnicode = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_unicode)); if (fullUnicode < 0) goto exception; - if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0) + if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, js_int32(0)) < 0) goto exception; } @@ -44776,13 +44830,13 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val, if (JS_ToLengthFree(ctx, &thisIndex, JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0) goto exception; nextIndex = string_advance_index(sp, thisIndex, fullUnicode); - if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0) + if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, js_int64(nextIndex)) < 0) goto exception; } } nextSourcePosition = 0; for(j = 0; j < results->len; j++) { - JSValueConst result; + JSValue result; result = results->arr[j]; if (js_get_length32(ctx, &nCaptures, result) < 0) goto exception; @@ -44802,7 +44856,7 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val, tab = JS_NewArray(ctx); if (JS_IsException(tab)) goto exception; - if (JS_DefinePropertyValueInt64(ctx, tab, 0, JS_DupValue(ctx, matched), + if (JS_DefinePropertyValueInt64(ctx, tab, 0, js_dup(matched), JS_PROP_C_W_E | JS_PROP_THROW) < 0) goto exception; for(n = 1; n < nCaptures; n++) { @@ -44824,12 +44878,12 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val, if (JS_IsException(namedCaptures)) goto exception; if (functionalReplace) { - if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_NewInt32(ctx, position), JS_PROP_C_W_E | JS_PROP_THROW) < 0) + if (JS_DefinePropertyValueInt64(ctx, tab, n++, js_int32(position), JS_PROP_C_W_E | JS_PROP_THROW) < 0) goto exception; - if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, str), JS_PROP_C_W_E | JS_PROP_THROW) < 0) + if (JS_DefinePropertyValueInt64(ctx, tab, n++, js_dup(str), JS_PROP_C_W_E | JS_PROP_THROW) < 0) goto exception; if (!JS_IsUndefined(namedCaptures)) { - if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, namedCaptures), JS_PROP_C_W_E | JS_PROP_THROW) < 0) + if (JS_DefinePropertyValueInt64(ctx, tab, n++, js_dup(namedCaptures), JS_PROP_C_W_E | JS_PROP_THROW) < 0) goto exception; } args[0] = JS_UNDEFINED; @@ -44847,7 +44901,7 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val, } args[0] = matched; args[1] = str; - args[2] = JS_NewInt32(ctx, position); + args[2] = js_int32(position); args[3] = tab; args[4] = namedCaptures1; args[5] = rep_val; @@ -44883,10 +44937,10 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val, return res; } -static JSValue js_regexp_Symbol_search(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_regexp_Symbol_search(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - JSValueConst rx = this_val; + JSValue rx = this_val; JSValue str, previousLastIndex, currentLastIndex, result, index; if (!JS_IsObject(rx)) @@ -44903,8 +44957,8 @@ static JSValue js_regexp_Symbol_search(JSContext *ctx, JSValueConst this_val, if (JS_IsException(previousLastIndex)) goto exception; - if (!js_same_value(ctx, previousLastIndex, JS_NewInt32(ctx, 0))) { - if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0) { + if (!js_same_value(ctx, previousLastIndex, js_int32(0))) { + if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, js_int32(0)) < 0) { goto exception; } } @@ -44926,7 +44980,7 @@ static JSValue js_regexp_Symbol_search(JSContext *ctx, JSValueConst this_val, JS_FreeValue(ctx, currentLastIndex); if (JS_IsNull(result)) { - return JS_NewInt32(ctx, -1); + return js_int32(-1); } else { index = JS_GetProperty(ctx, result, JS_ATOM_index); JS_FreeValue(ctx, result); @@ -44941,12 +44995,12 @@ static JSValue js_regexp_Symbol_search(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { // [Symbol.split](str, limit) - JSValueConst rx = this_val; - JSValueConst args[2]; + JSValue rx = this_val; + JSValue args[2]; JSValue str, ctor, splitter, A, flags, z, sub; JSString *strp; uint32_t lim, size, p, q; @@ -45006,7 +45060,7 @@ static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val, goto done; } while (q < size) { - if (JS_SetProperty(ctx, splitter, JS_ATOM_lastIndex, JS_NewInt32(ctx, q)) < 0) + if (JS_SetProperty(ctx, splitter, JS_ATOM_lastIndex, js_int32(q)) < 0) goto exception; JS_FreeValue(ctx, z); z = JS_RegExpExec(ctx, splitter, str); @@ -45034,9 +45088,14 @@ static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val, if (js_get_length64(ctx, &numberOfCaptures, z)) goto exception; for(i = 1; i < numberOfCaptures; i++) { - sub = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, z, i)); + sub = JS_GetPropertyInt64(ctx, z, i); if (JS_IsException(sub)) goto exception; + if (!JS_IsUndefined(sub)) { + sub = JS_ToStringFree(ctx, sub); + if (JS_IsException(sub)) + goto exception; + } if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0) goto exception; if (lengthA == lim) @@ -45068,9 +45127,8 @@ static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val, } static const JSCFunctionListEntry js_regexp_funcs[] = { + JS_CFUNC_DEF("escape", 1, js_regexp_escape ), JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ), - //JS_CFUNC_DEF("__RegExpExec", 2, js_regexp___RegExpExec ), - //JS_CFUNC_DEF("__RegExpDelete", 2, js_regexp___RegExpDelete ), }; static const JSCFunctionListEntry js_regexp_proto_funcs[] = { @@ -45081,6 +45139,7 @@ static const JSCFunctionListEntry js_regexp_proto_funcs[] = { JS_CGETSET_MAGIC_DEF("multiline", js_regexp_get_flag, NULL, LRE_FLAG_MULTILINE ), JS_CGETSET_MAGIC_DEF("dotAll", js_regexp_get_flag, NULL, LRE_FLAG_DOTALL ), JS_CGETSET_MAGIC_DEF("unicode", js_regexp_get_flag, NULL, LRE_FLAG_UNICODE ), + JS_CGETSET_MAGIC_DEF("unicodeSets", js_regexp_get_flag, NULL, LRE_FLAG_UNICODE_SETS ), JS_CGETSET_MAGIC_DEF("sticky", js_regexp_get_flag, NULL, LRE_FLAG_STICKY ), JS_CGETSET_MAGIC_DEF("hasIndices", js_regexp_get_flag, NULL, LRE_FLAG_INDICES ), JS_CFUNC_DEF("exec", 1, js_regexp_exec ), @@ -45092,8 +45151,6 @@ static const JSCFunctionListEntry js_regexp_proto_funcs[] = { JS_CFUNC_DEF("[Symbol.matchAll]", 1, js_regexp_Symbol_matchAll ), JS_CFUNC_DEF("[Symbol.search]", 1, js_regexp_Symbol_search ), JS_CFUNC_DEF("[Symbol.split]", 2, js_regexp_Symbol_split ), - //JS_CGETSET_DEF("__source", js_regexp_get___source, NULL ), - //JS_CGETSET_DEF("__flags", js_regexp_get___flags, NULL ), }; static const JSCFunctionListEntry js_regexp_string_iterator_proto_funcs[] = { @@ -45108,7 +45165,7 @@ void JS_AddIntrinsicRegExpCompiler(JSContext *ctx) void JS_AddIntrinsicRegExp(JSContext *ctx) { - JSValueConst obj; + JSValue obj; JS_AddIntrinsicRegExpCompiler(ctx); @@ -45117,11 +45174,11 @@ void JS_AddIntrinsicRegExp(JSContext *ctx) countof(js_regexp_proto_funcs)); obj = JS_NewGlobalCConstructor(ctx, "RegExp", js_regexp_constructor, 2, ctx->class_proto[JS_CLASS_REGEXP]); - ctx->regexp_ctor = JS_DupValue(ctx, obj); + ctx->regexp_ctor = js_dup(obj); JS_SetPropertyFunctionList(ctx, obj, js_regexp_funcs, countof(js_regexp_funcs)); ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR] = - JS_NewObjectProto(ctx, ctx->iterator_proto); + JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ITERATOR]); JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR], js_regexp_string_iterator_proto_funcs, countof(js_regexp_string_iterator_proto_funcs)); @@ -45129,15 +45186,6 @@ void JS_AddIntrinsicRegExp(JSContext *ctx) /* JSON */ -static int json_parse_expect(JSParseState *s, int tok) -{ - if (s->token.val != tok) { - /* XXX: dump token correctly in all cases */ - return js_parse_error(s, "expecting '%c'", tok); - } - return json_next_token(s); -} - static JSValue json_parse_value(JSParseState *s) { JSContext *ctx = s->ctx; @@ -45161,15 +45209,17 @@ static JSValue json_parse_value(JSParseState *s) prop_name = JS_ValueToAtom(ctx, s->token.u.str.str); if (prop_name == JS_ATOM_NULL) goto fail; - } else if (s->ext_json && s->token.val == TOK_IDENT) { - prop_name = JS_DupAtom(ctx, s->token.u.ident.atom); } else { - js_parse_error(s, "expecting property name"); + json_parse_error(s, s->token.ptr, "Expected property name or '}'"); goto fail; } if (json_next_token(s)) goto fail1; - if (json_parse_expect(s, ':')) + if (s->token.val != ':') { + json_parse_error(s, s->token.ptr, "Expected ':' after property name"); + goto fail1; + } + if (json_next_token(s)) goto fail1; prop_val = json_parse_value(s); if (JS_IsException(prop_val)) { @@ -45183,15 +45233,17 @@ static JSValue json_parse_value(JSParseState *s) if (ret < 0) goto fail; - if (s->token.val != ',') + if (s->token.val == '}') break; + if (s->token.val != ',') { + json_parse_error(s, s->token.ptr, "Expected ',' or '}' after property value"); + goto fail; + } if (json_next_token(s)) goto fail; - if (s->ext_json && s->token.val == '}') - break; } } - if (json_parse_expect(s, '}')) + if (json_next_token(s)) goto fail; } break; @@ -45206,29 +45258,29 @@ static JSValue json_parse_value(JSParseState *s) if (JS_IsException(val)) goto fail; if (s->token.val != ']') { - idx = 0; - for(;;) { + for(idx = 0;; idx++) { el = json_parse_value(s); if (JS_IsException(el)) goto fail; ret = JS_DefinePropertyValueUint32(ctx, val, idx, el, JS_PROP_C_W_E); if (ret < 0) goto fail; - if (s->token.val != ',') + if (s->token.val == ']') break; + if (s->token.val != ',') { + json_parse_error(s, s->token.ptr, "Expected ',' or ']' after array element"); + goto fail; + } if (json_next_token(s)) goto fail; - idx++; - if (s->ext_json && s->token.val == ']') - break; } } - if (json_parse_expect(s, ']')) + if (json_next_token(s)) goto fail; } break; case TOK_STRING: - val = JS_DupValue(ctx, s->token.u.str.str); + val = js_dup(s->token.u.str.str); if (json_next_token(s)) goto fail; break; @@ -45240,7 +45292,7 @@ static JSValue json_parse_value(JSParseState *s) case TOK_IDENT: if (s->token.u.ident.atom == JS_ATOM_false || s->token.u.ident.atom == JS_ATOM_true) { - val = JS_NewBool(ctx, s->token.u.ident.atom == JS_ATOM_true); + val = js_bool(s->token.u.ident.atom == JS_ATOM_true); } else if (s->token.u.ident.atom == JS_ATOM_null) { val = JS_NULL; } else { @@ -45265,14 +45317,13 @@ static JSValue json_parse_value(JSParseState *s) return JS_EXCEPTION; } -JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len, - const char *filename, int flags) +/* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */ +JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, const char *filename) { JSParseState s1, *s = &s1; JSValue val = JS_UNDEFINED; js_parse_init(ctx, s, buf, buf_len, filename, 1); - s->ext_json = ((flags & JS_PARSE_JSON_EXT) != 0); if (json_next_token(s)) goto fail; val = json_parse_value(s); @@ -45289,17 +45340,11 @@ JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len, return JS_EXCEPTION; } -JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, - const char *filename) -{ - return JS_ParseJSON2(ctx, buf, buf_len, filename, 0); -} - -static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder, - JSAtom name, JSValueConst reviver) +static JSValue internalize_json_property(JSContext *ctx, JSValue holder, + JSAtom name, JSValue reviver) { JSValue val, new_el, name_val, res; - JSValueConst args[2]; + JSValue args[2]; int ret, is_array; uint32_t i, len = 0; JSAtom prop; @@ -45364,11 +45409,11 @@ static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder, return JS_EXCEPTION; } -static JSValue js_json_parse(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_json_parse(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue obj, root; - JSValueConst reviver; + JSValue reviver; const char *str; size_t len; @@ -45399,7 +45444,7 @@ static JSValue js_json_parse(JSContext *ctx, JSValueConst this_val, } typedef struct JSONStringifyContext { - JSValueConst replacer_func; + JSValue replacer_func; JSValue stack; JSValue property_list; JSValue gap; @@ -45414,32 +45459,25 @@ static JSValue JS_ToQuotedStringFree(JSContext *ctx, JSValue val) { } static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc, - JSValueConst holder, JSValue val, JSValueConst key) + JSValue holder, JSValue val, JSValue key) { JSValue v; - JSValueConst args[2]; - - /* check for object.toJSON method */ - /* ECMA specifies this is done only for Object and BigInt */ - /* we do it for BigFloat and BigDecimal as an extension */ - if (JS_IsObject(val) || JS_IsBigInt(ctx, val) -#ifdef CONFIG_BIGNUM - || JS_IsBigFloat(val) || JS_IsBigDecimal(val) -#endif - ) { - JSValue f = JS_GetProperty(ctx, val, JS_ATOM_toJSON); - if (JS_IsException(f)) - goto exception; - if (JS_IsFunction(ctx, f)) { - v = JS_CallFree(ctx, f, val, 1, &key); - JS_FreeValue(ctx, val); - val = v; - if (JS_IsException(val)) - goto exception; - } else { - JS_FreeValue(ctx, f); - } - } + JSValue args[2]; + + if (JS_IsObject(val) || JS_IsBigInt(ctx, val)) { + JSValue f = JS_GetProperty(ctx, val, JS_ATOM_toJSON); + if (JS_IsException(f)) + goto exception; + if (JS_IsFunction(ctx, f)) { + v = JS_CallFree(ctx, f, val, 1, &key); + JS_FreeValue(ctx, val); + val = v; + if (JS_IsException(val)) + goto exception; + } else { + JS_FreeValue(ctx, f); + } + } if (!JS_IsUndefined(jsc->replacer_func)) { args[0] = key; @@ -45461,10 +45499,6 @@ static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc, case JS_TAG_BOOL: case JS_TAG_NULL: case JS_TAG_BIG_INT: -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: - case JS_TAG_BIG_DECIMAL: -#endif case JS_TAG_EXCEPTION: return val; default: @@ -45479,14 +45513,14 @@ static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc, } static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc, - JSValueConst holder, JSValue val, - JSValueConst indent) + JSValue holder, JSValue val, + JSValue indent) { JSValue indent1, sep, sep1, tab, v, prop; JSObject *p; int64_t i, len; int cl, ret; - BOOL has_content; + bool has_content; indent1 = JS_UNDEFINED; sep = JS_UNDEFINED; @@ -45507,39 +45541,32 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc, if (JS_IsException(val)) goto exception; goto concat_primitive; - } else if (cl == JS_CLASS_BOOLEAN || cl == JS_CLASS_BIG_INT -#ifdef CONFIG_BIGNUM - || cl == JS_CLASS_BIG_FLOAT - || cl == JS_CLASS_BIG_DECIMAL -#endif - ) - { - /* This will thow the same error as for the primitive object */ - set_value(ctx, &val, JS_DupValue(ctx, p->u.object_data)); + } else if (cl == JS_CLASS_BOOLEAN || cl == JS_CLASS_BIG_INT) { + set_value(ctx, &val, js_dup(p->u.object_data)); goto concat_primitive; } - v = js_array_includes(ctx, jsc->stack, 1, (JSValueConst *)&val); + v = js_array_includes(ctx, jsc->stack, 1, &val); if (JS_IsException(v)) goto exception; if (JS_ToBoolFree(ctx, v)) { JS_ThrowTypeError(ctx, "circular reference"); goto exception; } - indent1 = JS_ConcatString(ctx, JS_DupValue(ctx, indent), JS_DupValue(ctx, jsc->gap)); + indent1 = JS_ConcatString(ctx, js_dup(indent), js_dup(jsc->gap)); if (JS_IsException(indent1)) goto exception; if (!JS_IsEmptyString(jsc->gap)) { - sep = JS_ConcatString3(ctx, "\n", JS_DupValue(ctx, indent1), ""); + sep = JS_ConcatString3(ctx, "\n", js_dup(indent1), ""); if (JS_IsException(sep)) goto exception; - sep1 = JS_NewString(ctx, " "); + sep1 = js_new_string8(ctx, " "); if (JS_IsException(sep1)) goto exception; } else { - sep = JS_DupValue(ctx, jsc->empty); - sep1 = JS_DupValue(ctx, jsc->empty); + sep = js_dup(jsc->empty); + sep1 = js_dup(jsc->empty); } - v = js_array_push(ctx, jsc->stack, 1, (JSValueConst *)&val, 0); + v = js_array_push(ctx, jsc->stack, 1, &val, 0); if (check_exception_free(ctx, v)) goto exception; ret = JS_IsArray(ctx, val); @@ -45557,7 +45584,7 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc, if (JS_IsException(v)) goto exception; /* XXX: could do this string conversion only when needed */ - prop = JS_ToStringFree(ctx, JS_NewInt64(ctx, i)); + prop = JS_ToStringFree(ctx, js_int64(i)); if (JS_IsException(prop)) goto exception; v = js_json_check(ctx, jsc, val, v, prop); @@ -45577,21 +45604,21 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc, string_buffer_putc8(jsc->b, ']'); } else { if (!JS_IsUndefined(jsc->property_list)) - tab = JS_DupValue(ctx, jsc->property_list); + tab = js_dup(jsc->property_list); else - tab = js_object_keys(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val, JS_ITERATOR_KIND_KEY); + tab = js_object_keys(ctx, JS_UNDEFINED, 1, &val, JS_ITERATOR_KIND_KEY); if (JS_IsException(tab)) goto exception; if (js_get_length64(ctx, &len, tab)) goto exception; string_buffer_putc8(jsc->b, '{'); - has_content = FALSE; + has_content = false; for(i = 0; i < len; i++) { JS_FreeValue(ctx, prop); prop = JS_GetPropertyInt64(ctx, tab, i); if (JS_IsException(prop)) goto exception; - v = JS_GetPropertyValue(ctx, val, JS_DupValue(ctx, prop)); + v = JS_GetPropertyValue(ctx, val, js_dup(prop)); if (JS_IsException(v)) goto exception; v = js_json_check(ctx, jsc, val, v, prop); @@ -45611,10 +45638,10 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc, string_buffer_concat_value(jsc->b, sep1); if (js_json_to_str(ctx, jsc, val, v, indent1)) goto exception; - has_content = TRUE; + has_content = true; } } - if (has_content && !JS_IsEmptyString(jsc->gap)) { + if (has_content && JS_VALUE_GET_STRING(jsc->gap)->len != 0) { string_buffer_putc8(jsc->b, '\n'); string_buffer_concat_value(jsc->b, indent); } @@ -45648,12 +45675,7 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc, concat_value: return string_buffer_concat_value_free(jsc->b, val); case JS_TAG_BIG_INT: -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: - case JS_TAG_BIG_DECIMAL: -#endif - /* reject big numbers: use toJSON method to override */ - JS_ThrowTypeError(ctx, "Do not know how to serialize a BigInt"); + JS_ThrowTypeError(ctx, "BigInt are forbidden in JSON.stringify"); goto exception; default: JS_FreeValue(ctx, val); @@ -45670,8 +45692,8 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc, return -1; } -JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj, - JSValueConst replacer, JSValueConst space0) +JSValue JS_JSONStringify(JSContext *ctx, JSValue obj, + JSValue replacer, JSValue space0) { StringBuffer b_s; JSONStringifyContext jsc_s, *jsc = &jsc_s; @@ -45730,7 +45752,7 @@ JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj, continue; } present = js_array_includes(ctx, jsc->property_list, - 1, (JSValueConst *)&v); + 1, &v); if (JS_IsException(present)) { JS_FreeValue(ctx, v); goto exception; @@ -45743,7 +45765,7 @@ JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj, } } } - space = JS_DupValue(ctx, space0); + space = js_dup(space0); if (JS_IsObject(space)) { JSObject *p = JS_VALUE_GET_OBJ(space); if (p->class_id == JS_CLASS_NUMBER) { @@ -45765,7 +45787,7 @@ JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj, JSString *p = JS_VALUE_GET_STRING(space); jsc->gap = js_sub_string(ctx, p, 0, min_int(p->len, 10)); } else { - jsc->gap = JS_DupValue(ctx, jsc->empty); + jsc->gap = js_dup(jsc->empty); } JS_FreeValue(ctx, space); if (JS_IsException(jsc->gap)) @@ -45774,9 +45796,9 @@ JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj, if (JS_IsException(wrapper)) goto exception; if (JS_DefinePropertyValue(ctx, wrapper, JS_ATOM_empty_string, - JS_DupValue(ctx, obj), JS_PROP_C_W_E) < 0) + js_dup(obj), JS_PROP_C_W_E) < 0) goto exception; - val = JS_DupValue(ctx, obj); + val = js_dup(obj); val = js_json_check(ctx, jsc, wrapper, val, jsc->empty); if (JS_IsException(val)) @@ -45804,8 +45826,8 @@ JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj, return ret; } -static JSValue js_json_stringify(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_json_stringify(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { // stringify(val, replacer, space) return JS_JSONStringify(ctx, argv[0], argv[1], argv[2]); @@ -45829,16 +45851,16 @@ void JS_AddIntrinsicJSON(JSContext *ctx) /* Reflect */ -static JSValue js_reflect_apply(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_reflect_apply(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { 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, - int argc, JSValueConst *argv) +static JSValue js_reflect_construct(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - JSValueConst func, array_arg, new_target; + JSValue func, array_arg, new_target; JSValue *tab, ret; uint32_t len; @@ -45854,15 +45876,15 @@ static JSValue js_reflect_construct(JSContext *ctx, JSValueConst this_val, tab = build_arg_list(ctx, &len, array_arg); if (!tab) return JS_EXCEPTION; - ret = JS_CallConstructor2(ctx, func, new_target, len, (JSValueConst *)tab); + ret = JS_CallConstructor2(ctx, func, new_target, len, tab); free_arg_list(ctx, tab, len); return ret; } -static JSValue js_reflect_deleteProperty(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_reflect_deleteProperty(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - JSValueConst obj; + JSValue obj; JSAtom atom; int ret; @@ -45877,13 +45899,13 @@ static JSValue js_reflect_deleteProperty(JSContext *ctx, JSValueConst this_val, if (ret < 0) return JS_EXCEPTION; else - return JS_NewBool(ctx, ret); + return js_bool(ret); } -static JSValue js_reflect_get(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_reflect_get(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - JSValueConst obj, prop, receiver; + JSValue obj, prop, receiver; JSAtom atom; JSValue ret; @@ -45898,15 +45920,15 @@ static JSValue js_reflect_get(JSContext *ctx, JSValueConst this_val, atom = JS_ValueToAtom(ctx, prop); if (unlikely(atom == JS_ATOM_NULL)) return JS_EXCEPTION; - ret = JS_GetPropertyInternal(ctx, obj, atom, receiver, FALSE); + ret = JS_GetPropertyInternal(ctx, obj, atom, receiver, false); JS_FreeAtom(ctx, atom); return ret; } -static JSValue js_reflect_has(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_reflect_has(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - JSValueConst obj, prop; + JSValue obj, prop; JSAtom atom; int ret; @@ -45922,13 +45944,13 @@ static JSValue js_reflect_has(JSContext *ctx, JSValueConst this_val, if (ret < 0) return JS_EXCEPTION; else - return JS_NewBool(ctx, ret); + return js_bool(ret); } -static JSValue js_reflect_set(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_reflect_set(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - JSValueConst obj, prop, val, receiver; + JSValue obj, prop, val, receiver; int ret; JSAtom atom; @@ -45944,28 +45966,28 @@ static JSValue js_reflect_set(JSContext *ctx, JSValueConst this_val, atom = JS_ValueToAtom(ctx, prop); if (unlikely(atom == JS_ATOM_NULL)) return JS_EXCEPTION; - ret = JS_SetPropertyInternal(ctx, obj, atom, - JS_DupValue(ctx, val), receiver, 0); + ret = JS_SetPropertyInternal2(ctx, obj, atom, js_dup(val), receiver, + 0, NULL); JS_FreeAtom(ctx, atom); if (ret < 0) return JS_EXCEPTION; else - return JS_NewBool(ctx, ret); + return js_bool(ret); } -static JSValue js_reflect_setPrototypeOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_reflect_setPrototypeOf(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { int ret; - ret = JS_SetPrototypeInternal(ctx, argv[0], argv[1], FALSE); + ret = JS_SetPrototypeInternal(ctx, argv[0], argv[1], false); if (ret < 0) return JS_EXCEPTION; else - return JS_NewBool(ctx, ret); + return js_bool(ret); } -static JSValue js_reflect_ownKeys(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_reflect_ownKeys(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT) return JS_ThrowTypeErrorNotAnObject(ctx); @@ -46007,7 +46029,7 @@ static void js_proxy_finalizer(JSRuntime *rt, JSValue val) } } -static void js_proxy_mark(JSRuntime *rt, JSValueConst val, +static void js_proxy_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) { JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY); @@ -46023,7 +46045,7 @@ static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx) } static JSProxyData *get_proxy_method(JSContext *ctx, JSValue *pmethod, - JSValueConst obj, JSAtom name) + JSValue obj, JSAtom name) { JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY); JSValue method; @@ -46048,7 +46070,7 @@ static JSProxyData *get_proxy_method(JSContext *ctx, JSValue *pmethod, return s; } -static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj) +static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValue obj) { JSProxyData *s; JSValue method, ret, proto1; @@ -46059,7 +46081,7 @@ static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj) return JS_EXCEPTION; if (JS_IsUndefined(method)) return JS_GetPrototype(ctx, s->target); - ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target); + ret = JS_CallFree(ctx, method, s->handler, 1, &s->target); if (JS_IsException(ret)) return ret; if (JS_VALUE_GET_TAG(ret) != JS_TAG_NULL && @@ -46089,13 +46111,13 @@ static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj) return ret; } -static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj, - JSValueConst proto_val, BOOL throw_flag) +static int js_proxy_setPrototypeOf(JSContext *ctx, JSValue obj, + JSValue proto_val, bool throw_flag) { JSProxyData *s; JSValue method, ret, proto1; - JSValueConst args[2]; - BOOL res; + JSValue args[2]; + bool res; int res2; s = get_proxy_method(ctx, &method, obj, JS_ATOM_setPrototypeOf); @@ -46114,7 +46136,7 @@ static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj, JS_ThrowTypeError(ctx, "proxy: bad prototype"); return -1; } else { - return FALSE; + return false; } } res2 = JS_IsExtensible(ctx, s->target); @@ -46131,14 +46153,14 @@ static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj, } JS_FreeValue(ctx, proto1); } - return TRUE; + return true; } -static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj) +static int js_proxy_isExtensible(JSContext *ctx, JSValue obj) { JSProxyData *s; JSValue method, ret; - BOOL res; + bool res; int res2; s = get_proxy_method(ctx, &method, obj, JS_ATOM_isExtensible); @@ -46146,7 +46168,7 @@ static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj) return -1; if (JS_IsUndefined(method)) return JS_IsExtensible(ctx, s->target); - ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target); + ret = JS_CallFree(ctx, method, s->handler, 1, &s->target); if (JS_IsException(ret)) return -1; res = JS_ToBoolFree(ctx, ret); @@ -46160,11 +46182,11 @@ static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj) return res; } -static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj) +static int js_proxy_preventExtensions(JSContext *ctx, JSValue obj) { JSProxyData *s; JSValue method, ret; - BOOL res; + bool res; int res2; s = get_proxy_method(ctx, &method, obj, JS_ATOM_preventExtensions); @@ -46172,7 +46194,7 @@ static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj) return -1; if (JS_IsUndefined(method)) return JS_PreventExtensions(ctx, s->target); - ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target); + ret = JS_CallFree(ctx, method, s->handler, 1, &s->target); if (JS_IsException(ret)) return -1; res = JS_ToBoolFree(ctx, ret); @@ -46188,14 +46210,14 @@ static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj) return res; } -static int js_proxy_has(JSContext *ctx, JSValueConst obj, JSAtom atom) +static int js_proxy_has(JSContext *ctx, JSValue obj, JSAtom atom) { JSProxyData *s; JSValue method, ret1, atom_val; - int ret, res; + int res; JSObject *p; - JSValueConst args[2]; - BOOL res2; + JSValue args[2]; + bool ret, res2; s = get_proxy_method(ctx, &method, obj, JS_ATOM_has); if (!s) @@ -46232,13 +46254,13 @@ static int js_proxy_has(JSContext *ctx, JSValueConst obj, JSAtom atom) return ret; } -static JSValue js_proxy_get(JSContext *ctx, JSValueConst obj, JSAtom atom, - JSValueConst receiver) +static JSValue js_proxy_get(JSContext *ctx, JSValue obj, JSAtom atom, + JSValue receiver) { JSProxyData *s; JSValue method, ret, atom_val; int res; - JSValueConst args[3]; + JSValue args[3]; JSPropertyDescriptor desc; s = get_proxy_method(ctx, &method, obj, JS_ATOM_get); @@ -46246,7 +46268,7 @@ static JSValue js_proxy_get(JSContext *ctx, JSValueConst obj, JSAtom atom, return JS_EXCEPTION; /* Note: recursion is possible thru the prototype of s->target */ if (JS_IsUndefined(method)) - return JS_GetPropertyInternal(ctx, s->target, atom, receiver, FALSE); + return JS_GetPropertyInternal(ctx, s->target, atom, receiver, false); atom_val = JS_AtomToValue(ctx, atom); if (JS_IsException(atom_val)) { JS_FreeValue(ctx, method); @@ -46260,8 +46282,10 @@ static JSValue js_proxy_get(JSContext *ctx, JSValueConst obj, JSAtom atom, if (JS_IsException(ret)) return JS_EXCEPTION; res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom); - if (res < 0) + if (res < 0) { + JS_FreeValue(ctx, ret); return JS_EXCEPTION; + } if (res) { if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) { if (!js_same_value(ctx, desc.value, ret)) { @@ -46280,21 +46304,22 @@ static JSValue js_proxy_get(JSContext *ctx, JSValueConst obj, JSAtom atom, return ret; } -static int js_proxy_set(JSContext *ctx, JSValueConst obj, JSAtom atom, - JSValueConst value, JSValueConst receiver, int flags) +static int js_proxy_set(JSContext *ctx, JSValue obj, JSAtom atom, + JSValue value, JSValue receiver, int flags) { JSProxyData *s; JSValue method, ret1, atom_val; - int ret, res; - JSValueConst args[4]; + bool ret; + int res; + JSValue args[4]; s = get_proxy_method(ctx, &method, obj, JS_ATOM_set); if (!s) return -1; if (JS_IsUndefined(method)) { - return JS_SetPropertyInternal(ctx, s->target, atom, - JS_DupValue(ctx, value), receiver, - flags); + return JS_SetPropertyInternal2(ctx, s->target, atom, + js_dup(value), receiver, + flags, NULL); } atom_val = JS_AtomToValue(ctx, atom); if (JS_IsException(atom_val)) { @@ -46338,8 +46363,8 @@ static int js_proxy_set(JSContext *ctx, JSValueConst obj, JSAtom atom, return ret; } -static JSValue js_create_desc(JSContext *ctx, JSValueConst val, - JSValueConst getter, JSValueConst setter, +static JSValue js_create_desc(JSContext *ctx, JSValue val, + JSValue getter, JSValue setter, int flags) { JSValue ret; @@ -46347,43 +46372,43 @@ static JSValue js_create_desc(JSContext *ctx, JSValueConst val, if (JS_IsException(ret)) return ret; if (flags & JS_PROP_HAS_GET) { - JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, JS_DupValue(ctx, getter), + JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, js_dup(getter), JS_PROP_C_W_E); } if (flags & JS_PROP_HAS_SET) { - JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, JS_DupValue(ctx, setter), + JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, js_dup(setter), JS_PROP_C_W_E); } if (flags & JS_PROP_HAS_VALUE) { - JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, val), + JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, js_dup(val), JS_PROP_C_W_E); } if (flags & JS_PROP_HAS_WRITABLE) { JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable, - JS_NewBool(ctx, flags & JS_PROP_WRITABLE), + js_bool(flags & JS_PROP_WRITABLE), JS_PROP_C_W_E); } if (flags & JS_PROP_HAS_ENUMERABLE) { JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable, - JS_NewBool(ctx, flags & JS_PROP_ENUMERABLE), + js_bool(flags & JS_PROP_ENUMERABLE), JS_PROP_C_W_E); } if (flags & JS_PROP_HAS_CONFIGURABLE) { JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable, - JS_NewBool(ctx, flags & JS_PROP_CONFIGURABLE), + js_bool(flags & JS_PROP_CONFIGURABLE), JS_PROP_C_W_E); } return ret; } static int js_proxy_get_own_property(JSContext *ctx, JSPropertyDescriptor *pdesc, - JSValueConst obj, JSAtom prop) + JSValue obj, JSAtom prop) { JSProxyData *s; JSValue method, trap_result_obj, prop_val; int res, target_desc_ret, ret; JSObject *p; - JSValueConst args[2]; + JSValue args[2]; JSPropertyDescriptor result_desc, target_desc; s = get_proxy_method(ctx, &method, obj, JS_ATOM_getOwnPropertyDescriptor); @@ -46420,7 +46445,7 @@ static int js_proxy_get_own_property(JSContext *ctx, JSPropertyDescriptor *pdesc if (!(target_desc.flags & JS_PROP_CONFIGURABLE) || !p->extensible) goto fail; } - ret = FALSE; + ret = false; } else { int flags1, extensible_target; extensible_target = JS_IsExtensible(ctx, s->target); @@ -46463,7 +46488,7 @@ static int js_proxy_get_own_property(JSContext *ctx, JSPropertyDescriptor *pdesc return -1; } } - ret = TRUE; + ret = true; if (pdesc) { *pdesc = result_desc; } else { @@ -46473,18 +46498,18 @@ static int js_proxy_get_own_property(JSContext *ctx, JSPropertyDescriptor *pdesc return ret; } -static int js_proxy_define_own_property(JSContext *ctx, JSValueConst obj, - JSAtom prop, JSValueConst val, - JSValueConst getter, JSValueConst setter, +static int js_proxy_define_own_property(JSContext *ctx, JSValue obj, + JSAtom prop, JSValue val, + JSValue getter, JSValue setter, int flags) { JSProxyData *s; JSValue method, ret1, prop_val, desc_val; - int res, ret; + int res; JSObject *p; - JSValueConst args[3]; + JSValue args[3]; JSPropertyDescriptor desc; - BOOL setting_not_configurable; + bool ret, setting_not_configurable; s = get_proxy_method(ctx, &method, obj, JS_ATOM_defineProperty); if (!s) @@ -46573,13 +46598,14 @@ static int js_proxy_define_own_property(JSContext *ctx, JSValueConst obj, return 1; } -static int js_proxy_delete_property(JSContext *ctx, JSValueConst obj, +static int js_proxy_delete_property(JSContext *ctx, JSValue obj, JSAtom atom) { JSProxyData *s; JSValue method, ret, atom_val; - int res, res2, is_extensible; - JSValueConst args[2]; + int res2, is_extensible; + bool res; + JSValue args[2]; s = get_proxy_method(ctx, &method, obj, JS_ATOM_deleteProperty); if (!s) @@ -46638,7 +46664,7 @@ static int find_prop_key(const JSPropertyEnum *tab, int n, JSAtom atom) static int js_proxy_get_own_property_names(JSContext *ctx, JSPropertyEnum **ptab, uint32_t *plen, - JSValueConst obj) + JSValue obj) { JSProxyData *s; JSValue method, prop_array, val; @@ -46656,7 +46682,7 @@ static int js_proxy_get_own_property_names(JSContext *ctx, JS_VALUE_GET_OBJ(s->target), JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK); } - prop_array = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target); + prop_array = JS_CallFree(ctx, method, s->handler, 1, &s->target); if (JS_IsException(prop_array)) return -1; tab = NULL; @@ -46684,7 +46710,7 @@ static int js_proxy_get_own_property_names(JSContext *ctx, if (atom == JS_ATOM_NULL) goto fail; tab[i].atom = atom; - tab[i].is_enumerable = FALSE; /* XXX: redundant? */ + tab[i].is_enumerable = false; /* XXX: redundant? */ } /* check duplicate properties (XXX: inefficient, could store the @@ -46727,7 +46753,7 @@ static int js_proxy_get_own_property_names(JSContext *ctx, } /* mark the property as found */ if (!is_extensible) - tab[idx].is_enumerable = TRUE; + tab[idx].is_enumerable = true; } } } @@ -46753,13 +46779,13 @@ static int js_proxy_get_own_property_names(JSContext *ctx, return -1; } -static JSValue js_proxy_call_constructor(JSContext *ctx, JSValueConst func_obj, - JSValueConst new_target, - int argc, JSValueConst *argv) +static JSValue js_proxy_call_constructor(JSContext *ctx, JSValue func_obj, + JSValue new_target, + int argc, JSValue *argv) { JSProxyData *s; JSValue method, arg_array, ret; - JSValueConst args[3]; + JSValue args[3]; s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_construct); if (!s) @@ -46787,13 +46813,13 @@ static JSValue js_proxy_call_constructor(JSContext *ctx, JSValueConst func_obj, return ret; } -static JSValue js_proxy_call(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_obj, - int argc, JSValueConst *argv, int flags) +static JSValue js_proxy_call(JSContext *ctx, JSValue func_obj, + JSValue this_obj, + int argc, JSValue *argv, int flags) { JSProxyData *s; JSValue method, arg_array, ret; - JSValueConst args[3]; + JSValue args[3]; if (flags & JS_CALL_FLAG_CONSTRUCTOR) return js_proxy_call_constructor(ctx, func_obj, this_obj, argc, argv); @@ -46822,35 +46848,22 @@ static JSValue js_proxy_call(JSContext *ctx, JSValueConst func_obj, return ret; } -/* `js_resolve_proxy`: resolve the proxy chain - `*pval` is updated with to ultimate proxy target - `throw_exception` controls whether exceptions are thown or not - - return -1 in case of error - - otherwise return 0 - */ -static int js_resolve_proxy(JSContext *ctx, JSValueConst *pval, BOOL throw_exception) { - int depth = 0; - JSObject *p; - JSProxyData *s; +static int js_proxy_isArray(JSContext *ctx, JSValue obj) +{ + JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY); + if (!s) + return false; - while (JS_VALUE_GET_TAG(*pval) == JS_TAG_OBJECT) { - p = JS_VALUE_GET_OBJ(*pval); - if (p->class_id != JS_CLASS_PROXY) - break; - if (depth++ > 1000) { - if (throw_exception) - JS_ThrowStackOverflow(ctx); - return -1; - } - s = p->u.opaque; - if (s->is_revoked) { - if (throw_exception) - JS_ThrowTypeErrorRevokedProxy(ctx); - return -1; - } - *pval = s->target; + if (js_check_stack_overflow(ctx->rt, 0)) { + JS_ThrowStackOverflow(ctx); + return -1; } - return 0; + + if (s->is_revoked) { + JS_ThrowTypeErrorRevokedProxy(ctx); + return -1; + } + return JS_IsArray(ctx, s->target); } static const JSClassExoticMethods js_proxy_exotic_methods = { @@ -46863,10 +46876,10 @@ static const JSClassExoticMethods js_proxy_exotic_methods = { .set_property = js_proxy_set, }; -static JSValue js_proxy_constructor(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_proxy_constructor(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - JSValueConst target, handler; + JSValue target, handler; JSValue obj; JSProxyData *s; @@ -46884,24 +46897,24 @@ static JSValue js_proxy_constructor(JSContext *ctx, JSValueConst this_val, JS_FreeValue(ctx, obj); return JS_EXCEPTION; } - s->target = JS_DupValue(ctx, target); - s->handler = JS_DupValue(ctx, handler); + s->target = js_dup(target); + s->handler = js_dup(handler); s->is_func = JS_IsFunction(ctx, target); - s->is_revoked = FALSE; - JS_SetOpaque(obj, s); + s->is_revoked = false; + JS_SetOpaqueInternal(obj, s); JS_SetConstructorBit(ctx, obj, JS_IsConstructor(ctx, target)); return obj; } -static JSValue js_proxy_revoke(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic, +static JSValue js_proxy_revoke(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic, JSValue *func_data) { JSProxyData *s = JS_GetOpaque(func_data[0], JS_CLASS_PROXY); if (s) { /* We do not free the handler and target in case they are referenced as constants in the C call stack */ - s->is_revoked = TRUE; + s->is_revoked = true; JS_FreeValue(ctx, func_data[0]); func_data[0] = JS_NULL; } @@ -46909,13 +46922,13 @@ static JSValue js_proxy_revoke(JSContext *ctx, JSValueConst this_val, } static JSValue js_proxy_revoke_constructor(JSContext *ctx, - JSValueConst proxy_obj) + JSValue proxy_obj) { return JS_NewCFunctionData(ctx, js_proxy_revoke, 0, 0, 1, &proxy_obj); } -static JSValue js_proxy_revocable(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_proxy_revocable(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue proxy_obj, revoke_obj = JS_UNDEFINED, obj; @@ -46960,7 +46973,7 @@ void JS_AddIntrinsicProxy(JSContext *ctx) obj1 = JS_NewCFunction2(ctx, js_proxy_constructor, "Proxy", 2, JS_CFUNC_constructor, 0); - JS_SetConstructorBit(ctx, obj1, TRUE); + JS_SetConstructorBit(ctx, obj1, true); JS_SetPropertyFunctionList(ctx, obj1, js_proxy_funcs, countof(js_proxy_funcs)); JS_DefinePropertyValueStr(ctx, ctx->global_obj, "Proxy", @@ -46969,8 +46982,8 @@ void JS_AddIntrinsicProxy(JSContext *ctx) /* Symbol */ -static JSValue js_symbol_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) +static JSValue js_symbol_constructor(JSContext *ctx, JSValue new_target, + int argc, JSValue *argv) { JSValue str; JSString *p; @@ -46985,44 +46998,44 @@ static JSValue js_symbol_constructor(JSContext *ctx, JSValueConst new_target, return JS_EXCEPTION; p = JS_VALUE_GET_STRING(str); } - return JS_NewSymbol(ctx, p, JS_ATOM_TYPE_SYMBOL); + return JS_NewSymbolInternal(ctx, p, JS_ATOM_TYPE_SYMBOL); } -static JSValue js_thisSymbolValue(JSContext *ctx, JSValueConst this_val) +static JSValue js_thisSymbolValue(JSContext *ctx, JSValue this_val) { if (JS_VALUE_GET_TAG(this_val) == JS_TAG_SYMBOL) - return JS_DupValue(ctx, this_val); + return js_dup(this_val); if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) { JSObject *p = JS_VALUE_GET_OBJ(this_val); if (p->class_id == JS_CLASS_SYMBOL) { if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_SYMBOL) - return JS_DupValue(ctx, p->u.object_data); + return js_dup(p->u.object_data); } } return JS_ThrowTypeError(ctx, "not a symbol"); } -static JSValue js_symbol_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_symbol_toString(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue val, ret; val = js_thisSymbolValue(ctx, this_val); if (JS_IsException(val)) return val; /* XXX: use JS_ToStringInternal() with a flags */ - ret = js_string_constructor(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val); + ret = js_string_constructor(ctx, JS_UNDEFINED, 1, &val); JS_FreeValue(ctx, val); return ret; } -static JSValue js_symbol_valueOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_symbol_valueOf(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { return js_thisSymbolValue(ctx, this_val); } -static JSValue js_symbol_get_description(JSContext *ctx, JSValueConst this_val) +static JSValue js_symbol_get_description(JSContext *ctx, JSValue this_val) { JSValue val, ret; JSAtomStruct *p; @@ -47049,19 +47062,19 @@ static const JSCFunctionListEntry js_symbol_proto_funcs[] = { JS_CGETSET_DEF("description", js_symbol_get_description, NULL ), }; -static JSValue js_symbol_for(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_symbol_for(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue str; str = JS_ToString(ctx, argv[0]); if (JS_IsException(str)) return JS_EXCEPTION; - return JS_NewSymbol(ctx, JS_VALUE_GET_STRING(str), JS_ATOM_TYPE_GLOBAL_SYMBOL); + return JS_NewSymbolInternal(ctx, JS_VALUE_GET_STRING(str), JS_ATOM_TYPE_GLOBAL_SYMBOL); } -static JSValue js_symbol_keyFor(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_symbol_keyFor(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSAtomStruct *p; @@ -47070,7 +47083,7 @@ static JSValue js_symbol_keyFor(JSContext *ctx, JSValueConst this_val, p = JS_VALUE_GET_PTR(argv[0]); if (p->atom_type != JS_ATOM_TYPE_GLOBAL_SYMBOL) return JS_UNDEFINED; - return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p)); + return js_dup(JS_MKPTR(JS_TAG_STRING, p)); } static const JSCFunctionListEntry js_symbol_funcs[] = { @@ -47082,9 +47095,8 @@ static const JSCFunctionListEntry js_symbol_funcs[] = { typedef struct JSMapRecord { int ref_count; /* used during enumeration to avoid freeing the record */ - BOOL empty; /* TRUE if the record is deleted */ + bool empty; /* true if the record is deleted */ struct JSMapState *map; - struct JSMapRecord *next_weak_ref; struct list_head link; struct list_head hash_link; JSValue key; @@ -47092,7 +47104,7 @@ typedef struct JSMapRecord { } JSMapRecord; typedef struct JSMapState { - BOOL is_weak; /* TRUE if WeakSet/WeakMap */ + bool is_weak; /* true if WeakSet/WeakMap */ struct list_head records; /* list of JSMapRecord.link */ uint32_t record_count; struct list_head *hash_table; @@ -47104,13 +47116,13 @@ typedef struct JSMapState { #define MAGIC_SET (1 << 0) #define MAGIC_WEAK (1 << 1) -static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv, int magic) +static JSValue js_map_constructor(JSContext *ctx, JSValue new_target, + int argc, JSValue *argv, int magic) { JSMapState *s; JSValue obj, adder = JS_UNDEFINED, iter = JS_UNDEFINED, next_method = JS_UNDEFINED; - JSValueConst arr; - BOOL is_set, is_weak; + JSValue arr; + bool is_set, is_weak; is_set = magic & MAGIC_SET; is_weak = ((magic & MAGIC_WEAK) != 0); @@ -47122,7 +47134,7 @@ static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target, goto fail; init_list_head(&s->records); s->is_weak = is_weak; - JS_SetOpaque(obj, s); + JS_SetOpaqueInternal(obj, s); s->hash_size = 1; s->hash_table = js_malloc(ctx, sizeof(s->hash_table[0]) * s->hash_size); if (!s->hash_table) @@ -47135,7 +47147,7 @@ static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target, arr = argv[0]; if (!JS_IsUndefined(arr) && !JS_IsNull(arr)) { JSValue item, ret; - BOOL done; + int done; adder = JS_GetProperty(ctx, obj, is_set ? JS_ATOM_add : JS_ATOM_set); if (JS_IsException(adder)) @@ -47145,7 +47157,7 @@ static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target, goto fail; } - iter = JS_GetIterator(ctx, arr, FALSE); + iter = JS_GetIterator(ctx, arr, false); if (JS_IsException(iter)) goto fail; next_method = JS_GetProperty(ctx, iter, JS_ATOM_next); @@ -47161,14 +47173,14 @@ static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target, break; } if (is_set) { - ret = JS_Call(ctx, adder, obj, 1, (JSValueConst *)&item); + ret = JS_Call(ctx, adder, obj, 1, &item); if (JS_IsException(ret)) { JS_FreeValue(ctx, item); goto fail; } } else { JSValue key, value; - JSValueConst args[2]; + JSValue args[2]; key = JS_UNDEFINED; value = JS_UNDEFINED; if (!JS_IsObject(item)) { @@ -47205,7 +47217,7 @@ static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target, fail: if (JS_IsObject(iter)) { /* close the iterator object, preserving pending exception */ - JS_IteratorClose(ctx, iter, TRUE); + JS_IteratorClose(ctx, iter, true); } JS_FreeValue(ctx, next_method); JS_FreeValue(ctx, iter); @@ -47215,23 +47227,24 @@ static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target, } /* XXX: could normalize strings to speed up comparison */ -static JSValueConst map_normalize_key(JSContext *ctx, JSValueConst key) +static JSValue map_normalize_key(JSContext *ctx, JSValue key) { uint32_t tag = JS_VALUE_GET_TAG(key); /* convert -0.0 to +0.0 */ if (JS_TAG_IS_FLOAT64(tag) && JS_VALUE_GET_FLOAT64(key) == 0.0) { - key = JS_NewInt32(ctx, 0); + key = js_int32(0); } return key; } /* XXX: better hash ? */ -static uint32_t map_hash_key(JSContext *ctx, JSValueConst key) +static uint32_t map_hash_key(JSContext *ctx, JSValue key) { uint32_t tag = JS_VALUE_GET_NORM_TAG(key); uint32_t h; double d; JSFloat64Union u; + bf_t *a; switch(tag) { case JS_TAG_BOOL: @@ -47247,6 +47260,10 @@ static uint32_t map_hash_key(JSContext *ctx, JSValueConst key) case JS_TAG_INT: d = JS_VALUE_GET_INT(key); goto hash_float64; + case JS_TAG_BIG_INT: + a = JS_GetBigInt(key); + h = hash_string8((void *)a->tab, a->len * sizeof(*a->tab), 0); + break; case JS_TAG_FLOAT64: d = JS_VALUE_GET_FLOAT64(key); /* normalize the NaN */ @@ -47257,7 +47274,7 @@ static uint32_t map_hash_key(JSContext *ctx, JSValueConst key) h = (u.u32[0] ^ u.u32[1]) * 3163; return h ^= JS_TAG_FLOAT64; default: - h = 0; /* XXX: bignum support */ + h = 0; break; } h ^= tag; @@ -47265,7 +47282,7 @@ static uint32_t map_hash_key(JSContext *ctx, JSValueConst key) } static JSMapRecord *map_find_record(JSContext *ctx, JSMapState *s, - JSValueConst key) + JSValue key) { struct list_head *el; JSMapRecord *mr; @@ -47312,8 +47329,29 @@ static void map_hash_resize(JSContext *ctx, JSMapState *s) s->record_count_threshold = new_hash_size * 2; } +static JSWeakRefRecord **get_first_weak_ref(JSValue key) +{ + switch (JS_VALUE_GET_TAG(key)) { + case JS_TAG_OBJECT: + { + JSObject *p = JS_VALUE_GET_OBJ(key); + return &p->first_weak_ref; + } + break; + case JS_TAG_SYMBOL: + { + JSAtomStruct *p = JS_VALUE_GET_PTR(key); + return &p->first_weak_ref; + } + break; + default: + abort(); + } + return NULL; // pacify compiler +} + static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s, - JSValueConst key) + JSValue key) { uint32_t h; JSMapRecord *mr; @@ -47323,14 +47361,18 @@ static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s, return NULL; mr->ref_count = 1; mr->map = s; - mr->empty = FALSE; + mr->empty = false; if (s->is_weak) { - JSObject *p = JS_VALUE_GET_OBJ(key); - /* Add the weak reference */ - mr->next_weak_ref = p->first_weak_ref; - p->first_weak_ref = mr; + JSWeakRefRecord *wr = js_malloc(ctx, sizeof(*wr)); + if (!wr) { + js_free(ctx, mr); + return NULL; + } + wr->kind = JS_WEAK_REF_KIND_MAP; + wr->u.map_record = mr; + insert_weakref_record(key, wr); } else { - JS_DupValue(ctx, key); + js_dup(key); } mr->key = key; h = map_hash_key(ctx, key) & (s->hash_size - 1); @@ -47347,21 +47389,20 @@ static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s, reference list. we don't use a doubly linked list to save space, assuming a given object has few weak references to it */ -static void delete_weak_ref(JSRuntime *rt, JSMapRecord *mr) +static void delete_map_weak_ref(JSRuntime *rt, JSMapRecord *mr) { - JSMapRecord **pmr, *mr1; - JSObject *p; + JSWeakRefRecord **pwr, *wr; - p = JS_VALUE_GET_OBJ(mr->key); - pmr = &p->first_weak_ref; + pwr = get_first_weak_ref(mr->key); for(;;) { - mr1 = *pmr; - assert(mr1 != NULL); - if (mr1 == mr) + wr = *pwr; + assert(wr != NULL); + if (wr->kind == JS_WEAK_REF_KIND_MAP && wr->u.map_record == mr) break; - pmr = &mr1->next_weak_ref; + pwr = &wr->next_weak_ref; } - *pmr = mr1->next_weak_ref; + *pwr = wr->next_weak_ref; + js_free_rt(rt, wr); } static void map_delete_record(JSRuntime *rt, JSMapState *s, JSMapRecord *mr) @@ -47370,7 +47411,7 @@ static void map_delete_record(JSRuntime *rt, JSMapState *s, JSMapRecord *mr) return; list_del(&mr->hash_link); if (s->is_weak) { - delete_weak_ref(rt, mr); + delete_map_weak_ref(rt, mr); } else { JS_FreeValueRT(rt, mr->key); } @@ -47380,7 +47421,7 @@ static void map_delete_record(JSRuntime *rt, JSMapState *s, JSMapRecord *mr) js_free_rt(rt, mr); } else { /* keep a zombie record for iterators */ - mr->empty = TRUE; + mr->empty = true; mr->key = JS_UNDEFINED; mr->value = JS_UNDEFINED; } @@ -47397,45 +47438,21 @@ static void map_decref_record(JSRuntime *rt, JSMapRecord *mr) } } -static void reset_weak_ref(JSRuntime *rt, JSObject *p) -{ - JSMapRecord *mr, *mr_next; - JSMapState *s; - - /* first pass to remove the records from the WeakMap/WeakSet - lists */ - for(mr = p->first_weak_ref; mr != NULL; mr = mr->next_weak_ref) { - s = mr->map; - assert(s->is_weak); - assert(!mr->empty); /* no iterator on WeakMap/WeakSet */ - list_del(&mr->hash_link); - list_del(&mr->link); - } - - /* second pass to free the values to avoid modifying the weak - reference list while traversing it. */ - for(mr = p->first_weak_ref; mr != NULL; mr = mr_next) { - mr_next = mr->next_weak_ref; - JS_FreeValueRT(rt, mr->value); - js_free_rt(rt, mr); - } - - p->first_weak_ref = NULL; /* fail safe */ -} - -static JSValue js_map_set(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) +static JSValue js_map_set(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic); JSMapRecord *mr; - JSValueConst key, value; + JSValue key, value; + int is_set; if (!s) return JS_EXCEPTION; + is_set = (magic & MAGIC_SET); key = map_normalize_key(ctx, argv[0]); - if (s->is_weak && !JS_IsObject(key)) - return JS_ThrowTypeErrorNotAnObject(ctx); - if (magic & MAGIC_SET) + if (s->is_weak && !is_valid_weakref_target(key)) + return JS_ThrowTypeError(ctx, "invalid value used as %s key", is_set ? "WeakSet" : "WeakMap"); + if (is_set) value = JS_UNDEFINED; else value = argv[1]; @@ -47447,16 +47464,16 @@ static JSValue js_map_set(JSContext *ctx, JSValueConst this_val, if (!mr) return JS_EXCEPTION; } - mr->value = JS_DupValue(ctx, value); - return JS_DupValue(ctx, this_val); + mr->value = js_dup(value); + return js_dup(this_val); } -static JSValue js_map_get(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) +static JSValue js_map_get(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic); JSMapRecord *mr; - JSValueConst key; + JSValue key; if (!s) return JS_EXCEPTION; @@ -47465,29 +47482,29 @@ static JSValue js_map_get(JSContext *ctx, JSValueConst this_val, if (!mr) return JS_UNDEFINED; else - return JS_DupValue(ctx, mr->value); + return js_dup(mr->value); } -static JSValue js_map_has(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) +static JSValue js_map_has(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic); JSMapRecord *mr; - JSValueConst key; + JSValue key; if (!s) return JS_EXCEPTION; key = map_normalize_key(ctx, argv[0]); mr = map_find_record(ctx, s, key); - return JS_NewBool(ctx, mr != NULL); + return js_bool(mr != NULL); } -static JSValue js_map_delete(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) +static JSValue js_map_delete(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic); JSMapRecord *mr; - JSValueConst key; + JSValue key; if (!s) return JS_EXCEPTION; @@ -47499,8 +47516,8 @@ static JSValue js_map_delete(JSContext *ctx, JSValueConst this_val, return JS_TRUE; } -static JSValue js_map_clear(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) +static JSValue js_map_clear(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic); struct list_head *el, *el1; @@ -47515,19 +47532,19 @@ static JSValue js_map_clear(JSContext *ctx, JSValueConst this_val, return JS_UNDEFINED; } -static JSValue js_map_get_size(JSContext *ctx, JSValueConst this_val, int magic) +static JSValue js_map_get_size(JSContext *ctx, JSValue this_val, int magic) { JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic); if (!s) return JS_EXCEPTION; - return JS_NewUint32(ctx, s->record_count); + return js_uint32(s->record_count); } -static JSValue js_map_forEach(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) +static JSValue js_map_forEach(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic); - JSValueConst func, this_arg; + JSValue func, this_arg; JSValue ret, args[3]; struct list_head *el; JSMapRecord *mr; @@ -47549,13 +47566,13 @@ static JSValue js_map_forEach(JSContext *ctx, JSValueConst this_val, if (!mr->empty) { mr->ref_count++; /* must duplicate in case the record is deleted */ - args[1] = JS_DupValue(ctx, mr->key); + args[1] = js_dup(mr->key); if (magic) args[0] = args[1]; else - args[0] = JS_DupValue(ctx, mr->value); + args[0] = js_dup(mr->value); args[2] = this_val; - ret = JS_Call(ctx, func, this_arg, 3, (JSValueConst *)args); + ret = JS_Call(ctx, func, this_arg, 3, args); JS_FreeValue(ctx, args[0]); if (!magic) JS_FreeValue(ctx, args[1]); @@ -47571,26 +47588,24 @@ static JSValue js_map_forEach(JSContext *ctx, JSValueConst this_val, return JS_UNDEFINED; } -static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int is_map) +static JSValue js_map_groupBy(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - JSValueConst cb, args[2]; - JSValue res, iter, next, groups, key, v, prop; - JSAtom key_atom = JS_ATOM_NULL; + JSValue cb, res, iter, next, groups, k, v, prop; + JSValue args[2]; int64_t idx; - BOOL done; + int done; // "is function?" check must be observed before argv[0] is accessed cb = argv[1]; if (check_function(ctx, cb)) return JS_EXCEPTION; - iter = JS_GetIterator(ctx, argv[0], /*is_async*/FALSE); + iter = JS_GetIterator(ctx, argv[0], /*is_async*/false); if (JS_IsException(iter)) return JS_EXCEPTION; - key = JS_UNDEFINED; - key_atom = JS_ATOM_NULL; + k = JS_UNDEFINED; v = JS_UNDEFINED; prop = JS_UNDEFINED; groups = JS_UNDEFINED; @@ -47599,19 +47614,11 @@ static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val, if (JS_IsException(next)) goto exception; - if (is_map) { - groups = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, 0); - } else { - groups = JS_NewObjectProto(ctx, JS_NULL); - } + groups = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, 0); if (JS_IsException(groups)) goto exception; for (idx = 0; ; idx++) { - if (idx >= MAX_SAFE_INTEGER) { - JS_ThrowTypeError(ctx, "too many elements"); - goto iterator_close_exception; - } v = JS_IteratorNext(ctx, iter, next, 0, NULL, &done); if (JS_IsException(v)) goto exception; @@ -47619,21 +47626,12 @@ static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val, break; // v is JS_UNDEFINED args[0] = v; - args[1] = JS_NewInt64(ctx, idx); - key = JS_Call(ctx, cb, ctx->global_obj, 2, args); - if (JS_IsException(key)) - goto iterator_close_exception; + args[1] = js_int64(idx); + k = JS_Call(ctx, cb, ctx->global_obj, 2, args); + if (JS_IsException(k)) + goto exception; - if (is_map) { - prop = js_map_get(ctx, groups, 1, (JSValueConst *)&key, 0); - } else { - key_atom = JS_ValueToAtom(ctx, key); - JS_FreeValue(ctx, key); - key = JS_UNDEFINED; - if (key_atom == JS_ATOM_NULL) - goto iterator_close_exception; - prop = JS_GetProperty(ctx, groups, key_atom); - } + prop = js_map_get(ctx, groups, 1, &k, 0); if (JS_IsException(prop)) goto exception; @@ -47641,33 +47639,24 @@ static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val, prop = JS_NewArray(ctx); if (JS_IsException(prop)) goto exception; - if (is_map) { - args[0] = key; - args[1] = prop; - res = js_map_set(ctx, groups, 2, args, 0); - if (JS_IsException(res)) - goto exception; - JS_FreeValue(ctx, res); - } else { - prop = JS_DupValue(ctx, prop); - if (JS_DefinePropertyValue(ctx, groups, key_atom, prop, - JS_PROP_C_W_E) < 0) { - goto exception; - } - } + args[0] = k; + args[1] = prop; + res = js_map_set(ctx, groups, 2, args, 0); + if (JS_IsException(res)) + goto exception; + JS_FreeValue(ctx, res); } - res = js_array_push(ctx, prop, 1, (JSValueConst *)&v, /*unshift*/0); + + res = js_array_push(ctx, prop, 1, &v, /*unshift*/0); if (JS_IsException(res)) goto exception; // res is an int64 JS_FreeValue(ctx, prop); - JS_FreeValue(ctx, key); - JS_FreeAtom(ctx, key_atom); + JS_FreeValue(ctx, k); JS_FreeValue(ctx, v); prop = JS_UNDEFINED; - key = JS_UNDEFINED; - key_atom = JS_ATOM_NULL; + k = JS_UNDEFINED; v = JS_UNDEFINED; } @@ -47675,12 +47664,9 @@ static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val, JS_FreeValue(ctx, next); return groups; - iterator_close_exception: - JS_IteratorClose(ctx, iter, TRUE); - exception: - JS_FreeAtom(ctx, key_atom); +exception: JS_FreeValue(ctx, prop); - JS_FreeValue(ctx, key); + JS_FreeValue(ctx, k); JS_FreeValue(ctx, v); JS_FreeValue(ctx, groups); JS_FreeValue(ctx, iter); @@ -47704,7 +47690,7 @@ static void js_map_finalizer(JSRuntime *rt, JSValue val) mr = list_entry(el, JSMapRecord, link); if (!mr->empty) { if (s->is_weak) - delete_weak_ref(rt, mr); + delete_map_weak_ref(rt, mr); else JS_FreeValueRT(rt, mr->key); JS_FreeValueRT(rt, mr->value); @@ -47716,7 +47702,7 @@ static void js_map_finalizer(JSRuntime *rt, JSValue val) } } -static void js_map_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) +static void js_map_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); JSMapState *s; @@ -47760,7 +47746,7 @@ static void js_map_iterator_finalizer(JSRuntime *rt, JSValue val) } } -static void js_map_iterator_mark(JSRuntime *rt, JSValueConst val, +static void js_map_iterator_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); @@ -47772,8 +47758,8 @@ static void js_map_iterator_mark(JSRuntime *rt, JSValueConst val, } } -static JSValue js_create_map_iterator(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) +static JSValue js_create_map_iterator(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { JSIteratorKindEnum kind; JSMapState *s; @@ -47793,18 +47779,18 @@ static JSValue js_create_map_iterator(JSContext *ctx, JSValueConst this_val, JS_FreeValue(ctx, enum_obj); goto fail; } - it->obj = JS_DupValue(ctx, this_val); + it->obj = js_dup(this_val); it->kind = kind; it->cur_record = NULL; - JS_SetOpaque(enum_obj, it); + JS_SetOpaqueInternal(enum_obj, it); return enum_obj; fail: return JS_EXCEPTION; } -static JSValue js_map_iterator_next(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, - BOOL *pdone, int magic) +static JSValue js_map_iterator_next(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, + int *pdone, int magic) { JSMapIteratorData *it; JSMapState *s; @@ -47813,7 +47799,7 @@ static JSValue js_map_iterator_next(JSContext *ctx, JSValueConst this_val, it = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP_ITERATOR + magic); if (!it) { - *pdone = FALSE; + *pdone = false; return JS_EXCEPTION; } if (JS_IsUndefined(it->obj)) @@ -47835,7 +47821,7 @@ static JSValue js_map_iterator_next(JSContext *ctx, JSValueConst this_val, it->obj = JS_UNDEFINED; done: /* end of enumeration */ - *pdone = TRUE; + *pdone = true; return JS_UNDEFINED; } mr = list_entry(el, JSMapRecord, link); @@ -47848,27 +47834,705 @@ static JSValue js_map_iterator_next(JSContext *ctx, JSValueConst this_val, /* lock the record so that it won't be freed */ mr->ref_count++; it->cur_record = mr; - *pdone = FALSE; + *pdone = false; if (it->kind == JS_ITERATOR_KIND_KEY) { - return JS_DupValue(ctx, mr->key); + return js_dup(mr->key); } else { - JSValueConst args[2]; + JSValue args[2]; args[0] = mr->key; if (magic) args[1] = mr->key; else args[1] = mr->value; if (it->kind == JS_ITERATOR_KIND_VALUE) { - return JS_DupValue(ctx, args[1]); + return js_dup(args[1]); } else { return js_create_array(ctx, 2, args); } } } +static JSValue js_map_read(BCReaderState *s, int magic) +{ + JSContext *ctx = s->ctx; + JSValue obj, rv, argv[2]; + uint32_t i, prop_count; + + argv[0] = JS_UNDEFINED; + argv[1] = JS_UNDEFINED; + obj = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, magic); + if (JS_IsException(obj)) + return JS_EXCEPTION; + if (BC_add_object_ref(s, obj)) + goto fail; + if (bc_get_leb128(s, &prop_count)) + goto fail; + for(i = 0; i < prop_count; i++) { + argv[0] = JS_ReadObjectRec(s); + if (JS_IsException(argv[0])) + goto fail; + if (!(magic & MAGIC_SET)) { + argv[1] = JS_ReadObjectRec(s); + if (JS_IsException(argv[1])) + goto fail; + } + rv = js_map_set(ctx, obj, countof(argv), argv, magic); + if (JS_IsException(rv)) + goto fail; + JS_FreeValue(ctx, rv); + JS_FreeValue(ctx, argv[0]); + JS_FreeValue(ctx, argv[1]); + argv[0] = JS_UNDEFINED; + argv[1] = JS_UNDEFINED; + } + return obj; + fail: + JS_FreeValue(ctx, obj); + JS_FreeValue(ctx, argv[0]); + JS_FreeValue(ctx, argv[1]); + return JS_EXCEPTION; +} + +static int js_map_write(BCWriterState *s, struct JSMapState *map_state, + int magic) +{ + struct list_head *el; + JSMapRecord *mr; + + bc_put_leb128(s, map_state ? map_state->record_count : 0); + if (map_state) { + list_for_each(el, &map_state->records) { + mr = list_entry(el, JSMapRecord, link); + if (JS_WriteObjectRec(s, mr->key)) + return -1; + // mr->value is always JS_UNDEFINED for sets + if (!(magic & MAGIC_SET)) + if (JS_WriteObjectRec(s, mr->value)) + return -1; + } + } + + return 0; +} + +static JSValue JS_ReadMap(BCReaderState *s) +{ + return js_map_read(s, 0); +} + +static JSValue JS_ReadSet(BCReaderState *s) +{ + return js_map_read(s, MAGIC_SET); +} + +static int JS_WriteMap(BCWriterState *s, struct JSMapState *map_state) +{ + return js_map_write(s, map_state, 0); +} + +static int JS_WriteSet(BCWriterState *s, struct JSMapState *map_state) +{ + return js_map_write(s, map_state, MAGIC_SET); +} + +static int js_setlike_get_size(JSContext *ctx, JSValue setlike, int64_t *pout) +{ + JSMapState *s; + JSValue v; + double d; + + s = JS_GetOpaque(setlike, JS_CLASS_SET); + if (s) { + *pout = s->record_count; + } else { + v = JS_GetProperty(ctx, setlike, JS_ATOM_size); + if (JS_IsException(v)) + return -1; + if (JS_IsUndefined(v)) { + JS_ThrowTypeError(ctx, ".size is undefined"); + return -1; + } + if (JS_ToFloat64Free(ctx, &d, v) < 0) + return -1; + if (isnan(d)) { + JS_ThrowTypeError(ctx, ".size is not a number"); + return -1; + } + *pout = d; + } + return 0; +} + +static int js_setlike_get_has(JSContext *ctx, JSValue setlike, JSValue *pout) +{ + JSValue v; + + v = JS_GetProperty(ctx, setlike, JS_ATOM_has); + if (JS_IsException(v)) + return -1; + if (JS_IsUndefined(v)) { + JS_ThrowTypeError(ctx, ".has is undefined"); + return -1; + } + if (!JS_IsFunction(ctx, v)) { + JS_ThrowTypeError(ctx, ".has is not a function"); + JS_FreeValue(ctx, v); + return -1; + } + *pout = v; + return 0; +} + +static int js_setlike_get_keys(JSContext *ctx, JSValue setlike, JSValue *pout) +{ + JSValue v; + + v = JS_GetProperty(ctx, setlike, JS_ATOM_keys); + if (JS_IsException(v)) + return -1; + if (JS_IsUndefined(v)) { + JS_ThrowTypeError(ctx, ".keys is undefined"); + return -1; + } + if (!JS_IsFunction(ctx, v)) { + JS_ThrowTypeError(ctx, ".keys is not a function"); + JS_FreeValue(ctx, v); + return -1; + } + *pout = v; + return 0; +} + +static JSValue js_set_isDisjointFrom(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + JSValue item, iter, keys, has, next, rv, rval; + int done; + bool found; + JSMapState *s; + int64_t size; + int ok; + + has = JS_UNDEFINED; + iter = JS_UNDEFINED; + keys = JS_UNDEFINED; + next = JS_UNDEFINED; + rval = JS_EXCEPTION; + s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET); + if (!s) + goto exception; + // order matters! + if (js_setlike_get_size(ctx, argv[0], &size) < 0) + goto exception; + if (js_setlike_get_has(ctx, argv[0], &has) < 0) + goto exception; + if (js_setlike_get_keys(ctx, argv[0], &keys) < 0) + goto exception; + if (s->record_count > size) { + iter = JS_Call(ctx, keys, argv[0], 0, NULL); + if (JS_IsException(iter)) + goto exception; + next = JS_GetProperty(ctx, iter, JS_ATOM_next); + if (JS_IsException(next)) + goto exception; + found = false; + do { + item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done); + if (JS_IsException(item)) + goto exception; + if (done) // item is JS_UNDEFINED + break; + item = map_normalize_key(ctx, item); + found = (NULL != map_find_record(ctx, s, item)); + JS_FreeValue(ctx, item); + } while (!found); + } else { + iter = js_create_map_iterator(ctx, this_val, 0, NULL, MAGIC_SET); + if (JS_IsException(iter)) + goto exception; + found = false; + do { + item = js_map_iterator_next(ctx, iter, 0, NULL, &done, MAGIC_SET); + if (JS_IsException(item)) + goto exception; + if (done) // item is JS_UNDEFINED + break; + rv = JS_Call(ctx, has, argv[0], 1, &item); + JS_FreeValue(ctx, item); + ok = JS_ToBoolFree(ctx, rv); // returns -1 if rv is JS_EXCEPTION + if (ok < 0) + goto exception; + found = (ok > 0); + } while (!found); + } + rval = !found ? JS_TRUE : JS_FALSE; +exception: + JS_FreeValue(ctx, has); + JS_FreeValue(ctx, keys); + JS_FreeValue(ctx, iter); + JS_FreeValue(ctx, next); + return rval; +} + +static JSValue js_set_isSubsetOf(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + JSValue item, iter, keys, has, next, rv, rval; + bool found; + JSMapState *s; + int64_t size; + int done, ok; + + has = JS_UNDEFINED; + iter = JS_UNDEFINED; + keys = JS_UNDEFINED; + next = JS_UNDEFINED; + rval = JS_EXCEPTION; + s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET); + if (!s) + goto exception; + // order matters! + if (js_setlike_get_size(ctx, argv[0], &size) < 0) + goto exception; + if (js_setlike_get_has(ctx, argv[0], &has) < 0) + goto exception; + if (js_setlike_get_keys(ctx, argv[0], &keys) < 0) + goto exception; + found = false; + if (s->record_count > size) + goto fini; + iter = js_create_map_iterator(ctx, this_val, 0, NULL, MAGIC_SET); + if (JS_IsException(iter)) + goto exception; + found = true; + do { + item = js_map_iterator_next(ctx, iter, 0, NULL, &done, MAGIC_SET); + if (JS_IsException(item)) + goto exception; + if (done) // item is JS_UNDEFINED + break; + rv = JS_Call(ctx, has, argv[0], 1, &item); + JS_FreeValue(ctx, item); + ok = JS_ToBoolFree(ctx, rv); // returns -1 if rv is JS_EXCEPTION + if (ok < 0) + goto exception; + found = (ok > 0); + } while (found); +fini: + rval = found ? JS_TRUE : JS_FALSE; +exception: + JS_FreeValue(ctx, has); + JS_FreeValue(ctx, keys); + JS_FreeValue(ctx, iter); + JS_FreeValue(ctx, next); + return rval; +} + +static JSValue js_set_isSupersetOf(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + JSValue item, iter, keys, has, next, rval; + int done; + bool found; + JSMapState *s; + int64_t size; + + has = JS_UNDEFINED; + iter = JS_UNDEFINED; + keys = JS_UNDEFINED; + next = JS_UNDEFINED; + rval = JS_EXCEPTION; + s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET); + if (!s) + goto exception; + // order matters! + if (js_setlike_get_size(ctx, argv[0], &size) < 0) + goto exception; + if (js_setlike_get_has(ctx, argv[0], &has) < 0) + goto exception; + if (js_setlike_get_keys(ctx, argv[0], &keys) < 0) + goto exception; + found = false; + if (s->record_count < size) + goto fini; + iter = JS_Call(ctx, keys, argv[0], 0, NULL); + if (JS_IsException(iter)) + goto exception; + next = JS_GetProperty(ctx, iter, JS_ATOM_next); + if (JS_IsException(next)) + goto exception; + found = true; + do { + item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done); + if (JS_IsException(item)) + goto exception; + if (done) // item is JS_UNDEFINED + break; + item = map_normalize_key(ctx, item); + found = (NULL != map_find_record(ctx, s, item)); + JS_FreeValue(ctx, item); + } while (found); +fini: + rval = found ? JS_TRUE : JS_FALSE; +exception: + JS_FreeValue(ctx, has); + JS_FreeValue(ctx, keys); + JS_FreeValue(ctx, iter); + JS_FreeValue(ctx, next); + return rval; +} + +static JSValue js_set_intersection(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + JSValue newset, item, iter, keys, has, next, rv; + JSMapState *s, *t; + JSMapRecord *mr; + int64_t size; + int done, ok; + + has = JS_UNDEFINED; + iter = JS_UNDEFINED; + keys = JS_UNDEFINED; + next = JS_UNDEFINED; + newset = JS_UNDEFINED; + s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET); + if (!s) + goto exception; + // order matters! + if (js_setlike_get_size(ctx, argv[0], &size) < 0) + goto exception; + if (js_setlike_get_has(ctx, argv[0], &has) < 0) + goto exception; + if (js_setlike_get_keys(ctx, argv[0], &keys) < 0) + goto exception; + if (s->record_count > size) { + iter = JS_Call(ctx, keys, argv[0], 0, NULL); + if (JS_IsException(iter)) + goto exception; + next = JS_GetProperty(ctx, iter, JS_ATOM_next); + if (JS_IsException(next)) + goto exception; + newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET); + if (JS_IsException(newset)) + goto exception; + t = JS_GetOpaque(newset, JS_CLASS_SET); + for (;;) { + item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done); + if (JS_IsException(item)) + goto exception; + if (done) // item is JS_UNDEFINED + break; + item = map_normalize_key(ctx, item); + if (!map_find_record(ctx, s, item)) { + JS_FreeValue(ctx, item); + } else if (map_find_record(ctx, t, item)) { + JS_FreeValue(ctx, item); // no duplicates + } else if ((mr = map_add_record(ctx, t, item))) { + mr->value = JS_UNDEFINED; + } else { + JS_FreeValue(ctx, item); + goto exception; + } + } + } else { + iter = js_create_map_iterator(ctx, this_val, 0, NULL, MAGIC_SET); + if (JS_IsException(iter)) + goto exception; + newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET); + if (JS_IsException(newset)) + goto exception; + t = JS_GetOpaque(newset, JS_CLASS_SET); + for (;;) { + item = js_map_iterator_next(ctx, iter, 0, NULL, &done, MAGIC_SET); + if (JS_IsException(item)) + goto exception; + if (done) // item is JS_UNDEFINED + break; + rv = JS_Call(ctx, has, argv[0], 1, &item); + ok = JS_ToBoolFree(ctx, rv); // returns -1 if rv is JS_EXCEPTION + if (ok > 0) { + item = map_normalize_key(ctx, item); + if (map_find_record(ctx, t, item)) { + JS_FreeValue(ctx, item); // no duplicates + } else if ((mr = map_add_record(ctx, t, item))) { + mr->value = JS_UNDEFINED; + } else { + JS_FreeValue(ctx, item); + goto exception; + } + } else { + JS_FreeValue(ctx, item); + if (ok < 0) + goto exception; + } + } + } + goto fini; +exception: + JS_FreeValue(ctx, newset); + newset = JS_EXCEPTION; +fini: + JS_FreeValue(ctx, has); + JS_FreeValue(ctx, keys); + JS_FreeValue(ctx, iter); + JS_FreeValue(ctx, next); + return newset; +} + +static JSValue js_set_difference(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + JSValue newset, item, iter, keys, has, next, rv; + JSMapState *s, *t; + JSMapRecord *mr; + int64_t size; + int done; + int ok; + + has = JS_UNDEFINED; + iter = JS_UNDEFINED; + keys = JS_UNDEFINED; + next = JS_UNDEFINED; + newset = JS_UNDEFINED; + s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET); + if (!s) + goto exception; + // order matters! + if (js_setlike_get_size(ctx, argv[0], &size) < 0) + goto exception; + if (js_setlike_get_has(ctx, argv[0], &has) < 0) + goto exception; + if (js_setlike_get_keys(ctx, argv[0], &keys) < 0) + goto exception; + if (s->record_count > size) { + iter = JS_Call(ctx, keys, argv[0], 0, NULL); + if (JS_IsException(iter)) + goto exception; + next = JS_GetProperty(ctx, iter, JS_ATOM_next); + if (JS_IsException(next)) + goto exception; + newset = js_map_constructor(ctx, JS_UNDEFINED, 1, &this_val, MAGIC_SET); + if (JS_IsException(newset)) + goto exception; + t = JS_GetOpaque(newset, JS_CLASS_SET); + for (;;) { + item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done); + if (JS_IsException(item)) + goto exception; + if (done) // item is JS_UNDEFINED + break; + item = map_normalize_key(ctx, item); + mr = map_find_record(ctx, t, item); + if (mr) + map_delete_record(ctx->rt, t, mr); + JS_FreeValue(ctx, item); + } + } else { + iter = js_create_map_iterator(ctx, this_val, 0, NULL, MAGIC_SET); + if (JS_IsException(iter)) + goto exception; + newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET); + if (JS_IsException(newset)) + goto exception; + t = JS_GetOpaque(newset, JS_CLASS_SET); + for (;;) { + item = js_map_iterator_next(ctx, iter, 0, NULL, &done, MAGIC_SET); + if (JS_IsException(item)) + goto exception; + if (done) // item is JS_UNDEFINED + break; + rv = JS_Call(ctx, has, argv[0], 1, &item); + ok = JS_ToBoolFree(ctx, rv); // returns -1 if rv is JS_EXCEPTION + if (ok == 0) { + item = map_normalize_key(ctx, item); + if (map_find_record(ctx, t, item)) { + JS_FreeValue(ctx, item); // no duplicates + } else if ((mr = map_add_record(ctx, t, item))) { + mr->value = JS_UNDEFINED; + } else { + JS_FreeValue(ctx, item); + goto exception; + } + } else { + JS_FreeValue(ctx, item); + if (ok < 0) + goto exception; + } + } + } + goto fini; +exception: + JS_FreeValue(ctx, newset); + newset = JS_EXCEPTION; +fini: + JS_FreeValue(ctx, has); + JS_FreeValue(ctx, keys); + JS_FreeValue(ctx, iter); + JS_FreeValue(ctx, next); + return newset; +} + +static JSValue js_set_symmetricDifference(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + JSValue newset, item, iter, next, rv; + struct list_head *el; + JSMapState *s, *t; + JSMapRecord *mr; + int64_t size; + int done; + bool present; + + s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET); + if (!s) + return JS_EXCEPTION; + // order matters! they're JS-observable side effects + if (js_setlike_get_size(ctx, argv[0], &size) < 0) + return JS_EXCEPTION; + if (js_setlike_get_has(ctx, argv[0], &rv) < 0) + return JS_EXCEPTION; + JS_FreeValue(ctx, rv); + newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET); + if (JS_IsException(newset)) + return JS_EXCEPTION; + t = JS_GetOpaque(newset, JS_CLASS_SET); + iter = JS_UNDEFINED; + next = JS_UNDEFINED; + // can't clone this_val using js_map_constructor(), + // test262 mandates we don't call the .add method + list_for_each(el, &s->records) { + mr = list_entry(el, JSMapRecord, link); + if (mr->empty) + continue; + mr = map_add_record(ctx, t, js_dup(mr->key)); + if (!mr) + goto exception; + mr->value = JS_UNDEFINED; + } + iter = JS_GetProperty(ctx, argv[0], JS_ATOM_keys); + if (JS_IsException(iter)) + goto exception; + iter = JS_CallFree(ctx, iter, argv[0], 0, NULL); + if (JS_IsException(iter)) + goto exception; + next = JS_GetProperty(ctx, iter, JS_ATOM_next); + if (JS_IsException(next)) + goto exception; + for (;;) { + item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done); + if (JS_IsException(item)) + goto exception; + if (done) // item is JS_UNDEFINED + break; + // note the subtlety here: due to mutating iterators, it's + // possible for keys to disappear during iteration; test262 + // still expects us to maintain insertion order though, so + // we first check |this|, then |new|; |new| is a copy of |this| + // - if item exists in |this|, delete (if it exists) from |new| + // - if item misses in |this| and |new|, add to |new| + // - if item exists in |new| but misses in |this|, *don't* add it, + // mutating iterator erased it + item = map_normalize_key(ctx, item); + present = (NULL != map_find_record(ctx, s, item)); + mr = map_find_record(ctx, t, item); + if (present) { + if (mr) + map_delete_record(ctx->rt, t, mr); + JS_FreeValue(ctx, item); + } else if (mr) { + JS_FreeValue(ctx, item); + } else { + mr = map_add_record(ctx, t, item); + if (!mr) { + JS_FreeValue(ctx, item); + goto exception; + } + mr->value = JS_UNDEFINED; + } + } + goto fini; +exception: + JS_FreeValue(ctx, newset); + newset = JS_EXCEPTION; +fini: + JS_FreeValue(ctx, next); + JS_FreeValue(ctx, iter); + return newset; +} + +static JSValue js_set_union(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + JSValue newset, item, iter, next, rv; + struct list_head *el; + JSMapState *s, *t; + JSMapRecord *mr; + int64_t size; + int done; + + s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET); + if (!s) + return JS_EXCEPTION; + // order matters! they're JS-observable side effects + if (js_setlike_get_size(ctx, argv[0], &size) < 0) + return JS_EXCEPTION; + if (js_setlike_get_has(ctx, argv[0], &rv) < 0) + return JS_EXCEPTION; + JS_FreeValue(ctx, rv); + newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET); + if (JS_IsException(newset)) + return JS_EXCEPTION; + t = JS_GetOpaque(newset, JS_CLASS_SET); + iter = JS_UNDEFINED; + next = JS_UNDEFINED; + list_for_each(el, &s->records) { + mr = list_entry(el, JSMapRecord, link); + if (mr->empty) + continue; + mr = map_add_record(ctx, t, js_dup(mr->key)); + if (!mr) + goto exception; + mr->value = JS_UNDEFINED; + } + iter = JS_GetProperty(ctx, argv[0], JS_ATOM_keys); + if (JS_IsException(iter)) + goto exception; + iter = JS_CallFree(ctx, iter, argv[0], 0, NULL); + if (JS_IsException(iter)) + goto exception; + next = JS_GetProperty(ctx, iter, JS_ATOM_next); + if (JS_IsException(next)) + goto exception; + for (;;) { + item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done); + if (JS_IsException(item)) + goto exception; + if (done) // item is JS_UNDEFINED + break; + rv = js_map_set(ctx, newset, 1, &item, MAGIC_SET); + JS_FreeValue(ctx, item); + if (JS_IsException(rv)) + goto exception; + JS_FreeValue(ctx, rv); + } + goto fini; +exception: + JS_FreeValue(ctx, newset); + newset = JS_EXCEPTION; +fini: + JS_FreeValue(ctx, next); + JS_FreeValue(ctx, iter); + return newset; +} + static const JSCFunctionListEntry js_map_funcs[] = { - JS_CFUNC_MAGIC_DEF("groupBy", 2, js_object_groupBy, 1 ), + JS_CFUNC_DEF("groupBy", 2, js_map_groupBy ), + JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ), +}; + +static const JSCFunctionListEntry js_set_funcs[] = { JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ), }; @@ -47899,6 +48563,13 @@ static const JSCFunctionListEntry js_set_proto_funcs[] = { JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, MAGIC_SET ), JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, MAGIC_SET ), JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, MAGIC_SET ), + JS_CFUNC_DEF("isDisjointFrom", 1, js_set_isDisjointFrom ), + JS_CFUNC_DEF("isSubsetOf", 1, js_set_isSubsetOf ), + JS_CFUNC_DEF("isSupersetOf", 1, js_set_isSupersetOf ), + JS_CFUNC_DEF("intersection", 1, js_set_intersection ), + JS_CFUNC_DEF("difference", 1, js_set_difference ), + JS_CFUNC_DEF("symmetricDifference", 1, js_set_symmetricDifference ), + JS_CFUNC_DEF("union", 1, js_set_union ), JS_CFUNC_MAGIC_DEF("values", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | MAGIC_SET ), JS_ALIAS_DEF("keys", "values" ), JS_ALIAS_DEF("[Symbol.iterator]", "values" ), @@ -47953,22 +48624,24 @@ void JS_AddIntrinsicMapSet(JSContext *ctx) for(i = 0; i < 4; i++) { const char *name = JS_AtomGetStr(ctx, buf, sizeof(buf), JS_ATOM_Map + i); - ctx->class_proto[JS_CLASS_MAP + i] = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_MAP + i], + int class_id = JS_CLASS_MAP + i; + ctx->class_proto[class_id] = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, ctx->class_proto[class_id], js_map_proto_funcs_ptr[i], js_map_proto_funcs_count[i]); obj1 = JS_NewCFunctionMagic(ctx, js_map_constructor, name, 0, JS_CFUNC_constructor_magic, i); - if (i < 2) { - JS_SetPropertyFunctionList(ctx, obj1, js_map_funcs, - countof(js_map_funcs)); - } - JS_NewGlobalCConstructor2(ctx, obj1, name, ctx->class_proto[JS_CLASS_MAP + i]); + if (class_id == JS_CLASS_MAP) + JS_SetPropertyFunctionList(ctx, obj1, js_map_funcs, countof(js_map_funcs)); + else if (class_id == JS_CLASS_SET) + JS_SetPropertyFunctionList(ctx, obj1, js_set_funcs, countof(js_set_funcs)); + + JS_NewGlobalCConstructor2(ctx, obj1, name, ctx->class_proto[class_id]); } for(i = 0; i < 2; i++) { ctx->class_proto[JS_CLASS_MAP_ITERATOR + i] = - JS_NewObjectProto(ctx, ctx->iterator_proto); + JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ITERATOR]); JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_MAP_ITERATOR + i], js_map_proto_funcs_ptr[i + 4], js_map_proto_funcs_count[i + 4]); @@ -47993,13 +48666,13 @@ typedef struct JSPromiseData { JSPromiseStateEnum promise_state; /* 0=fulfill, 1=reject, list of JSPromiseReactionData.link */ struct list_head promise_reactions[2]; - BOOL is_handled; /* Note: only useful to debug */ + bool is_handled; /* Note: only useful to debug */ JSValue promise_result; } JSPromiseData; typedef struct JSPromiseFunctionDataResolved { int ref_count; - BOOL already_resolved; + bool already_resolved; } JSPromiseFunctionDataResolved; typedef struct JSPromiseFunctionData { @@ -48013,7 +48686,7 @@ typedef struct JSPromiseReactionData { JSValue handler; } JSPromiseReactionData; -JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise) + JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise) { JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE); if (!s) @@ -48029,8 +48702,15 @@ JSValue JS_PromiseResult(JSContext *ctx, JSValue promise) return JS_DupValue(ctx, s->promise_result); } +bool JS_IsPromise(JSValue val) +{ + if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) + return false; + return JS_VALUE_GET_OBJ(val)->class_id == JS_CLASS_PROMISE; +} + static int js_create_resolving_functions(JSContext *ctx, JSValue *args, - JSValueConst promise); + JSValue promise); static void promise_reaction_data_free(JSRuntime *rt, JSPromiseReactionData *rd) @@ -48041,40 +48721,52 @@ static void promise_reaction_data_free(JSRuntime *rt, js_free_rt(rt, rd); } +#ifdef ENABLE_DUMPS // JS_DUMP_PROMISE +#define promise_trace(ctx, ...) \ + do { \ + if (check_dump_flag(ctx->rt, JS_DUMP_PROMISE)) \ + printf(__VA_ARGS__); \ + } while (0) +#else +#define promise_trace(...) +#endif + static JSValue promise_reaction_job(JSContext *ctx, int argc, - JSValueConst *argv) + JSValue *argv) { - JSValueConst handler, arg, func; + JSValue handler, arg, func; JSValue res, res2; - BOOL is_reject; + bool is_reject; assert(argc == 5); handler = argv[2]; is_reject = JS_ToBool(ctx, argv[3]); arg = argv[4]; -#ifdef DUMP_PROMISE - printf("promise_reaction_job: is_reject=%d\n", is_reject); -#endif + + promise_trace(ctx, "promise_reaction_job: is_reject=%d\n", is_reject); if (JS_IsUndefined(handler)) { if (is_reject) { - res = JS_Throw(ctx, JS_DupValue(ctx, arg)); + res = JS_Throw(ctx, js_dup(arg)); } else { - res = JS_DupValue(ctx, arg); + res = js_dup(arg); } } else { res = JS_Call(ctx, handler, JS_UNDEFINED, 1, &arg); } is_reject = JS_IsException(res); - if (is_reject) + if (is_reject) { + if (unlikely(JS_IsUncatchableError(ctx, ctx->rt->current_exception))) + return JS_EXCEPTION; res = JS_GetException(ctx); + } func = argv[is_reject]; /* as an extension, we support undefined as value to avoid creating a dummy promise in the 'await' implementation of async functions */ if (!JS_IsUndefined(func)) { res2 = JS_Call(ctx, func, JS_UNDEFINED, - 1, (JSValueConst *)&res); + 1, &res); } else { res2 = JS_UNDEFINED; } @@ -48091,25 +48783,25 @@ void JS_SetHostPromiseRejectionTracker(JSRuntime *rt, rt->host_promise_rejection_tracker_opaque = opaque; } -static void fulfill_or_reject_promise(JSContext *ctx, JSValueConst promise, - JSValueConst value, BOOL is_reject) +static void fulfill_or_reject_promise(JSContext *ctx, JSValue promise, + JSValue value, bool is_reject) { JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE); struct list_head *el, *el1; JSPromiseReactionData *rd; - JSValueConst args[5]; + JSValue args[5]; if (!s || s->promise_state != JS_PROMISE_PENDING) return; /* should never happen */ - set_value(ctx, &s->promise_result, JS_DupValue(ctx, value)); + set_value(ctx, &s->promise_result, js_dup(value)); s->promise_state = JS_PROMISE_FULFILLED + is_reject; -#ifdef DUMP_PROMISE - printf("fulfill_or_reject_promise: is_reject=%d\n", is_reject); -#endif + + promise_trace(ctx, "fulfill_or_reject_promise: is_reject=%d\n", is_reject); + if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) { JSRuntime *rt = ctx->rt; if (rt->host_promise_rejection_tracker) { - rt->host_promise_rejection_tracker(ctx, promise, value, FALSE, + rt->host_promise_rejection_tracker(ctx, promise, value, false, rt->host_promise_rejection_tracker_opaque); } } @@ -48119,7 +48811,7 @@ static void fulfill_or_reject_promise(JSContext *ctx, JSValueConst promise, args[0] = rd->resolving_funcs[0]; args[1] = rd->resolving_funcs[1]; args[2] = rd->handler; - args[3] = JS_NewBool(ctx, is_reject); + args[3] = js_bool(is_reject); args[4] = value; JS_EnqueueJob(ctx, promise_reaction_job, 5, args); list_del(&rd->link); @@ -48133,31 +48825,30 @@ static void fulfill_or_reject_promise(JSContext *ctx, JSValueConst promise, } } -static void reject_promise(JSContext *ctx, JSValueConst promise, - JSValueConst value) +static void reject_promise(JSContext *ctx, JSValue promise, + JSValue value) { - fulfill_or_reject_promise(ctx, promise, value, TRUE); + fulfill_or_reject_promise(ctx, promise, value, true); } static JSValue js_promise_resolve_thenable_job(JSContext *ctx, - int argc, JSValueConst *argv) + int argc, JSValue *argv) { - JSValueConst promise, thenable, then; + JSValue promise, thenable, then; JSValue args[2], res; -#ifdef DUMP_PROMISE - printf("js_promise_resolve_thenable_job\n"); -#endif + promise_trace(ctx, "js_promise_resolve_thenable_job\n"); + assert(argc == 3); promise = argv[0]; thenable = argv[1]; then = argv[2]; if (js_create_resolving_functions(ctx, args, promise) < 0) return JS_EXCEPTION; - res = JS_Call(ctx, then, thenable, 2, (JSValueConst *)args); + res = JS_Call(ctx, then, thenable, 2, args); if (JS_IsException(res)) { JSValue error = JS_GetException(ctx); - res = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error); + res = JS_Call(ctx, args[1], JS_UNDEFINED, 1, &error); JS_FreeValue(ctx, error); } JS_FreeValue(ctx, args[0]); @@ -48175,7 +48866,7 @@ static void js_promise_resolve_function_free_resolved(JSRuntime *rt, static int js_create_resolving_functions(JSContext *ctx, JSValue *resolving_funcs, - JSValueConst promise) + JSValue promise) { JSValue obj; @@ -48187,7 +48878,7 @@ static int js_create_resolving_functions(JSContext *ctx, if (!sr) return -1; sr->ref_count = 1; - sr->already_resolved = FALSE; /* must be shared between the two functions */ + sr->already_resolved = false; /* must be shared between the two functions */ ret = 0; for(i = 0; i < 2; i++) { obj = JS_NewObjectProtoClass(ctx, ctx->function_proto, @@ -48206,8 +48897,8 @@ static int js_create_resolving_functions(JSContext *ctx, } sr->ref_count++; s->presolved = sr; - s->promise = JS_DupValue(ctx, promise); - JS_SetOpaque(obj, s); + s->promise = js_dup(promise); + JS_SetOpaqueInternal(obj, s); js_function_set_properties(ctx, obj, JS_ATOM_empty_string, 1); resolving_funcs[i] = obj; } @@ -48225,7 +48916,7 @@ static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val) } } -static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val, +static void js_promise_resolve_function_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) { JSPromiseFunctionData *s = JS_VALUE_GET_OBJ(val)->u.promise_function_data; @@ -48235,30 +48926,32 @@ static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val, } static JSValue js_promise_resolve_function_call(JSContext *ctx, - JSValueConst func_obj, - JSValueConst this_val, - int argc, JSValueConst *argv, + JSValue func_obj, + JSValue this_val, + int argc, JSValue *argv, int flags) { JSObject *p = JS_VALUE_GET_OBJ(func_obj); JSPromiseFunctionData *s; - JSValueConst resolution, args[3]; + JSValue resolution, args[3]; JSValue then; - BOOL is_reject; + bool is_reject; s = p->u.promise_function_data; if (!s || s->presolved->already_resolved) return JS_UNDEFINED; - s->presolved->already_resolved = TRUE; + s->presolved->already_resolved = true; is_reject = p->class_id - JS_CLASS_PROMISE_RESOLVE_FUNCTION; if (argc > 0) resolution = argv[0]; else resolution = JS_UNDEFINED; -#ifdef DUMP_PROMISE - printf("js_promise_resolving_function_call: is_reject=%d resolution=", is_reject); - JS_DumpValue(ctx, resolution); - printf("\n"); +#ifdef ENABLE_DUMPS // JS_DUMP_PROMISE + if (check_dump_flag(ctx->rt, JS_DUMP_PROMISE)) { + printf("js_promise_resolving_function_call: is_reject=%d resolution=", is_reject); + JS_DumpValue(ctx->rt, resolution); + printf("\n"); + } #endif if (is_reject || !JS_IsObject(resolution)) { goto done; @@ -48306,7 +48999,7 @@ static void js_promise_finalizer(JSRuntime *rt, JSValue val) js_free_rt(rt, s); } -static void js_promise_mark(JSRuntime *rt, JSValueConst val, +static void js_promise_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) { JSPromiseData *s = JS_GetOpaque(val, JS_CLASS_PROMISE); @@ -48327,10 +49020,10 @@ static void js_promise_mark(JSRuntime *rt, JSValueConst val, JS_MarkValue(rt, s->promise_result, mark_func); } -static JSValue js_promise_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) +static JSValue js_promise_constructor(JSContext *ctx, JSValue new_target, + int argc, JSValue *argv) { - JSValueConst executor; + JSValue executor; JSValue obj; JSPromiseData *s; JSValue args[2], ret; @@ -48346,18 +49039,18 @@ static JSValue js_promise_constructor(JSContext *ctx, JSValueConst new_target, if (!s) goto fail; s->promise_state = JS_PROMISE_PENDING; - s->is_handled = FALSE; + s->is_handled = false; for(i = 0; i < 2; i++) init_list_head(&s->promise_reactions[i]); s->promise_result = JS_UNDEFINED; - JS_SetOpaque(obj, s); + JS_SetOpaqueInternal(obj, s); if (js_create_resolving_functions(ctx, args, obj)) goto fail; - ret = JS_Call(ctx, executor, JS_UNDEFINED, 2, (JSValueConst *)args); + ret = JS_Call(ctx, executor, JS_UNDEFINED, 2, args); if (JS_IsException(ret)) { JSValue ret2, error; error = JS_GetException(ctx); - ret2 = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error); + ret2 = JS_Call(ctx, args[1], JS_UNDEFINED, 1, &error); JS_FreeValue(ctx, error); if (JS_IsException(ret2)) goto fail1; @@ -48376,8 +49069,8 @@ static JSValue js_promise_constructor(JSContext *ctx, JSValueConst new_target, } static JSValue js_promise_executor(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv, + JSValue this_val, + int argc, JSValue *argv, int magic, JSValue *func_data) { int i; @@ -48385,14 +49078,14 @@ static JSValue js_promise_executor(JSContext *ctx, for(i = 0; i < 2; i++) { if (!JS_IsUndefined(func_data[i])) return JS_ThrowTypeError(ctx, "resolving function already set"); - func_data[i] = JS_DupValue(ctx, argv[i]); + func_data[i] = js_dup(argv[i]); } return JS_UNDEFINED; } static JSValue js_promise_executor_new(JSContext *ctx) { - JSValueConst func_data[2]; + JSValue func_data[2]; func_data[0] = JS_UNDEFINED; func_data[1] = JS_UNDEFINED; @@ -48402,7 +49095,7 @@ static JSValue js_promise_executor_new(JSContext *ctx) static JSValue js_new_promise_capability(JSContext *ctx, JSValue *resolving_funcs, - JSValueConst ctor) + JSValue ctor) { JSValue executor, result_promise; JSCFunctionDataRecord *s; @@ -48414,10 +49107,10 @@ static JSValue js_new_promise_capability(JSContext *ctx, if (JS_IsUndefined(ctor)) { result_promise = js_promise_constructor(ctx, ctor, 1, - (JSValueConst *)&executor); + &executor); } else { result_promise = JS_CallConstructor(ctx, ctor, 1, - (JSValueConst *)&executor); + &executor); } if (JS_IsException(result_promise)) goto fail; @@ -48427,7 +49120,7 @@ static JSValue js_new_promise_capability(JSContext *ctx, goto fail; } for(i = 0; i < 2; i++) - resolving_funcs[i] = JS_DupValue(ctx, s->data[i]); + resolving_funcs[i] = js_dup(s->data[i]); JS_FreeValue(ctx, executor); return result_promise; fail: @@ -48441,24 +49134,24 @@ JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs) return js_new_promise_capability(ctx, resolving_funcs, JS_UNDEFINED); } -static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) +static JSValue js_promise_resolve(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { JSValue result_promise, resolving_funcs[2], ret; - BOOL is_reject = magic; + bool is_reject = magic; if (!JS_IsObject(this_val)) return JS_ThrowTypeErrorNotAnObject(ctx); if (!is_reject && JS_GetOpaque(argv[0], JS_CLASS_PROMISE)) { JSValue ctor; - BOOL is_same; + bool is_same; ctor = JS_GetProperty(ctx, argv[0], JS_ATOM_constructor); if (JS_IsException(ctor)) return ctor; is_same = js_same_value(ctx, ctor, this_val); JS_FreeValue(ctx, ctor); if (is_same) - return JS_DupValue(ctx, argv[0]); + return js_dup(argv[0]); } result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val); if (JS_IsException(result_promise)) @@ -48474,16 +49167,15 @@ static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val, return result_promise; } -static JSValue js_promise_withResolvers(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_promise_withResolvers(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue result_promise, resolving_funcs[2], obj; if (!JS_IsObject(this_val)) return JS_ThrowTypeErrorNotAnObject(ctx); result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val); if (JS_IsException(result_promise)) - return result_promise; + return JS_EXCEPTION; obj = JS_NewObject(ctx); if (JS_IsException(obj)) { JS_FreeValue(ctx, resolving_funcs[0]); @@ -48497,8 +49189,36 @@ static JSValue js_promise_withResolvers(JSContext *ctx, return obj; } +static JSValue js_promise_try(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + JSValue result_promise, resolving_funcs[2], ret, ret2; + bool is_reject = 0; + + if (!JS_IsObject(this_val)) + return JS_ThrowTypeErrorNotAnObject(ctx); + result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val); + if (JS_IsException(result_promise)) + return result_promise; + ret = JS_Call(ctx, argv[0], JS_UNDEFINED, argc - 1, argv + 1); + if (JS_IsException(ret)) { + is_reject = 1; + ret = JS_GetException(ctx); + } + ret2 = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED, 1, &ret); + JS_FreeValue(ctx, resolving_funcs[0]); + JS_FreeValue(ctx, resolving_funcs[1]); + JS_FreeValue(ctx, ret); + if (JS_IsException(ret2)) { + JS_FreeValue(ctx, result_promise); + return ret2; + } + JS_FreeValue(ctx, ret2); + return result_promise; +} + static __exception int remainingElementsCount_add(JSContext *ctx, - JSValueConst resolve_element_env, + JSValue resolve_element_env, int addend) { JSValue val; @@ -48511,7 +49231,7 @@ static __exception int remainingElementsCount_add(JSContext *ctx, return -1; remainingElementsCount += addend; if (JS_SetPropertyUint32(ctx, resolve_element_env, 0, - JS_NewInt32(ctx, remainingElementsCount)) < 0) + js_int32(remainingElementsCount)) < 0) return -1; return (remainingElementsCount == 0); } @@ -48521,17 +49241,17 @@ static __exception int remainingElementsCount_add(JSContext *ctx, #define PROMISE_MAGIC_any 2 static JSValue js_promise_all_resolve_element(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv, + JSValue this_val, + int argc, JSValue *argv, int magic, JSValue *func_data) { int resolve_type = magic & 3; int is_reject = magic & 4; - BOOL alreadyCalled = JS_ToBool(ctx, func_data[0]); - JSValueConst values = func_data[2]; - JSValueConst resolve = func_data[3]; - JSValueConst resolve_element_env = func_data[4]; + bool alreadyCalled = JS_ToBool(ctx, func_data[0]); + JSValue values = func_data[2]; + JSValue resolve = func_data[3]; + JSValue resolve_element_env = func_data[4]; JSValue ret, obj; int is_zero, index; @@ -48539,7 +49259,7 @@ static JSValue js_promise_all_resolve_element(JSContext *ctx, return JS_EXCEPTION; if (alreadyCalled) return JS_UNDEFINED; - func_data[0] = JS_NewBool(ctx, TRUE); + func_data[0] = JS_TRUE; if (resolve_type == PROMISE_MAGIC_allSettled) { JSValue str; @@ -48547,7 +49267,7 @@ static JSValue js_promise_all_resolve_element(JSContext *ctx, obj = JS_NewObject(ctx); if (JS_IsException(obj)) return JS_EXCEPTION; - str = JS_NewString(ctx, is_reject ? "rejected" : "fulfilled"); + str = js_new_string8(ctx, is_reject ? "rejected" : "fulfilled"); if (JS_IsException(str)) goto fail1; if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_status, @@ -48556,14 +49276,14 @@ static JSValue js_promise_all_resolve_element(JSContext *ctx, goto fail1; if (JS_DefinePropertyValue(ctx, obj, is_reject ? JS_ATOM_reason : JS_ATOM_value, - JS_DupValue(ctx, argv[0]), + js_dup(argv[0]), JS_PROP_C_W_E) < 0) { fail1: JS_FreeValue(ctx, obj); return JS_EXCEPTION; } } else { - obj = JS_DupValue(ctx, argv[0]); + obj = js_dup(argv[0]); } if (JS_DefinePropertyValueUint32(ctx, values, index, obj, JS_PROP_C_W_E) < 0) @@ -48578,10 +49298,10 @@ static JSValue js_promise_all_resolve_element(JSContext *ctx, error = js_aggregate_error_constructor(ctx, values); if (JS_IsException(error)) return JS_EXCEPTION; - ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&error); + ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, &error); JS_FreeValue(ctx, error); } else { - ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&values); + ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, &values); } if (JS_IsException(ret)) return ret; @@ -48591,16 +49311,15 @@ static JSValue js_promise_all_resolve_element(JSContext *ctx, } /* magic = 0: Promise.all 1: Promise.allSettled */ -static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) +static JSValue js_promise_all(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { JSValue result_promise, resolving_funcs[2], item, next_promise, ret; JSValue next_method = JS_UNDEFINED, values = JS_UNDEFINED; JSValue resolve_element_env = JS_UNDEFINED, resolve_element, reject_element; JSValue promise_resolve = JS_UNDEFINED, iter = JS_UNDEFINED; - JSValueConst then_args[2], resolve_element_data[5]; - BOOL done; - int index, is_zero, is_promise_any = (magic == PROMISE_MAGIC_any); + JSValue then_args[2], resolve_element_data[5]; + int done, index, is_zero, is_promise_any = (magic == PROMISE_MAGIC_any); if (!JS_IsObject(this_val)) return JS_ThrowTypeErrorNotAnObject(ctx); @@ -48611,13 +49330,13 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, if (JS_IsException(promise_resolve) || check_function(ctx, promise_resolve)) goto fail_reject; - iter = JS_GetIterator(ctx, argv[0], FALSE); + iter = JS_GetIterator(ctx, argv[0], false); if (JS_IsException(iter)) { JSValue error; fail_reject: error = JS_GetException(ctx); ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1, - (JSValueConst *)&error); + &error); JS_FreeValue(ctx, error); if (JS_IsException(ret)) goto fail; @@ -48634,7 +49353,7 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, goto fail_reject; /* remainingElementsCount field */ if (JS_DefinePropertyValueUint32(ctx, resolve_element_env, 0, - JS_NewInt32(ctx, 1), + js_int32(1), JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0) goto fail_reject; @@ -48648,15 +49367,15 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, if (done) break; next_promise = JS_Call(ctx, promise_resolve, - this_val, 1, (JSValueConst *)&item); + this_val, 1, &item); JS_FreeValue(ctx, item); if (JS_IsException(next_promise)) { fail_reject1: - JS_IteratorClose(ctx, iter, TRUE); + JS_IteratorClose(ctx, iter, true); goto fail_reject; } - resolve_element_data[0] = JS_NewBool(ctx, FALSE); - resolve_element_data[1] = JS_NewInt32(ctx, index); + resolve_element_data[0] = JS_FALSE; + resolve_element_data[1] = js_int32(index); resolve_element_data[2] = values; resolve_element_data[3] = resolving_funcs[is_promise_any]; resolve_element_data[4] = resolve_element_env; @@ -48681,9 +49400,9 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, JS_UNDEFINED, JS_PROP_C_W_E) < 0) goto fail_reject1; reject_element = resolve_element; - resolve_element = JS_DupValue(ctx, resolving_funcs[0]); + resolve_element = js_dup(resolving_funcs[0]); } else { - reject_element = JS_DupValue(ctx, resolving_funcs[1]); + reject_element = js_dup(resolving_funcs[1]); } if (remainingElementsCount_add(ctx, resolve_element_env, 1) < 0) { @@ -48716,7 +49435,7 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, values = error; } ret = JS_Call(ctx, resolving_funcs[is_promise_any], JS_UNDEFINED, - 1, (JSValueConst *)&values); + 1, &values); if (check_exception_free(ctx, ret)) goto fail_reject; } @@ -48736,13 +49455,13 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, goto done; } -static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_promise_race(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue result_promise, resolving_funcs[2], item, next_promise, ret; JSValue next_method = JS_UNDEFINED, iter = JS_UNDEFINED; JSValue promise_resolve = JS_UNDEFINED; - BOOL done; + int done; if (!JS_IsObject(this_val)) return JS_ThrowTypeErrorNotAnObject(ctx); @@ -48753,13 +49472,13 @@ static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val, if (JS_IsException(promise_resolve) || check_function(ctx, promise_resolve)) goto fail_reject; - iter = JS_GetIterator(ctx, argv[0], FALSE); + iter = JS_GetIterator(ctx, argv[0], false); if (JS_IsException(iter)) { JSValue error; fail_reject: error = JS_GetException(ctx); ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1, - (JSValueConst *)&error); + &error); JS_FreeValue(ctx, error); if (JS_IsException(ret)) goto fail; @@ -48778,15 +49497,15 @@ static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val, if (done) break; next_promise = JS_Call(ctx, promise_resolve, - this_val, 1, (JSValueConst *)&item); + this_val, 1, &item); JS_FreeValue(ctx, item); if (JS_IsException(next_promise)) { fail_reject1: - JS_IteratorClose(ctx, iter, TRUE); + JS_IteratorClose(ctx, iter, true); goto fail_reject; } ret = JS_InvokeFree(ctx, next_promise, JS_ATOM_then, 2, - (JSValueConst *)resolving_funcs); + resolving_funcs); if (check_exception_free(ctx, ret)) goto fail_reject1; } @@ -48806,9 +49525,9 @@ static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val, } static __exception int perform_promise_then(JSContext *ctx, - JSValueConst promise, - JSValueConst *resolve_reject, - JSValueConst *cap_resolving_funcs) + JSValue promise, + JSValue *resolve_reject, + JSValue *cap_resolving_funcs) { JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE); JSPromiseReactionData *rd_array[2], *rd; @@ -48817,7 +49536,7 @@ static __exception int perform_promise_then(JSContext *ctx, rd_array[0] = NULL; rd_array[1] = NULL; for(i = 0; i < 2; i++) { - JSValueConst handler; + JSValue handler; rd = js_mallocz(ctx, sizeof(*rd)); if (!rd) { if (i == 1) @@ -48825,11 +49544,11 @@ static __exception int perform_promise_then(JSContext *ctx, return -1; } for(j = 0; j < 2; j++) - rd->resolving_funcs[j] = JS_DupValue(ctx, cap_resolving_funcs[j]); + rd->resolving_funcs[j] = js_dup(cap_resolving_funcs[j]); handler = resolve_reject[i]; if (!JS_IsFunction(ctx, handler)) handler = JS_UNDEFINED; - rd->handler = JS_DupValue(ctx, handler); + rd->handler = js_dup(handler); rd_array[i] = rd; } @@ -48837,12 +49556,12 @@ static __exception int perform_promise_then(JSContext *ctx, for(i = 0; i < 2; i++) list_add_tail(&rd_array[i]->link, &s->promise_reactions[i]); } else { - JSValueConst args[5]; + JSValue args[5]; if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) { JSRuntime *rt = ctx->rt; if (rt->host_promise_rejection_tracker) { rt->host_promise_rejection_tracker(ctx, promise, s->promise_result, - TRUE, rt->host_promise_rejection_tracker_opaque); + true, rt->host_promise_rejection_tracker_opaque); } } i = s->promise_state - JS_PROMISE_FULFILLED; @@ -48850,18 +49569,18 @@ static __exception int perform_promise_then(JSContext *ctx, args[0] = rd->resolving_funcs[0]; args[1] = rd->resolving_funcs[1]; args[2] = rd->handler; - args[3] = JS_NewBool(ctx, i); + args[3] = js_bool(i); args[4] = s->promise_result; JS_EnqueueJob(ctx, promise_reaction_job, 5, args); for(i = 0; i < 2; i++) promise_reaction_data_free(ctx->rt, rd_array[i]); } - s->is_handled = TRUE; + s->is_handled = true; return 0; } -static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_promise_then(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue ctor, result_promise, resolving_funcs[2]; JSPromiseData *s; @@ -48879,7 +49598,7 @@ static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val, if (JS_IsException(result_promise)) return result_promise; ret = perform_promise_then(ctx, this_val, argv, - (JSValueConst *)resolving_funcs); + resolving_funcs); for(i = 0; i < 2; i++) JS_FreeValue(ctx, resolving_funcs[i]); if (ret) { @@ -48889,41 +49608,41 @@ static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val, return result_promise; } -static JSValue js_promise_catch(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_promise_catch(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - JSValueConst args[2]; + JSValue args[2]; args[0] = JS_UNDEFINED; args[1] = argv[0]; return JS_Invoke(ctx, this_val, JS_ATOM_then, 2, args); } -static JSValue js_promise_finally_value_thunk(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, +static JSValue js_promise_finally_value_thunk(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic, JSValue *func_data) { - return JS_DupValue(ctx, func_data[0]); + return js_dup(func_data[0]); } -static JSValue js_promise_finally_thrower(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, +static JSValue js_promise_finally_thrower(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic, JSValue *func_data) { - return JS_Throw(ctx, JS_DupValue(ctx, func_data[0])); + return JS_Throw(ctx, js_dup(func_data[0])); } -static JSValue js_promise_then_finally_func(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, +static JSValue js_promise_then_finally_func(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic, JSValue *func_data) { - JSValueConst ctor = func_data[0]; - JSValueConst onFinally = func_data[1]; + JSValue ctor = func_data[0]; + JSValue onFinally = func_data[1]; JSValue res, promise, ret, then_func; res = JS_Call(ctx, onFinally, JS_UNDEFINED, 0, NULL); if (JS_IsException(res)) return res; - promise = js_promise_resolve(ctx, ctor, 1, (JSValueConst *)&res, 0); + promise = js_promise_resolve(ctx, ctor, 1, &res, 0); JS_FreeValue(ctx, res); if (JS_IsException(promise)) return promise; @@ -48938,26 +49657,26 @@ static JSValue js_promise_then_finally_func(JSContext *ctx, JSValueConst this_va JS_FreeValue(ctx, promise); return then_func; } - ret = JS_InvokeFree(ctx, promise, JS_ATOM_then, 1, (JSValueConst *)&then_func); + ret = JS_InvokeFree(ctx, promise, JS_ATOM_then, 1, &then_func); JS_FreeValue(ctx, then_func); return ret; } -static JSValue js_promise_finally(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_promise_finally(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - JSValueConst onFinally = argv[0]; + JSValue onFinally = argv[0]; JSValue ctor, ret; JSValue then_funcs[2]; - JSValueConst func_data[2]; + JSValue func_data[2]; int i; ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED); if (JS_IsException(ctor)) return ctor; if (!JS_IsFunction(ctx, onFinally)) { - then_funcs[0] = JS_DupValue(ctx, onFinally); - then_funcs[1] = JS_DupValue(ctx, onFinally); + then_funcs[0] = js_dup(onFinally); + then_funcs[1] = js_dup(onFinally); } else { func_data[0] = ctor; func_data[1] = onFinally; @@ -48972,7 +49691,7 @@ static JSValue js_promise_finally(JSContext *ctx, JSValueConst this_val, } } JS_FreeValue(ctx, ctor); - ret = JS_Invoke(ctx, this_val, JS_ATOM_then, 2, (JSValueConst *)then_funcs); + ret = JS_Invoke(ctx, this_val, JS_ATOM_then, 2, then_funcs); JS_FreeValue(ctx, then_funcs[0]); JS_FreeValue(ctx, then_funcs[1]); return ret; @@ -48984,6 +49703,7 @@ static const JSCFunctionListEntry js_promise_funcs[] = { JS_CFUNC_MAGIC_DEF("all", 1, js_promise_all, PROMISE_MAGIC_all ), JS_CFUNC_MAGIC_DEF("allSettled", 1, js_promise_all, PROMISE_MAGIC_allSettled ), JS_CFUNC_MAGIC_DEF("any", 1, js_promise_all, PROMISE_MAGIC_any ), + JS_CFUNC_DEF("try", 1, js_promise_try ), JS_CFUNC_DEF("race", 1, js_promise_race ), JS_CFUNC_DEF("withResolvers", 0, js_promise_withResolvers ), JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL), @@ -49002,20 +49722,20 @@ static const JSCFunctionListEntry js_async_function_proto_funcs[] = { }; static JSValue js_async_from_sync_iterator_unwrap(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv, + JSValue this_val, + int argc, JSValue *argv, int magic, JSValue *func_data) { - return js_create_iterator_result(ctx, JS_DupValue(ctx, argv[0]), + return js_create_iterator_result(ctx, js_dup(argv[0]), JS_ToBool(ctx, func_data[0])); } static JSValue js_async_from_sync_iterator_unwrap_func_create(JSContext *ctx, - BOOL done) + bool done) { - JSValueConst func_data[1]; + JSValue func_data[1]; - func_data[0] = JS_NewBool(ctx, done); + func_data[0] = js_bool(done); return JS_NewCFunctionData(ctx, js_async_from_sync_iterator_unwrap, 1, 0, 1, func_data); } @@ -49044,7 +49764,7 @@ static void js_async_from_sync_iterator_finalizer(JSRuntime *rt, JSValue val) } } -static void js_async_from_sync_iterator_mark(JSRuntime *rt, JSValueConst val, +static void js_async_from_sync_iterator_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) { JSAsyncFromSyncIteratorData *s = @@ -49056,7 +49776,7 @@ static void js_async_from_sync_iterator_mark(JSRuntime *rt, JSValueConst val, } static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx, - JSValueConst sync_iter) + JSValue sync_iter) { JSValue async_iter, next_method; JSAsyncFromSyncIteratorData *s; @@ -49075,14 +49795,14 @@ static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx, JS_FreeValue(ctx, next_method); return JS_EXCEPTION; } - s->sync_iter = JS_DupValue(ctx, sync_iter); + s->sync_iter = js_dup(sync_iter); s->next_method = next_method; - JS_SetOpaque(async_iter, s); + JS_SetOpaqueInternal(async_iter, s); return async_iter; } -static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, +static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { JSValue promise, resolving_funcs[2], value, err, method; @@ -49100,7 +49820,7 @@ static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst thi } if (magic == GEN_MAGIC_NEXT) { - method = JS_DupValue(ctx, s->next_method); + method = js_dup(s->next_method); } else { method = JS_GetProperty(ctx, s->sync_iter, magic == GEN_MAGIC_RETURN ? JS_ATOM_return : @@ -49109,10 +49829,11 @@ static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst thi goto reject; if (JS_IsUndefined(method) || JS_IsNull(method)) { if (magic == GEN_MAGIC_RETURN) { - err = js_create_iterator_result(ctx, JS_DupValue(ctx, argv[0]), TRUE); + err = js_create_iterator_result(ctx, js_dup(argv[0]), true); is_reject = 0; } else { - err = JS_DupValue(ctx, argv[0]); + err = JS_MakeError(ctx, JS_TYPE_ERROR, "throw is not a method", + true); is_reject = 1; } goto done_resolve; @@ -49138,7 +49859,7 @@ static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst thi is_reject = 1; done_resolve: res2 = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED, - 1, (JSValueConst *)&err); + 1, &err); JS_FreeValue(ctx, err); JS_FreeValue(ctx, res2); JS_FreeValue(ctx, resolving_funcs[0]); @@ -49150,7 +49871,7 @@ static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst thi int res; value_wrapper_promise = js_promise_resolve(ctx, ctx->promise_ctor, - 1, (JSValueConst *)&value, 0); + 1, &value, 0); if (JS_IsException(value_wrapper_promise)) { JS_FreeValue(ctx, value); goto reject; @@ -49166,8 +49887,8 @@ static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst thi resolve_reject[1] = JS_UNDEFINED; res = perform_promise_then(ctx, value_wrapper_promise, - (JSValueConst *)resolve_reject, - (JSValueConst *)resolving_funcs); + resolve_reject, + resolving_funcs); JS_FreeValue(ctx, resolve_reject[0]); JS_FreeValue(ctx, value_wrapper_promise); JS_FreeValue(ctx, resolving_funcs[0]); @@ -49242,16 +49963,20 @@ void JS_AddIntrinsicPromise(JSContext *ctx) countof(js_promise_proto_funcs)); obj1 = JS_NewCFunction2(ctx, js_promise_constructor, "Promise", 1, JS_CFUNC_constructor, 0); - ctx->promise_ctor = JS_DupValue(ctx, obj1); + ctx->promise_ctor = js_dup(obj1); JS_SetPropertyFunctionList(ctx, obj1, js_promise_funcs, countof(js_promise_funcs)); JS_NewGlobalCConstructor2(ctx, obj1, "Promise", ctx->class_proto[JS_CLASS_PROMISE]); + /* Used to squelch a -Wcast-function-type warning. */ + JSCFunctionType ft; + /* AsyncFunction */ ctx->class_proto[JS_CLASS_ASYNC_FUNCTION] = JS_NewObjectProto(ctx, ctx->function_proto); - obj1 = JS_NewCFunction3(ctx, (JSCFunction *)js_function_constructor, + ft.generic_magic = js_function_constructor; + obj1 = JS_NewCFunction3(ctx, ft.generic, "AsyncFunction", 1, JS_CFUNC_constructor_or_func_magic, JS_FUNC_ASYNC, ctx->function_ctor); @@ -49287,7 +50012,8 @@ void JS_AddIntrinsicPromise(JSContext *ctx) /* AsyncGeneratorFunction */ ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION] = JS_NewObjectProto(ctx, ctx->function_proto); - obj1 = JS_NewCFunction3(ctx, (JSCFunction *)js_function_constructor, + ft.generic_magic = js_function_constructor; + obj1 = JS_NewCFunction3(ctx, ft.generic, "AsyncGeneratorFunction", 1, JS_CFUNC_constructor_or_func_magic, JS_FUNC_ASYNC_GENERATOR, @@ -49320,7 +50046,7 @@ static int isURIReserved(int c) { return c < 0x100 && memchr(";/?:@&=+$,#", c, sizeof(";/?:@&=+$,#") - 1) != NULL; } -static int FORMAT_ATTR(2, 3) js_throw_URIError(JSContext *ctx, const char *fmt, ...) +static int JS_PRINTF_FORMAT_ATTR(2, 3) js_throw_URIError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...) { va_list ap; @@ -49341,8 +50067,8 @@ static int hex_decode(JSContext *ctx, JSString *p, int k) { return c; } -static JSValue js_global_decodeURI(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int isComponent) +static JSValue js_global_decodeURI(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int isComponent) { JSValue str; StringBuffer b_s, *b = &b_s; @@ -49452,8 +50178,8 @@ static int encodeURI_hex(StringBuffer *b, int c) { return string_buffer_write8(b, buf, n); } -static JSValue js_global_encodeURI(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, +static JSValue js_global_encodeURI(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int isComponent) { JSValue str; @@ -49517,8 +50243,8 @@ static JSValue js_global_encodeURI(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static JSValue js_global_escape(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_global_escape(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue str; StringBuffer b_s, *b = &b_s; @@ -49543,8 +50269,8 @@ static JSValue js_global_escape(JSContext *ctx, JSValueConst this_val, return string_buffer_end(b); } -static JSValue js_global_unescape(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_global_unescape(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue str; StringBuffer b_s, *b = &b_s; @@ -49585,6 +50311,7 @@ static const JSCFunctionListEntry js_global_funcs[] = { JS_CFUNC_DEF("parseFloat", 1, js_parseFloat ), JS_CFUNC_DEF("isNaN", 1, js_global_isNaN ), JS_CFUNC_DEF("isFinite", 1, js_global_isFinite ), + JS_CFUNC_DEF("queueMicrotask", 1, js_global_queueMicrotask ), JS_CFUNC_MAGIC_DEF("decodeURI", 1, js_global_decodeURI, 0 ), JS_CFUNC_MAGIC_DEF("decodeURIComponent", 1, js_global_decodeURI, 1 ), @@ -49593,7 +50320,7 @@ static const JSCFunctionListEntry js_global_funcs[] = { JS_CFUNC_DEF("escape", 1, js_global_escape ), JS_CFUNC_DEF("unescape", 1, js_global_unescape ), JS_PROP_DOUBLE_DEF("Infinity", 1.0 / 0.0, 0 ), - JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ), + JS_PROP_U2D_DEF("NaN", 0x7FF8ull<<48, 0 ), // workaround for msvc JS_PROP_UNDEFINED_DEF("undefined", 0 ), JS_PROP_STRING_DEF("[Symbol.toStringTag]", "global", JS_PROP_CONFIGURABLE ), }; @@ -49606,16 +50333,16 @@ static int64_t math_mod(int64_t a, int64_t b) { return m + (m < 0) * b; } -static int64_t floor_div(int64_t a, int64_t b) { +static int64_t floor_div_int64(int64_t a, int64_t b) { /* integer division rounding toward -Infinity */ int64_t m = a % b; return (a - (m + (m < 0) * b)) / b; } -static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv); +static JSValue js_Date_parse(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv); -static __exception int JS_ThisTimeValue(JSContext *ctx, double *valp, JSValueConst this_val) +static __exception int JS_ThisTimeValue(JSContext *ctx, double *valp, JSValue this_val) { if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) { JSObject *p = JS_VALUE_GET_OBJ(this_val); @@ -49626,22 +50353,22 @@ static __exception int JS_ThisTimeValue(JSContext *ctx, double *valp, JSValueCon return -1; } -static JSValue JS_SetThisTimeValue(JSContext *ctx, JSValueConst this_val, double v) +static JSValue JS_SetThisTimeValue(JSContext *ctx, JSValue this_val, double v) { if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) { 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); - return JS_DupValue(ctx, p->u.object_data); + p->u.object_data = js_float64(v); + return js_dup(p->u.object_data); } } return JS_ThrowTypeError(ctx, "not a Date object"); } static int64_t days_from_year(int64_t y) { - return 365 * (y - 1970) + floor_div(y - 1969, 4) - - floor_div(y - 1901, 100) + floor_div(y - 1601, 400); + return 365 * (y - 1970) + floor_div_int64(y - 1969, 4) - + floor_div_int64(y - 1901, 100) + floor_div_int64(y - 1601, 400); } static int64_t days_in_year(int64_t y) { @@ -49651,7 +50378,7 @@ static int64_t days_in_year(int64_t y) { /* return the year, update days */ static int64_t year_from_days(int64_t *days) { int64_t y, d1, nd, d = *days; - y = floor_div(d * 10000, 3652425) + 1970; + y = floor_div_int64(d * 10000, 3652425) + 1970; /* the initial approximation is very good, so only a few iterations are necessary */ for(;;) { @@ -49675,8 +50402,9 @@ static int const month_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 static char const month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; static char const day_names[] = "SunMonTueWedThuFriSat"; -static __exception int get_date_fields(JSContext *ctx, JSValueConst obj, - double fields[minimum_length(9)], int is_local, int force) +static __exception int get_date_fields(JSContext *ctx, JSValue obj, + double fields[minimum_length(9)], + int is_local, int force) { double dval; int64_t d, days, wd, y, i, md, h, m, s, ms, tz = 0; @@ -49686,7 +50414,7 @@ static __exception int get_date_fields(JSContext *ctx, JSValueConst obj, if (isnan(dval)) { if (!force) - return FALSE; /* NaN */ + return false; /* NaN */ d = 0; /* initialize all fields to 0 */ } else { d = dval; /* assuming -8.64e15 <= dval <= -8.64e15 */ @@ -49725,7 +50453,7 @@ static __exception int get_date_fields(JSContext *ctx, JSValueConst obj, fields[6] = ms; fields[7] = wd; fields[8] = tz; - return TRUE; + return true; } static double time_clip(double t) { @@ -49794,8 +50522,8 @@ static double set_date_fields(double fields[minimum_length(7)], int is_local) { return time_clip(tv); } -static JSValue get_date_field(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) +static JSValue get_date_field(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { // get_date_field(obj, n, is_local) double fields[9]; @@ -49812,11 +50540,11 @@ static JSValue get_date_field(JSContext *ctx, JSValueConst this_val, if (magic & 0x100) { // getYear fields[0] -= 1900; } - return JS_NewFloat64(ctx, fields[n]); + return js_number(fields[n]); } -static JSValue set_date_field(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) +static JSValue set_date_field(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { // _field(obj, first_field, end_field, args, is_local) double fields[9]; @@ -49838,10 +50566,14 @@ static JSValue set_date_field(JSContext *ctx, JSValueConst this_val, if (JS_ToFloat64(ctx, &a, argv[i])) return JS_EXCEPTION; if (!isfinite(a)) - res = FALSE; + res = false; fields[first_field + i] = trunc(a); } - if (res && argc > 0) + + if (!res) + return JS_NAN; + + if (argc > 0) d = set_date_fields(fields, is_local); return JS_SetThisTimeValue(ctx, this_val, d); @@ -49855,8 +50587,8 @@ static JSValue set_date_field(JSContext *ctx, JSValueConst this_val, part: 1=date, 2=time 3=all XXX: should use a variant of strftime(). */ -static JSValue get_date_string(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) +static JSValue get_date_string(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { // _string(obj, fmt, part) char buf[64]; @@ -49874,7 +50606,7 @@ static JSValue get_date_string(JSContext *ctx, JSValueConst this_val, if (fmt == 2) return JS_ThrowRangeError(ctx, "Date value is NaN"); else - return JS_NewString(ctx, "Invalid Date"); + return js_new_string8(ctx, "Invalid Date"); } y = fields[0]; @@ -49958,26 +50690,20 @@ static JSValue get_date_string(JSContext *ctx, JSValueConst this_val, break; } } - return JS_NewStringLen(ctx, buf, pos); + if (!pos) { + // XXX: should throw exception? + return JS_AtomToString(ctx, JS_ATOM_empty_string); + } + return js_new_string8_len(ctx, buf, pos); } /* OS dependent: return the UTC time in ms since 1970. */ static int64_t date_now(void) { -#ifdef _MSC_VER - SYSTEMTIME st; - GetSystemTime(&st); - int64_t d; - SystemTimeToFileTime(&st, (FILETIME *) &d); - return (d - 116444736000000000ULL) / 10000; -#else - struct timeval tv; - gettimeofday(&tv, NULL); - return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000); -#endif + return js__gettimeofday_us() / 1000; } -static JSValue js_date_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) +static JSValue js_date_constructor(JSContext *ctx, JSValue new_target, + int argc, JSValue *argv) { // Date(y, mon, d, h, m, s, ms) JSValue rv; @@ -50004,7 +50730,7 @@ static JSValue js_date_constructor(JSContext *ctx, JSValueConst new_target, } v = JS_ToPrimitive(ctx, argv[0], HINT_NONE); if (JS_IsString(v)) { - dv = js_Date_parse(ctx, JS_UNDEFINED, 1, (JSValueConst *)&v); + dv = js_Date_parse(ctx, JS_UNDEFINED, 1, &v); JS_FreeValue(ctx, v); if (JS_IsException(dv)) return JS_EXCEPTION; @@ -50031,17 +50757,9 @@ static JSValue js_date_constructor(JSContext *ctx, JSValueConst new_target, val = (i == n) ? set_date_fields(fields, 1) : NAN; } has_val: -#if 0 - JSValueConst args[3]; - args[0] = new_target; - args[1] = ctx->class_proto[JS_CLASS_DATE]; - 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)); -#endif + JS_SetObjectData(ctx, rv, js_float64(val)); if (!JS_IsException(rv) && JS_IsUndefined(new_target)) { /* invoked as a function, return (new Date()).toString(); */ JSValue s; @@ -50052,8 +50770,8 @@ static JSValue js_date_constructor(JSContext *ctx, JSValueConst new_target, return rv; } -static JSValue js_Date_UTC(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_Date_UTC(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { // UTC(y, mon, d, h, m, s, ms) double fields[] = { 0, 0, 1, 0, 0, 0, 0 }; @@ -50074,17 +50792,17 @@ 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_float64(set_date_fields(fields, 0)); } /* Date string parsing */ -static BOOL string_skip_char(const uint8_t *sp, int *pp, int c) { +static bool string_skip_char(const uint8_t *sp, int *pp, int c) { if (sp[*pp] == c) { *pp += 1; - return TRUE; + return true; } else { - return FALSE; + return false; } } @@ -50113,7 +50831,7 @@ static int string_skip_until(const uint8_t *sp, int *pp, const char *stoplist) { } /* parse a numeric field (max_digits = 0 -> no maximum) */ -static BOOL string_get_digits(const uint8_t *sp, int *pp, int *pval, +static bool string_get_digits(const uint8_t *sp, int *pp, int *pval, int min_digits, int max_digits) { int v = 0; @@ -50127,13 +50845,13 @@ static BOOL string_get_digits(const uint8_t *sp, int *pp, int *pval, break; } if (p - p_start < min_digits) - return FALSE; + return false; *pval = v; *pp = p; - return TRUE; + return true; } -static BOOL string_get_milliseconds(const uint8_t *sp, int *pp, int *pval) { +static bool string_get_milliseconds(const uint8_t *sp, int *pp, int *pval) { /* parse optional fractional part as milliseconds and truncate. */ /* spec does not indicate which rounding should be used */ int mul = 100, ms = 0, c, p_start, p = *pp; @@ -50155,24 +50873,20 @@ static BOOL string_get_milliseconds(const uint8_t *sp, int *pp, int *pval) { *pp = p; } } - return TRUE; + return true; } -static uint8_t upper_ascii(uint8_t c) { - return c >= 'a' && c <= 'z' ? c - 'a' + 'A' : c; -} - -static BOOL string_get_tzoffset(const uint8_t *sp, int *pp, int *tzp, BOOL strict) { +static bool string_get_tzoffset(const uint8_t *sp, int *pp, int *tzp, bool strict) { int tz = 0, sgn, hh, mm, p = *pp; sgn = sp[p++]; if (sgn == '+' || sgn == '-') { int n = p; if (!string_get_digits(sp, &p, &hh, 1, 9)) - return FALSE; + return false; n = p - n; if (strict && n != 2 && n != 4) - return FALSE; + return false; while (n > 4) { n -= 2; hh /= 100; @@ -50184,31 +50898,31 @@ static BOOL string_get_tzoffset(const uint8_t *sp, int *pp, int *tzp, BOOL stric mm = 0; if (string_skip_char(sp, &p, ':') /* optional separator */ && !string_get_digits(sp, &p, &mm, 2, 2)) - return FALSE; + return false; } if (hh > 23 || mm > 59) - return FALSE; + return false; tz = hh * 60 + mm; if (sgn != '+') tz = -tz; } else if (sgn != 'Z') { - return FALSE; + return false; } *pp = p; *tzp = tz; - return TRUE; + return true; } -static BOOL string_match(const uint8_t *sp, int *pp, const char *s) { +static bool string_match(const uint8_t *sp, int *pp, const char *s) { int p = *pp; while (*s != '\0') { - if (upper_ascii(sp[p]) != upper_ascii(*s++)) - return FALSE; + if (to_upper_ascii(sp[p]) != to_upper_ascii(*s++)) + return false; p++; } *pp = p; - return TRUE; + return true; } static int find_abbrev(const uint8_t *sp, int p, const char *list, int count) { @@ -50216,7 +50930,7 @@ static int find_abbrev(const uint8_t *sp, int p, const char *list, int count) { for (n = 0; n < count; n++) { for (i = 0;; i++) { - if (upper_ascii(sp[p + i]) != upper_ascii(list[n * 3 + i])) + if (to_upper_ascii(sp[p + i]) != to_upper_ascii(list[n * 3 + i])) break; if (i == 2) return n; @@ -50225,75 +50939,75 @@ static int find_abbrev(const uint8_t *sp, int p, const char *list, int count) { return -1; } -static BOOL string_get_month(const uint8_t *sp, int *pp, int *pval) { +static bool string_get_month(const uint8_t *sp, int *pp, int *pval) { int n; n = find_abbrev(sp, *pp, month_names, 12); if (n < 0) - return FALSE; + return false; *pval = n + 1; *pp += 3; - return TRUE; + return true; } /* parse toISOString format */ -static BOOL js_date_parse_isostring(const uint8_t *sp, int fields[9], BOOL *is_local) { +static bool js_date_parse_isostring(const uint8_t *sp, int fields[9], bool *is_local) { int sgn, i, p = 0; /* initialize fields to the beginning of the Epoch */ for (i = 0; i < 9; i++) { fields[i] = (i == 2); } - *is_local = FALSE; + *is_local = false; /* year is either yyyy digits or [+-]yyyyyy */ sgn = sp[p]; if (sgn == '-' || sgn == '+') { p++; if (!string_get_digits(sp, &p, &fields[0], 6, 6)) - return FALSE; + return false; if (sgn == '-') { if (fields[0] == 0) - return FALSE; // reject -000000 + return false; // reject -000000 fields[0] = -fields[0]; } } else { if (!string_get_digits(sp, &p, &fields[0], 4, 4)) - return FALSE; + return false; } if (string_skip_char(sp, &p, '-')) { if (!string_get_digits(sp, &p, &fields[1], 2, 2)) /* month */ - return FALSE; + return false; if (fields[1] < 1) - return FALSE; + return false; fields[1] -= 1; if (string_skip_char(sp, &p, '-')) { if (!string_get_digits(sp, &p, &fields[2], 2, 2)) /* day */ - return FALSE; + return false; if (fields[2] < 1) - return FALSE; + return false; } } if (string_skip_char(sp, &p, 'T')) { - *is_local = TRUE; + *is_local = true; if (!string_get_digits(sp, &p, &fields[3], 2, 2) /* hour */ || !string_skip_char(sp, &p, ':') || !string_get_digits(sp, &p, &fields[4], 2, 2)) { /* minute */ fields[3] = 100; // reject unconditionally - return TRUE; + return true; } if (string_skip_char(sp, &p, ':')) { if (!string_get_digits(sp, &p, &fields[5], 2, 2)) /* second */ - return FALSE; + return false; string_get_milliseconds(sp, &p, &fields[6]); } } /* parse the time zone offset if present: [+-]HH:mm or [+-]HHmm */ if (sp[p]) { - *is_local = FALSE; - if (!string_get_tzoffset(sp, &p, &fields[8], TRUE)) - return FALSE; + *is_local = false; + if (!string_get_tzoffset(sp, &p, &fields[8], true)) + return false; } /* error if extraneous characters */ return sp[p] == '\0'; @@ -50323,25 +51037,27 @@ static struct { { "EEST", +3 * 60 }, // Eastern European Summer Time }; -static BOOL string_get_tzabbr(const uint8_t *sp, int *pp, int *offset) { - for (size_t i = 0; i < countof(js_tzabbr); i++) { +static bool string_get_tzabbr(const uint8_t *sp, int *pp, int *offset) { + size_t i; + + for (i = 0; i < countof(js_tzabbr); i++) { if (string_match(sp, pp, js_tzabbr[i].name)) { *offset = js_tzabbr[i].offset; - return TRUE; + return true; } } - return FALSE; + return false; } /* parse toString, toUTCString and other formats */ -static BOOL js_date_parse_otherstring(const uint8_t *sp, +static bool js_date_parse_otherstring(const uint8_t *sp, int fields[minimum_length(9)], - BOOL *is_local) { + bool *is_local) { int c, i, val, p = 0, p_start; int num[3]; - BOOL has_year = FALSE; - BOOL has_mon = FALSE; - BOOL has_time = FALSE; + bool has_year = false; + bool has_mon = false; + bool has_time = false; int num_index = 0; /* initialize fields to the beginning of 2001-01-01 */ @@ -50351,23 +51067,23 @@ static BOOL js_date_parse_otherstring(const uint8_t *sp, for (i = 3; i < 9; i++) { fields[i] = 0; } - *is_local = TRUE; + *is_local = true; while (string_skip_spaces(sp, &p)) { p_start = p; if ((c = sp[p]) == '+' || c == '-') { - if (has_time && string_get_tzoffset(sp, &p, &fields[8], FALSE)) { - *is_local = FALSE; + if (has_time && string_get_tzoffset(sp, &p, &fields[8], false)) { + *is_local = false; } else { p++; if (string_get_digits(sp, &p, &val, 1, 9)) { if (c == '-') { if (val == 0) - return FALSE; + return false; val = -val; } fields[0] = val; - has_year = TRUE; + has_year = true; } } } else @@ -50376,44 +51092,52 @@ static BOOL js_date_parse_otherstring(const uint8_t *sp, /* time part */ fields[3] = val; if (!string_get_digits(sp, &p, &fields[4], 1, 2)) - return FALSE; + return false; if (string_skip_char(sp, &p, ':')) { if (!string_get_digits(sp, &p, &fields[5], 1, 2)) - return FALSE; + return false; string_get_milliseconds(sp, &p, &fields[6]); - } - has_time = TRUE; + } else + if (sp[p] != '\0' && sp[p] != ' ') + return false; + has_time = true; } else { if (p - p_start > 2) { fields[0] = val; - has_year = TRUE; + has_year = true; } else if (val < 1 || val > 31) { fields[0] = val + (val < 100) * 1900 + (val < 50) * 100; - has_year = TRUE; + has_year = true; } else { if (num_index == 3) - return FALSE; + return false; num[num_index++] = val; } } } else if (string_get_month(sp, &p, &fields[1])) { - has_mon = TRUE; + has_mon = true; string_skip_until(sp, &p, "0123456789 -/("); } else if (has_time && string_match(sp, &p, "PM")) { - if (fields[3] < 12) + /* hours greater than 12 will be incremented and + rejected by the range check in js_Date_parse */ + /* 00:00 PM will be silently converted as 12:00 */ + if (fields[3] != 12) fields[3] += 12; continue; } else if (has_time && string_match(sp, &p, "AM")) { + /* 00:00 AM will be silently accepted */ + if (fields[3] > 12) + return false; if (fields[3] == 12) fields[3] -= 12; continue; } else if (string_get_tzabbr(sp, &p, &fields[8])) { - *is_local = FALSE; + *is_local = false; continue; } else if (c == '(') { /* skip parenthesized phrase */ @@ -50426,25 +51150,25 @@ static BOOL js_date_parse_otherstring(const uint8_t *sp, break; } if (level > 0) - return FALSE; + return false; } else if (c == ')') { - return FALSE; + return false; } else { if (has_year + has_mon + has_time + num_index) - return FALSE; + return false; /* skip a word */ string_skip_until(sp, &p, " -/("); } string_skip_separators(sp, &p); } if (num_index + has_year + has_mon > 3) - return FALSE; + return false; switch (num_index) { case 0: if (!has_year) - return FALSE; + return false; break; case 1: if (has_mon) @@ -50471,16 +51195,16 @@ static BOOL js_date_parse_otherstring(const uint8_t *sp, fields[2] = num[1]; break; default: - return FALSE; + return false; } if (fields[1] < 1 || fields[2] < 1) - return FALSE; + return false; fields[1] -= 1; - return TRUE; + return true; } -static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_Date_parse(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue s, rv; int fields[9]; @@ -50489,7 +51213,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, int i, c; JSString *sp; uint8_t buf[128]; - BOOL is_local; + bool is_local; rv = JS_NAN; @@ -50509,15 +51233,15 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, if (js_date_parse_isostring(buf, fields, &is_local) || js_date_parse_otherstring(buf, fields, &is_local)) { static int const field_max[6] = { 0, 11, 31, 24, 59, 59 }; - BOOL valid = TRUE; + bool valid = true; /* check field maximum values */ for (i = 1; i < 6; i++) { if (fields[i] > field_max[i]) - valid = FALSE; + valid = false; } /* special case 24:00:00.000 */ if (fields[3] == 24 && (fields[4] | fields[5] | fields[6])) - valid = FALSE; + valid = false; if (valid) { for(i = 0; i < 7; i++) fields1[i] = fields[i]; @@ -50529,18 +51253,18 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, return rv; } -static JSValue js_Date_now(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_Date_now(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { // now() - return JS_NewInt64(ctx, date_now()); + return js_int64(date_now()); } -static JSValue js_date_Symbol_toPrimitive(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_date_Symbol_toPrimitive(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { // Symbol_toPrimitive(hint) - JSValueConst obj = this_val; + JSValue obj = this_val; JSAtom hint = JS_ATOM_NULL; int hint_num; @@ -50568,8 +51292,8 @@ static JSValue js_date_Symbol_toPrimitive(JSContext *ctx, JSValueConst this_val, return JS_ToPrimitive(ctx, obj, hint_num | HINT_FORCE_ORDINARY); } -static JSValue js_date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_date_getTimezoneOffset(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { // getTimezoneOffset() double v; @@ -50580,22 +51304,22 @@ static JSValue js_date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val, return JS_NAN; else /* assuming -8.64e15 <= v <= -8.64e15 */ - return JS_NewInt64(ctx, getTimezoneOffset((int64_t)trunc(v))); + return js_int64(getTimezoneOffset((int64_t)trunc(v))); } -static JSValue js_date_getTime(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_date_getTime(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { // getTime() double v; if (JS_ThisTimeValue(ctx, &v, this_val)) return JS_EXCEPTION; - return JS_NewFloat64(ctx, v); + return js_float64(v); } -static JSValue js_date_setTime(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_date_setTime(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { // setTime(v) double v; @@ -50605,27 +51329,29 @@ static JSValue js_date_setTime(JSContext *ctx, JSValueConst this_val, return JS_SetThisTimeValue(ctx, this_val, time_clip(v)); } -static JSValue js_date_setYear(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_date_setYear(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { // setYear(y) double y; - JSValueConst args[1]; + JSValue args[1]; if (JS_ThisTimeValue(ctx, &y, this_val) || JS_ToFloat64(ctx, &y, argv[0])) return JS_EXCEPTION; y = +y; + if (isnan(y)) + return JS_SetThisTimeValue(ctx, this_val, y); if (isfinite(y)) { y = trunc(y); if (y >= 0 && y < 100) y += 1900; } - args[0] = JS_NewFloat64(ctx, y); + args[0] = js_float64(y); return set_date_field(ctx, this_val, 1, args, 0x011); } -static JSValue js_date_toJSON(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_date_toJSON(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { // toJSON(key) JSValue obj, tv, method, rv; @@ -50708,1990 +51434,160 @@ static const JSCFunctionListEntry js_date_proto_funcs[] = { JS_CFUNC_MAGIC_DEF("setUTCMinutes", 3, set_date_field, 0x470 ), JS_CFUNC_MAGIC_DEF("setHours", 4, set_date_field, 0x371 ), JS_CFUNC_MAGIC_DEF("setUTCHours", 4, set_date_field, 0x370 ), - JS_CFUNC_MAGIC_DEF("setDate", 1, set_date_field, 0x231 ), - JS_CFUNC_MAGIC_DEF("setUTCDate", 1, set_date_field, 0x230 ), - JS_CFUNC_MAGIC_DEF("setMonth", 2, set_date_field, 0x131 ), - JS_CFUNC_MAGIC_DEF("setUTCMonth", 2, set_date_field, 0x130 ), - JS_CFUNC_DEF("setYear", 1, js_date_setYear ), - JS_CFUNC_MAGIC_DEF("setFullYear", 3, set_date_field, 0x031 ), - JS_CFUNC_MAGIC_DEF("setUTCFullYear", 3, set_date_field, 0x030 ), - JS_CFUNC_DEF("toJSON", 1, js_date_toJSON ), -}; - -JSValue JS_NewDate(JSContext *ctx, double epoch_ms) -{ - JSValue obj = js_create_from_ctor(ctx, JS_UNDEFINED, JS_CLASS_DATE); - if (JS_IsException(obj)) - return JS_EXCEPTION; - JS_SetObjectData(ctx, obj, __JS_NewFloat64(ctx, time_clip(epoch_ms))); - return obj; -} - -JS_BOOL JS_IsDate(JSValue v) -{ - JSObject *p; - if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT) - return FALSE; - return JS_VALUE_GET_OBJ(v)->class_id == JS_CLASS_DATE; -} - -void JS_AddIntrinsicDate(JSContext *ctx) -{ - JSValueConst obj; - - /* Date */ - ctx->class_proto[JS_CLASS_DATE] = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_DATE], js_date_proto_funcs, - countof(js_date_proto_funcs)); - obj = JS_NewGlobalCConstructor(ctx, "Date", js_date_constructor, 7, - ctx->class_proto[JS_CLASS_DATE]); - JS_SetPropertyFunctionList(ctx, obj, js_date_funcs, countof(js_date_funcs)); -} - -/* eval */ - -void JS_AddIntrinsicEval(JSContext *ctx) -{ - ctx->eval_internal = __JS_EvalInternal; -} - -#ifdef CONFIG_BIGNUM - -/* Operators */ - -static void js_operator_set_finalizer(JSRuntime *rt, JSValue val) -{ - JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET); - int i, j; - JSBinaryOperatorDefEntry *ent; - - if (opset) { - for(i = 0; i < JS_OVOP_COUNT; i++) { - if (opset->self_ops[i]) - JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[i])); - } - for(j = 0; j < opset->left.count; j++) { - ent = &opset->left.tab[j]; - for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) { - if (ent->ops[i]) - JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i])); - } - } - js_free_rt(rt, opset->left.tab); - for(j = 0; j < opset->right.count; j++) { - ent = &opset->right.tab[j]; - for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) { - if (ent->ops[i]) - JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i])); - } - } - js_free_rt(rt, opset->right.tab); - js_free_rt(rt, opset); - } -} - -static void js_operator_set_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func) -{ - JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET); - int i, j; - JSBinaryOperatorDefEntry *ent; - - if (opset) { - for(i = 0; i < JS_OVOP_COUNT; i++) { - if (opset->self_ops[i]) - JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[i]), - mark_func); - } - for(j = 0; j < opset->left.count; j++) { - ent = &opset->left.tab[j]; - for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) { - if (ent->ops[i]) - JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]), - mark_func); - } - } - for(j = 0; j < opset->right.count; j++) { - ent = &opset->right.tab[j]; - for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) { - if (ent->ops[i]) - JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]), - mark_func); - } - } - } -} - - -/* create an OperatorSet object */ -static JSValue js_operators_create_internal(JSContext *ctx, - int argc, JSValueConst *argv, - BOOL is_primitive) -{ - JSValue opset_obj, prop, obj; - JSOperatorSetData *opset, *opset1; - JSBinaryOperatorDef *def; - JSValueConst arg; - int i, j; - JSBinaryOperatorDefEntry *new_tab; - JSBinaryOperatorDefEntry *ent; - uint32_t op_count; - - if (ctx->rt->operator_count == UINT32_MAX) { - return JS_ThrowTypeError(ctx, "too many operators"); - } - opset_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_OPERATOR_SET); - if (JS_IsException(opset_obj)) - goto fail; - opset = js_mallocz(ctx, sizeof(*opset)); - if (!opset) - goto fail; - JS_SetOpaque(opset_obj, opset); - if (argc >= 1) { - arg = argv[0]; - /* self operators */ - for(i = 0; i < JS_OVOP_COUNT; i++) { - prop = JS_GetPropertyStr(ctx, arg, js_overloadable_operator_names[i]); - if (JS_IsException(prop)) - goto fail; - if (!JS_IsUndefined(prop)) { - if (check_function(ctx, prop)) { - JS_FreeValue(ctx, prop); - goto fail; - } - opset->self_ops[i] = JS_VALUE_GET_OBJ(prop); - } - } - } - /* left & right operators */ - for(j = 1; j < argc; j++) { - arg = argv[j]; - prop = JS_GetPropertyStr(ctx, arg, "left"); - if (JS_IsException(prop)) - goto fail; - def = &opset->right; - if (JS_IsUndefined(prop)) { - prop = JS_GetPropertyStr(ctx, arg, "right"); - if (JS_IsException(prop)) - goto fail; - if (JS_IsUndefined(prop)) { - JS_ThrowTypeError(ctx, "left or right property must be present"); - goto fail; - } - def = &opset->left; - } - /* get the operator set */ - obj = JS_GetProperty(ctx, prop, JS_ATOM_prototype); - JS_FreeValue(ctx, prop); - if (JS_IsException(obj)) - goto fail; - prop = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet); - JS_FreeValue(ctx, obj); - if (JS_IsException(prop)) - goto fail; - opset1 = JS_GetOpaque2(ctx, prop, JS_CLASS_OPERATOR_SET); - if (!opset1) { - JS_FreeValue(ctx, prop); - goto fail; - } - op_count = opset1->operator_counter; - JS_FreeValue(ctx, prop); - - /* we assume there are few entries */ - new_tab = js_realloc(ctx, def->tab, - (def->count + 1) * sizeof(def->tab[0])); - if (!new_tab) - goto fail; - def->tab = new_tab; - def->count++; - ent = def->tab + def->count - 1; - memset(ent, 0, sizeof(def->tab[0])); - ent->operator_index = op_count; - - for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) { - prop = JS_GetPropertyStr(ctx, arg, - js_overloadable_operator_names[i]); - if (JS_IsException(prop)) - goto fail; - if (!JS_IsUndefined(prop)) { - if (check_function(ctx, prop)) { - JS_FreeValue(ctx, prop); - goto fail; - } - ent->ops[i] = JS_VALUE_GET_OBJ(prop); - } - } - } - opset->is_primitive = is_primitive; - opset->operator_counter = ctx->rt->operator_count++; - return opset_obj; - fail: - JS_FreeValue(ctx, opset_obj); - return JS_EXCEPTION; -} - -static JSValue js_operators_create(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return js_operators_create_internal(ctx, argc, argv, FALSE); -} - -static JSValue js_operators_updateBigIntOperators(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue opset_obj, prop; - JSOperatorSetData *opset; - const JSOverloadableOperatorEnum ops[2] = { JS_OVOP_DIV, JS_OVOP_POW }; - JSOverloadableOperatorEnum op; - int i; - - opset_obj = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_BIG_INT], - JS_ATOM_Symbol_operatorSet); - if (JS_IsException(opset_obj)) - goto fail; - opset = JS_GetOpaque2(ctx, opset_obj, JS_CLASS_OPERATOR_SET); - if (!opset) - goto fail; - for(i = 0; i < countof(ops); i++) { - op = ops[i]; - prop = JS_GetPropertyStr(ctx, argv[0], - js_overloadable_operator_names[op]); - if (JS_IsException(prop)) - goto fail; - if (!JS_IsUndefined(prop)) { - if (!JS_IsNull(prop) && check_function(ctx, prop)) { - JS_FreeValue(ctx, prop); - goto fail; - } - if (opset->self_ops[op]) - JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[op])); - if (JS_IsNull(prop)) { - opset->self_ops[op] = NULL; - } else { - opset->self_ops[op] = JS_VALUE_GET_PTR(prop); - } - } - } - JS_FreeValue(ctx, opset_obj); - return JS_UNDEFINED; - fail: - JS_FreeValue(ctx, opset_obj); - return JS_EXCEPTION; -} - -static int js_operators_set_default(JSContext *ctx, JSValueConst obj) -{ - JSValue opset_obj; - - if (!JS_IsObject(obj)) /* in case the prototype is not defined */ - return 0; - opset_obj = js_operators_create_internal(ctx, 0, NULL, TRUE); - if (JS_IsException(opset_obj)) - return -1; - /* cannot be modified by the user */ - JS_DefinePropertyValue(ctx, obj, JS_ATOM_Symbol_operatorSet, - opset_obj, 0); - return 0; -} - -static JSValue js_dummy_operators_ctor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) -{ - return js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT); -} - -static JSValue js_global_operators(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue func_obj, proto, opset_obj; - - func_obj = JS_UNDEFINED; - proto = JS_NewObject(ctx); - if (JS_IsException(proto)) - return JS_EXCEPTION; - opset_obj = js_operators_create_internal(ctx, argc, argv, FALSE); - if (JS_IsException(opset_obj)) - goto fail; - JS_DefinePropertyValue(ctx, proto, JS_ATOM_Symbol_operatorSet, - opset_obj, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - func_obj = JS_NewCFunction2(ctx, js_dummy_operators_ctor, "Operators", - 0, JS_CFUNC_constructor, 0); - if (JS_IsException(func_obj)) - goto fail; - JS_SetConstructor2(ctx, func_obj, proto, - 0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - JS_FreeValue(ctx, proto); - return func_obj; - fail: - JS_FreeValue(ctx, proto); - JS_FreeValue(ctx, func_obj); - return JS_EXCEPTION; -} - -static const JSCFunctionListEntry js_operators_funcs[] = { - JS_CFUNC_DEF("create", 1, js_operators_create ), - JS_CFUNC_DEF("updateBigIntOperators", 2, js_operators_updateBigIntOperators ), -}; - -/* must be called after all overloadable base types are initialized */ -void JS_AddIntrinsicOperators(JSContext *ctx) -{ - JSValue obj; - - ctx->allow_operator_overloading = TRUE; - obj = JS_NewCFunction(ctx, js_global_operators, "Operators", 1); - JS_SetPropertyFunctionList(ctx, obj, - js_operators_funcs, - countof(js_operators_funcs)); - JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_Operators, - obj, - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - /* add default operatorSets */ - js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BOOLEAN]); - js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_NUMBER]); - js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_STRING]); - js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_INT]); - js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT]); - js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL]); -} -#endif /* CONFIG_BIGNUM */ - -/* BigInt */ - -static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val) -{ - uint32_t tag; - - redo: - tag = JS_VALUE_GET_NORM_TAG(val); - switch(tag) { - case JS_TAG_INT: - case JS_TAG_BOOL: - val = JS_NewBigInt64(ctx, JS_VALUE_GET_INT(val)); - break; - case JS_TAG_BIG_INT: - break; - case JS_TAG_FLOAT64: -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: -#endif - { - bf_t *a, a_s; - - a = JS_ToBigFloat(ctx, &a_s, val); - if (!a) { - JS_FreeValue(ctx, val); - return JS_EXCEPTION; - } - if (!bf_is_finite(a)) { - JS_FreeValue(ctx, val); - val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to BigInt"); - } else { - JSValue val1 = JS_NewBigInt(ctx); - bf_t *r; - int ret; - if (JS_IsException(val1)) { - JS_FreeValue(ctx, val); - return JS_EXCEPTION; - } - r = JS_GetBigInt(val1); - ret = bf_set(r, a); - ret |= bf_rint(r, BF_RNDZ); - JS_FreeValue(ctx, val); - if (ret & BF_ST_MEM_ERROR) { - JS_FreeValue(ctx, val1); - val = JS_ThrowOutOfMemory(ctx); - } else if (ret & BF_ST_INEXACT) { - JS_FreeValue(ctx, val1); - val = JS_ThrowRangeError(ctx, "cannot convert to BigInt: not an integer"); - } else { - val = JS_CompactBigInt(ctx, val1); - } - } - if (a == &a_s) - bf_delete(a); - } - break; -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_DECIMAL: - val = JS_ToStringFree(ctx, val); - if (JS_IsException(val)) - break; - goto redo; -#endif - case JS_TAG_STRING: - val = JS_StringToBigIntErr(ctx, val); - break; - case JS_TAG_OBJECT: - val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER); - if (JS_IsException(val)) - break; - goto redo; - case JS_TAG_NULL: - case JS_TAG_UNDEFINED: - default: - JS_FreeValue(ctx, val); - return JS_ThrowTypeError(ctx, "cannot convert to BigInt"); - } - return val; -} - -static JSValue js_bigint_constructor(JSContext *ctx, - 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])); -} - -static JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val) -{ - if (JS_IsBigInt(ctx, this_val)) - return JS_DupValue(ctx, this_val); - - if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) { - JSObject *p = JS_VALUE_GET_OBJ(this_val); - if (p->class_id == JS_CLASS_BIG_INT) { - if (JS_IsBigInt(ctx, p->u.object_data)) - return JS_DupValue(ctx, p->u.object_data); - } - } - return JS_ThrowTypeError(ctx, "not a BigInt"); -} - -static JSValue js_bigint_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val; - int base; - JSValue ret; - - val = js_thisBigIntValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (argc == 0 || JS_IsUndefined(argv[0])) { - base = 10; - } else { - base = js_get_radix(ctx, argv[0]); - if (base < 0) - goto fail; - } - ret = js_bigint_to_string1(ctx, val, base); - JS_FreeValue(ctx, val); - return ret; - fail: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} - -static JSValue js_bigint_valueOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return js_thisBigIntValue(ctx, this_val); -} - -#ifdef CONFIG_BIGNUM -static JSValue js_bigint_div(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - bf_t a_s, b_s, *a, *b, *r, *q; - int status; - JSValue q_val, r_val; - - q_val = JS_NewBigInt(ctx); - if (JS_IsException(q_val)) - return JS_EXCEPTION; - r_val = JS_NewBigInt(ctx); - if (JS_IsException(r_val)) - goto fail; - b = NULL; - a = JS_ToBigInt(ctx, &a_s, argv[0]); - if (!a) - goto fail; - b = JS_ToBigInt(ctx, &b_s, argv[1]); - if (!b) { - JS_FreeBigInt(ctx, a, &a_s); - goto fail; - } - q = JS_GetBigInt(q_val); - r = JS_GetBigInt(r_val); - status = bf_divrem(q, r, a, b, BF_PREC_INF, BF_RNDZ, magic & 0xf); - JS_FreeBigInt(ctx, a, &a_s); - JS_FreeBigInt(ctx, b, &b_s); - if (unlikely(status)) { - throw_bf_exception(ctx, status); - goto fail; - } - q_val = JS_CompactBigInt(ctx, q_val); - if (magic & 0x10) { - JSValue ret; - ret = JS_NewArray(ctx); - if (JS_IsException(ret)) - goto fail; - JS_SetPropertyUint32(ctx, ret, 0, q_val); - JS_SetPropertyUint32(ctx, ret, 1, JS_CompactBigInt(ctx, r_val)); - return ret; - } else { - JS_FreeValue(ctx, r_val); - return q_val; - } - fail: - JS_FreeValue(ctx, q_val); - JS_FreeValue(ctx, r_val); - return JS_EXCEPTION; -} - -static JSValue js_bigint_sqrt(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - bf_t a_s, *a, *r, *rem; - int status; - JSValue r_val, rem_val; - - r_val = JS_NewBigInt(ctx); - if (JS_IsException(r_val)) - return JS_EXCEPTION; - rem_val = JS_NewBigInt(ctx); - if (JS_IsException(rem_val)) - return JS_EXCEPTION; - r = JS_GetBigInt(r_val); - rem = JS_GetBigInt(rem_val); - - a = JS_ToBigInt(ctx, &a_s, argv[0]); - if (!a) - goto fail; - status = bf_sqrtrem(r, rem, a); - JS_FreeBigInt(ctx, a, &a_s); - if (unlikely(status & ~BF_ST_INEXACT)) { - throw_bf_exception(ctx, status); - goto fail; - } - r_val = JS_CompactBigInt(ctx, r_val); - if (magic) { - JSValue ret; - ret = JS_NewArray(ctx); - if (JS_IsException(ret)) - goto fail; - JS_SetPropertyUint32(ctx, ret, 0, r_val); - JS_SetPropertyUint32(ctx, ret, 1, JS_CompactBigInt(ctx, rem_val)); - return ret; - } else { - JS_FreeValue(ctx, rem_val); - return r_val; - } - fail: - JS_FreeValue(ctx, r_val); - JS_FreeValue(ctx, rem_val); - return JS_EXCEPTION; -} - -static JSValue js_bigint_op1(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv, - int magic) -{ - bf_t a_s, *a; - int64_t res; - - a = JS_ToBigInt(ctx, &a_s, argv[0]); - if (!a) - return JS_EXCEPTION; - switch(magic) { - case 0: /* floorLog2 */ - if (a->sign || a->expn <= 0) { - res = -1; - } else { - res = a->expn - 1; - } - break; - case 1: /* ctz */ - if (bf_is_zero(a)) { - res = -1; - } else { - res = bf_get_exp_min(a); - } - break; - default: - abort(); - } - JS_FreeBigInt(ctx, a, &a_s); - return JS_NewBigInt64(ctx, res); -} -#endif - -static JSValue js_bigint_asUintN(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv, int asIntN) -{ - uint64_t bits; - bf_t a_s, *a = &a_s, *r, mask_s, *mask = &mask_s; - JSValue res; - - if (JS_ToIndex(ctx, &bits, argv[0])) - return JS_EXCEPTION; - res = JS_NewBigInt(ctx); - if (JS_IsException(res)) - return JS_EXCEPTION; - r = JS_GetBigInt(res); - a = JS_ToBigInt(ctx, &a_s, argv[1]); - if (!a) { - JS_FreeValue(ctx, res); - return JS_EXCEPTION; - } - /* XXX: optimize */ - r = JS_GetBigInt(res); - bf_init(ctx->bf_ctx, mask); - bf_set_ui(mask, 1); - bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ); - bf_add_si(mask, mask, -1, BF_PREC_INF, BF_RNDZ); - bf_logic_and(r, a, mask); - if (asIntN && bits != 0) { - bf_set_ui(mask, 1); - bf_mul_2exp(mask, bits - 1, BF_PREC_INF, BF_RNDZ); - if (bf_cmpu(r, mask) >= 0) { - bf_set_ui(mask, 1); - bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ); - bf_sub(r, r, mask, BF_PREC_INF, BF_RNDZ); - } - } - bf_delete(mask); - JS_FreeBigInt(ctx, a, &a_s); - return JS_CompactBigInt(ctx, res); -} - -static const JSCFunctionListEntry js_bigint_funcs[] = { - JS_CFUNC_MAGIC_DEF("asUintN", 2, js_bigint_asUintN, 0 ), - JS_CFUNC_MAGIC_DEF("asIntN", 2, js_bigint_asUintN, 1 ), -#ifdef CONFIG_BIGNUM - /* QuickJS extensions */ - JS_CFUNC_MAGIC_DEF("tdiv", 2, js_bigint_div, BF_RNDZ ), - JS_CFUNC_MAGIC_DEF("fdiv", 2, js_bigint_div, BF_RNDD ), - JS_CFUNC_MAGIC_DEF("cdiv", 2, js_bigint_div, BF_RNDU ), - JS_CFUNC_MAGIC_DEF("ediv", 2, js_bigint_div, BF_DIVREM_EUCLIDIAN ), - JS_CFUNC_MAGIC_DEF("tdivrem", 2, js_bigint_div, BF_RNDZ | 0x10 ), - JS_CFUNC_MAGIC_DEF("fdivrem", 2, js_bigint_div, BF_RNDD | 0x10 ), - JS_CFUNC_MAGIC_DEF("cdivrem", 2, js_bigint_div, BF_RNDU | 0x10 ), - JS_CFUNC_MAGIC_DEF("edivrem", 2, js_bigint_div, BF_DIVREM_EUCLIDIAN | 0x10 ), - JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigint_sqrt, 0 ), - JS_CFUNC_MAGIC_DEF("sqrtrem", 1, js_bigint_sqrt, 1 ), - JS_CFUNC_MAGIC_DEF("floorLog2", 1, js_bigint_op1, 0 ), - JS_CFUNC_MAGIC_DEF("ctz", 1, js_bigint_op1, 1 ), -#endif -}; - -static const JSCFunctionListEntry js_bigint_proto_funcs[] = { - JS_CFUNC_DEF("toString", 0, js_bigint_toString ), - JS_CFUNC_DEF("valueOf", 0, js_bigint_valueOf ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "BigInt", JS_PROP_CONFIGURABLE ), -}; - -void JS_AddIntrinsicBigInt(JSContext *ctx) -{ - JSRuntime *rt = ctx->rt; - JSValueConst obj1; - - rt->bigint_ops.to_string = js_bigint_to_string; - rt->bigint_ops.from_string = js_string_to_bigint; - rt->bigint_ops.unary_arith = js_unary_arith_bigint; - rt->bigint_ops.binary_arith = js_binary_arith_bigint; - rt->bigint_ops.compare = js_compare_bigfloat; - - ctx->class_proto[JS_CLASS_BIG_INT] = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_INT], - js_bigint_proto_funcs, - countof(js_bigint_proto_funcs)); - 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)); -} - -#ifdef CONFIG_BIGNUM - -/* BigFloat */ - -static JSValue js_thisBigFloatValue(JSContext *ctx, JSValueConst this_val) -{ - if (JS_IsBigFloat(this_val)) - return JS_DupValue(ctx, this_val); - - if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) { - JSObject *p = JS_VALUE_GET_OBJ(this_val); - if (p->class_id == JS_CLASS_BIG_FLOAT) { - if (JS_IsBigFloat(p->u.object_data)) - return JS_DupValue(ctx, p->u.object_data); - } - } - return JS_ThrowTypeError(ctx, "not a bigfloat"); -} - -static JSValue js_bigfloat_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val; - int base; - JSValue ret; - - val = js_thisBigFloatValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (argc == 0 || JS_IsUndefined(argv[0])) { - base = 10; - } else { - base = js_get_radix(ctx, argv[0]); - if (base < 0) - goto fail; - } - ret = js_ftoa(ctx, val, base, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN); - JS_FreeValue(ctx, val); - return ret; - fail: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} - -static JSValue js_bigfloat_valueOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return js_thisBigFloatValue(ctx, this_val); -} - -static int bigfloat_get_rnd_mode(JSContext *ctx, JSValueConst val) -{ - int rnd_mode; - if (JS_ToInt32Sat(ctx, &rnd_mode, val)) - return -1; - if (rnd_mode < BF_RNDN || rnd_mode > BF_RNDF) { - JS_ThrowRangeError(ctx, "invalid rounding mode"); - return -1; - } - return rnd_mode; -} - -static JSValue js_bigfloat_toFixed(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val, ret; - int64_t f; - int rnd_mode, radix; - - val = js_thisBigFloatValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (JS_ToInt64Sat(ctx, &f, argv[0])) - goto fail; - if (f < 0 || f > BF_PREC_MAX) { - JS_ThrowRangeError(ctx, "invalid number of digits"); - goto fail; - } - rnd_mode = BF_RNDNA; - radix = 10; - /* XXX: swap parameter order for rounding mode and radix */ - if (argc > 1) { - rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]); - if (rnd_mode < 0) - goto fail; - } - if (argc > 2) { - radix = js_get_radix(ctx, argv[2]); - if (radix < 0) - goto fail; - } - ret = js_ftoa(ctx, val, radix, f, rnd_mode | BF_FTOA_FORMAT_FRAC); - JS_FreeValue(ctx, val); - return ret; - fail: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} - -static BOOL js_bigfloat_is_finite(JSContext *ctx, JSValueConst val) -{ - BOOL res; - uint32_t tag; - - tag = JS_VALUE_GET_NORM_TAG(val); - switch(tag) { - case JS_TAG_BIG_FLOAT: - { - JSBigFloat *p = JS_VALUE_GET_PTR(val); - res = bf_is_finite(&p->num); - } - break; - default: - res = FALSE; - break; - } - return res; -} - -static JSValue js_bigfloat_toExponential(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val, ret; - int64_t f; - int rnd_mode, radix; - - val = js_thisBigFloatValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (JS_ToInt64Sat(ctx, &f, argv[0])) - goto fail; - if (!js_bigfloat_is_finite(ctx, val)) { - ret = JS_ToString(ctx, val); - } else if (JS_IsUndefined(argv[0])) { - ret = js_ftoa(ctx, val, 10, 0, - BF_RNDN | BF_FTOA_FORMAT_FREE_MIN | BF_FTOA_FORCE_EXP); - } else { - if (f < 0 || f > BF_PREC_MAX) { - JS_ThrowRangeError(ctx, "invalid number of digits"); - goto fail; - } - rnd_mode = BF_RNDNA; - radix = 10; - if (argc > 1) { - rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]); - if (rnd_mode < 0) - goto fail; - } - if (argc > 2) { - radix = js_get_radix(ctx, argv[2]); - if (radix < 0) - goto fail; - } - ret = js_ftoa(ctx, val, radix, f + 1, - rnd_mode | BF_FTOA_FORMAT_FIXED | BF_FTOA_FORCE_EXP); - } - JS_FreeValue(ctx, val); - return ret; - fail: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} - -static JSValue js_bigfloat_toPrecision(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val, ret; - int64_t p; - int rnd_mode, radix; - - val = js_thisBigFloatValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (JS_IsUndefined(argv[0])) - goto to_string; - if (JS_ToInt64Sat(ctx, &p, argv[0])) - goto fail; - if (!js_bigfloat_is_finite(ctx, val)) { - to_string: - ret = JS_ToString(ctx, this_val); - } else { - if (p < 1 || p > BF_PREC_MAX) { - JS_ThrowRangeError(ctx, "invalid number of digits"); - goto fail; - } - rnd_mode = BF_RNDNA; - radix = 10; - if (argc > 1) { - rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]); - if (rnd_mode < 0) - goto fail; - } - if (argc > 2) { - radix = js_get_radix(ctx, argv[2]); - if (radix < 0) - goto fail; - } - ret = js_ftoa(ctx, val, radix, p, rnd_mode | BF_FTOA_FORMAT_FIXED); - } - JS_FreeValue(ctx, val); - return ret; - fail: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} - -static const JSCFunctionListEntry js_bigfloat_proto_funcs[] = { - JS_CFUNC_DEF("toString", 0, js_bigfloat_toString ), - JS_CFUNC_DEF("valueOf", 0, js_bigfloat_valueOf ), - JS_CFUNC_DEF("toPrecision", 1, js_bigfloat_toPrecision ), - JS_CFUNC_DEF("toFixed", 1, js_bigfloat_toFixed ), - JS_CFUNC_DEF("toExponential", 1, js_bigfloat_toExponential ), -}; - -static JSValue js_bigfloat_constructor(JSContext *ctx, - 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); - if (JS_IsException(val)) - return val; - r = JS_GetBigFloat(val); - bf_set_zero(r, 0); - } else { - val = JS_DupValue(ctx, argv[0]); - redo: - switch(JS_VALUE_GET_NORM_TAG(val)) { - case JS_TAG_BIG_FLOAT: - break; - case JS_TAG_FLOAT64: - { - bf_t *r; - double d = JS_VALUE_GET_FLOAT64(val); - val = JS_NewBigFloat(ctx); - if (JS_IsException(val)) - break; - r = JS_GetBigFloat(val); - if (bf_set_float64(r, d)) - goto fail; - } - break; - case JS_TAG_INT: - { - bf_t *r; - int32_t v = JS_VALUE_GET_INT(val); - val = JS_NewBigFloat(ctx); - if (JS_IsException(val)) - break; - r = JS_GetBigFloat(val); - if (bf_set_si(r, v)) - goto fail; - } - break; - case JS_TAG_BIG_INT: - /* We keep the full precision of the integer */ - { - JSBigFloat *p = JS_VALUE_GET_PTR(val); - val = JS_MKPTR(JS_TAG_BIG_FLOAT, p); - } - break; - case JS_TAG_BIG_DECIMAL: - val = JS_ToStringFree(ctx, val); - if (JS_IsException(val)) - break; - goto redo; - case JS_TAG_STRING: - { - const char *str, *p; - size_t len; - int err; - - str = JS_ToCStringLen(ctx, &len, val); - JS_FreeValue(ctx, val); - if (!str) - return JS_EXCEPTION; - p = str; - p += skip_spaces(p); - if ((p - str) == len) { - bf_t *r; - val = JS_NewBigFloat(ctx); - if (JS_IsException(val)) - break; - r = JS_GetBigFloat(val); - bf_set_zero(r, 0); - err = 0; - } else { - val = js_atof(ctx, p, &p, 0, ATOD_ACCEPT_BIN_OCT | - ATOD_TYPE_BIG_FLOAT | - ATOD_ACCEPT_PREFIX_AFTER_SIGN); - if (JS_IsException(val)) { - JS_FreeCString(ctx, str); - return JS_EXCEPTION; - } - p += skip_spaces(p); - err = ((p - str) != len); - } - JS_FreeCString(ctx, str); - if (err) { - JS_FreeValue(ctx, val); - return JS_ThrowSyntaxError(ctx, "invalid bigfloat literal"); - } - } - break; - case JS_TAG_OBJECT: - val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER); - if (JS_IsException(val)) - break; - goto redo; - case JS_TAG_NULL: - case JS_TAG_UNDEFINED: - default: - JS_FreeValue(ctx, val); - return JS_ThrowTypeError(ctx, "cannot convert to bigfloat"); - } - } - return val; - fail: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} - -static JSValue js_bigfloat_get_const(JSContext *ctx, - JSValueConst this_val, int magic) -{ - bf_t *r; - JSValue val; - val = JS_NewBigFloat(ctx); - if (JS_IsException(val)) - return val; - r = JS_GetBigFloat(val); - switch(magic) { - case 0: /* PI */ - bf_const_pi(r, ctx->fp_env.prec, ctx->fp_env.flags); - break; - case 1: /* LN2 */ - bf_const_log2(r, ctx->fp_env.prec, ctx->fp_env.flags); - break; - case 2: /* MIN_VALUE */ - case 3: /* MAX_VALUE */ - { - slimb_t e_range, e; - e_range = (limb_t)1 << (bf_get_exp_bits(ctx->fp_env.flags) - 1); - bf_set_ui(r, 1); - if (magic == 2) { - e = -e_range + 2; - if (ctx->fp_env.flags & BF_FLAG_SUBNORMAL) - e -= ctx->fp_env.prec - 1; - bf_mul_2exp(r, e, ctx->fp_env.prec, ctx->fp_env.flags); - } else { - bf_mul_2exp(r, ctx->fp_env.prec, ctx->fp_env.prec, - ctx->fp_env.flags); - bf_add_si(r, r, -1, ctx->fp_env.prec, ctx->fp_env.flags); - bf_mul_2exp(r, e_range - ctx->fp_env.prec, ctx->fp_env.prec, - ctx->fp_env.flags); - } - } - break; - case 4: /* EPSILON */ - bf_set_ui(r, 1); - bf_mul_2exp(r, 1 - ctx->fp_env.prec, - ctx->fp_env.prec, ctx->fp_env.flags); - break; - default: - abort(); - } - return val; -} - -static JSValue js_bigfloat_parseFloat(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - bf_t *a; - const char *str; - JSValue ret; - int radix; - JSFloatEnv *fe; - - str = JS_ToCString(ctx, argv[0]); - if (!str) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &radix, argv[1])) { - fail: - JS_FreeCString(ctx, str); - return JS_EXCEPTION; - } - if (radix != 0 && (radix < 2 || radix > 36)) { - JS_ThrowRangeError(ctx, "radix must be between 2 and 36"); - goto fail; - } - fe = &ctx->fp_env; - if (argc > 2) { - fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV); - if (!fe) - goto fail; - } - ret = JS_NewBigFloat(ctx); - if (JS_IsException(ret)) - goto done; - a = JS_GetBigFloat(ret); - /* XXX: use js_atof() */ - bf_atof(a, str, NULL, radix, fe->prec, fe->flags); - done: - JS_FreeCString(ctx, str); - return ret; -} - -static JSValue js_bigfloat_isFinite(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValueConst val = argv[0]; - JSBigFloat *p; - - if (JS_VALUE_GET_NORM_TAG(val) != JS_TAG_BIG_FLOAT) - return JS_FALSE; - p = JS_VALUE_GET_PTR(val); - return JS_NewBool(ctx, bf_is_finite(&p->num)); -} - -static JSValue js_bigfloat_isNaN(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValueConst val = argv[0]; - JSBigFloat *p; - - if (JS_VALUE_GET_NORM_TAG(val) != JS_TAG_BIG_FLOAT) - return JS_FALSE; - p = JS_VALUE_GET_PTR(val); - return JS_NewBool(ctx, bf_is_nan(&p->num)); -} - -enum { - MATH_OP_ABS, - MATH_OP_FLOOR, - MATH_OP_CEIL, - MATH_OP_ROUND, - MATH_OP_TRUNC, - MATH_OP_SQRT, - MATH_OP_FPROUND, - MATH_OP_ACOS, - MATH_OP_ASIN, - MATH_OP_ATAN, - MATH_OP_ATAN2, - MATH_OP_COS, - MATH_OP_EXP, - MATH_OP_LOG, - MATH_OP_POW, - MATH_OP_SIN, - MATH_OP_TAN, - MATH_OP_FMOD, - MATH_OP_REM, - MATH_OP_SIGN, - - MATH_OP_ADD, - MATH_OP_SUB, - MATH_OP_MUL, - MATH_OP_DIV, -}; - -static JSValue js_bigfloat_fop(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - bf_t a_s, *a, *r; - JSFloatEnv *fe; - int rnd_mode; - JSValue op1, res; - - op1 = JS_ToNumeric(ctx, argv[0]); - if (JS_IsException(op1)) - return op1; - a = JS_ToBigFloat(ctx, &a_s, op1); - if (!a) { - JS_FreeValue(ctx, op1); - return JS_EXCEPTION; - } - fe = &ctx->fp_env; - if (argc > 1) { - fe = JS_GetOpaque2(ctx, argv[1], JS_CLASS_FLOAT_ENV); - if (!fe) - goto fail; - } - res = JS_NewBigFloat(ctx); - if (JS_IsException(res)) { - fail: - if (a == &a_s) - bf_delete(a); - JS_FreeValue(ctx, op1); - return JS_EXCEPTION; - } - r = JS_GetBigFloat(res); - switch (magic) { - case MATH_OP_ABS: - bf_set(r, a); - r->sign = 0; - break; - case MATH_OP_FLOOR: - rnd_mode = BF_RNDD; - goto rint; - case MATH_OP_CEIL: - rnd_mode = BF_RNDU; - goto rint; - case MATH_OP_ROUND: - rnd_mode = BF_RNDNA; - goto rint; - case MATH_OP_TRUNC: - rnd_mode = BF_RNDZ; - rint: - bf_set(r, a); - fe->status |= bf_rint(r, rnd_mode); - break; - case MATH_OP_SQRT: - fe->status |= bf_sqrt(r, a, fe->prec, fe->flags); - break; - case MATH_OP_FPROUND: - bf_set(r, a); - fe->status |= bf_round(r, fe->prec, fe->flags); - break; - case MATH_OP_ACOS: - fe->status |= bf_acos(r, a, fe->prec, fe->flags); - break; - case MATH_OP_ASIN: - fe->status |= bf_asin(r, a, fe->prec, fe->flags); - break; - case MATH_OP_ATAN: - fe->status |= bf_atan(r, a, fe->prec, fe->flags); - break; - case MATH_OP_COS: - fe->status |= bf_cos(r, a, fe->prec, fe->flags); - break; - case MATH_OP_EXP: - fe->status |= bf_exp(r, a, fe->prec, fe->flags); - break; - case MATH_OP_LOG: - fe->status |= bf_log(r, a, fe->prec, fe->flags); - break; - case MATH_OP_SIN: - fe->status |= bf_sin(r, a, fe->prec, fe->flags); - break; - case MATH_OP_TAN: - fe->status |= bf_tan(r, a, fe->prec, fe->flags); - break; - case MATH_OP_SIGN: - if (bf_is_nan(a) || bf_is_zero(a)) { - bf_set(r, a); - } else { - bf_set_si(r, 1 - 2 * a->sign); - } - break; - default: - abort(); - } - if (a == &a_s) - bf_delete(a); - JS_FreeValue(ctx, op1); - return res; -} - -static JSValue js_bigfloat_fop2(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - bf_t a_s, *a, b_s, *b, r_s, *r = &r_s; - JSFloatEnv *fe; - JSValue op1, op2, res; - - op1 = JS_ToNumeric(ctx, argv[0]); - if (JS_IsException(op1)) - return op1; - op2 = JS_ToNumeric(ctx, argv[1]); - if (JS_IsException(op2)) { - JS_FreeValue(ctx, op1); - return op2; - } - a = JS_ToBigFloat(ctx, &a_s, op1); - if (!a) - goto fail1; - b = JS_ToBigFloat(ctx, &b_s, op2); - if (!b) - goto fail2; - fe = &ctx->fp_env; - if (argc > 2) { - fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV); - if (!fe) - goto fail; - } - res = JS_NewBigFloat(ctx); - if (JS_IsException(res)) { - fail: - if (b == &b_s) - bf_delete(b); - fail2: - if (a == &a_s) - bf_delete(a); - fail1: - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - return JS_EXCEPTION; - } - r = JS_GetBigFloat(res); - switch (magic) { - case MATH_OP_ATAN2: - fe->status |= bf_atan2(r, a, b, fe->prec, fe->flags); - break; - case MATH_OP_POW: - fe->status |= bf_pow(r, a, b, fe->prec, fe->flags | BF_POW_JS_QUIRKS); - break; - case MATH_OP_FMOD: - fe->status |= bf_rem(r, a, b, fe->prec, fe->flags, BF_RNDZ); - break; - case MATH_OP_REM: - fe->status |= bf_rem(r, a, b, fe->prec, fe->flags, BF_RNDN); - break; - case MATH_OP_ADD: - fe->status |= bf_add(r, a, b, fe->prec, fe->flags); - break; - case MATH_OP_SUB: - fe->status |= bf_sub(r, a, b, fe->prec, fe->flags); - break; - case MATH_OP_MUL: - fe->status |= bf_mul(r, a, b, fe->prec, fe->flags); - break; - case MATH_OP_DIV: - fe->status |= bf_div(r, a, b, fe->prec, fe->flags); - break; - default: - abort(); - } - if (a == &a_s) - bf_delete(a); - if (b == &b_s) - bf_delete(b); - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - return res; -} - -static const JSCFunctionListEntry js_bigfloat_funcs[] = { - JS_CGETSET_MAGIC_DEF("PI", js_bigfloat_get_const, NULL, 0 ), - JS_CGETSET_MAGIC_DEF("LN2", js_bigfloat_get_const, NULL, 1 ), - JS_CGETSET_MAGIC_DEF("MIN_VALUE", js_bigfloat_get_const, NULL, 2 ), - JS_CGETSET_MAGIC_DEF("MAX_VALUE", js_bigfloat_get_const, NULL, 3 ), - JS_CGETSET_MAGIC_DEF("EPSILON", js_bigfloat_get_const, NULL, 4 ), - JS_CFUNC_DEF("parseFloat", 1, js_bigfloat_parseFloat ), - JS_CFUNC_DEF("isFinite", 1, js_bigfloat_isFinite ), - JS_CFUNC_DEF("isNaN", 1, js_bigfloat_isNaN ), - JS_CFUNC_MAGIC_DEF("abs", 1, js_bigfloat_fop, MATH_OP_ABS ), - JS_CFUNC_MAGIC_DEF("fpRound", 1, js_bigfloat_fop, MATH_OP_FPROUND ), - JS_CFUNC_MAGIC_DEF("floor", 1, js_bigfloat_fop, MATH_OP_FLOOR ), - JS_CFUNC_MAGIC_DEF("ceil", 1, js_bigfloat_fop, MATH_OP_CEIL ), - JS_CFUNC_MAGIC_DEF("round", 1, js_bigfloat_fop, MATH_OP_ROUND ), - JS_CFUNC_MAGIC_DEF("trunc", 1, js_bigfloat_fop, MATH_OP_TRUNC ), - JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigfloat_fop, MATH_OP_SQRT ), - JS_CFUNC_MAGIC_DEF("acos", 1, js_bigfloat_fop, MATH_OP_ACOS ), - JS_CFUNC_MAGIC_DEF("asin", 1, js_bigfloat_fop, MATH_OP_ASIN ), - JS_CFUNC_MAGIC_DEF("atan", 1, js_bigfloat_fop, MATH_OP_ATAN ), - JS_CFUNC_MAGIC_DEF("atan2", 2, js_bigfloat_fop2, MATH_OP_ATAN2 ), - JS_CFUNC_MAGIC_DEF("cos", 1, js_bigfloat_fop, MATH_OP_COS ), - JS_CFUNC_MAGIC_DEF("exp", 1, js_bigfloat_fop, MATH_OP_EXP ), - JS_CFUNC_MAGIC_DEF("log", 1, js_bigfloat_fop, MATH_OP_LOG ), - JS_CFUNC_MAGIC_DEF("pow", 2, js_bigfloat_fop2, MATH_OP_POW ), - JS_CFUNC_MAGIC_DEF("sin", 1, js_bigfloat_fop, MATH_OP_SIN ), - JS_CFUNC_MAGIC_DEF("tan", 1, js_bigfloat_fop, MATH_OP_TAN ), - JS_CFUNC_MAGIC_DEF("sign", 1, js_bigfloat_fop, MATH_OP_SIGN ), - JS_CFUNC_MAGIC_DEF("add", 2, js_bigfloat_fop2, MATH_OP_ADD ), - JS_CFUNC_MAGIC_DEF("sub", 2, js_bigfloat_fop2, MATH_OP_SUB ), - JS_CFUNC_MAGIC_DEF("mul", 2, js_bigfloat_fop2, MATH_OP_MUL ), - JS_CFUNC_MAGIC_DEF("div", 2, js_bigfloat_fop2, MATH_OP_DIV ), - JS_CFUNC_MAGIC_DEF("fmod", 2, js_bigfloat_fop2, MATH_OP_FMOD ), - JS_CFUNC_MAGIC_DEF("remainder", 2, js_bigfloat_fop2, MATH_OP_REM ), + JS_CFUNC_MAGIC_DEF("setDate", 1, set_date_field, 0x231 ), + JS_CFUNC_MAGIC_DEF("setUTCDate", 1, set_date_field, 0x230 ), + JS_CFUNC_MAGIC_DEF("setMonth", 2, set_date_field, 0x131 ), + JS_CFUNC_MAGIC_DEF("setUTCMonth", 2, set_date_field, 0x130 ), + JS_CFUNC_DEF("setYear", 1, js_date_setYear ), + JS_CFUNC_MAGIC_DEF("setFullYear", 3, set_date_field, 0x031 ), + JS_CFUNC_MAGIC_DEF("setUTCFullYear", 3, set_date_field, 0x030 ), + JS_CFUNC_DEF("toJSON", 1, js_date_toJSON ), }; -/* FloatEnv */ - -static JSValue js_float_env_constructor(JSContext *ctx, - JSValueConst new_target, - int argc, JSValueConst *argv) +JSValue JS_NewDate(JSContext *ctx, double epoch_ms) { - JSValue obj; - JSFloatEnv *fe; - int64_t prec; - int flags, rndmode; - - prec = ctx->fp_env.prec; - flags = ctx->fp_env.flags; - if (!JS_IsUndefined(argv[0])) { - if (JS_ToInt64Sat(ctx, &prec, argv[0])) - return JS_EXCEPTION; - if (prec < BF_PREC_MIN || prec > BF_PREC_MAX) - return JS_ThrowRangeError(ctx, "invalid precision"); - flags = BF_RNDN; /* RNDN, max exponent size, no subnormal */ - if (argc > 1 && !JS_IsUndefined(argv[1])) { - if (JS_ToInt32Sat(ctx, &rndmode, argv[1])) - return JS_EXCEPTION; - if (rndmode < BF_RNDN || rndmode > BF_RNDF) - return JS_ThrowRangeError(ctx, "invalid rounding mode"); - flags = rndmode; - } - } - - obj = JS_NewObjectClass(ctx, JS_CLASS_FLOAT_ENV); + JSValue obj = js_create_from_ctor(ctx, JS_UNDEFINED, JS_CLASS_DATE); if (JS_IsException(obj)) return JS_EXCEPTION; - fe = js_malloc(ctx, sizeof(*fe)); - if (!fe) - return JS_EXCEPTION; - fe->prec = prec; - fe->flags = flags; - fe->status = 0; - JS_SetOpaque(obj, fe); + JS_SetObjectData(ctx, obj, js_float64(time_clip(epoch_ms))); return obj; } -static void js_float_env_finalizer(JSRuntime *rt, JSValue val) -{ - JSFloatEnv *fe = JS_GetOpaque(val, JS_CLASS_FLOAT_ENV); - js_free_rt(rt, fe); -} - -static JSValue js_float_env_get_prec(JSContext *ctx, JSValueConst this_val) -{ - return JS_NewInt64(ctx, ctx->fp_env.prec); -} - -static JSValue js_float_env_get_expBits(JSContext *ctx, JSValueConst this_val) +bool JS_IsDate(JSValue v) { - return JS_NewInt32(ctx, bf_get_exp_bits(ctx->fp_env.flags)); + if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT) + return false; + return JS_VALUE_GET_OBJ(v)->class_id == JS_CLASS_DATE; } -static JSValue js_float_env_setPrec(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv) +void JS_AddIntrinsicDate(JSContext *ctx) { - JSValueConst func; - int exp_bits, flags, saved_flags; - JSValue ret; - limb_t saved_prec; - int64_t prec; - - func = argv[0]; - if (JS_ToInt64Sat(ctx, &prec, argv[1])) - return JS_EXCEPTION; - if (prec < BF_PREC_MIN || prec > BF_PREC_MAX) - return JS_ThrowRangeError(ctx, "invalid precision"); - exp_bits = BF_EXP_BITS_MAX; - - if (argc > 2 && !JS_IsUndefined(argv[2])) { - if (JS_ToInt32Sat(ctx, &exp_bits, argv[2])) - return JS_EXCEPTION; - if (exp_bits < BF_EXP_BITS_MIN || exp_bits > BF_EXP_BITS_MAX) - return JS_ThrowRangeError(ctx, "invalid number of exponent bits"); - } - - flags = BF_RNDN | BF_FLAG_SUBNORMAL | bf_set_exp_bits(exp_bits); - - saved_prec = ctx->fp_env.prec; - saved_flags = ctx->fp_env.flags; - - ctx->fp_env.prec = prec; - ctx->fp_env.flags = flags; + JSValue obj; - ret = JS_Call(ctx, func, JS_UNDEFINED, 0, NULL); - /* always restore the floating point precision */ - ctx->fp_env.prec = saved_prec; - ctx->fp_env.flags = saved_flags; - return ret; + /* Date */ + ctx->class_proto[JS_CLASS_DATE] = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_DATE], js_date_proto_funcs, + countof(js_date_proto_funcs)); + obj = JS_NewGlobalCConstructor(ctx, "Date", js_date_constructor, 7, + ctx->class_proto[JS_CLASS_DATE]); + JS_SetPropertyFunctionList(ctx, obj, js_date_funcs, countof(js_date_funcs)); } -#define FE_PREC (-1) -#define FE_EXP (-2) -#define FE_RNDMODE (-3) -#define FE_SUBNORMAL (-4) +/* eval */ -static JSValue js_float_env_proto_get_status(JSContext *ctx, JSValueConst this_val, int magic) +void JS_AddIntrinsicEval(JSContext *ctx) { - JSFloatEnv *fe; - fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV); - if (!fe) - return JS_EXCEPTION; - switch(magic) { - case FE_PREC: - return JS_NewInt64(ctx, fe->prec); - case FE_EXP: - return JS_NewInt32(ctx, bf_get_exp_bits(fe->flags)); - case FE_RNDMODE: - return JS_NewInt32(ctx, fe->flags & BF_RND_MASK); - case FE_SUBNORMAL: - return JS_NewBool(ctx, fe->flags & BF_FLAG_SUBNORMAL); - default: - return JS_NewBool(ctx, fe->status & magic); - } + ctx->eval_internal = __JS_EvalInternal; } -static JSValue js_float_env_proto_set_status(JSContext *ctx, JSValueConst this_val, JSValueConst val, int magic) -{ - JSFloatEnv *fe; - int b; - int64_t prec; - - fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV); - if (!fe) - return JS_EXCEPTION; - switch(magic) { - case FE_PREC: - if (JS_ToInt64Sat(ctx, &prec, val)) - return JS_EXCEPTION; - if (prec < BF_PREC_MIN || prec > BF_PREC_MAX) - return JS_ThrowRangeError(ctx, "invalid precision"); - fe->prec = prec; - break; - case FE_EXP: - if (JS_ToInt32Sat(ctx, &b, val)) - return JS_EXCEPTION; - if (b < BF_EXP_BITS_MIN || b > BF_EXP_BITS_MAX) - return JS_ThrowRangeError(ctx, "invalid number of exponent bits"); - fe->flags = (fe->flags & ~(BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)) | - bf_set_exp_bits(b); - break; - case FE_RNDMODE: - b = bigfloat_get_rnd_mode(ctx, val); - if (b < 0) - return JS_EXCEPTION; - fe->flags = (fe->flags & ~BF_RND_MASK) | b; - break; - case FE_SUBNORMAL: - b = JS_ToBool(ctx, val); - fe->flags = (fe->flags & ~BF_FLAG_SUBNORMAL) | (b ? BF_FLAG_SUBNORMAL: 0); - break; - default: - b = JS_ToBool(ctx, val); - fe->status = (fe->status & ~magic) & ((-b) & magic); - break; - } - return JS_UNDEFINED; -} +/* BigInt */ -static JSValue js_float_env_clearStatus(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val) { - JSFloatEnv *fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV); - if (!fe) - return JS_EXCEPTION; - fe->status = 0; - return JS_UNDEFINED; -} - -static const JSCFunctionListEntry js_float_env_funcs[] = { - JS_CGETSET_DEF("prec", js_float_env_get_prec, NULL ), - JS_CGETSET_DEF("expBits", js_float_env_get_expBits, NULL ), - JS_CFUNC_DEF("setPrec", 2, js_float_env_setPrec ), - JS_PROP_INT32_DEF("RNDN", BF_RNDN, 0 ), - JS_PROP_INT32_DEF("RNDZ", BF_RNDZ, 0 ), - JS_PROP_INT32_DEF("RNDU", BF_RNDU, 0 ), - JS_PROP_INT32_DEF("RNDD", BF_RNDD, 0 ), - JS_PROP_INT32_DEF("RNDNA", BF_RNDNA, 0 ), - JS_PROP_INT32_DEF("RNDA", BF_RNDA, 0 ), - JS_PROP_INT32_DEF("RNDF", BF_RNDF, 0 ), - JS_PROP_INT32_DEF("precMin", BF_PREC_MIN, 0 ), - JS_PROP_INT64_DEF("precMax", BF_PREC_MAX, 0 ), - JS_PROP_INT32_DEF("expBitsMin", BF_EXP_BITS_MIN, 0 ), - JS_PROP_INT32_DEF("expBitsMax", BF_EXP_BITS_MAX, 0 ), -}; - -static const JSCFunctionListEntry js_float_env_proto_funcs[] = { - JS_CGETSET_MAGIC_DEF("prec", js_float_env_proto_get_status, - js_float_env_proto_set_status, FE_PREC ), - JS_CGETSET_MAGIC_DEF("expBits", js_float_env_proto_get_status, - js_float_env_proto_set_status, FE_EXP ), - JS_CGETSET_MAGIC_DEF("rndMode", js_float_env_proto_get_status, - js_float_env_proto_set_status, FE_RNDMODE ), - JS_CGETSET_MAGIC_DEF("subnormal", js_float_env_proto_get_status, - js_float_env_proto_set_status, FE_SUBNORMAL ), - JS_CGETSET_MAGIC_DEF("invalidOperation", js_float_env_proto_get_status, - js_float_env_proto_set_status, BF_ST_INVALID_OP ), - JS_CGETSET_MAGIC_DEF("divideByZero", js_float_env_proto_get_status, - js_float_env_proto_set_status, BF_ST_DIVIDE_ZERO ), - JS_CGETSET_MAGIC_DEF("overflow", js_float_env_proto_get_status, - js_float_env_proto_set_status, BF_ST_OVERFLOW ), - JS_CGETSET_MAGIC_DEF("underflow", js_float_env_proto_get_status, - js_float_env_proto_set_status, BF_ST_UNDERFLOW ), - JS_CGETSET_MAGIC_DEF("inexact", js_float_env_proto_get_status, - js_float_env_proto_set_status, BF_ST_INEXACT ), - JS_CFUNC_DEF("clearStatus", 0, js_float_env_clearStatus ), -}; + uint32_t tag; -void JS_AddIntrinsicBigFloat(JSContext *ctx) -{ - JSRuntime *rt = ctx->rt; - JSValueConst obj1; - - rt->bigfloat_ops.to_string = js_bigfloat_to_string; - rt->bigfloat_ops.from_string = js_string_to_bigfloat; - rt->bigfloat_ops.unary_arith = js_unary_arith_bigfloat; - rt->bigfloat_ops.binary_arith = js_binary_arith_bigfloat; - rt->bigfloat_ops.compare = js_compare_bigfloat; - rt->bigfloat_ops.mul_pow10_to_float64 = js_mul_pow10_to_float64; - rt->bigfloat_ops.mul_pow10 = js_mul_pow10; - - ctx->class_proto[JS_CLASS_BIG_FLOAT] = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT], - js_bigfloat_proto_funcs, - countof(js_bigfloat_proto_funcs)); - 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)); - - ctx->class_proto[JS_CLASS_FLOAT_ENV] = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_FLOAT_ENV], - js_float_env_proto_funcs, - countof(js_float_env_proto_funcs)); - obj1 = JS_NewGlobalCConstructorOnly(ctx, "BigFloatEnv", - js_float_env_constructor, 1, - ctx->class_proto[JS_CLASS_FLOAT_ENV]); - JS_SetPropertyFunctionList(ctx, obj1, js_float_env_funcs, - countof(js_float_env_funcs)); -} - -/* BigDecimal */ - -static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val, - BOOL allow_null_or_undefined) -{ redo: - switch(JS_VALUE_GET_NORM_TAG(val)) { - case JS_TAG_BIG_DECIMAL: - break; - case JS_TAG_NULL: - if (!allow_null_or_undefined) - goto fail; - /* fall thru */ - case JS_TAG_BOOL: + tag = JS_VALUE_GET_NORM_TAG(val); + switch(tag) { case JS_TAG_INT: - { - bfdec_t *r; - int32_t v = JS_VALUE_GET_INT(val); - - val = JS_NewBigDecimal(ctx); - if (JS_IsException(val)) - break; - r = JS_GetBigDecimal(val); - if (bfdec_set_si(r, v)) { - JS_FreeValue(ctx, val); - val = JS_EXCEPTION; - break; - } - } + case JS_TAG_BOOL: + val = JS_NewBigInt64(ctx, JS_VALUE_GET_INT(val)); break; - case JS_TAG_FLOAT64: case JS_TAG_BIG_INT: - case JS_TAG_BIG_FLOAT: - val = JS_ToStringFree(ctx, val); - if (JS_IsException(val)) - break; - goto redo; - case JS_TAG_STRING: + break; + case JS_TAG_FLOAT64: { - const char *str, *p; - size_t len; - int err; + bf_t *a, a_s; - str = JS_ToCStringLen(ctx, &len, val); - JS_FreeValue(ctx, val); - if (!str) - return JS_EXCEPTION; - p = str; - p += skip_spaces(p); - if ((p - str) == len) { - bfdec_t *r; - val = JS_NewBigDecimal(ctx); - if (JS_IsException(val)) - break; - r = JS_GetBigDecimal(val); - bfdec_set_zero(r, 0); - err = 0; + a = JS_ToBigInt1(ctx, &a_s, val); + if (!bf_is_finite(a)) { + JS_FreeValue(ctx, val); + val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to BigInt"); } else { - val = js_atof(ctx, p, &p, 0, ATOD_TYPE_BIG_DECIMAL); - if (JS_IsException(val)) { - JS_FreeCString(ctx, str); + JSValue val1 = JS_NewBigInt(ctx); + bf_t *r; + int ret; + if (JS_IsException(val1)) { + JS_FreeValue(ctx, val); return JS_EXCEPTION; } - p += skip_spaces(p); - err = ((p - str) != len); - } - JS_FreeCString(ctx, str); - if (err) { + r = JS_GetBigInt(val1); + ret = bf_set(r, a); + ret |= bf_rint(r, BF_RNDZ); JS_FreeValue(ctx, val); - return JS_ThrowSyntaxError(ctx, "invalid bigdecimal literal"); + if (ret & BF_ST_MEM_ERROR) { + JS_FreeValue(ctx, val1); + val = JS_ThrowOutOfMemory(ctx); + } else if (ret & BF_ST_INEXACT) { + JS_FreeValue(ctx, val1); + val = JS_ThrowRangeError(ctx, "cannot convert to BigInt: not an integer"); + } else { + val = JS_CompactBigInt(ctx, val1); + } } + if (a == &a_s) + bf_delete(a); } break; + case JS_TAG_STRING: + val = JS_StringToBigIntErr(ctx, val); + break; case JS_TAG_OBJECT: val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER); if (JS_IsException(val)) break; goto redo; + case JS_TAG_NULL: case JS_TAG_UNDEFINED: - { - bfdec_t *r; - if (!allow_null_or_undefined) - goto fail; - val = JS_NewBigDecimal(ctx); - if (JS_IsException(val)) - break; - r = JS_GetBigDecimal(val); - bfdec_set_nan(r); - } - break; default: - fail: JS_FreeValue(ctx, val); - return JS_ThrowTypeError(ctx, "cannot convert to bigdecimal"); + return JS_ThrowTypeError(ctx, "cannot convert to BigInt"); } return val; } -static JSValue js_bigdecimal_constructor(JSContext *ctx, - JSValueConst new_target, - int argc, JSValueConst *argv) +static JSValue js_bigint_constructor(JSContext *ctx, + JSValue new_target, + int argc, JSValue *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); - if (JS_IsException(val)) - return val; - r = JS_GetBigDecimal(val); - bfdec_set_zero(r, 0); - } else { - val = JS_ToBigDecimalFree(ctx, JS_DupValue(ctx, argv[0]), FALSE); - } - return val; + return JS_ToBigIntCtorFree(ctx, js_dup(argv[0])); } -static JSValue js_thisBigDecimalValue(JSContext *ctx, JSValueConst this_val) +static JSValue js_thisBigIntValue(JSContext *ctx, JSValue this_val) { - if (JS_IsBigDecimal(this_val)) - return JS_DupValue(ctx, this_val); + if (JS_IsBigInt(ctx, this_val)) + return js_dup(this_val); if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) { JSObject *p = JS_VALUE_GET_OBJ(this_val); - if (p->class_id == JS_CLASS_BIG_DECIMAL) { - if (JS_IsBigDecimal(p->u.object_data)) - return JS_DupValue(ctx, p->u.object_data); + if (p->class_id == JS_CLASS_BIG_INT) { + if (JS_IsBigInt(ctx, p->u.object_data)) + return js_dup(p->u.object_data); } } - return JS_ThrowTypeError(ctx, "not a bigdecimal"); + return JS_ThrowTypeError(ctx, "not a BigInt"); } -static JSValue js_bigdecimal_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_bigint_toString(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue val; + int base; + JSValue ret; - val = js_thisBigDecimalValue(ctx, this_val); + val = js_thisBigIntValue(ctx, this_val); if (JS_IsException(val)) return val; - return JS_ToStringFree(ctx, val); -} - -static JSValue js_bigdecimal_valueOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return js_thisBigDecimalValue(ctx, this_val); -} - -static int js_bigdecimal_get_rnd_mode(JSContext *ctx, JSValueConst obj) -{ - const char *str; - size_t size; - int rnd_mode; - - str = JS_ToCStringLen(ctx, &size, obj); - if (!str) - return -1; - if (strlen(str) != size) - goto invalid_rounding_mode; - if (!strcmp(str, "floor")) { - rnd_mode = BF_RNDD; - } else if (!strcmp(str, "ceiling")) { - rnd_mode = BF_RNDU; - } else if (!strcmp(str, "down")) { - rnd_mode = BF_RNDZ; - } else if (!strcmp(str, "up")) { - rnd_mode = BF_RNDA; - } else if (!strcmp(str, "half-even")) { - rnd_mode = BF_RNDN; - } else if (!strcmp(str, "half-up")) { - rnd_mode = BF_RNDNA; - } else { - invalid_rounding_mode: - JS_FreeCString(ctx, str); - JS_ThrowTypeError(ctx, "invalid rounding mode"); - return -1; - } - JS_FreeCString(ctx, str); - return rnd_mode; -} - -typedef struct { - int64_t prec; - bf_flags_t flags; -} BigDecimalEnv; - -static int js_bigdecimal_get_env(JSContext *ctx, BigDecimalEnv *fe, - JSValueConst obj) -{ - JSValue prop; - int64_t val; - BOOL has_prec; - int rnd_mode; - - if (!JS_IsObject(obj)) { - JS_ThrowTypeErrorNotAnObject(ctx); - return -1; - } - prop = JS_GetProperty(ctx, obj, JS_ATOM_roundingMode); - if (JS_IsException(prop)) - return -1; - rnd_mode = js_bigdecimal_get_rnd_mode(ctx, prop); - JS_FreeValue(ctx, prop); - if (rnd_mode < 0) - return -1; - fe->flags = rnd_mode; - - prop = JS_GetProperty(ctx, obj, JS_ATOM_maximumSignificantDigits); - if (JS_IsException(prop)) - return -1; - has_prec = FALSE; - if (!JS_IsUndefined(prop)) { - if (JS_ToInt64SatFree(ctx, &val, prop)) - return -1; - if (val < 1 || val > BF_PREC_MAX) - goto invalid_precision; - fe->prec = val; - has_prec = TRUE; - } - - prop = JS_GetProperty(ctx, obj, JS_ATOM_maximumFractionDigits); - if (JS_IsException(prop)) - return -1; - if (!JS_IsUndefined(prop)) { - if (has_prec) { - JS_FreeValue(ctx, prop); - JS_ThrowTypeError(ctx, "cannot provide both maximumSignificantDigits and maximumFractionDigits"); - return -1; - } - if (JS_ToInt64SatFree(ctx, &val, prop)) - return -1; - if (val < 0 || val > BF_PREC_MAX) { - invalid_precision: - JS_ThrowTypeError(ctx, "invalid precision"); - return -1; - } - fe->prec = val; - fe->flags |= BF_FLAG_RADPNT_PREC; - has_prec = TRUE; - } - if (!has_prec) { - JS_ThrowTypeError(ctx, "precision must be present"); - return -1; - } - return 0; -} - - -static JSValue js_bigdecimal_fop(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - bfdec_t *a, *b, r_s, *r = &r_s; - JSValue op1, op2, res; - BigDecimalEnv fe_s, *fe = &fe_s; - int op_count, ret; - - if (magic == MATH_OP_SQRT || - magic == MATH_OP_ROUND) - op_count = 1; - else - op_count = 2; - - op1 = JS_ToNumeric(ctx, argv[0]); - if (JS_IsException(op1)) - return op1; - a = JS_ToBigDecimal(ctx, op1); - if (!a) { - JS_FreeValue(ctx, op1); - return JS_EXCEPTION; - } - if (op_count >= 2) { - op2 = JS_ToNumeric(ctx, argv[1]); - if (JS_IsException(op2)) { - JS_FreeValue(ctx, op1); - return op2; - } - b = JS_ToBigDecimal(ctx, op2); - if (!b) - goto fail; - } else { - op2 = JS_UNDEFINED; - b = NULL; - } - fe->flags = BF_RNDZ; - fe->prec = BF_PREC_INF; - if (op_count < argc) { - if (js_bigdecimal_get_env(ctx, fe, argv[op_count])) - goto fail; - } - - res = JS_NewBigDecimal(ctx); - if (JS_IsException(res)) { - fail: - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - return JS_EXCEPTION; - } - r = JS_GetBigDecimal(res); - switch (magic) { - case MATH_OP_ADD: - ret = bfdec_add(r, a, b, fe->prec, fe->flags); - break; - case MATH_OP_SUB: - ret = bfdec_sub(r, a, b, fe->prec, fe->flags); - break; - case MATH_OP_MUL: - ret = bfdec_mul(r, a, b, fe->prec, fe->flags); - break; - case MATH_OP_DIV: - ret = bfdec_div(r, a, b, fe->prec, fe->flags); - break; - case MATH_OP_FMOD: - ret = bfdec_rem(r, a, b, fe->prec, fe->flags, BF_RNDZ); - break; - case MATH_OP_SQRT: - ret = bfdec_sqrt(r, a, fe->prec, fe->flags); - break; - case MATH_OP_ROUND: - ret = bfdec_set(r, a); - if (!(ret & BF_ST_MEM_ERROR)) - ret = bfdec_round(r, fe->prec, fe->flags); - break; - default: - abort(); - } - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - ret &= BF_ST_MEM_ERROR | BF_ST_DIVIDE_ZERO | BF_ST_INVALID_OP | - BF_ST_OVERFLOW; - if (ret != 0) { - JS_FreeValue(ctx, res); - return throw_bf_exception(ctx, ret); + if (argc == 0 || JS_IsUndefined(argv[0])) { + base = 10; } else { - return res; - } -} - -static JSValue js_bigdecimal_toFixed(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val, ret; - int64_t f; - int rnd_mode; - - val = js_thisBigDecimalValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (JS_ToInt64Sat(ctx, &f, argv[0])) - goto fail; - if (f < 0 || f > BF_PREC_MAX) { - JS_ThrowRangeError(ctx, "invalid number of digits"); - goto fail; - } - rnd_mode = BF_RNDNA; - if (argc > 1) { - rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]); - if (rnd_mode < 0) + base = js_get_radix(ctx, argv[0]); + if (base < 0) goto fail; } - ret = js_bigdecimal_to_string1(ctx, val, f, rnd_mode | BF_FTOA_FORMAT_FRAC); + ret = js_bigint_to_string1(ctx, val, base); JS_FreeValue(ctx, val); return ret; fail: @@ -52699,123 +51595,76 @@ static JSValue js_bigdecimal_toFixed(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static JSValue js_bigdecimal_toExponential(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_bigint_valueOf(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - JSValue val, ret; - int64_t f; - int rnd_mode; - - val = js_thisBigDecimalValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (JS_ToInt64Sat(ctx, &f, argv[0])) - goto fail; - if (JS_IsUndefined(argv[0])) { - ret = js_bigdecimal_to_string1(ctx, val, 0, - BF_RNDN | BF_FTOA_FORMAT_FREE_MIN | BF_FTOA_FORCE_EXP); - } else { - if (f < 0 || f > BF_PREC_MAX) { - JS_ThrowRangeError(ctx, "invalid number of digits"); - goto fail; - } - rnd_mode = BF_RNDNA; - if (argc > 1) { - rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]); - if (rnd_mode < 0) - goto fail; - } - ret = js_bigdecimal_to_string1(ctx, val, f + 1, - rnd_mode | BF_FTOA_FORMAT_FIXED | BF_FTOA_FORCE_EXP); - } - JS_FreeValue(ctx, val); - return ret; - fail: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; + return js_thisBigIntValue(ctx, this_val); } -static JSValue js_bigdecimal_toPrecision(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_bigint_asUintN(JSContext *ctx, + JSValue this_val, + int argc, JSValue *argv, int asIntN) { - JSValue val, ret; - int64_t p; - int rnd_mode; + uint64_t bits; + bf_t a_s, *a = &a_s, *r, mask_s, *mask = &mask_s; + JSValue res; - val = js_thisBigDecimalValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (JS_IsUndefined(argv[0])) { - return JS_ToStringFree(ctx, val); - } - if (JS_ToInt64Sat(ctx, &p, argv[0])) - goto fail; - if (p < 1 || p > BF_PREC_MAX) { - JS_ThrowRangeError(ctx, "invalid number of digits"); - goto fail; + if (JS_ToIndex(ctx, &bits, argv[0])) + return JS_EXCEPTION; + res = JS_NewBigInt(ctx); + if (JS_IsException(res)) + return JS_EXCEPTION; + a = JS_ToBigInt(ctx, &a_s, argv[1]); + if (!a) { + JS_FreeValue(ctx, res); + return JS_EXCEPTION; } - rnd_mode = BF_RNDNA; - if (argc > 1) { - rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]); - if (rnd_mode < 0) - goto fail; + /* XXX: optimize */ + r = JS_GetBigInt(res); + bf_init(ctx->bf_ctx, mask); + bf_set_ui(mask, 1); + bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ); + bf_add_si(mask, mask, -1, BF_PREC_INF, BF_RNDZ); + bf_logic_and(r, a, mask); + if (asIntN && bits != 0) { + bf_set_ui(mask, 1); + bf_mul_2exp(mask, bits - 1, BF_PREC_INF, BF_RNDZ); + if (bf_cmpu(r, mask) >= 0) { + bf_set_ui(mask, 1); + bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ); + bf_sub(r, r, mask, BF_PREC_INF, BF_RNDZ); + } } - ret = js_bigdecimal_to_string1(ctx, val, p, - rnd_mode | BF_FTOA_FORMAT_FIXED); - JS_FreeValue(ctx, val); - return ret; - fail: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; + bf_delete(mask); + JS_FreeBigInt(ctx, a, &a_s); + return JS_CompactBigInt(ctx, res); } -static const JSCFunctionListEntry js_bigdecimal_proto_funcs[] = { - JS_CFUNC_DEF("toString", 0, js_bigdecimal_toString ), - JS_CFUNC_DEF("valueOf", 0, js_bigdecimal_valueOf ), - JS_CFUNC_DEF("toPrecision", 1, js_bigdecimal_toPrecision ), - JS_CFUNC_DEF("toFixed", 1, js_bigdecimal_toFixed ), - JS_CFUNC_DEF("toExponential", 1, js_bigdecimal_toExponential ), +static const JSCFunctionListEntry js_bigint_funcs[] = { + JS_CFUNC_MAGIC_DEF("asUintN", 2, js_bigint_asUintN, 0 ), + JS_CFUNC_MAGIC_DEF("asIntN", 2, js_bigint_asUintN, 1 ), }; -static const JSCFunctionListEntry js_bigdecimal_funcs[] = { - JS_CFUNC_MAGIC_DEF("add", 2, js_bigdecimal_fop, MATH_OP_ADD ), - JS_CFUNC_MAGIC_DEF("sub", 2, js_bigdecimal_fop, MATH_OP_SUB ), - JS_CFUNC_MAGIC_DEF("mul", 2, js_bigdecimal_fop, MATH_OP_MUL ), - JS_CFUNC_MAGIC_DEF("div", 2, js_bigdecimal_fop, MATH_OP_DIV ), - JS_CFUNC_MAGIC_DEF("mod", 2, js_bigdecimal_fop, MATH_OP_FMOD ), - JS_CFUNC_MAGIC_DEF("round", 1, js_bigdecimal_fop, MATH_OP_ROUND ), - JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigdecimal_fop, MATH_OP_SQRT ), +static const JSCFunctionListEntry js_bigint_proto_funcs[] = { + JS_CFUNC_DEF("toString", 0, js_bigint_toString ), + JS_CFUNC_DEF("valueOf", 0, js_bigint_valueOf ), + JS_PROP_STRING_DEF("[Symbol.toStringTag]", "BigInt", JS_PROP_CONFIGURABLE ), }; -void JS_AddIntrinsicBigDecimal(JSContext *ctx) +void JS_AddIntrinsicBigInt(JSContext *ctx) { - JSRuntime *rt = ctx->rt; - JSValueConst obj1; - - rt->bigdecimal_ops.to_string = js_bigdecimal_to_string; - rt->bigdecimal_ops.from_string = js_string_to_bigdecimal; - rt->bigdecimal_ops.unary_arith = js_unary_arith_bigdecimal; - rt->bigdecimal_ops.binary_arith = js_binary_arith_bigdecimal; - rt->bigdecimal_ops.compare = js_compare_bigdecimal; - - ctx->class_proto[JS_CLASS_BIG_DECIMAL] = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL], - js_bigdecimal_proto_funcs, - countof(js_bigdecimal_proto_funcs)); - 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)); -} + JSValue obj1; -void JS_EnableBignumExt(JSContext *ctx, BOOL enable) -{ - ctx->bignum_ext = enable; + ctx->class_proto[JS_CLASS_BIG_INT] = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_INT], + js_bigint_proto_funcs, + countof(js_bigint_proto_funcs)); + 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)); } -#endif /* CONFIG_BIGNUM */ - static const char * const native_error_name[JS_NATIVE_ERROR_COUNT] = { "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", "URIError", @@ -52833,18 +51682,8 @@ static void JS_AddIntrinsicBasicObjects(JSContext *ctx) ctx->function_proto = JS_NewCFunction3(ctx, js_function_proto, "", 0, JS_CFUNC_generic, 0, ctx->class_proto[JS_CLASS_OBJECT]); - ctx->class_proto[JS_CLASS_BYTECODE_FUNCTION] = JS_DupValue(ctx, ctx->function_proto); + ctx->class_proto[JS_CLASS_BYTECODE_FUNCTION] = js_dup(ctx->function_proto); ctx->class_proto[JS_CLASS_ERROR] = JS_NewObject(ctx); -#if 0 - /* these are auto-initialized from js_error_proto_funcs, - but delaying might be a problem */ - JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ERROR], JS_ATOM_name, - JS_AtomToString(ctx, JS_ATOM_Error), - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ERROR], JS_ATOM_message, - JS_AtomToString(ctx, JS_ATOM_empty_string), - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); -#endif JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ERROR], js_error_proto_funcs, countof(js_error_proto_funcs)); @@ -52881,7 +51720,7 @@ static void JS_AddIntrinsicBasicObjects(JSContext *ctx) void JS_AddIntrinsicBaseObjects(JSContext *ctx) { int i; - JSValueConst obj, number_obj; + JSValue obj, number_obj; JSValue obj1; ctx->throw_type_error = JS_NewCFunction(ctx, js_throw_type_error, NULL, 0); @@ -52897,7 +51736,7 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) JS_PROP_HAS_GET | JS_PROP_HAS_SET | JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE); JS_FreeValue(ctx, obj1); - JS_FreeValue(ctx, js_object_seal(ctx, JS_UNDEFINED, 1, (JSValueConst *)&ctx->throw_type_error, 1)); + JS_FreeValue(ctx, js_object_seal(ctx, JS_UNDEFINED, 1, &ctx->throw_type_error, 1)); ctx->global_obj = JS_NewObject(ctx); ctx->global_var_obj = JS_NewObjectProto(ctx, JS_NULL); @@ -52914,14 +51753,15 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) ctx->function_ctor = JS_NewCFunctionMagic(ctx, js_function_constructor, "Function", 1, JS_CFUNC_constructor_or_func_magic, JS_FUNC_NORMAL); - JS_NewGlobalCConstructor2(ctx, JS_DupValue(ctx, ctx->function_ctor), "Function", + JS_NewGlobalCConstructor2(ctx, js_dup(ctx->function_ctor), "Function", ctx->function_proto); /* Error */ - obj1 = JS_NewCFunctionMagic(ctx, js_error_constructor, - "Error", 1, JS_CFUNC_constructor_or_func_magic, -1); - JS_NewGlobalCConstructor2(ctx, obj1, + ctx->error_ctor = JS_NewCFunctionMagic(ctx, js_error_constructor, + "Error", 1, JS_CFUNC_constructor_or_func_magic, -1); + JS_NewGlobalCConstructor2(ctx, js_dup(ctx->error_ctor), "Error", ctx->class_proto[JS_CLASS_ERROR]); + JS_SetPropertyFunctionList(ctx, ctx->error_ctor, js_error_funcs, countof(js_error_funcs)); /* Used to squelch a -Wcast-function-type warning. */ JSCFunctionType ft = { .generic_magic = js_error_constructor }; @@ -52931,16 +51771,36 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) n_args = 1 + (i == JS_AGGREGATE_ERROR); func_obj = JS_NewCFunction3(ctx, ft.generic, native_error_name[i], n_args, - JS_CFUNC_constructor_or_func_magic, i, obj1); + JS_CFUNC_constructor_or_func_magic, i, + ctx->error_ctor); JS_NewGlobalCConstructor2(ctx, func_obj, native_error_name[i], ctx->native_error_proto[i]); } - /* Iterator prototype */ - ctx->iterator_proto = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, ctx->iterator_proto, + /* CallSite */ + _JS_AddIntrinsicCallSite(ctx); + + /* Iterator */ + ctx->class_proto[JS_CLASS_ITERATOR] = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ITERATOR], js_iterator_proto_funcs, countof(js_iterator_proto_funcs)); + obj = JS_NewGlobalCConstructor(ctx, "Iterator", js_iterator_constructor, 0, + ctx->class_proto[JS_CLASS_ITERATOR]); + ctx->iterator_ctor = js_dup(obj); + JS_SetPropertyFunctionList(ctx, obj, + js_iterator_funcs, + countof(js_iterator_funcs)); + + ctx->class_proto[JS_CLASS_ITERATOR_HELPER] = JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ITERATOR]); + JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ITERATOR_HELPER], + js_iterator_helper_proto_funcs, + countof(js_iterator_helper_proto_funcs)); + + ctx->class_proto[JS_CLASS_ITERATOR_WRAP] = JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ITERATOR]); + JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ITERATOR_WRAP], + js_iterator_wrap_proto_funcs, + countof(js_iterator_wrap_proto_funcs)); /* Array */ JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY], @@ -52949,7 +51809,7 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) obj = JS_NewGlobalCConstructor(ctx, "Array", js_array_constructor, 1, ctx->class_proto[JS_CLASS_ARRAY]); - ctx->array_ctor = JS_DupValue(ctx, obj); + ctx->array_ctor = js_dup(obj); JS_SetPropertyFunctionList(ctx, obj, js_array_funcs, countof(js_array_funcs)); @@ -52986,7 +51846,7 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) ctx->array_proto_values = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], JS_ATOM_values); - ctx->class_proto[JS_CLASS_ARRAY_ITERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto); + ctx->class_proto[JS_CLASS_ARRAY_ITERATOR] = JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ITERATOR]); JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY_ITERATOR], js_array_iterator_proto_funcs, countof(js_array_iterator_proto_funcs)); @@ -53000,7 +51860,7 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) /* Number */ ctx->class_proto[JS_CLASS_NUMBER] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_NUMBER); - JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_NUMBER], JS_NewInt32(ctx, 0)); + JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_NUMBER], js_int32(0)); JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_NUMBER], js_number_proto_funcs, countof(js_number_proto_funcs)); @@ -53011,7 +51871,7 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) /* Boolean */ ctx->class_proto[JS_CLASS_BOOLEAN] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_BOOLEAN); - JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_BOOLEAN], JS_NewBool(ctx, FALSE)); + JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_BOOLEAN], JS_FALSE); JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BOOLEAN], js_boolean_proto_funcs, countof(js_boolean_proto_funcs)); JS_NewGlobalCConstructor(ctx, "Boolean", js_boolean_constructor, 1, @@ -53028,7 +51888,7 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING], js_string_proto_funcs, countof(js_string_proto_funcs)); - ctx->class_proto[JS_CLASS_STRING_ITERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto); + ctx->class_proto[JS_CLASS_STRING_ITERATOR] = JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ITERATOR]); JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING_ITERATOR], js_string_iterator_proto_funcs, countof(js_string_iterator_proto_funcs)); @@ -53060,7 +51920,7 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) } /* ES6 Generator */ - ctx->class_proto[JS_CLASS_GENERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto); + ctx->class_proto[JS_CLASS_GENERATOR] = JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ITERATOR]); JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_GENERATOR], js_generator_proto_funcs, countof(js_generator_proto_funcs)); @@ -53083,11 +51943,11 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) /* global properties */ ctx->eval_obj = JS_NewCFunction(ctx, js_global_eval, "eval", 1); JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_eval, - JS_DupValue(ctx, ctx->eval_obj), + js_dup(ctx->eval_obj), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_globalThis, - JS_DupValue(ctx, ctx->global_obj), + js_dup(ctx->global_obj), JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE); } @@ -53095,21 +51955,30 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT] = { 0, 0, 0, 1, 1, 2, 2, - 3, 3, /* BigInt64Array, BigUint64Array */ - 2, 3 + 3, 3, // BigInt64Array, BigUint64Array + 1, 2, 3 // Float16Array, Float32Array, Float64Array }; static JSValue js_array_buffer_constructor3(JSContext *ctx, - JSValueConst new_target, - uint64_t len, JSClassID class_id, + JSValue new_target, + uint64_t len, uint64_t *max_len, + JSClassID class_id, uint8_t *buf, JSFreeArrayBufferDataFunc *free_func, - void *opaque, BOOL alloc_flag) + void *opaque, bool alloc_flag) { JSRuntime *rt = ctx->rt; JSValue obj; JSArrayBuffer *abuf = NULL; + uint64_t sab_alloc_len; + if (!alloc_flag && buf && max_len && free_func != js_array_buffer_free) { + // not observable from JS land, only through C API misuse; + // JS code cannot create externally managed buffers directly + return JS_ThrowInternalError(ctx, + "resizable ArrayBuffers not supported " + "for externally managed buffers"); + } obj = js_create_from_ctor(ctx, new_target, class_id); if (JS_IsException(obj)) return obj; @@ -53118,18 +51987,26 @@ static JSValue js_array_buffer_constructor3(JSContext *ctx, JS_ThrowRangeError(ctx, "invalid array buffer length"); goto fail; } + if (max_len && *max_len > INT32_MAX) { + JS_ThrowRangeError(ctx, "invalid max array buffer length"); + goto fail; + } abuf = js_malloc(ctx, sizeof(*abuf)); if (!abuf) goto fail; abuf->byte_length = len; + abuf->max_byte_length = max_len ? *max_len : -1; if (alloc_flag) { if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER && rt->sab_funcs.sab_alloc) { + // TOOD(bnoordhuis) resizing backing memory for SABs atomically + // is hard so we cheat and allocate |maxByteLength| bytes upfront + sab_alloc_len = max_len ? *max_len : len; abuf->data = rt->sab_funcs.sab_alloc(rt->sab_funcs.sab_opaque, - max_int(len, 1)); + max_int(sab_alloc_len, 1)); if (!abuf->data) goto fail; - memset(abuf->data, 0, len); + memset(abuf->data, 0, sab_alloc_len); } else { /* the allocation must be done after the object creation */ abuf->data = js_mallocz(ctx, max_int(len, 1)); @@ -53144,13 +52021,13 @@ static JSValue js_array_buffer_constructor3(JSContext *ctx, abuf->data = buf; } init_list_head(&abuf->array_list); - abuf->detached = FALSE; + abuf->detached = false; abuf->shared = (class_id == JS_CLASS_SHARED_ARRAY_BUFFER); abuf->opaque = opaque; abuf->free_func = free_func; if (alloc_flag && buf) memcpy(abuf->data, buf, len); - JS_SetOpaque(obj, abuf); + JS_SetOpaqueInternal(obj, abuf); return obj; fail: JS_FreeValue(ctx, obj); @@ -53164,59 +52041,94 @@ static void js_array_buffer_free(JSRuntime *rt, void *opaque, void *ptr) } static JSValue js_array_buffer_constructor2(JSContext *ctx, - JSValueConst new_target, - uint64_t len, JSClassID class_id) + JSValue new_target, + uint64_t len, uint64_t *max_len, + JSClassID class_id) { - return js_array_buffer_constructor3(ctx, new_target, len, class_id, - NULL, js_array_buffer_free, NULL, - TRUE); + return js_array_buffer_constructor3(ctx, new_target, len, max_len, + class_id, NULL, js_array_buffer_free, + NULL, true); } static JSValue js_array_buffer_constructor1(JSContext *ctx, - JSValueConst new_target, - uint64_t len) + JSValue new_target, + uint64_t len, uint64_t *max_len) { - return js_array_buffer_constructor2(ctx, new_target, len, + return js_array_buffer_constructor2(ctx, new_target, len, max_len, JS_CLASS_ARRAY_BUFFER); } JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len, JSFreeArrayBufferDataFunc *free_func, void *opaque, - BOOL is_shared) + bool is_shared) { - return js_array_buffer_constructor3(ctx, JS_UNDEFINED, len, - is_shared ? JS_CLASS_SHARED_ARRAY_BUFFER : JS_CLASS_ARRAY_BUFFER, - buf, free_func, opaque, FALSE); + JSClassID class_id = + is_shared ? JS_CLASS_SHARED_ARRAY_BUFFER : JS_CLASS_ARRAY_BUFFER; + return js_array_buffer_constructor3(ctx, JS_UNDEFINED, len, NULL, class_id, + buf, free_func, opaque, false); +} + +bool JS_IsArrayBuffer(JSValue obj) { + return JS_GetClassID(obj) == JS_CLASS_ARRAY_BUFFER; } /* create a new ArrayBuffer of length 'len' and copy 'buf' to it */ JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len) { - return js_array_buffer_constructor3(ctx, JS_UNDEFINED, len, + return js_array_buffer_constructor3(ctx, JS_UNDEFINED, len, NULL, JS_CLASS_ARRAY_BUFFER, (uint8_t *)buf, js_array_buffer_free, NULL, - TRUE); + true); } -static JSValue js_array_buffer_constructor(JSContext *ctx, - JSValueConst new_target, - int argc, JSValueConst *argv) +static JSValue js_array_buffer_constructor0(JSContext *ctx, JSValue new_target, + int argc, JSValue *argv, + JSClassID class_id) { - uint64_t len; + uint64_t len, max_len, *pmax_len = NULL; + JSValue obj, val; + int64_t i; + if (JS_ToIndex(ctx, &len, argv[0])) return JS_EXCEPTION; - return js_array_buffer_constructor1(ctx, new_target, len); + if (argc < 2) + goto next; + if (!JS_IsObject(argv[1])) + goto next; + obj = JS_ToObject(ctx, argv[1]); + if (JS_IsException(obj)) + return JS_EXCEPTION; + val = JS_GetProperty(ctx, obj, JS_ATOM_maxByteLength); + JS_FreeValue(ctx, obj); + if (JS_IsException(val)) + return JS_EXCEPTION; + if (JS_IsUndefined(val)) + goto next; + if (JS_ToInt64Free(ctx, &i, val)) + return JS_EXCEPTION; + // don't have to check i < 0 because len >= 0 + if (len > i || i > MAX_SAFE_INTEGER) + return JS_ThrowRangeError(ctx, "invalid array buffer max length"); + max_len = i; + pmax_len = &max_len; +next: + return js_array_buffer_constructor2(ctx, new_target, len, pmax_len, + class_id); +} + +static JSValue js_array_buffer_constructor(JSContext *ctx, JSValue new_target, + int argc, JSValue *argv) +{ + return js_array_buffer_constructor0(ctx, new_target, argc, argv, + JS_CLASS_ARRAY_BUFFER); } static JSValue js_shared_array_buffer_constructor(JSContext *ctx, - JSValueConst new_target, - int argc, JSValueConst *argv) + JSValue new_target, + int argc, JSValue *argv) { - uint64_t len; - if (JS_ToIndex(ctx, &len, argv[0])) - return JS_EXCEPTION; - return js_array_buffer_constructor2(ctx, new_target, len, + return js_array_buffer_constructor0(ctx, new_target, argc, argv, JS_CLASS_SHARED_ARRAY_BUFFER); } @@ -53256,20 +52168,17 @@ static void js_array_buffer_finalizer(JSRuntime *rt, JSValue val) } static JSValue js_array_buffer_isView(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv) + JSValue this_val, + int argc, JSValue *argv) { JSObject *p; - BOOL res; - res = FALSE; + if (JS_VALUE_GET_TAG(argv[0]) == JS_TAG_OBJECT) { p = JS_VALUE_GET_OBJ(argv[0]); - if (p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_DATAVIEW) { - res = TRUE; - } + return js_bool(is_typed_array(p->class_id) || + p->class_id == JS_CLASS_DATAVIEW); } - return JS_NewBool(ctx, res); + return JS_FALSE; } static const JSCFunctionListEntry js_array_buffer_funcs[] = { @@ -53282,18 +52191,56 @@ static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx) return JS_ThrowTypeError(ctx, "ArrayBuffer is detached"); } +static JSValue JS_ThrowTypeErrorArrayBufferOOB(JSContext *ctx) +{ + return JS_ThrowTypeError(ctx, "ArrayBuffer is detached or resized"); +} + +// #sec-get-arraybuffer.prototype.detached +static JSValue js_array_buffer_get_detached(JSContext *ctx, + JSValue this_val) +{ + JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, JS_CLASS_ARRAY_BUFFER); + if (!abuf) + return JS_EXCEPTION; + if (abuf->shared) + return JS_ThrowTypeError(ctx, "detached called on SharedArrayBuffer"); + return js_bool(abuf->detached); +} + static JSValue js_array_buffer_get_byteLength(JSContext *ctx, - JSValueConst this_val, + JSValue this_val, int class_id) { JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, class_id); if (!abuf) return JS_EXCEPTION; /* return 0 if detached */ - return JS_NewUint32(ctx, abuf->byte_length); + return js_uint32(abuf->byte_length); +} + +static JSValue js_array_buffer_get_maxByteLength(JSContext *ctx, + JSValue this_val, + int class_id) +{ + JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, class_id); + if (!abuf) + return JS_EXCEPTION; + if (array_buffer_is_resizable(abuf)) + return js_uint32(abuf->max_byte_length); + return js_uint32(abuf->byte_length); +} + +static JSValue js_array_buffer_get_resizable(JSContext *ctx, JSValue this_val, + int class_id) +{ + JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, class_id); + if (!abuf) + return JS_EXCEPTION; + return js_bool(array_buffer_is_resizable(abuf)); } -void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj) +void JS_DetachArrayBuffer(JSContext *ctx, JSValue obj) { JSArrayBuffer *abuf = JS_GetOpaque(obj, JS_CLASS_ARRAY_BUFFER); struct list_head *el; @@ -53304,7 +52251,7 @@ void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj) abuf->free_func(ctx->rt, abuf->opaque, abuf->data); abuf->data = NULL; abuf->byte_length = 0; - abuf->detached = TRUE; + abuf->detached = true; list_for_each(el, &abuf->array_list) { JSTypedArray *ta; @@ -53321,7 +52268,7 @@ void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj) } /* get an ArrayBuffer or SharedArrayBuffer */ -static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj) +static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValue obj) { JSObject *p; if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) @@ -53338,7 +52285,7 @@ static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj) /* return NULL if exception. WARNING: any JS call can detach the buffer and render the returned pointer invalid */ -uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj) +uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValue obj) { JSArrayBuffer *abuf = js_get_array_buffer(ctx, obj); if (!abuf) @@ -53354,9 +52301,148 @@ uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj) return NULL; } +static bool array_buffer_is_resizable(const JSArrayBuffer *abuf) +{ + return abuf->max_byte_length >= 0; +} + +// ES #sec-arraybuffer.prototype.transfer +static JSValue js_array_buffer_transfer(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) +{ + bool transfer_to_fixed_length = magic & 1; + JSArrayBuffer *abuf; + uint64_t new_len, old_len, max_len, *pmax_len; + uint8_t *bs, *new_bs; + + abuf = JS_GetOpaque2(ctx, this_val, JS_CLASS_ARRAY_BUFFER); + if (!abuf) + return JS_EXCEPTION; + if (abuf->shared) + return JS_ThrowTypeError(ctx, "cannot transfer a SharedArrayBuffer"); + if (argc < 1 || JS_IsUndefined(argv[0])) + new_len = abuf->byte_length; + else if (JS_ToIndex(ctx, &new_len, argv[0])) + return JS_EXCEPTION; + if (abuf->detached) + return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); + pmax_len = NULL; + if (!transfer_to_fixed_length) { + if (array_buffer_is_resizable(abuf)) { // carry over maxByteLength + max_len = abuf->max_byte_length; + if (new_len > max_len) + return JS_ThrowTypeError(ctx, "invalid array buffer length"); + // TODO(bnoordhuis) support externally managed RABs + if (abuf->free_func == js_array_buffer_free) + pmax_len = &max_len; + } + } + /* create an empty AB */ + if (new_len == 0) { + JS_DetachArrayBuffer(ctx, this_val); + return js_array_buffer_constructor2(ctx, JS_UNDEFINED, 0, pmax_len, + JS_CLASS_ARRAY_BUFFER); + } + bs = abuf->data; + old_len = abuf->byte_length; + /* if length mismatch, realloc. Otherwise, use the same backing buffer. */ + if (new_len != old_len) { + new_bs = js_realloc(ctx, bs, new_len); + if (!new_bs) + return JS_EXCEPTION; + bs = new_bs; + if (new_len > old_len) + memset(bs + old_len, 0, new_len - old_len); + } + /* neuter the backing buffer */ + abuf->data = NULL; + abuf->byte_length = 0; + abuf->detached = true; + return js_array_buffer_constructor3(ctx, JS_UNDEFINED, new_len, pmax_len, + JS_CLASS_ARRAY_BUFFER, + bs, abuf->free_func, + NULL, false); +} + +static JSValue js_array_buffer_resize(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int class_id) +{ + uint32_t size_log2, size_elem; + struct list_head *el; + JSArrayBuffer *abuf; + JSTypedArray *ta; + JSObject *p; + uint8_t *data; + int64_t len; + + abuf = JS_GetOpaque2(ctx, this_val, class_id); + if (!abuf) + return JS_EXCEPTION; + if (JS_ToInt64(ctx, &len, argv[0])) + return JS_EXCEPTION; + if (abuf->detached) + return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); + if (!array_buffer_is_resizable(abuf)) + return JS_ThrowTypeError(ctx, "array buffer is not resizable"); + // TODO(bnoordhuis) support externally managed RABs + if (abuf->free_func != js_array_buffer_free) + return JS_ThrowTypeError(ctx, "external array buffer is not resizable"); + if (len < 0 || len > abuf->max_byte_length) { + bad_length: + return JS_ThrowRangeError(ctx, "invalid array buffer length"); + } + // SABs can only grow and we don't need to realloc because + // js_array_buffer_constructor3 commits all memory upfront; + // regular RABs are resizable both ways and realloc + if (abuf->shared) { + if (len < abuf->byte_length) + goto bad_length; + // Note this is off-spec; there's supposed to be a single atomic + // |byteLength| property that's shared across SABs but we store + // it per SAB instead. That means when thread A calls sab.grow(2) + // at time t0, and thread B calls sab.grow(1) at time t1, we don't + // throw a TypeError in thread B as the spec says we should, + // instead both threads get their own view of the backing memory, + // 2 bytes big in A, and 1 byte big in B + abuf->byte_length = len; + } else { + data = js_realloc(ctx, abuf->data, max_int(len, 1)); + if (!data) + return JS_EXCEPTION; + if (len > abuf->byte_length) + memset(&data[abuf->byte_length], 0, len - abuf->byte_length); + abuf->byte_length = len; + abuf->data = data; + } + data = abuf->data; + // update lengths of all typed arrays backed by this array buffer + list_for_each(el, &abuf->array_list) { + ta = list_entry(el, JSTypedArray, link); + p = ta->obj; + if (p->class_id == JS_CLASS_DATAVIEW) + continue; + p->u.array.count = 0; + p->u.array.u.ptr = NULL; + size_log2 = typed_array_size_log2(p->class_id); + size_elem = 1 << size_log2; + if (ta->track_rab) { + if (len >= (int64_t)ta->offset + size_elem) { + p->u.array.count = (len - ta->offset) >> size_log2; + p->u.array.u.ptr = &data[ta->offset]; + } + } else { + if (len >= (int64_t)ta->offset + ta->length) { + p->u.array.count = ta->length >> size_log2; + p->u.array.u.ptr = &data[ta->offset]; + } + } + } + return JS_UNDEFINED; +} + static JSValue js_array_buffer_slice(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv, int class_id) + JSValue this_val, + int argc, JSValue *argv, int class_id) { JSArrayBuffer *abuf, *new_abuf; int64_t len, start, end, new_len; @@ -53383,11 +52469,11 @@ static JSValue js_array_buffer_slice(JSContext *ctx, return ctor; if (JS_IsUndefined(ctor)) { new_obj = js_array_buffer_constructor2(ctx, JS_UNDEFINED, new_len, - class_id); + NULL, class_id); } else { JSValue args[1]; - args[0] = JS_NewInt64(ctx, new_len); - new_obj = JS_CallConstructor(ctx, ctor, 1, (JSValueConst *)args); + args[0] = js_int64(new_len); + new_obj = JS_CallConstructor(ctx, ctor, 1, args); JS_FreeValue(ctx, ctor); JS_FreeValue(ctx, args[0]); } @@ -53422,7 +52508,13 @@ static JSValue js_array_buffer_slice(JSContext *ctx, static const JSCFunctionListEntry js_array_buffer_proto_funcs[] = { JS_CGETSET_MAGIC_DEF("byteLength", js_array_buffer_get_byteLength, NULL, JS_CLASS_ARRAY_BUFFER ), + JS_CGETSET_MAGIC_DEF("maxByteLength", js_array_buffer_get_maxByteLength, NULL, JS_CLASS_ARRAY_BUFFER ), + JS_CGETSET_MAGIC_DEF("resizable", js_array_buffer_get_resizable, NULL, JS_CLASS_ARRAY_BUFFER ), + JS_CGETSET_DEF("detached", js_array_buffer_get_detached, NULL ), + JS_CFUNC_MAGIC_DEF("resize", 1, js_array_buffer_resize, JS_CLASS_ARRAY_BUFFER ), JS_CFUNC_MAGIC_DEF("slice", 2, js_array_buffer_slice, JS_CLASS_ARRAY_BUFFER ), + JS_CFUNC_MAGIC_DEF("transfer", 0, js_array_buffer_transfer, 0 ), + JS_CFUNC_MAGIC_DEF("transferToFixedLength", 0, js_array_buffer_transfer, 1 ), JS_PROP_STRING_DEF("[Symbol.toStringTag]", "ArrayBuffer", JS_PROP_CONFIGURABLE ), }; @@ -53434,40 +52526,43 @@ static const JSCFunctionListEntry js_shared_array_buffer_funcs[] = { static const JSCFunctionListEntry js_shared_array_buffer_proto_funcs[] = { JS_CGETSET_MAGIC_DEF("byteLength", js_array_buffer_get_byteLength, NULL, JS_CLASS_SHARED_ARRAY_BUFFER ), + JS_CGETSET_MAGIC_DEF("maxByteLength", js_array_buffer_get_maxByteLength, NULL, JS_CLASS_SHARED_ARRAY_BUFFER ), + JS_CGETSET_MAGIC_DEF("growable", js_array_buffer_get_resizable, NULL, JS_CLASS_SHARED_ARRAY_BUFFER ), + JS_CFUNC_MAGIC_DEF("grow", 1, js_array_buffer_resize, JS_CLASS_SHARED_ARRAY_BUFFER ), JS_CFUNC_MAGIC_DEF("slice", 2, js_array_buffer_slice, JS_CLASS_SHARED_ARRAY_BUFFER ), JS_PROP_STRING_DEF("[Symbol.toStringTag]", "SharedArrayBuffer", JS_PROP_CONFIGURABLE ), }; -static JSObject *get_typed_array(JSContext *ctx, - JSValueConst this_val, - int is_dataview) +static bool is_typed_array(JSClassID class_id) { - JSObject *p; - if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT) - goto fail; - p = JS_VALUE_GET_OBJ(this_val); - if (is_dataview) { - if (p->class_id != JS_CLASS_DATAVIEW) - goto fail; - } else { - if (!(p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_FLOAT64_ARRAY)) { - fail: - JS_ThrowTypeError(ctx, "not a %s", is_dataview ? "DataView" : "TypedArray"); - return NULL; - } - } - return p; + return class_id >= JS_CLASS_UINT8C_ARRAY && class_id <= JS_CLASS_FLOAT64_ARRAY; } -/* WARNING: 'p' must be a typed array */ -static BOOL typed_array_is_detached(JSContext *ctx, JSObject *p) +// is the typed array detached or out of bounds relative to its RAB? +// |p| must be a typed array, *not* a DataView +static bool typed_array_is_oob(JSObject *p) { - JSTypedArray *ta = p->u.typed_array; - JSArrayBuffer *abuf = ta->buffer->u.array_buffer; - /* XXX: could simplify test by ensuring that - p->u.array.u.ptr is NULL iff it is detached */ - return abuf->detached; + JSArrayBuffer *abuf; + JSTypedArray *ta; + int len, size_elem; + int64_t end; + + assert(is_typed_array(p->class_id)); + + ta = p->u.typed_array; + abuf = ta->buffer->u.array_buffer; + if (abuf->detached) + return true; + len = abuf->byte_length; + if (ta->offset > len) + return true; + if (ta->track_rab) + return false; + if (len < (int64_t)ta->offset + ta->length) + return true; + size_elem = 1 << typed_array_size_log2(p->class_id); + end = (int64_t)ta->offset + (int64_t)p->u.array.count * size_elem; + return end > len; } /* WARNING: 'p' must be a typed array. Works even if the array buffer @@ -53479,82 +52574,71 @@ static uint32_t typed_array_get_length(JSContext *ctx, JSObject *p) return ta->length >> size_log2; } -static int validate_typed_array(JSContext *ctx, JSValueConst this_val) +static int validate_typed_array(JSContext *ctx, JSValue this_val) { JSObject *p; - p = get_typed_array(ctx, this_val, 0); + p = get_typed_array(ctx, this_val); if (!p) return -1; - if (typed_array_is_detached(ctx, p)) { - JS_ThrowTypeErrorDetachedArrayBuffer(ctx); + if (typed_array_is_oob(p)) { + JS_ThrowTypeErrorArrayBufferOOB(ctx); return -1; } return 0; } -static JSValue js_typed_array_get_length(JSContext *ctx, - JSValueConst this_val) +static JSValue js_typed_array_get_length(JSContext *ctx, JSValue this_val) { JSObject *p; - p = get_typed_array(ctx, this_val, 0); + p = get_typed_array(ctx, this_val); if (!p) return JS_EXCEPTION; - return JS_NewInt32(ctx, p->u.array.count); + return js_int32(p->u.array.count); } -static JSValue js_typed_array_get_buffer(JSContext *ctx, - JSValueConst this_val, int is_dataview) +static JSValue js_typed_array_get_buffer(JSContext *ctx, JSValue this_val) { JSObject *p; JSTypedArray *ta; - p = get_typed_array(ctx, this_val, is_dataview); + p = get_typed_array(ctx, this_val); if (!p) return JS_EXCEPTION; ta = p->u.typed_array; - return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer)); + return js_dup(JS_MKPTR(JS_TAG_OBJECT, ta->buffer)); } -static JSValue js_typed_array_get_byteLength(JSContext *ctx, - JSValueConst this_val, - int is_dataview) +static JSValue js_typed_array_get_byteLength(JSContext *ctx, JSValue this_val) { - JSObject *p; + uint32_t size_log2; JSTypedArray *ta; - p = get_typed_array(ctx, this_val, is_dataview); + JSObject *p; + + p = get_typed_array(ctx, this_val); if (!p) return JS_EXCEPTION; - if (typed_array_is_detached(ctx, p)) { - if (is_dataview) { - return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); - } else { - return JS_NewInt32(ctx, 0); - } - } + if (typed_array_is_oob(p)) + return js_int32(0); ta = p->u.typed_array; - return JS_NewInt32(ctx, ta->length); + if (!ta->track_rab) + return js_uint32(ta->length); + size_log2 = typed_array_size_log2(p->class_id); + return js_int64((int64_t)p->u.array.count << size_log2); } -static JSValue js_typed_array_get_byteOffset(JSContext *ctx, - JSValueConst this_val, - int is_dataview) +static JSValue js_typed_array_get_byteOffset(JSContext *ctx, JSValue this_val) { JSObject *p; JSTypedArray *ta; - p = get_typed_array(ctx, this_val, is_dataview); + p = get_typed_array(ctx, this_val); if (!p) return JS_EXCEPTION; - if (typed_array_is_detached(ctx, p)) { - if (is_dataview) { - return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); - } else { - return JS_NewInt32(ctx, 0); - } - } + if (typed_array_is_oob(p)) + return js_int32(0); ta = p->u.typed_array; - return JS_NewInt32(ctx, ta->offset); + return js_uint32(ta->offset); } -JSValue JS_NewTypedArray(JSContext *ctx, int argc, JSValueConst *argv, +JSValue JS_NewTypedArray(JSContext *ctx, int argc, JSValue *argv, JSTypedArrayEnum type) { if (type < JS_TYPED_ARRAY_UINT8C || type > JS_TYPED_ARRAY_FLOAT64) @@ -53567,18 +52651,18 @@ JSValue JS_NewTypedArray(JSContext *ctx, int argc, JSValueConst *argv, /* Return the buffer associated to the typed array or an exception if it is not a typed array or if the buffer is detached. pbyte_offset, pbyte_length or pbytes_per_element can be NULL. */ -JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj, +JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValue obj, size_t *pbyte_offset, size_t *pbyte_length, size_t *pbytes_per_element) { JSObject *p; JSTypedArray *ta; - p = get_typed_array(ctx, obj, FALSE); + p = get_typed_array(ctx, obj); if (!p) return JS_EXCEPTION; - if (typed_array_is_detached(ctx, p)) - return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); + if (typed_array_is_oob(p)) + return JS_ThrowTypeErrorArrayBufferOOB(ctx); ta = p->u.typed_array; if (pbyte_offset) *pbyte_offset = ta->offset; @@ -53587,62 +52671,89 @@ JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj, if (pbytes_per_element) { *pbytes_per_element = 1 << typed_array_size_log2(p->class_id); } - return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer)); + return js_dup(JS_MKPTR(JS_TAG_OBJECT, ta->buffer)); +} + +/* return NULL if exception. WARNING: any JS call can detach the + buffer and render the returned pointer invalid */ +uint8_t *JS_GetUint8Array(JSContext *ctx, size_t *psize, JSValue obj) +{ + JSObject *p; + JSTypedArray *ta; + JSArrayBuffer *abuf; + p = get_typed_array(ctx, obj); + if (!p) + goto fail; + if (typed_array_is_oob(p)) { + JS_ThrowTypeErrorArrayBufferOOB(ctx); + goto fail; + } + if (p->class_id != JS_CLASS_UINT8_ARRAY && p->class_id != JS_CLASS_UINT8C_ARRAY) { + JS_ThrowTypeError(ctx, "not a Uint8Array"); + goto fail; + } + ta = p->u.typed_array; + abuf = ta->buffer->u.array_buffer; + + *psize = ta->length; + return abuf->data + ta->offset; + fail: + *psize = 0; + return NULL; } static JSValue js_typed_array_get_toStringTag(JSContext *ctx, - JSValueConst this_val) + JSValue this_val) { JSObject *p; if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT) return JS_UNDEFINED; p = JS_VALUE_GET_OBJ(this_val); - if (!(p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_FLOAT64_ARRAY)) + if (!is_typed_array(p->class_id)) return JS_UNDEFINED; return JS_AtomToString(ctx, ctx->rt->class_array[p->class_id].class_name); } static JSValue js_typed_array_set_internal(JSContext *ctx, - JSValueConst dst, - JSValueConst src, - JSValueConst off) + JSValue dst, + JSValue src, + JSValue off) { JSObject *p; JSObject *src_p; uint32_t i; - int64_t src_len, offset; + int64_t dst_len, src_len, offset; JSValue val, src_obj = JS_UNDEFINED; - p = get_typed_array(ctx, dst, 0); + p = get_typed_array(ctx, dst); if (!p) goto fail; if (JS_ToInt64Sat(ctx, &offset, off)) goto fail; if (offset < 0) goto range_error; - if (typed_array_is_detached(ctx, p)) { + if (typed_array_is_oob(p)) { detached: - JS_ThrowTypeErrorDetachedArrayBuffer(ctx); + JS_ThrowTypeErrorArrayBufferOOB(ctx); goto fail; } + dst_len = p->u.array.count; src_obj = JS_ToObject(ctx, src); if (JS_IsException(src_obj)) goto fail; src_p = JS_VALUE_GET_OBJ(src_obj); - if (src_p->class_id >= JS_CLASS_UINT8C_ARRAY && - src_p->class_id <= JS_CLASS_FLOAT64_ARRAY) { + if (is_typed_array(src_p->class_id)) { JSTypedArray *dest_ta = p->u.typed_array; JSArrayBuffer *dest_abuf = dest_ta->buffer->u.array_buffer; JSTypedArray *src_ta = src_p->u.typed_array; JSArrayBuffer *src_abuf = src_ta->buffer->u.array_buffer; int shift = typed_array_size_log2(p->class_id); - if (src_abuf->detached) + if (typed_array_is_oob(src_p)) goto detached; src_len = src_p->u.array.count; - if (offset > (int64_t)(p->u.array.count - src_len)) + if (offset > dst_len - src_len) goto range_error; /* copying between typed objects */ @@ -53658,9 +52769,11 @@ static JSValue js_typed_array_set_internal(JSContext *ctx, } /* otherwise, default behavior is slow but correct */ } else { + // can change |dst| as a side effect; per spec, + // perform the range check against its old length if (js_get_length64(ctx, &src_len, src_obj)) goto fail; - if (offset > (int64_t)(p->u.array.count - src_len)) { + if (offset > dst_len - src_len) { range_error: JS_ThrowRangeError(ctx, "invalid array length"); goto fail; @@ -53670,8 +52783,14 @@ static JSValue js_typed_array_set_internal(JSContext *ctx, val = JS_GetPropertyUint32(ctx, src_obj, i); if (JS_IsException(val)) goto fail; - if (JS_SetPropertyUint32(ctx, dst, offset + i, val) < 0) + // Per spec: detaching the TA mid-iteration is allowed and should + // not throw an exception. Because iteration over the source array is + // observable, we cannot bail out early when the TA is first detached. + if (typed_array_is_oob(p)) { + JS_FreeValue(ctx, val); + } else if (JS_SetPropertyUint32(ctx, dst, offset + i, val) < 0) { goto fail; + } } done: JS_FreeValue(ctx, src_obj); @@ -53681,63 +52800,95 @@ static JSValue js_typed_array_set_internal(JSContext *ctx, return JS_EXCEPTION; } -static JSValue js_typed_array_at(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_typed_array_at(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSObject *p; int64_t idx, len; - p = get_typed_array(ctx, this_val, 0); + p = get_typed_array(ctx, this_val); if (!p) return JS_EXCEPTION; + if (typed_array_is_oob(p)) + return JS_ThrowTypeErrorArrayBufferOOB(ctx); + len = p->u.array.count; - if (typed_array_is_detached(ctx, p)) { - JS_ThrowTypeErrorDetachedArrayBuffer(ctx); - return JS_EXCEPTION; - } - + // note: can change p->u.array.count if (JS_ToInt64Sat(ctx, &idx, argv[0])) return JS_EXCEPTION; - len = p->u.array.count; if (idx < 0) idx = len + idx; - if (idx < 0 || idx >= len) + + if (idx < 0 || idx >= p->u.array.count) return JS_UNDEFINED; - return JS_GetPropertyInt64(ctx, this_val, idx); + + switch (p->class_id) { + case JS_CLASS_INT8_ARRAY: + return js_int32(p->u.array.u.int8_ptr[idx]); + case JS_CLASS_UINT8C_ARRAY: + case JS_CLASS_UINT8_ARRAY: + return js_int32(p->u.array.u.uint8_ptr[idx]); + case JS_CLASS_INT16_ARRAY: + return js_int32(p->u.array.u.int16_ptr[idx]); + case JS_CLASS_UINT16_ARRAY: + return js_int32(p->u.array.u.uint16_ptr[idx]); + case JS_CLASS_INT32_ARRAY: + return js_int32(p->u.array.u.int32_ptr[idx]); + case JS_CLASS_UINT32_ARRAY: + return js_uint32(p->u.array.u.uint32_ptr[idx]); + case JS_CLASS_FLOAT16_ARRAY: + return js_float64(fromfp16(p->u.array.u.fp16_ptr[idx])); + case JS_CLASS_FLOAT32_ARRAY: + return js_float64(p->u.array.u.float_ptr[idx]); + case JS_CLASS_FLOAT64_ARRAY: + return js_float64(p->u.array.u.double_ptr[idx]); + case JS_CLASS_BIG_INT64_ARRAY: + return JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]); + case JS_CLASS_BIG_UINT64_ARRAY: + return JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]); + } + + abort(); /* unreachable */ + return JS_UNDEFINED; } -static JSValue js_typed_array_with(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_typed_array_with(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue arr, val; JSObject *p; - int64_t idx, len; + int64_t idx; + uint32_t len, oldlen, newlen; - p = get_typed_array(ctx, this_val, /*is_dataview*/0); + p = get_typed_array(ctx, this_val); if (!p) return JS_EXCEPTION; + oldlen = p->u.array.count; if (JS_ToInt64Sat(ctx, &idx, argv[0])) return JS_EXCEPTION; - len = p->u.array.count; - if (idx < 0) - idx = len + idx; - if (idx < 0 || idx >= len) - return JS_ThrowRangeError(ctx, "invalid array index"); - val = JS_ToPrimitive(ctx, argv[1], HINT_NUMBER); if (JS_IsException(val)) return JS_EXCEPTION; + newlen = p->u.array.count; + if (idx < 0) + idx = newlen + idx; + if (idx < 0 || idx >= newlen) { + JS_FreeValue(ctx, val); + return JS_ThrowRangeError(ctx, "invalid array index"); + } + + len = min_uint32(oldlen, newlen); arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val, - p->class_id); + p->class_id, len); if (JS_IsException(arr)) { JS_FreeValue(ctx, val); return JS_EXCEPTION; } - if (JS_SetPropertyInt64(ctx, arr, idx, val) < 0) { + if (idx < len && JS_SetPropertyInt64(ctx, arr, idx, val) < 0) { JS_FreeValue(ctx, arr); return JS_EXCEPTION; } @@ -53745,61 +52896,26 @@ static JSValue js_typed_array_with(JSContext *ctx, JSValueConst this_val, } static JSValue js_typed_array_set(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv) + JSValue this_val, + int argc, JSValue *argv) { - JSValueConst offset = JS_UNDEFINED; + JSValue offset = JS_UNDEFINED; if (argc > 1) { offset = argv[1]; } return js_typed_array_set_internal(ctx, this_val, argv[0], offset); } -static JSValue js_create_typed_array_iterator(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) +static JSValue js_create_typed_array_iterator(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { if (validate_typed_array(ctx, this_val)) return JS_EXCEPTION; return js_create_array_iterator(ctx, this_val, argc, argv, magic); } -/* return < 0 if exception */ -static int js_typed_array_get_length_internal(JSContext *ctx, - JSValueConst obj) -{ - JSObject *p; - p = get_typed_array(ctx, obj, 0); - if (!p) - return -1; - if (typed_array_is_detached(ctx, p)) { - JS_ThrowTypeErrorDetachedArrayBuffer(ctx); - return -1; - } - return p->u.array.count; -} - -#if 0 -/* validate a typed array and return its length */ -static JSValue js_typed_array___getLength(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv) -{ - BOOL ignore_detached = JS_ToBool(ctx, argv[1]); - - if (ignore_detached) { - return js_typed_array_get_length(ctx, argv[0]); - } else { - int len; - len = js_typed_array_get_length_internal(ctx, argv[0]); - if (len < 0) - return JS_EXCEPTION; - return JS_NewInt32(ctx, len); - } -} -#endif - -static JSValue js_typed_array_create(JSContext *ctx, JSValueConst ctor, - int argc, JSValueConst *argv) +static JSValue js_typed_array_create(JSContext *ctx, JSValue ctor, + int argc, JSValue *argv) { JSValue ret; int new_len; @@ -53809,12 +52925,12 @@ static JSValue js_typed_array_create(JSContext *ctx, JSValueConst ctor, if (JS_IsException(ret)) return ret; /* validate the typed array */ - new_len = js_typed_array_get_length_internal(ctx, ret); + new_len = js_typed_array_get_length_unsafe(ctx, ret); if (new_len < 0) goto fail; if (argc == 1) { /* ensure that it is large enough */ - if (JS_ToLengthFree(ctx, &len, JS_DupValue(ctx, argv[0]))) + if (JS_ToLengthFree(ctx, &len, js_dup(argv[0]))) goto fail; if (new_len < len) { JS_ThrowTypeError(ctx, "TypedArray length is too small"); @@ -53826,26 +52942,17 @@ static JSValue js_typed_array_create(JSContext *ctx, JSValueConst ctor, return ret; } -#if 0 -static JSValue js_typed_array___create(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return js_typed_array_create(ctx, argv[0], max_int(argc - 1, 0), argv + 1); -} -#endif - static JSValue js_typed_array___speciesCreate(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv) + JSValue this_val, + int argc, JSValue *argv) { - JSValueConst obj; + JSValue obj; JSObject *p; JSValue ctor, ret; int argc1; obj = argv[0]; - p = get_typed_array(ctx, obj, 0); + p = get_typed_array(ctx, obj); if (!p) return JS_EXCEPTION; ctor = JS_SpeciesConstructor(ctx, obj, JS_UNDEFINED); @@ -53862,18 +52969,18 @@ static JSValue js_typed_array___speciesCreate(JSContext *ctx, return ret; } -static JSValue js_typed_array_from(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_typed_array_from(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { // from(items, mapfn = void 0, this_arg = void 0) - JSValueConst items = argv[0], mapfn, this_arg; - JSValueConst args[2]; + JSValue items = argv[0], mapfn, this_arg; + JSValue args[2]; JSValue stack[2]; JSValue iter, arr, r, v, v2; int64_t k, len; int done, mapping; - mapping = FALSE; + mapping = false; mapfn = JS_UNDEFINED; this_arg = JS_UNDEFINED; r = JS_UNDEFINED; @@ -53899,8 +53006,8 @@ static JSValue js_typed_array_from(JSContext *ctx, JSValueConst this_val, arr = JS_NewArray(ctx); if (JS_IsException(arr)) goto exception; - stack[0] = JS_DupValue(ctx, items); - if (js_for_of_start(ctx, &stack[1], FALSE)) + stack[0] = js_dup(items); + if (js_for_of_start(ctx, &stack[1], false)) goto exception; for (k = 0;; k++) { v = JS_IteratorNext(ctx, stack[0], stack[1], 0, NULL, &done); @@ -53918,7 +53025,7 @@ static JSValue js_typed_array_from(JSContext *ctx, JSValueConst this_val, } if (js_get_length64(ctx, &len, arr) < 0) goto exception; - v = JS_NewInt64(ctx, len); + v = js_int64(len); args[0] = v; r = js_typed_array_create(ctx, this_val, 1, args); JS_FreeValue(ctx, v); @@ -53930,7 +53037,7 @@ static JSValue js_typed_array_from(JSContext *ctx, JSValueConst this_val, goto exception; if (mapping) { args[0] = v; - args[1] = JS_NewInt32(ctx, k); + args[1] = js_int32(k); v2 = JS_Call(ctx, mapfn, this_arg, 2, args); JS_FreeValue(ctx, v); v = v2; @@ -53944,7 +53051,7 @@ static JSValue js_typed_array_from(JSContext *ctx, JSValueConst this_val, exception_close: if (!JS_IsUndefined(stack[0])) - JS_IteratorClose(ctx, stack[0], TRUE); + JS_IteratorClose(ctx, stack[0], true); exception: JS_FreeValue(ctx, r); r = JS_EXCEPTION; @@ -53955,20 +53062,20 @@ static JSValue js_typed_array_from(JSContext *ctx, JSValueConst this_val, return r; } -static JSValue js_typed_array_of(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_typed_array_of(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue obj; - JSValueConst args[1]; + JSValue args[1]; int i; - args[0] = JS_NewInt32(ctx, argc); + args[0] = js_int32(argc); obj = js_typed_array_create(ctx, this_val, 1, args); if (JS_IsException(obj)) return obj; for(i = 0; i < argc; i++) { - if (JS_SetPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i])) < 0) { + if (JS_SetPropertyUint32(ctx, obj, i, js_dup(argv[i])) < 0) { JS_FreeValue(ctx, obj); return JS_EXCEPTION; } @@ -53976,15 +53083,18 @@ static JSValue js_typed_array_of(JSContext *ctx, JSValueConst this_val, return obj; } -static JSValue js_typed_array_copyWithin(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_typed_array_copyWithin(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSObject *p; - int len, to, from, final, count, shift; + int len, to, from, final, count, shift, space; - len = js_typed_array_get_length_internal(ctx, this_val); - if (len < 0) + p = get_typed_array(ctx, this_val); + if (!p) return JS_EXCEPTION; + if (typed_array_is_oob(p)) + return JS_ThrowTypeErrorArrayBufferOOB(ctx); + len = p->u.array.count; if (JS_ToInt32Clamp(ctx, &to, argv[0], 0, len, len)) return JS_EXCEPTION; @@ -53998,34 +53108,39 @@ static JSValue js_typed_array_copyWithin(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } + if (typed_array_is_oob(p)) + return JS_ThrowTypeErrorArrayBufferOOB(ctx); + + // RAB may have been resized by evil .valueOf method + space = p->u.array.count - max_int(to, from); count = min_int(final - from, len - to); + count = min_int(count, space); if (count > 0) { - p = JS_VALUE_GET_OBJ(this_val); - if (typed_array_is_detached(ctx, p)) - return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); shift = typed_array_size_log2(p->class_id); memmove(p->u.array.u.uint8_ptr + (to << shift), p->u.array.u.uint8_ptr + (from << shift), count << shift); } - return JS_DupValue(ctx, this_val); + return js_dup(this_val); } -static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_typed_array_fill(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSObject *p; int len, k, final, shift; uint64_t v64; - len = js_typed_array_get_length_internal(ctx, this_val); - if (len < 0) + p = get_typed_array(ctx, this_val); + if (!p) return JS_EXCEPTION; - p = JS_VALUE_GET_OBJ(this_val); + if (typed_array_is_oob(p)) + return JS_ThrowTypeErrorArrayBufferOOB(ctx); + len = p->u.array.count; if (p->class_id == JS_CLASS_UINT8C_ARRAY) { int32_t v; - if (JS_ToUint8ClampFree(ctx, &v, JS_DupValue(ctx, argv[0]))) + if (JS_ToUint8ClampFree(ctx, &v, js_dup(argv[0]))) return JS_EXCEPTION; v64 = v; } else if (p->class_id <= JS_CLASS_UINT32_ARRAY) { @@ -54033,14 +53148,17 @@ static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val, if (JS_ToUint32(ctx, &v, argv[0])) return JS_EXCEPTION; v64 = v; - } else if (p->class_id <= JS_CLASS_BIG_UINT64_ARRAY) { + } else + if (p->class_id <= JS_CLASS_BIG_UINT64_ARRAY) { if (JS_ToBigInt64(ctx, (int64_t *)&v64, argv[0])) return JS_EXCEPTION; } else { double d; if (JS_ToFloat64(ctx, &d, argv[0])) return JS_EXCEPTION; - if (p->class_id == JS_CLASS_FLOAT32_ARRAY) { + if (p->class_id == JS_CLASS_FLOAT16_ARRAY) { + v64 = tofp16(d); + } else if (p->class_id == JS_CLASS_FLOAT32_ARRAY) { union { float f; uint32_t u32; @@ -54066,9 +53184,11 @@ static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } - if (typed_array_is_detached(ctx, p)) - return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); + if (typed_array_is_oob(p)) + return JS_ThrowTypeErrorArrayBufferOOB(ctx); + // RAB may have been resized by evil .valueOf method + final = min_int(final, p->u.array.count); shift = typed_array_size_log2(p->class_id); switch(shift) { case 0: @@ -54094,20 +53214,20 @@ static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val, default: abort(); } - return JS_DupValue(ctx, this_val); + return js_dup(this_val); } -static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int mode) +static JSValue js_typed_array_find(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int mode) { - JSValueConst func, this_arg; - JSValueConst args[3]; + JSValue func, this_arg; + JSValue args[3]; JSValue val, index_val, res; int len, k, end; int dir; val = JS_UNDEFINED; - len = js_typed_array_get_length_internal(ctx, this_val); + len = js_typed_array_get_length_unsafe(ctx, this_val); if (len < 0) goto exception; @@ -54129,7 +53249,7 @@ static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val, } for(; k != end; k += dir) { - index_val = JS_NewInt32(ctx, k); + index_val = js_int32(k); val = JS_GetPropertyValue(ctx, this_val, index_val); if (JS_IsException(val)) goto exception; @@ -54150,7 +53270,7 @@ static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val, JS_FreeValue(ctx, val); } if (mode == ArrayFindIndex || mode == ArrayFindLastIndex) - return JS_NewInt32(ctx, -1); + return js_int32(-1); else return JS_UNDEFINED; @@ -54163,21 +53283,28 @@ static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val, #define special_lastIndexOf 1 #define special_includes -1 -static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int special) +static JSValue js_typed_array_indexOf(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int special) { JSObject *p; int len, tag, is_int, is_bigint, k, stop, inc, res = -1; int64_t v64; double d; float f; + uint16_t hf; + bool oob; + + p = get_typed_array(ctx, this_val); + if (!p) + return JS_EXCEPTION; + if (typed_array_is_oob(p)) + return JS_ThrowTypeErrorArrayBufferOOB(ctx); + len = p->u.array.count; - len = js_typed_array_get_length_internal(ctx, this_val); - if (len < 0) - goto exception; if (len == 0) goto done; + oob = false; if (special == special_lastIndexOf) { k = len - 1; if (argc > 1) { @@ -54203,23 +53330,37 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val, } else { k = 0; if (argc > 1) { - if (JS_ToInt32Clamp(ctx, &k, argv[1], 0, len, len)) + if (JS_ToInt32Sat(ctx, &k, argv[1])) goto exception; + if (k < 0) { + k += len; + if (k < 0) + k = 0; + } else if (k > len) { + k = len; + oob = true; + } } stop = len; inc = 1; } - p = JS_VALUE_GET_OBJ(this_val); /* if the array was detached, no need to go further (but no exception is raised) */ - if (typed_array_is_detached(ctx, p)) { + if (typed_array_is_oob(p) || len > p->u.array.count) { /* "includes" scans all the properties, so "undefined" can match */ if (special == special_includes && JS_IsUndefined(argv[0]) && len > 0) - res = 0; + res = oob ? -1 : 0; goto done; } + // RAB may have been resized by evil .valueOf method + len = min_int(len, p->u.array.count); + if (len == 0) + goto done; + k = min_int(k, len); + stop = min_int(stop, len); + is_bigint = 0; is_int = 0; /* avoid warning */ v64 = 0; /* avoid warning */ @@ -54235,8 +53376,9 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val, v64 = d; is_int = (v64 == d); } - } else if (tag == JS_TAG_BIG_INT) { - JSBigFloat *p1 = JS_VALUE_GET_PTR(argv[0]); + } else + if (tag == JS_TAG_BIG_INT) { + JSBigInt *p1 = JS_VALUE_GET_PTR(argv[0]); if (p->class_id == JS_CLASS_BIG_INT64_ARRAY) { if (bf_get_int64(&v64, &p1->num, 0) != 0) @@ -54267,7 +53409,9 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val, pv = p->u.array.u.uint8_ptr; v = v64; if (inc > 0) { - pp = memchr(pv + k, v, len - k); + pp = NULL; + if (pv) + pp = memchr(pv + k, v, len - k); if (pp) res = pp - pv; } else { @@ -54318,6 +53462,39 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val, } } break; + case JS_CLASS_FLOAT16_ARRAY: + if (is_bigint) + break; + if (isnan(d)) { + const uint16_t *pv = p->u.array.u.fp16_ptr; + /* special case: indexOf returns -1, includes finds NaN */ + if (special != special_includes) + goto done; + for (; k != stop; k += inc) { + if (isfp16nan(pv[k])) { + res = k; + break; + } + } + } else if (d == 0) { + // special case: includes also finds negative zero + const uint16_t *pv = p->u.array.u.fp16_ptr; + for (; k != stop; k += inc) { + if (isfp16zero(pv[k])) { + res = k; + break; + } + } + } else if (hf = tofp16(d), d == fromfp16(hf)) { + const uint16_t *pv = p->u.array.u.fp16_ptr; + for (; k != stop; k += inc) { + if (pv[k] == hf) { + res = k; + break; + } + } + } + break; case JS_CLASS_FLOAT32_ARRAY: if (is_bigint) break; @@ -54367,15 +53544,12 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val, } break; case JS_CLASS_BIG_INT64_ARRAY: - if (is_bigint || (is_math_mode(ctx) && is_int && - v64 >= -MAX_SAFE_INTEGER && - v64 <= MAX_SAFE_INTEGER)) { + if (is_bigint) { goto scan64; } break; case JS_CLASS_BIG_UINT64_ARRAY: - if (is_bigint || (is_math_mode(ctx) && is_int && - v64 >= 0 && v64 <= MAX_SAFE_INTEGER)) { + if (is_bigint) { const uint64_t *pv; uint64_t v; scan64: @@ -54393,48 +53567,55 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val, done: if (special == special_includes) - return JS_NewBool(ctx, res >= 0); + return js_bool(res >= 0); else - return JS_NewInt32(ctx, res); + return js_int32(res); exception: return JS_EXCEPTION; } -static JSValue js_typed_array_join(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int toLocaleString) +static JSValue js_typed_array_join(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int toLocaleString) { JSValue sep = JS_UNDEFINED, el; StringBuffer b_s, *b = &b_s; - JSString *p = NULL; - int i, n; + JSString *s = NULL; + JSObject *p; + int i, len, oldlen, newlen; int c; - n = js_typed_array_get_length_internal(ctx, this_val); - if (n < 0) - goto exception; + p = get_typed_array(ctx, this_val); + if (!p) + return JS_EXCEPTION; + if (typed_array_is_oob(p)) + return JS_ThrowTypeErrorArrayBufferOOB(ctx); + len = oldlen = newlen = p->u.array.count; c = ','; /* default separator */ if (!toLocaleString && argc > 0 && !JS_IsUndefined(argv[0])) { sep = JS_ToString(ctx, argv[0]); if (JS_IsException(sep)) goto exception; - p = JS_VALUE_GET_STRING(sep); - if (p->len == 1 && !p->is_wide_char) - c = p->u.str8[0]; + s = JS_VALUE_GET_STRING(sep); + if (s->len == 1 && !s->is_wide_char) + c = s->u.str8[0]; else c = -1; + // ToString(sep) can detach or resize the arraybuffer as a side effect + newlen = p->u.array.count; + len = min_int(len, newlen); } string_buffer_init(ctx, b, 0); /* XXX: optimize with direct access */ - for(i = 0; i < n; i++) { + for(i = 0; i < len; i++) { if (i > 0) { if (c >= 0) { if (string_buffer_putc8(b, c)) goto fail; } else { - if (string_buffer_concat(b, p, 0, p->len)) + if (string_buffer_concat(b, s, 0, s->len)) goto fail; } } @@ -54450,6 +53631,19 @@ static JSValue js_typed_array_join(JSContext *ctx, JSValueConst this_val, goto fail; } } + + // add extra separators in case RAB was resized by evil .valueOf method + i = max_int(1, newlen); + for(/*empty*/; i < oldlen; i++) { + if (c >= 0) { + if (string_buffer_putc8(b, c)) + goto fail; + } else { + if (string_buffer_concat(b, s, 0, s->len)) + goto fail; + } + } + JS_FreeValue(ctx, sep); return string_buffer_end(b); @@ -54460,13 +53654,13 @@ static JSValue js_typed_array_join(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static JSValue js_typed_array_reverse(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_typed_array_reverse(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSObject *p; int len; - len = js_typed_array_get_length_internal(ctx, this_val); + len = js_typed_array_get_length_unsafe(ctx, this_val); if (len < 0) return JS_EXCEPTION; if (len > 0) { @@ -54520,20 +53714,20 @@ static JSValue js_typed_array_reverse(JSContext *ctx, JSValueConst this_val, abort(); } } - return JS_DupValue(ctx, this_val); + return js_dup(this_val); } -static JSValue js_typed_array_toReversed(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_typed_array_toReversed(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue arr, ret; JSObject *p; - p = get_typed_array(ctx, this_val, /*is_dataview*/0); + p = get_typed_array(ctx, this_val); if (!p) return JS_EXCEPTION; arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val, - p->class_id); + p->class_id, p->u.array.count); if (JS_IsException(arr)) return JS_EXCEPTION; ret = js_typed_array_reverse(ctx, arr, argc, argv); @@ -54541,18 +53735,21 @@ static JSValue js_typed_array_toReversed(JSContext *ctx, JSValueConst this_val, return ret; } -static JSValue js_typed_array_slice(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_typed_array_slice(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - JSValueConst args[2]; + JSValue args[2]; JSValue arr, val; JSObject *p, *p1; - int n, len, start, final, count, shift; + int n, len, start, final, count, shift, space; arr = JS_UNDEFINED; - len = js_typed_array_get_length_internal(ctx, this_val); - if (len < 0) - goto exception; + p = get_typed_array(ctx, this_val); + if (!p) + return JS_EXCEPTION; + if (typed_array_is_oob(p)) + return JS_ThrowTypeErrorArrayBufferOOB(ctx); + len = p->u.array.count; if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len)) goto exception; @@ -54563,13 +53760,8 @@ static JSValue js_typed_array_slice(JSContext *ctx, JSValueConst this_val, } count = max_int(final - start, 0); - p = get_typed_array(ctx, this_val, 0); - if (p == NULL) - goto exception; - shift = typed_array_size_log2(p->class_id); - args[0] = this_val; - args[1] = JS_NewInt32(ctx, count); + args[1] = js_int32(count); arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args); if (JS_IsException(arr)) goto exception; @@ -54579,19 +53771,26 @@ static JSValue js_typed_array_slice(JSContext *ctx, JSValueConst this_val, || validate_typed_array(ctx, arr)) goto exception; - p1 = get_typed_array(ctx, arr, 0); + if (len != p->u.array.count) + goto slow_path; + + p1 = get_typed_array(ctx, arr); if (p1 != NULL && p->class_id == p1->class_id && typed_array_get_length(ctx, p1) >= count && typed_array_get_length(ctx, p) >= start + count) { - memcpy(p1->u.array.u.uint8_ptr, - p->u.array.u.uint8_ptr + (start << shift), - count << shift); + shift = typed_array_size_log2(p->class_id); + memmove(p1->u.array.u.uint8_ptr, + p->u.array.u.uint8_ptr + (start << shift), + count << shift); } else { + slow_path: + space = max_int(0, p->u.array.count - start); + count = min_int(count, space); for (n = 0; n < count; n++) { - val = JS_GetPropertyValue(ctx, this_val, JS_NewInt32(ctx, start + n)); + val = JS_GetPropertyValue(ctx, this_val, js_int32(start + n)); if (JS_IsException(val)) goto exception; - if (JS_SetPropertyValue(ctx, arr, JS_NewInt32(ctx, n), val, + if (JS_SetPropertyValue(ctx, arr, js_int32(n), val, JS_PROP_THROW) < 0) goto exception; } @@ -54604,44 +53803,56 @@ static JSValue js_typed_array_slice(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static JSValue js_typed_array_subarray(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_typed_array_subarray(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { - JSValueConst args[4]; + JSArrayBuffer *abuf; + JSTypedArray *ta; + JSValue args[4]; JSValue arr, byteOffset, ta_buffer; JSObject *p; int len, start, final, count, shift, offset; - p = get_typed_array(ctx, this_val, 0); + p = get_typed_array(ctx, this_val); if (!p) goto exception; len = p->u.array.count; if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len)) goto exception; - final = len; if (!JS_IsUndefined(argv[1])) { if (JS_ToInt32Clamp(ctx, &final, argv[1], 0, len, len)) goto exception; } count = max_int(final - start, 0); - byteOffset = js_typed_array_get_byteOffset(ctx, this_val, 0); + byteOffset = js_typed_array_get_byteOffset(ctx, this_val); if (JS_IsException(byteOffset)) goto exception; + ta = p->u.typed_array; + abuf = ta->buffer->u.array_buffer; + if (ta->offset > abuf->byte_length) + goto range_error; + if (ta->offset == abuf->byte_length && count > 0) { + range_error: + JS_ThrowRangeError(ctx, "invalid offset"); + goto exception; + } shift = typed_array_size_log2(p->class_id); offset = JS_VALUE_GET_INT(byteOffset) + (start << shift); JS_FreeValue(ctx, byteOffset); - ta_buffer = js_typed_array_get_buffer(ctx, this_val, 0); + ta_buffer = js_typed_array_get_buffer(ctx, this_val); if (JS_IsException(ta_buffer)) goto exception; args[0] = this_val; args[1] = ta_buffer; - args[2] = JS_NewInt32(ctx, offset); - args[3] = JS_NewInt32(ctx, count); + args[2] = js_int32(offset); + args[3] = js_int32(count); + // result is length-tracking if source TA is and no explicit count is given + if (ta->track_rab && JS_IsUndefined(argv[1])) + args[3] = JS_UNDEFINED; arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 4, args); JS_FreeValue(ctx, ta_buffer); return arr; - exception: return JS_EXCEPTION; } @@ -54699,6 +53910,11 @@ static int js_TA_cmp_uint64(const void *a, const void *b, void *opaque) { return (y < x) - (y > x); } +static int js_TA_cmp_float16(const void *a, const void *b, void *opaque) { + return js_cmp_doubles(fromfp16(*(const uint16_t *)a), + fromfp16(*(const uint16_t *)b)); +} + static int js_TA_cmp_float32(const void *a, const void *b, void *opaque) { return js_cmp_doubles(*(const float *)a, *(const float *)b); } @@ -54708,27 +53924,27 @@ static int js_TA_cmp_float64(const void *a, const void *b, void *opaque) { } static JSValue js_TA_get_int8(JSContext *ctx, const void *a) { - return JS_NewInt32(ctx, *(const int8_t *)a); + return js_int32(*(const int8_t *)a); } static JSValue js_TA_get_uint8(JSContext *ctx, const void *a) { - return JS_NewInt32(ctx, *(const uint8_t *)a); + return js_int32(*(const uint8_t *)a); } static JSValue js_TA_get_int16(JSContext *ctx, const void *a) { - return JS_NewInt32(ctx, *(const int16_t *)a); + return js_int32(*(const int16_t *)a); } static JSValue js_TA_get_uint16(JSContext *ctx, const void *a) { - return JS_NewInt32(ctx, *(const uint16_t *)a); + return js_int32(*(const uint16_t *)a); } static JSValue js_TA_get_int32(JSContext *ctx, const void *a) { - return JS_NewInt32(ctx, *(const int32_t *)a); + return js_int32(*(const int32_t *)a); } static JSValue js_TA_get_uint32(JSContext *ctx, const void *a) { - return JS_NewUint32(ctx, *(const uint32_t *)a); + return js_uint32(*(const uint32_t *)a); } static JSValue js_TA_get_int64(JSContext *ctx, const void *a) { @@ -54739,21 +53955,24 @@ static JSValue js_TA_get_uint64(JSContext *ctx, const void *a) { return JS_NewBigUint64(ctx, *(uint64_t *)a); } +static JSValue js_TA_get_float16(JSContext *ctx, const void *a) { + return js_float64(fromfp16(*(const uint16_t *)a)); +} + static JSValue js_TA_get_float32(JSContext *ctx, const void *a) { - return __JS_NewFloat64(ctx, *(const float *)a); + return js_float64(*(const float *)a); } static JSValue js_TA_get_float64(JSContext *ctx, const void *a) { - return __JS_NewFloat64(ctx, *(const double *)a); + return js_float64(*(const double *)a); } struct TA_sort_context { JSContext *ctx; - int exception; /* 1 = exception, 2 = detached typed array */ - JSValueConst arr; - JSValueConst cmp; + int exception; + JSValue arr; + JSValue cmp; JSValue (*getfun)(JSContext *ctx, const void *a); - uint8_t *array_ptr; /* cannot change unless the array is detached */ int elt_size; }; @@ -54761,19 +53980,24 @@ static int js_TA_cmp_generic(const void *a, const void *b, void *opaque) { struct TA_sort_context *psc = opaque; JSContext *ctx = psc->ctx; uint32_t a_idx, b_idx; - JSValueConst argv[2]; + JSValue argv[2]; JSValue res; + JSObject *p; int cmp; + p = JS_VALUE_GET_OBJ(psc->arr); + if (typed_array_is_oob(p)) + return 0; + cmp = 0; if (!psc->exception) { - /* Note: the typed array can be detached without causing an - error */ a_idx = *(uint32_t *)a; b_idx = *(uint32_t *)b; - argv[0] = psc->getfun(ctx, psc->array_ptr + + if (a_idx >= p->u.array.count || b_idx >= p->u.array.count) + return 0; + argv[0] = psc->getfun(ctx, (char *)p->u.array.u.ptr + a_idx * (size_t)psc->elt_size); - argv[1] = psc->getfun(ctx, psc->array_ptr + + argv[1] = psc->getfun(ctx, (char *)p->u.array.u.ptr + b_idx * (size_t)(psc->elt_size)); res = JS_Call(ctx, psc->cmp, JS_UNDEFINED, 2, argv); if (JS_IsException(res)) { @@ -54796,10 +54020,6 @@ static int js_TA_cmp_generic(const void *a, const void *b, void *opaque) { /* make sort stable: compare array offsets */ cmp = (a_idx > b_idx) - (a_idx < b_idx); } - if (unlikely(typed_array_is_detached(ctx, - JS_VALUE_GET_PTR(psc->arr)))) { - psc->exception = 2; - } done: JS_FreeValue(ctx, argv[0]); JS_FreeValue(ctx, argv[1]); @@ -54807,16 +54027,21 @@ static int js_TA_cmp_generic(const void *a, const void *b, void *opaque) { return cmp; } -static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_typed_array_sort(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSObject *p; int len; size_t elt_size; struct TA_sort_context tsc; - void *array_ptr; int (*cmpfun)(const void *a, const void *b, void *opaque); + p = get_typed_array(ctx, this_val); + if (!p) + return JS_EXCEPTION; + if (typed_array_is_oob(p)) + return JS_ThrowTypeErrorArrayBufferOOB(ctx); + tsc.ctx = ctx; tsc.exception = 0; tsc.arr = this_val; @@ -54824,12 +54049,9 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val, if (!JS_IsUndefined(tsc.cmp) && check_function(ctx, tsc.cmp)) return JS_EXCEPTION; - len = js_typed_array_get_length_internal(ctx, this_val); - if (len < 0) - return JS_EXCEPTION; + len = p->u.array.count; if (len > 1) { - p = JS_VALUE_GET_OBJ(this_val); switch (p->class_id) { case JS_CLASS_INT8_ARRAY: tsc.getfun = js_TA_get_int8; @@ -54864,6 +54086,10 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val, tsc.getfun = js_TA_get_uint64; cmpfun = js_TA_cmp_uint64; break; + case JS_CLASS_FLOAT16_ARRAY: + tsc.getfun = js_TA_get_float16; + cmpfun = js_TA_cmp_float16; + break; case JS_CLASS_FLOAT32_ARRAY: tsc.getfun = js_TA_get_float32; cmpfun = js_TA_cmp_float32; @@ -54875,7 +54101,6 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val, default: abort(); } - array_ptr = p->u.array.u.ptr; elt_size = 1 << typed_array_size_log2(p->class_id); if (!JS_IsUndefined(tsc.cmp)) { uint32_t *array_idx; @@ -54888,73 +54113,75 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; for(i = 0; i < len; i++) array_idx[i] = i; - tsc.array_ptr = array_ptr; tsc.elt_size = elt_size; rqsort(array_idx, len, sizeof(array_idx[0]), js_TA_cmp_generic, &tsc); - if (tsc.exception) { - if (tsc.exception == 1) - goto fail; - /* detached typed array during the sort: no error */ - } else { - array_tmp = js_malloc(ctx, len * elt_size); - if (!array_tmp) { - fail: - js_free(ctx, array_idx); - return JS_EXCEPTION; + if (tsc.exception) + goto fail; + // per spec: typed array can be detached mid-iteration + if (typed_array_is_oob(p)) + goto done; + len = min_int(len, p->u.array.count); + if (len == 0) + goto done; + array_tmp = js_malloc(ctx, len * elt_size); + if (!array_tmp) { + fail: + js_free(ctx, array_idx); + return JS_EXCEPTION; + } + memcpy(array_tmp, p->u.array.u.ptr, len * elt_size); + switch(elt_size) { + case 1: + for(i = 0; i < len; i++) { + j = array_idx[i]; + p->u.array.u.uint8_ptr[i] = ((uint8_t *)array_tmp)[j]; } - memcpy(array_tmp, array_ptr, len * elt_size); - switch(elt_size) { - case 1: - for(i = 0; i < len; i++) { - j = array_idx[i]; - ((uint8_t *)array_ptr)[i] = ((uint8_t *)array_tmp)[j]; - } - break; - case 2: - for(i = 0; i < len; i++) { - j = array_idx[i]; - ((uint16_t *)array_ptr)[i] = ((uint16_t *)array_tmp)[j]; - } - break; - case 4: - for(i = 0; i < len; i++) { - j = array_idx[i]; - ((uint32_t *)array_ptr)[i] = ((uint32_t *)array_tmp)[j]; - } - break; - case 8: - for(i = 0; i < len; i++) { - j = array_idx[i]; - ((uint64_t *)array_ptr)[i] = ((uint64_t *)array_tmp)[j]; - } - break; - default: - abort(); + break; + case 2: + for(i = 0; i < len; i++) { + j = array_idx[i]; + p->u.array.u.uint16_ptr[i] = ((uint16_t *)array_tmp)[j]; + } + break; + case 4: + for(i = 0; i < len; i++) { + j = array_idx[i]; + p->u.array.u.uint32_ptr[i] = ((uint32_t *)array_tmp)[j]; } - js_free(ctx, array_tmp); + break; + case 8: + for(i = 0; i < len; i++) { + j = array_idx[i]; + p->u.array.u.uint64_ptr[i] = ((uint64_t *)array_tmp)[j]; + } + break; + default: + abort(); } + js_free(ctx, array_tmp); + done: js_free(ctx, array_idx); } else { - rqsort(array_ptr, len, elt_size, cmpfun, &tsc); + rqsort(p->u.array.u.ptr, len, elt_size, cmpfun, &tsc); if (tsc.exception) return JS_EXCEPTION; } } - return JS_DupValue(ctx, this_val); + return js_dup(this_val); } -static JSValue js_typed_array_toSorted(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_typed_array_toSorted(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) { JSValue arr, ret; JSObject *p; - p = get_typed_array(ctx, this_val, /*is_dataview*/0); + p = get_typed_array(ctx, this_val); if (!p) return JS_EXCEPTION; arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val, - p->class_id); + p->class_id, p->u.array.count); if (JS_IsException(arr)) return JS_EXCEPTION; ret = js_typed_array_sort(ctx, arr, argc, argv); @@ -54966,18 +54193,15 @@ static const JSCFunctionListEntry js_typed_array_base_funcs[] = { JS_CFUNC_DEF("from", 1, js_typed_array_from ), JS_CFUNC_DEF("of", 0, js_typed_array_of ), JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ), - //JS_CFUNC_DEF("__getLength", 2, js_typed_array___getLength ), - //JS_CFUNC_DEF("__create", 2, js_typed_array___create ), - //JS_CFUNC_DEF("__speciesCreate", 2, js_typed_array___speciesCreate ), }; static const JSCFunctionListEntry js_typed_array_base_proto_funcs[] = { JS_CGETSET_DEF("length", js_typed_array_get_length, NULL ), JS_CFUNC_DEF("at", 1, js_typed_array_at ), JS_CFUNC_DEF("with", 2, js_typed_array_with ), - JS_CGETSET_MAGIC_DEF("buffer", js_typed_array_get_buffer, NULL, 0 ), - JS_CGETSET_MAGIC_DEF("byteLength", js_typed_array_get_byteLength, NULL, 0 ), - JS_CGETSET_MAGIC_DEF("byteOffset", js_typed_array_get_byteOffset, NULL, 0 ), + JS_CGETSET_DEF("buffer", js_typed_array_get_buffer, NULL ), + JS_CGETSET_DEF("byteLength", js_typed_array_get_byteLength, NULL ), + JS_CGETSET_DEF("byteOffset", js_typed_array_get_byteOffset, NULL ), JS_CFUNC_DEF("set", 1, js_typed_array_set ), JS_CFUNC_MAGIC_DEF("values", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_VALUE ), JS_ALIAS_DEF("[Symbol.iterator]", "values" ), @@ -55012,15 +54236,15 @@ static const JSCFunctionListEntry js_typed_array_base_proto_funcs[] = { }; static JSValue js_typed_array_base_constructor(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv) + JSValue this_val, + int argc, JSValue *argv) { return JS_ThrowTypeError(ctx, "cannot be called"); } /* 'obj' must be an allocated typed array object */ -static int typed_array_init(JSContext *ctx, JSValueConst obj, - JSValue buffer, uint64_t offset, uint64_t len) +static int typed_array_init(JSContext *ctx, JSValue obj, JSValue buffer, + uint64_t offset, uint64_t len, bool track_rab) { JSTypedArray *ta; JSObject *p, *pbuffer; @@ -55040,6 +54264,7 @@ static int typed_array_init(JSContext *ctx, JSValueConst obj, ta->buffer = pbuffer; ta->offset = offset; ta->length = len << size_log2; + ta->track_rab = track_rab; list_add_tail(&ta->link, &abuf->array_list); p->u.typed_array = ta; p->u.array.count = len; @@ -55049,10 +54274,10 @@ static int typed_array_init(JSContext *ctx, JSValueConst obj, static JSValue js_array_from_iterator(JSContext *ctx, uint32_t *plen, - JSValueConst obj, JSValueConst method) + JSValue obj, JSValue method) { JSValue arr, iter, next_method = JS_UNDEFINED, val; - BOOL done; + int done; uint32_t k; *plen = 0; @@ -55090,8 +54315,8 @@ static JSValue js_array_from_iterator(JSContext *ctx, uint32_t *plen, } static JSValue js_typed_array_constructor_obj(JSContext *ctx, - JSValueConst new_target, - JSValueConst obj, + JSValue new_target, + JSValue obj, int classid) { JSValue iter, ret, arr = JS_UNDEFINED, val, buffer; @@ -55117,14 +54342,15 @@ static JSValue js_typed_array_constructor_obj(JSContext *ctx, } else { if (js_get_length64(ctx, &len, obj)) goto fail; - arr = JS_DupValue(ctx, obj); + arr = js_dup(obj); } buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED, - len << size_log2); + len << size_log2, + NULL); if (JS_IsException(buffer)) goto fail; - if (typed_array_init(ctx, ret, buffer, 0, len)) + if (typed_array_init(ctx, ret, buffer, 0, len, /*track_rab*/false)) goto fail; for(i = 0; i < len; i++) { @@ -55143,14 +54369,14 @@ static JSValue js_typed_array_constructor_obj(JSContext *ctx, } static JSValue js_typed_array_constructor_ta(JSContext *ctx, - JSValueConst new_target, - JSValueConst src_obj, - int classid) + JSValue new_target, + JSValue src_obj, + int classid, uint32_t len) { JSObject *p, *src_buffer; JSTypedArray *ta; JSValue obj, buffer; - uint32_t len, i; + uint32_t i; int size_log2; JSArrayBuffer *src_abuf, *abuf; @@ -55158,27 +54384,27 @@ static JSValue js_typed_array_constructor_ta(JSContext *ctx, if (JS_IsException(obj)) return obj; p = JS_VALUE_GET_OBJ(src_obj); - if (typed_array_is_detached(ctx, p)) { - JS_ThrowTypeErrorDetachedArrayBuffer(ctx); + if (typed_array_is_oob(p)) { + JS_ThrowTypeErrorArrayBufferOOB(ctx); goto fail; } ta = p->u.typed_array; - len = p->u.array.count; src_buffer = ta->buffer; src_abuf = src_buffer->u.array_buffer; size_log2 = typed_array_size_log2(classid); buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED, - (uint64_t)len << size_log2); + (uint64_t)len << size_log2, + NULL); if (JS_IsException(buffer)) goto fail; /* necessary because it could have been detached */ - if (typed_array_is_detached(ctx, p)) { + if (typed_array_is_oob(p)) { JS_FreeValue(ctx, buffer); - JS_ThrowTypeErrorDetachedArrayBuffer(ctx); + JS_ThrowTypeErrorArrayBufferOOB(ctx); goto fail; } abuf = JS_GetOpaque(buffer, JS_CLASS_ARRAY_BUFFER); - if (typed_array_init(ctx, obj, buffer, 0, len)) + if (typed_array_init(ctx, obj, buffer, 0, len, /*track_rab*/false)) goto fail; if (p->class_id == classid) { /* same type: copy the content */ @@ -55200,10 +54426,11 @@ static JSValue js_typed_array_constructor_ta(JSContext *ctx, } static JSValue js_typed_array_constructor(JSContext *ctx, - JSValueConst new_target, - int argc, JSValueConst *argv, + JSValue new_target, + int argc, JSValue *argv, int classid) { + bool track_rab = false; JSValue buffer, obj; JSArrayBuffer *abuf; int size_log2; @@ -55214,7 +54441,8 @@ static JSValue js_typed_array_constructor(JSContext *ctx, if (JS_ToIndex(ctx, &len, argv[0])) return JS_EXCEPTION; buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED, - len << size_log2); + len << size_log2, + NULL); if (JS_IsException(buffer)) return JS_EXCEPTION; offset = 0; @@ -55231,8 +54459,10 @@ static JSValue js_typed_array_constructor(JSContext *ctx, offset > abuf->byte_length) return JS_ThrowRangeError(ctx, "invalid offset"); if (JS_IsUndefined(argv[2])) { - if ((abuf->byte_length & ((1 << size_log2) - 1)) != 0) - goto invalid_length; + track_rab = array_buffer_is_resizable(abuf); + if (!track_rab) + if ((abuf->byte_length & ((1 << size_log2) - 1)) != 0) + goto invalid_length; len = (abuf->byte_length - offset) >> size_log2; } else { if (JS_ToIndex(ctx, &len, argv[2])) @@ -55244,11 +54474,11 @@ static JSValue js_typed_array_constructor(JSContext *ctx, return JS_ThrowRangeError(ctx, "invalid length"); } } - buffer = JS_DupValue(ctx, argv[0]); + buffer = js_dup(argv[0]); } else { - if (p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_FLOAT64_ARRAY) { - return js_typed_array_constructor_ta(ctx, new_target, argv[0], classid); + if (is_typed_array(p->class_id)) { + return js_typed_array_constructor_ta(ctx, new_target, argv[0], + classid, p->u.array.count); } else { return js_typed_array_constructor_obj(ctx, new_target, argv[0], classid); } @@ -55260,7 +54490,7 @@ static JSValue js_typed_array_constructor(JSContext *ctx, JS_FreeValue(ctx, buffer); return JS_EXCEPTION; } - if (typed_array_init(ctx, obj, buffer, offset, len)) { + if (typed_array_init(ctx, obj, buffer, offset, len, track_rab)) { JS_FreeValue(ctx, obj); return JS_EXCEPTION; } @@ -55282,7 +54512,7 @@ static void js_typed_array_finalizer(JSRuntime *rt, JSValue val) } } -static void js_typed_array_mark(JSRuntime *rt, JSValueConst val, +static void js_typed_array_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); @@ -55293,13 +54523,15 @@ static void js_typed_array_mark(JSRuntime *rt, JSValueConst val, } static JSValue js_dataview_constructor(JSContext *ctx, - JSValueConst new_target, - int argc, JSValueConst *argv) + JSValue new_target, + int argc, JSValue *argv) { + bool recompute_len = false; + bool track_rab = false; JSArrayBuffer *abuf; uint64_t offset; uint32_t len; - JSValueConst buffer; + JSValue buffer; JSValue obj; JSTypedArray *ta; JSObject *p; @@ -55325,6 +54557,9 @@ static JSValue js_dataview_constructor(JSContext *ctx, if (l > len) return JS_ThrowRangeError(ctx, "invalid byteLength"); len = l; + } else { + recompute_len = true; + track_rab = array_buffer_is_resizable(abuf); } obj = js_create_from_ctor(ctx, new_target, JS_CLASS_DATAVIEW); @@ -55335,6 +54570,16 @@ static JSValue js_dataview_constructor(JSContext *ctx, JS_ThrowTypeErrorDetachedArrayBuffer(ctx); goto fail; } + // RAB could have been resized in js_create_from_ctor() + if (offset > abuf->byte_length) { + goto out_of_bound; + } else if (recompute_len) { + len = abuf->byte_length - offset; + } else if (offset + len > abuf->byte_length) { + out_of_bound: + JS_ThrowRangeError(ctx, "invalid byteOffset or byteLength"); + goto fail; + } ta = js_malloc(ctx, sizeof(*ta)); if (!ta) { fail: @@ -55343,21 +54588,98 @@ static JSValue js_dataview_constructor(JSContext *ctx, } p = JS_VALUE_GET_OBJ(obj); ta->obj = p; - ta->buffer = JS_VALUE_GET_OBJ(JS_DupValue(ctx, buffer)); + ta->buffer = JS_VALUE_GET_OBJ(js_dup(buffer)); ta->offset = offset; ta->length = len; + ta->track_rab = track_rab; list_add_tail(&ta->link, &abuf->array_list); p->u.typed_array = ta; return obj; } +// is the DataView out of bounds relative to its parent arraybuffer? +static bool dataview_is_oob(JSObject *p) +{ + JSArrayBuffer *abuf; + JSTypedArray *ta; + + assert(p->class_id == JS_CLASS_DATAVIEW); + ta = p->u.typed_array; + abuf = ta->buffer->u.array_buffer; + if (abuf->detached) + return true; + if (ta->offset > abuf->byte_length) + return true; + if (ta->track_rab) + return false; + return (int64_t)ta->offset + ta->length > abuf->byte_length; +} + +static JSObject *get_dataview(JSContext *ctx, JSValue this_val) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT) + goto fail; + p = JS_VALUE_GET_OBJ(this_val); + if (p->class_id != JS_CLASS_DATAVIEW) { + fail: + JS_ThrowTypeError(ctx, "not a DataView"); + return NULL; + } + return p; +} + +static JSValue js_dataview_get_buffer(JSContext *ctx, JSValue this_val) +{ + JSObject *p; + JSTypedArray *ta; + p = get_dataview(ctx, this_val); + if (!p) + return JS_EXCEPTION; + ta = p->u.typed_array; + return js_dup(JS_MKPTR(JS_TAG_OBJECT, ta->buffer)); +} + +static JSValue js_dataview_get_byteLength(JSContext *ctx, JSValue this_val) +{ + JSArrayBuffer *abuf; + JSTypedArray *ta; + JSObject *p; + + p = get_dataview(ctx, this_val); + if (!p) + return JS_EXCEPTION; + if (dataview_is_oob(p)) + return JS_ThrowTypeErrorArrayBufferOOB(ctx); + ta = p->u.typed_array; + if (ta->track_rab) { + abuf = ta->buffer->u.array_buffer; + return js_uint32(abuf->byte_length - ta->offset); + } + return js_uint32(ta->length); +} + +static JSValue js_dataview_get_byteOffset(JSContext *ctx, JSValue this_val) +{ + JSTypedArray *ta; + JSObject *p; + + p = get_dataview(ctx, this_val); + if (!p) + return JS_EXCEPTION; + if (dataview_is_oob(p)) + return JS_ThrowTypeErrorArrayBufferOOB(ctx); + ta = p->u.typed_array; + return js_uint32(ta->offset); +} + static JSValue js_dataview_getValue(JSContext *ctx, - JSValueConst this_obj, - int argc, JSValueConst *argv, int class_id) + JSValue this_obj, + int argc, JSValue *argv, int class_id) { JSTypedArray *ta; JSArrayBuffer *abuf; - BOOL littleEndian, is_swap; + bool littleEndian, is_swap; int size; uint8_t *ptr; uint32_t v; @@ -55374,35 +54696,41 @@ static JSValue js_dataview_getValue(JSContext *ctx, abuf = ta->buffer->u.array_buffer; if (abuf->detached) return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); + // order matters: this check should come before the next one if ((pos + size) > ta->length) return JS_ThrowRangeError(ctx, "out of bound"); + // test262 expects a TypeError for this and V8, in its infinite wisdom, + // throws a "detached array buffer" exception, but IMO that doesn't make + // sense because the buffer is not in fact detached, it's still there + if ((int64_t)ta->offset + ta->length > abuf->byte_length) + return JS_ThrowTypeError(ctx, "out of bound"); ptr = abuf->data + ta->offset + pos; switch(class_id) { case JS_CLASS_INT8_ARRAY: - return JS_NewInt32(ctx, *(int8_t *)ptr); + return js_int32(*(int8_t *)ptr); case JS_CLASS_UINT8_ARRAY: - return JS_NewInt32(ctx, *(uint8_t *)ptr); + return js_int32(*(uint8_t *)ptr); case JS_CLASS_INT16_ARRAY: v = get_u16(ptr); if (is_swap) v = bswap16(v); - return JS_NewInt32(ctx, (int16_t)v); + return js_int32((int16_t)v); case JS_CLASS_UINT16_ARRAY: v = get_u16(ptr); if (is_swap) v = bswap16(v); - return JS_NewInt32(ctx, v); + return js_int32(v); case JS_CLASS_INT32_ARRAY: v = get_u32(ptr); if (is_swap) v = bswap32(v); - return JS_NewInt32(ctx, v); + return js_int32(v); case JS_CLASS_UINT32_ARRAY: v = get_u32(ptr); if (is_swap) v = bswap32(v); - return JS_NewUint32(ctx, v); + return js_uint32(v); case JS_CLASS_BIG_INT64_ARRAY: { uint64_t v; @@ -55421,6 +54749,14 @@ static JSValue js_dataview_getValue(JSContext *ctx, return JS_NewBigUint64(ctx, v); } break; + case JS_CLASS_FLOAT16_ARRAY: + { + uint16_t v; + v = get_u16(ptr); + if (is_swap) + v = bswap16(v); + return js_float64(fromfp16(v)); + } case JS_CLASS_FLOAT32_ARRAY: { union { @@ -55431,7 +54767,7 @@ static JSValue js_dataview_getValue(JSContext *ctx, if (is_swap) v = bswap32(v); u.i = v; - return __JS_NewFloat64(ctx, u.f); + return js_float64(u.f); } case JS_CLASS_FLOAT64_ARRAY: { @@ -55442,26 +54778,27 @@ static JSValue js_dataview_getValue(JSContext *ctx, u.i = get_u64(ptr); if (is_swap) u.i = bswap64(u.i); - return __JS_NewFloat64(ctx, u.f); + return js_float64(u.f); } default: abort(); } + return JS_EXCEPTION; // pacify compiler } static JSValue js_dataview_setValue(JSContext *ctx, - JSValueConst this_obj, - int argc, JSValueConst *argv, int class_id) + JSValue this_obj, + int argc, JSValue *argv, int class_id) { JSTypedArray *ta; JSArrayBuffer *abuf; - BOOL littleEndian, is_swap; + bool littleEndian, is_swap; int size; uint8_t *ptr; uint64_t v64; uint32_t v; uint64_t pos; - JSValueConst val; + JSValue val; ta = JS_GetOpaque2(ctx, this_obj, JS_CLASS_DATAVIEW); if (!ta) @@ -55475,14 +54812,17 @@ static JSValue js_dataview_setValue(JSContext *ctx, if (class_id <= JS_CLASS_UINT32_ARRAY) { if (JS_ToUint32(ctx, &v, val)) return JS_EXCEPTION; - } else if (class_id <= JS_CLASS_BIG_UINT64_ARRAY) { + } else + if (class_id <= JS_CLASS_BIG_UINT64_ARRAY) { if (JS_ToBigInt64(ctx, (int64_t *)&v64, val)) return JS_EXCEPTION; } else { double d; if (JS_ToFloat64(ctx, &d, val)) return JS_EXCEPTION; - if (class_id == JS_CLASS_FLOAT32_ARRAY) { + if (class_id == JS_CLASS_FLOAT16_ARRAY) { + v = tofp16(d); + } else if (class_id == JS_CLASS_FLOAT32_ARRAY) { union { float f; uint32_t i; @@ -55500,8 +54840,14 @@ static JSValue js_dataview_setValue(JSContext *ctx, abuf = ta->buffer->u.array_buffer; if (abuf->detached) return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); + // order matters: this check should come before the next one if ((pos + size) > ta->length) return JS_ThrowRangeError(ctx, "out of bound"); + // test262 expects a TypeError for this and V8, in its infinite wisdom, + // throws a "detached array buffer" exception, but IMO that doesn't make + // sense because the buffer is not in fact detached, it's still there + if ((int64_t)ta->offset + ta->length > abuf->byte_length) + return JS_ThrowTypeError(ctx, "out of bound"); ptr = abuf->data + ta->offset + pos; switch(class_id) { @@ -55511,6 +54857,7 @@ static JSValue js_dataview_setValue(JSContext *ctx, break; case JS_CLASS_INT16_ARRAY: case JS_CLASS_UINT16_ARRAY: + case JS_CLASS_FLOAT16_ARRAY: if (is_swap) v = bswap16(v); put_u16(ptr, v); @@ -55536,9 +54883,9 @@ static JSValue js_dataview_setValue(JSContext *ctx, } static const JSCFunctionListEntry js_dataview_proto_funcs[] = { - JS_CGETSET_MAGIC_DEF("buffer", js_typed_array_get_buffer, NULL, 1 ), - JS_CGETSET_MAGIC_DEF("byteLength", js_typed_array_get_byteLength, NULL, 1 ), - JS_CGETSET_MAGIC_DEF("byteOffset", js_typed_array_get_byteOffset, NULL, 1 ), + JS_CGETSET_DEF("buffer", js_dataview_get_buffer, NULL ), + JS_CGETSET_DEF("byteLength", js_dataview_get_byteLength, NULL ), + JS_CGETSET_DEF("byteOffset", js_dataview_get_byteOffset, NULL ), JS_CFUNC_MAGIC_DEF("getInt8", 1, js_dataview_getValue, JS_CLASS_INT8_ARRAY ), JS_CFUNC_MAGIC_DEF("getUint8", 1, js_dataview_getValue, JS_CLASS_UINT8_ARRAY ), JS_CFUNC_MAGIC_DEF("getInt16", 1, js_dataview_getValue, JS_CLASS_INT16_ARRAY ), @@ -55547,6 +54894,7 @@ static const JSCFunctionListEntry js_dataview_proto_funcs[] = { JS_CFUNC_MAGIC_DEF("getUint32", 1, js_dataview_getValue, JS_CLASS_UINT32_ARRAY ), JS_CFUNC_MAGIC_DEF("getBigInt64", 1, js_dataview_getValue, JS_CLASS_BIG_INT64_ARRAY ), JS_CFUNC_MAGIC_DEF("getBigUint64", 1, js_dataview_getValue, JS_CLASS_BIG_UINT64_ARRAY ), + JS_CFUNC_MAGIC_DEF("getFloat16", 1, js_dataview_getValue, JS_CLASS_FLOAT16_ARRAY ), JS_CFUNC_MAGIC_DEF("getFloat32", 1, js_dataview_getValue, JS_CLASS_FLOAT32_ARRAY ), JS_CFUNC_MAGIC_DEF("getFloat64", 1, js_dataview_getValue, JS_CLASS_FLOAT64_ARRAY ), JS_CFUNC_MAGIC_DEF("setInt8", 2, js_dataview_setValue, JS_CLASS_INT8_ARRAY ), @@ -55557,11 +54905,62 @@ static const JSCFunctionListEntry js_dataview_proto_funcs[] = { JS_CFUNC_MAGIC_DEF("setUint32", 2, js_dataview_setValue, JS_CLASS_UINT32_ARRAY ), JS_CFUNC_MAGIC_DEF("setBigInt64", 2, js_dataview_setValue, JS_CLASS_BIG_INT64_ARRAY ), JS_CFUNC_MAGIC_DEF("setBigUint64", 2, js_dataview_setValue, JS_CLASS_BIG_UINT64_ARRAY ), + JS_CFUNC_MAGIC_DEF("setFloat16", 2, js_dataview_setValue, JS_CLASS_FLOAT16_ARRAY ), JS_CFUNC_MAGIC_DEF("setFloat32", 2, js_dataview_setValue, JS_CLASS_FLOAT32_ARRAY ), JS_CFUNC_MAGIC_DEF("setFloat64", 2, js_dataview_setValue, JS_CLASS_FLOAT64_ARRAY ), JS_PROP_STRING_DEF("[Symbol.toStringTag]", "DataView", JS_PROP_CONFIGURABLE ), }; +static JSValue js_new_uint8array(JSContext *ctx, JSValue buffer) +{ + if (JS_IsException(buffer)) + return JS_EXCEPTION; + JSValue obj = js_create_from_ctor(ctx, JS_UNDEFINED, JS_CLASS_UINT8_ARRAY); + if (JS_IsException(obj)) { + JS_FreeValue(ctx, buffer); + return JS_EXCEPTION; + } + JSArrayBuffer *abuf = js_get_array_buffer(ctx, buffer); + assert(abuf != NULL); + if (typed_array_init(ctx, obj, buffer, 0, abuf->byte_length, /*track_rab*/false)) { + // 'buffer' is freed on error above. + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; + } + return obj; +} + +JSValue JS_NewUint8Array(JSContext *ctx, uint8_t *buf, size_t len, + JSFreeArrayBufferDataFunc *free_func, void *opaque, + bool is_shared) +{ + JSClassID class_id = + is_shared ? JS_CLASS_SHARED_ARRAY_BUFFER : JS_CLASS_ARRAY_BUFFER; + JSValue buffer = js_array_buffer_constructor3(ctx, JS_UNDEFINED, len, NULL, + class_id, buf, free_func, + opaque, false); + return js_new_uint8array(ctx, buffer); +} + +JSValue JS_NewUint8ArrayCopy(JSContext *ctx, const uint8_t *buf, size_t len) +{ + JSValue buffer = js_array_buffer_constructor3(ctx, JS_UNDEFINED, len, NULL, + JS_CLASS_ARRAY_BUFFER, + (uint8_t *)buf, + js_array_buffer_free, NULL, + true); + return js_new_uint8array(ctx, buffer); +} + +int JS_GetTypedArrayType(JSValue obj) +{ + JSClassID class_id = JS_GetClassID(obj); + if (is_typed_array(class_id)) + return class_id - JS_CLASS_UINT8C_ARRAY; + else + return -1; +} + /* Atomics */ #ifdef CONFIG_ATOMICS @@ -55579,7 +54978,7 @@ typedef enum AtomicsOpEnum { static void *js_atomics_get_ptr(JSContext *ctx, JSArrayBuffer **pabuf, int *psize_log2, JSClassID *pclass_id, - JSValueConst obj, JSValueConst idx_val, + JSValue obj, JSValue idx_val, int is_waitable) { JSObject *p; @@ -55587,7 +54986,7 @@ static void *js_atomics_get_ptr(JSContext *ctx, JSArrayBuffer *abuf; void *ptr; uint64_t idx; - BOOL err; + bool err; int size_log2; if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) @@ -55636,8 +55035,8 @@ static void *js_atomics_get_ptr(JSContext *ctx, } static JSValue js_atomics_op(JSContext *ctx, - JSValueConst this_obj, - int argc, JSValueConst *argv, int op) + JSValue this_obj, + int argc, JSValue *argv, int op) { int size_log2; uint64_t v, a, rep_val; @@ -55665,15 +55064,15 @@ static JSValue js_atomics_op(JSContext *ctx, rep_val = v64; } } else { - uint32_t v32; - if (JS_ToUint32(ctx, &v32, argv[2])) - return JS_EXCEPTION; - v = v32; - if (op == ATOMICS_OP_COMPARE_EXCHANGE) { - if (JS_ToUint32(ctx, &v32, argv[3])) - return JS_EXCEPTION; - rep_val = v32; - } + uint32_t v32; + if (JS_ToUint32(ctx, &v32, argv[2])) + return JS_EXCEPTION; + v = v32; + if (op == ATOMICS_OP_COMPARE_EXCHANGE) { + if (JS_ToUint32(ctx, &v32, argv[3])) + return JS_EXCEPTION; + rep_val = v32; + } } if (abuf->detached) return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); @@ -55683,18 +55082,17 @@ static JSValue js_atomics_op(JSContext *ctx, #define OP(op_name, func_name) \ case ATOMICS_OP_ ## op_name | (0 << 3): \ - a = func_name((_Atomic(uint8_t) *)ptr, v); \ + a = func_name((_Atomic uint8_t *)ptr, v); \ break; \ case ATOMICS_OP_ ## op_name | (1 << 3): \ - a = func_name((_Atomic(uint16_t) *)ptr, v); \ + a = func_name((_Atomic uint16_t *)ptr, v); \ break; \ case ATOMICS_OP_ ## op_name | (2 << 3): \ - a = func_name((_Atomic(uint32_t) *)ptr, v); \ + a = func_name((_Atomic uint32_t *)ptr, v); \ break; \ case ATOMICS_OP_ ## op_name | (3 << 3): \ - a = func_name((_Atomic(uint64_t) *)ptr, v); \ + a = func_name((_Atomic uint64_t *)ptr, v); \ break; - OP(ADD, atomic_fetch_add) OP(AND, atomic_fetch_and) OP(OR, atomic_fetch_or) @@ -55704,43 +55102,42 @@ static JSValue js_atomics_op(JSContext *ctx, #undef OP case ATOMICS_OP_LOAD | (0 << 3): - a = atomic_load((_Atomic(uint8_t) *)ptr); + a = atomic_load((_Atomic uint8_t *)ptr); break; case ATOMICS_OP_LOAD | (1 << 3): - a = atomic_load((_Atomic(uint16_t) *)ptr); + a = atomic_load((_Atomic uint16_t *)ptr); break; case ATOMICS_OP_LOAD | (2 << 3): - a = atomic_load((_Atomic(uint32_t) *)ptr); + a = atomic_load((_Atomic uint32_t *)ptr); break; case ATOMICS_OP_LOAD | (3 << 3): - a = atomic_load((_Atomic(uint64_t) *)ptr); + a = atomic_load((_Atomic uint64_t *)ptr); break; - case ATOMICS_OP_COMPARE_EXCHANGE | (0 << 3): { uint8_t v1 = v; - atomic_compare_exchange_strong((_Atomic(uint8_t) *)ptr, &v1, rep_val); + atomic_compare_exchange_strong((_Atomic uint8_t *)ptr, &v1, rep_val); a = v1; } break; case ATOMICS_OP_COMPARE_EXCHANGE | (1 << 3): { uint16_t v1 = v; - atomic_compare_exchange_strong((_Atomic(uint16_t) *)ptr, &v1, rep_val); + atomic_compare_exchange_strong((_Atomic uint16_t *)ptr, &v1, rep_val); a = v1; } break; case ATOMICS_OP_COMPARE_EXCHANGE | (2 << 3): { uint32_t v1 = v; - atomic_compare_exchange_strong((_Atomic(uint32_t) *)ptr, &v1, rep_val); + atomic_compare_exchange_strong((_Atomic uint32_t *)ptr, &v1, rep_val); a = v1; } break; case ATOMICS_OP_COMPARE_EXCHANGE | (3 << 3): { uint64_t v1 = v; - atomic_compare_exchange_strong((_Atomic(uint64_t) *)ptr, &v1, rep_val); + atomic_compare_exchange_strong((_Atomic uint64_t *)ptr, &v1, rep_val); a = v1; } break; @@ -55763,10 +55160,10 @@ static JSValue js_atomics_op(JSContext *ctx, goto done; case JS_CLASS_INT32_ARRAY: done: - ret = JS_NewInt32(ctx, a); + ret = js_int32(a); break; case JS_CLASS_UINT32_ARRAY: - ret = JS_NewUint32(ctx, a); + ret = js_uint32(a); break; case JS_CLASS_BIG_INT64_ARRAY: ret = JS_NewBigInt64(ctx, a); @@ -55781,8 +55178,8 @@ static JSValue js_atomics_op(JSContext *ctx, } static JSValue js_atomics_store(JSContext *ctx, - JSValueConst this_obj, - int argc, JSValueConst *argv) + JSValue this_obj, + int argc, JSValue *argv) { int size_log2; void *ptr; @@ -55795,7 +55192,7 @@ static JSValue js_atomics_store(JSContext *ctx, return JS_EXCEPTION; if (size_log2 == 3) { int64_t v64; - ret = JS_ToBigIntValueFree(ctx, JS_DupValue(ctx, argv[2])); + ret = JS_ToBigIntValueFree(ctx, js_dup(argv[2])); if (JS_IsException(ret)) return ret; if (JS_ToBigInt64(ctx, &v64, ret)) { @@ -55804,11 +55201,11 @@ static JSValue js_atomics_store(JSContext *ctx, } if (abuf->detached) return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); - atomic_store((_Atomic(uint64_t) *)ptr, v64); + atomic_store((_Atomic uint64_t *)ptr, v64); } else { uint32_t v; /* XXX: spec, would be simpler to return the written value */ - ret = JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[2])); + ret = JS_ToIntegerFree(ctx, js_dup(argv[2])); if (JS_IsException(ret)) return ret; if (JS_ToUint32(ctx, &v, ret)) { @@ -55819,13 +55216,13 @@ static JSValue js_atomics_store(JSContext *ctx, return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); switch(size_log2) { case 0: - atomic_store((_Atomic(uint8_t) *)ptr, v); + atomic_store((_Atomic uint8_t *)ptr, v); break; case 1: - atomic_store((_Atomic(uint16_t) *)ptr, v); + atomic_store((_Atomic uint16_t *)ptr, v); break; case 2: - atomic_store((_Atomic(uint32_t) *)ptr, v); + atomic_store((_Atomic uint32_t *)ptr, v); break; default: abort(); @@ -55835,36 +55232,62 @@ static JSValue js_atomics_store(JSContext *ctx, } static JSValue js_atomics_isLockFree(JSContext *ctx, - JSValueConst this_obj, - int argc, JSValueConst *argv) + JSValue this_obj, + int argc, JSValue *argv) { int v, ret; if (JS_ToInt32Sat(ctx, &v, argv[0])) return JS_EXCEPTION; ret = (v == 1 || v == 2 || v == 4 || v == 8); - return JS_NewBool(ctx, ret); + return js_bool(ret); } typedef struct JSAtomicsWaiter { struct list_head link; - BOOL linked; - pthread_cond_t cond; + bool linked; + js_cond_t cond; int32_t *ptr; } JSAtomicsWaiter; -static pthread_mutex_t js_atomics_mutex = PTHREAD_MUTEX_INITIALIZER; +static js_once_t js_atomics_once = JS_ONCE_INIT; +static js_mutex_t js_atomics_mutex; static struct list_head js_atomics_waiter_list = LIST_HEAD_INIT(js_atomics_waiter_list); +// no-op: Atomics.pause() is not allowed to block or yield to another +// thread, only to hint the CPU that it should back off for a bit; +// the amount of work we do here is a good enough substitute +static JSValue js_atomics_pause(JSContext *ctx, JSValue this_obj, + int argc, JSValue *argv) +{ + double d; + + if (argc > 0) { + switch (JS_VALUE_GET_TAG(argv[0])) { + case JS_TAG_FLOAT64: // accepted if and only if fraction == 0.0 + d = JS_VALUE_GET_FLOAT64(argv[0]); + if (isfinite(d)) + if (0 == modf(d, &d)) + break; + // fallthru + default: + return JS_ThrowTypeError(ctx, "not an integral number"); + case JS_TAG_UNDEFINED: + case JS_TAG_INT: + break; + } + } + return JS_UNDEFINED; +} + static JSValue js_atomics_wait(JSContext *ctx, - JSValueConst this_obj, - int argc, JSValueConst *argv) + JSValue this_obj, + int argc, JSValue *argv) { int64_t v; int32_t v32; void *ptr; int64_t timeout; - struct timespec ts; JSAtomicsWaiter waiter_s, *waiter; int ret, size_log2, res; double d; @@ -55883,7 +55306,6 @@ static JSValue js_atomics_wait(JSContext *ctx, } if (JS_ToFloat64(ctx, &d, argv[3])) return JS_EXCEPTION; - /* must use INT64_MAX + 1 because INT64_MAX cannot be exactly represented as a double */ if (isnan(d) || d >= 0x1p63) timeout = INT64_MAX; else if (d < 0) @@ -55895,44 +55317,34 @@ static JSValue js_atomics_wait(JSContext *ctx, /* XXX: inefficient if large number of waiters, should hash on 'ptr' value */ - /* XXX: use Linux futexes when available ? */ - pthread_mutex_lock(&js_atomics_mutex); + js_mutex_lock(&js_atomics_mutex); if (size_log2 == 3) { res = *(int64_t *)ptr != v; } else { res = *(int32_t *)ptr != v; } if (res) { - pthread_mutex_unlock(&js_atomics_mutex); + js_mutex_unlock(&js_atomics_mutex); return JS_AtomToString(ctx, JS_ATOM_not_equal); } waiter = &waiter_s; waiter->ptr = ptr; - pthread_cond_init(&waiter->cond, NULL); - waiter->linked = TRUE; + js_cond_init(&waiter->cond); + waiter->linked = true; list_add_tail(&waiter->link, &js_atomics_waiter_list); if (timeout == INT64_MAX) { - pthread_cond_wait(&waiter->cond, &js_atomics_mutex); + js_cond_wait(&waiter->cond, &js_atomics_mutex); ret = 0; } else { - /* XXX: use clock monotonic */ - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += timeout / 1000; - ts.tv_nsec += (timeout % 1000) * 1000000; - if (ts.tv_nsec >= 1000000000) { - ts.tv_nsec -= 1000000000; - ts.tv_sec++; - } - ret = pthread_cond_timedwait(&waiter->cond, &js_atomics_mutex, - &ts); + ret = js_cond_timedwait(&waiter->cond, &js_atomics_mutex, timeout * 1e6 /* to ns */); } if (waiter->linked) list_del(&waiter->link); - pthread_mutex_unlock(&js_atomics_mutex); - pthread_cond_destroy(&waiter->cond); - if (ret == ETIMEDOUT) { + js_mutex_unlock(&js_atomics_mutex); + js_cond_destroy(&waiter->cond); + if (ret == -1) { return JS_AtomToString(ctx, JS_ATOM_timed_out); } else { return JS_AtomToString(ctx, JS_ATOM_ok); @@ -55940,8 +55352,8 @@ static JSValue js_atomics_wait(JSContext *ctx, } static JSValue js_atomics_notify(JSContext *ctx, - JSValueConst this_obj, - int argc, JSValueConst *argv) + JSValue this_obj, + int argc, JSValue *argv) { struct list_head *el, *el1, waiter_list; int32_t count, n; @@ -55964,13 +55376,13 @@ static JSValue js_atomics_notify(JSContext *ctx, n = 0; if (abuf->shared && count > 0) { - pthread_mutex_lock(&js_atomics_mutex); + js_mutex_lock(&js_atomics_mutex); init_list_head(&waiter_list); list_for_each_safe(el, el1, &js_atomics_waiter_list) { waiter = list_entry(el, JSAtomicsWaiter, link); if (waiter->ptr == ptr) { list_del(&waiter->link); - waiter->linked = FALSE; + waiter->linked = false; list_add_tail(&waiter->link, &waiter_list); n++; if (n >= count) @@ -55979,11 +55391,11 @@ static JSValue js_atomics_notify(JSContext *ctx, } list_for_each(el, &waiter_list) { waiter = list_entry(el, JSAtomicsWaiter, link); - pthread_cond_signal(&waiter->cond); + js_cond_signal(&waiter->cond); } - pthread_mutex_unlock(&js_atomics_mutex); + js_mutex_unlock(&js_atomics_mutex); } - return JS_NewInt32(ctx, n); + return js_int32(n); } static const JSCFunctionListEntry js_atomics_funcs[] = { @@ -55997,6 +55409,7 @@ static const JSCFunctionListEntry js_atomics_funcs[] = { JS_CFUNC_MAGIC_DEF("load", 2, js_atomics_op, ATOMICS_OP_LOAD ), JS_CFUNC_DEF("store", 3, js_atomics_store ), JS_CFUNC_DEF("isLockFree", 1, js_atomics_isLockFree ), + JS_CFUNC_DEF("pause", 0, js_atomics_pause ), JS_CFUNC_DEF("wait", 4, js_atomics_wait ), JS_CFUNC_DEF("notify", 3, js_atomics_notify ), JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Atomics", JS_PROP_CONFIGURABLE ), @@ -56006,8 +55419,15 @@ static const JSCFunctionListEntry js_atomics_obj[] = { JS_OBJECT_DEF("Atomics", js_atomics_funcs, countof(js_atomics_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ), }; +static void js__atomics_init(void) { + js_mutex_init(&js_atomics_mutex); +} + +/* TODO(saghul) make this public and not dependent on typed arrays? */ void JS_AddIntrinsicAtomics(JSContext *ctx) { + js_once(&js_atomics_once, js__atomics_init); + /* add Atomics as autoinit object */ JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_atomics_obj, countof(js_atomics_obj)); } @@ -56017,7 +55437,7 @@ void JS_AddIntrinsicAtomics(JSContext *ctx) void JS_AddIntrinsicTypedArrays(JSContext *ctx) { JSValue typed_array_base_proto, typed_array_base_func; - JSValueConst array_buffer_func, shared_array_buffer_func; + JSValue array_buffer_func, shared_array_buffer_func; int i; ctx->class_proto[JS_CLASS_ARRAY_BUFFER] = JS_NewObject(ctx); @@ -56072,7 +55492,7 @@ void JS_AddIntrinsicTypedArrays(JSContext *ctx) ctx->class_proto[i] = JS_NewObjectProto(ctx, typed_array_base_proto); JS_DefinePropertyValueStr(ctx, ctx->class_proto[i], "BYTES_PER_ELEMENT", - JS_NewInt32(ctx, 1 << typed_array_size_log2(i)), + js_int32(1 << typed_array_size_log2(i)), 0); name = JS_AtomGetStr(ctx, buf, sizeof(buf), JS_ATOM_Uint8ClampedArray + i - JS_CLASS_UINT8C_ARRAY); @@ -56082,7 +55502,7 @@ void JS_AddIntrinsicTypedArrays(JSContext *ctx) JS_NewGlobalCConstructor2(ctx, func_obj, name, ctx->class_proto[i]); JS_DefinePropertyValueStr(ctx, func_obj, "BYTES_PER_ELEMENT", - JS_NewInt32(ctx, 1 << typed_array_size_log2(i)), + js_int32(1 << typed_array_size_log2(i)), 0); } JS_FreeValue(ctx, typed_array_base_proto); @@ -56102,166 +55522,817 @@ void JS_AddIntrinsicTypedArrays(JSContext *ctx) #endif } -#ifndef NDEBUG -static void *watchedRefCount = NULL; +/* Performance */ -void notifyRefCountIncrease(JSRefCountHeader *p) +static double js__now_ms(void) { - if (p == watchedRefCount) - fprintf(stderr, "increasing ref count %d for %p\n", p->ref_count, watchedRefCount); + return js__hrtime_ns() / 1e6; } -void notifyRefCountDecrease(JSRefCountHeader *p) +static JSValue js_perf_now(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) { - if (p == watchedRefCount) - fprintf(stderr, "decreasing ref count %d for %p\n", p->ref_count, watchedRefCount); + return js_float64(js__now_ms() - ctx->time_origin); } -void watchRefCount(void *p) +static const JSCFunctionListEntry js_perf_proto_funcs[] = { + JS_CFUNC_DEF2("now", 0, js_perf_now, JS_PROP_ENUMERABLE), +}; + +void JS_AddPerformance(JSContext *ctx) { - watchedRefCount = p; + ctx->time_origin = js__now_ms(); + + JSValue performance = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, performance, js_perf_proto_funcs, countof(js_perf_proto_funcs)); + JS_DefinePropertyValueStr(ctx, performance, "timeOrigin", + js_float64(ctx->time_origin), + JS_PROP_ENUMERABLE); + JS_DefinePropertyValueStr(ctx, ctx->global_obj, "performance", + js_dup(performance), + JS_PROP_WRITABLE | JS_PROP_ENUMERABLE | JS_PROP_CONFIGURABLE); + JS_FreeValue(ctx, performance); } -#endif -void setScopeLookup(JSContext *ctx, ScopeLookup *scopeLookup) +/* Equality comparisons and sameness */ +int JS_IsEqual(JSContext *ctx, JSValue op1, JSValue op2) { - ctx->scopeLookup = scopeLookup; + JSValue sp[2] = { js_dup(op1), js_dup(op2) }; + if (js_eq_slow(ctx, endof(sp), 0)) + return -1; + return JS_VALUE_GET_BOOL(sp[0]); } -void setFoundUndefinedHandler(JSContext *ctx, FoundUndefinedHandler *handler) +bool JS_IsStrictEqual(JSContext *ctx, JSValue op1, JSValue op2) { - ctx->handleUndefined = handler; + return js_strict_eq2(ctx, js_dup(op1), js_dup(op2), JS_EQ_STRICT); } -void setFunctionEnteredHandler(JSContext *ctx, FunctionEnteredHandler *handler) +bool JS_IsSameValue(JSContext *ctx, JSValue op1, JSValue op2) { - ctx->handleFunctionEntered = handler; + return js_same_value(ctx, op1, op2); } -void setFunctionExitedHandler(JSContext *ctx, FunctionExitedHandler *handler) +bool JS_IsSameValueZero(JSContext *ctx, JSValue op1, JSValue op2) { - ctx->handleFunctionExited = handler; + return js_same_value_zero(ctx, op1, op2); } -int isSimpleValue(JSValue v) +/* WeakRef */ + +typedef struct JSWeakRefData { + JSValue target; + JSValue obj; +} JSWeakRefData; + +static JSWeakRefData js_weakref_sentinel; + +static void js_weakref_finalizer(JSRuntime *rt, JSValue val) { - JSObject *p; - if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT) - return 1; - p = JS_VALUE_GET_OBJ(v); - return p->class_id >= JS_CLASS_OBJECT && p->class_id <= JS_CLASS_BOOLEAN; + JSWeakRefData *wrd = JS_GetOpaque(val, JS_CLASS_WEAK_REF); + if (!wrd || wrd == &js_weakref_sentinel) + return; + + /* Delete weak ref */ + JSWeakRefRecord **pwr, *wr; + + pwr = get_first_weak_ref(wrd->target); + for(;;) { + wr = *pwr; + assert(wr != NULL); + if (wr->kind == JS_WEAK_REF_KIND_WEAK_REF && wr->u.weak_ref_data == wrd) + break; + pwr = &wr->next_weak_ref; + } + *pwr = wr->next_weak_ref; + js_free_rt(rt, wrd); + js_free_rt(rt, wr); +} + +static JSValue js_weakref_constructor(JSContext *ctx, JSValue new_target, int argc, JSValue *argv) +{ + if (JS_IsUndefined(new_target)) + return JS_ThrowTypeError(ctx, "constructor requires 'new'"); + JSValue arg = argv[0]; + if (!is_valid_weakref_target(arg)) + return JS_ThrowTypeError(ctx, "invalid target"); + // TODO(saghul): short-circuit if the refcount is 1? + JSValue obj = js_create_from_ctor(ctx, new_target, JS_CLASS_WEAK_REF); + if (JS_IsException(obj)) + return JS_EXCEPTION; + JSWeakRefData *wrd = js_malloc(ctx, sizeof(*wrd)); + if (!wrd) { + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; + } + JSWeakRefRecord *wr = js_malloc(ctx, sizeof(*wr)); + if (!wr) { + JS_FreeValue(ctx, obj); + js_free(ctx, wrd); + return JS_EXCEPTION; + } + wrd->target = arg; + wrd->obj = obj; + wr->kind = JS_WEAK_REF_KIND_WEAK_REF; + wr->u.weak_ref_data = wrd; + insert_weakref_record(arg, wr); + + JS_SetOpaqueInternal(obj, wrd); + return obj; } -JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *func, - const char *name, int length, - JSCFunctionEnum cproto, int magic) +static JSValue js_weakref_deref(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) { - return JS_NewCFunction2(ctx, (JSCFunction *)func, name, length, cproto, - magic); + JSWeakRefData *wrd = JS_GetOpaque2(ctx, this_val, JS_CLASS_WEAK_REF); + if (!wrd) + return JS_EXCEPTION; + if (wrd == &js_weakref_sentinel) + return JS_UNDEFINED; + return js_dup(wrd->target); } -#ifdef JS_NAN_BOXING -JSValue mkVal(int32_t tag, int32_t val) +static const JSCFunctionListEntry js_weakref_proto_funcs[] = { + JS_CFUNC_DEF("deref", 0, js_weakref_deref ), + JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakRef", JS_PROP_CONFIGURABLE ), +}; + +static const JSClassShortDef js_weakref_class_def[] = { + { JS_ATOM_WeakRef, js_weakref_finalizer, NULL }, /* JS_CLASS_WEAK_REF */ +}; + +typedef struct JSFinRecEntry { + struct list_head link; + JSValue obj; + JSValue target; + JSValue held_val; + JSValue token; +} JSFinRecEntry; + +typedef struct JSFinalizationRegistryData { + struct list_head entries; + JSContext *ctx; + JSValue cb; +} JSFinalizationRegistryData; + +static void delete_finrec_weakref(JSRuntime *rt, JSFinRecEntry *fre) { - return ((uint64_t)(tag) << 32) | (uint32_t)(val); + JSWeakRefRecord **pwr, *wr; + + pwr = get_first_weak_ref(fre->target); + for(;;) { + wr = *pwr; + assert(wr != NULL); + if (wr->kind == JS_WEAK_REF_KIND_FINALIZATION_REGISTRY_ENTRY && wr->u.fin_rec_entry == fre) + break; + pwr = &wr->next_weak_ref; + } + *pwr = wr->next_weak_ref; + js_free_rt(rt, wr); } -JSValue mkPtr(int32_t tag, void *p) +static void js_finrec_finalizer(JSRuntime *rt, JSValue val) { - return ((uint64_t)(tag) << 32) | (uintptr_t)(p); + JSFinalizationRegistryData *frd = JS_GetOpaque(val, JS_CLASS_FINALIZATION_REGISTRY); + if (frd) { + struct list_head *el, *el1; + /* first pass to remove the weak ref entries and avoid having them modified + by freeing a token / held value. */ + list_for_each_safe(el, el1, &frd->entries) { + JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link); + delete_finrec_weakref(rt, fre); + } + /* second pass to actually free all objects. */ + list_for_each_safe(el, el1, &frd->entries) { + JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link); + list_del(&fre->link); + JS_FreeValueRT(rt, fre->held_val); + JS_FreeValueRT(rt, fre->token); + js_free_rt(rt, fre); + } + JS_FreeValueRT(rt, frd->cb); + js_free_rt(rt, frd); + } } -#else -JSValue mkVal(int32_t tag, int32_t val) + +static void js_finrec_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) { - return (JSValue){ (JSValueUnion){ .int32 = val }, tag }; + JSFinalizationRegistryData *frd = JS_GetOpaque(val, JS_CLASS_FINALIZATION_REGISTRY); + if (frd) { + JS_MarkValue(rt, frd->cb, mark_func); + struct list_head *el; + list_for_each(el, &frd->entries) { + JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link); + JS_MarkValue(rt, fre->held_val, mark_func); + JS_MarkValue(rt, fre->token, mark_func); + } + } } -JSValue mkPtr(int32_t tag, void *p) +static JSValue js_finrec_constructor(JSContext *ctx, JSValue new_target, int argc, JSValue *argv) { - return (JSValue){ (JSValueUnion){ .ptr = p }, tag }; + if (JS_IsUndefined(new_target)) + return JS_ThrowTypeError(ctx, "constructor requires 'new'"); + JSValue cb = argv[0]; + if (!JS_IsFunction(ctx, cb)) + return JS_ThrowTypeError(ctx, "argument must be a function"); + + JSValue obj = js_create_from_ctor(ctx, new_target, JS_CLASS_FINALIZATION_REGISTRY); + if (JS_IsException(obj)) + return JS_EXCEPTION; + JSFinalizationRegistryData *frd = js_malloc(ctx, sizeof(*frd)); + if (!frd) { + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; + } + init_list_head(&frd->entries); + frd->ctx = ctx; + frd->cb = js_dup(cb); + JS_SetOpaqueInternal(obj, frd); + return obj; } -#endif -void JS_FreeValue(JSContext *ctx, JSValue v) { - if (JS_VALUE_HAS_REF_COUNT(v)) { - JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); -#ifndef NDEBUG - notifyRefCountDecrease(p); -#endif - if (--p->ref_count <= 0) { - __JS_FreeValue(ctx, v); +static JSValue js_finrec_register(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) +{ + JSFinalizationRegistryData *frd = JS_GetOpaque2(ctx, this_val, JS_CLASS_FINALIZATION_REGISTRY); + if (!frd) + return JS_EXCEPTION; + + JSValue target = argv[0]; + JSValue held_val = argv[1]; + // The function length needs to return 2, so the 3rd argument won't be initialized. + JSValue token = argc > 2 ? argv[2] : JS_UNDEFINED; + + if (!is_valid_weakref_target(target)) + return JS_ThrowTypeError(ctx, "invalid target"); + if (js_same_value(ctx, target, this_val)) + return JS_UNDEFINED; + if (!JS_IsUndefined(held_val) && js_same_value(ctx, target, held_val)) + return JS_ThrowTypeError(ctx, "held value cannot be the target"); + if (!JS_IsUndefined(token) && !is_valid_weakref_target(token)) + return JS_ThrowTypeError(ctx, "invalid unregister token"); + + JSFinRecEntry *fre = js_malloc(ctx, sizeof(*fre)); + if (!fre) + return JS_EXCEPTION; + JSWeakRefRecord *wr = js_malloc(ctx, sizeof(*wr)); + if (!wr) { + js_free(ctx, fre); + return JS_EXCEPTION; + } + fre->obj = this_val; + fre->target = target; + fre->held_val = js_dup(held_val); + fre->token = js_dup(token); + list_add_tail(&fre->link, &frd->entries); + wr->kind = JS_WEAK_REF_KIND_FINALIZATION_REGISTRY_ENTRY; + wr->u.fin_rec_entry = fre; + insert_weakref_record(target, wr); + + return JS_UNDEFINED; +} + +static JSValue js_finrec_unregister(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) +{ + JSFinalizationRegistryData *frd = JS_GetOpaque2(ctx, this_val, JS_CLASS_FINALIZATION_REGISTRY); + if (!frd) + return JS_EXCEPTION; + + JSValue token = argv[0]; + if (!is_valid_weakref_target(token)) + return JS_ThrowTypeError(ctx, "invalid unregister token"); + + struct list_head *el, *el1; + bool removed = false; + list_for_each_safe(el, el1, &frd->entries) { + JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link); + if (js_same_value(ctx, fre->token, token)) { + list_del(&fre->link); + delete_finrec_weakref(ctx->rt, fre); + JS_FreeValue(ctx, fre->held_val); + JS_FreeValue(ctx, fre->token); + js_free(ctx, fre); + removed = true; } } + + return js_bool(removed); } -void JS_FreeValueRT(JSRuntime *rt, JSValue v) { - if (JS_VALUE_HAS_REF_COUNT(v)) { - JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); -#ifndef NDEBUG - notifyRefCountDecrease(p); -#endif - if (--p->ref_count <= 0) { - __JS_FreeValueRT(rt, v); + +static const JSCFunctionListEntry js_finrec_proto_funcs[] = { + JS_CFUNC_DEF("register", 2, js_finrec_register ), + JS_CFUNC_DEF("unregister", 1, js_finrec_unregister ), + JS_PROP_STRING_DEF("[Symbol.toStringTag]", "FinalizationRegistry", JS_PROP_CONFIGURABLE ), +}; + +static const JSClassShortDef js_finrec_class_def[] = { + { JS_ATOM_FinalizationRegistry, js_finrec_finalizer, js_finrec_mark }, /* JS_CLASS_FINALIZATION_REGISTRY */ +}; + +static JSValue js_finrec_job(JSContext *ctx, int argc, JSValue *argv) +{ + return JS_Call(ctx, argv[0], JS_UNDEFINED, 1, &argv[1]); +} + +void JS_AddIntrinsicWeakRef(JSContext *ctx) +{ + JSRuntime *rt = ctx->rt; + + /* WeakRef */ + if (!JS_IsRegisteredClass(rt, JS_CLASS_WEAK_REF)) { + init_class_range(rt, js_weakref_class_def, JS_CLASS_WEAK_REF, + countof(js_weakref_class_def)); + } + ctx->class_proto[JS_CLASS_WEAK_REF] = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_WEAK_REF], + js_weakref_proto_funcs, + countof(js_weakref_proto_funcs)); + JS_NewGlobalCConstructor(ctx, "WeakRef", js_weakref_constructor, 1, ctx->class_proto[JS_CLASS_WEAK_REF]); + + /* FinalizationRegistry */ + if (!JS_IsRegisteredClass(rt, JS_CLASS_FINALIZATION_REGISTRY)) { + init_class_range(rt, js_finrec_class_def, JS_CLASS_FINALIZATION_REGISTRY, + countof(js_finrec_class_def)); + } + ctx->class_proto[JS_CLASS_FINALIZATION_REGISTRY] = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_FINALIZATION_REGISTRY], + js_finrec_proto_funcs, + countof(js_finrec_proto_funcs)); + JS_NewGlobalCConstructor(ctx, "FinalizationRegistry", js_finrec_constructor, 1, ctx->class_proto[JS_CLASS_FINALIZATION_REGISTRY]); +} + +static void reset_weak_ref(JSRuntime *rt, JSWeakRefRecord **first_weak_ref) +{ + JSWeakRefRecord *wr, *wr_next; + JSWeakRefData *wrd; + JSMapRecord *mr; + JSMapState *s; + JSFinRecEntry *fre; + + /* first pass to remove the records from the WeakMap/WeakSet + lists */ + for(wr = *first_weak_ref; wr != NULL; wr = wr->next_weak_ref) { + switch(wr->kind) { + case JS_WEAK_REF_KIND_MAP: + mr = wr->u.map_record; + s = mr->map; + assert(s->is_weak); + assert(!mr->empty); /* no iterator on WeakMap/WeakSet */ + list_del(&mr->hash_link); + list_del(&mr->link); + break; + case JS_WEAK_REF_KIND_WEAK_REF: + wrd = wr->u.weak_ref_data; + wrd->target = JS_UNDEFINED; + break; + case JS_WEAK_REF_KIND_FINALIZATION_REGISTRY_ENTRY: + fre = wr->u.fin_rec_entry; + list_del(&fre->link); + break; + default: + abort(); } } + + /* second pass to free the values to avoid modifying the weak + reference list while traversing it. */ + for(wr = *first_weak_ref; wr != NULL; wr = wr_next) { + wr_next = wr->next_weak_ref; + switch(wr->kind) { + case JS_WEAK_REF_KIND_MAP: + mr = wr->u.map_record; + JS_FreeValueRT(rt, mr->value); + js_free_rt(rt, mr); + break; + case JS_WEAK_REF_KIND_WEAK_REF: + wrd = wr->u.weak_ref_data; + JS_SetOpaqueInternal(wrd->obj, &js_weakref_sentinel); + js_free_rt(rt, wrd); + break; + case JS_WEAK_REF_KIND_FINALIZATION_REGISTRY_ENTRY: { + fre = wr->u.fin_rec_entry; + JSFinalizationRegistryData *frd = JS_GetOpaque(fre->obj, JS_CLASS_FINALIZATION_REGISTRY); + assert(frd != NULL); + /** + * During the GC sweep phase the held object might be collected first. + */ + if (!rt->in_free && (!JS_IsObject(fre->held_val) || JS_IsLiveObject(rt, fre->held_val))) { + JSValue args[2]; + args[0] = frd->cb; + args[1] = fre->held_val; + JS_EnqueueJob(frd->ctx, js_finrec_job, 2, args); + } + JS_FreeValueRT(rt, fre->held_val); + JS_FreeValueRT(rt, fre->token); + js_free_rt(rt, fre); + break; + } + default: + abort(); + } + js_free_rt(rt, wr); + } + + *first_weak_ref = NULL; /* fail safe */ } -JSValue JS_NewBool(JSContext *ctx, JS_BOOL val) { - (void)ctx; - return JS_MKVAL(JS_TAG_BOOL, (val != 0)); + +static bool is_valid_weakref_target(JSValue val) +{ + switch (JS_VALUE_GET_TAG(val)) { + case JS_TAG_OBJECT: + break; + case JS_TAG_SYMBOL: { + // Per spec: prohibit symbols registered with Symbol.for() + JSAtomStruct *p = JS_VALUE_GET_PTR(val); + if (p->atom_type != JS_ATOM_TYPE_GLOBAL_SYMBOL) + break; + // fallthru + } + default: + return false; + } + + return true; } -JSValue JS_NewInt32(JSContext *ctx, int32_t val) { - (void)ctx; - return JS_MKVAL(JS_TAG_INT, val); + +static void insert_weakref_record(JSValue target, struct JSWeakRefRecord *wr) +{ + JSWeakRefRecord **pwr = get_first_weak_ref(target); + /* Add the weak reference */ + wr->next_weak_ref = *pwr; + *pwr = wr; } -JSValue JS_NewCatchOffset(JSContext *ctx, int32_t val) { - (void)ctx; - return JS_MKVAL(JS_TAG_CATCH_OFFSET, val); + +/* Poly IC */ + +JSInlineCache *init_ic(JSContext *ctx) +{ + JSInlineCache *ic; + ic = js_malloc(ctx, sizeof(JSInlineCache)); + if (unlikely(!ic)) + goto fail; + ic->count = 0; + ic->hash_bits = 2; + ic->capacity = 1 << ic->hash_bits; + ic->hash = js_mallocz(ctx, sizeof(ic->hash[0]) * ic->capacity); + if (unlikely(!ic->hash)) + goto fail; + ic->cache = NULL; + return ic; +fail: + js_free(ctx, ic); + return NULL; } -JSValue JS_NewInt64(JSContext *ctx, int64_t val) { - JSValue v; - if (val == (int32_t)val) { - v = JS_NewInt32(ctx, (int32_t)val); - } else { - v = __JS_NewFloat64(ctx, (double)val); + +int rebuild_ic(JSContext *ctx, JSInlineCache *ic) +{ + uint32_t i, count; + JSInlineCacheHashSlot *ch; + if (ic->count == 0) + goto end; + count = 0; + ic->cache = js_mallocz(ctx, sizeof(JSInlineCacheRingSlot) * ic->count); + if (unlikely(!ic->cache)) + goto fail; + for (i = 0; i < ic->capacity; i++) { + for (ch = ic->hash[i]; ch != NULL; ch = ch->next) { + ch->index = count++; + ic->cache[ch->index].atom = JS_DupAtom(ctx, ch->atom); + ic->cache[ch->index].index = 0; + } } - return v; +end: + return 0; +fail: + return -1; } -JSValue JS_NewUint32(JSContext *ctx, uint32_t val) { - JSValue v; - if (val <= 0x7fffffff) { - v = JS_NewInt32(ctx, val); - } else { - v = __JS_NewFloat64(ctx, val); + +int resize_ic_hash(JSContext *ctx, JSInlineCache *ic) +{ + uint32_t new_capacity, i, h; + JSInlineCacheHashSlot *ch, *ch_next; + JSInlineCacheHashSlot **new_hash; + new_capacity = 1 << (ic->hash_bits + 1); + new_hash = js_mallocz(ctx, sizeof(ic->hash[0]) * new_capacity); + if (unlikely(!new_hash)) + goto fail; + ic->hash_bits += 1; + for (i = 0; i < ic->capacity; i++) { + for (ch = ic->hash[i]; ch != NULL; ch = ch_next) { + h = get_index_hash(ch->atom, ic->hash_bits); + ch_next = ch->next; + ch->next = new_hash[h]; + new_hash[h] = ch; + } + } + js_free(ctx, ic->hash); + ic->hash = new_hash; + ic->capacity = new_capacity; + return 0; +fail: + return -1; +} + +int free_ic(JSRuntime* rt, JSInlineCache *ic) +{ + uint32_t i; + JSInlineCacheHashSlot *ch, *ch_next; + JSShape **shape, *(*shapes)[IC_CACHE_ITEM_CAPACITY]; + if (ic->cache) { + for (i = 0; i < ic->count; i++) { + shapes = &ic->cache[i].shape; + JS_FreeAtomRT(rt, ic->cache[i].atom); + for (shape = *shapes; shape != endof(*shapes); shape++) + js_free_shape_null(rt, *shape); + } + } + for (i = 0; i < ic->capacity; i++) { + for (ch = ic->hash[i]; ch != NULL; ch = ch_next) { + ch_next = ch->next; + JS_FreeAtomRT(rt, ch->atom); + js_free_rt(rt, ch); + } + } + if (ic->count > 0) + js_free_rt(rt, ic->cache); + js_free_rt(rt, ic->hash); + js_free_rt(rt, ic); + return 0; +} + +static void add_ic_slot(JSContext *ctx, JSInlineCacheUpdate *icu, + JSAtom atom, JSObject *object, uint32_t prop_offset) +{ + int32_t i; + uint32_t h; + JSInlineCacheHashSlot *ch; + JSInlineCacheRingSlot *cr; + JSInlineCache *ic; + JSShape *sh; + + if (!icu) + return; + ic = icu->ic; + if (!ic) + return; + sh = object->shape; + if (!sh->is_hashed) + return; + cr = NULL; + h = get_index_hash(atom, ic->hash_bits); + for (ch = ic->hash[h]; ch != NULL; ch = ch->next) { + if (ch->atom == atom) { + cr = ic->cache + ch->index; + break; + } } - return v; + assert(cr != NULL); + i = cr->index; + do { + if (sh == cr->shape[i]) { + cr->prop_offset[i] = prop_offset; + goto end; + } + i = (i + 1) % countof(cr->shape); + } while (i != cr->index); + js_free_shape_null(ctx->rt, cr->shape[i]); + cr->shape[i] = js_dup_shape(sh); + cr->prop_offset[i] = prop_offset; +end: + icu->offset = ch->index; } -JSValue JS_NewFloat64(JSContext *ctx, double d) + +/* CallSite */ + +static void js_callsite_finalizer(JSRuntime *rt, JSValue val) { - int32_t val; - union { - double d; - uint64_t u; - } u, t; - if (d >= INT32_MIN && d <= INT32_MAX) { - u.d = d; - val = (int32_t)d; - t.d = val; - /* -0 cannot be represented as integer, so we compare the bit - representation */ - if (u.u == t.u) - return JS_MKVAL(JS_TAG_INT, val); + JSCallSiteData *csd = JS_GetOpaque(val, JS_CLASS_CALL_SITE); + if (csd) { + JS_FreeValueRT(rt, csd->filename); + JS_FreeValueRT(rt, csd->func); + JS_FreeValueRT(rt, csd->func_name); + js_free_rt(rt, csd); + } +} + +static void js_callsite_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) +{ + JSCallSiteData *csd = JS_GetOpaque(val, JS_CLASS_CALL_SITE); + if (csd) { + JS_MarkValue(rt, csd->filename, mark_func); + JS_MarkValue(rt, csd->func, mark_func); + JS_MarkValue(rt, csd->func_name, mark_func); } - return __JS_NewFloat64(ctx, d); } -JSValue JS_NewCFunction(JSContext *ctx, JSCFunction *func, const char *name, - int length) { - return JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_generic, 0); +static JSValue js_new_callsite(JSContext *ctx, JSCallSiteData *csd) { + JSValue obj = js_create_from_ctor(ctx, JS_UNDEFINED, JS_CLASS_CALL_SITE); + if (JS_IsException(obj)) + return JS_EXCEPTION; + + JSCallSiteData *csd1 = js_malloc(ctx, sizeof(*csd)); + if (!csd1) { + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; + } + + memcpy(csd1, csd, sizeof(*csd)); + + JS_SetOpaqueInternal(obj, csd1); + + return obj; } -JS_BOOL JS_IsRegExp(JSContext *ctx, JSValue val) +static void js_new_callsite_data(JSContext *ctx, JSCallSiteData *csd, JSStackFrame *sf) { + const char *func_name_str; JSObject *p; - if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) - return FALSE; - return JS_VALUE_GET_OBJ(val)->class_id == JS_CLASS_REGEXP; + + csd->func = js_dup(sf->cur_func); + /* func_name_str is UTF-8 encoded if needed */ + func_name_str = get_func_name(ctx, sf->cur_func); + if (!func_name_str || func_name_str[0] == '\0') + csd->func_name = JS_NULL; + else + csd->func_name = JS_NewString(ctx, func_name_str); + JS_FreeCString(ctx, func_name_str); + if (JS_IsException(csd->func_name)) + csd->func_name = JS_NULL; + + p = JS_VALUE_GET_OBJ(sf->cur_func); + if (js_class_has_bytecode(p->class_id)) { + JSFunctionBytecode *b = p->u.func.function_bytecode; + int line_num1, col_num1; + line_num1 = find_line_num(ctx, b, + sf->cur_pc - b->byte_code_buf - 1, + &col_num1); + csd->native = false; + csd->line_num = line_num1; + csd->col_num = col_num1; + csd->filename = JS_AtomToString(ctx, b->filename); + if (JS_IsException(csd->filename)) { + csd->filename = JS_NULL; + JS_FreeValue(ctx, JS_GetException(ctx)); // Clear exception. + } + } else { + csd->native = true; + csd->line_num = -1; + csd->col_num = -1; + csd->filename = JS_NULL; + } +} + +static void js_new_callsite_data2(JSContext *ctx, JSCallSiteData *csd, const char *filename, int line_num, int col_num) +{ + csd->func = JS_NULL; + csd->func_name = JS_NULL; + csd->native = false; + csd->line_num = line_num; + csd->col_num = col_num; + /* filename is UTF-8 encoded if needed (original argument to __JS_EvalInternal()) */ + csd->filename = JS_NewString(ctx, filename); + if (JS_IsException(csd->filename)) { + csd->filename = JS_NULL; + JS_FreeValue(ctx, JS_GetException(ctx)); // Clear exception. + } +} + +static JSValue js_callsite_getfield(JSContext *ctx, JSValue this_val, int argc, JSValue *argv, int magic) +{ + JSCallSiteData *csd = JS_GetOpaque2(ctx, this_val, JS_CLASS_CALL_SITE); + if (!csd) + return JS_EXCEPTION; + JSValue *field = (void *)((char *)csd + magic); + return js_dup(*field); +} + +static JSValue js_callsite_isnative(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) +{ + JSCallSiteData *csd = JS_GetOpaque2(ctx, this_val, JS_CLASS_CALL_SITE); + if (!csd) + return JS_EXCEPTION; + return JS_NewBool(ctx, csd->native); +} + +static JSValue js_callsite_getnumber(JSContext *ctx, JSValue this_val, int argc, JSValue *argv, int magic) +{ + JSCallSiteData *csd = JS_GetOpaque2(ctx, this_val, JS_CLASS_CALL_SITE); + if (!csd) + return JS_EXCEPTION; + int *field = (void *)((char *)csd + magic); + return JS_NewInt32(ctx, *field); +} + +static const JSCFunctionListEntry js_callsite_proto_funcs[] = { + JS_CFUNC_DEF("isNative", 0, js_callsite_isnative), + JS_CFUNC_MAGIC_DEF("getFileName", 0, js_callsite_getfield, offsetof(JSCallSiteData, filename)), + JS_CFUNC_MAGIC_DEF("getFunction", 0, js_callsite_getfield, offsetof(JSCallSiteData, func)), + JS_CFUNC_MAGIC_DEF("getFunctionName", 0, js_callsite_getfield, offsetof(JSCallSiteData, func_name)), + JS_CFUNC_MAGIC_DEF("getColumnNumber", 0, js_callsite_getnumber, offsetof(JSCallSiteData, col_num)), + JS_CFUNC_MAGIC_DEF("getLineNumber", 0, js_callsite_getnumber, offsetof(JSCallSiteData, line_num)), + JS_PROP_STRING_DEF("[Symbol.toStringTag]", "CallSite", JS_PROP_CONFIGURABLE ), +}; + +static const JSClassShortDef js_callsite_class_def[] = { + { JS_ATOM_CallSite, js_callsite_finalizer, js_callsite_mark }, /* JS_CLASS_CALL_SITE */ +}; + +static void _JS_AddIntrinsicCallSite(JSContext *ctx) +{ + JSRuntime *rt = ctx->rt; + + if (!JS_IsRegisteredClass(rt, JS_CLASS_CALL_SITE)) { + init_class_range(rt, js_callsite_class_def, JS_CLASS_CALL_SITE, + countof(js_callsite_class_def)); + } + ctx->class_proto[JS_CLASS_CALL_SITE] = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_CALL_SITE], + js_callsite_proto_funcs, + countof(js_callsite_proto_funcs)); +} + +bool JS_DetectModule(const char *input, size_t input_len) +{ + JSRuntime *rt; + JSContext *ctx; + JSValue val; + bool is_module; + + is_module = true; + rt = JS_NewRuntime(); + if (!rt) + return false; + ctx = JS_NewContextRaw(rt); + if (!ctx) { + JS_FreeRuntime(rt); + return false; + } + JS_AddIntrinsicRegExp(ctx); // otherwise regexp literals don't parse + val = __JS_EvalInternal(ctx, JS_UNDEFINED, input, input_len, "", 1, + JS_EVAL_TYPE_MODULE|JS_EVAL_FLAG_COMPILE_ONLY, -1); + if (JS_IsException(val)) { + const char *msg = JS_ToCString(ctx, rt->current_exception); + // gruesome hack to recognize exceptions from import statements; + // necessary because we don't pass in a module loader + is_module = !!strstr(msg, "ReferenceError: could not load module"); + JS_FreeCString(ctx, msg); + } + JS_FreeValue(ctx, val); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + return is_module; } + +void setScopeLookup(JSContext *ctx, ScopeLookup *scopeLookup) +{ + ctx->scopeLookup = scopeLookup; +} + +void setFoundUndefinedHandler(JSContext *ctx, FoundUndefinedHandler *handler) +{ + ctx->handleUndefined = handler; +} + +void setFunctionEnteredHandler(JSContext *ctx, FunctionEnteredHandler *handler) +{ + ctx->handleFunctionEntered = handler; +} + +void setFunctionExitedHandler(JSContext *ctx, FunctionExitedHandler *handler) +{ + ctx->handleFunctionExited = handler; +} + +uintptr_t js_std_cmd(int cmd, ...) { + JSContext *ctx; + JSRuntime *rt; + JSValue *pv; + uintptr_t rv; + va_list ap; + + rv = 0; + va_start(ap, cmd); + switch (cmd) { + case 0: // GetOpaque + rt = va_arg(ap, JSRuntime *); + rv = (uintptr_t)rt->libc_opaque; + break; + case 1: // SetOpaque + rt = va_arg(ap, JSRuntime *); + rt->libc_opaque = va_arg(ap, void *); + break; + case 2: // ErrorBackTrace + ctx = va_arg(ap, JSContext *); + pv = va_arg(ap, JSValue *); + *pv = ctx->error_back_trace; + ctx->error_back_trace = JS_UNDEFINED; + break; + default: + rv = -1; + } + va_end(ap); + + return rv; +} + +#undef malloc +#undef free +#undef realloc diff --git a/src/shared/quickjs/quickjs.h b/src/shared/quickjs/quickjs.h index 3a22f5b7b..864fe641c 100644 --- a/src/shared/quickjs/quickjs.h +++ b/src/shared/quickjs/quickjs.h @@ -1,8 +1,10 @@ /* * QuickJS Javascript Engine * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon + * Copyright (c) 2017-2024 Fabrice Bellard + * Copyright (c) 2017-2024 Charlie Gordon + * Copyright (c) 2023-2025 Ben Noordhuis + * Copyright (c) 2023-2025 Saúl Ibarra Corretgé * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,26 +27,41 @@ #ifndef QUICKJS_H #define QUICKJS_H +#include #include #include +#include +#include #ifdef __cplusplus extern "C" { #endif #if defined(__GNUC__) || defined(__clang__) -#define js_likely(x) __builtin_expect(!!(x), 1) -#define js_unlikely(x) __builtin_expect(!!(x), 0) #define js_force_inline inline __attribute__((always_inline)) -#define __js_printf_like(f, a) __attribute__((format(printf, f, a))) +#define JS_EXTERN __attribute__((visibility("default"))) #else -#define js_likely(x) (x) -#define js_unlikely(x) (x) #define js_force_inline inline -#define __js_printf_like(a, b) +#define JS_EXTERN /* nothing */ #endif -#define JS_BOOL int +/* Borrowed from Folly */ +#ifndef JS_PRINTF_FORMAT +#ifdef _MSC_VER +#include +#define JS_PRINTF_FORMAT _Printf_format_string_ +#define JS_PRINTF_FORMAT_ATTR(format_param, dots_param) +#else +#define JS_PRINTF_FORMAT +#if !defined(__clang__) && defined(__GNUC__) +#define JS_PRINTF_FORMAT_ATTR(format_param, dots_param) \ + __attribute__((format(gnu_printf, format_param, dots_param))) +#else +#define JS_PRINTF_FORMAT_ATTR(format_param, dots_param) \ + __attribute__((format(printf, format_param, dots_param))) +#endif +#endif +#endif typedef struct JSRuntime JSRuntime; typedef struct JSContext JSContext; @@ -53,23 +70,23 @@ typedef struct JSClass JSClass; typedef uint32_t JSClassID; typedef uint32_t JSAtom; -#if INTPTR_MAX >= INT64_MAX -#define JS_PTR64 -#define JS_PTR64_DEF(a) a -#else -#define JS_PTR64_DEF(a) -#endif +/* Unless documented otherwise, C string pointers (`char *` or `const char *`) + are assumed to verify these constraints: + - unless a length is passed separately, the string has a null terminator + - string contents is either pure ASCII or is UTF-8 encoded. + */ -#ifndef JS_PTR64 -#define JS_NAN_BOXING +/* Overridable purely for testing purposes; don't touch. */ +#ifndef JS_NAN_BOXING +#if INTPTR_MAX < INT64_MAX +#define JS_NAN_BOXING 1 /* Use NAN boxing for 32bit builds. */ +#endif #endif enum { /* all tags with a reference count are negative */ - JS_TAG_FIRST = -11, /* first negative tag */ - JS_TAG_BIG_DECIMAL = -11, - JS_TAG_BIG_INT = -10, - JS_TAG_BIG_FLOAT = -9, + JS_TAG_FIRST = -9, /* first negative tag */ + JS_TAG_BIG_INT = -9, JS_TAG_SYMBOL = -8, JS_TAG_STRING = -7, JS_TAG_MODULE = -3, /* used internally */ @@ -87,52 +104,13 @@ enum { /* any larger tag is FLOAT64 if JS_NAN_BOXING */ }; -typedef struct JSRefCountHeader { - int ref_count; -} JSRefCountHeader; - #define JS_FLOAT64_NAN NAN +#define JSValueConst JSValue /* For backwards compatibility. */ -#ifdef CONFIG_CHECK_JSVALUE -/* JSValue consistency : it is not possible to run the code in this - mode, but it is useful to detect simple reference counting - errors. It would be interesting to modify a static C analyzer to - handle specific annotations (clang has such annotations but only - for objective C) */ -typedef struct __JSValue *JSValue; -typedef const struct __JSValue *JSValueConst; - -#define JS_VALUE_GET_TAG(v) (int)((uintptr_t)(v) & 0xf) -/* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */ -#define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v) -#define JS_VALUE_GET_INT(v) (int)((intptr_t)(v) >> 4) -#define JS_VALUE_GET_BOOL(v) JS_VALUE_GET_INT(v) -#define JS_VALUE_GET_FLOAT64(v) (double)JS_VALUE_GET_INT(v) -#define JS_VALUE_GET_PTR(v) (void *)((intptr_t)(v) & ~0xf) - -#define JS_MKVAL(tag, val) (JSValue)(intptr_t)(((val) << 4) | (tag)) -#define JS_MKPTR(tag, p) (JSValue)((intptr_t)(p) | (tag)) - -#define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64) - -#define JS_NAN JS_MKVAL(JS_TAG_FLOAT64, 1) - -static inline JSValue __JS_NewFloat64(JSContext *ctx, double d) -{ - return JS_MKVAL(JS_TAG_FLOAT64, (int)d); -} - -static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) -{ - return 0; -} - -#elif defined(JS_NAN_BOXING) +#if defined(JS_NAN_BOXING) && JS_NAN_BOXING typedef uint64_t JSValue; -#define JSValueConst JSValue - #define JS_VALUE_GET_TAG(v) (int)((v) >> 32) #define JS_VALUE_GET_INT(v) (int)(v) #define JS_VALUE_GET_BOOL(v) (int)(v) @@ -156,9 +134,8 @@ static inline double JS_VALUE_GET_FLOAT64(JSValue v) #define JS_NAN (0x7ff8000000000000 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32)) -static inline JSValue __JS_NewFloat64(JSContext *ctx, double d) +static inline JSValue __JS_NewFloat64(double d) { - (void) ctx; union { double d; uint64_t u64; @@ -166,7 +143,7 @@ static inline JSValue __JS_NewFloat64(JSContext *ctx, double d) JSValue v; u.d = d; /* normalize NaN */ - if (js_unlikely((u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000)) + if ((u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000) v = JS_NAN; else v = u.u64 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32); @@ -186,7 +163,7 @@ static inline int JS_VALUE_GET_NORM_TAG(JSValue v) return tag; } -static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) +static inline bool JS_VALUE_IS_NAN(JSValue v) { uint32_t tag; tag = JS_VALUE_GET_TAG(v); @@ -206,8 +183,6 @@ typedef struct JSValue { int64_t tag; } JSValue; -#define JSValueConst JSValue - #define JS_VALUE_GET_TAG(v) ((int32_t)(v).tag) /* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */ #define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v) @@ -216,26 +191,50 @@ typedef struct JSValue { #define JS_VALUE_GET_FLOAT64(v) ((v).u.float64) #define JS_VALUE_GET_PTR(v) ((v).u.ptr) -JSValue mkVal(int32_t tag, int32_t val); -JSValue mkPtr(int32_t tag, void *p); - -#define JS_MKVAL(tag, val) mkVal(tag, val) -#define JS_MKPTR(tag, p) mkPtr(tag, p) +/* msvc doesn't understand designated initializers without /std:c++20 */ +#ifdef __cplusplus +static inline JSValue JS_MKPTR(int64_t tag, void *ptr) +{ + JSValue v; + v.u.ptr = ptr; + v.tag = tag; + return v; +} +static inline JSValue JS_MKVAL(int64_t tag, int32_t int32) +{ + JSValue v; + v.u.int32 = int32; + v.tag = tag; + return v; +} +static inline JSValue JS_MKNAN(void) +{ + JSValue v; + v.u.float64 = JS_FLOAT64_NAN; + v.tag = JS_TAG_FLOAT64; + return v; +} +/* provide as macros for consistency and backward compat reasons */ +#define JS_MKPTR(tag, ptr) JS_MKPTR(tag, ptr) +#define JS_MKVAL(tag, val) JS_MKVAL(tag, val) +#define JS_NAN JS_MKNAN() /* alas, not a constant expression */ +#else +#define JS_MKPTR(tag, p) (JSValue){ (JSValueUnion){ .ptr = p }, tag } +#define JS_MKVAL(tag, val) (JSValue){ (JSValueUnion){ .int32 = val }, tag } +#define JS_NAN (JSValue){ (JSValueUnion){ .float64 = JS_FLOAT64_NAN }, JS_TAG_FLOAT64 } +#endif #define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64) -#define JS_NAN (JSValue){ .u.float64 = JS_FLOAT64_NAN, JS_TAG_FLOAT64 } - -static inline JSValue __JS_NewFloat64(JSContext *ctx, double d) +static inline JSValue __JS_NewFloat64(double d) { - (void) ctx; JSValue v; v.tag = JS_TAG_FLOAT64; v.u.float64 = d; return v; } -static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) +static inline bool JS_VALUE_IS_NAN(JSValue v) { union { double d; @@ -253,7 +252,6 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) #define JS_VALUE_IS_BOTH_FLOAT(v1, v2) (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v1)) && JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v2))) #define JS_VALUE_GET_OBJ(v) ((JSObject *)JS_VALUE_GET_PTR(v)) -#define JS_VALUE_GET_STRING(v) ((JSString *)JS_VALUE_GET_PTR(v)) #define JS_VALUE_HAS_REF_COUNT(v) ((unsigned)JS_VALUE_GET_TAG(v) >= (unsigned)JS_TAG_FIRST) /* special values */ @@ -294,8 +292,12 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) #define JS_PROP_NO_ADD (1 << 16) /* internal use */ #define JS_PROP_NO_EXOTIC (1 << 17) /* internal use */ +#define JS_PROP_DEFINE_PROPERTY (1 << 18) /* internal use */ +#define JS_PROP_REFLECT_DEFINE_PROPERTY (1 << 19) /* internal use */ -#define JS_DEFAULT_STACK_SIZE (256 * 1024) +#ifndef JS_DEFAULT_STACK_SIZE +#define JS_DEFAULT_STACK_SIZE (1024 * 1024) +#endif /* JS_Eval() flags */ #define JS_EVAL_TYPE_GLOBAL (0 << 0) /* global code (default) */ @@ -305,7 +307,7 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) #define JS_EVAL_TYPE_MASK (3 << 0) #define JS_EVAL_FLAG_STRICT (1 << 3) /* force 'strict' mode */ -#define JS_EVAL_FLAG_STRIP (1 << 4) /* force 'strip' mode */ +#define JS_EVAL_FLAG_UNUSED (1 << 4) /* unused */ /* compile but do not run. The result is an object with a JS_TAG_FUNCTION_BYTECODE or JS_TAG_MODULE tag. It can be executed with JS_EvalFunction(). */ @@ -316,93 +318,127 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) promise. Only allowed with JS_EVAL_TYPE_GLOBAL */ #define JS_EVAL_FLAG_ASYNC (1 << 7) -typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); -typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); -typedef JSValue JSCFunctionData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data); - -typedef struct JSMallocState { - size_t malloc_count; - size_t malloc_size; - size_t malloc_limit; - void *opaque; /* user opaque */ -} JSMallocState; +typedef JSValue JSCFunction(JSContext *ctx, JSValue this_val, int argc, JSValue *argv); +typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValue this_val, int argc, JSValue *argv, int magic); +typedef JSValue JSCFunctionData(JSContext *ctx, JSValue this_val, int argc, JSValue *argv, int magic, JSValue *func_data); typedef struct JSMallocFunctions { - void *(*js_malloc)(JSMallocState *s, size_t size); - void (*js_free)(JSMallocState *s, void *ptr); - void *(*js_realloc)(JSMallocState *s, void *ptr, size_t size); + void *(*js_calloc)(void *opaque, size_t count, size_t size); + void *(*js_malloc)(void *opaque, size_t size); + void (*js_free)(void *opaque, void *ptr); + void *(*js_realloc)(void *opaque, void *ptr, size_t size); size_t (*js_malloc_usable_size)(const void *ptr); } JSMallocFunctions; +// Debug trace system: the debug output will be produced to the dump stream (currently +// stdout) if dumps are enabled and JS_SetDumpFlags is invoked with the corresponding +// bit set. +#define JS_DUMP_BYTECODE_FINAL 0x01 /* dump pass 3 final byte code */ +#define JS_DUMP_BYTECODE_PASS2 0x02 /* dump pass 2 code */ +#define JS_DUMP_BYTECODE_PASS1 0x04 /* dump pass 1 code */ +#define JS_DUMP_BYTECODE_HEX 0x10 /* dump bytecode in hex */ +#define JS_DUMP_BYTECODE_PC2LINE 0x20 /* dump line number table */ +#define JS_DUMP_BYTECODE_STACK 0x40 /* dump compute_stack_size */ +#define JS_DUMP_BYTECODE_STEP 0x80 /* dump executed bytecode */ +#define JS_DUMP_READ_OBJECT 0x100 /* dump the marshalled objects at load time */ +#define JS_DUMP_FREE 0x200 /* dump every object free */ +#define JS_DUMP_GC 0x400 /* dump the occurrence of the automatic GC */ +#define JS_DUMP_GC_FREE 0x800 /* dump objects freed by the GC */ +#define JS_DUMP_MODULE_RESOLVE 0x1000 /* dump module resolution steps */ +#define JS_DUMP_PROMISE 0x2000 /* dump promise steps */ +#define JS_DUMP_LEAKS 0x4000 /* dump leaked objects and strings in JS_FreeRuntime */ +#define JS_DUMP_ATOM_LEAKS 0x8000 /* dump leaked atoms in JS_FreeRuntime */ +#define JS_DUMP_MEM 0x10000 /* dump memory usage in JS_FreeRuntime */ +#define JS_DUMP_OBJECTS 0x20000 /* dump objects in JS_FreeRuntime */ +#define JS_DUMP_ATOMS 0x40000 /* dump atoms in JS_FreeRuntime */ +#define JS_DUMP_SHAPES 0x80000 /* dump shapes in JS_FreeRuntime */ + +// Finalizers run in LIFO order at the very end of JS_FreeRuntime. +// Intended for cleanup of associated resources; the runtime itself +// is no longer usable. +typedef void JSRuntimeFinalizer(JSRuntime *rt, void *arg); + typedef struct JSGCObjectHeader JSGCObjectHeader; -JSRuntime *JS_NewRuntime(void); +JS_EXTERN JSRuntime *JS_NewRuntime(void); /* info lifetime must exceed that of rt */ -void JS_SetRuntimeInfo(JSRuntime *rt, const char *info); -void JS_SetMemoryLimit(JSRuntime *rt, size_t limit); -void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold); +JS_EXTERN void JS_SetRuntimeInfo(JSRuntime *rt, const char *info); +/* use 0 to disable memory limit */ +JS_EXTERN void JS_SetMemoryLimit(JSRuntime *rt, size_t limit); +JS_EXTERN void JS_SetDumpFlags(JSRuntime *rt, uint64_t flags); +JS_EXTERN uint64_t JS_GetDumpFlags(JSRuntime *rt); +JS_EXTERN size_t JS_GetGCThreshold(JSRuntime *rt); +JS_EXTERN void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold); /* use 0 to disable maximum stack size check */ -void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size); +JS_EXTERN void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size); /* should be called when changing thread to update the stack top value used to check stack overflow. */ -void JS_UpdateStackTop(JSRuntime *rt); -JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque); -void JS_FreeRuntime(JSRuntime *rt); -void *JS_GetRuntimeOpaque(JSRuntime *rt); -void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque); +JS_EXTERN void JS_UpdateStackTop(JSRuntime *rt); +JS_EXTERN JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque); +JS_EXTERN void JS_FreeRuntime(JSRuntime *rt); +JS_EXTERN void *JS_GetRuntimeOpaque(JSRuntime *rt); +JS_EXTERN void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque); +JS_EXTERN int JS_AddRuntimeFinalizer(JSRuntime *rt, + JSRuntimeFinalizer *finalizer, void *arg); typedef void JS_MarkFunc(JSRuntime *rt, JSGCObjectHeader *gp); -void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); -void JS_RunGC(JSRuntime *rt); -JS_BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj); - -JSContext *JS_NewContext(JSRuntime *rt); -void JS_FreeContext(JSContext *s); -JSContext *JS_DupContext(JSContext *ctx); -void *JS_GetContextOpaque(JSContext *ctx); -void JS_SetContextOpaque(JSContext *ctx, void *opaque); -JSRuntime *JS_GetRuntime(JSContext *ctx); -void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj); -JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id); +JS_EXTERN void JS_MarkValue(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func); +JS_EXTERN void JS_RunGC(JSRuntime *rt); +JS_EXTERN bool JS_IsLiveObject(JSRuntime *rt, JSValue obj); + +JS_EXTERN JSContext *JS_NewContext(JSRuntime *rt); +JS_EXTERN void JS_FreeContext(JSContext *s); +JS_EXTERN JSContext *JS_DupContext(JSContext *ctx); +JS_EXTERN void *JS_GetContextOpaque(JSContext *ctx); +JS_EXTERN void JS_SetContextOpaque(JSContext *ctx, void *opaque); +JS_EXTERN JSRuntime *JS_GetRuntime(JSContext *ctx); +JS_EXTERN void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj); +JS_EXTERN JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id); +JS_EXTERN JSValue JS_GetFunctionProto(JSContext *ctx); /* the following functions are used to select the intrinsic object to save memory */ -JSContext *JS_NewContextRaw(JSRuntime *rt); -void JS_AddIntrinsicBaseObjects(JSContext *ctx); -void JS_AddIntrinsicDate(JSContext *ctx); -void JS_AddIntrinsicEval(JSContext *ctx); -void JS_AddIntrinsicStringNormalize(JSContext *ctx); -void JS_AddIntrinsicRegExpCompiler(JSContext *ctx); -void JS_AddIntrinsicRegExp(JSContext *ctx); -void JS_AddIntrinsicJSON(JSContext *ctx); -void JS_AddIntrinsicProxy(JSContext *ctx); -void JS_AddIntrinsicMapSet(JSContext *ctx); -void JS_AddIntrinsicTypedArrays(JSContext *ctx); -void JS_AddIntrinsicPromise(JSContext *ctx); -void JS_AddIntrinsicBigInt(JSContext *ctx); -void JS_AddIntrinsicBigFloat(JSContext *ctx); -void JS_AddIntrinsicBigDecimal(JSContext *ctx); -/* enable operator overloading */ -void JS_AddIntrinsicOperators(JSContext *ctx); -/* enable "use math" */ -void JS_EnableBignumExt(JSContext *ctx, JS_BOOL enable); - -JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv); - -void *js_malloc_rt(JSRuntime *rt, size_t size); -void js_free_rt(JSRuntime *rt, void *ptr); -void *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size); -size_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr); -void *js_mallocz_rt(JSRuntime *rt, size_t size); - -void *js_malloc(JSContext *ctx, size_t size); -void js_free(JSContext *ctx, void *ptr); -void *js_realloc(JSContext *ctx, void *ptr, size_t size); -size_t js_malloc_usable_size(JSContext *ctx, const void *ptr); -void *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack); -void *js_mallocz(JSContext *ctx, size_t size); -char *js_strdup(JSContext *ctx, const char *str); -char *js_strndup(JSContext *ctx, const char *s, size_t n); +JS_EXTERN JSContext *JS_NewContextRaw(JSRuntime *rt); +JS_EXTERN void JS_AddIntrinsicBaseObjects(JSContext *ctx); +JS_EXTERN void JS_AddIntrinsicDate(JSContext *ctx); +JS_EXTERN void JS_AddIntrinsicEval(JSContext *ctx); +JS_EXTERN void JS_AddIntrinsicRegExpCompiler(JSContext *ctx); +JS_EXTERN void JS_AddIntrinsicRegExp(JSContext *ctx); +JS_EXTERN void JS_AddIntrinsicJSON(JSContext *ctx); +JS_EXTERN void JS_AddIntrinsicProxy(JSContext *ctx); +JS_EXTERN void JS_AddIntrinsicMapSet(JSContext *ctx); +JS_EXTERN void JS_AddIntrinsicTypedArrays(JSContext *ctx); +JS_EXTERN void JS_AddIntrinsicPromise(JSContext *ctx); +JS_EXTERN void JS_AddIntrinsicBigInt(JSContext *ctx); +JS_EXTERN void JS_AddIntrinsicWeakRef(JSContext *ctx); +JS_EXTERN void JS_AddPerformance(JSContext *ctx); + +/* for equality comparisons and sameness */ +JS_EXTERN int JS_IsEqual(JSContext *ctx, JSValue op1, JSValue op2); +JS_EXTERN bool JS_IsStrictEqual(JSContext *ctx, JSValue op1, JSValue op2); +JS_EXTERN bool JS_IsSameValue(JSContext *ctx, JSValue op1, JSValue op2); +/* Similar to same-value equality, but +0 and -0 are considered equal. */ +JS_EXTERN bool JS_IsSameValueZero(JSContext *ctx, JSValue op1, JSValue op2); + +/* Only used for running 262 tests. TODO(saghul) add build time flag. */ +JS_EXTERN JSValue js_string_codePointRange(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv); + +JS_EXTERN void *js_calloc_rt(JSRuntime *rt, size_t count, size_t size); +JS_EXTERN void *js_malloc_rt(JSRuntime *rt, size_t size); +JS_EXTERN void js_free_rt(JSRuntime *rt, void *ptr); +JS_EXTERN void *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size); +JS_EXTERN size_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr); +JS_EXTERN void *js_mallocz_rt(JSRuntime *rt, size_t size); + +JS_EXTERN void *js_calloc(JSContext *ctx, size_t count, size_t size); +JS_EXTERN void *js_malloc(JSContext *ctx, size_t size); +JS_EXTERN void js_free(JSContext *ctx, void *ptr); +JS_EXTERN void *js_realloc(JSContext *ctx, void *ptr, size_t size); +JS_EXTERN size_t js_malloc_usable_size(JSContext *ctx, const void *ptr); +JS_EXTERN void *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack); +JS_EXTERN void *js_mallocz(JSContext *ctx, size_t size); +JS_EXTERN char *js_strdup(JSContext *ctx, const char *str); +JS_EXTERN char *js_strndup(JSContext *ctx, const char *s, size_t n); typedef struct JSMemoryUsage { int64_t malloc_size, malloc_limit, memory_used_size; @@ -420,27 +456,27 @@ typedef struct JSMemoryUsage { int64_t binary_object_count, binary_object_size; } JSMemoryUsage; -void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s); -void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt); +JS_EXTERN void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s); +JS_EXTERN void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt); /* atom support */ #define JS_ATOM_NULL 0 -JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len); -JSAtom JS_NewAtom(JSContext *ctx, const char *str); -JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n); -JSAtom JS_DupAtom(JSContext *ctx, JSAtom v); -void JS_FreeAtom(JSContext *ctx, JSAtom v); -void JS_FreeAtomRT(JSRuntime *rt, JSAtom v); -JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom); -JSValue JS_AtomToString(JSContext *ctx, JSAtom atom); -const char *JS_AtomToCString(JSContext *ctx, JSAtom atom); -JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val); +JS_EXTERN JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len); +JS_EXTERN JSAtom JS_NewAtom(JSContext *ctx, const char *str); +JS_EXTERN JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n); +JS_EXTERN JSAtom JS_DupAtom(JSContext *ctx, JSAtom v); +JS_EXTERN void JS_FreeAtom(JSContext *ctx, JSAtom v); +JS_EXTERN void JS_FreeAtomRT(JSRuntime *rt, JSAtom v); +JS_EXTERN JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom); +JS_EXTERN JSValue JS_AtomToString(JSContext *ctx, JSAtom atom); +JS_EXTERN const char *JS_AtomToCString(JSContext *ctx, JSAtom atom); +JS_EXTERN JSAtom JS_ValueToAtom(JSContext *ctx, JSValue val); /* object class support */ typedef struct JSPropertyEnum { - JS_BOOL is_enumerable; + bool is_enumerable; JSAtom atom; } JSPropertyEnum; @@ -453,44 +489,44 @@ typedef struct JSPropertyDescriptor { typedef struct JSClassExoticMethods { /* Return -1 if exception (can only happen in case of Proxy object), - FALSE if the property does not exists, TRUE if it exists. If 1 is + false if the property does not exists, true if it exists. If 1 is returned, the property descriptor 'desc' is filled if != NULL. */ int (*get_own_property)(JSContext *ctx, JSPropertyDescriptor *desc, - JSValueConst obj, JSAtom prop); + JSValue obj, JSAtom prop); /* '*ptab' should hold the '*plen' property keys. Return 0 if OK, -1 if exception. The 'is_enumerable' field is ignored. */ int (*get_own_property_names)(JSContext *ctx, JSPropertyEnum **ptab, uint32_t *plen, - JSValueConst obj); - /* return < 0 if exception, or TRUE/FALSE */ - int (*delete_property)(JSContext *ctx, JSValueConst obj, JSAtom prop); - /* return < 0 if exception or TRUE/FALSE */ - int (*define_own_property)(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValueConst val, - JSValueConst getter, JSValueConst setter, + JSValue obj); + /* return < 0 if exception, or true/false */ + int (*delete_property)(JSContext *ctx, JSValue obj, JSAtom prop); + /* return < 0 if exception or true/false */ + int (*define_own_property)(JSContext *ctx, JSValue this_obj, + JSAtom prop, JSValue val, + JSValue getter, JSValue setter, int flags); /* The following methods can be emulated with the previous ones, so they are usually not needed */ - /* return < 0 if exception or TRUE/FALSE */ - int (*has_property)(JSContext *ctx, JSValueConst obj, JSAtom atom); - JSValue (*get_property)(JSContext *ctx, JSValueConst obj, JSAtom atom, - JSValueConst receiver); - /* return < 0 if exception or TRUE/FALSE */ - int (*set_property)(JSContext *ctx, JSValueConst obj, JSAtom atom, - JSValueConst value, JSValueConst receiver, int flags); + /* return < 0 if exception or true/false */ + int (*has_property)(JSContext *ctx, JSValue obj, JSAtom atom); + JSValue (*get_property)(JSContext *ctx, JSValue obj, JSAtom atom, + JSValue receiver); + /* return < 0 if exception or true/false */ + int (*set_property)(JSContext *ctx, JSValue obj, JSAtom atom, + JSValue value, JSValue receiver, int flags); } JSClassExoticMethods; typedef void JSClassFinalizer(JSRuntime *rt, JSValue val); -typedef void JSClassGCMark(JSRuntime *rt, JSValueConst val, +typedef void JSClassGCMark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func); #define JS_CALL_FLAG_CONSTRUCTOR (1 << 0) -typedef JSValue JSClassCall(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_val, int argc, JSValueConst *argv, +typedef JSValue JSClassCall(JSContext *ctx, JSValue func_obj, + JSValue this_val, int argc, JSValue *argv, int flags); typedef struct JSClassDef { - const char *class_name; + const char *class_name; /* pure ASCII only! */ JSClassFinalizer *finalizer; JSClassGCMark *gc_mark; /* if call != NULL, the object is a function. If (flags & @@ -504,224 +540,237 @@ typedef struct JSClassDef { JSClassExoticMethods *exotic; } JSClassDef; +#define JS_EVAL_OPTIONS_VERSION 1 + +typedef struct JSEvalOptions { + int version; + int eval_flags; + const char *filename; + int line_num; + // can add new fields in ABI-compatible manner by incrementing JS_EVAL2_VERSION +} JSEvalOptions; + #define JS_INVALID_CLASS_ID 0 -JSClassID JS_NewClassID(JSClassID *pclass_id); +JS_EXTERN JSClassID JS_NewClassID(JSRuntime *rt, JSClassID *pclass_id); /* Returns the class ID if `v` is an object, otherwise returns JS_INVALID_CLASS_ID. */ -JSClassID JS_GetClassID(JSValue v); -int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def); -int JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id); +JS_EXTERN JSClassID JS_GetClassID(JSValue v); +JS_EXTERN int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def); +JS_EXTERN bool JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id); /* value handling */ -JSValue JS_NewBool(JSContext *ctx, JS_BOOL val); -JSValue JS_NewInt32(JSContext *ctx, int32_t val); -JSValue JS_NewCatchOffset(JSContext *ctx, int32_t val); -JSValue JS_NewInt64(JSContext *ctx, int64_t val); -JSValue JS_NewUint32(JSContext *ctx, uint32_t val); -JSValue JS_NewBigInt64(JSContext *ctx, int64_t v); -JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v); +static js_force_inline JSValue JS_NewBool(JSContext *ctx, bool val) +{ + (void)&ctx; + return JS_MKVAL(JS_TAG_BOOL, (val != 0)); +} -JSValue JS_NewFloat64(JSContext *ctx, double d); +static js_force_inline JSValue JS_NewInt32(JSContext *ctx, int32_t val) +{ + (void)&ctx; + return JS_MKVAL(JS_TAG_INT, val); +} -static inline JS_BOOL JS_IsNumber(JSValueConst v) +static js_force_inline JSValue JS_NewFloat64(JSContext *ctx, double val) { - int tag = JS_VALUE_GET_TAG(v); - return tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag); + (void)&ctx; + return __JS_NewFloat64(val); } -static inline JS_BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v) +static js_force_inline JSValue JS_NewCatchOffset(JSContext *ctx, int32_t val) { - (void) ctx; - int tag = JS_VALUE_GET_TAG(v); - return tag == JS_TAG_BIG_INT; + (void)&ctx; + return JS_MKVAL(JS_TAG_CATCH_OFFSET, val); } -static inline JS_BOOL JS_IsBigFloat(JSValueConst v) +static js_force_inline JSValue JS_NewInt64(JSContext *ctx, int64_t val) { - int tag = JS_VALUE_GET_TAG(v); - return tag == JS_TAG_BIG_FLOAT; + JSValue v; + if (val >= INT32_MIN && val <= INT32_MAX) { + v = JS_NewInt32(ctx, (int32_t)val); + } else { + v = JS_NewFloat64(ctx, (double)val); + } + return v; +} + +static js_force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val) +{ + JSValue v; + if (val <= INT32_MAX) { + v = JS_NewInt32(ctx, (int32_t)val); + } else { + v = JS_NewFloat64(ctx, (double)val); + } + return v; } -static inline JS_BOOL JS_IsBigDecimal(JSValueConst v) +JS_EXTERN JSValue JS_NewNumber(JSContext *ctx, double d); +JS_EXTERN JSValue JS_NewBigInt64(JSContext *ctx, int64_t v); +JS_EXTERN JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v); + +static inline bool JS_IsNumber(JSValue v) { int tag = JS_VALUE_GET_TAG(v); - return tag == JS_TAG_BIG_DECIMAL; + return tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag); } -static inline JS_BOOL JS_IsBool(JSValueConst v) +static inline bool JS_IsBigInt(JSContext *ctx, JSValue v) +{ + (void)&ctx; + return JS_VALUE_GET_TAG(v) == JS_TAG_BIG_INT; +} + +static inline bool JS_IsBool(JSValue v) { return JS_VALUE_GET_TAG(v) == JS_TAG_BOOL; } -static inline JS_BOOL JS_IsNull(JSValueConst v) +static inline bool JS_IsNull(JSValue v) { return JS_VALUE_GET_TAG(v) == JS_TAG_NULL; } -static inline JS_BOOL JS_IsUndefined(JSValueConst v) +static inline bool JS_IsUndefined(JSValue v) { return JS_VALUE_GET_TAG(v) == JS_TAG_UNDEFINED; } -static inline JS_BOOL JS_IsException(JSValueConst v) +static inline bool JS_IsException(JSValue v) { - return js_unlikely(JS_VALUE_GET_TAG(v) == JS_TAG_EXCEPTION); + return JS_VALUE_GET_TAG(v) == JS_TAG_EXCEPTION; } -static inline JS_BOOL JS_IsUninitialized(JSValueConst v) +static inline bool JS_IsUninitialized(JSValue v) { - return js_unlikely(JS_VALUE_GET_TAG(v) == JS_TAG_UNINITIALIZED); + return JS_VALUE_GET_TAG(v) == JS_TAG_UNINITIALIZED; } -static inline JS_BOOL JS_IsString(JSValueConst v) +static inline bool JS_IsString(JSValue v) { return JS_VALUE_GET_TAG(v) == JS_TAG_STRING; } -static inline JS_BOOL JS_IsSymbol(JSValueConst v) +static inline bool JS_IsSymbol(JSValue v) { return JS_VALUE_GET_TAG(v) == JS_TAG_SYMBOL; } -static inline JS_BOOL JS_IsObject(JSValueConst v) +static inline bool JS_IsObject(JSValue v) { return JS_VALUE_GET_TAG(v) == JS_TAG_OBJECT; } -JSValue JS_Throw(JSContext *ctx, JSValue obj); -JSValue JS_GetException(JSContext *ctx); -JS_BOOL JS_HasException(JSContext *ctx); -JS_BOOL JS_IsError(JSContext *ctx, JSValueConst val); -void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, JS_BOOL flag); -void JS_ResetUncatchableError(JSContext *ctx); -JSValue JS_NewError(JSContext *ctx); -JSValue __js_printf_like(2, 3) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...); -JSValue __js_printf_like(2, 3) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...); -JSValue __js_printf_like(2, 3) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...); -JSValue __js_printf_like(2, 3) JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...); -JSValue __js_printf_like(2, 3) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...); -JSValue JS_ThrowOutOfMemory(JSContext *ctx); - -#ifndef NDEBUG -void notifyRefCountIncrease(JSRefCountHeader *p); -void notifyRefCountDecrease(JSRefCountHeader *p); -#endif - -void JS_FreeValue(JSContext *ctx, JSValue v); -void JS_FreeValueRT(JSRuntime *rt, JSValue v); - -static inline JSValue JS_DupValue(JSContext *ctx, JSValueConst v) -{ - (void) ctx; - if (JS_VALUE_HAS_REF_COUNT(v)) { - JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); -#ifndef NDEBUG - notifyRefCountIncrease(p); -#endif - p->ref_count++; - } - return v; -} - -static inline JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v) +JS_EXTERN JSValue JS_Throw(JSContext *ctx, JSValue obj); +JS_EXTERN JSValue JS_GetException(JSContext *ctx); +JS_EXTERN bool JS_HasException(JSContext *ctx); +JS_EXTERN JSValue JS_GetBacktrace(JSContext *ctx); +JS_EXTERN bool JS_IsError(JSContext *ctx, JSValue val); +JS_EXTERN bool JS_IsUncatchableError(JSContext* ctx, JSValue val); +JS_EXTERN void JS_SetUncatchableError(JSContext *ctx, JSValue val); +JS_EXTERN void JS_ClearUncatchableError(JSContext *ctx, JSValue val); +// Shorthand for: +// JSValue exc = JS_GetException(ctx); +// JS_ClearUncatchableError(ctx, exc); +// JS_Throw(ctx, exc); +JS_EXTERN void JS_ResetUncatchableError(JSContext *ctx); +JS_EXTERN JSValue JS_NewError(JSContext *ctx); +JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowPlainError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...); +JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowSyntaxError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...); +JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowTypeError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...); +JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowReferenceError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...); +JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowRangeError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...); +JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowInternalError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...); +JS_EXTERN JSValue JS_ThrowOutOfMemory(JSContext *ctx); +JS_EXTERN void JS_FreeValue(JSContext *ctx, JSValue v); +JS_EXTERN void JS_FreeValueRT(JSRuntime *rt, JSValue v); +JS_EXTERN JSValue JS_DupValue(JSContext *ctx, JSValue v); +JS_EXTERN JSValue JS_DupValueRT(JSRuntime *rt, JSValue v); +JS_EXTERN int JS_ToBool(JSContext *ctx, JSValue val); /* return -1 for JS_EXCEPTION */ +static inline JSValue JS_ToBoolean(JSContext *ctx, JSValue val) { - (void) rt; - if (JS_VALUE_HAS_REF_COUNT(v)) { - JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); -#ifndef NDEBUG - notifyRefCountIncrease(p); -#endif - p->ref_count++; - } - return v; + return JS_NewBool(ctx, JS_ToBool(ctx, val)); } - -JS_BOOL JS_StrictEq(JSContext *ctx, JSValueConst op1, JSValueConst op2); -JS_BOOL JS_SameValue(JSContext *ctx, JSValueConst op1, JSValueConst op2); -JS_BOOL JS_SameValueZero(JSContext *ctx, JSValueConst op1, JSValueConst op2); - -int JS_ToBool(JSContext *ctx, JSValueConst val); /* return -1 for JS_EXCEPTION */ -int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val); -static inline int JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValueConst val) +JS_EXTERN JSValue JS_ToNumber(JSContext *ctx, JSValue val); +JS_EXTERN int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValue val); +static inline int JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValue val) { return JS_ToInt32(ctx, (int32_t*)pres, val); } -int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val); -int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val); -int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val); +JS_EXTERN int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValue val); +JS_EXTERN int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValue val); +JS_EXTERN int JS_ToFloat64(JSContext *ctx, double *pres, JSValue val); /* return an exception if 'val' is a Number */ -int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val); +JS_EXTERN int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValue val); +JS_EXTERN int JS_ToBigUint64(JSContext *ctx, uint64_t *pres, JSValue val); /* same as JS_ToInt64() but allow BigInt */ -int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val); - -JSValue JS_NewStringLen(JSContext *ctx, const char *str1, size_t len1); -JSValue JS_NewString(JSContext *ctx, const char *str); -JSValue JS_NewAtomString(JSContext *ctx, const char *str); -JSValue JS_ToString(JSContext *ctx, JSValueConst val); -JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val); -const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, JS_BOOL cesu8); -static inline const char *JS_ToCStringLen(JSContext *ctx, size_t *plen, JSValueConst val1) +JS_EXTERN int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValue val); + +JS_EXTERN JSValue JS_NewStringLen(JSContext *ctx, const char *str1, size_t len1); +static inline JSValue JS_NewString(JSContext *ctx, const char *str) { + return JS_NewStringLen(ctx, str, strlen(str)); +} +JS_EXTERN JSValue JS_NewAtomString(JSContext *ctx, const char *str); +JS_EXTERN JSValue JS_ToString(JSContext *ctx, JSValue val); +JS_EXTERN JSValue JS_ToPropertyKey(JSContext *ctx, JSValue val); +JS_EXTERN const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValue val1, bool cesu8); +static inline const char *JS_ToCStringLen(JSContext *ctx, size_t *plen, JSValue val1) { return JS_ToCStringLen2(ctx, plen, val1, 0); } -static inline const char *JS_ToCString(JSContext *ctx, JSValueConst val1) +static inline const char *JS_ToCString(JSContext *ctx, JSValue val1) { return JS_ToCStringLen2(ctx, NULL, val1, 0); } -void JS_FreeCString(JSContext *ctx, const char *ptr); - -JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto, JSClassID class_id); -JSValue JS_NewObjectClass(JSContext *ctx, int class_id); -JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto); -JSValue JS_NewObject(JSContext *ctx); - -JS_BOOL JS_IsFunction(JSContext* ctx, JSValueConst val); -JS_BOOL JS_IsRegExp(JSContext* ctx, JSValueConst val); -JS_BOOL JS_IsConstructor(JSContext* ctx, JSValueConst val); -JS_BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, JS_BOOL val); -JS_BOOL JS_IsArrayBuffer(JSValueConst v); - -JSValue JS_NewArray(JSContext *ctx); -int JS_IsArray(JSContext *ctx, JSValueConst val); - -JSValue JS_NewDate(JSContext *ctx, double epoch_ms); -JS_BOOL JS_IsDate(JSValueConst v); - -JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, - JSAtom prop, JSValueConst receiver, - JS_BOOL throw_ref_error); -static js_force_inline JSValue JS_GetProperty(JSContext *ctx, JSValueConst this_obj, - JSAtom prop) -{ - return JS_GetPropertyInternal(ctx, this_obj, prop, this_obj, 0); -} -JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj, - const char *prop); -JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj, - uint32_t idx); - -int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj, - JSAtom prop, JSValue val, JSValueConst this_obj, - int flags); -static inline int JS_SetProperty(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValue val) -{ - return JS_SetPropertyInternal(ctx, this_obj, prop, val, this_obj, JS_PROP_THROW); -} -int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj, - uint32_t idx, JSValue val); -int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj, - int64_t idx, JSValue val); -int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj, - const char *prop, JSValue val); -int JS_HasProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop); -int JS_IsExtensible(JSContext *ctx, JSValueConst obj); -int JS_PreventExtensions(JSContext *ctx, JSValueConst obj); -int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags); -int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val); -JSValue JS_GetPrototype(JSContext *ctx, JSValueConst val); - -JSValue JS_ObjectSeal(JSContext *ctx, JSValueConst obj, int freeze); +JS_EXTERN void JS_FreeCString(JSContext *ctx, const char *ptr); + +JS_EXTERN JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValue proto, JSClassID class_id); +JS_EXTERN JSValue JS_NewObjectClass(JSContext *ctx, int class_id); +JS_EXTERN JSValue JS_NewObjectProto(JSContext *ctx, JSValue proto); +JS_EXTERN JSValue JS_NewObject(JSContext *ctx); +JS_EXTERN JSValue JS_ToObject(JSContext *ctx, JSValue val); +JS_EXTERN JSValue JS_ToObjectString(JSContext *ctx, JSValue val); + +JS_EXTERN bool JS_IsFunction(JSContext* ctx, JSValue val); +JS_EXTERN bool JS_IsConstructor(JSContext* ctx, JSValue val); +JS_EXTERN bool JS_SetConstructorBit(JSContext *ctx, JSValue func_obj, bool val); + +JS_EXTERN bool JS_IsRegExp(JSValue val); +JS_EXTERN bool JS_IsMap(JSValue val); +JS_EXTERN int JS_IsSimpleValue(JSContext* ctx, JSValue v); + +JS_EXTERN JSValue JS_NewArray(JSContext *ctx); +JS_EXTERN int JS_IsArray(JSContext *ctx, JSValue val); + +JS_EXTERN JSValue JS_NewDate(JSContext *ctx, double epoch_ms); +JS_EXTERN bool JS_IsDate(JSValue v); + +JS_EXTERN JSValue JS_GetProperty(JSContext *ctx, JSValue this_obj, JSAtom prop); +JS_EXTERN JSValue JS_GetPropertyUint32(JSContext *ctx, JSValue this_obj, + uint32_t idx); +JS_EXTERN JSValue JS_GetPropertyInt64(JSContext *ctx, JSValue this_obj, + int64_t idx); +JS_EXTERN JSValue JS_GetPropertyStr(JSContext *ctx, JSValue this_obj, + const char *prop); + +JS_EXTERN int JS_SetProperty(JSContext *ctx, JSValue this_obj, + JSAtom prop, JSValue val); +JS_EXTERN int JS_SetPropertyUint32(JSContext *ctx, JSValue this_obj, + uint32_t idx, JSValue val); +JS_EXTERN int JS_SetPropertyInt64(JSContext *ctx, JSValue this_obj, + int64_t idx, JSValue val); +JS_EXTERN int JS_SetPropertyStr(JSContext *ctx, JSValue this_obj, + const char *prop, JSValue val); +JS_EXTERN int JS_HasProperty(JSContext *ctx, JSValue this_obj, JSAtom prop); +JS_EXTERN int JS_IsExtensible(JSContext *ctx, JSValue obj); +JS_EXTERN int JS_PreventExtensions(JSContext *ctx, JSValue obj); +JS_EXTERN int JS_DeleteProperty(JSContext *ctx, JSValue obj, JSAtom prop, int flags); +JS_EXTERN int JS_SetPrototype(JSContext *ctx, JSValue obj, JSValue proto_val); +JS_EXTERN JSValue JS_GetPrototype(JSContext *ctx, JSValue val); +JS_EXTERN int JS_GetLength(JSContext *ctx, JSValue obj, int64_t *pres); +JS_EXTERN int JS_SetLength(JSContext *ctx, JSValue obj, int64_t len); +JS_EXTERN int JS_SealObject(JSContext *ctx, JSValue obj); +JS_EXTERN int JS_FreezeObject(JSContext *ctx, JSValue obj); #define JS_GPN_STRING_MASK (1 << 0) #define JS_GPN_SYMBOL_MASK (1 << 1) @@ -731,62 +780,75 @@ JSValue JS_ObjectSeal(JSContext *ctx, JSValueConst obj, int freeze); /* set theJSPropertyEnum.is_enumerable field */ #define JS_GPN_SET_ENUM (1 << 5) -int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, - uint32_t *plen, JSValueConst obj, int flags); -int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc, - JSValueConst obj, JSAtom prop); - -JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, - int argc, JSValueConst *argv); -JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom, - int argc, JSValueConst *argv); -JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj, - int argc, JSValueConst *argv); -JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj, - JSValueConst new_target, - int argc, JSValueConst *argv); -JS_BOOL JS_DetectModule(const char *input, size_t input_len); +JS_EXTERN int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, + uint32_t *plen, JSValue obj, int flags); +JS_EXTERN int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc, + JSValue obj, JSAtom prop); +JS_EXTERN void JS_FreePropertyEnum(JSContext *ctx, JSPropertyEnum *tab, + uint32_t len); + +JS_EXTERN JSValue JS_Call(JSContext *ctx, JSValue func_obj, JSValue this_obj, + int argc, JSValue *argv); +JS_EXTERN JSValue JS_Invoke(JSContext *ctx, JSValue this_val, JSAtom atom, + int argc, JSValue *argv); +JS_EXTERN JSValue JS_CallConstructor(JSContext *ctx, JSValue func_obj, + int argc, JSValue *argv); +JS_EXTERN JSValue JS_CallConstructor2(JSContext *ctx, JSValue func_obj, + JSValue new_target, + int argc, JSValue *argv); +/* Try to detect if the input is a module. Returns true if parsing the input + * as a module produces no syntax errors. It's a naive approach that is not + * wholly infallible: non-strict classic scripts may _parse_ okay as a module + * but not _execute_ as one (different runtime semantics.) Use with caution. + * |input| can be either ASCII or UTF-8 encoded source code. + */ +JS_EXTERN 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); -/* 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 line, 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, - JSAtom prop, JSValueConst val, - JSValueConst getter, JSValueConst setter, int flags); -int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValue val, int flags); -int JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj, - uint32_t idx, JSValue val, int flags); -int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj, - const char *prop, JSValue val, int flags); -int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValue getter, JSValue setter, - int flags); -void JS_SetOpaque(JSValue obj, void *opaque); -void *JS_GetOpaque(JSValueConst obj, JSClassID class_id); -void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id); +JS_EXTERN JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len, + const char *filename, int eval_flags); +JS_EXTERN JSValue JS_Eval2(JSContext *ctx, const char *input, size_t input_len, + JSEvalOptions *options); +JS_EXTERN JSValue JS_EvalThis(JSContext *ctx, JSValue this_obj, + const char *input, size_t input_len, + const char *filename, int eval_flags); +JS_EXTERN JSValue JS_EvalThis2(JSContext *ctx, JSValue this_obj, + const char *input, size_t input_len, + JSEvalOptions *options); +JS_EXTERN JSValue JS_GetGlobalObject(JSContext *ctx); +JS_EXTERN int JS_IsInstanceOf(JSContext *ctx, JSValue val, JSValue obj); +JS_EXTERN int JS_DefineProperty(JSContext *ctx, JSValue this_obj, + JSAtom prop, JSValue val, + JSValue getter, JSValue setter, int flags); +JS_EXTERN int JS_DefinePropertyValue(JSContext *ctx, JSValue this_obj, + JSAtom prop, JSValue val, int flags); +JS_EXTERN int JS_DefinePropertyValueUint32(JSContext *ctx, JSValue this_obj, + uint32_t idx, JSValue val, int flags); +JS_EXTERN int JS_DefinePropertyValueStr(JSContext *ctx, JSValue this_obj, + const char *prop, JSValue val, int flags); +JS_EXTERN int JS_DefinePropertyGetSet(JSContext *ctx, JSValue this_obj, + JSAtom prop, JSValue getter, JSValue setter, + int flags); +/* Only supported for custom classes, returns 0 on success < 0 otherwise. */ +JS_EXTERN int JS_SetOpaque(JSValue obj, void *opaque); +JS_EXTERN void *JS_GetOpaque(JSValue obj, JSClassID class_id); +JS_EXTERN void *JS_GetOpaque2(JSContext *ctx, JSValue obj, JSClassID class_id); +JS_EXTERN void *JS_GetAnyOpaque(JSValue obj, JSClassID *class_id); /* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */ -JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, - const char *filename); -#define JS_PARSE_JSON_EXT (1 << 0) /* allow extended JSON */ -JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len, - const char *filename, int flags); -JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj, - JSValueConst replacer, JSValueConst space0); +JS_EXTERN JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, + const char *filename); +JS_EXTERN JSValue JS_JSONStringify(JSContext *ctx, JSValue obj, + JSValue replacer, JSValue space0); typedef void JSFreeArrayBufferDataFunc(JSRuntime *rt, void *opaque, void *ptr); -JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len, - JSFreeArrayBufferDataFunc *free_func, void *opaque, - JS_BOOL is_shared); -JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len); -void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj); -uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj); +JS_EXTERN JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len, + JSFreeArrayBufferDataFunc *free_func, void *opaque, + bool is_shared); +JS_EXTERN JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len); +JS_EXTERN void JS_DetachArrayBuffer(JSContext *ctx, JSValue obj); +JS_EXTERN uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValue obj); +JS_EXTERN bool JS_IsArrayBuffer(JSValue obj); +JS_EXTERN uint8_t *JS_GetUint8Array(JSContext *ctx, size_t *psize, JSValue obj); typedef enum JSTypedArrayEnum { JS_TYPED_ARRAY_UINT8C = 0, @@ -798,24 +860,30 @@ typedef enum JSTypedArrayEnum { JS_TYPED_ARRAY_UINT32, JS_TYPED_ARRAY_BIG_INT64, JS_TYPED_ARRAY_BIG_UINT64, + JS_TYPED_ARRAY_FLOAT16, JS_TYPED_ARRAY_FLOAT32, JS_TYPED_ARRAY_FLOAT64, } JSTypedArrayEnum; -JSValue JS_NewTypedArray(JSContext *ctx, int argc, JSValueConst *argv, +JS_EXTERN JSValue JS_NewTypedArray(JSContext *ctx, int argc, JSValue *argv, JSTypedArrayEnum array_type); -JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj, - size_t *pbyte_offset, - size_t *pbyte_length, - size_t *pbytes_per_element); +JS_EXTERN JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValue obj, + size_t *pbyte_offset, + size_t *pbyte_length, + size_t *pbytes_per_element); +JS_EXTERN JSValue JS_NewUint8Array(JSContext *ctx, uint8_t *buf, size_t len, + JSFreeArrayBufferDataFunc *free_func, void *opaque, + bool is_shared); +/* returns -1 if not a typed array otherwise return a JSTypedArrayEnum value */ +JS_EXTERN int JS_GetTypedArrayType(JSValue obj); +JS_EXTERN JSValue JS_NewUint8ArrayCopy(JSContext *ctx, const uint8_t *buf, size_t len); typedef struct { void *(*sab_alloc)(void *opaque, size_t size); void (*sab_free)(void *opaque, void *ptr); void (*sab_dup)(void *opaque, void *ptr); void *sab_opaque; } JSSharedArrayBufferFunctions; -void JS_SetSharedArrayBufferFunctions(JSRuntime *rt, - const JSSharedArrayBufferFunctions *sf); +JS_EXTERN void JS_SetSharedArrayBufferFunctions(JSRuntime *rt, const JSSharedArrayBufferFunctions *sf); typedef enum JSPromiseStateEnum { JS_PROMISE_PENDING, @@ -823,23 +891,26 @@ typedef enum JSPromiseStateEnum { JS_PROMISE_REJECTED, } JSPromiseStateEnum; -JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs); -JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise); -JSValue JS_PromiseResult(JSContext *ctx, JSValue promise); +JS_EXTERN JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs); +JS_EXTERN JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise); +JS_EXTERN JSValue JS_PromiseResult(JSContext *ctx, JSValue promise); +JS_EXTERN bool JS_IsPromise(JSValue val); + +JS_EXTERN JSValue JS_NewSymbol(JSContext *ctx, const char *description, bool is_global); -/* is_handled = TRUE means that the rejection is handled */ -typedef void JSHostPromiseRejectionTracker(JSContext *ctx, JSValueConst promise, - JSValueConst reason, - JS_BOOL is_handled, void *opaque); -void JS_SetHostPromiseRejectionTracker(JSRuntime *rt, JSHostPromiseRejectionTracker *cb, void *opaque); +/* is_handled = true means that the rejection is handled */ +typedef void JSHostPromiseRejectionTracker(JSContext *ctx, JSValue promise, + JSValue reason, + bool is_handled, void *opaque); +JS_EXTERN void JS_SetHostPromiseRejectionTracker(JSRuntime *rt, JSHostPromiseRejectionTracker *cb, void *opaque); /* return != 0 if the JS code needs to be interrupted */ typedef int JSInterruptHandler(JSRuntime *rt, void *opaque); -void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque); -/* if can_block is TRUE, Atomics.wait() can be used */ -void JS_SetCanBlock(JSRuntime *rt, JS_BOOL can_block); +JS_EXTERN void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque); +/* if can_block is true, Atomics.wait() can be used */ +JS_EXTERN void JS_SetCanBlock(JSRuntime *rt, bool can_block); /* set the [IsHTMLDDA] internal slot */ -void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj); +JS_EXTERN void JS_SetIsHTMLDDA(JSContext *ctx, JSValue obj); typedef struct JSModuleDef JSModuleDef; @@ -853,51 +924,57 @@ typedef JSModuleDef *JSModuleLoaderFunc(JSContext *ctx, /* module_normalize = NULL is allowed and invokes the default module filename normalizer */ -void JS_SetModuleLoaderFunc(JSRuntime *rt, - JSModuleNormalizeFunc *module_normalize, - JSModuleLoaderFunc *module_loader, void *opaque); +JS_EXTERN void JS_SetModuleLoaderFunc(JSRuntime *rt, + JSModuleNormalizeFunc *module_normalize, + JSModuleLoaderFunc *module_loader, void *opaque); /* return the import.meta object of a module */ -JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m); -JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m); -JSValue JS_GetModuleNamespace(JSContext *ctx, JSModuleDef *m); +JS_EXTERN JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m); +JS_EXTERN JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m); +JS_EXTERN JSValue JS_GetModuleNamespace(JSContext *ctx, JSModuleDef *m); /* JS Job support */ -typedef JSValue JSJobFunc(JSContext *ctx, int argc, JSValueConst *argv); -int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func, int argc, JSValueConst *argv); +typedef JSValue JSJobFunc(JSContext *ctx, int argc, JSValue *argv); +JS_EXTERN int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func, int argc, JSValue *argv); -JS_BOOL JS_IsJobPending(JSRuntime *rt); -int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx); +JS_EXTERN bool JS_IsJobPending(JSRuntime *rt); +JS_EXTERN int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx); + +/* Structure to retrieve (de)serialized SharedArrayBuffer objects. */ +typedef struct JSSABTab { + uint8_t **tab; + size_t len; +} JSSABTab; /* Object Writer/Reader (currently only used to handle precompiled code) */ #define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */ -#define JS_WRITE_OBJ_BSWAP (1 << 1) /* byte swapped output */ +#define JS_WRITE_OBJ_BSWAP (0) /* byte swapped output (obsolete, handled transparently) */ #define JS_WRITE_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */ -#define JS_WRITE_OBJ_REFERENCE (1 << 3) /* allow object references to - encode arbitrary object - graph */ -uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj, - int flags); -uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj, - int flags, uint8_t ***psab_tab, size_t *psab_tab_len); +#define JS_WRITE_OBJ_REFERENCE (1 << 3) /* allow object references to encode arbitrary object graph */ +#define JS_WRITE_OBJ_STRIP_SOURCE (1 << 4) /* do not write source code information */ +#define JS_WRITE_OBJ_STRIP_DEBUG (1 << 5) /* do not write debug information */ +JS_EXTERN uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValue obj, int flags); +JS_EXTERN uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValue obj, + int flags, JSSABTab *psab_tab); #define JS_READ_OBJ_BYTECODE (1 << 0) /* allow function/module */ -#define JS_READ_OBJ_ROM_DATA (1 << 1) /* avoid duplicating 'buf' data */ +#define JS_READ_OBJ_ROM_DATA (0) /* avoid duplicating 'buf' data (obsolete, broken by ICs) */ #define JS_READ_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */ #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); +JS_EXTERN JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, int flags); +JS_EXTERN JSValue JS_ReadObject2(JSContext *ctx, const uint8_t *buf, size_t buf_len, + int flags, JSSABTab *psab_tab); /* 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); +JS_EXTERN 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); +JS_EXTERN int JS_ResolveModule(JSContext *ctx, JSValue obj); /* only exported for os.Worker() */ -JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels); +JS_EXTERN JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels); /* only exported for os.Worker() */ -JSValue JS_LoadModule(JSContext *ctx, const char *basename, +JS_EXTERN JSValue JS_LoadModule(JSContext *ctx, const char *basename, const char *filename); /* C function definition */ @@ -919,39 +996,49 @@ typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */ typedef union JSCFunctionType { JSCFunction *generic; - JSValue (*generic_magic)(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); + JSValue (*generic_magic)(JSContext *ctx, JSValue this_val, int argc, JSValue *argv, int magic); JSCFunction *constructor; - JSValue (*constructor_magic)(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv, int magic); + JSValue (*constructor_magic)(JSContext *ctx, JSValue new_target, int argc, JSValue *argv, int magic); JSCFunction *constructor_or_func; double (*f_f)(double); double (*f_f_f)(double, double); - JSValue (*getter)(JSContext *ctx, JSValueConst this_val); - JSValue (*setter)(JSContext *ctx, JSValueConst this_val, JSValueConst val); - JSValue (*getter_magic)(JSContext *ctx, JSValueConst this_val, int magic); - JSValue (*setter_magic)(JSContext *ctx, JSValueConst this_val, JSValueConst val, int magic); - JSValue (*iterator_next)(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int *pdone, int magic); + JSValue (*getter)(JSContext *ctx, JSValue this_val); + JSValue (*setter)(JSContext *ctx, JSValue this_val, JSValue val); + JSValue (*getter_magic)(JSContext *ctx, JSValue this_val, int magic); + JSValue (*setter_magic)(JSContext *ctx, JSValue this_val, JSValue val, int magic); + JSValue (*iterator_next)(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int *pdone, int magic); } JSCFunctionType; -JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func, - const char *name, - int length, JSCFunctionEnum cproto, int magic); -JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func, - int length, int magic, int data_len, - JSValueConst *data); +JS_EXTERN JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func, + const char *name, + int length, JSCFunctionEnum cproto, int magic); +JS_EXTERN JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func, + int length, int magic, int data_len, + JSValue *data); -JSValue JS_NewCFunction(JSContext *ctx, JSCFunction *func, const char *name, - int length); +static inline JSValue JS_NewCFunction(JSContext *ctx, JSCFunction *func, const char *name, + int length) +{ + return JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_generic, 0); +} -JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *func, - const char *name, int length, JSCFunctionEnum cproto, int magic); -void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj, - JSValueConst proto); +static inline JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *func, + const char *name, + int length, JSCFunctionEnum cproto, int magic) +{ + /* Used to squelch a -Wcast-function-type warning. */ + JSCFunctionType ft; + ft.generic_magic = func; + return JS_NewCFunction2(ctx, ft.generic, name, length, cproto, magic); +} +JS_EXTERN void JS_SetConstructor(JSContext *ctx, JSValue func_obj, + JSValue proto); /* C property definition */ typedef struct JSCFunctionListEntry { - const char *name; + const char *name; /* pure ASCII or UTF-8 encoded */ uint8_t prop_flags; uint8_t def_type; int16_t magic; @@ -973,9 +1060,10 @@ typedef struct JSCFunctionListEntry { const struct JSCFunctionListEntry *tab; int len; } prop_list; - const char *str; + const char *str; /* pure ASCII or UTF-8 encoded */ int32_t i32; int64_t i64; + uint64_t u64; double f64; } u; } JSCFunctionListEntry; @@ -992,41 +1080,43 @@ typedef struct JSCFunctionListEntry { #define JS_DEF_ALIAS 9 /* Note: c++ does not like nested designators */ -#define JS_CFUNC_DEF(name, length, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } } -#define JS_CFUNC_MAGIC_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_generic_magic, { .generic_magic = func1 } } } } -#define JS_CFUNC_SPECIAL_DEF(name, length, cproto, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_ ## cproto, { .cproto = func1 } } } } -#define JS_ITERATOR_NEXT_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_iterator_next, { .iterator_next = func1 } } } } -#define JS_CGETSET_DEF(name, fgetter, fsetter) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET, 0, .u = { .getset = { .get = { .getter = fgetter }, .set = { .setter = fsetter } } } } -#define JS_CGETSET_MAGIC_DEF(name, fgetter, fsetter, magic) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET_MAGIC, magic, .u = { .getset = { .get = { .getter_magic = fgetter }, .set = { .setter_magic = fsetter } } } } -#define JS_PROP_STRING_DEF(name, cstr, prop_flags) { name, prop_flags, JS_DEF_PROP_STRING, 0, .u = { .str = cstr } } -#define JS_PROP_INT32_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT32, 0, .u = { .i32 = val } } -#define JS_PROP_INT64_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT64, 0, .u = { .i64 = val } } -#define JS_PROP_DOUBLE_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_DOUBLE, 0, .u = { .f64 = val } } -#define JS_PROP_UNDEFINED_DEF(name, prop_flags) { name, prop_flags, JS_DEF_PROP_UNDEFINED, 0, .u = { .i32 = 0 } } -#define JS_OBJECT_DEF(name, tab, len, prop_flags) { name, prop_flags, JS_DEF_OBJECT, 0, .u = { .prop_list = { tab, len } } } -#define JS_ALIAS_DEF(name, from) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, -1 } } } -#define JS_ALIAS_BASE_DEF(name, from, base) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, base } } } - -void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj, - const JSCFunctionListEntry *tab, - int len); +#define JS_CFUNC_DEF(name, length, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } } +#define JS_CFUNC_DEF2(name, length, func1, prop_flags) { name, prop_flags, JS_DEF_CFUNC, 0, { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } } +#define JS_CFUNC_MAGIC_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, { .func = { length, JS_CFUNC_generic_magic, { .generic_magic = func1 } } } } +#define JS_CFUNC_SPECIAL_DEF(name, length, cproto, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, { .func = { length, JS_CFUNC_ ## cproto, { .cproto = func1 } } } } +#define JS_ITERATOR_NEXT_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, { .func = { length, JS_CFUNC_iterator_next, { .iterator_next = func1 } } } } +#define JS_CGETSET_DEF(name, fgetter, fsetter) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET, 0, { .getset = { .get = { .getter = fgetter }, .set = { .setter = fsetter } } } } +#define JS_CGETSET_DEF2(name, fgetter, fsetter, prop_flags) { name, prop_flags, JS_DEF_CGETSET, 0, { .getset = { .get = { .getter = fgetter }, .set = { .setter = fsetter } } } } +#define JS_CGETSET_MAGIC_DEF(name, fgetter, fsetter, magic) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET_MAGIC, magic, { .getset = { .get = { .getter_magic = fgetter }, .set = { .setter_magic = fsetter } } } } +#define JS_PROP_STRING_DEF(name, cstr, prop_flags) { name, prop_flags, JS_DEF_PROP_STRING, 0, { .str = cstr } } +#define JS_PROP_INT32_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT32, 0, { .i32 = val } } +#define JS_PROP_INT64_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT64, 0, { .i64 = val } } +#define JS_PROP_DOUBLE_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_DOUBLE, 0, { .f64 = val } } +#define JS_PROP_U2D_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_DOUBLE, 0, { .u64 = val } } +#define JS_PROP_UNDEFINED_DEF(name, prop_flags) { name, prop_flags, JS_DEF_PROP_UNDEFINED, 0, { .i32 = 0 } } +#define JS_OBJECT_DEF(name, tab, len, prop_flags) { name, prop_flags, JS_DEF_OBJECT, 0, { .prop_list = { tab, len } } } +#define JS_ALIAS_DEF(name, from) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, { .alias = { from, -1 } } } +#define JS_ALIAS_BASE_DEF(name, from, base) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, { .alias = { from, base } } } + +JS_EXTERN void JS_SetPropertyFunctionList(JSContext *ctx, JSValue obj, + const JSCFunctionListEntry *tab, + int len); /* C module definition */ typedef int JSModuleInitFunc(JSContext *ctx, JSModuleDef *m); -JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str, - JSModuleInitFunc *func); +JS_EXTERN JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str, + JSModuleInitFunc *func); /* can only be called before the module is instantiated */ -int JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *name_str); -int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m, - const JSCFunctionListEntry *tab, int len); +JS_EXTERN int JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *name_str); +JS_EXTERN int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m, + const JSCFunctionListEntry *tab, int len); /* can only be called after the module is instantiated */ -int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name, - JSValue val); -int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m, - const JSCFunctionListEntry *tab, int len); - +JS_EXTERN int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name, + JSValue val); +JS_EXTERN int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m, + const JSCFunctionListEntry *tab, int len); /* Qbs extensions */ struct LookupResult @@ -1041,22 +1131,24 @@ void setScopeLookup(JSContext *ctx, ScopeLookup *scopeLookup); // Alternative: Request with throw in script engine typedef void FoundUndefinedHandler(JSContext *ctx); void setFoundUndefinedHandler(JSContext *ctx, FoundUndefinedHandler *handler); - typedef void FunctionEnteredHandler(JSContext *ctx, JSValue this_val); typedef void FunctionExitedHandler(JSContext *ctx); void setFunctionEnteredHandler(JSContext *ctx, FunctionEnteredHandler *handler); void setFunctionExitedHandler(JSContext *ctx, FunctionExitedHandler *handler); -int isSimpleValue(JSValue v); -#ifndef NDEBUG -void watchRefCount(void *p); -#endif +/* Version */ + +#define QJS_VERSION_MAJOR 0 +#define QJS_VERSION_MINOR 8 +#define QJS_VERSION_PATCH 0 +#define QJS_VERSION_SUFFIX "" + +JS_EXTERN const char* JS_GetVersion(void); -void build_backtrace(JSContext *ctx, JSValueConst error_obj, - const char *filename, int line_num, - int backtrace_flags); +/* Integration point for quickjs-libc.c, not for public use. */ +JS_EXTERN uintptr_t js_std_cmd(int cmd, ...); -#undef js_unlikely +#undef JS_EXTERN #undef js_force_inline #ifdef __cplusplus diff --git a/src/shared/quickjs/quickjs.qbs b/src/shared/quickjs/quickjs.qbs index bdce37979..160886fd7 100644 --- a/src/shared/quickjs/quickjs.qbs +++ b/src/shared/quickjs/quickjs.qbs @@ -4,7 +4,7 @@ StaticLibrary { Depends { name: "qbsbuildconfig" } Depends { name: "cpp" } - cpp.cLanguageVersion: qbs.toolchain.contains("msvc") ? "c99" : "gnu99" + cpp.cLanguageVersion: qbs.toolchain.contains("msvc") ? "c11" : "gnu11" cpp.defines: ['CONFIG_VERSION="2021-03-27"'].concat(qbsbuildconfig.dumpJsLeaks ? "DUMP_LEAKS" : []) cpp.warningLevel: "none" @@ -22,6 +22,7 @@ StaticLibrary { "libunicode.h", "list.h", "quickjs-atom.h", + "quickjs-c-atomics.h", "quickjs-opcode.h", "quickjs.c", "quickjs.h", diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp index 31fcd9238..3bbe65c51 100644 --- a/tests/auto/blackbox/tst_blackbox.cpp +++ b/tests/auto/blackbox/tst_blackbox.cpp @@ -2704,8 +2704,9 @@ void TestBlackbox::referenceErrorInExport() QbsRunParameters params; params.expectFailure = true; QVERIFY(runQbs(params) != 0); - QVERIFY2(m_qbsStderr.contains("referenceErrorInExport.qbs:5:27 'includePaths' is not defined"), - m_qbsStderr.constData()); + QVERIFY2( + m_qbsStderr.contains("referenceErrorInExport.qbs:5:27 includePaths is not defined"), + m_qbsStderr.constData()); } void TestBlackbox::removeDuplicateLibraries_data() diff --git a/tests/auto/language/tst_language.cpp b/tests/auto/language/tst_language.cpp index 51906f203..65f07757a 100644 --- a/tests/auto/language/tst_language.cpp +++ b/tests/auto/language/tst_language.cpp @@ -1042,12 +1042,9 @@ void TestLanguage::erroneousFiles_data() "is allowed."; QTest::newRow("importloop1") << "Loop detected when importing"; - QTest::newRow("nonexistentouter") - << "'outer' is not defined"; - QTest::newRow("invalid_file") - << "does not exist"; - QTest::newRow("invalid-parameter-rhs") - << "'access' is not defined"; + QTest::newRow("nonexistentouter") << "outer is not defined"; + QTest::newRow("invalid_file") << "does not exist"; + QTest::newRow("invalid-parameter-rhs") << "access is not defined"; QTest::newRow("invalid-parameter-type") << "Value assigned to property 'stringParameter' does not have type 'string'."; QTest::newRow("invalid_property_type") @@ -1125,7 +1122,7 @@ void TestLanguage::erroneousFiles_data() QTest::newRow("missing-colon") << "Invalid item 'dummy.cxxFlags'. Did you mean to set a module property?"; QTest::newRow("syntax-error-in-probe") - << "syntax-error-in-probe.qbs:4:20.*'fngkgsdjfgklkf' is not defined"; + << "syntax-error-in-probe.qbs:4:20.*fngkgsdjfgklkf is not defined"; QTest::newRow("wrong-toplevel-item") << "wrong-toplevel-item.qbs:1:1.*The top-level item must be of type 'Project' or " "'Product', but it is of type 'Artifact'.";