Commit 99df710d authored by Nico Hartmann's avatar Nico Hartmann Committed by Commit Bot

[turbofan] Push BigInt truncation over addition and heap constants

This change implements lowering of speculative BigInt addition as well as
BigInt heap constants to corresponding int64 versions, if they are used in
a context where the result is truncated to the least significant 64 bits
(e.g. using asUintN). The JSHeapBroker is extended to provide access to the
BigInt's least significant digit during concurrent compilation. The BigInt
context (required to introduce correct conversions) is recognized in the
RepresentationChanger by either the output type propagated downward or the
TypeCheckKind propagated upward. This is necessary, because the TypeCheckKind
may only be set by nodes that may potentially deopt (and sit in the effect
chain). This is the case for SpeculativeBigIntAdd, but not for BigIntAsUintN.

This CL contains a simple fix to prevent int64-lowered BigInts to flow into
state values as the deoptimizer cannot handle them yet. A more sophisticated
solution to allow the deoptimizer to materialize truncated BigInts will be
added in a following CL.

Bug: v8:9407
Change-Id: I96a293e9077962f53e5f199857644f004e3ae56e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1684183
Commit-Queue: Nico Hartmann <nicohartmann@google.com>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarSigurd Schneider <sigurds@chromium.org>
Reviewed-by: 's avatarMaya Lekova <mslekova@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62665}
parent 2e82ead8
...@@ -72,6 +72,7 @@ enum class OddballType : uint8_t { ...@@ -72,6 +72,7 @@ enum class OddballType : uint8_t {
V(Symbol) \ V(Symbol) \
/* Subtypes of HeapObject */ \ /* Subtypes of HeapObject */ \
V(AllocationSite) \ V(AllocationSite) \
V(BigInt) \
V(CallHandlerInfo) \ V(CallHandlerInfo) \
V(Cell) \ V(Cell) \
V(Code) \ V(Code) \
...@@ -478,6 +479,14 @@ class AllocationSiteRef : public HeapObjectRef { ...@@ -478,6 +479,14 @@ class AllocationSiteRef : public HeapObjectRef {
bool CanInlineCall() const; bool CanInlineCall() const;
}; };
class BigIntRef : public HeapObjectRef {
public:
using HeapObjectRef::HeapObjectRef;
Handle<BigInt> object() const;
uint64_t AsUint64() const;
};
class V8_EXPORT_PRIVATE MapRef : public HeapObjectRef { class V8_EXPORT_PRIVATE MapRef : public HeapObjectRef {
public: public:
using HeapObjectRef::HeapObjectRef; using HeapObjectRef::HeapObjectRef;
......
...@@ -810,6 +810,18 @@ class AllocationSiteData : public HeapObjectData { ...@@ -810,6 +810,18 @@ class AllocationSiteData : public HeapObjectData {
bool serialized_boilerplate_ = false; bool serialized_boilerplate_ = false;
}; };
class BigIntData : public HeapObjectData {
public:
BigIntData(JSHeapBroker* broker, ObjectData** storage, Handle<BigInt> object)
: HeapObjectData(broker, storage, object),
as_uint64_(object->AsUint64(nullptr)) {}
uint64_t AsUint64() const { return as_uint64_; }
private:
const uint64_t as_uint64_;
};
// Only used in JSNativeContextSpecialization. // Only used in JSNativeContextSpecialization.
class ScriptContextTableData : public HeapObjectData { class ScriptContextTableData : public HeapObjectData {
public: public:
...@@ -3263,6 +3275,11 @@ double MutableHeapNumberRef::value() const { ...@@ -3263,6 +3275,11 @@ double MutableHeapNumberRef::value() const {
return data()->AsMutableHeapNumber()->value(); return data()->AsMutableHeapNumber()->value();
} }
uint64_t BigIntRef::AsUint64() const {
IF_BROKER_DISABLED_ACCESS_HANDLE_C(BigInt, AsUint64);
return data()->AsBigInt()->AsUint64();
}
CellRef SourceTextModuleRef::GetCell(int cell_index) const { CellRef SourceTextModuleRef::GetCell(int cell_index) const {
if (broker()->mode() == JSHeapBroker::kDisabled) { if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleAllocation handle_allocation; AllowHandleAllocation handle_allocation;
......
...@@ -19,6 +19,7 @@ RedundancyElimination::~RedundancyElimination() = default; ...@@ -19,6 +19,7 @@ RedundancyElimination::~RedundancyElimination() = default;
Reduction RedundancyElimination::Reduce(Node* node) { Reduction RedundancyElimination::Reduce(Node* node) {
if (node_checks_.Get(node)) return NoChange(); if (node_checks_.Get(node)) return NoChange();
switch (node->opcode()) { switch (node->opcode()) {
case IrOpcode::kCheckBigInt:
case IrOpcode::kCheckBounds: case IrOpcode::kCheckBounds:
case IrOpcode::kCheckEqualsInternalizedString: case IrOpcode::kCheckEqualsInternalizedString:
case IrOpcode::kCheckEqualsSymbol: case IrOpcode::kCheckEqualsSymbol:
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "src/base/bits.h" #include "src/base/bits.h"
#include "src/codegen/code-factory.h" #include "src/codegen/code-factory.h"
#include "src/compiler/js-heap-broker.h"
#include "src/compiler/machine-operator.h" #include "src/compiler/machine-operator.h"
#include "src/compiler/node-matchers.h" #include "src/compiler/node-matchers.h"
#include "src/compiler/type-cache.h" #include "src/compiler/type-cache.h"
...@@ -137,10 +138,11 @@ bool IsWord(MachineRepresentation rep) { ...@@ -137,10 +138,11 @@ bool IsWord(MachineRepresentation rep) {
} // namespace } // namespace
RepresentationChanger::RepresentationChanger(JSGraph* jsgraph, Isolate* isolate) RepresentationChanger::RepresentationChanger(JSGraph* jsgraph,
JSHeapBroker* broker)
: cache_(TypeCache::Get()), : cache_(TypeCache::Get()),
jsgraph_(jsgraph), jsgraph_(jsgraph),
isolate_(isolate), broker_(broker),
testing_type_errors_(false), testing_type_errors_(false),
type_error_(false) {} type_error_(false) {}
...@@ -432,6 +434,8 @@ Node* RepresentationChanger::GetTaggedPointerRepresentationFor( ...@@ -432,6 +434,8 @@ Node* RepresentationChanger::GetTaggedPointerRepresentationFor(
op = machine()->ChangeInt64ToFloat64(); op = machine()->ChangeInt64ToFloat64();
node = jsgraph()->graph()->NewNode(op, node); node = jsgraph()->graph()->NewNode(op, node);
op = simplified()->ChangeFloat64ToTaggedPointer(); op = simplified()->ChangeFloat64ToTaggedPointer();
} else if (output_type.Is(Type::BigInt())) {
op = simplified()->ChangeUint64ToBigInt();
} else { } else {
return TypeError(node, output_rep, output_type, return TypeError(node, output_rep, output_type,
MachineRepresentation::kTaggedPointer); MachineRepresentation::kTaggedPointer);
...@@ -461,10 +465,11 @@ Node* RepresentationChanger::GetTaggedPointerRepresentationFor( ...@@ -461,10 +465,11 @@ Node* RepresentationChanger::GetTaggedPointerRepresentationFor(
// TODO(turbofan): Consider adding a Bailout operator that just deopts // TODO(turbofan): Consider adding a Bailout operator that just deopts
// for TaggedSigned output representation. // for TaggedSigned output representation.
op = simplified()->CheckedTaggedToTaggedPointer(use_info.feedback()); op = simplified()->CheckedTaggedToTaggedPointer(use_info.feedback());
} else if ((IsAnyTagged(output_rep) || IsAnyCompressed(output_rep)) && } else if (IsAnyTagged(output_rep) &&
use_info.type_check() == TypeCheckKind::kBigInt) { (use_info.type_check() == TypeCheckKind::kBigInt ||
if (IsAnyCompressed(output_rep)) { output_type.Is(Type::BigInt()))) {
node = InsertChangeCompressedToTagged(node); if (output_type.Is(Type::BigInt())) {
return node;
} }
op = simplified()->CheckBigInt(use_info.feedback()); op = simplified()->CheckBigInt(use_info.feedback());
} else if (output_rep == MachineRepresentation::kCompressedPointer) { } else if (output_rep == MachineRepresentation::kCompressedPointer) {
...@@ -1290,6 +1295,15 @@ Node* RepresentationChanger::GetWord64RepresentationFor( ...@@ -1290,6 +1295,15 @@ Node* RepresentationChanger::GetWord64RepresentationFor(
} }
break; break;
} }
case IrOpcode::kHeapConstant: {
HeapObjectMatcher m(node);
if (m.HasValue() && m.Ref(broker_).IsBigInt()) {
auto bigint = m.Ref(broker_).AsBigInt();
return jsgraph()->Int64Constant(
static_cast<int64_t>(bigint.AsUint64()));
}
break;
}
default: default:
break; break;
} }
...@@ -1367,11 +1381,12 @@ Node* RepresentationChanger::GetWord64RepresentationFor( ...@@ -1367,11 +1381,12 @@ Node* RepresentationChanger::GetWord64RepresentationFor(
return TypeError(node, output_rep, output_type, return TypeError(node, output_rep, output_type,
MachineRepresentation::kWord64); MachineRepresentation::kWord64);
} }
} else if ((IsAnyTagged(output_rep) || IsAnyCompressed(output_rep)) && } else if (IsAnyTagged(output_rep) &&
output_type.Is(Type::BigInt())) { use_info.truncation().IsUsedAsWord64() &&
if (IsAnyCompressed(output_rep)) { (use_info.type_check() == TypeCheckKind::kBigInt ||
node = InsertChangeCompressedToTagged(node); output_type.Is(Type::BigInt()))) {
} node = GetTaggedPointerRepresentationFor(node, output_rep, output_type,
use_node, use_info);
op = simplified()->TruncateBigIntToUint64(); op = simplified()->TruncateBigIntToUint64();
} else if (CanBeTaggedPointer(output_rep)) { } else if (CanBeTaggedPointer(output_rep)) {
if (output_type.Is(cache_->kInt64)) { if (output_type.Is(cache_->kInt64)) {
...@@ -1711,6 +1726,8 @@ Node* RepresentationChanger::InsertChangeCompressedToTagged(Node* node) { ...@@ -1711,6 +1726,8 @@ Node* RepresentationChanger::InsertChangeCompressedToTagged(Node* node) {
node); node);
} }
Isolate* RepresentationChanger::isolate() const { return broker_->isolate(); }
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -173,9 +173,12 @@ class UseInfo { ...@@ -173,9 +173,12 @@ class UseInfo {
static UseInfo TruncatingWord32() { static UseInfo TruncatingWord32() {
return UseInfo(MachineRepresentation::kWord32, Truncation::Word32()); return UseInfo(MachineRepresentation::kWord32, Truncation::Word32());
} }
static UseInfo TruncatedBigIntAsWord64() { static UseInfo TruncatingWord64() {
return UseInfo(MachineRepresentation::kWord64, Truncation::Word64());
}
static UseInfo CheckedBigIntTruncatingWord64(const VectorSlotPair& feedback) {
return UseInfo(MachineRepresentation::kWord64, Truncation::Word64(), return UseInfo(MachineRepresentation::kWord64, Truncation::Word64(),
TypeCheckKind::kBigInt); TypeCheckKind::kBigInt, feedback);
} }
static UseInfo Word64() { static UseInfo Word64() {
return UseInfo(MachineRepresentation::kWord64, Truncation::Any()); return UseInfo(MachineRepresentation::kWord64, Truncation::Any());
...@@ -308,7 +311,7 @@ class UseInfo { ...@@ -308,7 +311,7 @@ class UseInfo {
// Eagerly folds any representation changes for constants. // Eagerly folds any representation changes for constants.
class V8_EXPORT_PRIVATE RepresentationChanger final { class V8_EXPORT_PRIVATE RepresentationChanger final {
public: public:
RepresentationChanger(JSGraph* jsgraph, Isolate* isolate); RepresentationChanger(JSGraph* jsgraph, JSHeapBroker* broker);
// Changes representation from {output_type} to {use_rep}. The {truncation} // Changes representation from {output_type} to {use_rep}. The {truncation}
// parameter is only used for sanity checking - if the changer cannot figure // parameter is only used for sanity checking - if the changer cannot figure
...@@ -338,7 +341,7 @@ class V8_EXPORT_PRIVATE RepresentationChanger final { ...@@ -338,7 +341,7 @@ class V8_EXPORT_PRIVATE RepresentationChanger final {
private: private:
TypeCache const* cache_; TypeCache const* cache_;
JSGraph* jsgraph_; JSGraph* jsgraph_;
Isolate* isolate_; JSHeapBroker* broker_;
friend class RepresentationChangerTester; // accesses the below fields. friend class RepresentationChangerTester; // accesses the below fields.
...@@ -398,7 +401,7 @@ class V8_EXPORT_PRIVATE RepresentationChanger final { ...@@ -398,7 +401,7 @@ class V8_EXPORT_PRIVATE RepresentationChanger final {
Node* InsertUnconditionalDeopt(Node* node, DeoptimizeReason reason); Node* InsertUnconditionalDeopt(Node* node, DeoptimizeReason reason);
JSGraph* jsgraph() const { return jsgraph_; } JSGraph* jsgraph() const { return jsgraph_; }
Isolate* isolate() const { return isolate_; } Isolate* isolate() const;
Factory* factory() const { return isolate()->factory(); } Factory* factory() const { return isolate()->factory(); }
SimplifiedOperatorBuilder* simplified() { return jsgraph()->simplified(); } SimplifiedOperatorBuilder* simplified() { return jsgraph()->simplified(); }
MachineOperatorBuilder* machine() { return jsgraph()->machine(); } MachineOperatorBuilder* machine() { return jsgraph()->machine(); }
......
...@@ -1117,8 +1117,11 @@ class RepresentationSelector { ...@@ -1117,8 +1117,11 @@ class RepresentationSelector {
if (IsAnyCompressed(rep)) { if (IsAnyCompressed(rep)) {
return MachineType::AnyCompressed(); return MachineType::AnyCompressed();
} }
// Word64 representation is only valid for safe integer values.
if (rep == MachineRepresentation::kWord64) { if (rep == MachineRepresentation::kWord64) {
if (type.Is(Type::BigInt())) {
return MachineType::AnyTagged();
}
DCHECK(type.Is(TypeCache::Get()->kSafeInteger)); DCHECK(type.Is(TypeCache::Get()->kSafeInteger));
return MachineType(rep, MachineSemantic::kInt64); return MachineType(rep, MachineSemantic::kInt64);
} }
...@@ -1134,7 +1137,17 @@ class RepresentationSelector { ...@@ -1134,7 +1137,17 @@ class RepresentationSelector {
void VisitStateValues(Node* node) { void VisitStateValues(Node* node) {
if (propagate()) { if (propagate()) {
for (int i = 0; i < node->InputCount(); i++) { for (int i = 0; i < node->InputCount(); i++) {
EnqueueInput(node, i, UseInfo::Any()); // When lowering 64 bit BigInts to Word64 representation, we have to
// make sure they are rematerialized before deoptimization. By
// propagating a AnyTagged use, the RepresentationChanger is going to
// insert the necessary conversions.
// TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
// truncated BigInts.
if (TypeOf(node->InputAt(i)).Is(Type::BigInt())) {
EnqueueInput(node, i, UseInfo::AnyTagged());
} else {
EnqueueInput(node, i, UseInfo::Any());
}
} }
} else if (lower()) { } else if (lower()) {
Zone* zone = jsgraph_->zone(); Zone* zone = jsgraph_->zone();
...@@ -1143,6 +1156,12 @@ class RepresentationSelector { ...@@ -1143,6 +1156,12 @@ class RepresentationSelector {
ZoneVector<MachineType>(node->InputCount(), zone); 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
// truncated BigInts.
if (TypeOf(input).Is(Type::BigInt())) {
ProcessInput(node, i, UseInfo::AnyTagged());
}
(*types)[i] = (*types)[i] =
DeoptMachineTypeOf(GetInfo(input)->representation(), TypeOf(input)); DeoptMachineTypeOf(GetInfo(input)->representation(), TypeOf(input));
} }
...@@ -2481,7 +2500,7 @@ class RepresentationSelector { ...@@ -2481,7 +2500,7 @@ class RepresentationSelector {
return; return;
} }
case IrOpcode::kBigIntAsUintN: { case IrOpcode::kBigIntAsUintN: {
ProcessInput(node, 0, UseInfo::TruncatedBigIntAsWord64()); ProcessInput(node, 0, UseInfo::TruncatingWord64());
SetOutput(node, MachineRepresentation::kWord64, Type::BigInt()); SetOutput(node, MachineRepresentation::kWord64, Type::BigInt());
return; return;
} }
...@@ -2646,9 +2665,18 @@ class RepresentationSelector { ...@@ -2646,9 +2665,18 @@ class RepresentationSelector {
return; return;
} }
case IrOpcode::kSpeculativeBigIntAdd: { case IrOpcode::kSpeculativeBigIntAdd: {
VisitBinop(node, if (truncation.IsUsedAsWord64()) {
UseInfo::CheckedBigIntAsTaggedPointer(VectorSlotPair{}), VisitBinop(node,
MachineRepresentation::kTaggedPointer); UseInfo::CheckedBigIntTruncatingWord64(VectorSlotPair{}),
MachineRepresentation::kWord64);
if (lower()) {
ChangeToPureOp(node, lowering->machine()->Int64Add());
}
} else {
VisitBinop(node,
UseInfo::CheckedBigIntAsTaggedPointer(VectorSlotPair{}),
MachineRepresentation::kTaggedPointer);
}
return; return;
} }
case IrOpcode::kStringConcat: { case IrOpcode::kStringConcat: {
...@@ -3594,7 +3622,7 @@ SimplifiedLowering::SimplifiedLowering(JSGraph* jsgraph, JSHeapBroker* broker, ...@@ -3594,7 +3622,7 @@ SimplifiedLowering::SimplifiedLowering(JSGraph* jsgraph, JSHeapBroker* broker,
poisoning_level_(poisoning_level) {} poisoning_level_(poisoning_level) {}
void SimplifiedLowering::LowerAllNodes() { void SimplifiedLowering::LowerAllNodes() {
RepresentationChanger changer(jsgraph(), jsgraph()->isolate()); RepresentationChanger changer(jsgraph(), broker_);
RepresentationSelector selector(jsgraph(), broker_, zone_, &changer, RepresentationSelector selector(jsgraph(), broker_, zone_, &changer,
source_positions_, node_origins_); source_positions_, node_origins_);
selector.Run(this); selector.Run(this);
......
...@@ -239,6 +239,15 @@ NEVER_READ_ONLY_SPACE_IMPL(MutableBigInt) ...@@ -239,6 +239,15 @@ NEVER_READ_ONLY_SPACE_IMPL(MutableBigInt)
MaybeHandle<MutableBigInt> MutableBigInt::New(Isolate* isolate, int length, MaybeHandle<MutableBigInt> MutableBigInt::New(Isolate* isolate, int length,
AllocationType allocation) { AllocationType allocation) {
if (length > BigInt::kMaxLength) { if (length > BigInt::kMaxLength) {
// If the result of a BigInt computation is truncated to 64 bit, Turbofan
// can sometimes truncate intermediate results already, which can prevent
// those from exceeding the maximum length, effectively changing the
// semantics of optimized code. As this is a performance optimization, this
// behavior is accepted. To prevent the fuzzer from detecting this
// difference, we crash the program.
if (FLAG_correctness_fuzzer_suppressions) {
FATAL("Aborting on invalid BigInt length");
}
THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig), THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig),
MutableBigInt); MutableBigInt);
} }
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include <limits> #include <limits>
#include "src/compiler/access-info.h"
#include "src/compiler/js-heap-broker.h"
#include "src/compiler/node-matchers.h" #include "src/compiler/node-matchers.h"
#include "src/compiler/representation-change.h" #include "src/compiler/representation-change.h"
#include "src/compiler/type-cache.h" #include "src/compiler/type-cache.h"
...@@ -25,13 +27,15 @@ class RepresentationChangerTester : public HandleAndZoneScope, ...@@ -25,13 +27,15 @@ class RepresentationChangerTester : public HandleAndZoneScope,
javascript_(main_zone()), javascript_(main_zone()),
jsgraph_(main_isolate(), main_graph_, &main_common_, &javascript_, jsgraph_(main_isolate(), main_graph_, &main_common_, &javascript_,
&main_simplified_, &main_machine_), &main_simplified_, &main_machine_),
changer_(&jsgraph_, main_isolate()) { broker_{main_isolate(), main_zone(), FLAG_trace_heap_broker},
changer_(&jsgraph_, &broker_) {
Node* s = graph()->NewNode(common()->Start(num_parameters)); Node* s = graph()->NewNode(common()->Start(num_parameters));
graph()->SetStart(s); graph()->SetStart(s);
} }
JSOperatorBuilder javascript_; JSOperatorBuilder javascript_;
JSGraph jsgraph_; JSGraph jsgraph_;
JSHeapBroker broker_;
RepresentationChanger changer_; RepresentationChanger changer_;
Isolate* isolate() { return main_isolate(); } Isolate* isolate() { return main_isolate(); }
......
// Copyright 2019 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 --opt
function TestAsUintN() {
assertEquals(0n, BigInt.asUintN(64, 0n));
assertEquals(0n, BigInt.asUintN(8, 0n));
assertEquals(0n, BigInt.asUintN(1, 0n));
assertEquals(0n, BigInt.asUintN(0, 0n));
assertEquals(0n, BigInt.asUintN(100, 0n));
assertEquals(123n, BigInt.asUintN(64, 123n));
assertEquals(123n, BigInt.asUintN(32, 123n));
assertEquals(123n, BigInt.asUintN(8, 123n));
assertEquals(59n, BigInt.asUintN(6, 123n));
assertEquals(27n, BigInt.asUintN(5, 123n));
assertEquals(11n, BigInt.asUintN(4, 123n));
assertEquals(1n, BigInt.asUintN(1, 123n));
assertEquals(0n, BigInt.asUintN(0, 123n));
assertEquals(123n, BigInt.asUintN(72, 123n));
assertEquals(BigInt("0xFFFFFFFFFFFFFF85"), BigInt.asUintN(64, -123n));
assertEquals(BigInt("0xFFFFFF85"), BigInt.asUintN(32, -123n));
assertEquals(BigInt("0x85"), BigInt.asUintN(8, -123n));
assertEquals(5n, BigInt.asUintN(6, -123n));
assertEquals(5n, BigInt.asUintN(5, -123n));
assertEquals(5n, BigInt.asUintN(4, -123n));
assertEquals(1n, BigInt.asUintN(1, -123n));
assertEquals(0n, BigInt.asUintN(0, -123n));
assertEquals(BigInt("0xFFFFFFFFFFFFFFFF85"), BigInt.asUintN(72, -123n));
}
function TestInt64LoweredOperations() {
assertEquals(0n, BigInt.asUintN(64, -0n));
assertEquals(0n, BigInt.asUintN(64, 15n + -15n));
assertEquals(0n, BigInt.asUintN(64, 0n + 0n));
assertEquals(14n, BigInt.asUintN(32, 8n + 6n));
assertEquals(813n, BigInt.asUintN(10, 1013n + -200n));
assertEquals(15n, BigInt.asUintN(4, -319n + 302n));
for (let i = 0; i < 2; ++i) {
let x = 32n; // x = 32n
if (i === 1) {
x = BigInt.asUintN(64, x + 3n); // x = 35n
const y = x + -8n + x; // x = 35n, y = 62n
x = BigInt.asUintN(6, y + x); // x = 33n, y = 62n
x = -9n + y + -x; // x = 20n
x = BigInt.asUintN(10000 * i, x); // x = 20n
} else {
x = x + 400n; // x = 432n
x = -144n + BigInt.asUintN(8, 500n) + x; // x = 532n
}
assertEquals(20n, BigInt.asUintN(8, x));
}
let x = 7n;
for (let i = 0; i < 10; ++i) {
x = x + 5n;
}
assertEquals(57n, BigInt.asUintN(8, x));
let y = 7n;
for(let i = 0; i < 10; ++i) {
y = BigInt.asUintN(4, y + 16n);
}
assertEquals(7n, y);
}
function OptimizeAndTest(fn) {
%PrepareFunctionForOptimization(fn);
fn();
fn();
%OptimizeFunctionOnNextCall(fn);
fn();
assertOptimized(fn);
fn();
}
OptimizeAndTest(TestAsUintN);
OptimizeAndTest(TestInt64LoweredOperations);
// Copyright 2019 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 --opt
function TestNegate() {
assertEquals(0n, -0n);
const x = 15n;
assertEquals(-15n, -x);
assertEquals(15n, - -x);
assertEquals(30n, -(-x + -x));
}
function OptimizeAndTest(fn) {
%PrepareFunctionForOptimization(fn);
fn();
fn();
%OptimizeFunctionOnNextCall(fn);
fn();
assertOptimized(fn);
fn();
}
OptimizeAndTest(TestNegate);
// Copyright 2019 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 --opt
{
function test(a, b, c) {
let x = BigInt.asUintN(64, a + b);
console.log(x);
try {
return BigInt.asUintN(64, x + c);
} catch(_) {
return x;
}
}
%PrepareFunctionForOptimization(test);
test(3n, 4n, 5n);
test(6n, 7n, 8n);
test(9n, 2n, 1n);
%OptimizeFunctionOnNextCall(test);
test(1n, 2n, 3n);
test(3n, 2n, 1n);
assertEquals(6n, test(1n, 3n, 2n));
assertEquals(5n, test(2n, 3n, 2));
}
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