Bug 1438727: [Part 18] Add StringObject Concat r=tcampbell

--HG--
extra : rebase_source : addd0efac40facb2a5987d899a83aeec79e6d7dd
This commit is contained in:
Matthew Gaudet 2018-05-09 16:19:58 -04:00
Родитель 3a971ac57a
Коммит 40ba10080a
7 изменённых файлов: 172 добавлений и 55 удалений

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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()
{

Просмотреть файл

@ -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,

Просмотреть файл

@ -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<DoConcatStringObjectFn>(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;
}

Просмотреть файл

@ -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<CanGC>(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<NoGC>(cx, lstr, rstr);
if (!str) {
RootedString nlstr(cx, lstr), nrstr(cx, rstr);
str = ConcatStrings<CanGC>(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<DoConcatStringObjectFn>(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

Просмотреть файл

@ -1893,5 +1893,63 @@ typedef bool (*SetObjectElementFn)(JSContext*, HandleObject, HandleValue,
const VMFunction SetObjectElementInfo =
FunctionInfo<SetObjectElementFn>(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<CanGC>(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<NoGC>(cx, lstr, rstr);
if (!str) {
RootedString nlstr(cx, lstr), nrstr(cx, rstr);
str = ConcatStrings<CanGC>(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<DoConcatStringObjectFn>(DoConcatStringObject, "DoConcatStringObject", TailCall, PopValues(2));
} // namespace jit
} // namespace js

Просмотреть файл

@ -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;