[JSC] Avoid cloned arguments allocation in ArrayPrototype methods
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 10 Nov 2016 06:34:05 +0000 (06:34 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 10 Nov 2016 06:34:05 +0000 (06:34 +0000)
commit4764c90873ed360c402455356970b512ccfb87d3
tree63b2af69e23f62d212991fa51c6e1612d1286d82
parent1dfbe36109cba535ff482f62f61576ab8a951e02
[JSC] Avoid cloned arguments allocation in ArrayPrototype methods
https://bugs.webkit.org/show_bug.cgi?id=164502

Reviewed by Saam Barati.

JSTests:

* stress/argument-intrinsic-basic.js: Added.
(shouldBe):
(builtin.createBuiltin):
* stress/argument-intrinsic-inlining-with-result-escape.js: Added.
(shouldBe):
(builtin.createBuiltin):
(escape):
* stress/argument-intrinsic-nested-inlining.js: Added.
(shouldBe):
(builtin.createBuiltin):
(builtinCaller1):
(builtinCaller2):
(escape):
* stress/argument-intrinsic-not-convert-to-get-argument.js: Added.
(shouldBe):
(builtin.createBuiltin):
* stress/argument-intrinsic-with-stack-write.js: Added.
(shouldBe):
(builtin.createBuiltin):

Source/JavaScriptCore:

In many builtin functions, we use `arguments` to just get optional parameters.
While FTL argument elimination can drop `arguments` allocations, it leaves
the allocations in LLInt, Baseline, and DFG. And we found that DFG compiled
Array#map is heavily used in ES6SampleBench/Basic. And it always creates
a meaningless ClonedArguments.

Using ES6 default parameter here is not a solution. It increases the number
of parameters of the CodeBlock (not `function.length`). And the optional
parameters in Array.prototype.xxx methods are not typically passed. For
example, we typically do not pass `thisArg` to `Array.prototype.map` function.
In this case, the arity check frequently fails. It requires the additional C
call to fixup arguments and it becomes pure overhead.

To solve this problem, this patch introduces a new bytecode intrinsic @argument().
This offers the way to retrieve the argument value without increasing the
arity of the function. And if the argument is not passed (out of bounds), it
just returns `undefined`. The semantics of this intrinsic is the same to the C++
ExecState::argument(). This operation does not require `arguments` object. And we
can drop the `argument` references even in lower 3 tiers.

We implement op_get_argument for this intrinsic. And later this will be converted
to DFG GetArgument node. All the tiers handles this feature.

This patch improves ES6SampleBench/Basic 13.8% in steady state. And in summary,
it improves 4.5%.

In the future, we can improve the implementation of the default parameters.
Currently, the default parameter always increases the arity of the function. So
if you do not pass the argument, the arity check fails. But since it is the default
parameter, it is likely that we don't pass the argument. Using op_get_argument to
implement the default parameter can decrease the case in which the arity check
frequently fails. And it can change the builtin implementation to use the ES6
default parameters instead of using the special @argument() intrinsic in the future.
And at that case, the user code also receives the benefit.

ES6SampleBench/Basic.
    Baseline:
        Running... Basic ( 1  to go)
        firstIteration:     39.38 ms +- 4.48 ms
        averageWorstCase:   20.79 ms +- 0.96 ms
        steadyState:        1959.22 ms +- 65.55 ms

    Patched:
        Running... Basic ( 1  to go)
        firstIteration:     37.85 ms +- 4.09 ms
        averageWorstCase:   18.60 ms +- 0.76 ms
        steadyState:        1721.89 ms +- 57.58 ms

All summary.
    Baseline:
        summary:            164.34 ms +- 5.01 ms
    Patched:
        summary:            157.26 ms +- 5.96 ms

* builtins/ArrayConstructor.js:
* builtins/ArrayPrototype.js:
(reduce):
(reduceRight):
(every):
(forEach):
(filter):
(map):
(some):
(fill):
(find):
(findIndex):
(includes):
(copyWithin):
* builtins/DatePrototype.js:
(toLocaleString):
(toLocaleDateString):
(toLocaleTimeString):
* builtins/MapPrototype.js:
(forEach):
* builtins/NumberPrototype.js:
(toLocaleString):
* builtins/SetPrototype.js:
(forEach):
* builtins/StringPrototype.js:
(padStart):
(padEnd):
(localeCompare):
* builtins/TypedArrayConstructor.js:
* builtins/TypedArrayPrototype.js:
(every):
(fill):
(find):
(findIndex):
(forEach):
(some):
(reduce):
(reduceRight):
(map):
(filter):
* bytecode/BytecodeIntrinsicRegistry.h:
* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::finishCreation):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitGetArgument):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::BytecodeIntrinsicNode::emit_intrinsic_argument):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasHeapPrediction):
(JSC::DFG::Node::hasArgumentIndex):
(JSC::DFG::Node::argumentIndex):
* dfg/DFGNodeType.h:
* dfg/DFGPreciseLocalClobberize.h:
(JSC::DFG::PreciseLocalClobberizeAdaptor::readTop):
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileGetArgument):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileGetArgument):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_get_argument):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_get_argument):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208524 268f45cc-cd09-0410-ab3c-d52691b4dbfc
50 files changed:
JSTests/ChangeLog
JSTests/stress/argument-intrinsic-basic.js [new file with mode: 0644]
JSTests/stress/argument-intrinsic-inlining-use-caller-arg.js [new file with mode: 0644]
JSTests/stress/argument-intrinsic-inlining-with-result-escape.js [new file with mode: 0644]
JSTests/stress/argument-intrinsic-inlining-with-vararg-with-enough-arguments.js [new file with mode: 0644]
JSTests/stress/argument-intrinsic-inlining-with-vararg.js [new file with mode: 0644]
JSTests/stress/argument-intrinsic-nested-inlining.js [new file with mode: 0644]
JSTests/stress/argument-intrinsic-not-convert-to-get-argument.js [new file with mode: 0644]
JSTests/stress/argument-intrinsic-with-stack-write.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/builtins/ArrayConstructor.js
Source/JavaScriptCore/builtins/ArrayPrototype.js
Source/JavaScriptCore/builtins/DatePrototype.js
Source/JavaScriptCore/builtins/MapPrototype.js
Source/JavaScriptCore/builtins/NumberPrototype.js
Source/JavaScriptCore/builtins/SetPrototype.js
Source/JavaScriptCore/builtins/StringPrototype.js
Source/JavaScriptCore/builtins/TypedArrayConstructor.js
Source/JavaScriptCore/builtins/TypedArrayPrototype.js
Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.h
Source/JavaScriptCore/bytecode/BytecodeList.json
Source/JavaScriptCore/bytecode/BytecodeUseDef.h
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCapabilities.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGGraph.cpp
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGPreciseLocalClobberize.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/jit/AssemblyHelpers.h
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITOpcodes.cpp
Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
Source/JavaScriptCore/llint/LowLevelInterpreter64.asm