diff --git a/js/src/jit-test/tests/ion/dce-with-rinstructions.js b/js/src/jit-test/tests/ion/dce-with-rinstructions.js index 1706787dd2b0..17ea857b1416 100644 --- a/js/src/jit-test/tests/ion/dce-with-rinstructions.js +++ b/js/src/jit-test/tests/ion/dce-with-rinstructions.js @@ -329,7 +329,16 @@ function rround_double(i) { 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) { @@ -420,6 +429,7 @@ for (i = 0; i < 100; 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); diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index e649caa5b43c..b630ba5f8294 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -4806,6 +4806,11 @@ class MCharCodeAt } void computeRange(TempAllocator &alloc); + + bool writeRecoverData(CompactBufferWriter &writer) const; + bool canRecoverOnBailout() const { + return true; + } }; class MFromCharCode diff --git a/js/src/jit/Recover.cpp b/js/src/jit/Recover.cpp index ce2df8857af5..f60f7c2a387d 100644 --- a/js/src/jit/Recover.cpp +++ b/js/src/jit/Recover.cpp @@ -8,6 +8,7 @@ #include "jscntxt.h" #include "jsmath.h" +#include "jsstr.h" #include "builtin/TypedObject.h" @@ -557,6 +558,31 @@ RRound::recover(JSContext *cx, SnapshotIterator &iter) const 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 { diff --git a/js/src/jit/Recover.h b/js/src/jit/Recover.h index c71e62f3ccb9..d1f36d244be2 100644 --- a/js/src/jit/Recover.h +++ b/js/src/jit/Recover.h @@ -33,6 +33,7 @@ namespace jit { _(Concat) \ _(Floor) \ _(Round) \ + _(CharCodeAt) \ _(FromCharCode) \ _(Pow) \ _(PowHalf) \ @@ -297,6 +298,18 @@ class RRound MOZ_FINAL : public RInstruction 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: diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index bc3c753cea1b..68ced5bff0e9 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1008,41 +1008,54 @@ js_str_charAt(JSContext *cx, unsigned argc, Value *vp) 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); } + if (args.length() != 0) + index = args[0]; + else + index.setInt32(0); - jschar c; - if (!str->getChar(cx, i, &c)) - return false; - args.rval().setInt32(c); - return true; - -out_of_range: - args.rval().setNaN(); - return true; + return js::str_charCodeAt_impl(cx, str, index, args.rval()); } /* diff --git a/js/src/jsstr.h b/js/src/jsstr.h index 2fca47bedf5e..08ef5719dd6b 100644 --- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -326,9 +326,15 @@ 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.