Ignore:
Timestamp:
Dec 9, 2016, 11:32:38 PM (9 years ago)
Author:
[email protected]
Message:

JSVALUE64: Pass arguments in platform argument registers when making JavaScript calls
https://bugs.webkit.org/show_bug.cgi?id=160355

Reviewed by Filip Pizlo.

JSTests:

New microbenchmarks to measure call type performance.

  • microbenchmarks/calling-computed-args.js: Added.
  • microbenchmarks/calling-many-callees.js: Added.
  • microbenchmarks/calling-one-callee-fixed.js: Added.
  • microbenchmarks/calling-one-callee.js: Added.
  • microbenchmarks/calling-poly-callees.js: Added.
  • microbenchmarks/calling-poly-extra-arity-callees.js: Added.
  • microbenchmarks/calling-tailcall.js: Added.
  • microbenchmarks/calling-virtual-arity-fixup-callees.js: Added.
  • microbenchmarks/calling-virtual-arity-fixup-stackargs.js: Added.
  • microbenchmarks/calling-virtual-callees.js: Added.
  • microbenchmarks/calling-virtual-extra-arity-callees.js: Added.

Source/JavaScriptCore:

This patch implements passing JavaScript function arguments in registers for 64 bit platforms.

The implemented convention follows the ABI conventions for the associated platform.
The first two arguments are the callee and argument count, the rest of the argument registers
contain "this" and following argument until all platform argument registers are exhausted.
Arguments beyond what fit in registers are placed on the stack in the same location as
before this patch.

For X86-64 non-Windows platforms, there are 6 argument registers specified in the related ABI.
ARM64 has had argument registers. This allows for 4 or 6 parameter values to be placed in
registers on these respective platforms. This patch doesn't implement passing arguments in
registers for 32 bit platform, since most platforms have at most 4 argument registers
specified and 32 bit platforms use two 32 bit registers/memory locations to store one JSValue.

The call frame on the stack in unchanged in format and the arguments that are passed in
registers use the corresponding call frame location as a spill location. Arguments can
also be passed on the stack. The LLInt, baseline JIT'ed code as well as the initial entry
from C++ code base arguments on the stack. DFG s and FTL generated code pass arguments
via registers. All callees can accept arguments either in registers or on the stack.
The callee is responsible for moving argument to its preferred location.

The multiple entry points to JavaSCript code is now handled via the JITEntryPoints class and
related code. That class now has entries for StackArgsArityCheckNotRequired,
StackArgsMustCheckArity and for platforms that support registers arguments,
RegisterArgsArityCheckNotRequired, RegisterArgsMustCheckArity as well as and additional
RegisterArgsPossibleExtraArgs entry point when extra registers argument are passed.
This last case is needed to spill those extra arguments to the corresponding call frame
slots.

  • JavaScriptCore.xcodeproj/project.pbxproj:
  • b3/B3ArgumentRegValue.h:
  • b3/B3Validate.cpp:
  • bytecode/CallLinkInfo.cpp:

(JSC::CallLinkInfo::CallLinkInfo):

  • bytecode/CallLinkInfo.h:

(JSC::CallLinkInfo::setUpCall):
(JSC::CallLinkInfo::argumentsLocation):
(JSC::CallLinkInfo::argumentsInRegisters):

  • bytecode/PolymorphicAccess.cpp:

(JSC::AccessCase::generateImpl):

  • dfg/DFGAbstractInterpreterInlines.h:

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

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGCPSRethreadingPhase.cpp:

(JSC::DFG::CPSRethreadingPhase::canonicalizeLocalsInBlock):
(JSC::DFG::CPSRethreadingPhase::specialCaseArguments):
(JSC::DFG::CPSRethreadingPhase::computeIsFlushed):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGCommon.h:
  • dfg/DFGDCEPhase.cpp:

(JSC::DFG::DCEPhase::run):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGDriver.cpp:

(JSC::DFG::compileImpl):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):

  • dfg/DFGGenerationInfo.h:

(JSC::DFG::GenerationInfo::initArgumentRegisterValue):

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::dump):
(JSC::DFG::Graph::methodOfGettingAValueProfileFor):

  • dfg/DFGGraph.h:

(JSC::DFG::Graph::needsFlushedThis):
(JSC::DFG::Graph::addImmediateShouldSpeculateInt32):

  • dfg/DFGInPlaceAbstractState.cpp:

(JSC::DFG::InPlaceAbstractState::initialize):

  • dfg/DFGJITCompiler.cpp:

(JSC::DFG::JITCompiler::link):
(JSC::DFG::JITCompiler::compile):
(JSC::DFG::JITCompiler::compileFunction):
(JSC::DFG::JITCompiler::compileEntry): Deleted.

  • dfg/DFGJITCompiler.h:

(JSC::DFG::JITCompiler::addJSDirectCall):
(JSC::DFG::JITCompiler::JSDirectCallRecord::JSDirectCallRecord):
(JSC::DFG::JITCompiler::JSDirectCallRecord::hasSlowCall):

  • dfg/DFGJITFinalizer.cpp:

(JSC::DFG::JITFinalizer::JITFinalizer):
(JSC::DFG::JITFinalizer::finalize):
(JSC::DFG::JITFinalizer::finalizeFunction):

  • dfg/DFGJITFinalizer.h:
  • dfg/DFGLiveCatchVariablePreservationPhase.cpp:

(JSC::DFG::LiveCatchVariablePreservationPhase::handleBlock):

  • dfg/DFGMaximalFlushInsertionPhase.cpp:

(JSC::DFG::MaximalFlushInsertionPhase::treatRegularBlock):
(JSC::DFG::MaximalFlushInsertionPhase::treatRootBlock):

  • dfg/DFGMayExit.cpp:
  • dfg/DFGMinifiedNode.cpp:

(JSC::DFG::MinifiedNode::fromNode):

  • dfg/DFGMinifiedNode.h:

(JSC::DFG::belongsInMinifiedGraph):

  • dfg/DFGNode.cpp:

(JSC::DFG::Node::hasVariableAccessData):

  • dfg/DFGNode.h:

(JSC::DFG::Node::accessesStack):
(JSC::DFG::Node::setVariableAccessData):
(JSC::DFG::Node::hasArgumentRegisterIndex):
(JSC::DFG::Node::argumentRegisterIndex):

  • dfg/DFGNodeType.h:
  • dfg/DFGOSRAvailabilityAnalysisPhase.cpp:

(JSC::DFG::LocalOSRAvailabilityCalculator::executeNode):

  • dfg/DFGOSREntrypointCreationPhase.cpp:

(JSC::DFG::OSREntrypointCreationPhase::run):

  • dfg/DFGPlan.cpp:

(JSC::DFG::Plan::compileInThreadImpl):

  • dfg/DFGPreciseLocalClobberize.h:

(JSC::DFG::PreciseLocalClobberizeAdaptor::readTop):

  • dfg/DFGPredictionInjectionPhase.cpp:

(JSC::DFG::PredictionInjectionPhase::run):

  • dfg/DFGPredictionPropagationPhase.cpp:
  • dfg/DFGPutStackSinkingPhase.cpp:
  • dfg/DFGRegisterBank.h:

(JSC::DFG::RegisterBank::iterator::unlock):
(JSC::DFG::RegisterBank::unlockAtIndex):

  • dfg/DFGSSAConversionPhase.cpp:

(JSC::DFG::SSAConversionPhase::run):

  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::SpeculativeJIT):
(JSC::DFG::SpeculativeJIT::clearGenerationInfo):
(JSC::DFG::dumpRegisterInfo):
(JSC::DFG::SpeculativeJIT::dump):
(JSC::DFG::SpeculativeJIT::compileCurrentBlock):
(JSC::DFG::SpeculativeJIT::checkArgumentTypes):
(JSC::DFG::SpeculativeJIT::setupArgumentRegistersForEntry):
(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::allocate):
(JSC::DFG::SpeculativeJIT::spill):
(JSC::DFG::SpeculativeJIT::generationInfoFromVirtualRegister):
(JSC::DFG::JSValueOperand::JSValueOperand):
(JSC::DFG::JSValueOperand::gprUseSpecific):

  • dfg/DFGSpeculativeJIT32_64.cpp:

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

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::fillJSValue):
(JSC::DFG::SpeculativeJIT::emitCall):
(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGStrengthReductionPhase.cpp:

(JSC::DFG::StrengthReductionPhase::handleNode):

  • dfg/DFGThunks.cpp:

(JSC::DFG::osrEntryThunkGenerator):

  • dfg/DFGVariableEventStream.cpp:

(JSC::DFG::VariableEventStream::reconstruct):

  • dfg/DFGVirtualRegisterAllocationPhase.cpp:

(JSC::DFG::VirtualRegisterAllocationPhase::allocateRegister):
(JSC::DFG::VirtualRegisterAllocationPhase::run):

  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLJITCode.cpp:

(JSC::FTL::JITCode::~JITCode):
(JSC::FTL::JITCode::initializeEntrypointThunk):
(JSC::FTL::JITCode::setEntryFor):
(JSC::FTL::JITCode::addressForCall):
(JSC::FTL::JITCode::executableAddressAtOffset):
(JSC::FTL::JITCode::initializeAddressForCall): Deleted.
(JSC::FTL::JITCode::initializeArityCheckEntrypoint): Deleted.

  • ftl/FTLJITCode.h:
  • ftl/FTLJITFinalizer.cpp:

(JSC::FTL::JITFinalizer::finalizeFunction):

  • ftl/FTLLink.cpp:

(JSC::FTL::link):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::lower):
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileGetArgumentRegister):
(JSC::FTL::DFG::LowerDFGToB3::compileCallOrConstruct):
(JSC::FTL::DFG::LowerDFGToB3::compileDirectCallOrConstruct):
(JSC::FTL::DFG::LowerDFGToB3::compileTailCall):
(JSC::FTL::DFG::LowerDFGToB3::compileCallOrConstructVarargsSpread):
(JSC::FTL::DFG::LowerDFGToB3::compileCallOrConstructVarargs):
(JSC::FTL::DFG::LowerDFGToB3::compileCallEval):

  • ftl/FTLOSREntry.cpp:

(JSC::FTL::prepareOSREntry):

  • ftl/FTLOutput.cpp:

(JSC::FTL::Output::argumentRegister):
(JSC::FTL::Output::argumentRegisterInt32):

  • ftl/FTLOutput.h:
  • interpreter/ShadowChicken.cpp:

(JSC::ShadowChicken::update):

  • jit/AssemblyHelpers.cpp:

(JSC::AssemblyHelpers::emitDumbVirtualCall):

  • jit/AssemblyHelpers.h:

(JSC::AssemblyHelpers::spillArgumentRegistersToFrameBeforePrologue):
(JSC::AssemblyHelpers::spillArgumentRegistersToFrame):
(JSC::AssemblyHelpers::fillArgumentRegistersFromFrameBeforePrologue):
(JSC::AssemblyHelpers::emitPutArgumentToCallFrameBeforePrologue):
(JSC::AssemblyHelpers::emitPutArgumentToCallFrame):
(JSC::AssemblyHelpers::emitGetFromCallFrameHeaderBeforePrologue):
(JSC::AssemblyHelpers::emitGetFromCallFrameArgumentBeforePrologue):
(JSC::AssemblyHelpers::emitGetPayloadFromCallFrameHeaderBeforePrologue):
(JSC::AssemblyHelpers::incrementCounter):

  • jit/CachedRecovery.cpp:

(JSC::CachedRecovery::addTargetJSValueRegs):

  • jit/CachedRecovery.h:

(JSC::CachedRecovery::gprTargets):
(JSC::CachedRecovery::setWantedFPR):
(JSC::CachedRecovery::wantedJSValueRegs):
(JSC::CachedRecovery::setWantedJSValueRegs): Deleted.

  • jit/CallFrameShuffleData.h:
  • jit/CallFrameShuffler.cpp:

(JSC::CallFrameShuffler::CallFrameShuffler):
(JSC::CallFrameShuffler::dump):
(JSC::CallFrameShuffler::tryWrites):
(JSC::CallFrameShuffler::prepareAny):

  • jit/CallFrameShuffler.h:

(JSC::CallFrameShuffler::snapshot):
(JSC::CallFrameShuffler::addNew):
(JSC::CallFrameShuffler::initDangerFrontier):
(JSC::CallFrameShuffler::updateDangerFrontier):
(JSC::CallFrameShuffler::findDangerFrontierFrom):

  • jit/CallFrameShuffler64.cpp:

(JSC::CallFrameShuffler::emitDisplace):

  • jit/GPRInfo.h:

(JSC::JSValueRegs::operator==):
(JSC::JSValueRegs::operator!=):
(JSC::GPRInfo::toArgumentIndex):
(JSC::argumentRegisterFor):
(JSC::argumentRegisterForCallee):
(JSC::argumentRegisterForArgumentCount):
(JSC::argumentRegisterIndexForJSFunctionArgument):
(JSC::jsFunctionArgumentForArgumentRegister):
(JSC::argumentRegisterForFunctionArgument):
(JSC::numberOfRegisterArgumentsFor):

  • jit/JIT.cpp:

(JSC::JIT::compileWithoutLinking):
(JSC::JIT::link):
(JSC::JIT::compileCTINativeCall): Deleted.

  • jit/JIT.h:

(JSC::JIT::compileNativeCallEntryPoints):

  • jit/JITCall.cpp:

(JSC::JIT::compileSetupVarargsFrame):
(JSC::JIT::compileCallEval):
(JSC::JIT::compileCallEvalSlowCase):
(JSC::JIT::compileOpCall):
(JSC::JIT::compileOpCallSlowCase):

  • jit/JITCall32_64.cpp:

(JSC::JIT::compileCallEvalSlowCase):
(JSC::JIT::compileOpCall):
(JSC::JIT::compileOpCallSlowCase):

  • jit/JITCode.cpp:

(JSC::JITCode::execute):
(JSC::DirectJITCode::DirectJITCode):
(JSC::DirectJITCode::initializeEntryPoints):
(JSC::DirectJITCode::addressForCall):
(JSC::NativeJITCode::addressForCall):
(JSC::DirectJITCode::initializeCodeRef): Deleted.

  • jit/JITCode.h:

(JSC::JITCode::executableAddress): Deleted.

  • jit/JITEntryPoints.h: Added.

(JSC::JITEntryPoints::JITEntryPoints):
(JSC::JITEntryPoints::entryFor):
(JSC::JITEntryPoints::setEntryFor):
(JSC::JITEntryPoints::offsetOfEntryFor):
(JSC::JITEntryPoints::registerEntryTypeForArgumentCount):
(JSC::JITEntryPoints::registerEntryTypeForArgumentType):
(JSC::JITEntryPoints::clearEntries):
(JSC::JITEntryPoints::operator=):
(JSC::JITEntryPointsWithRef::JITEntryPointsWithRef):
(JSC::JITEntryPointsWithRef::codeRef):
(JSC::argumentsLocationFor):
(JSC::registerEntryPointTypeFor):
(JSC::entryPointTypeFor):
(JSC::thunkEntryPointTypeFor):
(JSC::JITJSCallThunkEntryPointsWithRef::JITJSCallThunkEntryPointsWithRef):
(JSC::JITJSCallThunkEntryPointsWithRef::entryFor):
(JSC::JITJSCallThunkEntryPointsWithRef::setEntryFor):
(JSC::JITJSCallThunkEntryPointsWithRef::offsetOfEntryFor):
(JSC::JITJSCallThunkEntryPointsWithRef::clearEntries):
(JSC::JITJSCallThunkEntryPointsWithRef::codeRef):
(JSC::JITJSCallThunkEntryPointsWithRef::operator=):

  • jit/JITOpcodes.cpp:

(JSC::JIT::privateCompileJITEntryNativeCall):
(JSC::JIT::privateCompileCTINativeCall): Deleted.

  • jit/JITOpcodes32_64.cpp:

(JSC::JIT::privateCompileJITEntryNativeCall):
(JSC::JIT::privateCompileCTINativeCall): Deleted.

  • jit/JITOperations.cpp:
  • jit/JITThunks.cpp:

(JSC::JITThunks::jitEntryNativeCall):
(JSC::JITThunks::jitEntryNativeConstruct):
(JSC::JITThunks::jitEntryStub):
(JSC::JITThunks::jitCallThunkEntryStub):
(JSC::JITThunks::hostFunctionStub):
(JSC::JITThunks::ctiNativeCall): Deleted.
(JSC::JITThunks::ctiNativeConstruct): Deleted.

  • jit/JITThunks.h:
  • jit/JSInterfaceJIT.h:

(JSC::JSInterfaceJIT::emitJumpIfNotInt32):
(JSC::JSInterfaceJIT::emitLoadInt32):

  • jit/RegisterSet.cpp:

(JSC::RegisterSet::argumentRegisters):

  • jit/RegisterSet.h:
  • jit/Repatch.cpp:

(JSC::linkSlowFor):
(JSC::revertCall):
(JSC::unlinkFor):
(JSC::linkVirtualFor):
(JSC::linkPolymorphicCall):

  • jit/SpecializedThunkJIT.h:

(JSC::SpecializedThunkJIT::SpecializedThunkJIT):
(JSC::SpecializedThunkJIT::checkJSStringArgument):
(JSC::SpecializedThunkJIT::linkFailureHere):
(JSC::SpecializedThunkJIT::finalize):

  • jit/ThunkGenerator.h:
  • jit/ThunkGenerators.cpp:

(JSC::createRegisterArgumentsSpillEntry):
(JSC::slowPathFor):
(JSC::linkCallThunkGenerator):
(JSC::linkDirectCallThunkGenerator):
(JSC::linkPolymorphicCallThunkGenerator):
(JSC::virtualThunkFor):
(JSC::nativeForGenerator):
(JSC::nativeCallGenerator):
(JSC::nativeTailCallGenerator):
(JSC::nativeTailCallWithoutSavedTagsGenerator):
(JSC::nativeConstructGenerator):
(JSC::stringCharLoadRegCall):
(JSC::charCodeAtThunkGenerator):
(JSC::charAtThunkGenerator):
(JSC::fromCharCodeThunkGenerator):
(JSC::clz32ThunkGenerator):
(JSC::sqrtThunkGenerator):
(JSC::floorThunkGenerator):
(JSC::ceilThunkGenerator):
(JSC::truncThunkGenerator):
(JSC::roundThunkGenerator):
(JSC::expThunkGenerator):
(JSC::logThunkGenerator):
(JSC::absThunkGenerator):
(JSC::imulThunkGenerator):
(JSC::randomThunkGenerator):
(JSC::boundThisNoArgsFunctionCallGenerator):

  • jit/ThunkGenerators.h:
  • jsc.cpp:

(jscmain):

  • llint/LLIntEntrypoint.cpp:

(JSC::LLInt::setFunctionEntrypoint):
(JSC::LLInt::setEvalEntrypoint):
(JSC::LLInt::setProgramEntrypoint):
(JSC::LLInt::setModuleProgramEntrypoint):

  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::entryOSR):
(JSC::LLInt::setUpCall):

  • llint/LLIntThunks.cpp:

(JSC::LLInt::generateThunkWithJumpTo):
(JSC::LLInt::functionForRegisterCallEntryThunkGenerator):
(JSC::LLInt::functionForStackCallEntryThunkGenerator):
(JSC::LLInt::functionForRegisterConstructEntryThunkGenerator):
(JSC::LLInt::functionForStackConstructEntryThunkGenerator):
(JSC::LLInt::functionForRegisterCallArityCheckThunkGenerator):
(JSC::LLInt::functionForStackCallArityCheckThunkGenerator):
(JSC::LLInt::functionForRegisterConstructArityCheckThunkGenerator):
(JSC::LLInt::functionForStackConstructArityCheckThunkGenerator):
(JSC::LLInt::functionForCallEntryThunkGenerator): Deleted.
(JSC::LLInt::functionForConstructEntryThunkGenerator): Deleted.
(JSC::LLInt::functionForCallArityCheckThunkGenerator): Deleted.
(JSC::LLInt::functionForConstructArityCheckThunkGenerator): Deleted.

  • llint/LLIntThunks.h:
  • runtime/ArityCheckMode.h:
  • runtime/ExecutableBase.cpp:

(JSC::ExecutableBase::clearCode):

  • runtime/ExecutableBase.h:

(JSC::ExecutableBase::entrypointFor):
(JSC::ExecutableBase::offsetOfEntryFor):
(JSC::ExecutableBase::offsetOfJITCodeWithArityCheckFor): Deleted.

  • runtime/JSBoundFunction.cpp:

(JSC::boundThisNoArgsFunctionCall):

  • runtime/NativeExecutable.cpp:

(JSC::NativeExecutable::finishCreation):

  • runtime/ScriptExecutable.cpp:

(JSC::ScriptExecutable::installCode):

  • runtime/VM.cpp:

(JSC::VM::VM):
(JSC::thunkGeneratorForIntrinsic):
(JSC::VM::clearCounters):
(JSC::VM::dumpCounters):

  • runtime/VM.h:

(JSC::VM::getJITEntryStub):
(JSC::VM::getJITCallThunkEntryStub):
(JSC::VM::addressOfCounter):
(JSC::VM::counterFor):

  • wasm/WasmBinding.cpp:

(JSC::Wasm::importStubGenerator):

Source/WTF:

Added a new build option ENABLE_VM_COUNTERS to enable JIT'able counters.
The default is for the option to be off.

  • wtf/Platform.h:

Added ENABLE_VM_COUNTERS

File:
1 edited

Legend:

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

    r209638 r209653  
    8181}
    8282
    83 GPRReg SpeculativeJIT::fillJSValue(Edge edge)
     83GPRReg SpeculativeJIT::fillJSValue(Edge edge, GPRReg gprToUse)
    8484{
    8585    VirtualRegister virtualRegister = edge->virtualRegister();
     
    8888    switch (info.registerFormat()) {
    8989    case DataFormatNone: {
    90         GPRReg gpr = allocate();
     90        GPRReg gpr = allocate(gprToUse);
    9191
    9292        if (edge->hasConstant()) {
     
    121121        // If not, we'll zero extend in place, so mark on the info that this is now type DataFormatInt32, not DataFormatJSInt32.
    122122        if (m_gprs.isLocked(gpr)) {
    123             GPRReg result = allocate();
     123            GPRReg result = allocate(gprToUse);
     124            m_jit.or64(GPRInfo::tagTypeNumberRegister, gpr, result);
     125            return result;
     126        }
     127        if (gprToUse != InvalidGPRReg && gpr != gprToUse) {
     128            GPRReg result = allocate(gprToUse);
    124129            m_jit.or64(GPRInfo::tagTypeNumberRegister, gpr, result);
    125130            return result;
     
    139144    case DataFormatJSBoolean: {
    140145        GPRReg gpr = info.gpr();
     146        if (gprToUse != InvalidGPRReg && gpr != gprToUse) {
     147            GPRReg result = allocate(gprToUse);
     148            m_jit.move(gpr, result);
     149            return result;
     150        }
    141151        m_gprs.lock(gpr);
    142152        return gpr;
     
    633643{
    634644    CallLinkInfo::CallType callType;
     645    ArgumentsLocation argumentsLocation = StackArgs;
    635646    bool isVarargs = false;
    636647    bool isForwardVarargs = false;
     
    715726    GPRReg calleeGPR = InvalidGPRReg;
    716727    CallFrameShuffleData shuffleData;
    717    
     728    std::optional<JSValueOperand> tailCallee;
     729    std::optional<GPRTemporary> calleeGPRTemporary;
     730
     731    incrementCounter(&m_jit, VM::DFGCaller);
     732
    718733    ExecutableBase* executable = nullptr;
    719734    FunctionExecutable* functionExecutable = nullptr;
     
    734749        unsigned numUsedStackSlots = m_jit.graph().m_nextMachineLocal;
    735750       
     751        incrementCounter(&m_jit, VM::CallVarargs);
    736752        if (isForwardVarargs) {
    737753            flushRegisters();
     
    842858
    843859        if (isTail) {
     860            incrementCounter(&m_jit, VM::TailCall);
    844861            Edge calleeEdge = m_jit.graph().child(node, 0);
    845             JSValueOperand callee(this, calleeEdge);
    846             calleeGPR = callee.gpr();
     862            // We can't get the a specific register for the callee, since that will just move
     863            // from any current register.  When we silent fill in the slow path we'll fill
     864            // the original register and won't have the callee in the right register.
     865            // Therefore we allocate a temp register for the callee and move ourselves.
     866            tailCallee.emplace(this, calleeEdge);
     867            GPRReg tailCalleeGPR = tailCallee->gpr();
     868            calleeGPR = argumentRegisterForCallee();
     869            if (tailCalleeGPR != calleeGPR)
     870                calleeGPRTemporary = GPRTemporary(this, calleeGPR);
    847871            if (!isDirect)
    848                 callee.use();
    849 
     872                tailCallee->use();
     873
     874            argumentsLocation = argumentsLocationFor(numAllocatedArgs);
     875            shuffleData.argumentsInRegisters = argumentsLocation != StackArgs;
    850876            shuffleData.tagTypeNumber = GPRInfo::tagTypeNumberRegister;
    851877            shuffleData.numLocals = m_jit.graph().frameRegisterCount();
    852             shuffleData.callee = ValueRecovery::inGPR(calleeGPR, DataFormatJS);
     878            shuffleData.callee = ValueRecovery::inGPR(tailCalleeGPR, DataFormatJS);
    853879            shuffleData.args.resize(numAllocatedArgs);
    854880
     
    865891
    866892            shuffleData.setupCalleeSaveRegisters(m_jit.codeBlock());
    867         } else {
     893        } else if (node->op() == CallEval) {
     894            // CallEval is handled with the arguments in the stack
    868895            m_jit.store32(MacroAssembler::TrustedImm32(numPassedArgs), JITCompiler::calleeFramePayloadSlot(CallFrameSlot::argumentCount));
    869896
     
    879906            for (unsigned i = numPassedArgs; i < numAllocatedArgs; ++i)
    880907                m_jit.storeTrustedValue(jsUndefined(), JITCompiler::calleeArgumentSlot(i));
     908
     909            incrementCounter(&m_jit, VM::CallEval);
     910        } else {
     911            for (unsigned i = numPassedArgs; i-- > 0;) {
     912                GPRReg platformArgGPR = argumentRegisterForFunctionArgument(i);
     913                Edge argEdge = m_jit.graph().m_varArgChildren[node->firstChild() + 1 + i];
     914                JSValueOperand arg(this, argEdge, platformArgGPR);
     915                GPRReg argGPR = arg.gpr();
     916                ASSERT(argGPR == platformArgGPR || platformArgGPR == InvalidGPRReg);
     917
     918                // Only free the non-argument registers at this point.
     919                if (platformArgGPR == InvalidGPRReg) {
     920                    use(argEdge);
     921                    m_jit.store64(argGPR, JITCompiler::calleeArgumentSlot(i));
     922                }
     923            }
     924
     925            // Use the argument edges for arguments passed in registers.
     926            for (unsigned i = numPassedArgs; i-- > 0;) {
     927                GPRReg argGPR = argumentRegisterForFunctionArgument(i);
     928                if (argGPR != InvalidGPRReg) {
     929                    Edge argEdge = m_jit.graph().m_varArgChildren[node->firstChild() + 1 + i];
     930                    use(argEdge);
     931                }
     932            }
     933
     934            GPRTemporary argCount(this, argumentRegisterForArgumentCount());
     935            GPRReg argCountGPR = argCount.gpr();
     936            m_jit.move(TrustedImm32(numPassedArgs), argCountGPR);
     937            argumentsLocation = argumentsLocationFor(numAllocatedArgs);
     938
     939            for (unsigned i = numPassedArgs; i < numAllocatedArgs; ++i) {
     940                GPRReg platformArgGPR = argumentRegisterForFunctionArgument(i);
     941
     942                if (platformArgGPR == InvalidGPRReg)
     943                    m_jit.storeTrustedValue(jsUndefined(), JITCompiler::calleeArgumentSlot(i));
     944                else {
     945                    GPRTemporary argumentTemp(this, platformArgGPR);
     946                    m_jit.move(TrustedImm64(JSValue::encode(jsUndefined())), argumentTemp.gpr());
     947                }
     948            }
    881949        }
    882950    }
     
    884952    if (!isTail || isVarargs || isForwardVarargs) {
    885953        Edge calleeEdge = m_jit.graph().child(node, 0);
    886         JSValueOperand callee(this, calleeEdge);
     954        JSValueOperand callee(this, calleeEdge, argumentRegisterForCallee());
    887955        calleeGPR = callee.gpr();
    888956        callee.use();
    889         m_jit.store64(calleeGPR, JITCompiler::calleeFrameSlot(CallFrameSlot::callee));
     957        if (argumentsLocation == StackArgs)
     958            m_jit.store64(calleeGPR, JITCompiler::calleeFrameSlot(CallFrameSlot::callee));
    890959
    891960        flushRegisters();
     
    914983   
    915984    CallLinkInfo* callLinkInfo = m_jit.codeBlock()->addCallLinkInfo();
    916     callLinkInfo->setUpCall(callType, m_currentNode->origin.semantic, calleeGPR);
     985    callLinkInfo->setUpCall(callType, argumentsLocation, m_currentNode->origin.semantic, calleeGPR);
    917986
    918987    if (node->op() == CallEval) {
     
    9551024            RELEASE_ASSERT(node->op() == DirectTailCall);
    9561025           
     1026            if (calleeGPRTemporary != std::nullopt)
     1027                m_jit.move(tailCallee->gpr(), calleeGPRTemporary->gpr());
     1028
    9571029            JITCompiler::PatchableJump patchableJump = m_jit.patchableJump();
    9581030            JITCompiler::Label mainPath = m_jit.label();
     1031
     1032            incrementCounter(&m_jit, VM::TailCall);
     1033            incrementCounter(&m_jit, VM::DirectCall);
    9591034           
    9601035            m_jit.emitStoreCallSiteIndex(callSite);
     
    9721047            silentFillAllRegisters(InvalidGPRReg);
    9731048            m_jit.exceptionCheck();
     1049            if (calleeGPRTemporary != std::nullopt)
     1050                m_jit.move(tailCallee->gpr(), calleeGPRTemporary->gpr());
    9741051            m_jit.jump().linkTo(mainPath, &m_jit);
    9751052           
     
    9821059        JITCompiler::Label mainPath = m_jit.label();
    9831060       
     1061        incrementCounter(&m_jit, VM::DirectCall);
     1062
    9841063        m_jit.emitStoreCallSiteIndex(callSite);
    9851064       
     
    9891068        JITCompiler::Label slowPath = m_jit.label();
    9901069        if (isX86())
    991             m_jit.pop(JITCompiler::selectScratchGPR(calleeGPR));
    992 
    993         callOperation(operationLinkDirectCall, callLinkInfo, calleeGPR);
     1070            m_jit.pop(GPRInfo::nonArgGPR0);
     1071
     1072        m_jit.move(MacroAssembler::TrustedImmPtr(callLinkInfo), GPRInfo::nonArgGPR0); // Link info needs to be in nonArgGPR0
     1073        JITCompiler::Call slowCall = m_jit.nearCall();
     1074
    9941075        m_jit.exceptionCheck();
    9951076        m_jit.jump().linkTo(mainPath, &m_jit);
     
    9981079       
    9991080        setResultAndResetStack();
    1000        
    1001         m_jit.addJSDirectCall(call, slowPath, callLinkInfo);
     1081
     1082        m_jit.addJSDirectCall(call, slowCall, slowPath, callLinkInfo);
    10021083        return;
    10031084    }
    1004    
     1085
     1086    if (isTail && calleeGPRTemporary != std::nullopt)
     1087        m_jit.move(tailCallee->gpr(), calleeGPRTemporary->gpr());
     1088
    10051089    m_jit.emitStoreCallSiteIndex(callSite);
    10061090   
     
    10261110    if (node->op() == TailCall) {
    10271111        CallFrameShuffler callFrameShuffler(m_jit, shuffleData);
    1028         callFrameShuffler.setCalleeJSValueRegs(JSValueRegs(GPRInfo::regT0));
     1112        if (argumentsLocation == StackArgs)
     1113            callFrameShuffler.setCalleeJSValueRegs(JSValueRegs(argumentRegisterForCallee()));
    10291114        callFrameShuffler.prepareForSlowPath();
    1030     } else {
    1031         m_jit.move(calleeGPR, GPRInfo::regT0); // Callee needs to be in regT0
    1032 
    1033         if (isTail)
    1034             m_jit.emitRestoreCalleeSaves(); // This needs to happen after we moved calleeGPR to regT0
    1035     }
    1036 
    1037     m_jit.move(MacroAssembler::TrustedImmPtr(callLinkInfo), GPRInfo::regT2); // Link info needs to be in regT2
     1115    } else if (isTail)
     1116        m_jit.emitRestoreCalleeSaves();
     1117
     1118    m_jit.move(MacroAssembler::TrustedImmPtr(callLinkInfo), GPRInfo::nonArgGPR0); // Link info needs to be in nonArgGPR0
    10381119    JITCompiler::Call slowCall = m_jit.nearCall();
    10391120
    10401121    done.link(&m_jit);
    10411122
    1042     if (isTail)
     1123    if (isTail) {
     1124        tailCallee = std::nullopt;
     1125        calleeGPRTemporary = std::nullopt;
    10431126        m_jit.abortWithReason(JITDidReturnFromTailCall);
    1044     else
     1127    } else
    10451128        setResultAndResetStack();
    10461129
     
    41674250    }
    41684251
     4252    case GetArgumentRegister:
     4253        break;
     4254           
    41694255    case GetRestLength: {
    41704256        compileGetRestLength(node);
Note: See TracChangeset for help on using the changeset viewer.