Bug 719135 - Move some arithmetic operations to jsinterpinlines. r=dvander

This commit is contained in:
Jan de Mooij 2012-01-20 13:01:44 +01:00
parent 60292745ec
commit d509a9c8b2
4 changed files with 198 additions and 119 deletions

View File

@ -1094,6 +1094,11 @@ class TypeScript
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

View File

@ -595,6 +595,40 @@ TypeScript::MonitorUnknown(JSContext *cx, JSScript *script, jsbytecode *pc)
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)

View File

@ -2413,145 +2413,51 @@ END_CASE(JSOP_URSH)
BEGIN_CASE(JSOP_ADD)
{
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--;
}
}
Value rval = regs.sp[-1];
if (!AddOperation(cx, lval, rval, &regs.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, &regs.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, &regs.sp[-2]))
goto error;
regs.sp--;
}
END_CASE(JSOP_MUL)
#undef BINARY_OP
BEGIN_CASE(JSOP_DIV)
{
Value rval = regs.sp[-1];
Value lval = regs.sp[-2];
double d1, d2;
if (!ToNumber(cx, lval, &d1) || !ToNumber(cx, rval, &d2))
Value rval = regs.sp[-1];
if (!DivOperation(cx, lval, rval, &regs.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, &regs.sp[-2]))
goto error;
regs.sp--;
}
END_CASE(JSOP_MOD)

View File

@ -44,13 +44,16 @@
#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"
@ -511,6 +514,137 @@ InterpreterFrames::enableInterruptsIfRunning(JSScript *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__ */