Bug 914132 part 3 - Inline |typeof object| if the input is known to be non-callable and does not emulate undefined. r=bhackett

This commit is contained in:
Jan de Mooij 2013-09-10 16:17:06 +02:00
parent dd0f1d0dfb
commit 3b7924fcb9
6 changed files with 86 additions and 11 deletions

View File

@ -6433,17 +6433,27 @@ CodeGenerator::visitTypeOfV(LTypeOfV *lir)
Register output = ToRegister(lir->output());
Register tag = masm.splitTagForTest(value);
OutOfLineTypeOfV *ool = new OutOfLineTypeOfV(lir);
JSRuntime *rt = GetIonContext()->runtime;
Label done;
OutOfLineTypeOfV *ool = NULL;
if (lir->mir()->inputMaybeCallableOrEmulatesUndefined()) {
// The input may be a callable object (result is "function") or may
// emulate undefined (result is "undefined"). Use an OOL path.
ool = new OutOfLineTypeOfV(lir);
if (!addOutOfLineCode(ool))
return false;
JSRuntime *rt = GetIonContext()->runtime;
// Jump to the OOL path if the value is an object. Objects are complicated
// since they may have a typeof hook.
masm.branchTestObject(Assembler::Equal, tag, ool->entry());
Label done;
} else {
// Input is not callable and does not emulate undefined, so if
// it's an object the result is always "object".
Label notObject;
masm.branchTestObject(Assembler::NotEqual, tag, &notObject);
masm.movePtr(ImmGCPtr(rt->atomState.object), output);
masm.jump(&done);
masm.bind(&notObject);
}
Label notNumber;
masm.branchTestNumber(Assembler::NotEqual, tag, &notNumber);
@ -6472,6 +6482,7 @@ CodeGenerator::visitTypeOfV(LTypeOfV *lir)
masm.movePtr(ImmGCPtr(rt->atomState.string), output);
masm.bind(&done);
if (ool)
masm.bind(ool->rejoin());
return true;
}

View File

@ -8934,6 +8934,8 @@ IonBuilder::jsop_typeof()
MDefinition *input = current->pop();
MTypeOf *ins = MTypeOf::New(input, input->type());
ins->infer(cx);
current->add(ins);
current->push(ins);

View File

@ -215,6 +215,19 @@ MaybeEmulatesUndefined(JSContext *cx, MDefinition *op)
return types->hasObjectFlags(cx, types::OBJECT_FLAG_EMULATES_UNDEFINED);
}
static bool
MaybeCallable(JSContext *cx, MDefinition *op)
{
if (!op->mightBeType(MIRType_Object))
return false;
types::StackTypeSet *types = op->resultTypeSet();
if (!types)
return true;
return types->maybeCallable();
}
void
MTest::infer(JSContext *cx)
{
@ -1883,6 +1896,15 @@ MTypeOf::foldsTo(bool useValueNumbers)
return MConstant::New(StringValue(TypeName(type, rt)));
}
void
MTypeOf::infer(JSContext *cx)
{
JS_ASSERT(inputMaybeCallableOrEmulatesUndefined());
if (!MaybeEmulatesUndefined(cx, input()) && !MaybeCallable(cx, input()))
markInputNotCallableOrEmulatesUndefined();
}
MBitAnd *
MBitAnd::New(MDefinition *left, MDefinition *right)
{

View File

@ -2895,9 +2895,11 @@ class MTypeOf
public BoxInputsPolicy
{
MIRType inputType_;
bool inputMaybeCallableOrEmulatesUndefined_;
MTypeOf(MDefinition *def, MIRType inputType)
: MUnaryInstruction(def), inputType_(inputType)
: MUnaryInstruction(def), inputType_(inputType),
inputMaybeCallableOrEmulatesUndefined_(true)
{
setResultType(MIRType_String);
setMovable();
@ -2916,7 +2918,16 @@ class MTypeOf
MIRType inputType() const {
return inputType_;
}
MDefinition *foldsTo(bool useValueNumbers);
void infer(JSContext *cx);
bool inputMaybeCallableOrEmulatesUndefined() const {
return inputMaybeCallableOrEmulatesUndefined_;
}
void markInputNotCallableOrEmulatesUndefined() {
inputMaybeCallableOrEmulatesUndefined_ = false;
}
AliasSet getAliasSet() const {
return AliasSet::None();

View File

@ -1106,6 +1106,32 @@ StackTypeSet::isDOMClass()
return true;
}
bool
StackTypeSet::maybeCallable()
{
if (!maybeObject())
return false;
if (unknownObject())
return true;
unsigned count = getObjectCount();
for (unsigned i = 0; i < count; i++) {
Class *clasp;
if (JSObject *object = getSingleObject(i))
clasp = object->getClass();
else if (TypeObject *object = getTypeObject(i))
clasp = object->clasp;
else
continue;
if (clasp->isCallable())
return true;
}
return false;
}
JSObject *
StackTypeSet::getCommonPrototype()
{

View File

@ -625,6 +625,9 @@ class StackTypeSet : public TypeSet
/* Whether all objects have JSCLASS_IS_DOMJSCLASS set. */
bool isDOMClass();
/* Whether clasp->isCallable() is true for one or more objects in this set. */
bool maybeCallable();
/* Get the single value which can appear in this type set, otherwise NULL. */
JSObject *getSingleton();