Skip to content
Permalink
Browse files
[BigInt] Add ValueBitLShift into DFG
https://bugs.webkit.org/show_bug.cgi?id=192664

Reviewed by Saam Barati.

JSTests:

We are adding tests to cover ValueBitwise operations AI changes.

* stress/big-int-left-shift-untyped.js: Added.
* stress/bit-op-with-object-returning-int32.js:
* stress/value-bit-and-ai-rule.js: Added.
* stress/value-bit-lshift-ai-rule.js: Added.
* stress/value-bit-or-ai-rule.js: Added.
* stress/value-bit-xor-ai-rule.js: Added.

PerformanceTests:

* BigIntBench/big-int-simple-lshift.js: Added.

Source/JavaScriptCore:

This patch is splitting the `BitLShift` into `ArithBitLShift` and
`ValueBitLShift` to handle BigInt speculation more efficiently during
DFG and FTL layers. Following the same approach of other `ValueBitOps`,
`ValueBitLShift` handles Untyped and BigInt speculations, while
`ArithBitLShift` handles number and boolean operands and always results into
Int32.

* bytecode/BytecodeList.rb:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::finishCreation):
* bytecode/Opcode.h:
* dfg/DFGAbstractInterpreter.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::handleConstantBinaryBitwiseOp):
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

We moved `BitLShift` constant fold rules to a new method
`handleConstantBinaryBitwiseOp` to be reused by `ArithBitLShift` and
`ValueBitLShift`. This also enables support of constant folding on other
bitwise operations like `ValueBitAnd`, `ValueBitOr` and `ValueBitXor`, when
their binary use kind is UntypedUse. Such cases can happen on those
nodes because fixup phase is conservative.

* dfg/DFGBackwardsPropagationPhase.cpp:
(JSC::DFG::BackwardsPropagationPhase::isWithinPowerOfTwo):
(JSC::DFG::BackwardsPropagationPhase::propagate):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsicGetter):
(JSC::DFG::ByteCodeParser::parseBlock):

We parse `op_lshift` as `ArithBitLShift` when its operands are numbers.
Otherwise, we fallback to `ValueBitLShift` and rely on fixup phase to
convert `ValueBitLShift` into `ArithBitLShift` when possible.

* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):

`ArithBitLShift` has the same clobberize rules as former `BitLShift`.
`ValueBitLShift` only clobberize world when it is UntypedUse.

* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):

`ValueBitLShift` can GC when `BigIntUse` because it allocates new
JSBigInts to perform this operation. It also can GC on UntypedUse
because of observable user code.

* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):

`ValueBitLShift` and `ArithBitLShift` has the same fixup rules of
other binary bitwise operations. In the case of `ValueBitLShift`
We check if we should speculate on BigInt or Untyped and fallback to
`ArithBitLShift` when both cheks fail.

* dfg/DFGNode.h:
(JSC::DFG::Node::hasHeapPrediction):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:

We updated `operationValueBitLShift` to handle BigInt cases. Also, we
added `operationBitLShiftBigInt` that is used when we compile
`ValueBitLValueBitLShift(BigIntUse)`.

* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:

`ValueBitLShift`'s prediction propagation rules differs from other
bitwise operations, because using only heap prediction for this node causes
significant performance regression on Octane's zlib and mandreel.
The reason is because of cases where a function is compiled but the
instruction `op_lshift` was never executed before. If we use
`getPrediction()` we will emit a `ForceOSRExit`, resulting in more OSR
than desired. To solve such issue, we are then using
`getPredictionWithoutOSR()` and falling back to `getHeapPrediction()`
only on cases where we can't rely on node's input types.

* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileValueLShiftOp):
(JSC::DFG::SpeculativeJIT::compileShiftOp):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::shiftOp):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStrengthReductionPhase.cpp:
(JSC::DFG::StrengthReductionPhase::handleNode):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileArithBitLShift):
(JSC::FTL::DFG::LowerDFGToB3::compileValueBitLShift):
(JSC::FTL::DFG::LowerDFGToB3::compileBitLShift): Deleted.
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):


Canonical link: https://commits.webkit.org/213622@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@247387 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
caiolima committed Jul 12, 2019
1 parent 52ca365 commit f5bb3642140e8556c5750ecb7e3c512f02748fd9
Showing 36 changed files with 459 additions and 73 deletions.
@@ -1,3 +1,19 @@
2019-07-12 Caio Lima <ticaiolima@gmail.com>

[BigInt] Add ValueBitLShift into DFG
https://bugs.webkit.org/show_bug.cgi?id=192664

Reviewed by Saam Barati.

We are adding tests to cover ValueBitwise operations AI changes.

* stress/big-int-left-shift-untyped.js: Added.
* stress/bit-op-with-object-returning-int32.js:
* stress/value-bit-and-ai-rule.js: Added.
* stress/value-bit-lshift-ai-rule.js: Added.
* stress/value-bit-or-ai-rule.js: Added.
* stress/value-bit-xor-ai-rule.js: Added.

2019-07-11 Justin Michaud <justin_michaud@apple.com>

Add b3 macro lowering for CheckMul on arm64
@@ -0,0 +1,22 @@
//@ runBigIntEnabled

function assert(a, e) {
if (a !== e)
throw new Error("Expected: " + e + " but got: " + a);
}

function untypedLShift(a, b) {
return a << b;
}
noInline(untypedLShift);

let o = {
valueOf: () => 0b11101n
}

for (var i = 0; i < 10000; i++) {
assert(untypedLShift(0b11101n, 10n), 0b111010000000000n);
assert(untypedLShift(o, 10n), 0b111010000000000n);
assert(untypedLShift(0b11101, 10), 0b111010000000000);
}

@@ -46,3 +46,13 @@ for (var i = 0; i < 10000; i++)

assert(numberOfDFGCompiles(bitNot) <= 1, true);

function bitLShift(a, b) {
return a << b;
}
noInline(bitLShift);

for (var i = 0; i < 10000; i++)
assert(bitLShift(o, 3), 0b1101000);

assert(numberOfDFGCompiles(bitLShift) <= 1, true);

@@ -0,0 +1,22 @@
//@ runBigIntEnabled

function assert(a, e) {
if (a !== e)
throw new Error("Expected: " + e + " bug got: " + a);
}

let predicate = true;
function foo(a) {
let v = a;
if (predicate)
v = 0b1010;

let c = v & 0b11;
return c;
}
noInline(foo);

for (let i = 0; i < 10000; i++) {
assert(foo(0b1010n), 0b10);
}

@@ -0,0 +1,22 @@
//@ runBigIntEnabled

function assert(a, e) {
if (a !== e)
throw new Error("Expected: " + e + " bug got: " + a);
}

let predicate = true;
function foo(a) {
let v = a;
if (predicate)
v = 1;

let c = v << 4;
return c;
}
noInline(foo);

for (let i = 0; i < 10000; i++) {
assert(foo(1n), 16);
}

@@ -0,0 +1,22 @@
//@ runBigIntEnabled

function assert(a, e) {
if (a !== e)
throw new Error("Expected: " + e + " bug got: " + a);
}

let predicate = true;
function foo(a) {
let v = a;
if (predicate)
v = 0b1000;

let c = v | 0b11;
return c;
}
noInline(foo);

for (let i = 0; i < 10000; i++) {
assert(foo(0b1000n), 0b1011);
}

@@ -0,0 +1,22 @@
//@ runBigIntEnabled

function assert(a, e) {
if (a !== e)
throw new Error("Expected: " + e + " bug got: " + a);
}

let predicate = true;
function foo(a) {
let v = a;
if (predicate)
v = 0b1010;

let c = v ^ 0b0101;
return c;
}
noInline(foo);

for (let i = 0; i < 10000; i++) {
assert(foo(0b1010n), 0b1111);
}

@@ -0,0 +1,15 @@
function bigInt(a, b) {
let c = a << b;
return c + b;
}
noInline(bigInt);

for (let i = 0; i < 100000; i++) {
bigInt(0b1111n, 0x100n);
}

let out;
for (let i = 0; i < 100000; i++) {
out = bigInt(0xfffffffffffffffffffffffn, 10n);
}

@@ -1,3 +1,12 @@
2019-07-12 Caio Lima <ticaiolima@gmail.com>

[BigInt] Add ValueBitLShift into DFG
https://bugs.webkit.org/show_bug.cgi?id=192664

Reviewed by Saam Barati.

* BigIntBench/big-int-simple-lshift.js: Added.

2019-06-28 Konstantin Tokarev <annulen@yandex.ru>

Remove traces of ENABLE_ICONDATABASE remaining after its removal in 219733
@@ -1,3 +1,112 @@
2019-07-12 Caio Lima <ticaiolima@gmail.com>

[BigInt] Add ValueBitLShift into DFG
https://bugs.webkit.org/show_bug.cgi?id=192664

Reviewed by Saam Barati.

This patch is splitting the `BitLShift` into `ArithBitLShift` and
`ValueBitLShift` to handle BigInt speculation more efficiently during
DFG and FTL layers. Following the same approach of other `ValueBitOps`,
`ValueBitLShift` handles Untyped and BigInt speculations, while
`ArithBitLShift` handles number and boolean operands and always results into
Int32.

* bytecode/BytecodeList.rb:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::finishCreation):
* bytecode/Opcode.h:
* dfg/DFGAbstractInterpreter.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::handleConstantBinaryBitwiseOp):
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

We moved `BitLShift` constant fold rules to a new method
`handleConstantBinaryBitwiseOp` to be reused by `ArithBitLShift` and
`ValueBitLShift`. This also enables support of constant folding on other
bitwise operations like `ValueBitAnd`, `ValueBitOr` and `ValueBitXor`, when
their binary use kind is UntypedUse. Such cases can happen on those
nodes because fixup phase is conservative.

* dfg/DFGBackwardsPropagationPhase.cpp:
(JSC::DFG::BackwardsPropagationPhase::isWithinPowerOfTwo):
(JSC::DFG::BackwardsPropagationPhase::propagate):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsicGetter):
(JSC::DFG::ByteCodeParser::parseBlock):

We parse `op_lshift` as `ArithBitLShift` when its operands are numbers.
Otherwise, we fallback to `ValueBitLShift` and rely on fixup phase to
convert `ValueBitLShift` into `ArithBitLShift` when possible.

* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):

`ArithBitLShift` has the same clobberize rules as former `BitLShift`.
`ValueBitLShift` only clobberize world when it is UntypedUse.

* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):

`ValueBitLShift` can GC when `BigIntUse` because it allocates new
JSBigInts to perform this operation. It also can GC on UntypedUse
because of observable user code.

* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):

`ValueBitLShift` and `ArithBitLShift` has the same fixup rules of
other binary bitwise operations. In the case of `ValueBitLShift`
We check if we should speculate on BigInt or Untyped and fallback to
`ArithBitLShift` when both cheks fail.

* dfg/DFGNode.h:
(JSC::DFG::Node::hasHeapPrediction):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:

We updated `operationValueBitLShift` to handle BigInt cases. Also, we
added `operationBitLShiftBigInt` that is used when we compile
`ValueBitLValueBitLShift(BigIntUse)`.

* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:

`ValueBitLShift`'s prediction propagation rules differs from other
bitwise operations, because using only heap prediction for this node causes
significant performance regression on Octane's zlib and mandreel.
The reason is because of cases where a function is compiled but the
instruction `op_lshift` was never executed before. If we use
`getPrediction()` we will emit a `ForceOSRExit`, resulting in more OSR
than desired. To solve such issue, we are then using
`getPredictionWithoutOSR()` and falling back to `getHeapPrediction()`
only on cases where we can't rely on node's input types.

* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileValueLShiftOp):
(JSC::DFG::SpeculativeJIT::compileShiftOp):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::shiftOp):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStrengthReductionPhase.cpp:
(JSC::DFG::StrengthReductionPhase::handleNode):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileArithBitLShift):
(JSC::FTL::DFG::LowerDFGToB3::compileValueBitLShift):
(JSC::FTL::DFG::LowerDFGToB3::compileBitLShift): Deleted.
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):

2019-07-12 Keith Miller <keith_miller@apple.com>

getIndexQuickly should be const
@@ -226,7 +226,6 @@
:beloweq,
:mod,
:pow,
:lshift,
:rshift,
:urshift,
],
@@ -261,6 +260,7 @@
:bitand,
:bitor,
:bitxor,
:lshift,
],
args: {
dst: VirtualRegister,
@@ -545,6 +545,7 @@ bool CodeBlock::finishCreation(VM& vm, ScriptExecutable* ownerExecutable, Unlink
LINK(OpBitor, profile)
LINK(OpBitnot, profile)
LINK(OpBitxor, profile)
LINK(OpLshift, profile)

LINK(OpGetById, profile)

@@ -107,6 +107,7 @@ extern const unsigned opcodeLengths[];
macro(OpBitor) \
macro(OpBitnot) \
macro(OpBitxor) \
macro(OpLshift) \

#define FOR_EACH_OPCODE_WITH_ARRAY_PROFILE(macro) \
macro(OpHasIndexedProperty) \
@@ -218,6 +218,8 @@ class AbstractInterpreter {
void clobberWorld();
void didFoldClobberWorld();

bool handleConstantBinaryBitwiseOp(Node*);

template<typename Functor>
void forAllValues(unsigned indexInBlock, Functor&);

0 comments on commit f5bb364

Please sign in to comment.