Bug 914132 part 3 - Inline |typeof object| if the input is known to be non-callable and does not emulate undefined. r=bhackett
authorJan de Mooij <jdemooij@mozilla.com>
Tue, 10 Sep 2013 16:17:06 +0200
changeset 146413 8c452ca6d4165f69c4dc0901fc6bf9753e58afb2
parent 146412 61824642543ad2d21365f8a8e368686f452f9f69
child 146414 e112a8245e294e13071e95d8fd06e29620f49c52
push id25260
push userryanvm@gmail.com
push dateWed, 11 Sep 2013 00:29:30 +0000
treeherdermozilla-central@f73bed2856a8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs914132
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 914132 part 3 - Inline |typeof object| if the input is known to be non-callable and does not emulate undefined. r=bhackett
js/src/jit/CodeGenerator.cpp
js/src/jit/IonBuilder.cpp
js/src/jit/MIR.cpp
js/src/jit/MIR.h
js/src/jsinfer.cpp
js/src/jsinfer.h
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -6428,28 +6428,38 @@ class OutOfLineTypeOfV : public OutOfLin
 
 bool
 CodeGenerator::visitTypeOfV(LTypeOfV *lir)
 {
     const ValueOperand value = ToValue(lir, LTypeOfV::Input);
     Register output = ToRegister(lir->output());
     Register tag = masm.splitTagForTest(value);
 
-    OutOfLineTypeOfV *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;
 
+    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;
+
+        masm.branchTestObject(Assembler::Equal, tag, ool->entry());
+    } 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);
     masm.movePtr(ImmGCPtr(rt->atomState.number), output);
     masm.jump(&done);
     masm.bind(&notNumber);
 
     Label notUndefined;
     masm.branchTestUndefined(Assembler::NotEqual, tag, &notUndefined);
@@ -6467,17 +6477,18 @@ CodeGenerator::visitTypeOfV(LTypeOfV *li
     masm.branchTestBoolean(Assembler::NotEqual, tag, &notBoolean);
     masm.movePtr(ImmGCPtr(rt->atomState.boolean), output);
     masm.jump(&done);
     masm.bind(&notBoolean);
 
     masm.movePtr(ImmGCPtr(rt->atomState.string), output);
 
     masm.bind(&done);
-    masm.bind(ool->rejoin());
+    if (ool)
+        masm.bind(ool->rejoin());
     return true;
 }
 
 bool
 CodeGenerator::visitOutOfLineTypeOfV(OutOfLineTypeOfV *ool)
 {
     LTypeOfV *ins = ool->ins();
 
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -8929,16 +8929,18 @@ IonBuilder::jsop_this()
 }
 
 bool
 IonBuilder::jsop_typeof()
 {
     MDefinition *input = current->pop();
     MTypeOf *ins = MTypeOf::New(input, input->type());
 
+    ins->infer(cx);
+
     current->add(ins);
     current->push(ins);
 
     return true;
 }
 
 bool
 IonBuilder::jsop_toid()
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -210,16 +210,29 @@ MaybeEmulatesUndefined(JSContext *cx, MD
     if (!types)
         return true;
 
     if (!types->maybeObject())
         return false;
     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)
 {
     JS_ASSERT(operandMightEmulateUndefined());
 
     if (!MaybeEmulatesUndefined(cx, getOperand(0)))
         markOperandCantEmulateUndefined();
 }
@@ -1878,16 +1891,25 @@ MTypeOf::foldsTo(bool useValueNumbers)
       default:
         return this;
     }
 
     JSRuntime *rt = GetIonContext()->runtime;
     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)
 {
     return new MBitAnd(left, right);
 }
 
 MBitAnd *
 MBitAnd::NewAsmJS(MDefinition *left, MDefinition *right)
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -2890,19 +2890,21 @@ class MBitNot
     void computeRange();
 };
 
 class MTypeOf
   : public MUnaryInstruction,
     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();
     }
 
   public:
     INSTRUCTION_HEADER(TypeOf)
 
@@ -2911,17 +2913,26 @@ class MTypeOf
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
     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();
     }
 };
 
 class MToId
   : public MBinaryInstruction,
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -1101,16 +1101,42 @@ StackTypeSet::isDOMClass()
 
         if (!(clasp->flags & JSCLASS_IS_DOMJSCLASS))
             return false;
     }
 
     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()
 {
     if (unknownObject())
         return NULL;
 
     JSObject *proto = NULL;
     unsigned count = getObjectCount();
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -620,16 +620,19 @@ class StackTypeSet : public TypeSet
     JSObject *getCommonPrototype();
 
     /* Get the typed array type of all objects in this set, or TypedArrayObject::TYPE_MAX. */
     int getTypedArrayType();
 
     /* 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();
 
     /* Whether any objects in the type set needs a barrier on id. */
     bool propertyNeedsBarrier(JSContext *cx, jsid id);
 
     /*
      * Whether this set contains all types in other, except (possibly) the