зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1608771 - Part 1, BigInt<>I64 conversion for inlined calls r=wingo,lth
This is part 1 of implementing the Wasm BigInt<>I64 conversion proposal for inlined Ion to Wasm calls. This part implements Ion MIR and LIR instructions that are needed for conversion between BigInts and I64. Differential Revision: https://phabricator.services.mozilla.com/D65233
This commit is contained in:
Родитель
ebf7dd1da8
Коммит
fb18e7c404
|
@ -4626,6 +4626,126 @@ void CodeGenerator::visitToNumeric(LToNumeric* lir) {
|
||||||
masm.bind(ool->rejoin());
|
masm.bind(ool->rejoin());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CodeGenerator::visitBooleanToInt64(LBooleanToInt64* lir) {
|
||||||
|
Register input = ToRegister(lir->input());
|
||||||
|
Register64 output = ToOutRegister64(lir);
|
||||||
|
|
||||||
|
masm.move32To64ZeroExtend(input, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeGenerator::emitStringToInt64(LInstruction* lir, Register input,
|
||||||
|
Register temp, Register64 output) {
|
||||||
|
masm.reserveStack(sizeof(uint64_t));
|
||||||
|
masm.moveStackPtrTo(temp);
|
||||||
|
pushArg(temp);
|
||||||
|
pushArg(input);
|
||||||
|
|
||||||
|
using Fn = bool (*)(JSContext*, HandleString, uint64_t*, bool*);
|
||||||
|
callVM<Fn, DoStringToInt64>(lir);
|
||||||
|
|
||||||
|
masm.load64(Address(masm.getStackPointer(), 0), output);
|
||||||
|
masm.freeStack(sizeof(uint64_t));
|
||||||
|
bailoutIfFalseBool(ReturnReg, lir->snapshot());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeGenerator::visitStringToInt64(LStringToInt64* lir) {
|
||||||
|
Register input = ToRegister(lir->input());
|
||||||
|
Register temp = ToTempRegisterOrInvalid(lir->temp());
|
||||||
|
Register64 output = ToOutRegister64(lir);
|
||||||
|
MOZ_ASSERT(lir->mir()->input()->type() == MIRType::String);
|
||||||
|
|
||||||
|
emitStringToInt64(lir, input, temp, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeGenerator::visitValueToInt64(LValueToInt64* lir) {
|
||||||
|
ValueOperand input = ToValue(lir, LValueToInt64::Input);
|
||||||
|
Register64 output = ToOutRegister64(lir);
|
||||||
|
Register scratch = ToTempRegisterOrInvalid(lir->temp());
|
||||||
|
Register tag = masm.extractTag(input, scratch);
|
||||||
|
Label fail, done;
|
||||||
|
|
||||||
|
bool maybeBigInt = lir->mir()->input()->mightBeType(MIRType::BigInt);
|
||||||
|
bool maybeBool = lir->mir()->input()->mightBeType(MIRType::Boolean);
|
||||||
|
bool maybeString = lir->mir()->input()->mightBeType(MIRType::String);
|
||||||
|
int checks = int(maybeBigInt) + int(maybeBool) + int(maybeString);
|
||||||
|
|
||||||
|
if (checks == 0) {
|
||||||
|
// Bail on other types.
|
||||||
|
masm.jump(&fail);
|
||||||
|
} else {
|
||||||
|
// BigInt.
|
||||||
|
if (maybeBigInt) {
|
||||||
|
Label notBigInt;
|
||||||
|
masm.branchTestBigInt(Assembler::NotEqual, tag, ¬BigInt);
|
||||||
|
masm.unboxBigInt(input, scratch);
|
||||||
|
Register bigint = input.scratchReg();
|
||||||
|
masm.movePtr(scratch, bigint);
|
||||||
|
masm.loadBigInt64(bigint, output);
|
||||||
|
masm.jump(&done);
|
||||||
|
masm.bind(¬BigInt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boolean
|
||||||
|
if (maybeBool) {
|
||||||
|
Label notBoolean;
|
||||||
|
masm.branchTestBoolean(Assembler::NotEqual, tag, ¬Boolean);
|
||||||
|
Register unboxed = ToTempUnboxRegister(lir->tempToUnbox());
|
||||||
|
unboxed = masm.extractBoolean(input, unboxed);
|
||||||
|
masm.move32To64ZeroExtend(unboxed, output);
|
||||||
|
masm.jump(&done);
|
||||||
|
masm.bind(¬Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
// String
|
||||||
|
if (maybeString) {
|
||||||
|
masm.branchTestString(Assembler::NotEqual, tag, &fail);
|
||||||
|
#ifdef JS_NUNBOX32
|
||||||
|
Register unboxed = input.payloadReg();
|
||||||
|
#else
|
||||||
|
Register unboxed = ToTempUnboxRegister(lir->tempToUnbox());
|
||||||
|
#endif
|
||||||
|
masm.unboxString(input, unboxed);
|
||||||
|
emitStringToInt64(lir, unboxed, scratch, output);
|
||||||
|
masm.jump(&done);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bailoutFrom(&fail, lir->snapshot());
|
||||||
|
masm.bind(&done);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeGenerator::visitTruncateBigIntToInt64(LTruncateBigIntToInt64* lir) {
|
||||||
|
Register operand = ToRegister(lir->input());
|
||||||
|
Register64 output = ToOutRegister64(lir);
|
||||||
|
MOZ_ASSERT(lir->mir()->input()->type() == MIRType::BigInt);
|
||||||
|
|
||||||
|
masm.loadBigInt64(operand, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeGenerator::visitInt64ToBigInt(LInt64ToBigInt* lir) {
|
||||||
|
MOZ_ASSERT(lir->mir()->input()->type() == MIRType::Int64);
|
||||||
|
|
||||||
|
Register64 input = ToRegister64(lir->getInt64Operand(LInt64ToBigInt::Input));
|
||||||
|
Register temp = ToTempRegisterOrInvalid(lir->temp1());
|
||||||
|
Register bigint = ToTempRegisterOrInvalid(lir->temp2());
|
||||||
|
Register output = ToRegister(lir->getDef(0));
|
||||||
|
|
||||||
|
#if JS_BITS_PER_WORD == 32
|
||||||
|
using Fn = BigInt* (*)(JSContext*, uint32_t, uint32_t);
|
||||||
|
OutOfLineCode* ool = oolCallVM<Fn, jit::CreateBigIntFromInt64>(
|
||||||
|
lir, ArgList(input.low, input.high), StoreRegisterTo(output));
|
||||||
|
#else
|
||||||
|
using Fn = BigInt* (*)(JSContext*, uint64_t);
|
||||||
|
OutOfLineCode* ool = oolCallVM<Fn, jit::CreateBigIntFromInt64>(
|
||||||
|
lir, ArgList(input), StoreRegisterTo(output));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
masm.newGCBigInt(bigint, temp, ool->entry(), true);
|
||||||
|
masm.initializeBigInt64(Scalar::BigInt64, bigint, input);
|
||||||
|
masm.movePtr(bigint, output);
|
||||||
|
masm.bind(ool->rejoin());
|
||||||
|
}
|
||||||
|
|
||||||
void CodeGenerator::visitTypeBarrierV(LTypeBarrierV* lir) {
|
void CodeGenerator::visitTypeBarrierV(LTypeBarrierV* lir) {
|
||||||
ValueOperand operand = ToValue(lir, LTypeBarrierV::Input);
|
ValueOperand operand = ToValue(lir, LTypeBarrierV::Input);
|
||||||
Register unboxScratch = ToTempRegisterOrInvalid(lir->unboxTemp());
|
Register unboxScratch = ToTempRegisterOrInvalid(lir->unboxTemp());
|
||||||
|
|
|
@ -265,6 +265,9 @@ class CodeGenerator final : public CodeGeneratorSpecific {
|
||||||
template <class OrderedHashTable>
|
template <class OrderedHashTable>
|
||||||
void emitLoadIteratorValues(Register result, Register temp, Register front);
|
void emitLoadIteratorValues(Register result, Register temp, Register front);
|
||||||
|
|
||||||
|
void emitStringToInt64(LInstruction* lir, Register input, Register temp,
|
||||||
|
Register64 output);
|
||||||
|
|
||||||
template <size_t NumDefs>
|
template <size_t NumDefs>
|
||||||
void emitIonToWasmCallBase(LIonToWasmCallBase<NumDefs>* lir);
|
void emitIonToWasmCallBase(LIonToWasmCallBase<NumDefs>* lir);
|
||||||
|
|
||||||
|
|
|
@ -2200,6 +2200,66 @@ void LIRGenerator::visitTruncateToInt32(MTruncateToInt32* truncate) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LIRGenerator::visitToInt64(MToInt64* ins) {
|
||||||
|
MDefinition* opd = ins->input();
|
||||||
|
|
||||||
|
switch (opd->type()) {
|
||||||
|
case MIRType::Value: {
|
||||||
|
LValueToInt64* lir =
|
||||||
|
new (alloc()) LValueToInt64(useBox(opd), temp(), tempToUnbox());
|
||||||
|
assignSnapshot(lir, Bailout_NonPrimitiveInput);
|
||||||
|
defineInt64(lir, ins);
|
||||||
|
assignSafepoint(lir, ins);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MIRType::Boolean: {
|
||||||
|
LBooleanToInt64* lir =
|
||||||
|
new (alloc()) LBooleanToInt64(useRegisterAtStart(opd));
|
||||||
|
defineInt64(lir, ins);
|
||||||
|
assignSafepoint(lir, ins);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MIRType::String: {
|
||||||
|
LStringToInt64* lir =
|
||||||
|
new (alloc()) LStringToInt64(useRegister(opd), temp());
|
||||||
|
// May bail out on parse failure.
|
||||||
|
assignSnapshot(lir, Bailout_NonPrimitiveInput);
|
||||||
|
defineInt64(lir, ins);
|
||||||
|
assignSafepoint(lir, ins);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// An Int64 may be passed here from a BigInt to Int64 conversion.
|
||||||
|
case MIRType::Int64: {
|
||||||
|
redefine(ins, opd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Undefined, Null, Number, and Symbol throw.
|
||||||
|
// Objects may be effectful.
|
||||||
|
// BigInt operands are eliminated by the type policy.
|
||||||
|
MOZ_CRASH("unexpected type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LIRGenerator::visitTruncateBigIntToInt64(MTruncateBigIntToInt64* ins) {
|
||||||
|
MOZ_ASSERT(ins->input()->type() == MIRType::BigInt);
|
||||||
|
LTruncateBigIntToInt64* lir =
|
||||||
|
new (alloc()) LTruncateBigIntToInt64(useRegister(ins->input()));
|
||||||
|
defineInt64(lir, ins);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LIRGenerator::visitInt64ToBigInt(MInt64ToBigInt* ins) {
|
||||||
|
MOZ_ASSERT(ins->input()->type() == MIRType::Int64);
|
||||||
|
LInt64ToBigInt* lir =
|
||||||
|
new (alloc()) LInt64ToBigInt(useInt64(ins->input()), temp(), temp());
|
||||||
|
define(lir, ins);
|
||||||
|
assignSafepoint(lir, ins);
|
||||||
|
}
|
||||||
|
|
||||||
void LIRGenerator::visitWasmTruncateToInt32(MWasmTruncateToInt32* ins) {
|
void LIRGenerator::visitWasmTruncateToInt32(MWasmTruncateToInt32* ins) {
|
||||||
MDefinition* input = ins->input();
|
MDefinition* input = ins->input();
|
||||||
switch (input->type()) {
|
switch (input->type()) {
|
||||||
|
|
|
@ -3725,6 +3725,52 @@ MDefinition* MToNumeric::foldsTo(TempAllocator& alloc) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MDefinition* MTruncateBigIntToInt64::foldsTo(TempAllocator& alloc) {
|
||||||
|
MDefinition* input = getOperand(0);
|
||||||
|
|
||||||
|
if (input->isBox()) {
|
||||||
|
input = input->getOperand(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the operand converts an I64 to BigInt, drop both conversions.
|
||||||
|
if (input->isInt64ToBigInt()) {
|
||||||
|
return input->getOperand(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fold this operation if the input operand is constant.
|
||||||
|
if (input->isConstant()) {
|
||||||
|
return MConstant::NewInt64(
|
||||||
|
alloc, BigInt::toInt64(input->toConstant()->toBigInt()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
MDefinition* MToInt64::foldsTo(TempAllocator& alloc) {
|
||||||
|
MDefinition* input = getOperand(0);
|
||||||
|
|
||||||
|
if (input->isBox()) {
|
||||||
|
input = input->getOperand(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// When the input is an Int64 already, just return it.
|
||||||
|
if (input->type() == MIRType::Int64) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fold this operation if the input operand is constant.
|
||||||
|
if (input->isConstant()) {
|
||||||
|
switch (input->type()) {
|
||||||
|
case MIRType::Boolean:
|
||||||
|
return MConstant::NewInt64(alloc, input->toConstant()->toBoolean());
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
MDefinition* MToNumberInt32::foldsTo(TempAllocator& alloc) {
|
MDefinition* MToNumberInt32::foldsTo(TempAllocator& alloc) {
|
||||||
MDefinition* input = getOperand(0);
|
MDefinition* input = getOperand(0);
|
||||||
|
|
||||||
|
|
|
@ -4224,6 +4224,74 @@ class MTruncateToInt32 : public MUnaryInstruction, public ToInt32Policy::Data {
|
||||||
ALLOW_CLONE(MTruncateToInt32)
|
ALLOW_CLONE(MTruncateToInt32)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Takes a Value or typed input and returns a suitable Int64 using the
|
||||||
|
// ToBigInt algorithm, possibly calling out to the VM for string, etc inputs.
|
||||||
|
class MToInt64 : public MUnaryInstruction, public ToInt64Policy::Data {
|
||||||
|
explicit MToInt64(MDefinition* arg) : MUnaryInstruction(classOpcode, arg) {
|
||||||
|
setResultType(MIRType::Int64);
|
||||||
|
setGuard(); // May bail on non-Bool, non-BigInt, or invalid Strings.
|
||||||
|
setMovable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
INSTRUCTION_HEADER(ToInt64)
|
||||||
|
TRIVIAL_NEW_WRAPPERS
|
||||||
|
|
||||||
|
void computeRange(TempAllocator& alloc) override;
|
||||||
|
bool congruentTo(const MDefinition* ins) const override {
|
||||||
|
return congruentIfOperandsEqual(ins);
|
||||||
|
}
|
||||||
|
|
||||||
|
AliasSet getAliasSet() const override { return AliasSet::None(); }
|
||||||
|
|
||||||
|
MDefinition* foldsTo(TempAllocator& alloc) override;
|
||||||
|
|
||||||
|
ALLOW_CLONE(MToInt64)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Takes a BigInt pointer and returns its toInt64 value.
|
||||||
|
class MTruncateBigIntToInt64 : public MUnaryInstruction,
|
||||||
|
public NoTypePolicy::Data {
|
||||||
|
explicit MTruncateBigIntToInt64(MDefinition* arg)
|
||||||
|
: MUnaryInstruction(classOpcode, arg) {
|
||||||
|
MOZ_ASSERT(arg->type() == MIRType::BigInt);
|
||||||
|
setResultType(MIRType::Int64);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
INSTRUCTION_HEADER(TruncateBigIntToInt64)
|
||||||
|
TRIVIAL_NEW_WRAPPERS
|
||||||
|
|
||||||
|
bool congruentTo(const MDefinition* ins) const override {
|
||||||
|
return congruentIfOperandsEqual(ins);
|
||||||
|
}
|
||||||
|
|
||||||
|
MDefinition* foldsTo(TempAllocator& alloc) override;
|
||||||
|
|
||||||
|
ALLOW_CLONE(MTruncateBigIntToInt64)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Takes an Int64 and returns a fresh BigInt pointer.
|
||||||
|
class MInt64ToBigInt : public MUnaryInstruction, public NoTypePolicy::Data {
|
||||||
|
explicit MInt64ToBigInt(MDefinition* arg)
|
||||||
|
: MUnaryInstruction(classOpcode, arg) {
|
||||||
|
MOZ_ASSERT(arg->type() == MIRType::Int64);
|
||||||
|
setResultType(MIRType::BigInt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
INSTRUCTION_HEADER(Int64ToBigInt)
|
||||||
|
TRIVIAL_NEW_WRAPPERS
|
||||||
|
|
||||||
|
bool congruentTo(const MDefinition* ins) const override {
|
||||||
|
return congruentIfOperandsEqual(ins);
|
||||||
|
}
|
||||||
|
|
||||||
|
AliasSet getAliasSet() const override { return AliasSet::None(); }
|
||||||
|
|
||||||
|
ALLOW_CLONE(MInt64ToBigInt)
|
||||||
|
};
|
||||||
|
|
||||||
// Converts any type to a string
|
// Converts any type to a string
|
||||||
class MToString : public MUnaryInstruction, public ToStringPolicy::Data {
|
class MToString : public MUnaryInstruction, public ToStringPolicy::Data {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -2631,6 +2631,16 @@ void MacroAssembler::Push(JSValueType type, Register reg) {
|
||||||
framePushed_ += sizeof(Value);
|
framePushed_ += sizeof(Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroAssembler::Push(const Register64 reg) {
|
||||||
|
#if JS_BITS_PER_WORD == 64
|
||||||
|
Push(reg.reg);
|
||||||
|
#else
|
||||||
|
MOZ_ASSERT(MOZ_LITTLE_ENDIAN(), "Big-endian not supported.");
|
||||||
|
Push(reg.high);
|
||||||
|
Push(reg.low);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void MacroAssembler::PushValue(const Address& addr) {
|
void MacroAssembler::PushValue(const Address& addr) {
|
||||||
MOZ_ASSERT(addr.base != getStackPointer());
|
MOZ_ASSERT(addr.base != getStackPointer());
|
||||||
pushValue(addr);
|
pushValue(addr);
|
||||||
|
|
|
@ -387,6 +387,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
|
||||||
void Push(const ValueOperand& val);
|
void Push(const ValueOperand& val);
|
||||||
void Push(const Value& val);
|
void Push(const Value& val);
|
||||||
void Push(JSValueType type, Register reg);
|
void Push(JSValueType type, Register reg);
|
||||||
|
void Push(const Register64 reg);
|
||||||
void PushValue(const Address& addr);
|
void PushValue(const Address& addr);
|
||||||
void PushEmptyRooted(VMFunctionData::RootType rootType);
|
void PushEmptyRooted(VMFunctionData::RootType rootType);
|
||||||
inline CodeOffset PushWithPatch(ImmWord word);
|
inline CodeOffset PushWithPatch(ImmWord word);
|
||||||
|
|
|
@ -1707,6 +1707,10 @@ void MTruncateToInt32::computeRange(TempAllocator& alloc) {
|
||||||
setRange(output);
|
setRange(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MToInt64::computeRange(TempAllocator& alloc) {
|
||||||
|
setRange(new (alloc) Range(getOperand(0)));
|
||||||
|
}
|
||||||
|
|
||||||
void MToNumeric::computeRange(TempAllocator& alloc) {
|
void MToNumeric::computeRange(TempAllocator& alloc) {
|
||||||
setRange(new (alloc) Range(getOperand(0)));
|
setRange(new (alloc) Range(getOperand(0)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -830,6 +830,35 @@ bool ToStringPolicy::staticAdjustInputs(TempAllocator& alloc,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ToInt64Policy::staticAdjustInputs(TempAllocator& alloc,
|
||||||
|
MInstruction* ins) {
|
||||||
|
MOZ_ASSERT(ins->isToInt64());
|
||||||
|
|
||||||
|
MDefinition* input = ins->getOperand(0);
|
||||||
|
MIRType type = input->type();
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case MIRType::BigInt: {
|
||||||
|
auto* replace = MTruncateBigIntToInt64::New(alloc, input);
|
||||||
|
ins->block()->insertBefore(ins, replace);
|
||||||
|
ins->replaceOperand(0, replace);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// No need for boxing for these types, because they are handled specially
|
||||||
|
// when this instruction is lowered to LIR.
|
||||||
|
case MIRType::Boolean:
|
||||||
|
case MIRType::String:
|
||||||
|
case MIRType::Int64:
|
||||||
|
case MIRType::Value:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template <unsigned Op>
|
template <unsigned Op>
|
||||||
bool ObjectPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
|
bool ObjectPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
|
||||||
MInstruction* ins) {
|
MInstruction* ins) {
|
||||||
|
@ -1152,6 +1181,7 @@ bool TypedArrayIndexPolicy::adjustInputs(TempAllocator& alloc,
|
||||||
_(ToDoublePolicy) \
|
_(ToDoublePolicy) \
|
||||||
_(ToInt32Policy) \
|
_(ToInt32Policy) \
|
||||||
_(ToStringPolicy) \
|
_(ToStringPolicy) \
|
||||||
|
_(ToInt64Policy) \
|
||||||
_(TypeBarrierPolicy) \
|
_(TypeBarrierPolicy) \
|
||||||
_(TypedArrayIndexPolicy)
|
_(TypedArrayIndexPolicy)
|
||||||
|
|
||||||
|
|
|
@ -336,6 +336,19 @@ class ToStringPolicy final : public TypePolicy {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Box non-Boolean, non-String, non-BigInt as input to a ToInt64 instruction.
|
||||||
|
class ToInt64Policy final : public TypePolicy {
|
||||||
|
public:
|
||||||
|
constexpr ToInt64Policy() = default;
|
||||||
|
EMPTY_DATA_;
|
||||||
|
static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc,
|
||||||
|
MInstruction* ins);
|
||||||
|
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc,
|
||||||
|
MInstruction* ins) const override {
|
||||||
|
return staticAdjustInputs(alloc, ins);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <unsigned Op>
|
template <unsigned Op>
|
||||||
class ObjectPolicy final : public TypePolicy {
|
class ObjectPolicy final : public TypePolicy {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -89,6 +89,7 @@ namespace jit {
|
||||||
_(CopyElementsForWrite, js::NativeObject::CopyElementsForWrite) \
|
_(CopyElementsForWrite, js::NativeObject::CopyElementsForWrite) \
|
||||||
_(CopyLexicalEnvironmentObject, js::jit::CopyLexicalEnvironmentObject) \
|
_(CopyLexicalEnvironmentObject, js::jit::CopyLexicalEnvironmentObject) \
|
||||||
_(CreateAsyncFromSyncIterator, js::CreateAsyncFromSyncIterator) \
|
_(CreateAsyncFromSyncIterator, js::CreateAsyncFromSyncIterator) \
|
||||||
|
_(CreateBigIntFromInt64, js::jit::CreateBigIntFromInt64) \
|
||||||
_(CreateGenerator, js::jit::CreateGenerator) \
|
_(CreateGenerator, js::jit::CreateGenerator) \
|
||||||
_(CreateThisForFunctionWithProto, js::CreateThisForFunctionWithProto) \
|
_(CreateThisForFunctionWithProto, js::CreateThisForFunctionWithProto) \
|
||||||
_(CreateThisFromIC, js::jit::CreateThisFromIC) \
|
_(CreateThisFromIC, js::jit::CreateThisFromIC) \
|
||||||
|
@ -115,6 +116,7 @@ namespace jit {
|
||||||
_(DoCallFallback, js::jit::DoCallFallback) \
|
_(DoCallFallback, js::jit::DoCallFallback) \
|
||||||
_(DoConcatStringObject, js::jit::DoConcatStringObject) \
|
_(DoConcatStringObject, js::jit::DoConcatStringObject) \
|
||||||
_(DoSpreadCallFallback, js::jit::DoSpreadCallFallback) \
|
_(DoSpreadCallFallback, js::jit::DoSpreadCallFallback) \
|
||||||
|
_(DoStringToInt64, js::jit::DoStringToInt64) \
|
||||||
_(DoToNumeric, js::jit::DoToNumeric) \
|
_(DoToNumeric, js::jit::DoToNumeric) \
|
||||||
_(DoTypeUpdateFallback, js::jit::DoTypeUpdateFallback) \
|
_(DoTypeUpdateFallback, js::jit::DoTypeUpdateFallback) \
|
||||||
_(EnterWith, js::jit::EnterWith) \
|
_(EnterWith, js::jit::EnterWith) \
|
||||||
|
|
|
@ -2004,6 +2004,32 @@ void* AllocateBigIntNoGC(JSContext* cx, bool requestMinorGC) {
|
||||||
return js::AllocateBigInt<NoGC>(cx, gc::TenuredHeap);
|
return js::AllocateBigInt<NoGC>(cx, gc::TenuredHeap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if JS_BITS_PER_WORD == 32
|
||||||
|
BigInt* CreateBigIntFromInt64(JSContext* cx, uint32_t low, uint32_t high) {
|
||||||
|
int64_t n = ((uint64_t)high << 32) + low;
|
||||||
|
return js::BigInt::createFromInt64(cx, n);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
BigInt* CreateBigIntFromInt64(JSContext* cx, uint64_t i64) {
|
||||||
|
return js::BigInt::createFromInt64(cx, i64);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool DoStringToInt64(JSContext* cx, HandleString str, uint64_t* res,
|
||||||
|
bool* parseSuccess) {
|
||||||
|
BigInt* bi;
|
||||||
|
*parseSuccess = true;
|
||||||
|
JS_TRY_VAR_OR_RETURN_FALSE(cx, bi, js::StringToBigInt(cx, str));
|
||||||
|
|
||||||
|
if (!bi) {
|
||||||
|
*parseSuccess = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
*res = js::BigInt::toUint64(bi);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template <EqualityKind Kind>
|
template <EqualityKind Kind>
|
||||||
bool BigIntEqual(BigInt* x, BigInt* y) {
|
bool BigIntEqual(BigInt* x, BigInt* y) {
|
||||||
AutoUnsafeCallWithABI unsafe;
|
AutoUnsafeCallWithABI unsafe;
|
||||||
|
|
|
@ -715,6 +715,10 @@ struct OutParamToDataType<uint32_t*> {
|
||||||
static const DataType result = Type_Int32;
|
static const DataType result = Type_Int32;
|
||||||
};
|
};
|
||||||
template <>
|
template <>
|
||||||
|
struct OutParamToDataType<uint64_t*> {
|
||||||
|
static const DataType result = Type_Pointer;
|
||||||
|
};
|
||||||
|
template <>
|
||||||
struct OutParamToDataType<uint8_t**> {
|
struct OutParamToDataType<uint8_t**> {
|
||||||
static const DataType result = Type_Pointer;
|
static const DataType result = Type_Pointer;
|
||||||
};
|
};
|
||||||
|
@ -1128,6 +1132,13 @@ bool IsPossiblyWrappedTypedArray(JSContext* cx, JSObject* obj, bool* result);
|
||||||
bool DoToNumeric(JSContext* cx, HandleValue arg, MutableHandleValue ret);
|
bool DoToNumeric(JSContext* cx, HandleValue arg, MutableHandleValue ret);
|
||||||
|
|
||||||
void* AllocateBigIntNoGC(JSContext* cx, bool requestMinorGC);
|
void* AllocateBigIntNoGC(JSContext* cx, bool requestMinorGC);
|
||||||
|
#if JS_BITS_PER_WORD == 32
|
||||||
|
BigInt* CreateBigIntFromInt64(JSContext* cx, uint32_t low, uint32_t high);
|
||||||
|
#else
|
||||||
|
BigInt* CreateBigIntFromInt64(JSContext* cx, uint64_t i64);
|
||||||
|
#endif
|
||||||
|
bool DoStringToInt64(JSContext* cx, HandleString str, uint64_t* res,
|
||||||
|
bool* parseSuccess);
|
||||||
|
|
||||||
template <EqualityKind Kind>
|
template <EqualityKind Kind>
|
||||||
bool BigIntEqual(BigInt* x, BigInt* y);
|
bool BigIntEqual(BigInt* x, BigInt* y);
|
||||||
|
|
|
@ -5493,6 +5493,96 @@ class LToNumeric : public LInstructionHelper<BOX_PIECES, BOX_PIECES, 0> {
|
||||||
static const size_t Input = 0;
|
static const size_t Input = 0;
|
||||||
|
|
||||||
const MToNumeric* mir() const { return mir_->toToNumeric(); }
|
const MToNumeric* mir() const { return mir_->toToNumeric(); }
|
||||||
|
const LDefinition* temp() { return getTemp(0); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert a Boolean to an Int64, following ToBigInt.
|
||||||
|
class LBooleanToInt64 : public LInstructionHelper<INT64_PIECES, 1, 0> {
|
||||||
|
public:
|
||||||
|
LIR_HEADER(BooleanToInt64)
|
||||||
|
|
||||||
|
explicit LBooleanToInt64(const LAllocation& input)
|
||||||
|
: LInstructionHelper(classOpcode) {
|
||||||
|
setOperand(Input, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const size_t Input = 0;
|
||||||
|
|
||||||
|
const MToInt64* mir() const { return mir_->toToInt64(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert a String to an Int64, following ToBigInt.
|
||||||
|
class LStringToInt64 : public LInstructionHelper<INT64_PIECES, 1, 1> {
|
||||||
|
public:
|
||||||
|
LIR_HEADER(StringToInt64)
|
||||||
|
|
||||||
|
explicit LStringToInt64(const LAllocation& input, const LDefinition& temp)
|
||||||
|
: LInstructionHelper(classOpcode) {
|
||||||
|
setOperand(Input, input);
|
||||||
|
setTemp(0, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const size_t Input = 0;
|
||||||
|
|
||||||
|
const MToInt64* mir() const { return mir_->toToInt64(); }
|
||||||
|
const LDefinition* temp() { return getTemp(0); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Simulate ToBigInt on a Value and produce a matching Int64.
|
||||||
|
class LValueToInt64 : public LInstructionHelper<INT64_PIECES, BOX_PIECES, 2> {
|
||||||
|
public:
|
||||||
|
LIR_HEADER(ValueToInt64)
|
||||||
|
|
||||||
|
explicit LValueToInt64(const LBoxAllocation& input, const LDefinition& temp,
|
||||||
|
const LDefinition& tempToUnbox)
|
||||||
|
: LInstructionHelper(classOpcode) {
|
||||||
|
setBoxOperand(Input, input);
|
||||||
|
setTemp(0, temp);
|
||||||
|
setTemp(1, tempToUnbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const size_t Input = 0;
|
||||||
|
|
||||||
|
const MToInt64* mir() const { return mir_->toToInt64(); }
|
||||||
|
const LDefinition* temp() { return getTemp(0); }
|
||||||
|
const LDefinition* tempToUnbox() { return getTemp(1); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Truncate a BigInt to an unboxed int64.
|
||||||
|
class LTruncateBigIntToInt64 : public LInstructionHelper<INT64_PIECES, 1, 0> {
|
||||||
|
public:
|
||||||
|
LIR_HEADER(TruncateBigIntToInt64)
|
||||||
|
|
||||||
|
explicit LTruncateBigIntToInt64(const LAllocation& input)
|
||||||
|
: LInstructionHelper(classOpcode) {
|
||||||
|
setOperand(Input, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const size_t Input = 0;
|
||||||
|
|
||||||
|
const MTruncateBigIntToInt64* mir() const {
|
||||||
|
return mir_->toTruncateBigIntToInt64();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a new BigInt* from an unboxed int64.
|
||||||
|
class LInt64ToBigInt : public LInstructionHelper<1, INT64_PIECES, 2> {
|
||||||
|
public:
|
||||||
|
LIR_HEADER(Int64ToBigInt)
|
||||||
|
|
||||||
|
explicit LInt64ToBigInt(const LInt64Allocation& input,
|
||||||
|
const LDefinition& temp1, const LDefinition& temp2)
|
||||||
|
: LInstructionHelper(classOpcode) {
|
||||||
|
setInt64Operand(Input, input);
|
||||||
|
setTemp(0, temp1);
|
||||||
|
setTemp(1, temp2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const size_t Input = 0;
|
||||||
|
|
||||||
|
const MInt64ToBigInt* mir() const { return mir_->toInt64ToBigInt(); }
|
||||||
|
const LDefinition* temp1() { return getTemp(0); }
|
||||||
|
const LDefinition* temp2() { return getTemp(1); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Guard that a value is in a TypeSet.
|
// Guard that a value is in a TypeSet.
|
||||||
|
|
Загрузка…
Ссылка в новой задаче