Ignore:
Timestamp:
Nov 11, 2016, 6:58:11 PM (9 years ago)
Author:
[email protected]
Message:

We should have a more concise way of determining when we're varargs calling a function using rest parameters
https://bugs.webkit.org/show_bug.cgi?id=164258

Reviewed by Yusuke Suzuki.

JSTests:

  • microbenchmarks/call-using-spread.js: Added.

(bar):
(foo):

  • microbenchmarks/spread-large-array.js: Added.

(foo):
(arrays.push):

  • microbenchmarks/spread-small-array.js: Added.

(foo):

  • stress/spread-array-iterator-watchpoint-2.js: Added.

(foo):
(arrayIterator.next):

  • stress/spread-array-iterator-watchpoint.js: Added.

(foo):
(Array.prototype.Symbol.iterator):

  • stress/spread-non-array.js: Added.

(assert):
(foo):
(let.customIterator.Symbol.iterator):
(bar):

Source/JavaScriptCore:

This patch adds two new bytecodes and DFG nodes for the following code patterns:

`
foo(a, b, ...c)
let x = [a, b, ...c];
`

To do this, I've introduced two new bytecode operations (and their
corresponding DFG nodes):

op_spread and op_new_array_with_spread.

op_spread takes a single input and performs the ES6 iteration protocol on it.
It returns the result of doing the spread inside a new class I've
made called JSFixedArray. JSFixedArray is a cell with a single 'size'
field and a buffer of values allocated inline in the cell. Abstracting
the protocol into a single node is good because it will make IR analysis
in the future much simpler. For now, it's also good because it allows
us to create fast paths for array iteration (which is quite common).
This fast path allows us to emit really good code for array iteration
inside the DFG/FTL.

op_new_array_with_spread is a variable argument bytecode that also
has a bit vector associated with it. The bit vector indicates if
any particular argument is to be spread or not. Arguments that
are spread are known to be JSFixedArray because we must emit an
op_spread before op_new_array_with_spread consumes the value.
For example, for this array:
[a, b, ...c, d, ...e]
we will have this bit vector:
[0, 0, 1, 0, 1]

The reason I've chosen this IR is that it will make eliminating
a rest allocation for this type of code much easier:

`
function foo(...args) {

return bar(a, b, ...args);

}
`

It will be easier to analyze the IR now that the operations
will be described at a high level.

This patch is an ~8% speedup on ES6SampleBench on my MBP.

  • CMakeLists.txt:
  • DerivedSources.make:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • builtins/IteratorHelpers.js: Added.

(performIteration):

  • bytecode/BytecodeList.json:
  • bytecode/BytecodeUseDef.h:

(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::dumpBytecode):

  • bytecode/ObjectPropertyConditionSet.cpp:

(JSC::generateConditionForSelfEquivalence):

  • bytecode/ObjectPropertyConditionSet.h:
  • bytecode/TrackedReferences.cpp:

(JSC::TrackedReferences::check):

  • bytecode/UnlinkedCodeBlock.h:

(JSC::UnlinkedCodeBlock::bitVectors):
(JSC::UnlinkedCodeBlock::bitVector):
(JSC::UnlinkedCodeBlock::addBitVector):
(JSC::UnlinkedCodeBlock::shrinkToFit):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::emitNewArrayWithSpread):

  • bytecompiler/BytecodeGenerator.h:
  • bytecompiler/NodesCodegen.cpp:

(JSC::ArrayNode::emitBytecode):

  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::addToGraph):
(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):
(JSC::DFG::FixupPhase::watchHavingABadTime):

  • dfg/DFGGraph.h:

(JSC::DFG::Graph::isWatchingArrayIteratorProtocolWatchpoint):

  • dfg/DFGNode.h:

(JSC::DFG::Node::bitVector):

  • dfg/DFGNodeType.h:
  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGPredictionPropagationPhase.cpp:
  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileSpread):
(JSC::DFG::SpeculativeJIT::compileNewArrayWithSpread):

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::callOperation):

  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGStructureRegistrationPhase.cpp:

(JSC::DFG::StructureRegistrationPhase::run):

  • ftl/FTLAbstractHeapRepository.h:
  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileNewArrayWithSpread):
(JSC::FTL::DFG::LowerDFGToB3::compileSpread):
(JSC::FTL::DFG::LowerDFGToB3::allocateVariableSizedCell):

  • jit/AssemblyHelpers.h:

(JSC::AssemblyHelpers::emitAllocateVariableSizedCell):
(JSC::AssemblyHelpers::emitAllocateVariableSizedJSObject):

  • jit/JIT.cpp:

(JSC::JIT::privateCompileMainPass):

  • jit/JIT.h:
  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_new_array_with_spread):
(JSC::JIT::emit_op_spread):

  • jit/JITOperations.h:
  • llint/LLIntData.cpp:

(JSC::LLInt::Data::performAssertions):

  • llint/LLIntSlowPaths.cpp:
  • llint/LowLevelInterpreter.asm:
  • runtime/ArrayIteratorAdaptiveWatchpoint.cpp: Added.

(JSC::ArrayIteratorAdaptiveWatchpoint::ArrayIteratorAdaptiveWatchpoint):
(JSC::ArrayIteratorAdaptiveWatchpoint::handleFire):

  • runtime/ArrayIteratorAdaptiveWatchpoint.h: Added.
  • runtime/CommonSlowPaths.cpp:

(JSC::SLOW_PATH_DECL):

  • runtime/CommonSlowPaths.h:
  • runtime/IteratorOperations.h:

(JSC::forEachInIterable):

  • runtime/JSCInlines.h:
  • runtime/JSFixedArray.cpp: Added.

(JSC::JSFixedArray::visitChildren):

  • runtime/JSFixedArray.h: Added.

(JSC::JSFixedArray::createStructure):
(JSC::JSFixedArray::createFromArray):
(JSC::JSFixedArray::get):
(JSC::JSFixedArray::buffer):
(JSC::JSFixedArray::size):
(JSC::JSFixedArray::offsetOfSize):
(JSC::JSFixedArray::offsetOfData):
(JSC::JSFixedArray::create):
(JSC::JSFixedArray::JSFixedArray):
(JSC::JSFixedArray::allocationSize):

  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::JSGlobalObject):
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):
(JSC::JSGlobalObject::objectPrototypeIsSane): Deleted.
(JSC::JSGlobalObject::arrayPrototypeChainIsSane): Deleted.
(JSC::JSGlobalObject::stringPrototypeChainIsSane): Deleted.

  • runtime/JSGlobalObject.h:

(JSC::JSGlobalObject::arrayIteratorProtocolWatchpoint):
(JSC::JSGlobalObject::iteratorProtocolFunction):

  • runtime/JSGlobalObjectInlines.h: Added.

(JSC::JSGlobalObject::objectPrototypeIsSane):
(JSC::JSGlobalObject::arrayPrototypeChainIsSane):
(JSC::JSGlobalObject::stringPrototypeChainIsSane):
(JSC::JSGlobalObject::isArrayIteratorProtocolFastAndNonObservable):

  • runtime/JSType.h:
  • runtime/VM.cpp:

(JSC::VM::VM):

  • runtime/VM.h:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r208619 r208637  
    786786    }
    787787   
    788     Node* addToGraph(Node::VarArgTag, NodeType op, OpInfo info1, OpInfo info2)
     788    Node* addToGraph(Node::VarArgTag, NodeType op, OpInfo info1, OpInfo info2 = OpInfo())
    789789    {
    790790        Node* result = m_graph.addNode(
     
    38303830            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(Node::VarArg, NewArray, OpInfo(profile->selectIndexingType()), OpInfo(0)));
    38313831            NEXT_OPCODE(op_new_array);
     3832        }
     3833
     3834        case op_new_array_with_spread: {
     3835            int startOperand = currentInstruction[2].u.operand;
     3836            int numOperands = currentInstruction[3].u.operand;
     3837            const BitVector& bitVector = m_inlineStackTop->m_profiledBlock->unlinkedCodeBlock()->bitVector(currentInstruction[4].u.unsignedValue);
     3838            for (int operandIdx = startOperand; operandIdx > startOperand - numOperands; --operandIdx)
     3839                addVarArgChild(get(VirtualRegister(operandIdx)));
     3840
     3841            BitVector* copy = m_graph.m_bitVectors.add(bitVector);
     3842            ASSERT(*copy == bitVector);
     3843
     3844            set(VirtualRegister(currentInstruction[1].u.operand),
     3845                addToGraph(Node::VarArg, NewArrayWithSpread, OpInfo(copy)));
     3846            NEXT_OPCODE(op_new_array_with_spread);
     3847        }
     3848
     3849        case op_spread: {
     3850            set(VirtualRegister(currentInstruction[1].u.operand),
     3851                addToGraph(Spread, get(VirtualRegister(currentInstruction[2].u.operand))));
     3852            NEXT_OPCODE(op_spread);
    38323853        }
    38333854           
Note: See TracChangeset for help on using the changeset viewer.