Commit 80fb2815 authored by Qifan Pan's avatar Qifan Pan Committed by V8 LUCI CQ

[turbofan] Rematerialize BigInt64 in deopt

This CL introduces two MachineTypes - SignedBigInt64 and UnsignedBigInt64, which are represented as Word64 but will be rematerialized to BigInt in deoptimization. This will avoid unnecessary conversions for BigInt64s when they are passed to StateValues.

Bug: v8:9407
Change-Id: I65fdee3e028ed8f9920b1c20ff78993c7784de48
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3858238Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarNico Hartmann <nicohartmann@chromium.org>
Commit-Queue: Qifan Pan <panq@google.com>
Cr-Commit-Position: refs/heads/main@{#83230}
parent 8199d70f
...@@ -79,6 +79,10 @@ std::ostream& operator<<(std::ostream& os, MachineSemantic type) { ...@@ -79,6 +79,10 @@ std::ostream& operator<<(std::ostream& os, MachineSemantic type) {
return os << "kTypeInt64"; return os << "kTypeInt64";
case MachineSemantic::kUint64: case MachineSemantic::kUint64:
return os << "kTypeUint64"; return os << "kTypeUint64";
case MachineSemantic::kSignedBigInt64:
return os << "kTypeSignedBigInt64";
case MachineSemantic::kUnsignedBigInt64:
return os << "kTypeUnsignedBigInt64";
case MachineSemantic::kNumber: case MachineSemantic::kNumber:
return os << "kTypeNumber"; return os << "kTypeNumber";
case MachineSemantic::kAny: case MachineSemantic::kAny:
......
...@@ -86,6 +86,8 @@ enum class MachineSemantic : uint8_t { ...@@ -86,6 +86,8 @@ enum class MachineSemantic : uint8_t {
kUint32, kUint32,
kInt64, kInt64,
kUint64, kUint64,
kSignedBigInt64,
kUnsignedBigInt64,
kNumber, kNumber,
kAny kAny
}; };
...@@ -193,6 +195,14 @@ class MachineType { ...@@ -193,6 +195,14 @@ class MachineType {
return MachineType(MachineRepresentation::kWord64, return MachineType(MachineRepresentation::kWord64,
MachineSemantic::kUint64); MachineSemantic::kUint64);
} }
constexpr static MachineType SignedBigInt64() {
return MachineType(MachineRepresentation::kWord64,
MachineSemantic::kSignedBigInt64);
}
constexpr static MachineType UnsignedBigInt64() {
return MachineType(MachineRepresentation::kWord64,
MachineSemantic::kUnsignedBigInt64);
}
constexpr static MachineType Float32() { constexpr static MachineType Float32() {
return MachineType(MachineRepresentation::kFloat32, return MachineType(MachineRepresentation::kFloat32,
MachineSemantic::kNumber); MachineSemantic::kNumber);
......
...@@ -1171,6 +1171,12 @@ void CodeGenerator::AddTranslationForOperand(Instruction* instr, ...@@ -1171,6 +1171,12 @@ void CodeGenerator::AddTranslationForOperand(Instruction* instr,
translations_.StoreUint32StackSlot(LocationOperand::cast(op)->index()); translations_.StoreUint32StackSlot(LocationOperand::cast(op)->index());
} else if (type == MachineType::Int64()) { } else if (type == MachineType::Int64()) {
translations_.StoreInt64StackSlot(LocationOperand::cast(op)->index()); translations_.StoreInt64StackSlot(LocationOperand::cast(op)->index());
} else if (type == MachineType::SignedBigInt64()) {
translations_.StoreSignedBigInt64StackSlot(
LocationOperand::cast(op)->index());
} else if (type == MachineType::UnsignedBigInt64()) {
translations_.StoreUnsignedBigInt64StackSlot(
LocationOperand::cast(op)->index());
} else { } else {
#if defined(V8_COMPRESS_POINTERS) #if defined(V8_COMPRESS_POINTERS)
CHECK(MachineRepresentation::kTagged == type.representation() || CHECK(MachineRepresentation::kTagged == type.representation() ||
...@@ -1199,6 +1205,10 @@ void CodeGenerator::AddTranslationForOperand(Instruction* instr, ...@@ -1199,6 +1205,10 @@ void CodeGenerator::AddTranslationForOperand(Instruction* instr,
translations_.StoreUint32Register(converter.ToRegister(op)); translations_.StoreUint32Register(converter.ToRegister(op));
} else if (type == MachineType::Int64()) { } else if (type == MachineType::Int64()) {
translations_.StoreInt64Register(converter.ToRegister(op)); translations_.StoreInt64Register(converter.ToRegister(op));
} else if (type == MachineType::SignedBigInt64()) {
translations_.StoreSignedBigInt64Register(converter.ToRegister(op));
} else if (type == MachineType::UnsignedBigInt64()) {
translations_.StoreUnsignedBigInt64Register(converter.ToRegister(op));
} else { } else {
#if defined(V8_COMPRESS_POINTERS) #if defined(V8_COMPRESS_POINTERS)
CHECK(MachineRepresentation::kTagged == type.representation() || CHECK(MachineRepresentation::kTagged == type.representation() ||
...@@ -1229,7 +1239,7 @@ void CodeGenerator::AddTranslationForOperand(Instruction* instr, ...@@ -1229,7 +1239,7 @@ void CodeGenerator::AddTranslationForOperand(Instruction* instr,
DCHECK_EQ(4, kSystemPointerSize); DCHECK_EQ(4, kSystemPointerSize);
Smi smi(static_cast<Address>(constant.ToInt32())); Smi smi(static_cast<Address>(constant.ToInt32()));
DCHECK(smi.IsSmi()); DCHECK(smi.IsSmi());
literal = DeoptimizationLiteral(smi.value()); literal = DeoptimizationLiteral(static_cast<double>(smi.value()));
} else if (type.representation() == MachineRepresentation::kBit) { } else if (type.representation() == MachineRepresentation::kBit) {
if (constant.ToInt32() == 0) { if (constant.ToInt32() == 0) {
literal = literal =
...@@ -1246,16 +1256,25 @@ void CodeGenerator::AddTranslationForOperand(Instruction* instr, ...@@ -1246,16 +1256,25 @@ void CodeGenerator::AddTranslationForOperand(Instruction* instr,
DCHECK(type.representation() != MachineRepresentation::kNone || DCHECK(type.representation() != MachineRepresentation::kNone ||
constant.ToInt32() == FrameStateDescriptor::kImpossibleValue); constant.ToInt32() == FrameStateDescriptor::kImpossibleValue);
if (type == MachineType::Uint32()) { if (type == MachineType::Uint32()) {
literal = DeoptimizationLiteral( literal =
static_cast<uint32_t>(constant.ToInt32())); DeoptimizationLiteral(static_cast<double>(constant.ToInt32()));
} else { } else {
literal = DeoptimizationLiteral(constant.ToInt32()); literal =
DeoptimizationLiteral(static_cast<double>(constant.ToInt32()));
} }
} }
break; break;
case Constant::kInt64: case Constant::kInt64:
DCHECK_EQ(8, kSystemPointerSize); DCHECK_EQ(8, kSystemPointerSize);
if (type.representation() == MachineRepresentation::kWord64) { if (type == MachineType::SignedBigInt64()) {
literal = DeoptimizationLiteral(constant.ToInt64());
} else if (type == MachineType::UnsignedBigInt64()) {
literal =
DeoptimizationLiteral(static_cast<uint64_t>(constant.ToInt64()));
} else if (type.representation() == MachineRepresentation::kWord64) {
CHECK_EQ(
constant.ToInt64(),
static_cast<int64_t>(static_cast<double>(constant.ToInt64())));
literal = literal =
DeoptimizationLiteral(static_cast<double>(constant.ToInt64())); DeoptimizationLiteral(static_cast<double>(constant.ToInt64()));
} else { } else {
...@@ -1264,7 +1283,7 @@ void CodeGenerator::AddTranslationForOperand(Instruction* instr, ...@@ -1264,7 +1283,7 @@ void CodeGenerator::AddTranslationForOperand(Instruction* instr,
DCHECK_EQ(MachineRepresentation::kTagged, type.representation()); DCHECK_EQ(MachineRepresentation::kTagged, type.representation());
Smi smi(static_cast<Address>(constant.ToInt64())); Smi smi(static_cast<Address>(constant.ToInt64()));
DCHECK(smi.IsSmi()); DCHECK(smi.IsSmi());
literal = DeoptimizationLiteral(smi.value()); literal = DeoptimizationLiteral(static_cast<double>(smi.value()));
} }
break; break;
case Constant::kFloat32: case Constant::kFloat32:
...@@ -1325,6 +1344,12 @@ Handle<Object> DeoptimizationLiteral::Reify(Isolate* isolate) const { ...@@ -1325,6 +1344,12 @@ Handle<Object> DeoptimizationLiteral::Reify(Isolate* isolate) const {
case DeoptimizationLiteralKind::kNumber: { case DeoptimizationLiteralKind::kNumber: {
return isolate->factory()->NewNumber(number_); return isolate->factory()->NewNumber(number_);
} }
case DeoptimizationLiteralKind::kSignedBigInt64: {
return BigInt::FromInt64(isolate, signed_bigint64_);
}
case DeoptimizationLiteralKind::kUnsignedBigInt64: {
return BigInt::FromUint64(isolate, unsigned_bigint64_);
}
case DeoptimizationLiteralKind::kInvalid: { case DeoptimizationLiteralKind::kInvalid: {
UNREACHABLE(); UNREACHABLE();
} }
......
...@@ -55,26 +55,52 @@ class InstructionOperandIterator { ...@@ -55,26 +55,52 @@ class InstructionOperandIterator {
size_t pos_; size_t pos_;
}; };
enum class DeoptimizationLiteralKind { kObject, kNumber, kInvalid }; enum class DeoptimizationLiteralKind {
kObject,
kNumber,
kSignedBigInt64,
kUnsignedBigInt64,
kInvalid
};
// Either a non-null Handle<Object> or a double. // A non-null Handle<Object>, a double, an int64_t, or a uint64_t.
class DeoptimizationLiteral { class DeoptimizationLiteral {
public: public:
DeoptimizationLiteral() DeoptimizationLiteral()
: kind_(DeoptimizationLiteralKind::kInvalid), object_(), number_(0) {} : kind_(DeoptimizationLiteralKind::kInvalid), object_() {}
explicit DeoptimizationLiteral(Handle<Object> object) explicit DeoptimizationLiteral(Handle<Object> object)
: kind_(DeoptimizationLiteralKind::kObject), object_(object) { : kind_(DeoptimizationLiteralKind::kObject), object_(object) {
CHECK(!object_.is_null()); CHECK(!object_.is_null());
} }
explicit DeoptimizationLiteral(double number) explicit DeoptimizationLiteral(double number)
: kind_(DeoptimizationLiteralKind::kNumber), number_(number) {} : kind_(DeoptimizationLiteralKind::kNumber), number_(number) {}
explicit DeoptimizationLiteral(int64_t signed_bigint64)
: kind_(DeoptimizationLiteralKind::kSignedBigInt64),
signed_bigint64_(signed_bigint64) {}
explicit DeoptimizationLiteral(uint64_t unsigned_bigint64)
: kind_(DeoptimizationLiteralKind::kUnsignedBigInt64),
unsigned_bigint64_(unsigned_bigint64) {}
Handle<Object> object() const { return object_; } Handle<Object> object() const { return object_; }
bool operator==(const DeoptimizationLiteral& other) const { bool operator==(const DeoptimizationLiteral& other) const {
return kind_ == other.kind_ && object_.equals(other.object_) && if (kind_ != other.kind_) {
base::bit_cast<uint64_t>(number_) == return false;
}
switch (kind_) {
case DeoptimizationLiteralKind::kObject:
return object_.equals(other.object_);
case DeoptimizationLiteralKind::kNumber:
return base::bit_cast<uint64_t>(number_) ==
base::bit_cast<uint64_t>(other.number_); base::bit_cast<uint64_t>(other.number_);
case DeoptimizationLiteralKind::kSignedBigInt64:
return signed_bigint64_ == other.signed_bigint64_;
case DeoptimizationLiteralKind::kUnsignedBigInt64:
return unsigned_bigint64_ == other.unsigned_bigint64_;
case DeoptimizationLiteralKind::kInvalid:
return true;
}
UNREACHABLE();
} }
Handle<Object> Reify(Isolate* isolate) const; Handle<Object> Reify(Isolate* isolate) const;
...@@ -91,8 +117,12 @@ class DeoptimizationLiteral { ...@@ -91,8 +117,12 @@ class DeoptimizationLiteral {
private: private:
DeoptimizationLiteralKind kind_; DeoptimizationLiteralKind kind_;
union {
Handle<Object> object_; Handle<Object> object_;
double number_ = 0; double number_;
int64_t signed_bigint64_;
uint64_t unsigned_bigint64_;
};
}; };
// These structs hold pc offsets for generated instructions and is only used // These structs hold pc offsets for generated instructions and is only used
......
...@@ -26,6 +26,10 @@ bool IsNonTruncatingMachineTypeFor(const MachineType& mt, const Type& type) { ...@@ -26,6 +26,10 @@ bool IsNonTruncatingMachineTypeFor(const MachineType& mt, const Type& type) {
if (type.IsNone()) return true; if (type.IsNone()) return true;
// TODO(nicohartmann@): Add more cases here. // TODO(nicohartmann@): Add more cases here.
if (type.Is(Type::BigInt())) { if (type.Is(Type::BigInt())) {
if (mt.representation() == MachineRepresentation::kWord64) {
return type.Is(Type::SignedBigInt64()) ||
type.Is(Type::UnsignedBigInt64());
}
return mt.representation() == MachineRepresentation::kTaggedPointer || return mt.representation() == MachineRepresentation::kTaggedPointer ||
mt.representation() == MachineRepresentation::kTagged; mt.representation() == MachineRepresentation::kTagged;
} }
......
...@@ -223,6 +223,11 @@ bool IsSomePositiveOrderedNumber(Type type) { ...@@ -223,6 +223,11 @@ bool IsSomePositiveOrderedNumber(Type type) {
return type.Is(Type::OrderedNumber()) && (type.IsNone() || type.Min() > 0); return type.Is(Type::OrderedNumber()) && (type.IsNone() || type.Min() > 0);
} }
inline bool IsLargeBigInt(Type type) {
return type.Is(Type::BigInt()) && !type.Is(Type::SignedBigInt64()) &&
!type.Is(Type::UnsignedBigInt64());
}
class JSONGraphWriterWithVerifierTypes : public JSONGraphWriter { class JSONGraphWriterWithVerifierTypes : public JSONGraphWriter {
public: public:
JSONGraphWriterWithVerifierTypes(std::ostream& os, const Graph* graph, JSONGraphWriterWithVerifierTypes(std::ostream& os, const Graph* graph,
...@@ -1307,6 +1312,14 @@ class RepresentationSelector { ...@@ -1307,6 +1312,14 @@ class RepresentationSelector {
return MachineType::AnyTagged(); return MachineType::AnyTagged();
} }
if (rep == MachineRepresentation::kWord64) { if (rep == MachineRepresentation::kWord64) {
if (type.Is(Type::SignedBigInt64())) {
return MachineType::SignedBigInt64();
}
if (type.Is(Type::UnsignedBigInt64())) {
return MachineType::UnsignedBigInt64();
}
if (type.Is(Type::BigInt())) { if (type.Is(Type::BigInt())) {
return MachineType::AnyTagged(); return MachineType::AnyTagged();
} }
...@@ -1328,13 +1341,11 @@ class RepresentationSelector { ...@@ -1328,13 +1341,11 @@ class RepresentationSelector {
void VisitStateValues(Node* node) { void VisitStateValues(Node* node) {
if (propagate<T>()) { if (propagate<T>()) {
for (int i = 0; i < node->InputCount(); i++) { for (int i = 0; i < node->InputCount(); i++) {
// When lowering 64 bit BigInts to Word64 representation, we have to // BigInt64s are rematerialized in deoptimization. The other BigInts
// make sure they are rematerialized before deoptimization. By // must be rematerialized before deoptimization. By propagating an
// propagating a AnyTagged use, the RepresentationChanger is going to // AnyTagged use, the RepresentationChanger is going to insert the
// insert the necessary conversions. // necessary conversions.
// TODO(nicohartmann): Remove, once the deoptimizer can rematerialize if (IsLargeBigInt(TypeOf(node->InputAt(i)))) {
// truncated BigInts.
if (TypeOf(node->InputAt(i)).Is(Type::BigInt())) {
EnqueueInput<T>(node, i, UseInfo::AnyTagged()); EnqueueInput<T>(node, i, UseInfo::AnyTagged());
} else { } else {
EnqueueInput<T>(node, i, UseInfo::Any()); EnqueueInput<T>(node, i, UseInfo::Any());
...@@ -1346,9 +1357,7 @@ class RepresentationSelector { ...@@ -1346,9 +1357,7 @@ class RepresentationSelector {
zone->New<ZoneVector<MachineType>>(node->InputCount(), zone); zone->New<ZoneVector<MachineType>>(node->InputCount(), zone);
for (int i = 0; i < node->InputCount(); i++) { for (int i = 0; i < node->InputCount(); i++) {
Node* input = node->InputAt(i); Node* input = node->InputAt(i);
// TODO(nicohartmann): Remove, once the deoptimizer can rematerialize if (IsLargeBigInt(TypeOf(input))) {
// truncated BigInts.
if (TypeOf(input).Is(Type::BigInt())) {
ConvertInput(node, i, UseInfo::AnyTagged()); ConvertInput(node, i, UseInfo::AnyTagged());
} }
...@@ -1377,9 +1386,7 @@ class RepresentationSelector { ...@@ -1377,9 +1386,7 @@ class RepresentationSelector {
// state-values node). // state-values node).
Node* accumulator = node.stack(); Node* accumulator = node.stack();
if (propagate<T>()) { if (propagate<T>()) {
// TODO(nicohartmann): Remove, once the deoptimizer can rematerialize if (IsLargeBigInt(TypeOf(accumulator))) {
// truncated BigInts.
if (TypeOf(accumulator).Is(Type::BigInt())) {
EnqueueInput<T>(node, FrameState::kFrameStateStackInput, EnqueueInput<T>(node, FrameState::kFrameStateStackInput,
UseInfo::AnyTagged()); UseInfo::AnyTagged());
} else { } else {
...@@ -1387,9 +1394,7 @@ class RepresentationSelector { ...@@ -1387,9 +1394,7 @@ class RepresentationSelector {
UseInfo::Any()); UseInfo::Any());
} }
} else if (lower<T>()) { } else if (lower<T>()) {
// TODO(nicohartmann): Remove, once the deoptimizer can rematerialize if (IsLargeBigInt(TypeOf(accumulator))) {
// truncated BigInts.
if (TypeOf(accumulator).Is(Type::BigInt())) {
ConvertInput(node, FrameState::kFrameStateStackInput, ConvertInput(node, FrameState::kFrameStateStackInput,
UseInfo::AnyTagged()); UseInfo::AnyTagged());
} }
...@@ -1424,9 +1429,7 @@ class RepresentationSelector { ...@@ -1424,9 +1429,7 @@ class RepresentationSelector {
void VisitObjectState(Node* node) { void VisitObjectState(Node* node) {
if (propagate<T>()) { if (propagate<T>()) {
for (int i = 0; i < node->InputCount(); i++) { for (int i = 0; i < node->InputCount(); i++) {
// TODO(nicohartmann): Remove, once the deoptimizer can rematerialize if (IsLargeBigInt(TypeOf(node->InputAt(i)))) {
// truncated BigInts.
if (TypeOf(node->InputAt(i)).Is(Type::BigInt())) {
EnqueueInput<T>(node, i, UseInfo::AnyTagged()); EnqueueInput<T>(node, i, UseInfo::AnyTagged());
} else { } else {
EnqueueInput<T>(node, i, UseInfo::Any()); EnqueueInput<T>(node, i, UseInfo::Any());
...@@ -1440,9 +1443,7 @@ class RepresentationSelector { ...@@ -1440,9 +1443,7 @@ class RepresentationSelector {
Node* input = node->InputAt(i); Node* input = node->InputAt(i);
(*types)[i] = (*types)[i] =
DeoptMachineTypeOf(GetInfo(input)->representation(), TypeOf(input)); DeoptMachineTypeOf(GetInfo(input)->representation(), TypeOf(input));
// TODO(nicohartmann): Remove, once the deoptimizer can rematerialize if (IsLargeBigInt(TypeOf(input))) {
// truncated BigInts.
if (TypeOf(node->InputAt(i)).Is(Type::BigInt())) {
ConvertInput(node, i, UseInfo::AnyTagged()); ConvertInput(node, i, UseInfo::AnyTagged());
} }
} }
...@@ -1981,7 +1982,7 @@ class RepresentationSelector { ...@@ -1981,7 +1982,7 @@ class RepresentationSelector {
case wasm::kI32: case wasm::kI32:
return MachineType::Int32(); return MachineType::Int32();
case wasm::kI64: case wasm::kI64:
return MachineType::Int64(); return MachineType::SignedBigInt64();
case wasm::kF32: case wasm::kF32:
return MachineType::Float32(); return MachineType::Float32();
case wasm::kF64: case wasm::kF64:
...@@ -2983,7 +2984,10 @@ class RepresentationSelector { ...@@ -2983,7 +2984,10 @@ class RepresentationSelector {
node, InsertTypeOverrideForVerifier(Type::UnsignedBigInt63(), node, InsertTypeOverrideForVerifier(Type::UnsignedBigInt63(),
jsgraph_->ZeroConstant())); jsgraph_->ZeroConstant()));
} else if (p.bits() == 64) { } else if (p.bits() == 64) {
DeferReplacement(node, node->InputAt(0)); DeferReplacement(node, InsertTypeOverrideForVerifier(
is_asuintn ? Type::UnsignedBigInt64()
: Type::SignedBigInt64(),
node->InputAt(0)));
} else { } else {
if (is_asuintn) { if (is_asuintn) {
const uint64_t mask = (1ULL << p.bits()) - 1ULL; const uint64_t mask = (1ULL << p.bits()) - 1ULL;
......
...@@ -145,6 +145,22 @@ void TranslationArrayPrintSingleFrame( ...@@ -145,6 +145,22 @@ void TranslationArrayPrintSingleFrame(
break; break;
} }
case TranslationOpcode::SIGNED_BIGINT64_REGISTER: {
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
int reg_code = iterator.NextUnsigned();
os << "{input=" << converter.NameOfCPURegister(reg_code)
<< " (signed bigint64)}";
break;
}
case TranslationOpcode::UNSIGNED_BIGINT64_REGISTER: {
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
int reg_code = iterator.NextUnsigned();
os << "{input=" << converter.NameOfCPURegister(reg_code)
<< " (unsigned bigint64)}";
break;
}
case TranslationOpcode::UINT32_REGISTER: { case TranslationOpcode::UINT32_REGISTER: {
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1); DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
int reg_code = iterator.NextUnsigned(); int reg_code = iterator.NextUnsigned();
...@@ -195,6 +211,20 @@ void TranslationArrayPrintSingleFrame( ...@@ -195,6 +211,20 @@ void TranslationArrayPrintSingleFrame(
break; break;
} }
case TranslationOpcode::SIGNED_BIGINT64_STACK_SLOT: {
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
int input_slot_index = iterator.Next();
os << "{input=" << input_slot_index << " (signed bigint64)}";
break;
}
case TranslationOpcode::UNSIGNED_BIGINT64_STACK_SLOT: {
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
int input_slot_index = iterator.Next();
os << "{input=" << input_slot_index << " (unsigned bigint64)}";
break;
}
case TranslationOpcode::UINT32_STACK_SLOT: { case TranslationOpcode::UINT32_STACK_SLOT: {
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1); DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
int input_slot_index = iterator.Next(); int input_slot_index = iterator.Next();
...@@ -329,6 +359,14 @@ TranslatedValue TranslatedValue::NewInt64ToBigInt(TranslatedState* container, ...@@ -329,6 +359,14 @@ TranslatedValue TranslatedValue::NewInt64ToBigInt(TranslatedState* container,
return slot; return slot;
} }
// static
TranslatedValue TranslatedValue::NewUint64ToBigInt(TranslatedState* container,
uint64_t value) {
TranslatedValue slot(container, kUint64ToBigInt);
slot.uint64_value_ = value;
return slot;
}
// static // static
TranslatedValue TranslatedValue::NewUInt32(TranslatedState* container, TranslatedValue TranslatedValue::NewUInt32(TranslatedState* container,
uint32_t value) { uint32_t value) {
...@@ -375,6 +413,11 @@ int64_t TranslatedValue::int64_value() const { ...@@ -375,6 +413,11 @@ int64_t TranslatedValue::int64_value() const {
return int64_value_; return int64_value_;
} }
uint64_t TranslatedValue::uint64_value() const {
DCHECK(kUint64ToBigInt == kind());
return uint64_value_;
}
uint32_t TranslatedValue::uint32_value() const { uint32_t TranslatedValue::uint32_value() const {
DCHECK(kind() == kUInt32 || kind() == kBoolBit); DCHECK(kind() == kUInt32 || kind() == kBoolBit);
return uint32_value_; return uint32_value_;
...@@ -547,6 +590,9 @@ Handle<Object> TranslatedValue::GetValue() { ...@@ -547,6 +590,9 @@ Handle<Object> TranslatedValue::GetValue() {
case TranslatedValue::kInt64ToBigInt: case TranslatedValue::kInt64ToBigInt:
heap_object = BigInt::FromInt64(isolate(), int64_value()); heap_object = BigInt::FromInt64(isolate(), int64_value());
break; break;
case TranslatedValue::kUint64ToBigInt:
heap_object = BigInt::FromUint64(isolate(), uint64_value());
break;
case TranslatedValue::kUInt32: case TranslatedValue::kUInt32:
number = uint32_value(); number = uint32_value();
heap_object = isolate()->factory()->NewHeapNumber(number); heap_object = isolate()->factory()->NewHeapNumber(number);
...@@ -562,7 +608,8 @@ Handle<Object> TranslatedValue::GetValue() { ...@@ -562,7 +608,8 @@ Handle<Object> TranslatedValue::GetValue() {
default: default:
UNREACHABLE(); UNREACHABLE();
} }
DCHECK(!IsSmiDouble(number) || kind() == TranslatedValue::kInt64ToBigInt); DCHECK(!IsSmiDouble(number) || kind() == TranslatedValue::kInt64ToBigInt ||
kind() == TranslatedValue::kUint64ToBigInt);
set_initialized_storage(heap_object); set_initialized_storage(heap_object);
return storage_; return storage_;
} }
...@@ -868,6 +915,8 @@ TranslatedFrame TranslatedState::CreateNextTranslatedFrame( ...@@ -868,6 +915,8 @@ TranslatedFrame TranslatedState::CreateNextTranslatedFrame(
case TranslationOpcode::REGISTER: case TranslationOpcode::REGISTER:
case TranslationOpcode::INT32_REGISTER: case TranslationOpcode::INT32_REGISTER:
case TranslationOpcode::INT64_REGISTER: case TranslationOpcode::INT64_REGISTER:
case TranslationOpcode::SIGNED_BIGINT64_REGISTER:
case TranslationOpcode::UNSIGNED_BIGINT64_REGISTER:
case TranslationOpcode::UINT32_REGISTER: case TranslationOpcode::UINT32_REGISTER:
case TranslationOpcode::BOOL_REGISTER: case TranslationOpcode::BOOL_REGISTER:
case TranslationOpcode::FLOAT_REGISTER: case TranslationOpcode::FLOAT_REGISTER:
...@@ -875,6 +924,8 @@ TranslatedFrame TranslatedState::CreateNextTranslatedFrame( ...@@ -875,6 +924,8 @@ TranslatedFrame TranslatedState::CreateNextTranslatedFrame(
case TranslationOpcode::STACK_SLOT: case TranslationOpcode::STACK_SLOT:
case TranslationOpcode::INT32_STACK_SLOT: case TranslationOpcode::INT32_STACK_SLOT:
case TranslationOpcode::INT64_STACK_SLOT: case TranslationOpcode::INT64_STACK_SLOT:
case TranslationOpcode::SIGNED_BIGINT64_STACK_SLOT:
case TranslationOpcode::UNSIGNED_BIGINT64_STACK_SLOT:
case TranslationOpcode::UINT32_STACK_SLOT: case TranslationOpcode::UINT32_STACK_SLOT:
case TranslationOpcode::BOOL_STACK_SLOT: case TranslationOpcode::BOOL_STACK_SLOT:
case TranslationOpcode::FLOAT_STACK_SLOT: case TranslationOpcode::FLOAT_STACK_SLOT:
...@@ -1089,6 +1140,42 @@ int TranslatedState::CreateNextTranslatedValue( ...@@ -1089,6 +1140,42 @@ int TranslatedState::CreateNextTranslatedValue(
return translated_value.GetChildrenCount(); return translated_value.GetChildrenCount();
} }
case TranslationOpcode::SIGNED_BIGINT64_REGISTER: {
int input_reg = iterator->NextUnsigned();
if (registers == nullptr) {
TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
frame.Add(translated_value);
return translated_value.GetChildrenCount();
}
intptr_t value = registers->GetRegister(input_reg);
if (trace_file != nullptr) {
PrintF(trace_file, "%" V8PRIdPTR " ; %s (signed bigint64)", value,
converter.NameOfCPURegister(input_reg));
}
TranslatedValue translated_value =
TranslatedValue::NewInt64ToBigInt(this, value);
frame.Add(translated_value);
return translated_value.GetChildrenCount();
}
case TranslationOpcode::UNSIGNED_BIGINT64_REGISTER: {
int input_reg = iterator->NextUnsigned();
if (registers == nullptr) {
TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
frame.Add(translated_value);
return translated_value.GetChildrenCount();
}
intptr_t value = registers->GetRegister(input_reg);
if (trace_file != nullptr) {
PrintF(trace_file, "%" V8PRIdPTR " ; %s (unsigned bigint64)", value,
converter.NameOfCPURegister(input_reg));
}
TranslatedValue translated_value =
TranslatedValue::NewUint64ToBigInt(this, value);
frame.Add(translated_value);
return translated_value.GetChildrenCount();
}
case TranslationOpcode::UINT32_REGISTER: { case TranslationOpcode::UINT32_REGISTER: {
int input_reg = iterator->NextUnsigned(); int input_reg = iterator->NextUnsigned();
if (registers == nullptr) { if (registers == nullptr) {
...@@ -1205,6 +1292,36 @@ int TranslatedState::CreateNextTranslatedValue( ...@@ -1205,6 +1292,36 @@ int TranslatedState::CreateNextTranslatedValue(
return translated_value.GetChildrenCount(); return translated_value.GetChildrenCount();
} }
case TranslationOpcode::SIGNED_BIGINT64_STACK_SLOT: {
int slot_offset =
OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
uint64_t value = GetUInt64Slot(fp, slot_offset);
if (trace_file != nullptr) {
PrintF(trace_file, "%" V8PRIdPTR " ; (signed bigint64) [fp %c %3d] ",
static_cast<intptr_t>(value), slot_offset < 0 ? '-' : '+',
std::abs(slot_offset));
}
TranslatedValue translated_value =
TranslatedValue::NewInt64ToBigInt(this, value);
frame.Add(translated_value);
return translated_value.GetChildrenCount();
}
case TranslationOpcode::UNSIGNED_BIGINT64_STACK_SLOT: {
int slot_offset =
OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
uint64_t value = GetUInt64Slot(fp, slot_offset);
if (trace_file != nullptr) {
PrintF(trace_file, "%" V8PRIdPTR " ; (unsigned bigint64) [fp %c %3d] ",
static_cast<intptr_t>(value), slot_offset < 0 ? '-' : '+',
std::abs(slot_offset));
}
TranslatedValue translated_value =
TranslatedValue::NewUint64ToBigInt(this, value);
frame.Add(translated_value);
return translated_value.GetChildrenCount();
}
case TranslationOpcode::UINT32_STACK_SLOT: { case TranslationOpcode::UINT32_STACK_SLOT: {
int slot_offset = int slot_offset =
OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next()); OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
......
...@@ -73,6 +73,7 @@ class TranslatedValue { ...@@ -73,6 +73,7 @@ class TranslatedValue {
kInt32, kInt32,
kInt64, kInt64,
kInt64ToBigInt, kInt64ToBigInt,
kUint64ToBigInt,
kUInt32, kUInt32,
kBoolBit, kBoolBit,
kFloat, kFloat,
...@@ -111,6 +112,8 @@ class TranslatedValue { ...@@ -111,6 +112,8 @@ class TranslatedValue {
static TranslatedValue NewInt64(TranslatedState* container, int64_t value); static TranslatedValue NewInt64(TranslatedState* container, int64_t value);
static TranslatedValue NewInt64ToBigInt(TranslatedState* container, static TranslatedValue NewInt64ToBigInt(TranslatedState* container,
int64_t value); int64_t value);
static TranslatedValue NewUint64ToBigInt(TranslatedState* container,
uint64_t value);
static TranslatedValue NewUInt32(TranslatedState* container, uint32_t value); static TranslatedValue NewUInt32(TranslatedState* container, uint32_t value);
static TranslatedValue NewBool(TranslatedState* container, uint32_t value); static TranslatedValue NewBool(TranslatedState* container, uint32_t value);
static TranslatedValue NewTagged(TranslatedState* container, Object literal); static TranslatedValue NewTagged(TranslatedState* container, Object literal);
...@@ -152,7 +155,9 @@ class TranslatedValue { ...@@ -152,7 +155,9 @@ class TranslatedValue {
uint32_t uint32_value_; uint32_t uint32_value_;
// kind is kInt32. // kind is kInt32.
int32_t int32_value_; int32_t int32_value_;
// kind is kInt64. // kind is kUint64ToBigInt.
uint64_t uint64_value_;
// kind is kInt64 or kInt64ToBigInt.
int64_t int64_value_; int64_t int64_value_;
// kind is kFloat // kind is kFloat
Float32 float_value_; Float32 float_value_;
...@@ -167,6 +172,7 @@ class TranslatedValue { ...@@ -167,6 +172,7 @@ class TranslatedValue {
int32_t int32_value() const; int32_t int32_value() const;
int64_t int64_value() const; int64_t int64_value() const;
uint32_t uint32_value() const; uint32_t uint32_value() const;
uint64_t uint64_value() const;
Float32 float_value() const; Float32 float_value() const;
Float64 double_value() const; Float64 double_value() const;
int object_length() const; int object_length() const;
......
...@@ -287,6 +287,20 @@ void TranslationArrayBuilder::StoreInt64Register(Register reg) { ...@@ -287,6 +287,20 @@ void TranslationArrayBuilder::StoreInt64Register(Register reg) {
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1); DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
} }
void TranslationArrayBuilder::StoreSignedBigInt64Register(Register reg) {
auto opcode = TranslationOpcode::SIGNED_BIGINT64_REGISTER;
AddOpcode(opcode);
AddRegister(reg);
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
}
void TranslationArrayBuilder::StoreUnsignedBigInt64Register(Register reg) {
auto opcode = TranslationOpcode::UNSIGNED_BIGINT64_REGISTER;
AddOpcode(opcode);
AddRegister(reg);
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
}
void TranslationArrayBuilder::StoreUint32Register(Register reg) { void TranslationArrayBuilder::StoreUint32Register(Register reg) {
auto opcode = TranslationOpcode::UINT32_REGISTER; auto opcode = TranslationOpcode::UINT32_REGISTER;
AddOpcode(opcode); AddOpcode(opcode);
...@@ -334,6 +348,20 @@ void TranslationArrayBuilder::StoreInt64StackSlot(int index) { ...@@ -334,6 +348,20 @@ void TranslationArrayBuilder::StoreInt64StackSlot(int index) {
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1); DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
} }
void TranslationArrayBuilder::StoreSignedBigInt64StackSlot(int index) {
auto opcode = TranslationOpcode::SIGNED_BIGINT64_STACK_SLOT;
AddOpcode(opcode);
Add(index);
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
}
void TranslationArrayBuilder::StoreUnsignedBigInt64StackSlot(int index) {
auto opcode = TranslationOpcode::UNSIGNED_BIGINT64_STACK_SLOT;
AddOpcode(opcode);
Add(index);
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
}
void TranslationArrayBuilder::StoreUint32StackSlot(int index) { void TranslationArrayBuilder::StoreUint32StackSlot(int index) {
auto opcode = TranslationOpcode::UINT32_STACK_SLOT; auto opcode = TranslationOpcode::UINT32_STACK_SLOT;
AddOpcode(opcode); AddOpcode(opcode);
......
...@@ -90,6 +90,8 @@ class TranslationArrayBuilder { ...@@ -90,6 +90,8 @@ class TranslationArrayBuilder {
void StoreRegister(Register reg); void StoreRegister(Register reg);
void StoreInt32Register(Register reg); void StoreInt32Register(Register reg);
void StoreInt64Register(Register reg); void StoreInt64Register(Register reg);
void StoreSignedBigInt64Register(Register reg);
void StoreUnsignedBigInt64Register(Register reg);
void StoreUint32Register(Register reg); void StoreUint32Register(Register reg);
void StoreBoolRegister(Register reg); void StoreBoolRegister(Register reg);
void StoreFloatRegister(FloatRegister reg); void StoreFloatRegister(FloatRegister reg);
...@@ -97,6 +99,8 @@ class TranslationArrayBuilder { ...@@ -97,6 +99,8 @@ class TranslationArrayBuilder {
void StoreStackSlot(int index); void StoreStackSlot(int index);
void StoreInt32StackSlot(int index); void StoreInt32StackSlot(int index);
void StoreInt64StackSlot(int index); void StoreInt64StackSlot(int index);
void StoreSignedBigInt64StackSlot(int index);
void StoreUnsignedBigInt64StackSlot(int index);
void StoreUint32StackSlot(int index); void StoreUint32StackSlot(int index);
void StoreBoolStackSlot(int index); void StoreBoolStackSlot(int index);
void StoreFloatStackSlot(int index); void StoreFloatStackSlot(int index);
......
...@@ -30,6 +30,10 @@ namespace internal { ...@@ -30,6 +30,10 @@ namespace internal {
V(INT32_STACK_SLOT, 1) \ V(INT32_STACK_SLOT, 1) \
V(INT64_REGISTER, 1) \ V(INT64_REGISTER, 1) \
V(INT64_STACK_SLOT, 1) \ V(INT64_STACK_SLOT, 1) \
V(SIGNED_BIGINT64_REGISTER, 1) \
V(SIGNED_BIGINT64_STACK_SLOT, 1) \
V(UNSIGNED_BIGINT64_REGISTER, 1) \
V(UNSIGNED_BIGINT64_STACK_SLOT, 1) \
V(INTERPRETED_FRAME, 5) \ V(INTERPRETED_FRAME, 5) \
V(JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME, 3) \ V(JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME, 3) \
V(JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME, 3) \ V(JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME, 3) \
......
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --turbofan --no-always-turbofan
(function OptimizeAndTestAsUintN() {
function f(x) {
// Will be lowered to Int64Constant(-1) and stored as an immediate.
let y = BigInt.asUintN(64, -1n);
try {
return x + y;
} catch(_) {
return y;
}
}
%PrepareFunctionForOptimization(f);
assertEquals(2n ** 64n, f(1n));
assertEquals(2n ** 64n + 1n, f(2n));
%OptimizeFunctionOnNextCall(f);
assertEquals(2n ** 64n, f(1n));
assertOptimized(f);
// Should be rematerialized to 2n ** 64n - 1n in code generation.
assertEquals(2n ** 64n - 1n, f(0));
if (%Is64Bit()) {
assertUnoptimized(f);
}
})();
(function OptimizeAndTestAsUintN() {
function f(x) {
// Will be lowered to Int64Sub because exponentiation is not truncated and
// stored in a register.
let y = BigInt.asUintN(64, -(2n ** 0n));
try {
return x + y;
} catch(_) {
return y;
}
}
%PrepareFunctionForOptimization(f);
assertEquals(2n ** 64n, f(1n));
assertEquals(2n ** 64n + 1n, f(2n));
%OptimizeFunctionOnNextCall(f);
assertEquals(2n ** 64n, f(1n));
assertOptimized(f);
// Should be rematerialized to 2n ** 64n - 1n in deoptimization.
assertEquals(2n ** 64n - 1n, f(0));
if (%Is64Bit()) {
assertUnoptimized(f);
}
})();
(function OptimizeAndTestAsUintN() {
function f(x) {
// Will be lowered to Int64Sub because exponentiation is not truncated and
// stored in a stack slot.
let y = BigInt.asUintN(64, -(2n ** 0n));
try {
// The recursion is used to make sure `y` is stored on the stack.
return (x < 3n) ? (x + y) : f(x - 1n);
} catch(_) {
return y;
}
}
%PrepareFunctionForOptimization(f);
assertEquals(2n ** 64n, f(1n));
assertEquals(2n ** 64n + 1n, f(2n));
%OptimizeFunctionOnNextCall(f);
assertEquals(2n ** 64n, f(1n));
assertOptimized(f);
// Should be rematerialized to 2n ** 64n - 1n in deoptimization.
assertEquals(2n ** 64n - 1n, f(0));
if (%Is64Bit()) {
assertUnoptimized(f);
}
})();
(function OptimizeAndTestAsIntN() {
function f(x) {
// Will be lowered to Int64Constant(-1) and stored as an immediate.
let y = BigInt.asIntN(64, -1n);
try {
return x + y;
} catch (_) {
return y;
}
}
%PrepareFunctionForOptimization(f);
assertEquals(0n, f(1n));
assertEquals(1n, f(2n));
%OptimizeFunctionOnNextCall(f);
assertEquals(0n, f(1n));
assertOptimized(f);
// Should be rematerialized to -1n in code generation.
assertEquals(-1n, f(0));
if (%Is64Bit()) {
assertUnoptimized(f);
}
})();
(function OptimizeAndTestAsIntN() {
function f(x) {
// Will be lowered to Int64Sub because exponentiation is not truncated and
// stored in a register.
let y = BigInt.asIntN(64, -(2n ** 0n));
try {
return x + y;
} catch(_) {
return y;
}
}
%PrepareFunctionForOptimization(f);
assertEquals(0n, f(1n));
assertEquals(1n, f(2n));
%OptimizeFunctionOnNextCall(f);
assertEquals(0n, f(1n));
assertOptimized(f);
// Should be rematerialized to -1n in deoptimization.
assertEquals(-1n, f(0));
if (%Is64Bit()) {
assertUnoptimized(f);
}
})();
(function OptimizeAndTestAsIntN() {
function f(x) {
// Will be lowered to Int64Sub because exponentiation is not truncated and
// stored in a stack slot.
let y = BigInt.asIntN(64, -(2n ** 0n));
try {
// The recursion is used to make sure `y` is stored on the stack.
return (x < 3n) ? (x + y) : f(x - 1n);
} catch(_) {
return y;
}
}
%PrepareFunctionForOptimization(f);
assertEquals(0n, f(1n));
assertEquals(1n, f(2n));
%OptimizeFunctionOnNextCall(f);
assertEquals(0n, f(1n));
assertOptimized(f);
// Should be rematerialized to -1n in deoptimization.
assertEquals(-1n, f(0));
if (%Is64Bit()) {
assertUnoptimized(f);
}
})();
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --turbofan --no-always-turbofan --turbo-inline-js-wasm-calls
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
let builder = new WasmModuleBuilder();
builder
.addFunction("f", kSig_l_v) // () -> i64
.addBody([
kExprI64Const, 0,
kExprI64Const, 1,
kExprI64Sub, // -1
])
.exportFunc();
let module = builder.instantiate();
function f(x) {
let y = module.exports.f();
try {
return x + y;
} catch(_) {
return y;
}
}
%PrepareFunctionForOptimization(f);
assertEquals(0n, f(1n));
assertEquals(1n, f(2n));
%OptimizeFunctionOnNextCall(f);
assertEquals(0n, f(1n));
assertOptimized(f);
// After optimization, the result of the js wasm call is stored in word64 and
// passed to StateValues without conversion. Rematerialization will happen
// in deoptimizer.
assertEquals(-1n, f(0));
if (%Is64Bit()) {
assertUnoptimized(f);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment