summaryrefslogtreecommitdiff
path: root/js/src/vm/Interpreter-inl.h
diff options
context:
space:
mode:
authorBrian Smith <brian@dbsoft.org>2023-07-19 17:10:33 -0500
committerBrian Smith <brian@dbsoft.org>2023-07-19 17:10:33 -0500
commit24e4a09270cd7194c09e6370cf308a4350ae5e37 (patch)
treed35d3fdc84ea7bd8f3cfcf03ee18c29d6646949d /js/src/vm/Interpreter-inl.h
parentf193a4a7dce742005883f67ec4260637d41661aa (diff)
downloaduxp-24e4a09270cd7194c09e6370cf308a4350ae5e37.tar.gz
Issue #1240 - Part 5g - Implement BigInt comparison operators.
Implement BigInt support for equality operators. https://bugzilla.mozilla.org/show_bug.cgi?id=1486173 Part 3. Implement BigInt support for relational comparison operators. https://bugzilla.mozilla.org/show_bug.cgi?id=1492669
Diffstat (limited to 'js/src/vm/Interpreter-inl.h')
-rw-r--r--js/src/vm/Interpreter-inl.h177
1 files changed, 143 insertions, 34 deletions
diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h
index ecdb619868..a48c753f1d 100644
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -8,6 +8,8 @@
#include "vm/Interpreter.h"
+#include "mozilla/Maybe.h"
+
#include "jscompartment.h"
#include "jsnum.h"
#include "jsstr.h"
@@ -660,51 +662,158 @@ ProcessCallSiteObjOperation(JSContext* cx, RootedObject& cso, RootedObject& raw,
return true;
}
-#define RELATIONAL_OP(OP) \
- JS_BEGIN_MACRO \
- /* Optimize for two int-tagged operands (typical loop control). */ \
- if (lhs.isInt32() && rhs.isInt32()) { \
- *res = lhs.toInt32() OP rhs.toInt32(); \
- } else { \
- if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) \
- return false; \
- if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) \
- return false; \
- if (lhs.isString() && rhs.isString()) { \
- JSString* l = lhs.toString(); \
- JSString* r = rhs.toString(); \
- int32_t result; \
- if (!CompareStrings(cx, l, r, &result)) \
- return false; \
- *res = result OP 0; \
- } else { \
- double l, r; \
- if (!ToNumber(cx, lhs, &l) || !ToNumber(cx, rhs, &r)) \
- return false; \
- *res = (l OP r); \
- } \
- } \
- return true; \
- JS_END_MACRO
+// BigInt proposal 3.2.4 Abstract Relational Comparison
+// Returns Nothing when at least one operand is a NaN, or when
+// ToNumeric or StringToBigInt can't interpret a string as a numeric
+// value. (These cases correspond to a NaN result in the spec.)
+// Otherwise, return a boolean to indicate whether lhs is less than
+// rhs. The operands must be primitives; the caller is responsible for
+// evaluating them in the correct order.
+static MOZ_ALWAYS_INLINE bool
+LessThanImpl(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
+ mozilla::Maybe<bool>& res)
+{
+ // Steps 1 and 2 are performed by the caller.
+
+ // Step 3.
+ if (lhs.isString() && rhs.isString()) {
+ JSString* l = lhs.toString();
+ JSString* r = rhs.toString();
+ int32_t result;
+ if (!CompareStrings(cx, l, r, &result)) {
+ return false;
+ }
+ res = mozilla::Some(result < 0);
+ return true;
+ }
+
+ // Step 4a.
+ if (lhs.isBigInt() && rhs.isString()) {
+ return BigInt::lessThan(cx, lhs, rhs, res);
+ }
+ // Step 4b.
+ if (lhs.isString() && rhs.isBigInt()) {
+ return BigInt::lessThan(cx, lhs, rhs, res);
+ }
+
+ // Steps 4c and 4d.
+ if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
+ return false;
+ }
+
+ // Steps 4e-j.
+ if (lhs.isBigInt() || rhs.isBigInt()) {
+ return BigInt::lessThan(cx, lhs, rhs, res);
+ }
+
+ // Step 4e for Number operands.
+ MOZ_ASSERT(lhs.isNumber() && rhs.isNumber());
+ double lhsNum = lhs.toNumber();
+ double rhsNum = rhs.toNumber();
+
+ if (mozilla::IsNaN(lhsNum) || mozilla::IsNaN(rhsNum)) {
+ res = mozilla::Maybe<bool>(mozilla::Nothing());
+ return true;
+ }
+
+ res = mozilla::Some(lhsNum < rhsNum);
+ return true;
+}
static MOZ_ALWAYS_INLINE bool
-LessThanOperation(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res) {
- RELATIONAL_OP(<);
+LessThanOperation(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res)
+{
+ if (lhs.isInt32() && rhs.isInt32()) {
+ *res = lhs.toInt32() < rhs.toInt32();
+ return true;
+ }
+
+ if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
+ return false;
+ }
+
+ if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
+ return false;
+ }
+
+ mozilla::Maybe<bool> tmpResult;
+ if (!LessThanImpl(cx, lhs, rhs, tmpResult)) {
+ return false;
+ }
+ *res = tmpResult.valueOr(false);
+ return true;
}
static MOZ_ALWAYS_INLINE bool
-LessThanOrEqualOperation(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res) {
- RELATIONAL_OP(<=);
+LessThanOrEqualOperation(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res)
+{
+ if (lhs.isInt32() && rhs.isInt32()) {
+ *res = lhs.toInt32() <= rhs.toInt32();
+ return true;
+ }
+
+ if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
+ return false;
+ }
+
+ if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
+ return false;
+ }
+
+ mozilla::Maybe<bool> tmpResult;
+ if (!LessThanImpl(cx, rhs, lhs, tmpResult)) {
+ return false;
+ }
+ *res = !tmpResult.valueOr(true);
+ return true;
}
static MOZ_ALWAYS_INLINE bool
-GreaterThanOperation(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res) {
- RELATIONAL_OP(>);
+GreaterThanOperation(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res)
+{
+ if (lhs.isInt32() && rhs.isInt32()) {
+ *res = lhs.toInt32() > rhs.toInt32();
+ return true;
+ }
+
+ if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
+ return false;
+ }
+
+ if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
+ return false;
+ }
+
+ mozilla::Maybe<bool> tmpResult;
+ if (!LessThanImpl(cx, rhs, lhs, tmpResult)) {
+ return false;
+ }
+ *res = tmpResult.valueOr(false);
+ return true;
}
static MOZ_ALWAYS_INLINE bool
-GreaterThanOrEqualOperation(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res) {
- RELATIONAL_OP(>=);
+GreaterThanOrEqualOperation(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res)
+{
+ if (lhs.isInt32() && rhs.isInt32()) {
+ *res = lhs.toInt32() >= rhs.toInt32();
+ return true;
+ }
+
+ if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
+ return false;
+ }
+
+ if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
+ return false;
+ }
+
+ mozilla::Maybe<bool> tmpResult;
+ if (!LessThanImpl(cx, lhs, rhs, tmpResult)) {
+ return false;
+ }
+ *res = !tmpResult.valueOr(true);
+ return true;
}
static MOZ_ALWAYS_INLINE bool