summaryrefslogtreecommitdiff
path: root/js/src/jsnum.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jsnum.h')
-rw-r--r--js/src/jsnum.h356
1 files changed, 356 insertions, 0 deletions
diff --git a/js/src/jsnum.h b/js/src/jsnum.h
new file mode 100644
index 0000000000..62b3d617f1
--- /dev/null
+++ b/js/src/jsnum.h
@@ -0,0 +1,356 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jsnum_h
+#define jsnum_h
+
+#include "mozilla/FloatingPoint.h"
+#include "mozilla/Range.h"
+
+#include "NamespaceImports.h"
+
+#include "js/Conversions.h"
+
+
+// This macro is should be `one' if current compiler supports builtin functions
+// like __builtin_sadd_overflow.
+#if __GNUC__ >= 5
+ // GCC 5 and above supports these functions.
+ #define BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(x) 1
+#else
+ // For CLANG, we use its own function to check for this.
+ #ifdef __has_builtin
+ #define BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(x) __has_builtin(x)
+ #endif
+#endif
+#ifndef BUILTIN_CHECKED_ARITHMETIC_SUPPORTED
+ #define BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(x) 0
+#endif
+
+namespace js {
+
+class StringBuffer;
+
+extern MOZ_MUST_USE bool
+InitRuntimeNumberState(JSRuntime* rt);
+
+#if !EXPOSE_INTL_API
+extern void
+FinishRuntimeNumberState(JSRuntime* rt);
+#endif
+
+/* Initialize the Number class, returning its prototype object. */
+extern JSObject*
+InitNumberClass(JSContext* cx, HandleObject obj);
+
+} /* namespace js */
+
+/*
+ * String constants for global function names, used in jsapi.c and jsnum.c.
+ */
+extern const char js_isNaN_str[];
+extern const char js_isFinite_str[];
+extern const char js_parseFloat_str[];
+extern const char js_parseInt_str[];
+
+class JSAtom;
+
+namespace js {
+
+/*
+ * When base == 10, this function implements ToString() as specified by
+ * ECMA-262-5 section 9.8.1; but note that it handles integers specially for
+ * performance. See also js::NumberToCString().
+ */
+template <AllowGC allowGC>
+extern JSString*
+NumberToString(ExclusiveContext* cx, double d);
+
+extern JSAtom*
+NumberToAtom(ExclusiveContext* cx, double d);
+
+template <AllowGC allowGC>
+extern JSFlatString*
+Int32ToString(ExclusiveContext* cx, int32_t i);
+
+extern JSAtom*
+Int32ToAtom(ExclusiveContext* cx, int32_t si);
+
+/*
+ * Convert an integer or double (contained in the given value) to a string and
+ * append to the given buffer.
+ */
+extern MOZ_MUST_USE bool JS_FASTCALL
+NumberValueToStringBuffer(JSContext* cx, const Value& v, StringBuffer& sb);
+
+/* Same as js_NumberToString, different signature. */
+extern JSFlatString*
+NumberToString(JSContext* cx, double d);
+
+extern JSFlatString*
+IndexToString(JSContext* cx, uint32_t index);
+
+/*
+ * Usually a small amount of static storage is enough, but sometimes we need
+ * to dynamically allocate much more. This struct encapsulates that.
+ * Dynamically allocated memory will be freed when the object is destroyed.
+ */
+struct ToCStringBuf
+{
+ /*
+ * The longest possible result that would need to fit in sbuf is
+ * (-0x80000000).toString(2), which has length 33. Longer cases are
+ * possible, but they'll go in dbuf.
+ */
+ static const size_t sbufSize = 34;
+ char sbuf[sbufSize];
+ char* dbuf;
+
+ ToCStringBuf();
+ ~ToCStringBuf();
+};
+
+/*
+ * Convert a number to a C string. When base==10, this function implements
+ * ToString() as specified by ECMA-262-5 section 9.8.1. It handles integral
+ * values cheaply. Return nullptr if we ran out of memory. See also
+ * NumberToCString().
+ */
+extern char*
+NumberToCString(JSContext* cx, ToCStringBuf* cbuf, double d, int base = 10);
+
+/*
+ * The largest positive integer such that all positive integers less than it
+ * may be precisely represented using the IEEE-754 double-precision format.
+ */
+const double DOUBLE_INTEGRAL_PRECISION_LIMIT = uint64_t(1) << 53;
+
+/*
+ * Parse a decimal number encoded in |chars|. The decimal number must be
+ * sufficiently small that it will not overflow the integrally-precise range of
+ * the double type -- that is, the number will be smaller than
+ * DOUBLE_INTEGRAL_PRECISION_LIMIT
+ */
+template <typename CharT>
+extern double
+ParseDecimalNumber(const mozilla::Range<const CharT> chars);
+
+/*
+ * Compute the positive integer of the given base described immediately at the
+ * start of the range [start, end) -- no whitespace-skipping, no magical
+ * leading-"0" octal or leading-"0x" hex behavior, no "+"/"-" parsing, just
+ * reading the digits of the integer. Return the index one past the end of the
+ * digits of the integer in *endp, and return the integer itself in *dp. If
+ * base is 10 or a power of two the returned integer is the closest possible
+ * double; otherwise extremely large integers may be slightly inaccurate.
+ *
+ * If [start, end) does not begin with a number with the specified base,
+ * *dp == 0 and *endp == start upon return.
+ */
+template <typename CharT>
+extern MOZ_MUST_USE bool
+GetPrefixInteger(ExclusiveContext* cx, const CharT* start, const CharT* end, int base,
+ const CharT** endp, double* dp);
+
+/*
+ * This is like GetPrefixInteger, but only deals with base 10, and doesn't have
+ * and |endp| outparam. It should only be used when the characters are known to
+ * only contain digits.
+ */
+extern MOZ_MUST_USE bool
+GetDecimalInteger(ExclusiveContext* cx, const char16_t* start, const char16_t* end, double* dp);
+
+extern MOZ_MUST_USE bool
+StringToNumber(ExclusiveContext* cx, JSString* str, double* result);
+
+/* ES5 9.3 ToNumber, overwriting *vp with the appropriate number value. */
+MOZ_ALWAYS_INLINE MOZ_MUST_USE bool
+ToNumber(JSContext* cx, JS::MutableHandleValue vp)
+{
+ if (vp.isNumber())
+ return true;
+ double d;
+ extern JS_PUBLIC_API(bool) ToNumberSlow(JSContext* cx, HandleValue v, double* dp);
+ if (!ToNumberSlow(cx, vp, &d))
+ return false;
+
+ vp.setNumber(d);
+ return true;
+}
+
+MOZ_MUST_USE bool
+num_parseInt(JSContext* cx, unsigned argc, Value* vp);
+
+} /* namespace js */
+
+/*
+ * Similar to strtod except that it replaces overflows with infinities of the
+ * correct sign, and underflows with zeros of the correct sign. Guaranteed to
+ * return the closest double number to the given input in dp.
+ *
+ * Also allows inputs of the form [+|-]Infinity, which produce an infinity of
+ * the appropriate sign. The case of the "Infinity" string must match exactly.
+ * If the string does not contain a number, set *dEnd to begin and return 0.0
+ * in *d.
+ *
+ * Return false if out of memory.
+ */
+template <typename CharT>
+extern MOZ_MUST_USE bool
+js_strtod(js::ExclusiveContext* cx, const CharT* begin, const CharT* end,
+ const CharT** dEnd, double* d);
+
+namespace js {
+
+extern MOZ_MUST_USE bool
+num_toString(JSContext* cx, unsigned argc, Value* vp);
+
+extern MOZ_MUST_USE bool
+num_valueOf(JSContext* cx, unsigned argc, Value* vp);
+
+static MOZ_ALWAYS_INLINE bool
+ValueFitsInInt32(const Value& v, int32_t* pi)
+{
+ if (v.isInt32()) {
+ *pi = v.toInt32();
+ return true;
+ }
+ return v.isDouble() && mozilla::NumberIsInt32(v.toDouble(), pi);
+}
+
+/*
+ * Returns true if the given value is definitely an index: that is, the value
+ * is a number that's an unsigned 32-bit integer.
+ *
+ * This method prioritizes common-case speed over accuracy in every case. It
+ * can produce false negatives (but not false positives): some values which are
+ * indexes will be reported not to be indexes by this method. Users must
+ * consider this possibility when using this method.
+ */
+static MOZ_ALWAYS_INLINE bool
+IsDefinitelyIndex(const Value& v, uint32_t* indexp)
+{
+ if (v.isInt32() && v.toInt32() >= 0) {
+ *indexp = v.toInt32();
+ return true;
+ }
+
+ int32_t i;
+ if (v.isDouble() && mozilla::NumberIsInt32(v.toDouble(), &i) && i >= 0) {
+ *indexp = uint32_t(i);
+ return true;
+ }
+
+ return false;
+}
+
+/* ES5 9.4 ToInteger. */
+static MOZ_MUST_USE inline bool
+ToInteger(JSContext* cx, HandleValue v, double* dp)
+{
+ if (v.isInt32()) {
+ *dp = v.toInt32();
+ return true;
+ }
+ if (v.isDouble()) {
+ *dp = v.toDouble();
+ } else {
+ extern JS_PUBLIC_API(bool) ToNumberSlow(JSContext* cx, HandleValue v, double* dp);
+ if (!ToNumberSlow(cx, v, dp))
+ return false;
+ }
+ *dp = JS::ToInteger(*dp);
+ return true;
+}
+
+/* ES6 7.1.15 ToLength, but clamped to the [0,2^32-2] range. If the
+ * return value is false then *overflow will be true iff the value was
+ * not clampable to uint32_t range.
+ *
+ * For JSContext and ExclusiveContext.
+ */
+template<typename T>
+MOZ_MUST_USE bool ToLengthClamped(T* cx, HandleValue v, uint32_t* out, bool* overflow);
+
+/* Convert and range check an index value as for DataView, SIMD, and Atomics
+ * operations, eg ES7 24.2.1.1, DataView's GetViewValue():
+ *
+ * 1. numericIndex = ToNumber(argument) (may throw TypeError)
+ * 2. intIndex = ToInteger(numericIndex)
+ * 3. if intIndex != numericIndex throw RangeError
+ *
+ * This function additionally bounds the range to the non-negative contiguous
+ * integers:
+ *
+ * 4. if intIndex < 0 or intIndex > 2^53 throw RangeError
+ *
+ * Return true and set |*index| to the integer value if |argument| is a valid
+ * array index argument. Otherwise report an TypeError or RangeError and return
+ * false.
+ *
+ * The returned index will always be in the range 0 <= *index <= 2^53.
+ */
+MOZ_MUST_USE bool ToIntegerIndex(JSContext* cx, JS::HandleValue v, uint64_t* index);
+
+MOZ_MUST_USE inline bool
+SafeAdd(int32_t one, int32_t two, int32_t* res)
+{
+#if BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(__builtin_sadd_overflow)
+ // Using compiler's builtin function.
+ return !__builtin_sadd_overflow(one, two, res);
+#else
+ // Use unsigned for the 32-bit operation since signed overflow gets
+ // undefined behavior.
+ *res = uint32_t(one) + uint32_t(two);
+ int64_t ores = (int64_t)one + (int64_t)two;
+ return ores == (int64_t)*res;
+#endif
+}
+
+MOZ_MUST_USE inline bool
+SafeSub(int32_t one, int32_t two, int32_t* res)
+{
+#if BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(__builtin_ssub_overflow)
+ return !__builtin_ssub_overflow(one, two, res);
+#else
+ *res = uint32_t(one) - uint32_t(two);
+ int64_t ores = (int64_t)one - (int64_t)two;
+ return ores == (int64_t)*res;
+#endif
+}
+
+MOZ_MUST_USE inline bool
+SafeMul(int32_t one, int32_t two, int32_t* res)
+{
+#if BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(__builtin_smul_overflow)
+ return !__builtin_smul_overflow(one, two, res);
+#else
+ *res = uint32_t(one) * uint32_t(two);
+ int64_t ores = (int64_t)one * (int64_t)two;
+ return ores == (int64_t)*res;
+#endif
+}
+
+extern MOZ_MUST_USE bool
+ToNumberSlow(ExclusiveContext* cx, HandleValue v, double* dp);
+
+// Variant of ToNumber which takes an ExclusiveContext instead of a JSContext.
+// ToNumber is part of the API and can't use ExclusiveContext directly.
+MOZ_ALWAYS_INLINE MOZ_MUST_USE bool
+ToNumber(ExclusiveContext* cx, HandleValue v, double* out)
+{
+ if (v.isNumber()) {
+ *out = v.toNumber();
+ return true;
+ }
+ return ToNumberSlow(cx, v, out);
+}
+
+void FIX_FPU();
+
+} /* namespace js */
+
+#endif /* jsnum_h */