зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1438727: [Part 18] Add StringObject Concat r=tcampbell
--HG-- extra : rebase_source : addd0efac40facb2a5987d899a83aeec79e6d7dd
This commit is contained in:
Родитель
3a971ac57a
Коммит
40ba10080a
|
@ -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;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче