Bug 953114 - Fix GetElementIC typed array issue. r=efaust
authorJan de Mooij <jdemooij@mozilla.com>
Sat, 04 Jan 2014 13:32:35 +0100
changeset 162161 91a585e70f2851e73c62679823a6e24eefdee9b1
parent 162160 5e992c8ea14f9146e31e6b684fc2f79431c552dd
child 162162 d4757785001e996f078f1ca1a7eeb3f20913c820
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersefaust
bugs953114
milestone29.0a1
Bug 953114 - Fix GetElementIC typed array issue. r=efaust
js/src/jit/CodeGenerator.cpp
js/src/jit/CodeGenerator.h
js/src/jit/IonCaches.cpp
js/src/jit/IonCaches.h
js/src/jit/MIR.cpp
js/src/jit/MIR.h
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -6505,51 +6505,54 @@ CodeGenerator::visitGetPropertyParIC(Out
     restoreLiveIgnore(lir, StoreValueTo(ic->output()).clobbered());
 
     masm.jump(ool->rejoin());
     return true;
 }
 
 bool
 CodeGenerator::addGetElementCache(LInstruction *ins, Register obj, ConstantOrRegister index,
-                                  TypedOrValueRegister output, bool monitoredResult)
+                                  TypedOrValueRegister output, bool monitoredResult,
+                                  bool allowDoubleResult)
 {
     switch (gen->info().executionMode()) {
       case SequentialExecution: {
         RegisterSet liveRegs = ins->safepoint()->liveRegs();
-        GetElementIC cache(liveRegs, obj, index, output, monitoredResult);
+        GetElementIC cache(liveRegs, obj, index, output, monitoredResult, allowDoubleResult);
         return addCache(ins, allocateCache(cache));
       }
       case ParallelExecution: {
-        GetElementParIC cache(obj, index, output, monitoredResult);
+        GetElementParIC cache(obj, index, output, monitoredResult, allowDoubleResult);
         return addCache(ins, allocateCache(cache));
       }
       default:
         MOZ_ASSUME_UNREACHABLE("No such execution mode");
     }
 }
 
 bool
 CodeGenerator::visitGetElementCacheV(LGetElementCacheV *ins)
 {
     Register obj = ToRegister(ins->object());
     ConstantOrRegister index = TypedOrValueRegister(ToValue(ins, LGetElementCacheV::Index));
     TypedOrValueRegister output = TypedOrValueRegister(GetValueOutput(ins));
-
-    return addGetElementCache(ins, obj, index, output, ins->mir()->monitoredResult());
+    const MGetElementCache *mir = ins->mir();
+
+    return addGetElementCache(ins, obj, index, output, mir->monitoredResult(), mir->allowDoubleResult());
 }
 
 bool
 CodeGenerator::visitGetElementCacheT(LGetElementCacheT *ins)
 {
     Register obj = ToRegister(ins->object());
     ConstantOrRegister index = TypedOrValueRegister(MIRType_Int32, ToAnyRegister(ins->index()));
     TypedOrValueRegister output(ins->mir()->type(), ToAnyRegister(ins->output()));
-
-    return addGetElementCache(ins, obj, index, output, ins->mir()->monitoredResult());
+    const MGetElementCache *mir = ins->mir();
+
+    return addGetElementCache(ins, obj, index, output, mir->monitoredResult(), mir->allowDoubleResult());
 }
 
 typedef bool (*GetElementICFn)(JSContext *, size_t, HandleObject, HandleValue, MutableHandleValue);
 const VMFunction GetElementIC::UpdateInfo =
     FunctionInfo<GetElementICFn>(GetElementIC::update);
 
 bool
 CodeGenerator::visitGetElementIC(OutOfLineUpdateCache *ool, DataPtr<GetElementIC> &ic)
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -340,17 +340,18 @@ class CodeGenerator : public CodeGenerat
         return counts;
     }
 
   private:
     bool addGetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
                              PropertyName *name, TypedOrValueRegister output,
                              bool allowGetters);
     bool addGetElementCache(LInstruction *ins, Register obj, ConstantOrRegister index,
-                            TypedOrValueRegister output, bool monitoredResult);
+                            TypedOrValueRegister output, bool monitoredResult,
+                            bool allowDoubleResult);
     bool addSetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
                              PropertyName *name, ConstantOrRegister value, bool strict,
                              bool needsTypeBarrier);
     bool addSetElementCache(LInstruction *ins, Register obj, Register unboxIndex, Register temp,
                             FloatRegister tempFloat, ValueOperand index, ConstantOrRegister value,
                             bool strict, bool guardHoles);
     bool checkForAbortPar(LInstruction *lir);
 
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -3160,26 +3160,31 @@ GetElementIC::canAttachTypedArrayElement
         if (index == UINT32_MAX)
             return false;
     }
     if (index >= obj->as<TypedArrayObject>().length())
         return false;
 
     // The output register is not yet specialized as a float register, the only
     // way to accept float typed arrays for now is to return a Value type.
-    int arrayType = obj->as<TypedArrayObject>().type();
-    bool floatOutput = arrayType == ScalarTypeRepresentation::TYPE_FLOAT32 ||
-                       arrayType == ScalarTypeRepresentation::TYPE_FLOAT64;
-    return !floatOutput || output.hasValue();
+    uint32_t arrayType = obj->as<TypedArrayObject>().type();
+    if (arrayType == ScalarTypeRepresentation::TYPE_FLOAT32 ||
+        arrayType == ScalarTypeRepresentation::TYPE_FLOAT64)
+    {
+        return output.hasValue();
+    }
+
+    return output.hasValue() || !output.typedReg().isFloat();
 }
 
 static void
 GenerateGetTypedArrayElement(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
                              TypedArrayObject *tarr, const Value &idval, Register object,
-                             ConstantOrRegister index, TypedOrValueRegister output)
+                             ConstantOrRegister index, TypedOrValueRegister output,
+                             bool allowDoubleResult)
 {
     JS_ASSERT(GetElementIC::canAttachTypedArrayElement(tarr, idval, output));
 
     Label failures;
 
     // The array type is the object within the table of typed array classes.
     int arrayType = tarr->type();
 
@@ -3251,22 +3256,22 @@ GenerateGetTypedArrayElement(JSContext *
 
     // Load elements vector.
     masm.loadPtr(Address(object, TypedArrayObject::dataOffset()), elementReg);
 
     // Load the value. We use an invalid register because the destination
     // register is necessary a non double register.
     int width = TypedArrayObject::slotWidth(arrayType);
     BaseIndex source(elementReg, indexReg, ScaleFromElemWidth(width));
-    if (output.hasValue())
-        masm.loadFromTypedArray(arrayType, source, output.valueReg(), true,
+    if (output.hasValue()) {
+        masm.loadFromTypedArray(arrayType, source, output.valueReg(), allowDoubleResult,
                                 elementReg, &popAndFail);
-    else
-        masm.loadFromTypedArray(arrayType, source, output.typedReg(),
-                                elementReg, &popAndFail);
+    } else {
+        masm.loadFromTypedArray(arrayType, source, output.typedReg(), elementReg, &popAndFail);
+    }
 
     masm.pop(object);
     attacher.jumpRejoin(masm);
 
     // Restore the object before continuing to the next stub.
     masm.bind(&popAndFail);
     masm.pop(object);
     masm.bind(&failures);
@@ -3275,17 +3280,18 @@ GenerateGetTypedArrayElement(JSContext *
 }
 
 bool
 GetElementIC::attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr,
                                       const Value &idval)
 {
     MacroAssembler masm(cx, ion);
     RepatchStubAppender attacher(*this);
-    GenerateGetTypedArrayElement(cx, masm, attacher, tarr, idval, object(), index(), output());
+    GenerateGetTypedArrayElement(cx, masm, attacher, tarr, idval, object(), index(), output(),
+                                 allowDoubleResult());
     return linkAndAttachStub(cx, masm, attacher, ion, "typed array");
 }
 
 bool
 GetElementIC::attachArgumentsElement(JSContext *cx, IonScript *ion, JSObject *obj)
 {
     JS_ASSERT(obj->is<ArgumentsObject>());
 
@@ -3870,17 +3876,18 @@ GetElementParIC::attachDenseElement(Lock
 }
 
 bool
 GetElementParIC::attachTypedArrayElement(LockedJSContext &cx, IonScript *ion,
                                          TypedArrayObject *tarr, const Value &idval)
 {
     MacroAssembler masm(cx, ion);
     DispatchStubPrepender attacher(*this);
-    GenerateGetTypedArrayElement(cx, masm, attacher, tarr, idval, object(), index(), output());
+    GenerateGetTypedArrayElement(cx, masm, attacher, tarr, idval, object(), index(), output(),
+                                 allowDoubleResult());
     return linkAndAttachStub(cx, masm, attacher, ion, "parallel typed array");
 }
 
 bool
 GetElementParIC::update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj,
                         HandleValue idval, MutableHandleValue vp)
 {
     AutoFlushCache afc("GetElementParCache", slice->runtime()->jitRuntime());
--- a/js/src/jit/IonCaches.h
+++ b/js/src/jit/IonCaches.h
@@ -707,32 +707,34 @@ class GetElementIC : public RepatchIonCa
   protected:
     RegisterSet liveRegs_;
 
     Register object_;
     ConstantOrRegister index_;
     TypedOrValueRegister output_;
 
     bool monitoredResult_ : 1;
+    bool allowDoubleResult_ : 1;
     bool hasDenseStub_ : 1;
     bool hasStrictArgumentsStub_ : 1;
     bool hasNormalArgumentsStub_ : 1;
 
     size_t failedUpdates_;
 
     static const size_t MAX_FAILED_UPDATES;
 
   public:
     GetElementIC(RegisterSet liveRegs, Register object, ConstantOrRegister index,
-                 TypedOrValueRegister output, bool monitoredResult)
+                 TypedOrValueRegister output, bool monitoredResult, bool allowDoubleResult)
       : liveRegs_(liveRegs),
         object_(object),
         index_(index),
         output_(output),
         monitoredResult_(monitoredResult),
+        allowDoubleResult_(allowDoubleResult),
         hasDenseStub_(false),
         hasStrictArgumentsStub_(false),
         hasNormalArgumentsStub_(false),
         failedUpdates_(0)
     {
     }
 
     CACHE_HEADER(GetElement)
@@ -746,16 +748,19 @@ class GetElementIC : public RepatchIonCa
         return index_;
     }
     TypedOrValueRegister output() const {
         return output_;
     }
     bool monitoredResult() const {
         return monitoredResult_;
     }
+    bool allowDoubleResult() const {
+        return allowDoubleResult_;
+    }
     bool hasDenseStub() const {
         return hasDenseStub_;
     }
     bool hasArgumentsStub(bool strict) const {
         return strict ? hasStrictArgumentsStub_ : hasNormalArgumentsStub_;
     }
     void setHasDenseStub() {
         JS_ASSERT(!hasDenseStub());
@@ -1071,24 +1076,26 @@ class GetPropertyParIC : public Parallel
 class GetElementParIC : public ParallelIonCache
 {
   protected:
     Register object_;
     ConstantOrRegister index_;
     TypedOrValueRegister output_;
 
     bool monitoredResult_ : 1;
+    bool allowDoubleResult_ : 1;
 
   public:
     GetElementParIC(Register object, ConstantOrRegister index,
-                    TypedOrValueRegister output, bool monitoredResult)
+                    TypedOrValueRegister output, bool monitoredResult, bool allowDoubleResult)
       : object_(object),
         index_(index),
         output_(output),
-        monitoredResult_(monitoredResult)
+        monitoredResult_(monitoredResult),
+        allowDoubleResult_(allowDoubleResult)
     {
     }
 
     CACHE_HEADER(GetElementPar)
 
 #ifdef JS_CPU_X86
     // x86 lacks a general purpose scratch register for dispatch caches and
     // must be given one manually.
@@ -1102,16 +1109,19 @@ class GetElementParIC : public ParallelI
         return index_;
     }
     TypedOrValueRegister output() const {
         return output_;
     }
     bool monitoredResult() const {
         return monitoredResult_;
     }
+    bool allowDoubleResult() const {
+        return allowDoubleResult_;
+    }
 
     // CanAttachNativeGetProp Helpers
     typedef LockedJSContext & Context;
     bool canMonitorSingletonUndefinedSlot(HandleObject, HandleShape) const { return true; }
     bool allowGetters() const { return false; }
     bool allowArrayLength(Context, HandleObject) const { return false; }
 
     bool attachReadSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, const Value &idval,
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -2658,16 +2658,25 @@ MLoadTypedArrayElementStatic::length() c
 }
 
 void *
 MStoreTypedArrayElementStatic::base() const
 {
     return typedArray_->viewData();
 }
 
+bool
+MGetElementCache::allowDoubleResult() const
+{
+    if (!resultTypeSet())
+        return true;
+
+    return resultTypeSet()->hasType(types::Type::DoubleType());
+}
+
 size_t
 MStoreTypedArrayElementStatic::length() const
 {
     return typedArray_->byteLength();
 }
 
 bool
 MGetPropertyPolymorphic::mightAlias(MDefinition *store)
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -6894,16 +6894,19 @@ class MGetElementCache
         return getOperand(0);
     }
     MDefinition *index() const {
         return getOperand(1);
     }
     bool monitoredResult() const {
         return monitoredResult_;
     }
+
+    bool allowDoubleResult() const;
+
     TypePolicy *typePolicy() {
         if (type() == MIRType_Value)
             return &PolicyV;
         return &PolicyT;
     }
 };
 
 class MBindNameCache