Commit 98c6c367 authored by Qifan Pan's avatar Qifan Pan Committed by V8 LUCI CQ

Reland "[turbofan] Rematerialize BigInt64 in deopt"

This is a reland of commit 80fb2815

This CL fixes the signedness of rematerialized Numbers from immediates, which was introduced by the original change. Besides, BigInt truncation to zero bits is lowered to Int64Constant instead of NumberConstant of zero, which will flow into the state values directly.

Original change's description:
> [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/+/3858238
> Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
> Reviewed-by: Nico Hartmann <nicohartmann@chromium.org>
> Commit-Queue: Qifan Pan <panq@google.com>
> Cr-Commit-Position: refs/heads/main@{#83230}

Bug: v8:9407, chromium:1364319, chromium:1364400
Change-Id: I0b4e077b52f64af46018b6c045893bbd56153f32
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3899258
Commit-Queue: Qifan Pan <panq@google.com>
Reviewed-by: 's avatarNico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/main@{#83384}
parent 4e23f53c
...@@ -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
}; };
...@@ -189,6 +191,14 @@ class MachineType { ...@@ -189,6 +191,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 =
...@@ -1247,15 +1257,24 @@ void CodeGenerator::AddTranslationForOperand(Instruction* instr, ...@@ -1247,15 +1257,24 @@ void CodeGenerator::AddTranslationForOperand(Instruction* instr,
constant.ToInt32() == FrameStateDescriptor::kImpossibleValue); constant.ToInt32() == FrameStateDescriptor::kImpossibleValue);
if (type == MachineType::Uint32()) { if (type == MachineType::Uint32()) {
literal = DeoptimizationLiteral( literal = DeoptimizationLiteral(
static_cast<uint32_t>(constant.ToInt32())); static_cast<double>(static_cast<uint32_t>(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_;
Handle<Object> object_; union {
double number_ = 0; Handle<Object> object_;
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:
...@@ -2979,11 +2980,14 @@ class RepresentationSelector { ...@@ -2979,11 +2980,14 @@ class RepresentationSelector {
is_asuintn ? Type::UnsignedBigInt64() : Type::SignedBigInt64()); is_asuintn ? Type::UnsignedBigInt64() : Type::SignedBigInt64());
if (lower<T>()) { if (lower<T>()) {
if (p.bits() == 0) { if (p.bits() == 0) {
DeferReplacement( DeferReplacement(node, InsertTypeOverrideForVerifier(
node, InsertTypeOverrideForVerifier(Type::UnsignedBigInt63(), Type::UnsignedBigInt63(),
jsgraph_->ZeroConstant())); jsgraph_->Int64Constant(0)));
} 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
function f() {
return "abcd".charCodeAt(BigInt.asUintN(0, -1307n));
}
%PrepareFunctionForOptimization(f);
try { f(); } catch(e) {}
try { f(); } catch(e) {}
%OptimizeFunctionOnNextCall(f);
assertThrows(f, TypeError);
// 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
function foo(deopt, x) {
x = x >>> 0;
return deopt ? Math.max(x) : x;
}
function bar(deopt) {
return foo(deopt, 4294967295);
};
%PrepareFunctionForOptimization(bar);
%PrepareFunctionForOptimization(foo);
bar(false);
%OptimizeFunctionOnNextCall(bar);
// bar will bailout because of insufficient type feedback for generic named
// access. The HeapNumber should be correctly rematerialized in deoptimzer.
assertEquals(4294967295, bar(true));
// 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