Bug 1024587 - IonMonkey: Implement CharCodeAt Recover Instruction. r=nbp,evilpie
authorNicolas Devillers <devillers.nicolas@gmail.com>
Thu, 26 Jun 2014 03:01:55 -0700
changeset 190897 09970d776de2a131aec5d5e6aa5e904a1b7cf168
parent 190896 53a36cd7ac52573e85b1dcc9639b0c3b3ef0895b
child 190898 150fe5a9f627288893bc688776f4dedcbe16b60d
push id45432
push usernpierron@mozilla.com
push dateThu, 26 Jun 2014 10:02:27 +0000
treeherdermozilla-inbound@09970d776de2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp, evilpie
bugs1024587
milestone33.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 1024587 - IonMonkey: Implement CharCodeAt Recover Instruction. r=nbp,evilpie
js/src/jit-test/tests/ion/dce-with-rinstructions.js
js/src/jit/MIR.h
js/src/jit/Recover.cpp
js/src/jit/Recover.h
js/src/jsstr.cpp
js/src/jsstr.h
--- a/js/src/jit-test/tests/ion/dce-with-rinstructions.js
+++ b/js/src/jit-test/tests/ion/dce-with-rinstructions.js
@@ -324,17 +324,26 @@ function rround_number(i) {
 }
 
 var uceFault_round_double = eval(uneval(uceFault).replace('uceFault', 'uceFault_round_double'));
 function rround_double(i) {
     var x = Math.round(i + (-1 >>> 0));
     if (uceFault_round_double(i) || uceFault_round_double(i))
         assertEq(x, 99 + (-1 >>> 0)); /* = i + 2 ^ 32 - 1 */
      return i;
- }
+}
+
+var uceFault_Char_Code_At = eval(uneval(uceFault).replace('uceFault', 'uceFault_Char_Code_At'));
+function rcharCodeAt(i) {
+    var s = "aaaaa";
+    var x = s.charCodeAt(i % 4);
+    if (uceFault_Char_Code_At(i) || uceFault_Char_Code_At(i))
+        assertEq(x, 97 );
+    return i;
+}
 
 var uceFault_from_char_code = eval(uneval(uceFault).replace('uceFault', 'uceFault_from_char_code'));
 function rfrom_char_code(i) {
     var x = String.fromCharCode(i);
     if (uceFault_from_char_code(i) || uceFault_from_char_code(i))
         assertEq(x, "c");
     return i;
 }
@@ -415,16 +424,17 @@ for (i = 0; i < 100; i++) {
     rmod_number(i);
     rmod_object(i);
     rconcat_string(i);
     rconcat_number(i);
     rfloor_number(i);
     rfloor_object(i);
     rround_number(i);
     rround_double(i);
+    rcharCodeAt(i);
     rfrom_char_code(i);
     rfrom_char_code_non_ascii(i);
     rpow_number(i);
     rpow_object(i);
     rpowhalf_number(i);
     rpowhalf_object(i);
 }
 
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -4801,16 +4801,21 @@ class MCharCodeAt
     }
 
     virtual AliasSet getAliasSet() const {
         // Strings are immutable, so there is no implicit dependency.
         return AliasSet::None();
     }
 
     void computeRange(TempAllocator &alloc);
+
+    bool writeRecoverData(CompactBufferWriter &writer) const;
+    bool canRecoverOnBailout() const {
+        return true;
+    }
 };
 
 class MFromCharCode
   : public MUnaryInstruction,
     public IntPolicy<0>
 {
     explicit MFromCharCode(MDefinition *code)
       : MUnaryInstruction(code)
--- a/js/src/jit/Recover.cpp
+++ b/js/src/jit/Recover.cpp
@@ -3,16 +3,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/Recover.h"
 
 #include "jscntxt.h"
 #include "jsmath.h"
+#include "jsstr.h"
 
 #include "builtin/TypedObject.h"
 
 #include "jit/IonSpewer.h"
 #include "jit/JitFrameIterator.h"
 #include "jit/MIR.h"
 #include "jit/MIRGraph.h"
 #include "jit/VMFunctions.h"
@@ -553,16 +554,41 @@ RRound::recover(JSContext *cx, SnapshotI
     if(!js::math_round_handle(cx, arg, &result))
         return false;
 
     iter.storeInstructionResult(result);
     return true;
 }
 
 bool
+MCharCodeAt::writeRecoverData(CompactBufferWriter &writer) const
+{
+    MOZ_ASSERT(canRecoverOnBailout());
+    writer.writeUnsigned(uint32_t(RInstruction::Recover_CharCodeAt));
+    return true;
+}
+
+RCharCodeAt::RCharCodeAt(CompactBufferReader &reader)
+{}
+
+bool
+RCharCodeAt::recover(JSContext *cx, SnapshotIterator &iter) const
+{
+    RootedString lhs(cx, iter.read().toString());
+    RootedValue rhs(cx, iter.read());
+    RootedValue result(cx);
+
+    if (!js::str_charCodeAt_impl(cx, lhs, rhs, &result))
+        return false;
+
+    iter.storeInstructionResult(result);
+    return true;
+}
+
+bool
 MFromCharCode::writeRecoverData(CompactBufferWriter &writer) const
 {
     MOZ_ASSERT(canRecoverOnBailout());
     writer.writeUnsigned(uint32_t(RInstruction::Recover_FromCharCode));
     return true;
 }
 
 RFromCharCode::RFromCharCode(CompactBufferReader &reader)
--- a/js/src/jit/Recover.h
+++ b/js/src/jit/Recover.h
@@ -28,16 +28,17 @@ namespace jit {
     _(Add)                                      \
     _(Sub)                                      \
     _(Mul)                                      \
     _(Div)                                      \
     _(Mod)                                      \
     _(Concat)                                   \
     _(Floor)                                    \
     _(Round)                                    \
+    _(CharCodeAt)                               \
     _(FromCharCode)                             \
     _(Pow)                                      \
     _(PowHalf)                                  \
     _(NewObject)                                \
     _(NewDerivedTypedObject)
 
 class RResumePoint;
 class SnapshotIterator;
@@ -292,16 +293,28 @@ class RRound MOZ_FINAL : public RInstruc
 
     virtual uint32_t numOperands() const {
         return 1;
     }
 
     bool recover(JSContext *cx, SnapshotIterator &iter) const;
 };
 
+class RCharCodeAt MOZ_FINAL : public RInstruction
+{
+  public:
+    RINSTRUCTION_HEADER_(CharCodeAt)
+
+    virtual uint32_t numOperands() const {
+        return 2;
+    }
+
+    bool recover(JSContext *cx, SnapshotIterator &iter) const;
+};
+
 class RFromCharCode MOZ_FINAL : public RInstruction
 {
   public:
     RINSTRUCTION_HEADER_(FromCharCode)
 
     virtual uint32_t numOperands() const {
         return 1;
     }
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -1004,50 +1004,63 @@ js_str_charAt(JSContext *cx, unsigned ar
     return true;
 
   out_of_range:
     args.rval().setString(cx->runtime()->emptyString);
     return true;
 }
 
 bool
+js::str_charCodeAt_impl(JSContext *cx, HandleString string, HandleValue index, MutableHandleValue res)
+{
+    RootedString str(cx);
+    size_t i;
+    if (index.isInt32()) {
+        i = index.toInt32();
+        if (i >= string->length())
+            goto out_of_range;
+    } else {
+        double d = 0.0;
+        if (!ToInteger(cx, index, &d))
+            return false;
+        // check whether d is negative as size_t is unsigned
+        if (d < 0 || string->length() <= d )
+            goto out_of_range;
+        i = size_t(d);
+    }
+    jschar c;
+    if (!string->getChar(cx, i , &c))
+        return false;
+    res.setInt32(c);
+    return true;
+
+out_of_range:
+    res.setNaN();
+    return true;
+}
+
+bool
 js_str_charCodeAt(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-
     RootedString str(cx);
-    size_t i;
-    if (args.thisv().isString() && args.length() != 0 && args[0].isInt32()) {
+    RootedValue index(cx);
+    if (args.thisv().isString()) {
         str = args.thisv().toString();
-        i = size_t(args[0].toInt32());
-        if (i >= str->length())
-            goto out_of_range;
     } else {
         str = ThisToStringForStringProto(cx, args);
         if (!str)
             return false;
-
-        double d = 0.0;
-        if (args.length() > 0 && !ToInteger(cx, args[0], &d))
-            return false;
-
-        if (d < 0 || str->length() <= d)
-            goto out_of_range;
-        i = size_t(d);
     }
-
-    jschar c;
-    if (!str->getChar(cx, i, &c))
-        return false;
-    args.rval().setInt32(c);
-    return true;
-
-out_of_range:
-    args.rval().setNaN();
-    return true;
+    if (args.length() != 0)
+        index = args[0];
+    else
+        index.setInt32(0);
+
+    return js::str_charCodeAt_impl(cx, str, index, args.rval());
 }
 
 /*
  * Boyer-Moore-Horspool superlinear search for pat:patlen in text:textlen.
  * The patlen argument must be positive and no greater than sBMHPatLenMax.
  *
  * Return the index of pat in text, or -1 if not found.
  */
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -321,19 +321,25 @@ str_fromCharCode_one_arg(JSContext *cx, 
 } /* namespace js */
 
 extern bool
 js_str_toString(JSContext *cx, unsigned argc, js::Value *vp);
 
 extern bool
 js_str_charAt(JSContext *cx, unsigned argc, js::Value *vp);
 
+namespace js {
+
+extern bool
+str_charCodeAt_impl(JSContext *cx, HandleString string, HandleValue index, MutableHandleValue res);
+
+} /* namespace js */
+
 extern bool
 js_str_charCodeAt(JSContext *cx, unsigned argc, js::Value *vp);
-
 /*
  * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
  * least 6 bytes long.  Return the number of UTF-8 bytes of data written.
  */
 extern int
 js_OneUcs4ToUtf8Char(uint8_t *utf8Buffer, uint32_t ucs4Char);
 
 namespace js {