Bug 719135 - Move some arithmetic operations to jsinterpinlines. r=dvander
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -1089,16 +1089,21 @@ class TypeScript
/*
* Monitor a bytecode pushing a value which is not accounted for by the
* inference type constraints, such as integer overflow.
*/
static inline void MonitorOverflow(JSContext *cx, JSScript *script, jsbytecode *pc);
static inline void MonitorString(JSContext *cx, JSScript *script, jsbytecode *pc);
static inline void MonitorUnknown(JSContext *cx, JSScript *script, jsbytecode *pc);
+ static inline void GetPcScript(JSContext *cx, JSScript **script, jsbytecode **pc);
+ static inline void MonitorOverflow(JSContext *cx);
+ static inline void MonitorString(JSContext *cx);
+ static inline void MonitorUnknown(JSContext *cx);
+
/*
* Monitor a bytecode pushing any value. This must be called for any opcode
* which is JOF_TYPESET, and where either the script has not been analyzed
* by type inference or where the pc has type barriers. For simplicity, we
* always monitor JOF_TYPESET opcodes in the interpreter and stub calls,
* and only look at barriers when generating JIT code for the script.
*/
static inline void Monitor(JSContext *cx, JSScript *script, jsbytecode *pc,
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -591,16 +591,50 @@ TypeScript::MonitorString(JSContext *cx,
/* static */ inline void
TypeScript::MonitorUnknown(JSContext *cx, JSScript *script, jsbytecode *pc)
{
if (cx->typeInferenceEnabled())
TypeDynamicResult(cx, script, pc, Type::UnknownType());
}
/* static */ inline void
+TypeScript::GetPcScript(JSContext *cx, JSScript **script, jsbytecode **pc)
+{
+ *script = cx->fp()->script();
+ *pc = cx->regs().pc;
+}
+
+/* static */ inline void
+TypeScript::MonitorOverflow(JSContext *cx)
+{
+ JSScript *script;
+ jsbytecode *pc;
+ GetPcScript(cx, &script, &pc);
+ MonitorOverflow(cx, script, pc);
+}
+
+/* static */ inline void
+TypeScript::MonitorString(JSContext *cx)
+{
+ JSScript *script;
+ jsbytecode *pc;
+ GetPcScript(cx, &script, &pc);
+ MonitorString(cx, script, pc);
+}
+
+/* static */ inline void
+TypeScript::MonitorUnknown(JSContext *cx)
+{
+ JSScript *script;
+ jsbytecode *pc;
+ GetPcScript(cx, &script, &pc);
+ MonitorUnknown(cx, script, pc);
+}
+
+/* static */ inline void
TypeScript::MonitorAssign(JSContext *cx, JSScript *script, jsbytecode *pc,
JSObject *obj, jsid id, const js::Value &rval)
{
if (cx->typeInferenceEnabled() && !obj->hasSingletonType()) {
/*
* Mark as unknown any object which has had dynamic assignments to
* non-integer properties at SETELEM opcodes. This avoids making large
* numbers of type properties for hashmap-style objects. We don't need
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -2408,155 +2408,61 @@ BEGIN_CASE(JSOP_URSH)
regs.sp--;
if (!regs.sp[-1].setNumber(uint32_t(u)))
TypeScript::MonitorOverflow(cx, script, regs.pc);
}
END_CASE(JSOP_URSH)
BEGIN_CASE(JSOP_ADD)
{
+ Value lval = regs.sp[-2];
Value rval = regs.sp[-1];
- Value lval = regs.sp[-2];
-
- if (lval.isInt32() && rval.isInt32()) {
- int32_t l = lval.toInt32(), r = rval.toInt32();
- int32_t sum = l + r;
- if (JS_UNLIKELY(bool((l ^ sum) & (r ^ sum) & 0x80000000))) {
- regs.sp[-2].setDouble(double(l) + double(r));
- TypeScript::MonitorOverflow(cx, script, regs.pc);
- } else {
- regs.sp[-2].setInt32(sum);
- }
- regs.sp--;
- } else
-#if JS_HAS_XML_SUPPORT
- if (IsXML(lval) && IsXML(rval)) {
- if (!js_ConcatenateXML(cx, &lval.toObject(), &rval.toObject(), &rval))
- goto error;
- regs.sp[-2] = rval;
- regs.sp--;
- TypeScript::MonitorUnknown(cx, script, regs.pc);
- } else
-#endif
- {
- /*
- * If either operand is an object, any non-integer result must be
- * reported to inference.
- */
- bool lIsObject = lval.isObject(), rIsObject = rval.isObject();
-
- if (!ToPrimitive(cx, &lval))
- goto error;
- if (!ToPrimitive(cx, &rval))
- goto error;
- bool lIsString, rIsString;
- if ((lIsString = lval.isString()) | (rIsString = rval.isString())) {
- JSString *lstr, *rstr;
- if (lIsString) {
- lstr = lval.toString();
- } else {
- lstr = ToString(cx, lval);
- if (!lstr)
- goto error;
- regs.sp[-2].setString(lstr);
- }
- if (rIsString) {
- rstr = rval.toString();
- } else {
- rstr = ToString(cx, rval);
- if (!rstr)
- goto error;
- regs.sp[-1].setString(rstr);
- }
- JSString *str = js_ConcatStrings(cx, lstr, rstr);
- if (!str)
- goto error;
- if (lIsObject || rIsObject)
- TypeScript::MonitorString(cx, script, regs.pc);
- regs.sp[-2].setString(str);
- regs.sp--;
- } else {
- double l, r;
- if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))
- goto error;
- l += r;
- if (!regs.sp[-2].setNumber(l) &&
- (lIsObject || rIsObject || (!lval.isDouble() && !rval.isDouble()))) {
- TypeScript::MonitorOverflow(cx, script, regs.pc);
- }
- regs.sp--;
- }
- }
+ if (!AddOperation(cx, lval, rval, ®s.sp[-2]))
+ goto error;
+ regs.sp--;
}
END_CASE(JSOP_ADD)
-#define BINARY_OP(OP) \
- JS_BEGIN_MACRO \
- Value rval = regs.sp[-1]; \
- Value lval = regs.sp[-2]; \
- double d1, d2; \
- if (!ToNumber(cx, lval, &d1) || !ToNumber(cx, rval, &d2)) \
- goto error; \
- double d = d1 OP d2; \
- regs.sp--; \
- if (!regs.sp[-1].setNumber(d) && \
- !(lval.isDouble() || rval.isDouble())) { \
- TypeScript::MonitorOverflow(cx, script, regs.pc); \
- } \
- JS_END_MACRO
-
BEGIN_CASE(JSOP_SUB)
- BINARY_OP(-);
+{
+ Value lval = regs.sp[-2];
+ Value rval = regs.sp[-1];
+ if (!SubOperation(cx, lval, rval, ®s.sp[-2]))
+ goto error;
+ regs.sp--;
+}
END_CASE(JSOP_SUB)
BEGIN_CASE(JSOP_MUL)
- BINARY_OP(*);
+{
+ Value lval = regs.sp[-2];
+ Value rval = regs.sp[-1];
+ if (!MulOperation(cx, lval, rval, ®s.sp[-2]))
+ goto error;
+ regs.sp--;
+}
END_CASE(JSOP_MUL)
-#undef BINARY_OP
-
BEGIN_CASE(JSOP_DIV)
{
+ Value lval = regs.sp[-2];
Value rval = regs.sp[-1];
- Value lval = regs.sp[-2];
- double d1, d2;
- if (!ToNumber(cx, lval, &d1) || !ToNumber(cx, rval, &d2))
+ if (!DivOperation(cx, lval, rval, ®s.sp[-2]))
goto error;
regs.sp--;
-
- regs.sp[-1].setNumber(NumberDiv(d1, d2));
-
- if (d2 == 0 || (regs.sp[-1].isDouble() && !(lval.isDouble() || rval.isDouble())))
- TypeScript::MonitorOverflow(cx, script, regs.pc);
}
END_CASE(JSOP_DIV)
BEGIN_CASE(JSOP_MOD)
{
- Value &lref = regs.sp[-2];
- Value &rref = regs.sp[-1];
- int32_t l, r;
- if (lref.isInt32() && rref.isInt32() &&
- (l = lref.toInt32()) >= 0 && (r = rref.toInt32()) > 0) {
- int32_t mod = l % r;
- regs.sp--;
- regs.sp[-1].setInt32(mod);
- } else {
- double d1, d2;
- if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
- goto error;
- regs.sp--;
- if (d2 == 0) {
- regs.sp[-1].setDouble(js_NaN);
- } else {
- d1 = js_fmod(d1, d2);
- regs.sp[-1].setDouble(d1);
- }
- TypeScript::MonitorOverflow(cx, script, regs.pc);
- }
+ Value lval = regs.sp[-2];
+ Value rval = regs.sp[-1];
+ if (!ModOperation(cx, lval, rval, ®s.sp[-2]))
+ goto error;
+ regs.sp--;
}
END_CASE(JSOP_MOD)
BEGIN_CASE(JSOP_NOT)
{
Value *_;
bool cond;
POP_BOOLEAN(cx, _, cond);
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -39,23 +39,26 @@
* ***** END LICENSE BLOCK ***** */
#ifndef jsinterpinlines_h__
#define jsinterpinlines_h__
#include "jsapi.h"
#include "jsbool.h"
#include "jscompartment.h"
+#include "jsinfer.h"
#include "jsinterp.h"
+#include "jslibmath.h"
#include "jsnum.h"
#include "jsprobes.h"
#include "jsstr.h"
#include "methodjit/MethodJIT.h"
#include "jsfuninlines.h"
+#include "jsinferinlines.h"
#include "jspropertycacheinlines.h"
#include "jstypedarrayinlines.h"
#include "vm/Stack-inl.h"
namespace js {
class AutoPreserveEnumerators {
@@ -506,11 +509,142 @@ ScriptEpilogueOrGeneratorYield(JSContext
inline void
InterpreterFrames::enableInterruptsIfRunning(JSScript *script)
{
if (script == regs->fp()->script())
enabler.enableInterrupts();
}
+static JS_ALWAYS_INLINE bool
+AddOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res)
+{
+ Value lval = lhs;
+ Value rval = rhs;
+
+ if (lval.isInt32() && rval.isInt32()) {
+ int32_t l = lval.toInt32(), r = rval.toInt32();
+ int32_t sum = l + r;
+ if (JS_UNLIKELY(bool((l ^ sum) & (r ^ sum) & 0x80000000))) {
+ res->setDouble(double(l) + double(r));
+ types::TypeScript::MonitorOverflow(cx);
+ } else {
+ res->setInt32(sum);
+ }
+ } else
+#if JS_HAS_XML_SUPPORT
+ if (IsXML(lval) && IsXML(rval)) {
+ if (!js_ConcatenateXML(cx, &lval.toObject(), &rval.toObject(), res))
+ return false;
+ types::TypeScript::MonitorUnknown(cx);
+ } else
+#endif
+ {
+ /*
+ * If either operand is an object, any non-integer result must be
+ * reported to inference.
+ */
+ bool lIsObject = lval.isObject(), rIsObject = rval.isObject();
+
+ if (!ToPrimitive(cx, &lval))
+ return false;
+ if (!ToPrimitive(cx, &rval))
+ return false;
+ bool lIsString, rIsString;
+ if ((lIsString = lval.isString()) | (rIsString = rval.isString())) {
+ js::AutoStringRooter lstr(cx), rstr(cx);
+ if (lIsString) {
+ lstr.setString(lval.toString());
+ } else {
+ lstr.setString(ToString(cx, lval));
+ if (!lstr.string())
+ return false;
+ }
+ if (rIsString) {
+ rstr.setString(rval.toString());
+ } else {
+ rstr.setString(ToString(cx, rval));
+ if (!rstr.string())
+ return false;
+ }
+ JSString *str = js_ConcatStrings(cx, lstr.string(), rstr.string());
+ if (!str)
+ return false;
+ if (lIsObject || rIsObject)
+ types::TypeScript::MonitorString(cx);
+ res->setString(str);
+ } else {
+ double l, r;
+ if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))
+ return false;
+ l += r;
+ if (!res->setNumber(l) &&
+ (lIsObject || rIsObject || (!lval.isDouble() && !rval.isDouble()))) {
+ types::TypeScript::MonitorOverflow(cx);
+ }
+ }
+ }
+ return true;
+}
+
+static JS_ALWAYS_INLINE bool
+SubOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res)
+{
+ double d1, d2;
+ if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
+ return false;
+ double d = d1 - d2;
+ if (!res->setNumber(d) && !(lhs.isDouble() || rhs.isDouble()))
+ types::TypeScript::MonitorOverflow(cx);
+ return true;
+}
+
+static JS_ALWAYS_INLINE bool
+MulOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res)
+{
+ double d1, d2;
+ if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
+ return false;
+ double d = d1 * d2;
+ if (!res->setNumber(d) && !(lhs.isDouble() || rhs.isDouble()))
+ types::TypeScript::MonitorOverflow(cx);
+ return true;
+}
+
+static JS_ALWAYS_INLINE bool
+DivOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res)
+{
+ double d1, d2;
+ if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
+ return false;
+ res->setNumber(NumberDiv(d1, d2));
+
+ if (d2 == 0 || (res->isDouble() && !(lhs.isDouble() || rhs.isDouble())))
+ types::TypeScript::MonitorOverflow(cx);
+ return true;
+}
+
+static JS_ALWAYS_INLINE bool
+ModOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res)
+{
+ int32_t l, r;
+ if (lhs.isInt32() && rhs.isInt32() &&
+ (l = lhs.toInt32()) >= 0 && (r = rhs.toInt32()) > 0) {
+ int32_t mod = l % r;
+ res->setInt32(mod);
+ return true;
+ }
+
+ double d1, d2;
+ if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
+ return false;
+
+ if (d2 == 0)
+ res->setDouble(js_NaN);
+ else
+ res->setDouble(js_fmod(d1, d2));
+ types::TypeScript::MonitorOverflow(cx);
+ return true;
+}
+
} /* namespace js */
#endif /* jsinterpinlines_h__ */