Ignore:
Timestamp:
Jun 7, 2021, 3:51:25 PM (4 years ago)
Author:
[email protected]
Message:

Put the Baseline JIT prologue and op_loop_hint code in JIT thunks.
https://bugs.webkit.org/show_bug.cgi?id=226375

Reviewed by Keith Miller and Robin Morisset.

Baseline JIT prologue code varies in behavior based on several variables. These
variables include (1) whether the prologue does any arguments value profiling,
(2) whether the prologue is for a constructor, and (3) whether the compiled
CodeBlock will have such a large frame that it is greater than the stack reserved
zone (aka red zone) which would require additional stack check logic.

The pre-existing code would generate specialized code based on these (and other
variables). In converting to using thunks for the prologue, we opt not to
convert these specializations into runtime checks. Instead, the implementation
uses 1 of 8 possible specialized thunks to reduce the need to pass arguments for
runtime checks. The only needed argument passed to the prologue thunks is the
codeBlock pointer.

There are 8 possible thunks because we specialize based on 3 variables:

  1. doesProfiling
  2. isConstructor
  3. hasHugeFrame

23 yields 8 permutations of prologue thunk specializations.

Similarly, there are also 8 analogous arity fixup prologues that work similarly.

The op_loop_hint thunk only takes 1 runtime argument: the bytecode offset.

We've tried doing the loop_hint optimization check in the thunk (in order to move
both the fast and slow path into the thunk for maximum space savings). However,
this seems to have some slight negative impact on benchmark performance. We ended
up just keeping the fast path and instead have the slow path call a thunk to do
its work. This realizes the bulk of the size savings without the perf impact.

This patch also optimizes op_enter a bit more by eliminating the need to pass any
arguments to the thunk. The thunk previously took 2 arguments: localsToInit and
canBeOptimized. localsToInit is now computed in the thunk at runtime, and
canBeOptimized is used as a specialization argument to generate 2 variants of the
op_enter thunk: op_enter_canBeOptimized_Generator and op_enter_cannotBeOptimized_Generator,
thereby removing the need to pass it as a runtime argument.

LinkBuffer size results (from a single run of Speedometer2):

BaselineJIT: 93319628 (88.996532 MB) => 83851824 (79.967331 MB) 0.90x

ExtraCTIThunk: 5992 (5.851562 KB) => 6984 (6.820312 KB) 1.17x

...

Total: 197530008 (188.379295 MB) => 188459444 (179.728931 MB) 0.95x

Speedometer2 and JetStream2 results (as measured on an M1 Mac) are neutral.

  • assembler/AbstractMacroAssembler.h:

(JSC::AbstractMacroAssembler::untagReturnAddressWithoutExtraValidation):

  • assembler/MacroAssemblerARM64E.h:

(JSC::MacroAssemblerARM64E::untagReturnAddress):
(JSC::MacroAssemblerARM64E::untagReturnAddressWithoutExtraValidation):

  • assembler/MacroAssemblerARMv7.h:

(JSC::MacroAssemblerARMv7::branchAdd32):

  • assembler/MacroAssemblerMIPS.h:

(JSC::MacroAssemblerMIPS::branchAdd32):

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::offsetOfNumCalleeLocals):
(JSC::CodeBlock::offsetOfNumVars):
(JSC::CodeBlock::offsetOfArgumentValueProfiles):
(JSC::CodeBlock::offsetOfShouldAlwaysBeInlined):

  • jit/AssemblyHelpers.h:

(JSC::AssemblyHelpers::emitSaveCalleeSavesFor):
(JSC::AssemblyHelpers::emitSaveCalleeSavesForBaselineJIT):
(JSC::AssemblyHelpers::emitRestoreCalleeSavesForBaselineJIT):

  • jit/JIT.cpp:

(JSC::JIT::compileAndLinkWithoutFinalizing):
(JSC::JIT::prologueGenerator):
(JSC::JIT::arityFixupPrologueGenerator):
(JSC::JIT::privateCompileExceptionHandlers):

  • jit/JIT.h:
  • jit/JITInlines.h:

(JSC::JIT::emitNakedNearCall):

  • jit/JITOpcodes.cpp:

(JSC::JIT::op_ret_handlerGenerator):
(JSC::JIT::emit_op_enter):
(JSC::JIT::op_enter_Generator):
(JSC::JIT::op_enter_canBeOptimized_Generator):
(JSC::JIT::op_enter_cannotBeOptimized_Generator):
(JSC::JIT::emit_op_loop_hint):
(JSC::JIT::emitSlow_op_loop_hint):
(JSC::JIT::op_loop_hint_Generator):
(JSC::JIT::op_enter_handlerGenerator): Deleted.

  • jit/JITOpcodes32_64.cpp:

(JSC::JIT::emit_op_enter):

  • jit/ThunkGenerators.cpp:

(JSC::popThunkStackPreservesAndHandleExceptionGenerator):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/jit/JIT.cpp

    r278445 r278576  
    5656}
    5757
     58#if ENABLE(EXTRA_CTI_THUNKS)
     59#if CPU(ARM64) || (CPU(X86_64) && !OS(WINDOWS))
     60// These are supported ports.
     61#else
     62// This is a courtesy reminder (and warning) that the implementation of EXTRA_CTI_THUNKS can
     63// use up to 6 argument registers and/or 6/7 temp registers, and make use of ARM64 like
     64// features. Hence, it may not work for many other ports without significant work. If you
     65// plan on adding EXTRA_CTI_THUNKS support for your port, please remember to search the
     66// EXTRA_CTI_THUNKS code for CPU(ARM64) and CPU(X86_64) conditional code, and add support
     67// for your port there as well.
     68#error "unsupported architecture"
     69#endif
     70#endif // ENABLE(EXTRA_CTI_THUNKS)
     71
    5872Seconds totalBaselineCompileTime;
    5973Seconds totalDFGCompileTime;
     
    8498}
    8599
    86 #if ENABLE(DFG_JIT)
     100#if ENABLE(DFG_JIT) && !ENABLE(EXTRA_CTI_THUNKS)
    87101void JIT::emitEnterOptimizationCheck()
    88102{
     
    102116    skipOptimize.link(this);
    103117}
    104 #endif
     118#endif // ENABLE(DFG_JIT) && !ENABLE(EXTRA_CTI_THUNKS)(
    105119
    106120void JIT::emitNotifyWrite(WatchpointSet* set)
     
    683697}
    684698
     699static inline unsigned prologueGeneratorSelector(bool doesProfiling, bool isConstructor, bool hasHugeFrame)
     700{
     701    return doesProfiling << 2 | isConstructor << 1 | hasHugeFrame << 0;
     702}
     703
     704#define FOR_EACH_NON_PROFILING_PROLOGUE_GENERATOR(v) \
     705    v(!doesProfiling, !isConstructor, !hasHugeFrame, prologueGenerator0, arityFixup_prologueGenerator0) \
     706    v(!doesProfiling, !isConstructor,  hasHugeFrame, prologueGenerator1, arityFixup_prologueGenerator1) \
     707    v(!doesProfiling,  isConstructor, !hasHugeFrame, prologueGenerator2, arityFixup_prologueGenerator2) \
     708    v(!doesProfiling,  isConstructor,  hasHugeFrame, prologueGenerator3, arityFixup_prologueGenerator3)
     709
     710#if ENABLE(DFG_JIT)
     711#define FOR_EACH_PROFILING_PROLOGUE_GENERATOR(v) \
     712    v( doesProfiling, !isConstructor, !hasHugeFrame, prologueGenerator4, arityFixup_prologueGenerator4) \
     713    v( doesProfiling, !isConstructor,  hasHugeFrame, prologueGenerator5, arityFixup_prologueGenerator5) \
     714    v( doesProfiling,  isConstructor, !hasHugeFrame, prologueGenerator6, arityFixup_prologueGenerator6) \
     715    v( doesProfiling,  isConstructor,  hasHugeFrame, prologueGenerator7, arityFixup_prologueGenerator7)
     716
     717#else // not ENABLE(DFG_JIT)
     718#define FOR_EACH_PROFILING_PROLOGUE_GENERATOR(v)
     719#endif // ENABLE(DFG_JIT)
     720
     721#define FOR_EACH_PROLOGUE_GENERATOR(v) \
     722    FOR_EACH_NON_PROFILING_PROLOGUE_GENERATOR(v) \
     723    FOR_EACH_PROFILING_PROLOGUE_GENERATOR(v)
     724
    685725void JIT::compileAndLinkWithoutFinalizing(JITCompilationEffort effort)
    686726{
     
    751791
    752792    emitFunctionPrologue();
     793
     794#if !ENABLE(EXTRA_CTI_THUNKS)
    753795    emitPutToCallFrameHeader(m_codeBlock, CallFrameSlot::codeBlock);
    754796
     
    772814        ASSERT(!m_bytecodeIndex);
    773815        if (shouldEmitProfiling()) {
    774             for (unsigned argument = 0; argument < m_codeBlock->numParameters(); ++argument) {
    775                 // If this is a constructor, then we want to put in a dummy profiling site (to
    776                 // keep things consistent) but we don't actually want to record the dummy value.
    777                 if (m_codeBlock->isConstructor() && !argument)
    778                     continue;
     816            // If this is a constructor, then we want to put in a dummy profiling site (to
     817            // keep things consistent) but we don't actually want to record the dummy value.
     818            unsigned startArgument = m_codeBlock->isConstructor() ? 1 : 0;
     819            for (unsigned argument = startArgument; argument < m_codeBlock->numParameters(); ++argument) {
    779820                int offset = CallFrame::argumentOffsetIncludingThis(argument) * static_cast<int>(sizeof(Register));
    780821#if USE(JSVALUE64)
     
    790831        }
    791832    }
    792    
     833#else // ENABLE(EXTRA_CTI_THUNKS)
     834    constexpr GPRReg codeBlockGPR = regT7;
     835    ASSERT(!m_bytecodeIndex);
     836
     837    int frameTopOffset = stackPointerOffsetFor(m_codeBlock) * sizeof(Register);
     838    unsigned maxFrameSize = -frameTopOffset;
     839
     840    bool doesProfiling = (m_codeBlock->codeType() == FunctionCode) && shouldEmitProfiling();
     841    bool isConstructor = m_codeBlock->isConstructor();
     842    bool hasHugeFrame = maxFrameSize > Options::reservedZoneSize();
     843
     844    static constexpr ThunkGenerator generators[] = {
     845#define USE_PROLOGUE_GENERATOR(doesProfiling, isConstructor, hasHugeFrame, name, arityFixupName) name,
     846        FOR_EACH_PROLOGUE_GENERATOR(USE_PROLOGUE_GENERATOR)
     847#undef USE_PROLOGUE_GENERATOR
     848    };
     849    static constexpr unsigned numberOfGenerators = sizeof(generators) / sizeof(generators[0]);
     850
     851    move(TrustedImmPtr(m_codeBlock), codeBlockGPR);
     852
     853    unsigned generatorSelector = prologueGeneratorSelector(doesProfiling, isConstructor, hasHugeFrame);
     854    RELEASE_ASSERT(generatorSelector < numberOfGenerators);
     855    auto generator = generators[generatorSelector];
     856    emitNakedNearCall(vm().getCTIStub(generator).retaggedCode<NoPtrTag>());
     857
     858    Label bodyLabel(this);
     859#endif // !ENABLE(EXTRA_CTI_THUNKS)
     860
    793861    RELEASE_ASSERT(!JITCode::isJIT(m_codeBlock->jitType()));
    794862
     
    804872    m_pcToCodeOriginMapBuilder.appendItem(label(), PCToCodeOriginMapBuilder::defaultCodeOrigin());
    805873
     874#if !ENABLE(EXTRA_CTI_THUNKS)
    806875    stackOverflow.link(this);
    807876    m_bytecodeIndex = BytecodeIndex(0);
     
    809878        addPtr(TrustedImm32(-static_cast<int32_t>(maxFrameExtentForSlowPathCall)), stackPointerRegister);
    810879    callOperationWithCallFrameRollbackOnException(operationThrowStackOverflowError, m_codeBlock);
     880#endif
    811881
    812882    // If the number of parameters is 1, we never require arity fixup.
     
    814884    if (m_codeBlock->codeType() == FunctionCode && requiresArityFixup) {
    815885        m_arityCheck = label();
     886#if !ENABLE(EXTRA_CTI_THUNKS)
    816887        store8(TrustedImm32(0), &m_codeBlock->m_shouldAlwaysBeInlined);
    817888        emitFunctionPrologue();
     
    832903        emitNakedNearCall(m_vm->getCTIStub(arityFixupGenerator).retaggedCode<NoPtrTag>());
    833904
     905        jump(beginLabel);
     906
     907#else // ENABLE(EXTRA_CTI_THUNKS)
     908        emitFunctionPrologue();
     909
     910        static_assert(codeBlockGPR == regT7);
     911        ASSERT(!m_bytecodeIndex);
     912
     913        static constexpr ThunkGenerator generators[] = {
     914#define USE_PROLOGUE_GENERATOR(doesProfiling, isConstructor, hasHugeFrame, name, arityFixupName) arityFixupName,
     915            FOR_EACH_PROLOGUE_GENERATOR(USE_PROLOGUE_GENERATOR)
     916#undef USE_PROLOGUE_GENERATOR
     917        };
     918        static constexpr unsigned numberOfGenerators = sizeof(generators) / sizeof(generators[0]);
     919
     920        move(TrustedImmPtr(m_codeBlock), codeBlockGPR);
     921
     922        RELEASE_ASSERT(generatorSelector < numberOfGenerators);
     923        auto generator = generators[generatorSelector];
     924        RELEASE_ASSERT(generator);
     925        emitNakedNearCall(vm().getCTIStub(generator).retaggedCode<NoPtrTag>());
     926
     927        jump(bodyLabel);
     928#endif // !ENABLE(EXTRA_CTI_THUNKS)
     929
    834930#if ASSERT_ENABLED
    835931        m_bytecodeIndex = BytecodeIndex(); // Reset this, in order to guard its use with ASSERTs.
    836932#endif
    837 
    838         jump(beginLabel);
    839933    } else
    840934        m_arityCheck = entryLabel; // Never require arity fixup.
     
    842936    ASSERT(m_jmpTable.isEmpty());
    843937   
     938#if !ENABLE(EXTRA_CTI_THUNKS)
    844939    privateCompileExceptionHandlers();
     940#endif
    845941   
    846942    if (m_disassembler)
     
    851947    link();
    852948}
     949
     950#if ENABLE(EXTRA_CTI_THUNKS)
     951MacroAssemblerCodeRef<JITThunkPtrTag> JIT::prologueGenerator(VM& vm, bool doesProfiling, bool isConstructor, bool hasHugeFrame, const char* thunkName)
     952{
     953    // This function generates the Baseline JIT's prologue code. It is not useable by other tiers.
     954    constexpr GPRReg codeBlockGPR = regT7; // incoming.
     955
     956    constexpr int virtualRegisterSize = static_cast<int>(sizeof(Register));
     957    constexpr int virtualRegisterSizeShift = 3;
     958    static_assert((1 << virtualRegisterSizeShift) == virtualRegisterSize);
     959
     960    tagReturnAddress();
     961
     962    storePtr(codeBlockGPR, addressFor(CallFrameSlot::codeBlock));
     963
     964    load32(Address(codeBlockGPR, CodeBlock::offsetOfNumCalleeLocals()), regT1);
     965    if constexpr (maxFrameExtentForSlowPathCallInRegisters)
     966        add32(TrustedImm32(maxFrameExtentForSlowPathCallInRegisters), regT1);
     967    lshift32(TrustedImm32(virtualRegisterSizeShift), regT1);
     968    neg64(regT1);
     969#if ASSERT_ENABLED
     970    Probe::Function probeFunction = [] (Probe::Context& context) {
     971        CodeBlock* codeBlock = context.fp<CallFrame*>()->codeBlock();
     972        int64_t frameTopOffset = stackPointerOffsetFor(codeBlock) * sizeof(Register);
     973        RELEASE_ASSERT(context.gpr<intptr_t>(regT1) == frameTopOffset);
     974    };
     975    probe(tagCFunctionPtr<JITProbePtrTag>(probeFunction), nullptr);
     976#endif
     977
     978    addPtr(callFrameRegister, regT1);
     979
     980    JumpList stackOverflow;
     981    if (hasHugeFrame)
     982        stackOverflow.append(branchPtr(Above, regT1, callFrameRegister));
     983    stackOverflow.append(branchPtr(Above, AbsoluteAddress(vm.addressOfSoftStackLimit()), regT1));
     984
     985    // We'll be imminently returning with a `retab` (ARM64E's return with authentication
     986    // using the B key) in the normal path (see MacroAssemblerARM64E's implementation of
     987    // ret()), which will do validation. So, extra validation here is redundant and unnecessary.
     988    untagReturnAddressWithoutExtraValidation();
     989#if CPU(X86_64)
     990    pop(regT2); // Save the return address.
     991#endif
     992    move(regT1, stackPointerRegister);
     993    tagReturnAddress();
     994    checkStackPointerAlignment();
     995#if CPU(X86_64)
     996    push(regT2); // Restore the return address.
     997#endif
     998
     999    emitSaveCalleeSavesForBaselineJIT();
     1000    emitMaterializeTagCheckRegisters();
     1001
     1002    if (doesProfiling) {
     1003        constexpr GPRReg argumentValueProfileGPR = regT6;
     1004        constexpr GPRReg numParametersGPR = regT5;
     1005        constexpr GPRReg argumentGPR = regT4;
     1006
     1007        load32(Address(codeBlockGPR, CodeBlock::offsetOfNumParameters()), numParametersGPR);
     1008        loadPtr(Address(codeBlockGPR, CodeBlock::offsetOfArgumentValueProfiles()), argumentValueProfileGPR);
     1009        if (isConstructor)
     1010            addPtr(TrustedImm32(sizeof(ValueProfile)), argumentValueProfileGPR);
     1011
     1012        int startArgument = CallFrameSlot::thisArgument + (isConstructor ? 1 : 0);
     1013        int startArgumentOffset = startArgument * virtualRegisterSize;
     1014        move(TrustedImm64(startArgumentOffset), argumentGPR);
     1015
     1016        add32(TrustedImm32(static_cast<int>(CallFrameSlot::thisArgument)), numParametersGPR);
     1017        lshift32(TrustedImm32(virtualRegisterSizeShift), numParametersGPR);
     1018
     1019        addPtr(callFrameRegister, argumentGPR);
     1020        addPtr(callFrameRegister, numParametersGPR);
     1021
     1022        Label loopStart(this);
     1023        Jump done = branchPtr(AboveOrEqual, argumentGPR, numParametersGPR);
     1024        {
     1025            load64(Address(argumentGPR), regT0);
     1026            store64(regT0, Address(argumentValueProfileGPR, OBJECT_OFFSETOF(ValueProfile, m_buckets)));
     1027
     1028            // The argument ValueProfiles are stored in a FixedVector. Hence, the
     1029            // address of the next profile can be trivially computed with an increment.
     1030            addPtr(TrustedImm32(sizeof(ValueProfile)), argumentValueProfileGPR);
     1031            addPtr(TrustedImm32(virtualRegisterSize), argumentGPR);
     1032            jump().linkTo(loopStart, this);
     1033        }
     1034        done.link(this);
     1035    }
     1036    ret();
     1037
     1038    stackOverflow.link(this);
     1039#if CPU(X86_64)
     1040    addPtr(TrustedImm32(1 * sizeof(CPURegister)), stackPointerRegister); // discard return address.
     1041#endif
     1042
     1043    uint32_t locationBits = CallSiteIndex(0).bits();
     1044    store32(TrustedImm32(locationBits), tagFor(CallFrameSlot::argumentCountIncludingThis));
     1045
     1046    if (maxFrameExtentForSlowPathCall)
     1047        addPtr(TrustedImm32(-static_cast<int32_t>(maxFrameExtentForSlowPathCall)), stackPointerRegister);
     1048
     1049    setupArguments<decltype(operationThrowStackOverflowError)>(codeBlockGPR);
     1050    prepareCallOperation(vm);
     1051    MacroAssembler::Call operationCall = call(OperationPtrTag);
     1052    Jump handleExceptionJump = jump();
     1053
     1054    auto handler = vm.getCTIStub(handleExceptionWithCallFrameRollbackGenerator);
     1055
     1056    LinkBuffer patchBuffer(*this, GLOBAL_THUNK_ID, LinkBuffer::Profile::ExtraCTIThunk);
     1057    patchBuffer.link(operationCall, FunctionPtr<OperationPtrTag>(operationThrowStackOverflowError));
     1058    patchBuffer.link(handleExceptionJump, CodeLocationLabel(handler.retaggedCode<NoPtrTag>()));
     1059    return FINALIZE_CODE(patchBuffer, JITThunkPtrTag, thunkName);
     1060}
     1061
     1062static constexpr bool doesProfiling = true;
     1063static constexpr bool isConstructor = true;
     1064static constexpr bool hasHugeFrame = true;
     1065
     1066#define DEFINE_PROGLOGUE_GENERATOR(doesProfiling, isConstructor, hasHugeFrame, name, arityFixupName) \
     1067    MacroAssemblerCodeRef<JITThunkPtrTag> JIT::name(VM& vm) \
     1068    { \
     1069        JIT jit(vm); \
     1070        return jit.prologueGenerator(vm, doesProfiling, isConstructor, hasHugeFrame, "Baseline: " #name); \
     1071    }
     1072
     1073FOR_EACH_PROLOGUE_GENERATOR(DEFINE_PROGLOGUE_GENERATOR)
     1074#undef DEFINE_PROGLOGUE_GENERATOR
     1075
     1076MacroAssemblerCodeRef<JITThunkPtrTag> JIT::arityFixupPrologueGenerator(VM& vm, bool isConstructor, ThunkGenerator normalPrologueGenerator, const char* thunkName)
     1077{
     1078    // This function generates the Baseline JIT's prologue code. It is not useable by other tiers.
     1079    constexpr GPRReg codeBlockGPR = regT7; // incoming.
     1080    constexpr GPRReg numParametersGPR = regT6;
     1081
     1082    tagReturnAddress();
     1083#if CPU(X86_64)
     1084    push(framePointerRegister);
     1085#elif CPU(ARM64)
     1086    pushPair(framePointerRegister, linkRegister);
     1087#endif
     1088
     1089    storePtr(codeBlockGPR, addressFor(CallFrameSlot::codeBlock));
     1090    store8(TrustedImm32(0), Address(codeBlockGPR, CodeBlock::offsetOfShouldAlwaysBeInlined()));
     1091
     1092    load32(payloadFor(CallFrameSlot::argumentCountIncludingThis), regT1);
     1093    load32(Address(codeBlockGPR, CodeBlock::offsetOfNumParameters()), numParametersGPR);
     1094    Jump noFixupNeeded = branch32(AboveOrEqual, regT1, numParametersGPR);
     1095
     1096    if constexpr (maxFrameExtentForSlowPathCall)
     1097        addPtr(TrustedImm32(-static_cast<int32_t>(maxFrameExtentForSlowPathCall)), stackPointerRegister);
     1098
     1099    loadPtr(Address(codeBlockGPR, CodeBlock::offsetOfGlobalObject()), argumentGPR0);
     1100
     1101    static_assert(std::is_same<decltype(operationConstructArityCheck), decltype(operationCallArityCheck)>::value);
     1102    setupArguments<decltype(operationCallArityCheck)>(argumentGPR0);
     1103    prepareCallOperation(vm);
     1104
     1105    MacroAssembler::Call arityCheckCall = call(OperationPtrTag);
     1106    Jump handleExceptionJump = emitNonPatchableExceptionCheck(vm);
     1107
     1108    if constexpr (maxFrameExtentForSlowPathCall)
     1109        addPtr(TrustedImm32(maxFrameExtentForSlowPathCall), stackPointerRegister);
     1110    Jump needFixup = branchTest32(NonZero, returnValueGPR);
     1111    noFixupNeeded.link(this);
     1112
     1113    // The normal prologue expects incoming codeBlockGPR.
     1114    load64(addressFor(CallFrameSlot::codeBlock), codeBlockGPR);
     1115
     1116#if CPU(X86_64)
     1117    pop(framePointerRegister);
     1118#elif CPU(ARM64)
     1119    popPair(framePointerRegister, linkRegister);
     1120#endif
     1121    untagReturnAddress();
     1122
     1123    JumpList normalPrologueJump;
     1124    normalPrologueJump.append(jump());
     1125
     1126    needFixup.link(this);
     1127
     1128    // Restore the stack for arity fixup, and preserve the return address.
     1129    // arityFixupGenerator will be shifting the stack. So, we can't use the stack to
     1130    // preserve the return address. We also can't use callee saved registers because
     1131    // they haven't been saved yet.
     1132    //
     1133    // arityFixupGenerator is carefully crafted to only use a0, a1, a2, t3, t4 and t5.
     1134    // So, the return address can be preserved in regT7.
     1135#if CPU(X86_64)
     1136    pop(argumentGPR2); // discard.
     1137    pop(regT7); // save return address.
     1138#elif CPU(ARM64)
     1139    popPair(framePointerRegister, linkRegister);
     1140    untagReturnAddress();
     1141    move(linkRegister, regT7);
     1142    auto randomReturnAddressTag = random();
     1143    move(TrustedImm32(randomReturnAddressTag), regT1);
     1144    tagPtr(regT1, regT7);
     1145#endif
     1146    move(returnValueGPR, GPRInfo::argumentGPR0);
     1147    Call arityFixupCall = nearCall();
     1148
     1149#if CPU(X86_64)
     1150    push(regT7); // restore return address.
     1151#elif CPU(ARM64)
     1152    move(TrustedImm32(randomReturnAddressTag), regT1);
     1153    untagPtr(regT1, regT7);
     1154    move(regT7, linkRegister);
     1155#endif
     1156
     1157    load64(addressFor(CallFrameSlot::codeBlock), codeBlockGPR);
     1158    normalPrologueJump.append(jump());
     1159
     1160    auto arityCheckOperation = isConstructor ? operationConstructArityCheck : operationCallArityCheck;
     1161    auto arityFixup = vm.getCTIStub(arityFixupGenerator);
     1162    auto normalPrologue = vm.getCTIStub(normalPrologueGenerator);
     1163    auto exceptionHandler = vm.getCTIStub(popThunkStackPreservesAndHandleExceptionGenerator);
     1164
     1165    LinkBuffer patchBuffer(*this, GLOBAL_THUNK_ID, LinkBuffer::Profile::ExtraCTIThunk);
     1166    patchBuffer.link(arityCheckCall, FunctionPtr<OperationPtrTag>(arityCheckOperation));
     1167    patchBuffer.link(arityFixupCall, FunctionPtr(arityFixup.retaggedCode<NoPtrTag>()));
     1168    patchBuffer.link(normalPrologueJump, CodeLocationLabel(normalPrologue.retaggedCode<NoPtrTag>()));
     1169    patchBuffer.link(handleExceptionJump, CodeLocationLabel(exceptionHandler.retaggedCode<NoPtrTag>()));
     1170    return FINALIZE_CODE(patchBuffer, JITThunkPtrTag, thunkName);
     1171}
     1172
     1173#define DEFINE_ARITY_PROGLOGUE_GENERATOR(doesProfiling, isConstructor, hasHugeFrame, name, arityFixupName) \
     1174MacroAssemblerCodeRef<JITThunkPtrTag> JIT::arityFixupName(VM& vm) \
     1175    { \
     1176        JIT jit(vm); \
     1177        return jit.arityFixupPrologueGenerator(vm, isConstructor, name, "Baseline: " #arityFixupName); \
     1178    }
     1179
     1180FOR_EACH_PROLOGUE_GENERATOR(DEFINE_ARITY_PROGLOGUE_GENERATOR)
     1181#undef DEFINE_ARITY_PROGLOGUE_GENERATOR
     1182
     1183#endif // ENABLE(EXTRA_CTI_THUNKS)
    8531184
    8541185void JIT::link()
     
    10471378}
    10481379
     1380#if !ENABLE(EXTRA_CTI_THUNKS)
    10491381void JIT::privateCompileExceptionHandlers()
    10501382{
    1051 #if !ENABLE(EXTRA_CTI_THUNKS)
    10521383    if (!m_exceptionChecksWithCallFrameRollback.empty()) {
    10531384        m_exceptionChecksWithCallFrameRollback.link(this);
     
    10741405        jumpToExceptionHandler(vm());
    10751406    }
    1076 #endif // ENABLE(EXTRA_CTI_THUNKS)
    1077 }
     1407}
     1408#endif // !ENABLE(EXTRA_CTI_THUNKS)
    10781409
    10791410void JIT::doMainThreadPreparationBeforeCompile()
Note: See TracChangeset for help on using the changeset viewer.