Bug 799818 part 3 - Guard for strings when inlining known constants. r=jandem
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Fri, 19 Oct 2012 16:45:18 -0700
changeset 110966 9e4c7538d6a96b42da832fff0209aaaf16d7c6a7
parent 110965 e70b2e6a920777160858b9d105a89949af221a1f
child 110967 9af9ca79f02667fa7e4927f33283a3e1666ae366
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersjandem
bugs799818
milestone19.0a1
Bug 799818 part 3 - Guard for strings when inlining known constants. r=jandem
js/src/ion/IonBuilder.cpp
js/src/ion/Lowering.cpp
js/src/ion/Lowering.h
js/src/ion/MIR.h
js/src/ion/MOpcodes.h
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -4413,24 +4413,26 @@ TestSingletonProperty(JSContext *cx, Han
 
     *isKnownConstant = true;
     return true;
 }
 
 static inline bool
 TestSingletonPropertyTypes(JSContext *cx, types::StackTypeSet *types,
                            HandleObject globalObj, HandleId id,
-                           bool *isKnownConstant, bool *testObject)
+                           bool *isKnownConstant, bool *testObject,
+                           bool *testString)
 {
     // As for TestSingletonProperty, but the input is any value in a type set
     // rather than a specific object. If testObject is set then the constant
     // result can only be used after ensuring the input is an object.
 
     *isKnownConstant = false;
     *testObject = false;
+    *testString = false;
 
     if (!types || types->unknownObject())
         return true;
 
     RootedObject singleton(cx, types->getSingleton());
     if (singleton)
         return TestSingletonProperty(cx, singleton, id, isKnownConstant);
 
@@ -4450,16 +4452,25 @@ TestSingletonPropertyTypes(JSContext *cx
         break;
 
       case JSVAL_TYPE_BOOLEAN:
         key = JSProto_Boolean;
         break;
 
       case JSVAL_TYPE_OBJECT:
       case JSVAL_TYPE_UNKNOWN: {
+        if (types->hasType(types::Type::StringType())) {
+            // Do not optimize if the object is either a String or an Object.
+            if (types->maybeObject())
+                return true;
+            key = JSProto_String;
+            *testString = true;
+            break;
+        }
+
         // For property accesses which may be on many objects, we just need to
         // find a prototype common to all the objects; if that prototype
         // has the singleton property, the access will not be on a missing property.
         bool thoughtConstant = true;
         for (unsigned i = 0; i < types->getObjectCount(); i++) {
             types::TypeObject *object = types->getTypeObject(i);
             if (!object) {
                 // Try to get it through the singleton.
@@ -5879,28 +5890,32 @@ IonBuilder::getPropTryConstant(bool *emi
 {
     JS_ASSERT(*emitted == false);
     JSObject *singleton = types ? types->getSingleton() : NULL;
     if (!singleton || barrier)
         return true;
 
     RootedObject global(cx, &script_->global());
 
-    bool isConstant, testObject;
-    if (!TestSingletonPropertyTypes(cx, unaryTypes.inTypes, global, id, &isConstant, &testObject))
+    bool isConstant, testObject, testString;
+    if (!TestSingletonPropertyTypes(cx, unaryTypes.inTypes, global, id,
+                                    &isConstant, &testObject, &testString))
         return false;
 
     if (!isConstant)
         return true;
 
     MDefinition *obj = current->pop();
 
     // Property access is a known constant -- safe to emit.
+	JS_ASSERT(!testString || !testObject);
     if (testObject)
         current->add(MGuardObject::New(obj));
+	else if (testString)
+        current->add(MGuardString::New(obj));
 
     MConstant *known = MConstant::New(ObjectValue(*singleton));
     if (singleton->isFunction()) {
         RootedFunction singletonFunc(cx, singleton->toFunction());
         if (TestAreKnownDOMTypes(cx, unaryTypes.inTypes) &&
             TestShouldDOMCall(cx, unaryTypes.inTypes, singletonFunc))
         {
             FreezeDOMTypes(cx, unaryTypes.inTypes);
--- a/js/src/ion/Lowering.cpp
+++ b/js/src/ion/Lowering.cpp
@@ -1714,16 +1714,25 @@ LIRGenerator::visitGuardObject(MGuardObj
 {
     // The type policy does all the work, so at this point the input
     // is guaranteed to be an object.
     JS_ASSERT(ins->input()->type() == MIRType_Object);
     return redefine(ins, ins->input());
 }
 
 bool
+LIRGenerator::visitGuardString(MGuardString *ins)
+{
+    // The type policy does all the work, so at this point the input
+    // is guaranteed to be a string.
+    JS_ASSERT(ins->input()->type() == MIRType_String);
+    return redefine(ins, ins->input());
+}
+
+bool
 LIRGenerator::visitCallGetProperty(MCallGetProperty *ins)
 {
     LCallGetProperty *lir = new LCallGetProperty();
     if (!useBoxAtStart(lir, LCallGetProperty::Value, ins->value()))
         return false;
     return defineVMReturn(lir, ins) && assignSafepoint(lir, ins);
 }
 
--- a/js/src/ion/Lowering.h
+++ b/js/src/ion/Lowering.h
@@ -160,16 +160,17 @@ class LIRGenerator : public LIRGenerator
     bool visitClampToUint8(MClampToUint8 *ins);
     bool visitLoadFixedSlot(MLoadFixedSlot *ins);
     bool visitStoreFixedSlot(MStoreFixedSlot *ins);
     bool visitGetPropertyCache(MGetPropertyCache *ins);
     bool visitGetElementCache(MGetElementCache *ins);
     bool visitBindNameCache(MBindNameCache *ins);
     bool visitGuardClass(MGuardClass *ins);
     bool visitGuardObject(MGuardObject *ins);
+    bool visitGuardString(MGuardString *ins);
     bool visitCallGetProperty(MCallGetProperty *ins);
     bool visitDeleteProperty(MDeleteProperty *ins);
     bool visitGetNameCache(MGetNameCache *ins);
     bool visitCallGetElement(MCallGetElement *ins);
     bool visitCallSetElement(MCallSetElement *ins);
     bool visitSetPropertyCache(MSetPropertyCache *ins);
     bool visitCallSetProperty(MCallSetProperty *ins);
     bool visitIteratorStart(MIteratorStart *ins);
--- a/js/src/ion/MIR.h
+++ b/js/src/ion/MIR.h
@@ -1496,16 +1496,47 @@ class MGuardObject : public MUnaryInstru
     TypePolicy *typePolicy() {
         return this;
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
+class MGuardString
+  : public MUnaryInstruction,
+    public StringPolicy
+{
+    MGuardString(MDefinition *ins)
+      : MUnaryInstruction(ins)
+    {
+        setGuard();
+        setMovable();
+        setResultType(MIRType_String);
+    }
+
+  public:
+    INSTRUCTION_HEADER(GuardString);
+
+    static MGuardString *New(MDefinition *ins) {
+        return new MGuardString(ins);
+    }
+
+    MDefinition *input() const {
+        return getOperand(0);
+    }
+
+    TypePolicy *typePolicy() {
+        return this;
+    }
+    AliasSet getAliasSet() const {
+        return AliasSet::None();
+    }
+};
+
 // Caller-side allocation of |this| for |new|:
 // Given a prototype operand, construct |this| for JSOP_NEW.
 // For native constructors, returns MagicValue(JS_IS_CONSTRUCTING).
 class MCreateThis
   : public MAryInstruction<2>,
     public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >
 {
     // Template for |this|, provided by TI, or NULL.
--- a/js/src/ion/MOpcodes.h
+++ b/js/src/ion/MOpcodes.h
@@ -58,16 +58,17 @@ namespace ion {
     _(Concat)                                                               \
     _(CharCodeAt)                                                           \
     _(FromCharCode)                                                         \
     _(Return)                                                               \
     _(Throw)                                                                \
     _(Box)                                                                  \
     _(Unbox)                                                                \
     _(GuardObject)                                                          \
+    _(GuardString)                                                          \
     _(ToDouble)                                                             \
     _(ToInt32)                                                              \
     _(TruncateToInt32)                                                      \
     _(ToString)                                                             \
     _(NewSlots)                                                             \
     _(NewArray)                                                             \
     _(NewObject)                                                            \
     _(NewCallObject)                                                        \