Bug 1024589 - IonMonkey: Implement FromCharCode Recover Instruction. r=nbp
authorRémi Weng <wengremi@gmail.com>
Mon, 23 Jun 2014 04:41:40 -0700
changeset 190135 e430f92519ce03f7930d75b02074c8d6547e62dd
parent 190134 b9fac1fab6ca9ba4b839667ce8c795b863adeeea
child 190136 6ddc7aee37ebc7787598eb313200032ceb7a7f64
push id7411
push userkwierso@gmail.com
push dateTue, 24 Jun 2014 02:07:45 +0000
treeherderfx-team@cc4602e0c1d8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp
bugs1024589
milestone33.0a1
Bug 1024589 - IonMonkey: Implement FromCharCode Recover Instruction. r=nbp
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
@@ -326,16 +326,32 @@ function rconcat_string(i) {
 var uceFault_concat_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_concat_number'));
 function rconcat_number(i) {
     var x = "s" + i;
     if (uceFault_concat_number(i) || uceFault_concat_number(i))
         assertEq(x, "s99");
     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;
+}
+
+var uceFault_from_char_code_non_ascii = eval(uneval(uceFault).replace('uceFault', 'uceFault_from_char_code_non_ascii'));
+function rfrom_char_code_non_ascii(i) {
+    var x = String.fromCharCode(i * 100);
+    if (uceFault_from_char_code_non_ascii(i) || uceFault_from_char_code_non_ascii(i))
+        assertEq(x, "\u26AC");
+    return i;
+}
+
 var uceFault_pow_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_pow_number'));
 function rpow_number(i) {
     var x = Math.pow(i, 3.14159);
     if (uceFault_pow_number(i) || uceFault_pow_number(i))
         assertEq(x, Math.pow(99, 3.14159));
     return i;
 }
 
@@ -399,16 +415,18 @@ 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);
+    rfrom_char_code(i);
+    rfrom_char_code_non_ascii(i);
     rpow_number(i);
     rpow_object(i);
     rpowhalf_number(i);
     rpowhalf_object(i);
 }
 
 // Test that we can refer multiple time to the same recover instruction, as well
 // as chaining recover instructions.
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -4825,16 +4825,21 @@ class MFromCharCode
     }
 
     virtual AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
+
+    bool writeRecoverData(CompactBufferWriter &writer) const;
+    bool canRecoverOnBailout() const {
+        return true;
+    }
 };
 
 class MStringSplit
   : public MBinaryInstruction,
     public MixPolicy<StringPolicy<0>, StringPolicy<1> >
 {
     types::TypeObject *typeObject_;
 
--- a/js/src/jit/Recover.cpp
+++ b/js/src/jit/Recover.cpp
@@ -413,16 +413,41 @@ RConcat::recover(JSContext *cx, Snapshot
     if (!js::AddValues(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)
+{}
+
+bool
+RFromCharCode::recover(JSContext *cx, SnapshotIterator &iter) const
+{
+    RootedValue operand(cx, iter.read());
+    RootedValue result(cx);
+
+    MOZ_ASSERT(!operand.isObject());
+    if (!js::str_fromCharCode_one_arg(cx, operand, &result))
+        return false;
+
+    iter.storeInstructionResult(result);
+    return true;
+}
+
+bool
 MMul::writeRecoverData(CompactBufferWriter &writer) const
 {
     MOZ_ASSERT(canRecoverOnBailout());
     writer.writeUnsigned(uint32_t(RInstruction::Recover_Mul));
     writer.writeByte(specialization_ == MIRType_Float32);
     return true;
 }
 
--- 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)                                    \
+    _(FromCharCode)                             \
     _(Pow)                                      \
     _(PowHalf)                                  \
     _(NewObject)                                \
     _(NewDerivedTypedObject)
 
 class RResumePoint;
 class SnapshotIterator;
 
@@ -291,16 +292,28 @@ class RRound MOZ_FINAL : public RInstruc
 
     virtual uint32_t numOperands() const {
         return 1;
     }
 
     bool recover(JSContext *cx, SnapshotIterator &iter) const;
 };
 
+class RFromCharCode MOZ_FINAL : public RInstruction
+{
+  public:
+    RINSTRUCTION_HEADER_(FromCharCode)
+
+    virtual uint32_t numOperands() const {
+        return 1;
+    }
+
+    bool recover(JSContext *cx, SnapshotIterator &iter) const;
+};
+
 class RPow MOZ_FINAL : public RInstruction
 {
   public:
     RINSTRUCTION_HEADER_(Pow)
 
     virtual uint32_t numOperands() const {
         return 2;
     }
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -4150,48 +4150,69 @@ js_String(JSContext *cx, unsigned argc, 
 }
 
 bool
 js::str_fromCharCode(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     JS_ASSERT(args.length() <= ARGS_LENGTH_MAX);
-    if (args.length() == 1) {
-        uint16_t code;
-        if (!ToUint16(cx, args[0], &code))
-            return false;
-        if (StaticStrings::hasUnit(code)) {
-            args.rval().setString(cx->staticStrings().getUnit(code));
-            return true;
-        }
-        args[0].setInt32(code);
-    }
+    if (args.length() == 1)
+        return str_fromCharCode_one_arg(cx, args[0], args.rval());
+
     jschar *chars = cx->pod_malloc<jschar>(args.length() + 1);
     if (!chars)
         return false;
     for (unsigned i = 0; i < args.length(); i++) {
         uint16_t code;
         if (!ToUint16(cx, args[i], &code)) {
             js_free(chars);
             return false;
         }
-        chars[i] = (jschar)code;
+        chars[i] = jschar(code);
     }
     chars[args.length()] = 0;
     JSString *str = js_NewString<CanGC>(cx, chars, args.length());
     if (!str) {
         js_free(chars);
         return false;
     }
 
     args.rval().setString(str);
     return true;
 }
 
+bool
+js::str_fromCharCode_one_arg(JSContext *cx, HandleValue code, MutableHandleValue rval)
+{
+    uint16_t ucode;
+
+    if (!ToUint16(cx, code, &ucode))
+        return false;
+
+    if (StaticStrings::hasUnit(ucode)) {
+        rval.setString(cx->staticStrings().getUnit(ucode));
+        return true;
+    }
+
+    jschar *chars = cx->pod_malloc<jschar>(2);
+    if (!chars)
+        return false;
+    chars[0] = jschar(ucode);
+    chars[1] = 0;
+    JSString *str = js_NewString<CanGC>(cx, chars, 1);
+    if (!str) {
+        js_free(chars);
+        return false;
+    }
+
+    rval.setString(str);
+    return true;
+}
+
 static const JSFunctionSpec string_static_methods[] = {
     JS_FN("fromCharCode", js::str_fromCharCode, 1, 0),
     JS_SELF_HOSTED_FN("fromCodePoint", "String_static_fromCodePoint", 0,0),
 
     // This must be at the end because of bug 853075: functions listed after
     // self-hosted methods aren't available in self-hosted code.
 #if EXPOSE_INTL_API
     JS_SELF_HOSTED_FN("localeCompare", "String_static_localeCompare", 2,0),
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -301,16 +301,19 @@ DeflateStringToBuffer(JSContext *maybecx
  * function optimization in js{interp,tracer}.cpp.
  */
 extern bool
 str_replace(JSContext *cx, unsigned argc, js::Value *vp);
 
 extern bool
 str_fromCharCode(JSContext *cx, unsigned argc, Value *vp);
 
+extern bool
+str_fromCharCode_one_arg(JSContext *cx, HandleValue code, MutableHandleValue rval);
+
 } /* 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);