Backed out changeset 7218723f5a9b (bug 956051) for bustage.
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 17 Jan 2014 11:05:11 -0500
changeset 163970 fbd443bb2208ede14fb012cd955d41fbe33b1f4a
parent 163969 8f1ffc0fe9142b397041bd35f010c6355f648815
child 163971 648a54eeed1924f0646c4bab288f18a7928ce97f
push id38599
push userryanvm@gmail.com
push dateFri, 17 Jan 2014 16:05:16 +0000
treeherdermozilla-inbound@fbd443bb2208 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs956051
milestone29.0a1
backs out7218723f5a9b545f6a049a00628b67c5f559d168
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
Backed out changeset 7218723f5a9b (bug 956051) for bustage. CLOSED TREE
js/src/jit/CodeGenerator.cpp
js/src/jit/CodeGenerator.h
js/src/jit/IonBuilder.h
js/src/jit/LIR-Common.h
js/src/jit/LOpcodes.h
js/src/jit/Lowering.cpp
js/src/jit/Lowering.h
js/src/jit/MCallOptimize.cpp
js/src/jit/MIR.h
js/src/jit/MOpcodes.h
js/src/jit/ParallelSafetyAnalysis.cpp
js/src/jit/VMFunctions.cpp
js/src/jit/VMFunctions.h
js/src/jsstr.cpp
js/src/jsstr.h
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -784,61 +784,36 @@ bool
 CodeGenerator::visitRegExpTest(LRegExpTest *lir)
 {
     pushArg(ToRegister(lir->string()));
     pushArg(ToRegister(lir->regexp()));
     return callVM(RegExpTestRawInfo, lir);
 }
 
 typedef JSString *(*RegExpReplaceFn)(JSContext *, HandleString, HandleObject, HandleString);
-static const VMFunction RegExpReplaceInfo = FunctionInfo<RegExpReplaceFn>(RegExpReplace);
+static const VMFunction RegExpReplaceInfo = FunctionInfo<RegExpReplaceFn>(regexp_replace);
 
 bool
 CodeGenerator::visitRegExpReplace(LRegExpReplace *lir)
 {
     if (lir->replacement()->isConstant())
         pushArg(ImmGCPtr(lir->replacement()->toConstant()->toString()));
     else
         pushArg(ToRegister(lir->replacement()));
 
-    pushArg(ToRegister(lir->pattern()));
+    pushArg(ToRegister(lir->regexp()));
 
     if (lir->string()->isConstant())
         pushArg(ImmGCPtr(lir->string()->toConstant()->toString()));
     else
         pushArg(ToRegister(lir->string()));
 
     return callVM(RegExpReplaceInfo, lir);
 }
 
-typedef JSString *(*StringReplaceFn)(JSContext *, HandleString, HandleString, HandleString);
-static const VMFunction StringReplaceInfo = FunctionInfo<StringReplaceFn>(StringReplace);
-
-bool
-CodeGenerator::visitStringReplace(LStringReplace *lir)
-{
-    if (lir->replacement()->isConstant())
-        pushArg(ImmGCPtr(lir->replacement()->toConstant()->toString()));
-    else
-        pushArg(ToRegister(lir->replacement()));
-
-    if (lir->pattern()->isConstant())
-        pushArg(ImmGCPtr(lir->pattern()->toConstant()->toString()));
-    else
-        pushArg(ToRegister(lir->pattern()));
-
-    if (lir->string()->isConstant())
-        pushArg(ImmGCPtr(lir->string()->toConstant()->toString()));
-    else
-        pushArg(ToRegister(lir->string()));
-
-    return callVM(StringReplaceInfo, lir);
-}
-
-
 typedef JSObject *(*LambdaFn)(JSContext *, HandleFunction, HandleObject);
 static const VMFunction LambdaInfo =
     FunctionInfo<LambdaFn>(js::Lambda);
 
 bool
 CodeGenerator::visitLambdaForSingleton(LLambdaForSingleton *lir)
 {
     pushArg(ToRegister(lir->scopeChain()));
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -88,17 +88,16 @@ class CodeGenerator : public CodeGenerat
     bool visitTypeObjectDispatch(LTypeObjectDispatch *lir);
     bool visitIntToString(LIntToString *lir);
     bool visitDoubleToString(LDoubleToString *lir);
     bool visitInteger(LInteger *lir);
     bool visitRegExp(LRegExp *lir);
     bool visitRegExpExec(LRegExpExec *lir);
     bool visitRegExpTest(LRegExpTest *lir);
     bool visitRegExpReplace(LRegExpReplace *lir);
-    bool visitStringReplace(LStringReplace *lir);
     bool visitLambda(LLambda *lir);
     bool visitLambdaForSingleton(LLambdaForSingleton *lir);
     bool visitLambdaPar(LLambdaPar *lir);
     bool visitPointer(LPointer *lir);
     bool visitSlots(LSlots *lir);
     bool visitStoreSlotV(LStoreSlotV *store);
     bool visitElements(LElements *lir);
     bool visitConvertElementsToDoubles(LConvertElementsToDoubles *lir);
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -624,17 +624,17 @@ class IonBuilder : public MIRGenerator
     InliningStatus inlineMathFunction(CallInfo &callInfo, MMathFunction::Function function);
 
     // String natives.
     InliningStatus inlineStringObject(CallInfo &callInfo);
     InliningStatus inlineStringSplit(CallInfo &callInfo);
     InliningStatus inlineStrCharCodeAt(CallInfo &callInfo);
     InliningStatus inlineStrFromCharCode(CallInfo &callInfo);
     InliningStatus inlineStrCharAt(CallInfo &callInfo);
-    InliningStatus inlineStrReplace(CallInfo &callInfo);
+    InliningStatus inlineStrReplaceRegExp(CallInfo &callInfo);
 
     // RegExp natives.
     InliningStatus inlineRegExpExec(CallInfo &callInfo);
     InliningStatus inlineRegExpTest(CallInfo &callInfo);
 
     // Array intrinsics.
     InliningStatus inlineUnsafePutElements(CallInfo &callInfo);
     bool inlineUnsafeSetDenseArrayElement(CallInfo &callInfo, uint32_t base);
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -3241,71 +3241,44 @@ class LRegExpTest : public LCallInstruct
         return getOperand(1);
     }
 
     const MRegExpTest *mir() const {
         return mir_->toRegExpTest();
     }
 };
 
-
-class LStrReplace : public LCallInstructionHelper<1, 3, 0>
-{
-  public:
-    LStrReplace(const LAllocation &string, const LAllocation &pattern,
+class LRegExpReplace : public LCallInstructionHelper<1, 3, 0>
+{
+  public:
+    LIR_HEADER(RegExpReplace)
+
+    LRegExpReplace(const LAllocation &string, const LAllocation &regexp,
                    const LAllocation &replacement)
     {
         setOperand(0, string);
-        setOperand(1, pattern);
+        setOperand(1, regexp);
         setOperand(2, replacement);
     }
 
     const LAllocation *string() {
         return getOperand(0);
     }
-    const LAllocation *pattern() {
+    const LAllocation *regexp() {
         return getOperand(1);
     }
     const LAllocation *replacement() {
         return getOperand(2);
     }
-};
-
-class LRegExpReplace: public LStrReplace
-{
-  public:
-    LIR_HEADER(RegExpReplace);
-
-    LRegExpReplace(const LAllocation &string, const LAllocation &pattern,
-                   const LAllocation &replacement)
-      : LStrReplace(string, pattern, replacement)
-    {
-    }
 
     const MRegExpReplace *mir() const {
         return mir_->toRegExpReplace();
     }
 };
 
-class LStringReplace: public LStrReplace
-{
-  public:
-    LIR_HEADER(StringReplace);
-
-    LStringReplace(const LAllocation &string, const LAllocation &pattern,
-                   const LAllocation &replacement)
-      : LStrReplace(string, pattern, replacement)
-    {
-    }
-
-    const MStringReplace *mir() const {
-        return mir_->toStringReplace();
-    }
-};
-
 class LLambdaForSingleton : public LCallInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(LambdaForSingleton)
 
     LLambdaForSingleton(const LAllocation &scopeChain)
     {
         setOperand(0, scopeChain);
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -147,17 +147,16 @@
     _(OsrValue)                     \
     _(OsrScopeChain)                \
     _(OsrReturnValue)               \
     _(OsrArgumentsObject)           \
     _(RegExp)                       \
     _(RegExpExec)                   \
     _(RegExpTest)                   \
     _(RegExpReplace)                \
-    _(StringReplace)                \
     _(Lambda)                       \
     _(LambdaForSingleton)           \
     _(LambdaPar)                    \
     _(ImplicitThis)                 \
     _(Slots)                        \
     _(Elements)                     \
     _(ConvertElementsToDoubles)     \
     _(MaybeToDoubleElement)         \
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -1933,35 +1933,22 @@ LIRGenerator::visitRegExpTest(MRegExpTes
     LRegExpTest *lir = new(alloc()) LRegExpTest(useRegisterAtStart(ins->regexp()),
                                                 useRegisterAtStart(ins->string()));
     return defineReturn(lir, ins) && assignSafepoint(lir, ins);
 }
 
 bool
 LIRGenerator::visitRegExpReplace(MRegExpReplace *ins)
 {
-    JS_ASSERT(ins->pattern()->type() == MIRType_Object);
+    JS_ASSERT(ins->regexp()->type() == MIRType_Object);
     JS_ASSERT(ins->string()->type() == MIRType_String);
     JS_ASSERT(ins->replacement()->type() == MIRType_String);
 
     LRegExpReplace *lir = new(alloc()) LRegExpReplace(useRegisterOrConstantAtStart(ins->string()),
-                                                      useRegisterAtStart(ins->pattern()),
-                                                      useRegisterOrConstantAtStart(ins->replacement()));
-    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
-}
-
-bool
-LIRGenerator::visitStringReplace(MStringReplace *ins)
-{
-    JS_ASSERT(ins->pattern()->type() == MIRType_String);
-    JS_ASSERT(ins->string()->type() == MIRType_String);
-    JS_ASSERT(ins->replacement()->type() == MIRType_String);
-
-    LStringReplace *lir = new(alloc()) LStringReplace(useRegisterOrConstantAtStart(ins->string()),
-                                                      useRegisterAtStart(ins->pattern()),
+                                                      useRegisterAtStart(ins->regexp()),
                                                       useRegisterOrConstantAtStart(ins->replacement()));
     return defineReturn(lir, ins) && assignSafepoint(lir, ins);
 }
 
 bool
 LIRGenerator::visitLambda(MLambda *ins)
 {
     if (ins->info().singletonType || ins->info().useNewTypeForClone) {
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -143,17 +143,16 @@ class LIRGenerator : public LIRGenerator
     bool visitToFloat32(MToFloat32 *convert);
     bool visitToInt32(MToInt32 *convert);
     bool visitTruncateToInt32(MTruncateToInt32 *truncate);
     bool visitToString(MToString *convert);
     bool visitRegExp(MRegExp *ins);
     bool visitRegExpExec(MRegExpExec *ins);
     bool visitRegExpTest(MRegExpTest *ins);
     bool visitRegExpReplace(MRegExpReplace *ins);
-    bool visitStringReplace(MStringReplace *ins);
     bool visitLambda(MLambda *ins);
     bool visitLambdaPar(MLambdaPar *ins);
     bool visitImplicitThis(MImplicitThis *ins);
     bool visitSlots(MSlots *ins);
     bool visitElements(MElements *ins);
     bool visitConstantElements(MConstantElements *ins);
     bool visitConvertElementsToDoubles(MConvertElementsToDoubles *ins);
     bool visitMaybeToDoubleElement(MMaybeToDoubleElement *ins);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -115,17 +115,17 @@ IonBuilder::inlineNativeCall(CallInfo &c
         return inlineStringSplit(callInfo);
     if (native == js_str_charCodeAt)
         return inlineStrCharCodeAt(callInfo);
     if (native == js::str_fromCharCode)
         return inlineStrFromCharCode(callInfo);
     if (native == js_str_charAt)
         return inlineStrCharAt(callInfo);
     if (native == str_replace)
-        return inlineStrReplace(callInfo);
+        return inlineStrReplaceRegExp(callInfo);
 
     // RegExp natives.
     if (native == regexp_exec && CallResultEscapes(pc))
         return inlineRegExpExec(callInfo);
     if (native == regexp_exec && !CallResultEscapes(pc))
         return inlineRegExpTest(callInfo);
     if (native == regexp_test)
         return inlineRegExpTest(callInfo);
@@ -1169,53 +1169,48 @@ IonBuilder::inlineRegExpTest(CallInfo &c
     current->push(match);
     if (!resumeAfter(match))
         return InliningStatus_Error;
 
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineStrReplace(CallInfo &callInfo)
+IonBuilder::inlineStrReplaceRegExp(CallInfo &callInfo)
 {
     if (callInfo.argc() != 2 || callInfo.constructing())
         return InliningStatus_NotInlined;
 
     // Return: String.
     if (getInlineReturnType() != MIRType_String)
         return InliningStatus_NotInlined;
 
     // This: String.
     if (callInfo.thisArg()->type() != MIRType_String)
         return InliningStatus_NotInlined;
 
     // Arg 0: RegExp.
     types::TemporaryTypeSet *arg0Type = callInfo.getArg(0)->resultTypeSet();
     const Class *clasp = arg0Type ? arg0Type->getKnownClass() : nullptr;
-    if (clasp != &RegExpObject::class_ && callInfo.getArg(0)->type() != MIRType_String)
+    if (clasp != &RegExpObject::class_)
         return InliningStatus_NotInlined;
 
     // Arg 1: String.
     if (callInfo.getArg(1)->type() != MIRType_String)
         return InliningStatus_NotInlined;
 
     callInfo.setImplicitlyUsedUnchecked();
 
-    MInstruction *cte;
-    if (callInfo.getArg(0)->type() == MIRType_String) {
-        cte = MStringReplace::New(alloc(), callInfo.thisArg(), callInfo.getArg(0),
-                                  callInfo.getArg(1));
-    } else {
-        cte = MRegExpReplace::New(alloc(), callInfo.thisArg(), callInfo.getArg(0),
-                                  callInfo.getArg(1));
-    }
+    MInstruction *cte = MRegExpReplace::New(alloc(), callInfo.thisArg(), callInfo.getArg(0),
+                                            callInfo.getArg(1));
     current->add(cte);
     current->push(cte);
-    if (cte->isEffectful() && !resumeAfter(cte))
+    if (!resumeAfter(cte))
         return InliningStatus_Error;
+
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineUnsafePutElements(CallInfo &callInfo)
 {
     uint32_t argc = callInfo.argc();
     if (argc < 3 || (argc % 3) != 0 || callInfo.constructing())
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -4880,91 +4880,54 @@ class MRegExpTest
         return this;
     }
 
     bool possiblyCalls() const {
         return true;
     }
 };
 
-template <class Policy1>
-class MStrReplace
+class MRegExpReplace
   : public MTernaryInstruction,
-    public Mix3Policy<StringPolicy<0>, Policy1, StringPolicy<2> >
-{
-  protected:
-
-    MStrReplace(MDefinition *string, MDefinition *pattern, MDefinition *replacement)
-      : MTernaryInstruction(string, pattern, replacement)
-    {
-        setMovable();
+    public Mix3Policy<StringPolicy<0>, ObjectPolicy<1>, StringPolicy<2> >
+{
+  private:
+
+    MRegExpReplace(MDefinition *string, MDefinition *regexp, MDefinition *replacement)
+      : MTernaryInstruction(string, regexp, replacement)
+    {
         setResultType(MIRType_String);
     }
 
   public:
+    INSTRUCTION_HEADER(RegExpReplace)
+
+    static MRegExpReplace *New(TempAllocator &alloc, MDefinition *string, MDefinition *regexp, MDefinition *replacement) {
+        return new(alloc) MRegExpReplace(string, regexp, replacement);
+    }
 
     MDefinition *string() const {
         return getOperand(0);
     }
-    MDefinition *pattern() const {
+    MDefinition *regexp() const {
         return getOperand(1);
     }
     MDefinition *replacement() const {
         return getOperand(2);
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
 
     bool possiblyCalls() const {
         return true;
     }
 };
 
-class MRegExpReplace
-    : public MStrReplace< ObjectPolicy<1> >
-{
-  private:
-
-    MRegExpReplace(MDefinition *string, MDefinition *pattern, MDefinition *replacement)
-      :  MStrReplace(string, pattern, replacement)
-    {
-    }
-
-  public:
-    INSTRUCTION_HEADER(RegExpReplace);
-
-    static MRegExpReplace *New(TempAllocator &alloc, MDefinition *string, MDefinition *pattern, MDefinition *replacement) {
-        return new(alloc) MRegExpReplace(string, pattern, replacement);
-    }
-};
-
-class MStringReplace
-    : public MStrReplace< StringPolicy<1> >
-{
-  private:
-
-    MStringReplace(MDefinition *string, MDefinition *pattern, MDefinition *replacement)
-      :  MStrReplace(string, pattern, replacement)
-    {
-    }
-
-  public:
-    INSTRUCTION_HEADER(StringReplace);
-
-    static MStringReplace *New(TempAllocator &alloc, MDefinition *string, MDefinition *pattern, MDefinition *replacement) {
-        return new(alloc) MStringReplace(string, pattern, replacement);
-    }
-
-    AliasSet getAliasSet() const {
-        return AliasSet::None();
-    }
-};
-
 struct LambdaFunctionInfo
 {
     // The functions used in lambdas are the canonical original function in
     // the script, and are immutable except for delazification. Record this
     // information while still on the main thread to avoid races.
     CompilerRootFunction fun;
     uint16_t flags;
     gc::Cell *scriptOrLazyScript;
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -96,17 +96,16 @@ namespace jit {
     _(InitPropGetterSetter)                                                 \
     _(Start)                                                                \
     _(OsrEntry)                                                             \
     _(Nop)                                                                  \
     _(RegExp)                                                               \
     _(RegExpExec)                                                           \
     _(RegExpTest)                                                           \
     _(RegExpReplace)                                                        \
-    _(StringReplace)                                                        \
     _(Lambda)                                                               \
     _(ImplicitThis)                                                         \
     _(Slots)                                                                \
     _(Elements)                                                             \
     _(ConstantElements)                                                     \
     _(ConvertElementsToDoubles)                                             \
     _(MaybeToDoubleElement)                                                 \
     _(LoadSlot)                                                             \
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -276,17 +276,16 @@ class ParallelSafetyVisitor : public MIn
     UNSAFE_OP(SetDOMProperty)
     UNSAFE_OP(NewStringObject)
     UNSAFE_OP(Random)
     UNSAFE_OP(Pow)
     UNSAFE_OP(PowHalf)
     UNSAFE_OP(RegExpTest)
     UNSAFE_OP(RegExpExec)
     UNSAFE_OP(RegExpReplace)
-    UNSAFE_OP(StringReplace)
     UNSAFE_OP(CallInstanceOf)
     UNSAFE_OP(FunctionBoundary)
     UNSAFE_OP(GuardString)
     UNSAFE_OP(NewDeclEnvObject)
     UNSAFE_OP(In)
     UNSAFE_OP(InArray)
     SAFE_OP(GuardThreadExclusive)
     SAFE_OP(CheckInterruptPar)
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -909,42 +909,28 @@ InitBaselineFrameForOsr(BaselineFrame *f
 
 JSObject *CreateDerivedTypedObj(JSContext *cx, HandleObject type,
                                 HandleObject owner, int32_t offset)
 {
     return TypedObject::createDerived(cx, type, owner, offset);
 }
 
 JSString *
-RegExpReplace(JSContext *cx, HandleString string, HandleObject regexp, HandleString repl)
+regexp_replace(JSContext *cx, HandleString string, HandleObject regexp, HandleString repl)
 {
-    JS_ASSERT(string);
-    JS_ASSERT(repl);
+    JS_ASSERT(!!string);
+    JS_ASSERT(!!repl);
 
     RootedValue rval(cx);
     if (!str_replace_regexp_raw(cx, string, regexp, repl, &rval))
         return nullptr;
 
     return rval.toString();
 }
 
-JSString *
-StringReplace(JSContext *cx, HandleString string, HandleString pattern, HandleString repl)
-{
-    JS_ASSERT(string);
-    JS_ASSERT(pattern);
-    JS_ASSERT(repl);
-
-    RootedValue rval(cx);
-    if (!str_replace_string_raw(cx, string, pattern, repl, &rval))
-        return nullptr;
-
-    return rval.toString();
-}
-
 bool
 Recompile(JSContext *cx)
 {
     JS_ASSERT(cx->currentlyRunningInJit());
     JitActivationIterator activations(cx->runtime());
     IonFrameIterator iter(activations);
 
     JS_ASSERT(iter.type() == IonFrame_Exit);
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -658,20 +658,18 @@ bool DebugLeaveBlock(JSContext *cx, Base
 
 bool InitBaselineFrameForOsr(BaselineFrame *frame, StackFrame *interpFrame,
                              uint32_t numStackValues);
 
 JSObject *CreateDerivedTypedObj(JSContext *cx, HandleObject type,
                                 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);
+JSString *regexp_replace(JSContext *cx, HandleString string, HandleObject regexp,
+                         HandleString repl);
 
 #ifdef DEBUG
 void AssertValidObjectPtr(JSContext *cx, JSObject *obj);
 void AssertValidStringPtr(JSContext *cx, JSString *str);
 void AssertValidValue(JSContext *cx, Value *v);
 #endif
 
 } // namespace jit
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -1726,23 +1726,16 @@ class MOZ_STACK_CLASS StringRegExpGuard
 
         JS_ASSERT(ObjectClassIs(obj_, ESClass_RegExp, cx));
 
         if (!RegExpToShared(cx, obj_, &re_))
             return false;
         return true;
     }
 
-    bool init(JSContext *cx, HandleString pattern) {
-        fm.patstr = AtomizeString(cx, pattern);
-        if (!fm.patstr)
-            return false;
-        return true;
-    }
-
     /*
      * Attempt to match |patstr| to |textstr|. A flags argument, metachars in
      * the pattern string, or a lengthy pattern string can thwart this process.
      *
      * |checkMetaChars| looks for regexp metachars in the pattern string.
      *
      * Return whether flat matching could be used.
      *
@@ -2451,17 +2444,17 @@ ReplaceRegExp(JSContext *cx, RegExpStati
 
     rdata.sb.infallibleAppend(left, leftlen); /* skipped-over portion of the search value */
     DoReplace(res, rdata);
     return true;
 }
 
 static bool
 BuildFlatReplacement(JSContext *cx, HandleString textstr, HandleString repstr,
-                     const FlatMatch &fm, MutableHandleValue rval)
+                     const FlatMatch &fm, CallArgs *args)
 {
     RopeBuilder builder(cx);
     size_t match = fm.match();
     size_t matchEnd = match + fm.patternLength();
 
     if (textstr->isRope()) {
         /*
          * If we are replacing over a rope, avoid flattening it by iterating
@@ -2523,29 +2516,29 @@ BuildFlatReplacement(JSContext *cx, Hand
         if (!rightSide ||
             !builder.append(leftSide) ||
             !builder.append(repstr) ||
             !builder.append(rightSide)) {
             return false;
         }
     }
 
-    rval.setString(builder.result());
+    args->rval().setString(builder.result());
     return true;
 }
 
 /*
  * Perform a linear-scan dollar substitution on the replacement text,
  * constructing a result string that looks like:
  *
  *      newstring = string[:matchStart] + dollarSub(replaceValue) + string[matchLimit:]
  */
 static inline bool
 BuildDollarReplacement(JSContext *cx, JSString *textstrArg, JSLinearString *repstr,
-                       const jschar *firstDollar, const FlatMatch &fm, MutableHandleValue rval)
+                       const jschar *firstDollar, const FlatMatch &fm, CallArgs *args)
 {
     Rooted<JSLinearString*> textstr(cx, textstrArg->ensureLinear(cx));
     if (!textstr)
         return false;
 
     JS_ASSERT(repstr->chars() <= firstDollar && firstDollar < repstr->chars() + repstr->length());
     size_t matchStart = fm.match();
     size_t matchLimit = matchStart + fm.patternLength();
@@ -2607,17 +2600,17 @@ BuildDollarReplacement(JSContext *cx, JS
     ENSURE(rightSide);
 
     RopeBuilder builder(cx);
     ENSURE(builder.append(leftSide) &&
            builder.append(newReplace) &&
            builder.append(rightSide));
 #undef ENSURE
 
-    rval.setString(builder.result());
+    args->rval().setString(builder.result());
     return true;
 }
 
 struct StringRange
 {
     size_t start;
     size_t length;
 
@@ -2863,56 +2856,20 @@ js::str_replace_regexp_raw(JSContext *cx
 
     if (!rdata.g.init(cx, regexp))
         return false;
 
     return StrReplaceRegExp(cx, rdata, rval);
 }
 
 static inline bool
-StrReplaceString(JSContext *cx, ReplaceData &rdata, const FlatMatch &fm, MutableHandleValue rval)
-{
-    /*
-     * Note: we could optimize the text.length == pattern.length case if we wanted,
-     * even in the presence of dollar metachars.
-     */
-    if (rdata.dollar)
-        return BuildDollarReplacement(cx, rdata.str, rdata.repstr, rdata.dollar, fm, rval);
-    return BuildFlatReplacement(cx, rdata.str, rdata.repstr, fm, rval);
-}
-
-static const uint32_t ReplaceOptArg = 2;
-
-bool
-js::str_replace_string_raw(JSContext *cx, HandleString string, HandleString pattern,
-                          HandleString replacement, MutableHandleValue rval)
-{
-    ReplaceData rdata(cx);
-
-    rdata.str = string;
-    JSLinearString *repl = replacement->ensureLinear(cx);
-    if (!repl)
-        return false;
-    rdata.setReplacementString(repl);
-
-    if (!rdata.g.init(cx, pattern))
-        return false;
-    const FlatMatch *fm = rdata.g.tryFlatMatch(cx, rdata.str, ReplaceOptArg, ReplaceOptArg, false);
-
-    if (fm->match() < 0) {
-        rval.setString(string);
-        return true;
-    }
-
-    return StrReplaceString(cx, rdata, *fm, rval);
-}
-
-static inline bool
 str_replace_flat_lambda(JSContext *cx, CallArgs outerArgs, ReplaceData &rdata, const FlatMatch &fm)
 {
+    JS_ASSERT(fm.match() >= 0);
+
     RootedString matchStr(cx, js_NewDependentString(cx, rdata.str, fm.match(), fm.patternLength()));
     if (!matchStr)
         return false;
 
     /* lambda(matchStr, matchStart, textstr) */
     static const uint32_t lambdaArgc = 3;
     if (!rdata.fig.args().init(lambdaArgc))
         return false;
@@ -2949,16 +2906,18 @@ str_replace_flat_lambda(JSContext *cx, C
           builder.append(rightSide))) {
         return false;
     }
 
     outerArgs.rval().setString(builder.result());
     return true;
 }
 
+static const uint32_t ReplaceOptArg = 2;
+
 /*
  * Pattern match the script to check if it is is indexing into a particular
  * object, e.g. 'function(a) { return b[a]; }'. Avoid calling the script in
  * such cases, which are used by javascript packers (particularly the popular
  * Dean Edwards packer) to efficiently encode large scripts. We only handle the
  * code patterns generated by such packers here.
  */
 static bool
@@ -3053,31 +3012,38 @@ js::str_replace(JSContext *cx, unsigned 
      *
      * However, if the user invokes our (non-standard) |flags| argument
      * extension then we revert to creating a regular expression. Note that
      * this is observable behavior through the side-effect mutation of the
      * |RegExp| statics.
      */
 
     const FlatMatch *fm = rdata.g.tryFlatMatch(cx, rdata.str, ReplaceOptArg, args.length(), false);
-
     if (!fm) {
         if (cx->isExceptionPending())  /* oom in RopeMatch in tryFlatMatch */
             return false;
         return str_replace_regexp(cx, args, rdata);
     }
 
     if (fm->match() < 0) {
         args.rval().setString(rdata.str);
         return true;
     }
 
     if (rdata.lambda)
         return str_replace_flat_lambda(cx, args, rdata, *fm);
-    return StrReplaceString(cx, rdata, *fm, args.rval());
+
+    /*
+     * Note: we could optimize the text.length == pattern.length case if we wanted,
+     * even in the presence of dollar metachars.
+     */
+    if (rdata.dollar)
+        return BuildDollarReplacement(cx, rdata.str, rdata.repstr, rdata.dollar, *fm, &args);
+
+    return BuildFlatReplacement(cx, rdata.str, rdata.repstr, *fm, &args);
 }
 
 namespace {
 
 class SplitMatchResult {
     size_t endIndex_;
     size_t length_;
 
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -365,18 +365,14 @@ str_split_string(JSContext *cx, HandleTy
 bool
 str_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
             MutableHandleObject objp);
 
 bool
 str_replace_regexp_raw(JSContext *cx, HandleString string, HandleObject regexp,
                        HandleString replacement, MutableHandleValue rval);
 
-bool
-str_replace_string_raw(JSContext *cx, HandleString string, HandleString pattern,
-                       HandleString replacement, MutableHandleValue rval);
-
 } /* namespace js */
 
 extern bool
 js_String(JSContext *cx, unsigned argc, js::Value *vp);
 
 #endif /* jsstr_h */