Bug 997081 - Optimize StoreElementHole OOL VM call. r=bhackett
authorJan de Mooij <jdemooij@mozilla.com>
Wed, 16 Apr 2014 17:24:23 +0200
changeset 197321 7cfba1345851d9f3b2810e3cc54e134a3ba9e39a
parent 197320 32df543ab3c6a035d8b3a2e4cb03751d1173f275
child 197322 bfb975c73a502373bfc1da2916b633bdc89a38ea
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs997081
milestone31.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 997081 - Optimize StoreElementHole OOL VM call. r=bhackett
js/src/jit/CodeGenerator.cpp
js/src/jit/ParallelFunctions.cpp
js/src/jit/ParallelFunctions.h
js/src/jit/VMFunctions.cpp
js/src/jit/VMFunctions.h
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -5510,22 +5510,22 @@ CodeGenerator::visitStoreElementHoleV(LS
         masm.storeValue(value, Address(elements, ToInt32(lir->index()) * sizeof(js::Value)));
     else
         masm.storeValue(value, BaseIndex(elements, ToRegister(lir->index()), TimesEight));
 
     masm.bind(ool->rejoin());
     return true;
 }
 
-typedef bool (*SetObjectElementFn)(JSContext *, HandleObject, HandleValue, HandleValue,
-                                   bool strict);
-typedef bool (*SetElementParFn)(ForkJoinContext *, HandleObject, HandleValue, HandleValue, bool);
-static const VMFunctionsModal SetObjectElementInfo = VMFunctionsModal(
-    FunctionInfo<SetObjectElementFn>(SetObjectElement),
-    FunctionInfo<SetElementParFn>(SetElementPar));
+typedef bool (*SetDenseElementFn)(JSContext *, HandleObject, int32_t, HandleValue,
+                                  bool strict);
+typedef bool (*SetDenseElementParFn)(ForkJoinContext *, HandleObject, int32_t, HandleValue, bool);
+static const VMFunctionsModal SetDenseElementInfo = VMFunctionsModal(
+    FunctionInfo<SetDenseElementFn>(SetDenseElement),
+    FunctionInfo<SetDenseElementParFn>(SetDenseElementPar));
 
 bool
 CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole *ool)
 {
     Register object, elements;
     LInstruction *ins = ool->ins();
     const LAllocation *index;
     MIRType valueType;
@@ -5595,21 +5595,21 @@ CodeGenerator::visitOutOfLineStoreElemen
     }
 
     masm.bind(&callStub);
     saveLive(ins);
 
     pushArg(Imm32(current->mir()->strict()));
     pushArg(value);
     if (index->isConstant())
-        pushArg(*index->toConstant());
+        pushArg(Imm32(ToInt32(index)));
     else
-        pushArg(TypedOrValueRegister(MIRType_Int32, ToAnyRegister(index)));
+        pushArg(ToRegister(index));
     pushArg(object);
-    if (!callVM(SetObjectElementInfo, ins))
+    if (!callVM(SetDenseElementInfo, ins))
         return false;
 
     restoreLive(ins);
     masm.jump(ool->rejoin());
     return true;
 }
 
 typedef bool (*ArrayPopShiftFn)(JSContext *, HandleObject, MutableHandleValue);
@@ -6618,16 +6618,23 @@ CodeGenerator::visitCallGetElement(LCall
     if (op == JSOP_GETELEM) {
         return callVM(GetElementInfo, lir);
     } else {
         JS_ASSERT(op == JSOP_CALLELEM);
         return callVM(CallElementInfo, lir);
     }
 }
 
+typedef bool (*SetObjectElementFn)(JSContext *, HandleObject, HandleValue, HandleValue,
+                                   bool strict);
+typedef bool (*SetElementParFn)(ForkJoinContext *, HandleObject, HandleValue, HandleValue, bool);
+static const VMFunctionsModal SetObjectElementInfo = VMFunctionsModal(
+    FunctionInfo<SetObjectElementFn>(SetObjectElement),
+    FunctionInfo<SetElementParFn>(SetElementPar));
+
 bool
 CodeGenerator::visitCallSetElement(LCallSetElement *lir)
 {
     pushArg(Imm32(current->mir()->strict()));
     pushArg(ToValue(lir, LCallSetElement::Value));
     pushArg(ToValue(lir, LCallSetElement::Index));
     pushArg(ToRegister(lir->getOperand(0)));
     return callVM(SetObjectElementInfo, lir);
--- a/js/src/jit/ParallelFunctions.cpp
+++ b/js/src/jit/ParallelFunctions.cpp
@@ -271,16 +271,24 @@ jit::SetElementPar(ForkJoinContext *cx, 
     // for certain deoptimizing behaviors, such as marking having written to
     // holes and non-indexed element accesses. We don't do that here, as we
     // can't modify any TI state anyways. If we need to add a new type, we
     // would bail out.
     RootedValue v(cx, value);
     return baseops::SetPropertyHelper<ParallelExecution>(cx, obj, obj, id, 0, &v, strict);
 }
 
+bool
+jit::SetDenseElementPar(ForkJoinContext *cx, HandleObject obj, int32_t index, HandleValue value,
+                        bool strict)
+{
+    RootedValue indexVal(cx, Int32Value(index));
+    return SetElementPar(cx, obj, indexVal, value, strict);
+}
+
 JSString *
 jit::ConcatStringsPar(ForkJoinContext *cx, HandleString left, HandleString right)
 {
     return ConcatStrings<NoGC>(cx, left, right);
 }
 
 JSFlatString *
 jit::IntToStringPar(ForkJoinContext *cx, int i)
--- a/js/src/jit/ParallelFunctions.h
+++ b/js/src/jit/ParallelFunctions.h
@@ -28,16 +28,18 @@ bool InterruptCheckPar(ForkJoinContext *
 // generation.
 JSObject *ExtendArrayPar(ForkJoinContext *cx, JSObject *array, uint32_t length);
 
 // Set properties and elements on thread local objects.
 bool SetPropertyPar(ForkJoinContext *cx, HandleObject obj, HandlePropertyName name,
                     HandleValue value, bool strict, jsbytecode *pc);
 bool SetElementPar(ForkJoinContext *cx, HandleObject obj, HandleValue index,
                    HandleValue value, bool strict);
+bool SetDenseElementPar(ForkJoinContext *cx, HandleObject obj, int32_t index,
+                        HandleValue value, bool strict);
 
 // String related parallel functions. These tend to call existing VM functions
 // that take a ThreadSafeContext.
 JSString *ConcatStringsPar(ForkJoinContext *cx, HandleString left, HandleString right);
 JSFlatString *IntToStringPar(ForkJoinContext *cx, int i);
 JSString *DoubleToStringPar(ForkJoinContext *cx, double d);
 JSString *PrimitiveToStringPar(ForkJoinContext *cx, HandleValue input);
 bool StringToNumberPar(ForkJoinContext *cx, JSString *str, double *out);
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -1032,16 +1032,55 @@ Recompile(JSContext *cx)
 
     MethodStatus status = Recompile(cx, script, nullptr, nullptr, isConstructing);
     if (status == Method_Error)
         return false;
 
     return true;
 }
 
+bool
+SetDenseElement(JSContext *cx, HandleObject obj, int32_t index, HandleValue value,
+                bool strict)
+{
+    // This function is called from Ion code for StoreElementHole's OOL path.
+    // In this case we know the object is native, has no indexed properties
+    // and we can use setDenseElement instead of setDenseElementWithType.
+
+    MOZ_ASSERT(obj->isNative());
+    MOZ_ASSERT(!obj->isIndexed());
+
+    JSObject::EnsureDenseResult result = JSObject::ED_SPARSE;
+    do {
+        if (index < 0)
+            break;
+        bool isArray = obj->is<ArrayObject>();
+        if (isArray && !obj->as<ArrayObject>().lengthIsWritable())
+            break;
+        uint32_t idx = uint32_t(index);
+        result = obj->ensureDenseElements(cx, idx, 1);
+        if (result != JSObject::ED_OK)
+            break;
+        if (isArray) {
+            ArrayObject &arr = obj->as<ArrayObject>();
+            if (idx >= arr.length())
+                arr.setLengthInt32(idx + 1);
+        }
+        obj->setDenseElement(idx, value);
+        return true;
+    } while (false);
+
+    if (result == JSObject::ED_FAILED)
+        return false;
+    MOZ_ASSERT(result == JSObject::ED_SPARSE);
+
+    RootedValue indexVal(cx, Int32Value(index));
+    return SetObjectElement(cx, obj, indexVal, value, strict);
+}
+
 #ifdef DEBUG
 void
 AssertValidObjectPtr(JSContext *cx, JSObject *obj)
 {
     // Check what we can, so that we'll hopefully assert/crash if we get a
     // bogus object (pointer).
     JS_ASSERT(obj->compartment() == cx->compartment());
     JS_ASSERT(obj->runtimeFromMainThread() == cx->runtime());
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -672,16 +672,19 @@ JSObject *CreateDerivedTypedObj(JSContex
                                 HandleObject owner, int32_t offset);
 
 bool Recompile(JSContext *cx);
 JSString *RegExpReplace(JSContext *cx, HandleString string, HandleObject regexp,
                         HandleString repl);
 JSString *StringReplace(JSContext *cx, HandleString string, HandleString pattern,
                         HandleString repl);
 
+bool SetDenseElement(JSContext *cx, HandleObject obj, int32_t index, HandleValue value,
+                     bool strict);
+
 #ifdef DEBUG
 void AssertValidObjectPtr(JSContext *cx, JSObject *obj);
 void AssertValidStringPtr(JSContext *cx, JSString *str);
 void AssertValidValue(JSContext *cx, Value *v);
 #endif
 
 } // namespace jit
 } // namespace js