| Differences between
and this patch
- Source/JavaScriptCore/b3/B3ValueRep.cpp +45 lines
Lines 28-33 Source/JavaScriptCore/b3/B3ValueRep.cpp_sec1
28
28
29
#if ENABLE(B3_JIT)
29
#if ENABLE(B3_JIT)
30
30
31
#include "AssemblyHelpers.h"
32
31
namespace JSC { namespace B3 {
33
namespace JSC { namespace B3 {
32
34
33
void ValueRep::dump(PrintStream& out) const
35
void ValueRep::dump(PrintStream& out) const
Lines 55-60 void ValueRep::dump(PrintStream& out) co Source/JavaScriptCore/b3/B3ValueRep.cpp_sec2
55
    RELEASE_ASSERT_NOT_REACHED();
57
    RELEASE_ASSERT_NOT_REACHED();
56
}
58
}
57
59
60
void ValueRep::emitRestore(AssemblyHelpers& jit, Reg reg)
61
{
62
    if (reg.isGPR()) {
63
        switch (kind()) {
64
        case Register:
65
            if (isGPR())
66
                jit.move(gpr(), reg.gpr());
67
            else
68
                jit.moveDoubleTo64(fpr(), reg.gpr());
69
            break;
70
        case Stack:
71
            jit.load64(AssemblyHelpers::Address(GPRInfo::callFrameRegister, offsetFromFP()), reg.gpr());
72
            break;
73
        case Constant:
74
            jit.move(TrustedImm64(value()), reg.gpr());
75
            break;
76
        default:
77
            RELEASE_ASSERT_NOT_REACHED();
78
            break;
79
        }
80
        return;
81
    }
82
    
83
    switch (kind()) {
84
    case Register:
85
        if (isGPR())
86
            jit.move64ToDouble(gpr(), reg.fpr());
87
        else
88
            jit.moveDouble(fpr(), reg.fpr());
89
        break;
90
    case Stack:
91
        jit.loadDouble(AssemblyHelpers::Address(GPRInfo::callFrameRegister, offsetFromFP()), reg.fpr());
92
        break;
93
    case Constant:
94
        jit.move(TrustedImm64(value()), jit.scratchRegister());
95
        jit.move64ToDouble(jit.scratchRegister(), reg.fpr());
96
        break;
97
    default:
98
        RELEASE_ASSERT_NOT_REACHED();
99
        break;
100
    }
101
}
102
58
} } // namespace JSC::B3
103
} } // namespace JSC::B3
59
104
60
namespace WTF {
105
namespace WTF {
- Source/JavaScriptCore/b3/B3ValueRep.h -1 / +9 lines
Lines 34-40 Source/JavaScriptCore/b3/B3ValueRep.h_sec1
34
#include "Reg.h"
34
#include "Reg.h"
35
#include <wtf/PrintStream.h>
35
#include <wtf/PrintStream.h>
36
36
37
namespace JSC { namespace B3 {
37
namespace JSC {
38
39
class AssemblyHelpers;
40
41
namespace B3 {
38
42
39
// We use this class to describe value representations at stackmaps. It's used both to force a
43
// We use this class to describe value representations at stackmaps. It's used both to force a
40
// representation and to get the representation. When the B3 client forces a representation, we say
44
// representation and to get the representation. When the B3 client forces a representation, we say
Lines 216-221 public: Source/JavaScriptCore/b3/B3ValueRep.h_sec2
216
220
217
    JS_EXPORT_PRIVATE void dump(PrintStream&) const;
221
    JS_EXPORT_PRIVATE void dump(PrintStream&) const;
218
222
223
    // This has a simple contract: it emits code to restore the value into the given register. This
224
    // will work even if it requires moving between bits a GPR and a FPR.
225
    void emitRestore(AssemblyHelpers&, Reg);
226
219
private:
227
private:
220
    Kind m_kind;
228
    Kind m_kind;
221
    union U {
229
    union U {
- Source/JavaScriptCore/dfg/DFGCommon.h -1 / +1 lines
Lines 38-44 namespace JSC { namespace DFG { Source/JavaScriptCore/dfg/DFGCommon.h_sec1
38
// We are in the middle of an experimental transition from LLVM to B3 as the backend for the FTL. We don't
38
// We are in the middle of an experimental transition from LLVM to B3 as the backend for the FTL. We don't
39
// yet know how it will turn out. For now, this flag will control whether FTL uses B3. Remember to set this
39
// yet know how it will turn out. For now, this flag will control whether FTL uses B3. Remember to set this
40
// to 0 before committing!
40
// to 0 before committing!
41
#define FTL_USES_B3 0
41
#define FTL_USES_B3 1
42
42
43
struct Node;
43
struct Node;
44
44
- Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp -17 / +200 lines
Lines 205-212 public: Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec1
205
#endif // FTL_USE_B3
205
#endif // FTL_USE_B3
206
206
207
        auto preOrder = m_graph.blocksInPreOrder();
207
        auto preOrder = m_graph.blocksInPreOrder();
208
        
208
209
        // If we have any CallVarargs then we need to have a spill slot for it.
209
#if !FTL_USES_B3
210
        bool hasVarargs = false;
210
        bool hasVarargs = false;
211
        size_t maxNumberOfCatchSpills = 0;
211
        size_t maxNumberOfCatchSpills = 0;
212
        for (DFG::BasicBlock* block : preOrder) {
212
        for (DFG::BasicBlock* block : preOrder) {
Lines 270-279 public: Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec2
270
            }
270
            }
271
        }
271
        }
272
272
273
#if FTL_USES_B3
273
        // B3 doesn't need the varargs spill slot because we just use call arg area size as a way to
274
        UNUSED_PARAM(hasVarargs);
274
        // request spill slots.
275
        // FIXME
276
#else
277
        if (hasVarargs) {
275
        if (hasVarargs) {
278
            LValue varargsSpillSlots = m_out.alloca(
276
            LValue varargsSpillSlots = m_out.alloca(
279
                arrayType(m_out.int64, JSCallVarargs::numSpillSlotsNeeded()));
277
                arrayType(m_out.int64, JSCallVarargs::numSpillSlotsNeeded()));
Lines 284-289 public: Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec3
284
                m_out.int32Zero, varargsSpillSlots);
282
                m_out.int32Zero, varargsSpillSlots);
285
        }
283
        }
286
284
285
        // B3 doesn't need the exception spill slot because we just use the 
287
        if (m_graph.m_hasExceptionHandlers && maxNumberOfCatchSpills) {
286
        if (m_graph.m_hasExceptionHandlers && maxNumberOfCatchSpills) {
288
            RegisterSet volatileRegisters = RegisterSet::volatileRegistersForJSCall();
287
            RegisterSet volatileRegisters = RegisterSet::volatileRegistersForJSCall();
289
            maxNumberOfCatchSpills = std::min(volatileRegisters.numberOfSetRegisters(), maxNumberOfCatchSpills);
288
            maxNumberOfCatchSpills = std::min(volatileRegisters.numberOfSetRegisters(), maxNumberOfCatchSpills);
Lines 296-302 public: Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec4
296
                m_out.constInt64(m_ftlState.exceptionHandlingSpillSlotStackmapID),
295
                m_out.constInt64(m_ftlState.exceptionHandlingSpillSlotStackmapID),
297
                m_out.int32Zero, exceptionHandlingVolatileRegistersSpillSlots);
296
                m_out.int32Zero, exceptionHandlingVolatileRegistersSpillSlots);
298
        }
297
        }
299
#endif
298
#endif // !FTL_USES_B3
300
        
299
        
301
        // We should not create any alloca's after this point, since they will cease to
300
        // We should not create any alloca's after this point, since they will cease to
302
        // be mem2reg candidates.
301
        // be mem2reg candidates.
Lines 5069-5100 private: Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec5
5069
    
5068
    
5070
    void compileCallOrConstructVarargs()
5069
    void compileCallOrConstructVarargs()
5071
    {
5070
    {
5072
#if FTL_USES_B3
5071
        Node* node = m_node;
5073
        if (verboseCompilationEnabled() || !verboseCompilationEnabled())
5074
            CRASH();
5075
#else
5076
        LValue jsCallee = lowJSValue(m_node->child1());
5072
        LValue jsCallee = lowJSValue(m_node->child1());
5077
        LValue thisArg = lowJSValue(m_node->child3());
5073
        LValue thisArg = lowJSValue(m_node->child3());
5078
        
5074
        
5079
        LValue jsArguments = nullptr;
5075
        LValue jsArguments = nullptr;
5076
        bool forwarding = false;
5080
        
5077
        
5081
        switch (m_node->op()) {
5078
        switch (node->op()) {
5082
        case CallVarargs:
5079
        case CallVarargs:
5083
        case TailCallVarargs:
5080
        case TailCallVarargs:
5084
        case TailCallVarargsInlinedCaller:
5081
        case TailCallVarargsInlinedCaller:
5085
        case ConstructVarargs:
5082
        case ConstructVarargs:
5086
            jsArguments = lowJSValue(m_node->child2());
5083
            jsArguments = lowJSValue(node->child2());
5087
            break;
5084
            break;
5088
        case CallForwardVarargs:
5085
        case CallForwardVarargs:
5089
        case TailCallForwardVarargs:
5086
        case TailCallForwardVarargs:
5090
        case TailCallForwardVarargsInlinedCaller:
5087
        case TailCallForwardVarargsInlinedCaller:
5091
        case ConstructForwardVarargs:
5088
        case ConstructForwardVarargs:
5089
            forwarding = true;
5092
            break;
5090
            break;
5093
        default:
5091
        default:
5094
            DFG_CRASH(m_graph, m_node, "bad node type");
5092
            DFG_CRASH(m_graph, node, "bad node type");
5095
            break;
5093
            break;
5096
        }
5094
        }
5097
        
5095
        
5096
#if FTL_USES_B3
5097
        // FIXME: Need a story for exceptions.
5098
        // https://bugs.webkit.org/show_bug.cgi?id=151686
5099
5100
        PatckpointValue* patchpoint = m_out.patchpoint(Int64);
5101
5102
        // Append the forms of the arguments that we will use before any clobbering happens.
5103
        patchpoint->append(jsCallee, ValueRep::SomeRegister);
5104
        if (jsArguments)
5105
            patchpoint->append(jsArguments, ValueRep::SomeRegister);
5106
        patchpoint->append(thisArg, ValueRep::SomeRegister);
5107
5108
        if (!forwarding) {
5109
            // Now append them again for after clobbering. Note that the compiler may ask us to use a
5110
            // different register for the late for the post-clobbering version of the value. This gives
5111
            // the compiler to spill these values without having to burn any callee-saves.
5112
            patchpoint->append(jsCallee, ValueRep::LateColdAny);
5113
            patchpoint->append(jsArguments, ValueRep::LateColdAny);
5114
            patchpoint->append(thisArg, ValueRep::LateColdAny);
5115
        }
5116
5117
        patchpoint->clobber(RegisterSet::macroScratchRegisters());
5118
        parchpoint->clobberLate(RegisterSet::volatileRegistersForJSCall());
5119
        patchpoint->resultConstraint = ValueRep::reg(GPRInfo::returnValueGPR);
5120
5121
        // This is the minimum amount of call arg area stack space that all JS->JS calls always have.
5122
        unsigned minimumJSCallAreaSize =
5123
            sizeof(CallerFrameAndPC) +
5124
            WTF::roundUpToMultipleOf(stackAlignmentBytes(), 5 * sizeof(EncodedJSValue));
5125
5126
        m_proc.requestCallArgAreaSize(minimumJSCallAreaSize);
5127
        
5128
        CodeOrigin codeOrigin = codeOriginDescriptionOfCallSite();
5129
        State* state = &m_ftlState;
5130
        patchpoint->setGenerator(
5131
            [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
5132
                AllowMacroScratchRegisterUsage allowScratch(jit);
5133
                CallSiteIndex callSiteIndex =
5134
                    state->jitCode->common.addUniqueCallSiteIndex(codeOrigin);
5135
5136
                // FIXME: We would ask the OSR exit descriptor to prepare and then we would modify
5137
                // the OSRExit data structure inside the OSRExitHandle to link it up to this call.
5138
                // Also, the exception checks JumpList should be linked to somewhere.
5139
                // https://bugs.webkit.org/show_bug.cgi?id=151686
5140
                CCallHelpers::JumpList exceptions;
5141
5142
                jit.store32(
5143
                    CCallHelpers::TrustedImm32(callSiteIndex.bits()),
5144
                    CCallHelpers::tagFor(VirtualRegister(JSStack::ArgumentCount)));
5145
5146
                CallLinkInfo* callLinkInfo = jit.codeBlock()->addCallLinkInfo();
5147
                CallVarargsData* data = node->callVarargsData();
5148
5149
                unsigned argIndex = 1;
5150
                GPRReg calleeGPR = params[argIndex++].gpr();
5151
                GPRReg argumentsGPR = jsArguments ? params[argIndex++].gpr() : InvalidGPRReg;
5152
                GPRReg thisGPR = params[argIndex++].gpr();
5153
5154
                B3::ValueRep calleeLateRep;
5155
                B3::ValueRep argumentsLateRep;
5156
                B3::ValueRep thisLateRep;
5157
                if (!forwarding) {
5158
                    calleeLateRep = params[argIndex++];
5159
                    argumentsLateRep = params[argIndex++];
5160
                    thisLateRep = params[argIndex++];
5161
                }
5162
5163
                // Get some scratch registers.
5164
                RegisterSet usedRegisters;
5165
                usedRegisters.merge(RegisterSet::stackRegisters());
5166
                usedRegisters.merge(RegisterSet::reservedHardwareRegisters());
5167
                usedRegisters.merge(RegisterSet::calleeSaveRegisters());
5168
                usedRegisters.set(calleeGPR);
5169
                if (argumentsGPR != InvalidGPRReg)
5170
                    usedRegisters.set(argumentsGPR);
5171
                usedRegisters.set(thisGPR);
5172
                if (calleeLateRep.isReg())
5173
                    usedRegisters.set(calleeLateRep.reg());
5174
                if (argumentsLateRep.isReg())
5175
                    usedRegisters.set(argumentsLateRep.reg());
5176
                if (thisLateRep.isReg())
5177
                    usedRegisters.set(thisLateRep.reg());
5178
                ScratchRegisterAllocator allocator(usedRegisters);
5179
                GPRReg scratchGPR1 = allocator.allocateScratchGPR();
5180
                GPRReg scratchGPR2 = allocator.allocateScratchGPR();
5181
                GPRReg scratchGPR3 = forwarding ? allocator.allocateScratchGPR() : InvalidGPRReg;
5182
                RELEASE_ASSERT(!allocator.numberOfReusedRegisters());
5183
5184
                auto callWithExceptionCheck = [&] (void* callee) {
5185
                    jit.move(CCallHelpers::TrustedImmPtr(callee), GPRInfo::nonPreservedNonArgumentGPR);
5186
                    jit.call(GPRInfo::nonPreservedNonArgumentGPR);
5187
                    exceptions.append(jit.emitExceptionCheck(AssemblyHelpers::NormalExceptionCheck, AssemblyHelpers::FarJumpWidth));
5188
                };
5189
5190
                auto adjustStack = [&] (GPRReg amount) {
5191
                    jit.addPtr(CCallHelpers::TrustedImm32(sizeof(CallerFrameAndPC)), amount, CCallHelpers::stackPointerRegister);
5192
                };
5193
5194
                unsigned originalStackHeight = params.proc().frameSize();
5195
5196
                if (forwarding) {
5197
                    jit.move(TrustedImm32(originalStackHeight / sizeof(EncodedJSValue)), scratchGPR2);
5198
                    
5199
                    CCallHelpers::JumpList slowCase;
5200
                    emitSetupVarargsFrameFastCase(jit, scratchGPR2, scratchGPR1, scratchGPR2, scratchGPR3, node->child2()->origin.semantic.inlineCallFrame, data->firstVarArgOffset, slowCase);
5201
5202
                    CCallHelpers::Jump done = jit.jump();
5203
                    slowCase.link(&jit);
5204
                    jit.setupArgumentsExecState();
5205
                    callWithExceptionCheck(bitwise_cast<void*>(operationThrowStackOverflowForVarargs));
5206
                    jit.abortWithReason(DFGVarargsThrowingPathDidNotThrow);
5207
                    
5208
                    done.link(&jit);
5209
5210
                    adjustStack(scratchGPR2);
5211
                    jit.move(calleeGPR, GPRInfo::regT0);
5212
                } else {
5213
                    jit.move(TrustedImm32(originalStackHeight / sizeof(EncodedJSValue)), scratchGPR1);
5214
                    jit.setupArgumentsWithExecState(argumentsGPR, scratchGPR1, CCallHelpers::TrustedImm32(data->firstVarArgOffset));
5215
                    callWithExceptionCheck(bitwise_cast<void*>(operationSizeFrameForVarargs));
5216
5217
                    jit.move(GPRInfo::returnValueGPR, scratchGPR1);
5218
                    jit.move(CCallHelpers::TrustedImm32(originalStackHeight / sizeof(EncodedJSValue)), scratchGPR2);
5219
                    argumentsLateRep.emitRestore(jit, argumentsGPR);
5220
                    emitSetVarargsFrame(jit, scratchGPR1, false, scratchGPR2, scratchGPR2);
5221
                    jit.addPtr(CCallHelpers::TrustedImm32(-minimumJSCallAreaSize), scratchGPR2, CCallHelpers::stackPointerRegister);
5222
                    jit.setupArgumentsWithExecState(scratchGPR2, argumentsGPR, CCallHelpers::TrustedImm32(data->firstVarArgOffset), scratchGPR1);
5223
                    callWithExceptionCheck(bitwise_cast<void*>(operationSetupVarargsFrame));
5224
                    
5225
                    adjustStack(GPRInfo::returnValueGPR);
5226
5227
                    // Now we need to dump thisLateRep into the stack and we need to put the callee
5228
                    // into regT0. Note that neither of the LateRep's can use volatile registers, so
5229
                    // taking care of callee first is wise.
5230
                    calleeLateRep.emitRestore(jit, GPRInfo::regT0);
5231
                    
5232
                    thisLateRep.emitRestore(jit, thisGPR); // This may not emit code if thisGPR got a callee-save.
5233
                    jit.store64(GPRInfo::regT0, CCallHelpers::calleeFrameSlot(JSStack::Callee));
5234
                    jit.store64(thisGPR, CCallHelpers::calleeArgumentSlot(0));
5235
5236
                    CallLinkInfo* callLinkInfo = jit.codeBlock()->addCallLinkInfo();
5237
5238
                    CCallHelpers::DateLabelPtr targetToCheck;
5239
                    CCallHelpers::Jump slowPath = jit.branchPtrWithPatch(
5240
                        CCallHelpers::NotEqual, GPRInfo::regT0, targetToCheck,
5241
                        CCallHelpers::TrustedImmPtr(0));
5242
5243
                    CCallHelpers::Jump fastCall = jit.nearCall();
5244
                    CCallHelpers::Jump done = jit.jump();
5245
5246
                    slowPath.link(&jit);
5247
5248
                    jit.move(CCallHelpers::TrustedImmPtr(callLinkInfo, GPRInfo::regT2));
5249
                    CCallHelpers::Call slowCall = jit.nearCall();
5250
                    done.link(&jit);
5251
5252
                    CallLinkInfo::CallType callType;
5253
                    if (node->op() == ConstructVarargs || node->op() == ConstructForwardVarargs)
5254
                        callType = CallLinkInfo::ConstructVarargs;
5255
                    else if (node->op() == TailCallVarargs || node->op() == TailCallForwardVarargs)
5256
                        callType = CallLinkInfo::TailCallVarargs;
5257
                    else
5258
                        callType = CallLinkInfo::CallVarargs;
5259
                    callLinkInfo->setUpCall(callType, node->origin.semantic, GPRInfo::regT0);
5260
5261
                    jit.addPtr(
5262
                        CCallHelpers::TrustedImm32(-originalStackHeight),
5263
                        GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister);
5264
5265
                    jit.addLinkTask(
5266
                        [=] (LinkBuffer& linkBuffer) {
5267
                            MacroAssemblerCodePtr linkCall =
5268
                                linkBuffer.vm().getCTIStub(linkCallThunkGenerator).code();
5269
                            linkBuffer.link(slowCall, FunctionPtr(linkCall.executableAddress()));
5270
5271
                            callLinkInfo->setCallLocations(
5272
                                linkBuffer.locationOfNearCall(slowCall),
5273
                                linkBuffer.locationOf(targetToCheck),
5274
                                linkBuffer.locationOfNearCall(fastCall));
5275
                        });
5276
                }
5277
            });
5278
5279
        setJSValue(patchpoint);
5280
#else
5098
        unsigned stackmapID = m_stackmapIDs++;
5281
        unsigned stackmapID = m_stackmapIDs++;
5099
        
5282
        
5100
        StackmapArgumentList arguments;
5283
        StackmapArgumentList arguments;
Lines 5108-5122 private: Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec6
5108
5291
5109
        arguments.insert(0, m_out.constInt32(2 + !!jsArguments));
5292
        arguments.insert(0, m_out.constInt32(2 + !!jsArguments));
5110
        arguments.insert(0, constNull(m_out.ref8));
5293
        arguments.insert(0, constNull(m_out.ref8));
5111
        arguments.insert(0, m_out.constInt32(sizeOfICFor(m_node)));
5294
        arguments.insert(0, m_out.constInt32(sizeOfICFor(node)));
5112
        arguments.insert(0, m_out.constInt64(stackmapID));
5295
        arguments.insert(0, m_out.constInt64(stackmapID));
5113
        
5296
        
5114
        LValue call = m_out.call(m_out.int64, m_out.patchpointInt64Intrinsic(), arguments);
5297
        LValue call = m_out.call(m_out.int64, m_out.patchpointInt64Intrinsic(), arguments);
5115
        setInstructionCallingConvention(call, LLVMCCallConv);
5298
        setInstructionCallingConvention(call, LLVMCCallConv);
5116
        
5299
        
5117
        m_ftlState.jsCallVarargses.append(JSCallVarargs(stackmapID, m_node, codeOriginDescriptionOfCallSite()));
5300
        m_ftlState.jsCallVarargses.append(JSCallVarargs(stackmapID, node, codeOriginDescriptionOfCallSite()));
5118
5301
5119
        switch (m_node->op()) {
5302
        switch (node->op()) {
5120
        case TailCallVarargs:
5303
        case TailCallVarargs:
5121
        case TailCallForwardVarargs:
5304
        case TailCallForwardVarargs:
5122
            m_out.unreachable();
5305
            m_out.unreachable();

Return to Bug 152468