From 40ba10080a941b5d47a38c661c77ef0fa23bfaca Mon Sep 17 00:00:00 2001 From: Matthew Gaudet Date: Wed, 9 May 2018 16:19:58 -0400 Subject: [PATCH] Bug 1438727: [Part 18] Add StringObject Concat r=tcampbell --HG-- extra : rebase_source : addd0efac40facb2a5987d899a83aeec79e6d7dd --- js/src/jit/BaselineCacheIRCompiler.cpp | 37 ++++++++++++++++ js/src/jit/CacheIR.cpp | 33 ++++++++++++++ js/src/jit/CacheIR.h | 6 +++ js/src/jit/IonCacheIRCompiler.cpp | 27 ++++++++++++ js/src/jit/SharedIC.cpp | 59 ++------------------------ js/src/jit/VMFunctions.cpp | 58 +++++++++++++++++++++++++ js/src/jit/VMFunctions.h | 7 +++ 7 files changed, 172 insertions(+), 55 deletions(-) diff --git a/js/src/jit/BaselineCacheIRCompiler.cpp b/js/src/jit/BaselineCacheIRCompiler.cpp index d1781bd39eec..138658a9f874 100644 --- a/js/src/jit/BaselineCacheIRCompiler.cpp +++ b/js/src/jit/BaselineCacheIRCompiler.cpp @@ -47,6 +47,7 @@ class MOZ_RAII BaselineCacheIRCompiler : public CacheIRCompiler bool makesGCCalls_; MOZ_MUST_USE bool callVM(MacroAssembler& masm, const VMFunction& fun); + MOZ_MUST_USE bool tailCallVM(MacroAssembler& masm, const VMFunction& fun); MOZ_MUST_USE bool callTypeUpdateIC(Register obj, ValueOperand val, Register scratch, LiveGeneralRegisterSet saveRegs); @@ -158,6 +159,20 @@ BaselineCacheIRCompiler::callVM(MacroAssembler& masm, const VMFunction& fun) return true; } +bool +BaselineCacheIRCompiler::tailCallVM(MacroAssembler& masm, const VMFunction& fun) +{ + MOZ_ASSERT(!inStubFrame_); + + TrampolinePtr code = cx_->runtime()->jitRuntime()->getVMWrapper(fun); + MOZ_ASSERT(fun.expectTailCall == TailCall); + MOZ_ASSERT(engine_ == ICStubEngine::Baseline); + size_t argSize = fun.explicitStackSlots() * sizeof(void*); + + EmitBaselineTailCallVM(code, masm, argSize); + return true; +} + JitCode* BaselineCacheIRCompiler::compile() { @@ -2422,3 +2437,25 @@ BaselineCacheIRCompiler::emitCallStringConcatResult() stubFrame.leave(masm); return true; } + +bool +BaselineCacheIRCompiler::emitCallStringObjectConcatResult() +{ + ValueOperand lhs = allocator.useValueRegister(masm, reader.valOperandId()); + ValueOperand rhs = allocator.useValueRegister(masm, reader.valOperandId()); + + allocator.discardStack(masm); + + // For the expression decompiler + EmitRestoreTailCallReg(masm); + masm.pushValue(lhs); + masm.pushValue(rhs); + + masm.pushValue(rhs); + masm.pushValue(lhs); + + if (!tailCallVM(masm, DoConcatStringObjectInfo)) + return false; + + return true; +} diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp index a91dbe998666..5e3543c3d05d 100644 --- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -5114,6 +5114,8 @@ BinaryArithIRGenerator::tryAttachStub() return true; if (tryAttachStringConcat()) return true; + if (tryAttachStringObjectConcat()) + return true; trackAttached(IRGenerator::NotAttached); return false; @@ -5291,6 +5293,37 @@ BinaryArithIRGenerator::tryAttachStringConcat() return true; } +bool +BinaryArithIRGenerator::tryAttachStringObjectConcat() +{ + if (op_ != JSOP_ADD) + return false; + + if (!(lhs_.isObject() && rhs_.isString()) && + !(lhs_.isString() && rhs_.isObject())) + return false; + + ValOperandId lhsId(writer.setInputOperandId(0)); + ValOperandId rhsId(writer.setInputOperandId(1)); + + // This guard is actually overly tight, as the runtime + // helper can handle lhs or rhs being a string, so long + // as the other is an object. + if (lhs_.isString()) { + writer.guardIsString(lhsId); + writer.guardIsObject(rhsId); + } else { + writer.guardIsObject(lhsId); + writer.guardIsString(rhsId); + } + + writer.callStringObjectConcatResult(lhsId, rhsId); + + writer.returnFromIC(); + trackAttached("BinaryArith.StringObjectConcat"); + return true; +} + bool BinaryArithIRGenerator::tryAttachBooleanWithInt32() { diff --git a/js/src/jit/CacheIR.h b/js/src/jit/CacheIR.h index 001a88196a37..2636b7050f10 100644 --- a/js/src/jit/CacheIR.h +++ b/js/src/jit/CacheIR.h @@ -319,6 +319,7 @@ extern const char* CacheKindNames[]; \ _(CallStringSplitResult) \ _(CallStringConcatResult) \ + _(CallStringObjectConcatResult) \ \ _(CompareStringResult) \ _(CompareObjectResult) \ @@ -1235,6 +1236,10 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter writeOpWithOperandId(CacheOp::CallStringConcatResult, lhs); writeOperandId(rhs); } + void callStringObjectConcatResult(ValOperandId lhs, ValOperandId rhs) { + writeOpWithOperandId(CacheOp::CallStringObjectConcatResult, lhs); + writeOperandId(rhs); + } void callStringSplitResult(StringOperandId str, StringOperandId sep, ObjectGroup* group) { writeOp(CacheOp::CallStringSplitResult); writeOperandId(str); @@ -1886,6 +1891,7 @@ class MOZ_RAII BinaryArithIRGenerator : public IRGenerator bool tryAttachDoubleWithInt32(); bool tryAttachBooleanWithInt32(); bool tryAttachStringConcat(); + bool tryAttachStringObjectConcat(); public: BinaryArithIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc, ICState::Mode, diff --git a/js/src/jit/IonCacheIRCompiler.cpp b/js/src/jit/IonCacheIRCompiler.cpp index 039e84f9c20c..4cdd1ac5dd9d 100644 --- a/js/src/jit/IonCacheIRCompiler.cpp +++ b/js/src/jit/IonCacheIRCompiler.cpp @@ -2556,3 +2556,30 @@ IonCacheIRCompiler::emitCallStringConcatResult() masm.tagValue(JSVAL_TYPE_STRING, ReturnReg, output.valueReg()); return true; } + +typedef bool (*DoConcatStringObjectFn)(JSContext*, HandleValue, HandleValue, + MutableHandleValue); +const VMFunction DoIonConcatStringObjectInfo = + FunctionInfo(DoConcatStringObject, "DoIonConcatStringObject"); + +bool +IonCacheIRCompiler::emitCallStringObjectConcatResult() +{ + AutoSaveLiveRegisters save(*this); + AutoOutputRegister output(*this); + + ValueOperand lhs = allocator.useValueRegister(masm, reader.valOperandId()); + ValueOperand rhs = allocator.useValueRegister(masm, reader.valOperandId()); + + allocator.discardStack(masm); + + prepareVMCall(masm, save); + masm.Push(rhs); + masm.Push(lhs); + + if (!callVM(masm, DoIonConcatStringObjectInfo)) + return false; + + masm.storeCallResultValue(output); + return true; +} diff --git a/js/src/jit/SharedIC.cpp b/js/src/jit/SharedIC.cpp index a33ae8c5ea61..782fbea6a62b 100644 --- a/js/src/jit/SharedIC.cpp +++ b/js/src/jit/SharedIC.cpp @@ -977,60 +977,9 @@ ICBinaryArith_StringConcat::Compiler::generateStubCode(MacroAssembler& masm) return true; } -static JSString* -ConvertObjectToStringForConcat(JSContext* cx, HandleValue obj) -{ - MOZ_ASSERT(obj.isObject()); - RootedValue rootedObj(cx, obj); - if (!ToPrimitive(cx, &rootedObj)) - return nullptr; - return ToString(cx, rootedObj); -} - -static bool -DoConcatStringObject(JSContext* cx, bool lhsIsString, HandleValue lhs, HandleValue rhs, - MutableHandleValue res) -{ - JSString* lstr = nullptr; - JSString* rstr = nullptr; - if (lhsIsString) { - // Convert rhs first. - MOZ_ASSERT(lhs.isString() && rhs.isObject()); - rstr = ConvertObjectToStringForConcat(cx, rhs); - if (!rstr) - return false; - - // lhs is already string. - lstr = lhs.toString(); - } else { - MOZ_ASSERT(rhs.isString() && lhs.isObject()); - // Convert lhs first. - lstr = ConvertObjectToStringForConcat(cx, lhs); - if (!lstr) - return false; - - // rhs is already string. - rstr = rhs.toString(); - } - - JSString* str = ConcatStrings(cx, lstr, rstr); - if (!str) { - RootedString nlstr(cx, lstr), nrstr(cx, rstr); - str = ConcatStrings(cx, nlstr, nrstr); - if (!str) - return false; - } - - // Technically, we need to call TypeScript::MonitorString for this PC, however - // it was called when this stub was attached so it's OK. - - res.setString(str); - return true; -} - -typedef bool (*DoConcatStringObjectFn)(JSContext*, bool lhsIsString, HandleValue, HandleValue, +typedef bool (*DoConcatStringObjectFn)(JSContext*, HandleValue, HandleValue, MutableHandleValue); -static const VMFunction DoConcatStringObjectInfo = +static const VMFunction DoSharedConcatStringObjectInfo = FunctionInfo(DoConcatStringObject, "DoConcatStringObject", TailCall, PopValues(2)); @@ -1056,8 +1005,8 @@ ICBinaryArith_StringObjectConcat::Compiler::generateStubCode(MacroAssembler& mas // Push arguments. masm.pushValue(R1); masm.pushValue(R0); - masm.push(Imm32(lhsIsString_)); - if (!tailCallVM(DoConcatStringObjectInfo, masm)) + + if (!tailCallVM(DoSharedConcatStringObjectInfo, masm)) return false; // Failure case - jump to next stub diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 99cf7ae393a7..07d244399d05 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -1893,5 +1893,63 @@ typedef bool (*SetObjectElementFn)(JSContext*, HandleObject, HandleValue, const VMFunction SetObjectElementInfo = FunctionInfo(js::SetObjectElement, "SetObjectElement"); + +static JSString* +ConvertObjectToStringForConcat(JSContext* cx, HandleValue obj) +{ + MOZ_ASSERT(obj.isObject()); + RootedValue rootedObj(cx, obj); + if (!ToPrimitive(cx, &rootedObj)) + return nullptr; + return ToString(cx, rootedObj); +} + +bool +DoConcatStringObject(JSContext* cx, HandleValue lhs, HandleValue rhs, + MutableHandleValue res) +{ + JSString* lstr = nullptr; + JSString* rstr = nullptr; + + if (lhs.isString()) { + // Convert rhs first. + MOZ_ASSERT(lhs.isString() && rhs.isObject()); + rstr = ConvertObjectToStringForConcat(cx, rhs); + if (!rstr) + return false; + + // lhs is already string. + lstr = lhs.toString(); + } else { + MOZ_ASSERT(rhs.isString() && lhs.isObject()); + // Convert lhs first. + lstr = ConvertObjectToStringForConcat(cx, lhs); + if (!lstr) + return false; + + // rhs is already string. + rstr = rhs.toString(); + } + + JSString* str = ConcatStrings(cx, lstr, rstr); + if (!str) { + RootedString nlstr(cx, lstr), nrstr(cx, rstr); + str = ConcatStrings(cx, nlstr, nrstr); + if (!str) + return false; + } + + // Technically, we need to call TypeScript::MonitorString for this PC, however + // it was called when this stub was attached so it's OK. + + res.setString(str); + return true; +} + +typedef bool (*DoConcatStringObjectFn)(JSContext*, HandleValue, HandleValue, + MutableHandleValue); +const VMFunction DoConcatStringObjectInfo = + FunctionInfo(DoConcatStringObject, "DoConcatStringObject", TailCall, PopValues(2)); + } // namespace jit } // namespace js diff --git a/js/src/jit/VMFunctions.h b/js/src/jit/VMFunctions.h index 5344f96a95be..bc00d8f514aa 100644 --- a/js/src/jit/VMFunctions.h +++ b/js/src/jit/VMFunctions.h @@ -953,6 +953,13 @@ CloseIteratorFromIon(JSContext* cx, JSObject* obj); extern const VMFunction SetObjectElementInfo; +bool +DoConcatStringObject(JSContext* cx, HandleValue lhs, HandleValue rhs, + MutableHandleValue res); + +// This is the tailcall version of DoConcatStringObject +extern const VMFunction DoConcatStringObjectInfo; + extern const VMFunction StringsEqualInfo; extern const VMFunction StringsNotEqualInfo;