Bug 928423 - Fix Ion GetElementIC GetProp stub to work with non-atomized strings. r=efaust
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 24 Oct 2013 16:03:58 +0200
changeset 166738 c37138aadb0c0d5d7ddd8db9232ca5697d45f3b2
parent 166737 38414f29834c053dd4a85a8f74af88ed64e78b69
child 166739 f73cf917219c25250b0d6857369196f3c691725a
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust
bugs928423
milestone27.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 928423 - Fix Ion GetElementIC GetProp stub to work with non-atomized strings. r=efaust
js/src/jit-test/tests/ion/bug928423.js
js/src/jit/IonCaches.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug928423.js
@@ -0,0 +1,14 @@
+function f(o, p) {
+    try {} catch(e) {};
+    return o[p];
+}
+function test() {
+    var o = {foo: 1, bar: 2, foobar: 3};
+
+    for (var i = 0; i < 30; i++) {
+	assertEq(f(o, "foo1".substr(0, 3)), 1);
+	assertEq(f(o, "bar1".substr(0, 3)), 2);
+	assertEq(f(o, "foobar1".substr(0, 6)), 3);
+    }
+}
+test();
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -2977,16 +2977,29 @@ GetElementIC::canAttachGetProp(JSObject 
 {
     uint32_t dummy;
     return (obj->isNative() &&
             idval.isString() &&
             JSID_IS_ATOM(id) &&
             !JSID_TO_ATOM(id)->isIndex(&dummy));
 }
 
+static bool
+EqualStringsHelper(JSString *str1, JSString *str2)
+{
+    JS_ASSERT(str1->isAtom());
+    JS_ASSERT(!str2->isAtom());
+    JS_ASSERT(str1->length() == str2->length());
+
+    const jschar *chars = str2->getChars(NULL);
+    if (!chars)
+        return false;
+    return mozilla::PodEqual(str1->asAtom().chars(), chars, str1->length());
+}
+
 bool
 GetElementIC::attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj,
                             const Value &idval, HandlePropertyName name,
                             void *returnAddr)
 {
     JS_ASSERT(index().reg().hasValue());
 
     RootedObject holder(cx);
@@ -3001,24 +3014,69 @@ GetElementIC::attachGetProp(JSContext *c
                       output().hasValue());
 
     if (!cacheable) {
         IonSpew(IonSpew_InlineCaches, "GETELEM uncacheable property");
         return true;
     }
 
     JS_ASSERT(idval.isString());
+    JS_ASSERT(idval.toString()->length() == name->length());
 
     Label failures;
     MacroAssembler masm(cx);
     SkipRoot skip(cx, &masm);
 
-    // Guard on the index value.
+    // Ensure the index is a string.
     ValueOperand val = index().reg().valueReg();
-    masm.branchTestValue(Assembler::NotEqual, val, idval, &failures);
+    masm.branchTestString(Assembler::NotEqual, val, &failures);
+
+    Register scratch = output().valueReg().scratchReg();
+    masm.unboxString(val, scratch);
+
+    Label equal;
+    masm.branchPtr(Assembler::Equal, scratch, ImmGCPtr(name), &equal);
+
+    // The pointers are not equal, so if the input string is also an atom it
+    // must be a different string.
+    masm.loadPtr(Address(scratch, JSString::offsetOfLengthAndFlags()), scratch);
+    masm.branchTest32(Assembler::NonZero, scratch, Imm32(JSString::ATOM_BIT), &failures);
+
+    // Check the length.
+    masm.rshiftPtr(Imm32(JSString::LENGTH_SHIFT), scratch);
+    masm.branch32(Assembler::NotEqual, scratch, Imm32(name->length()), &failures);
+
+    // We have a non-atomized string with the same length. For now call a helper
+    // function to do the comparison.
+    RegisterSet volatileRegs = RegisterSet::Volatile();
+    masm.PushRegsInMask(volatileRegs);
+
+    Register objReg = object();
+    JS_ASSERT(objReg != scratch);
+
+    if (!volatileRegs.has(objReg))
+        masm.push(objReg);
+
+    masm.setupUnalignedABICall(2, scratch);
+    masm.movePtr(ImmGCPtr(name), objReg);
+    masm.passABIArg(objReg);
+    masm.unboxString(val, scratch);
+    masm.passABIArg(scratch);
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, EqualStringsHelper));
+    masm.mov(ReturnReg, scratch);
+
+    if (!volatileRegs.has(objReg))
+        masm.pop(objReg);
+
+    RegisterSet ignore = RegisterSet();
+    ignore.add(scratch);
+    masm.PopRegsInMaskIgnore(volatileRegs, ignore);
+
+    masm.branchIfFalseBool(scratch, &failures);
+    masm.bind(&equal);
 
     RepatchStubAppender attacher(*this);
     if (canCache == GetPropertyIC::CanAttachReadSlot) {
         GenerateReadSlot(cx, ion, masm, attacher, obj, holder, shape, object(), output(),
                          &failures);
     } else {
         JS_ASSERT(canCache == GetPropertyIC::CanAttachCallGetter);
         // Set the frame for bailout safety of the OOL call.