mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-24 02:35:41 +00:00
Bug 891215 (part 15) - Slim down Interpreter-inl.h. r=terrence.
--HG-- extra : rebase_source : dea8c481504ce50b2b1869d81b4d6aa1a1f1a212
This commit is contained in:
parent
fb24fe9213
commit
b4e6f716de
@ -28,50 +28,6 @@
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* Compute the implicit |this| parameter for a call expression where the callee
|
||||
* funval was resolved from an unqualified name reference to a property on obj
|
||||
* (an object on the scope chain).
|
||||
*
|
||||
* We can avoid computing |this| eagerly and push the implicit callee-coerced
|
||||
* |this| value, undefined, if any of these conditions hold:
|
||||
*
|
||||
* 1. The nominal |this|, obj, is a global object.
|
||||
*
|
||||
* 2. The nominal |this|, obj, has one of Block, Call, or DeclEnv class (this
|
||||
* is what IsCacheableNonGlobalScope tests). Such objects-as-scopes must be
|
||||
* censored with undefined.
|
||||
*
|
||||
* Otherwise, we bind |this| to obj->thisObject(). Only names inside |with|
|
||||
* statements and embedding-specific scope objects fall into this category.
|
||||
*
|
||||
* If the callee is a strict mode function, then code implementing JSOP_THIS
|
||||
* in the interpreter and JITs will leave undefined as |this|. If funval is a
|
||||
* function not in strict mode, JSOP_THIS code replaces undefined with funval's
|
||||
* global.
|
||||
*
|
||||
* We set *vp to undefined early to reduce code size and bias this code for the
|
||||
* common and future-friendly cases.
|
||||
*/
|
||||
inline bool
|
||||
ComputeImplicitThis(JSContext *cx, HandleObject obj, MutableHandleValue vp)
|
||||
{
|
||||
vp.setUndefined();
|
||||
|
||||
if (obj->is<GlobalObject>())
|
||||
return true;
|
||||
|
||||
if (IsCacheableNonGlobalScope(obj))
|
||||
return true;
|
||||
|
||||
JSObject *nobj = JSObject::thisObject(cx, obj);
|
||||
if (!nobj)
|
||||
return false;
|
||||
|
||||
vp.setObject(*nobj);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
ComputeThis(JSContext *cx, AbstractFramePtr frame)
|
||||
{
|
||||
@ -345,154 +301,6 @@ DefVarOrConstOperation(JSContext *cx, HandleObject varobj, HandlePropertyName dn
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
SetConstOperation(JSContext *cx, HandleObject varobj, HandlePropertyName name, HandleValue rval)
|
||||
{
|
||||
return JSObject::defineProperty(cx, varobj, name, rval,
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY);
|
||||
}
|
||||
|
||||
inline void
|
||||
InterpreterFrames::enableInterruptsIfRunning(JSScript *script)
|
||||
{
|
||||
if (regs->fp()->script() == script)
|
||||
enabler.enable();
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
AddOperation(JSContext *cx, HandleScript script, jsbytecode *pc,
|
||||
MutableHandleValue lhs, MutableHandleValue rhs, Value *res)
|
||||
{
|
||||
if (lhs.isInt32() && rhs.isInt32()) {
|
||||
int32_t l = lhs.toInt32(), r = rhs.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, script, pc);
|
||||
} else {
|
||||
res->setInt32(sum);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If either operand is an object, any non-integer result must be
|
||||
* reported to inference.
|
||||
*/
|
||||
bool lIsObject = lhs.isObject(), rIsObject = rhs.isObject();
|
||||
|
||||
if (!ToPrimitive(cx, lhs))
|
||||
return false;
|
||||
if (!ToPrimitive(cx, rhs))
|
||||
return false;
|
||||
bool lIsString, rIsString;
|
||||
if ((lIsString = lhs.isString()) | (rIsString = rhs.isString())) {
|
||||
JSString *lstr, *rstr;
|
||||
if (lIsString) {
|
||||
lstr = lhs.toString();
|
||||
} else {
|
||||
lstr = ToString<CanGC>(cx, lhs);
|
||||
if (!lstr)
|
||||
return false;
|
||||
}
|
||||
if (rIsString) {
|
||||
rstr = rhs.toString();
|
||||
} else {
|
||||
// Save/restore lstr in case of GC activity under ToString.
|
||||
lhs.setString(lstr);
|
||||
rstr = ToString<CanGC>(cx, rhs);
|
||||
if (!rstr)
|
||||
return false;
|
||||
lstr = lhs.toString();
|
||||
}
|
||||
JSString *str = ConcatStrings<NoGC>(cx, lstr, rstr);
|
||||
if (!str) {
|
||||
RootedString nlstr(cx, lstr), nrstr(cx, rstr);
|
||||
str = ConcatStrings<CanGC>(cx, nlstr, nrstr);
|
||||
if (!str)
|
||||
return false;
|
||||
}
|
||||
if (lIsObject || rIsObject)
|
||||
types::TypeScript::MonitorString(cx, script, pc);
|
||||
res->setString(str);
|
||||
} else {
|
||||
double l, r;
|
||||
if (!ToNumber(cx, lhs, &l) || !ToNumber(cx, rhs, &r))
|
||||
return false;
|
||||
l += r;
|
||||
Value nres = NumberValue(l);
|
||||
if (nres.isDouble() &&
|
||||
(lIsObject || rIsObject || (!lhs.isDouble() && !rhs.isDouble()))) {
|
||||
types::TypeScript::MonitorOverflow(cx, script, pc);
|
||||
}
|
||||
*res = nres;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
SubOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue 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, script, pc);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
MulOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue 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, script, pc);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
DivOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue 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, script, pc);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
ModOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue 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;
|
||||
|
||||
res->setNumber(NumberMod(d1, d2));
|
||||
types::TypeScript::MonitorOverflow(cx, script, pc);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
NegOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue val,
|
||||
MutableHandleValue res)
|
||||
@ -690,39 +498,6 @@ GetElementOperation(JSContext *cx, JSOp op, MutableHandleValue lref, HandleValue
|
||||
return GetObjectElementOperation(cx, op, obj, isObject, rref, res);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
SetObjectElementOperation(JSContext *cx, Handle<JSObject*> obj, HandleId id, const Value &value,
|
||||
bool strict, JSScript *maybeScript = NULL, jsbytecode *pc = NULL)
|
||||
{
|
||||
RootedScript script(cx, maybeScript);
|
||||
types::TypeScript::MonitorAssign(cx, obj, id);
|
||||
|
||||
if (obj->isNative() && JSID_IS_INT(id)) {
|
||||
uint32_t length = obj->getDenseInitializedLength();
|
||||
int32_t i = JSID_TO_INT(id);
|
||||
if ((uint32_t)i >= length) {
|
||||
// In an Ion activation, GetPcScript won't work. For non-baseline activations,
|
||||
// that's ok, because optimized ion doesn't generate analysis info. However,
|
||||
// baseline must generate this information, so it passes the script and pc in
|
||||
// as arguments.
|
||||
if (script || cx->currentlyRunningInInterpreter()) {
|
||||
JS_ASSERT(!!script == !!pc);
|
||||
if (!script)
|
||||
types::TypeScript::GetPcScript(cx, script.address(), &pc);
|
||||
|
||||
if (script->hasAnalysis())
|
||||
script->analysis()->getCode(pc).arrayWriteHole = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (obj->isNative() && !obj->setHadElementsAccess(cx))
|
||||
return false;
|
||||
|
||||
RootedValue tmp(cx, value);
|
||||
return JSObject::setGeneric(cx, obj, obj, id, &tmp, strict);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSString *
|
||||
TypeOfOperation(JSContext *cx, HandleValue v)
|
||||
{
|
||||
|
@ -1063,6 +1063,216 @@ FrameGuard::~FrameGuard()
|
||||
stack_->releaseFrame(fp_);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the implicit |this| parameter for a call expression where the callee
|
||||
* funval was resolved from an unqualified name reference to a property on obj
|
||||
* (an object on the scope chain).
|
||||
*
|
||||
* We can avoid computing |this| eagerly and push the implicit callee-coerced
|
||||
* |this| value, undefined, if any of these conditions hold:
|
||||
*
|
||||
* 1. The nominal |this|, obj, is a global object.
|
||||
*
|
||||
* 2. The nominal |this|, obj, has one of Block, Call, or DeclEnv class (this
|
||||
* is what IsCacheableNonGlobalScope tests). Such objects-as-scopes must be
|
||||
* censored with undefined.
|
||||
*
|
||||
* Otherwise, we bind |this| to obj->thisObject(). Only names inside |with|
|
||||
* statements and embedding-specific scope objects fall into this category.
|
||||
*
|
||||
* If the callee is a strict mode function, then code implementing JSOP_THIS
|
||||
* in the interpreter and JITs will leave undefined as |this|. If funval is a
|
||||
* function not in strict mode, JSOP_THIS code replaces undefined with funval's
|
||||
* global.
|
||||
*
|
||||
* We set *vp to undefined early to reduce code size and bias this code for the
|
||||
* common and future-friendly cases.
|
||||
*/
|
||||
inline bool
|
||||
ComputeImplicitThis(JSContext *cx, HandleObject obj, MutableHandleValue vp)
|
||||
{
|
||||
vp.setUndefined();
|
||||
|
||||
if (obj->is<GlobalObject>())
|
||||
return true;
|
||||
|
||||
if (IsCacheableNonGlobalScope(obj))
|
||||
return true;
|
||||
|
||||
JSObject *nobj = JSObject::thisObject(cx, obj);
|
||||
if (!nobj)
|
||||
return false;
|
||||
|
||||
vp.setObject(*nobj);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
AddOperation(JSContext *cx, HandleScript script, jsbytecode *pc,
|
||||
MutableHandleValue lhs, MutableHandleValue rhs, Value *res)
|
||||
{
|
||||
if (lhs.isInt32() && rhs.isInt32()) {
|
||||
int32_t l = lhs.toInt32(), r = rhs.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, script, pc);
|
||||
} else {
|
||||
res->setInt32(sum);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If either operand is an object, any non-integer result must be
|
||||
* reported to inference.
|
||||
*/
|
||||
bool lIsObject = lhs.isObject(), rIsObject = rhs.isObject();
|
||||
|
||||
if (!ToPrimitive(cx, lhs))
|
||||
return false;
|
||||
if (!ToPrimitive(cx, rhs))
|
||||
return false;
|
||||
bool lIsString, rIsString;
|
||||
if ((lIsString = lhs.isString()) | (rIsString = rhs.isString())) {
|
||||
JSString *lstr, *rstr;
|
||||
if (lIsString) {
|
||||
lstr = lhs.toString();
|
||||
} else {
|
||||
lstr = ToString<CanGC>(cx, lhs);
|
||||
if (!lstr)
|
||||
return false;
|
||||
}
|
||||
if (rIsString) {
|
||||
rstr = rhs.toString();
|
||||
} else {
|
||||
// Save/restore lstr in case of GC activity under ToString.
|
||||
lhs.setString(lstr);
|
||||
rstr = ToString<CanGC>(cx, rhs);
|
||||
if (!rstr)
|
||||
return false;
|
||||
lstr = lhs.toString();
|
||||
}
|
||||
JSString *str = ConcatStrings<NoGC>(cx, lstr, rstr);
|
||||
if (!str) {
|
||||
RootedString nlstr(cx, lstr), nrstr(cx, rstr);
|
||||
str = ConcatStrings<CanGC>(cx, nlstr, nrstr);
|
||||
if (!str)
|
||||
return false;
|
||||
}
|
||||
if (lIsObject || rIsObject)
|
||||
types::TypeScript::MonitorString(cx, script, pc);
|
||||
res->setString(str);
|
||||
} else {
|
||||
double l, r;
|
||||
if (!ToNumber(cx, lhs, &l) || !ToNumber(cx, rhs, &r))
|
||||
return false;
|
||||
l += r;
|
||||
Value nres = NumberValue(l);
|
||||
if (nres.isDouble() &&
|
||||
(lIsObject || rIsObject || (!lhs.isDouble() && !rhs.isDouble()))) {
|
||||
types::TypeScript::MonitorOverflow(cx, script, pc);
|
||||
}
|
||||
*res = nres;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
SubOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue 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, script, pc);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
MulOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue 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, script, pc);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
DivOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue 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, script, pc);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
ModOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue 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;
|
||||
|
||||
res->setNumber(NumberMod(d1, d2));
|
||||
types::TypeScript::MonitorOverflow(cx, script, pc);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
SetObjectElementOperation(JSContext *cx, Handle<JSObject*> obj, HandleId id, const Value &value,
|
||||
bool strict, JSScript *maybeScript = NULL, jsbytecode *pc = NULL)
|
||||
{
|
||||
RootedScript script(cx, maybeScript);
|
||||
types::TypeScript::MonitorAssign(cx, obj, id);
|
||||
|
||||
if (obj->isNative() && JSID_IS_INT(id)) {
|
||||
uint32_t length = obj->getDenseInitializedLength();
|
||||
int32_t i = JSID_TO_INT(id);
|
||||
if ((uint32_t)i >= length) {
|
||||
// In an Ion activation, GetPcScript won't work. For non-baseline activations,
|
||||
// that's ok, because optimized ion doesn't generate analysis info. However,
|
||||
// baseline must generate this information, so it passes the script and pc in
|
||||
// as arguments.
|
||||
if (script || cx->currentlyRunningInInterpreter()) {
|
||||
JS_ASSERT(!!script == !!pc);
|
||||
if (!script)
|
||||
types::TypeScript::GetPcScript(cx, script.address(), &pc);
|
||||
|
||||
if (script->hasAnalysis())
|
||||
script->analysis()->getCode(pc).arrayWriteHole = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (obj->isNative() && !obj->setHadElementsAccess(cx))
|
||||
return false;
|
||||
|
||||
RootedValue tmp(cx, value);
|
||||
return JSObject::setGeneric(cx, obj, obj, id, &tmp, strict);
|
||||
}
|
||||
|
||||
static JS_NEVER_INLINE bool
|
||||
Interpret(JSContext *cx, RunState &state)
|
||||
{
|
||||
|
@ -350,8 +350,11 @@ class InterpreterFrames {
|
||||
~InterpreterFrames();
|
||||
|
||||
/* If this js::Interpret frame is running |script|, enable interrupts. */
|
||||
inline void enableInterruptsIfRunning(JSScript *script);
|
||||
inline void enableInterruptsUnconditionally() { enabler.enable(); }
|
||||
void enableInterruptsIfRunning(JSScript *script) {
|
||||
if (regs->fp()->script() == script)
|
||||
enabler.enable();
|
||||
}
|
||||
void enableInterruptsUnconditionally() { enabler.enable(); }
|
||||
|
||||
InterpreterFrames *older;
|
||||
|
||||
@ -509,6 +512,14 @@ bool
|
||||
InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandleValue idval,
|
||||
HandleValue val);
|
||||
|
||||
inline bool
|
||||
SetConstOperation(JSContext *cx, HandleObject varobj, HandlePropertyName name, HandleValue rval)
|
||||
{
|
||||
return JSObject::defineProperty(cx, varobj, name, rval,
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY);
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* vm_Interpreter_h */
|
||||
|
Loading…
Reference in New Issue
Block a user