| Differences between
and this patch
- a/Source/JavaScriptCore/ChangeLog +199 lines
Lines 1-5 a/Source/JavaScriptCore/ChangeLog_sec1
1
2015-08-21  Basile Clement  <basile_clement@apple.com>
1
2015-08-21  Basile Clement  <basile_clement@apple.com>
2
2
3
        jsc-tailcall: We should reuse the frame efficiently in the DFG instead of doing a memmove
4
        https://bugs.webkit.org/show_bug.cgi?id=147508
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        This introduces a new class (CallFrameShuffler) whose responsibility is
9
        to build a call frame for a tail call over the previously existing
10
        frame by taking into account that the slots we are writing to could
11
        still hold values we will need later. 
12
13
        The rest of the patch is mostly small refactorings to make the job of
14
        this class easier.
15
16
        * CMakeLists.txt:
17
        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
18
        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
19
        * JavaScriptCore.xcodeproj/project.pbxproj:
20
        * assembler/ARM64Assembler.h:
21
        (JSC::ARM64Registers::isSp):
22
        (JSC::ARM64Registers::isZr):
23
        (JSC::ARM64Assembler::firstRegister):
24
        (JSC::ARM64Assembler::lastRegister):
25
        (JSC::ARM64Assembler::firstFPRegister):
26
        (JSC::ARM64Assembler::lastFPRegister):
27
        (JSC::ARM64Assembler::isSp):
28
        (JSC::ARM64Assembler::isZr):
29
        * assembler/ARMAssembler.h:
30
        (JSC::ARMAssembler::firstRegister):
31
        (JSC::ARMAssembler::lastRegister):
32
        (JSC::ARMAssembler::firstFPRegister):
33
        (JSC::ARMAssembler::lastFPRegister):
34
        * assembler/AbortReason.h:
35
        * assembler/AbstractMacroAssembler.h:
36
        (JSC::AbstractMacroAssembler::firstRegister):
37
        (JSC::AbstractMacroAssembler::lastRegister):
38
        (JSC::AbstractMacroAssembler::firstFPRegister):
39
        (JSC::AbstractMacroAssembler::lastFPRegister):
40
        * assembler/MIPSAssembler.h:
41
        (JSC::MIPSAssembler::firstRegister):
42
        (JSC::MIPSAssembler::lastRegister):
43
        (JSC::MIPSAssembler::firstFPRegister):
44
        (JSC::MIPSAssembler::lastFPRegister):
45
        * assembler/MacroAssembler.h:
46
        (JSC::MacroAssembler::nextRegister):
47
        (JSC::MacroAssembler::nextFPRegister):
48
        (JSC::MacroAssembler::numberOfRegisters):
49
        (JSC::MacroAssembler::registerIndex):
50
        (JSC::MacroAssembler::numberOfFPRegisters):
51
        (JSC::MacroAssembler::fpRegisterIndex):
52
        (JSC::MacroAssembler::totalNumberOfRegisters):
53
        * assembler/SH4Assembler.h:
54
        (JSC::SH4Assembler::firstRegister):
55
        (JSC::SH4Assembler::lastRegister):
56
        (JSC::SH4Assembler::firstFPRegister):
57
        (JSC::SH4Assembler::lastFPRegister):
58
        * assembler/X86Assembler.h:
59
        (JSC::X86Assembler::firstRegister):
60
        (JSC::X86Assembler::lastRegister):
61
        (JSC::X86Assembler::firstFPRegister):
62
        (JSC::X86Assembler::lastFPRegister):
63
        * bytecode/CallLinkInfo.h:
64
        (JSC::CallLinkInfo::setFrameShuffleData):
65
        (JSC::CallLinkInfo::frameShuffleData):
66
        * bytecode/ValueRecovery.cpp:
67
        (JSC::ValueRecovery::dumpInContext):
68
        * bytecode/ValueRecovery.h:
69
        (JSC::ValueRecovery::operator bool):
70
        (JSC::ValueRecovery::inFPR):
71
        (JSC::ValueRecovery::isInGPR):
72
        (JSC::ValueRecovery::isInFPR):
73
        (JSC::ValueRecovery::isInRegisters):
74
        (JSC::ValueRecovery::isInJSStack):
75
        (JSC::ValueRecovery::dataFormat):
76
        (JSC::ValueRecovery::gpr):
77
        (JSC::ValueRecovery::isInJSValueRegs):
78
        (JSC::ValueRecovery::jsValueRegs):
79
        (JSC::ValueRecovery::fpr):
80
        (JSC::ValueRecovery::virtualRegister):
81
        (JSC::ValueRecovery::constant):
82
        * dfg/DFGByteCodeParser.cpp:
83
        (JSC::DFG::ByteCodeParser::parseBlock):
84
        * dfg/DFGGenerationInfo.h:
85
        (JSC::DFG::GenerationInfo::recovery):
86
        * dfg/DFGOSRExitCompiler32_64.cpp:
87
        (JSC::DFG::OSRExitCompiler::compileExit):
88
        * dfg/DFGOSRExitCompiler64.cpp:
89
        (JSC::DFG::OSRExitCompiler::compileExit):
90
        * dfg/DFGSpeculativeJIT32_64.cpp:
91
        (JSC::DFG::SpeculativeJIT::emitCall):
92
        * dfg/DFGSpeculativeJIT64.cpp:
93
        (JSC::DFG::SpeculativeJIT::emitCall):
94
        * dfg/DFGVariableEventStream.cpp:
95
        (JSC::DFG::VariableEventStream::reconstruct):
96
        * jit/CallFrameShuffleData.cpp: Added.
97
        (JSC::CallFrameShuffleData::setupCalleeSaveRegisters):
98
        * jit/CallFrameShuffleData.h: Added.
99
        * jit/CallFrameShuffler.cpp: Added.
100
        (JSC::CallFrameShuffler::CallFrameShuffler):
101
        (JSC::CallFrameShuffler::dump):
102
        (JSC::CallFrameShuffler::getCachedRecovery):
103
        (JSC::CallFrameShuffler::setCachedRecovery):
104
        (JSC::CallFrameShuffler::spill):
105
        (JSC::CallFrameShuffler::emitDeltaCheck):
106
        (JSC::CallFrameShuffler::prepareForSlowPath):
107
        (JSC::CallFrameShuffler::prepareForTailCall):
108
        (JSC::CallFrameShuffler::tryWrites):
109
        (JSC::CallFrameShuffler::performSafeWrites):
110
        (JSC::CallFrameShuffler::prepareAny):
111
        * jit/CallFrameShuffler.h: Added.
112
        (JSC::CachedRecovery::CachedRecovery):
113
        (JSC::CachedRecovery::targets):
114
        (JSC::CachedRecovery::addTarget):
115
        (JSC::CachedRecovery::removeTarget):
116
        (JSC::CachedRecovery::clearTargets):
117
        (JSC::CachedRecovery::setWantedJSValueRegs):
118
        (JSC::CachedRecovery::boxingRequiresGPR):
119
        (JSC::CachedRecovery::boxingRequiresFPR):
120
        (JSC::CachedRecovery::recovery):
121
        (JSC::CachedRecovery::setRecovery):
122
        (JSC::CachedRecovery::wantedJSValueRegs):
123
        (JSC::CallFrameShuffler::lockGPR):
124
        (JSC::CallFrameShuffler::acquireGPR):
125
        (JSC::CallFrameShuffler::releaseGPR):
126
        (JSC::CallFrameShuffler::snapshot):
127
        (JSC::CallFrameShuffler::setCalleeJSValueRegs):
128
        (JSC::CallFrameShuffler::assumeCalleeIsCell):
129
        (JSC::CallFrameShuffler::canBox):
130
        (JSC::CallFrameShuffler::ensureBox):
131
        (JSC::CallFrameShuffler::ensureLoad):
132
        (JSC::CallFrameShuffler::canLoadAndBox):
133
        (JSC::CallFrameShuffler::updateRecovery):
134
        (JSC::CallFrameShuffler::clearCachedRecovery):
135
        (JSC::CallFrameShuffler::addCachedRecovery):
136
        (JSC::CallFrameShuffler::numLocals):
137
        (JSC::CallFrameShuffler::getOld):
138
        (JSC::CallFrameShuffler::setOld):
139
        (JSC::CallFrameShuffler::firstOld):
140
        (JSC::CallFrameShuffler::lastOld):
141
        (JSC::CallFrameShuffler::isValidOld):
142
        (JSC::CallFrameShuffler::argCount):
143
        (JSC::CallFrameShuffler::getNew):
144
        (JSC::CallFrameShuffler::setNew):
145
        (JSC::CallFrameShuffler::addNew):
146
        (JSC::CallFrameShuffler::firstNew):
147
        (JSC::CallFrameShuffler::lastNew):
148
        (JSC::CallFrameShuffler::isValidNew):
149
        (JSC::CallFrameShuffler::newAsOld):
150
        (JSC::CallFrameShuffler::getFreeRegister):
151
        (JSC::CallFrameShuffler::getFreeGPR):
152
        (JSC::CallFrameShuffler::getFreeFPR):
153
        (JSC::CallFrameShuffler::hasFreeRegister):
154
        (JSC::CallFrameShuffler::ensureRegister):
155
        (JSC::CallFrameShuffler::ensureGPR):
156
        (JSC::CallFrameShuffler::ensureFPR):
157
        (JSC::CallFrameShuffler::addressForOld):
158
        (JSC::CallFrameShuffler::isUndecided):
159
        (JSC::CallFrameShuffler::isSlowPath):
160
        (JSC::CallFrameShuffler::addressForNew):
161
        (JSC::CallFrameShuffler::dangerFrontier):
162
        (JSC::CallFrameShuffler::isDangerNew):
163
        (JSC::CallFrameShuffler::updateDangerFrontier):
164
        (JSC::CallFrameShuffler::hasOnlySafeWrites):
165
        * jit/CallFrameShuffler32_64.cpp: Added.
166
        (JSC::CallFrameShuffler::emitStore):
167
        (JSC::CallFrameShuffler::emitBox):
168
        (JSC::CallFrameShuffler::emitLoad):
169
        (JSC::CallFrameShuffler::canLoad):
170
        (JSC::CachedRecovery::loadsIntoFPR):
171
        (JSC::CachedRecovery::loadsIntoGPR):
172
        (JSC::CallFrameShuffler::emitDisplace):
173
        * jit/CallFrameShuffler64.cpp: Added.
174
        (JSC::CallFrameShuffler::emitStore):
175
        (JSC::CallFrameShuffler::emitBox):
176
        (JSC::CallFrameShuffler::emitLoad):
177
        (JSC::CallFrameShuffler::canLoad):
178
        (JSC::CachedRecovery::loadsIntoFPR):
179
        (JSC::CachedRecovery::loadsIntoGPR):
180
        (JSC::CallFrameShuffler::emitDisplace):
181
        * jit/GPRInfo.h:
182
        (JSC::JSValueRegs::operator bool):
183
        (JSC::JSValueRegs::operator==):
184
        (JSC::JSValueRegs::operator!=):
185
        (JSC::JSValueSource::operator bool):
186
        (JSC::JSValueRegs::operator!):
187
        (JSC::JSValueSource::operator!):
188
        * jit/JITCall.cpp:
189
        (JSC::JIT::compileOpCall):
190
        (JSC::JIT::compileOpCallSlowCase):
191
        * jit/Reg.h:
192
        (JSC::Reg::operator bool):
193
        * jit/RegisterMap.h: Added.
194
        (JSC::RegisterMap::operator[]):
195
        (JSC::GPRMap::operator[]):
196
        (JSC::FPRMap::operator[]):
197
        * jit/Repatch.cpp:
198
        (JSC::linkPolymorphicCall):
199
200
2015-08-21  Basile Clement  <basile_clement@apple.com>
201
3
        Unreviewed, fixes the build.
202
        Unreviewed, fixes the build.
4
        https://bugs.webkit.org/show_bug.cgi?id=148316
203
        https://bugs.webkit.org/show_bug.cgi?id=148316
5
204
- a/Source/JavaScriptCore/CMakeLists.txt +4 lines
Lines 343-348 set(JavaScriptCore_SOURCES a/Source/JavaScriptCore/CMakeLists.txt_sec1
343
    jit/AccessorCallJITStubRoutine.cpp
343
    jit/AccessorCallJITStubRoutine.cpp
344
    jit/AssemblyHelpers.cpp
344
    jit/AssemblyHelpers.cpp
345
    jit/BinarySwitch.cpp
345
    jit/BinarySwitch.cpp
346
    jit/CallFrameShuffleData.cpp
347
    jit/CallFrameShuffler.cpp
348
    jit/CallFrameShuffler32_64.cpp
349
    jit/CallFrameShuffler64.cpp
346
    jit/ExecutableAllocationFuzz.cpp
350
    jit/ExecutableAllocationFuzz.cpp
347
    jit/ExecutableAllocator.cpp
351
    jit/ExecutableAllocator.cpp
348
    jit/ExecutableAllocatorFixedVMPool.cpp
352
    jit/ExecutableAllocatorFixedVMPool.cpp
- a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj +7 lines
Lines 606-611 a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj_sec1
606
    <ClCompile Include="..\jit\AccessorCallJITStubRoutine.cpp" />
606
    <ClCompile Include="..\jit\AccessorCallJITStubRoutine.cpp" />
607
    <ClCompile Include="..\jit\AssemblyHelpers.cpp" />
607
    <ClCompile Include="..\jit\AssemblyHelpers.cpp" />
608
    <ClCompile Include="..\jit\BinarySwitch.cpp" />
608
    <ClCompile Include="..\jit\BinarySwitch.cpp" />
609
    <ClCompile Include="..\jit\CallFrameShuffleData.cpp" />
610
    <ClCompile Include="..\jit\CallFrameShuffler.cpp" />
611
    <ClCompile Include="..\jit\CallFrameShuffler32_64.cpp" />
612
    <ClCompile Include="..\jit\CallFrameShuffler64.cpp" />
609
    <ClCompile Include="..\jit\ExecutableAllocationFuzz.cpp" />
613
    <ClCompile Include="..\jit\ExecutableAllocationFuzz.cpp" />
610
    <ClCompile Include="..\jit\ExecutableAllocator.cpp" />
614
    <ClCompile Include="..\jit\ExecutableAllocator.cpp" />
611
    <ClCompile Include="..\jit\ExecutableAllocatorFixedVMPool.cpp" />
615
    <ClCompile Include="..\jit\ExecutableAllocatorFixedVMPool.cpp" />
Lines 1370-1375 a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj_sec2
1370
    <ClInclude Include="..\jit\AccessorCallJITStubRoutine.h" />
1374
    <ClInclude Include="..\jit\AccessorCallJITStubRoutine.h" />
1371
    <ClInclude Include="..\jit\AssemblyHelpers.h" />
1375
    <ClInclude Include="..\jit\AssemblyHelpers.h" />
1372
    <ClInclude Include="..\jit\BinarySwitch.h" />
1376
    <ClInclude Include="..\jit\BinarySwitch.h" />
1377
    <ClInclude Include="..\jit\CallFrameShuffleData.h" />
1378
    <ClInclude Include="..\jit\CallFrameShuffler.h" />
1373
    <ClInclude Include="..\jit\CCallHelpers.h" />
1379
    <ClInclude Include="..\jit\CCallHelpers.h" />
1374
    <ClInclude Include="..\jit\CompactJITCodeMap.h" />
1380
    <ClInclude Include="..\jit\CompactJITCodeMap.h" />
1375
    <ClInclude Include="..\jit\ExecutableAllocationFuzz.h" />
1381
    <ClInclude Include="..\jit\ExecutableAllocationFuzz.h" />
Lines 1400-1405 a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj_sec3
1400
    <ClInclude Include="..\jit\Reg.h" />
1406
    <ClInclude Include="..\jit\Reg.h" />
1401
    <ClInclude Include="..\jit\RegisterAtOffset.h" />
1407
    <ClInclude Include="..\jit\RegisterAtOffset.h" />
1402
    <ClInclude Include="..\jit\RegisterAtOffsetList.h" />
1408
    <ClInclude Include="..\jit\RegisterAtOffsetList.h" />
1409
    <ClInclude Include="..\jit\RegisterMap.h" />
1403
    <ClInclude Include="..\jit\RegisterPreservationWrapperGenerator.h" />
1410
    <ClInclude Include="..\jit\RegisterPreservationWrapperGenerator.h" />
1404
    <ClInclude Include="..\jit\RegisterSet.h" />
1411
    <ClInclude Include="..\jit\RegisterSet.h" />
1405
    <ClInclude Include="..\jit\Repatch.h" />
1412
    <ClInclude Include="..\jit\Repatch.h" />
- a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters +15 lines
Lines 378-383 a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters_sec1
378
    <ClCompile Include="..\jit\HostCallReturnValue.cpp">
378
    <ClCompile Include="..\jit\HostCallReturnValue.cpp">
379
      <Filter>jit</Filter>
379
      <Filter>jit</Filter>
380
    </ClCompile>
380
    </ClCompile>
381
    <ClCompile Include="..\jit\CallFrameShuffleData.cpp">
382
      <Filter>jit</Filter>
383
    </ClCompile>
384
    <ClCompile Include="..\jit\CallFrameShuffler.cpp">
385
      <Filter>jit</Filter>
386
    </ClCompile>
387
    <ClCompile Include="..\jit\CallFrameShuffler32_64.cpp">
388
      <Filter>jit</Filter>
389
    </ClCompile>
390
    <ClCompile Include="..\jit\CallFrameShuffler64.cpp">
391
      <Filter>jit</Filter>
392
    </ClCompile>
381
    <ClCompile Include="..\jit\JIT.cpp">
393
    <ClCompile Include="..\jit\JIT.cpp">
382
      <Filter>jit</Filter>
394
      <Filter>jit</Filter>
383
    </ClCompile>
395
    </ClCompile>
Lines 3784-3789 a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters_sec2
3784
    <ClInclude Include="..\jit\Repatch.h">
3796
    <ClInclude Include="..\jit\Repatch.h">
3785
      <Filter>jit</Filter>
3797
      <Filter>jit</Filter>
3786
    </ClInclude>
3798
    </ClInclude>
3799
    <ClInclude Include="..\jit\RegisterMap.h">
3800
      <Filter>jit</Filter>
3801
    </ClInclude>
3787
    <ClInclude Include="..\jit\RegisterSet.h">
3802
    <ClInclude Include="..\jit\RegisterSet.h">
3788
      <Filter>jit</Filter>
3803
      <Filter>jit</Filter>
3789
    </ClInclude>
3804
    </ClInclude>
- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj -2 / +30 lines
Lines 960-969 a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj_sec1
960
		5DBB151B131D0B310056AD36 /* testapi.js in Copy Support Script */ = {isa = PBXBuildFile; fileRef = 14D857740A4696C80032146C /* testapi.js */; };
960
		5DBB151B131D0B310056AD36 /* testapi.js in Copy Support Script */ = {isa = PBXBuildFile; fileRef = 14D857740A4696C80032146C /* testapi.js */; };
961
		5DBB1525131D0BD70056AD36 /* minidom.js in Copy Support Script */ = {isa = PBXBuildFile; fileRef = 1412110D0A48788700480255 /* minidom.js */; };
961
		5DBB1525131D0BD70056AD36 /* minidom.js in Copy Support Script */ = {isa = PBXBuildFile; fileRef = 1412110D0A48788700480255 /* minidom.js */; };
962
		5DE6E5B30E1728EC00180407 /* create_hash_table in Headers */ = {isa = PBXBuildFile; fileRef = F692A8540255597D01FF60F7 /* create_hash_table */; settings = {ATTRIBUTES = (); }; };
962
		5DE6E5B30E1728EC00180407 /* create_hash_table in Headers */ = {isa = PBXBuildFile; fileRef = F692A8540255597D01FF60F7 /* create_hash_table */; settings = {ATTRIBUTES = (); }; };
963
		623A37EC1B87A7C000754209 /* RegisterMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 623A37EB1B87A7BD00754209 /* RegisterMap.h */; };
963
		627673231B680C1E00FD9F2E /* CallMode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 627673211B680C1E00FD9F2E /* CallMode.cpp */; };
964
		627673231B680C1E00FD9F2E /* CallMode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 627673211B680C1E00FD9F2E /* CallMode.cpp */; };
964
		627673241B680C1E00FD9F2E /* CallMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 627673221B680C1E00FD9F2E /* CallMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
965
		627673241B680C1E00FD9F2E /* CallMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 627673221B680C1E00FD9F2E /* CallMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
965
		62D2D38F1ADF103F000206C1 /* FunctionRareData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62D2D38D1ADF103F000206C1 /* FunctionRareData.cpp */; };
966
		62D2D38F1ADF103F000206C1 /* FunctionRareData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62D2D38D1ADF103F000206C1 /* FunctionRareData.cpp */; };
966
		62D2D3901ADF103F000206C1 /* FunctionRareData.h in Headers */ = {isa = PBXBuildFile; fileRef = 62D2D38E1ADF103F000206C1 /* FunctionRareData.h */; settings = {ATTRIBUTES = (Private, ); }; };
967
		62D2D3901ADF103F000206C1 /* FunctionRareData.h in Headers */ = {isa = PBXBuildFile; fileRef = 62D2D38E1ADF103F000206C1 /* FunctionRareData.h */; settings = {ATTRIBUTES = (Private, ); }; };
968
		62D755D41B84FB3D001801FA /* CallFrameShuffler64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62D755D31B84FB39001801FA /* CallFrameShuffler64.cpp */; };
969
		62D755D51B84FB40001801FA /* CallFrameShuffler32_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62D755D21B84FB39001801FA /* CallFrameShuffler32_64.cpp */; };
970
		62D755D61B84FB46001801FA /* CallFrameShuffler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62D755D01B84FB39001801FA /* CallFrameShuffler.cpp */; };
971
		62D755D71B84FB4A001801FA /* CallFrameShuffler.h in Headers */ = {isa = PBXBuildFile; fileRef = 62D755D11B84FB39001801FA /* CallFrameShuffler.h */; };
972
		62EC9BB61B7EB07C00303AD1 /* CallFrameShuffleData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62EC9BB41B7EB07C00303AD1 /* CallFrameShuffleData.cpp */; };
973
		62EC9BB71B7EB07C00303AD1 /* CallFrameShuffleData.h in Headers */ = {isa = PBXBuildFile; fileRef = 62EC9BB51B7EB07C00303AD1 /* CallFrameShuffleData.h */; settings = {ATTRIBUTES = (Private, ); }; };
967
		62F2AA371B0BEDE300610C7A /* DFGLazyNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62A9A29E1B0BED4800BD54CA /* DFGLazyNode.cpp */; };
974
		62F2AA371B0BEDE300610C7A /* DFGLazyNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62A9A29E1B0BED4800BD54CA /* DFGLazyNode.cpp */; };
968
		62F2AA381B0BEDE300610C7A /* DFGLazyNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 62A9A29F1B0BED4800BD54CA /* DFGLazyNode.h */; settings = {ATTRIBUTES = (Private, ); }; };
975
		62F2AA381B0BEDE300610C7A /* DFGLazyNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 62A9A29F1B0BED4800BD54CA /* DFGLazyNode.h */; settings = {ATTRIBUTES = (Private, ); }; };
969
		6507D29E0E871E5E00D7D896 /* JSTypeInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 6507D2970E871E4A00D7D896 /* JSTypeInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
976
		6507D29E0E871E5E00D7D896 /* JSTypeInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 6507D2970E871E4A00D7D896 /* JSTypeInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
Lines 2676-2687 a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj_sec2
2676
		5DAFD6CB146B686300FBEFB4 /* JSC.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = JSC.xcconfig; sourceTree = "<group>"; };
2683
		5DAFD6CB146B686300FBEFB4 /* JSC.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = JSC.xcconfig; sourceTree = "<group>"; };
2677
		5DDDF44614FEE72200B4FB4D /* LLIntDesiredOffsets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntDesiredOffsets.h; path = LLIntOffsets/LLIntDesiredOffsets.h; sourceTree = BUILT_PRODUCTS_DIR; };
2684
		5DDDF44614FEE72200B4FB4D /* LLIntDesiredOffsets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntDesiredOffsets.h; path = LLIntOffsets/LLIntDesiredOffsets.h; sourceTree = BUILT_PRODUCTS_DIR; };
2678
		5DE3D0F40DD8DDFB00468714 /* WebKitAvailability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebKitAvailability.h; sourceTree = "<group>"; };
2685
		5DE3D0F40DD8DDFB00468714 /* WebKitAvailability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebKitAvailability.h; sourceTree = "<group>"; };
2686
		623A37EB1B87A7BD00754209 /* RegisterMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterMap.h; sourceTree = "<group>"; };
2679
		627673211B680C1E00FD9F2E /* CallMode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CallMode.cpp; sourceTree = "<group>"; };
2687
		627673211B680C1E00FD9F2E /* CallMode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CallMode.cpp; sourceTree = "<group>"; };
2680
		627673221B680C1E00FD9F2E /* CallMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallMode.h; sourceTree = "<group>"; };
2688
		627673221B680C1E00FD9F2E /* CallMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallMode.h; sourceTree = "<group>"; };
2681
		62A9A29E1B0BED4800BD54CA /* DFGLazyNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGLazyNode.cpp; path = dfg/DFGLazyNode.cpp; sourceTree = "<group>"; };
2689
		62A9A29E1B0BED4800BD54CA /* DFGLazyNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGLazyNode.cpp; path = dfg/DFGLazyNode.cpp; sourceTree = "<group>"; };
2682
		62A9A29F1B0BED4800BD54CA /* DFGLazyNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGLazyNode.h; path = dfg/DFGLazyNode.h; sourceTree = "<group>"; };
2690
		62A9A29F1B0BED4800BD54CA /* DFGLazyNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGLazyNode.h; path = dfg/DFGLazyNode.h; sourceTree = "<group>"; };
2683
		62D2D38D1ADF103F000206C1 /* FunctionRareData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FunctionRareData.cpp; sourceTree = "<group>"; };
2691
		62D2D38D1ADF103F000206C1 /* FunctionRareData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FunctionRareData.cpp; sourceTree = "<group>"; };
2684
		62D2D38E1ADF103F000206C1 /* FunctionRareData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FunctionRareData.h; sourceTree = "<group>"; };
2692
		62D2D38E1ADF103F000206C1 /* FunctionRareData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FunctionRareData.h; sourceTree = "<group>"; };
2693
		62D755D01B84FB39001801FA /* CallFrameShuffler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CallFrameShuffler.cpp; sourceTree = "<group>"; };
2694
		62D755D11B84FB39001801FA /* CallFrameShuffler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallFrameShuffler.h; sourceTree = "<group>"; };
2695
		62D755D21B84FB39001801FA /* CallFrameShuffler32_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CallFrameShuffler32_64.cpp; sourceTree = "<group>"; };
2696
		62D755D31B84FB39001801FA /* CallFrameShuffler64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CallFrameShuffler64.cpp; sourceTree = "<group>"; };
2697
		62EC9BB41B7EB07C00303AD1 /* CallFrameShuffleData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CallFrameShuffleData.cpp; sourceTree = "<group>"; };
2698
		62EC9BB51B7EB07C00303AD1 /* CallFrameShuffleData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallFrameShuffleData.h; sourceTree = "<group>"; };
2685
		6507D2970E871E4A00D7D896 /* JSTypeInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSTypeInfo.h; sourceTree = "<group>"; };
2699
		6507D2970E871E4A00D7D896 /* JSTypeInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSTypeInfo.h; sourceTree = "<group>"; };
2686
		651122E5140469BA002B101D /* testRegExp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = testRegExp.cpp; sourceTree = "<group>"; };
2700
		651122E5140469BA002B101D /* testRegExp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = testRegExp.cpp; sourceTree = "<group>"; };
2687
		6511230514046A4C002B101D /* testRegExp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testRegExp; sourceTree = BUILT_PRODUCTS_DIR; };
2701
		6511230514046A4C002B101D /* testRegExp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testRegExp; sourceTree = BUILT_PRODUCTS_DIR; };
Lines 3901-3916 a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj_sec3
3901
		1429D92C0ED22D7000B89619 /* jit */ = {
3915
		1429D92C0ED22D7000B89619 /* jit */ = {
3902
			isa = PBXGroup;
3916
			isa = PBXGroup;
3903
			children = (
3917
			children = (
3904
				0FF054F71AC35B4400E5BE57 /* ExecutableAllocationFuzz.cpp */,
3905
				0FF054F81AC35B4400E5BE57 /* ExecutableAllocationFuzz.h */,
3906
				0F7576D018E1FEE9002EF4CD /* AccessorCallJITStubRoutine.cpp */,
3918
				0F7576D018E1FEE9002EF4CD /* AccessorCallJITStubRoutine.cpp */,
3907
				0F7576D118E1FEE9002EF4CD /* AccessorCallJITStubRoutine.h */,
3919
				0F7576D118E1FEE9002EF4CD /* AccessorCallJITStubRoutine.h */,
3908
				0F24E53B17EA9F5900ABB217 /* AssemblyHelpers.cpp */,
3920
				0F24E53B17EA9F5900ABB217 /* AssemblyHelpers.cpp */,
3909
				0F24E53C17EA9F5900ABB217 /* AssemblyHelpers.h */,
3921
				0F24E53C17EA9F5900ABB217 /* AssemblyHelpers.h */,
3910
				0F64B26F1A784BAF006E4E66 /* BinarySwitch.cpp */,
3922
				0F64B26F1A784BAF006E4E66 /* BinarySwitch.cpp */,
3911
				0F64B2701A784BAF006E4E66 /* BinarySwitch.h */,
3923
				0F64B2701A784BAF006E4E66 /* BinarySwitch.h */,
3924
				62EC9BB41B7EB07C00303AD1 /* CallFrameShuffleData.cpp */,
3925
				62EC9BB51B7EB07C00303AD1 /* CallFrameShuffleData.h */,
3926
				62D755D01B84FB39001801FA /* CallFrameShuffler.cpp */,
3927
				62D755D11B84FB39001801FA /* CallFrameShuffler.h */,
3928
				62D755D21B84FB39001801FA /* CallFrameShuffler32_64.cpp */,
3929
				62D755D31B84FB39001801FA /* CallFrameShuffler64.cpp */,
3912
				0F24E53D17EA9F5900ABB217 /* CCallHelpers.h */,
3930
				0F24E53D17EA9F5900ABB217 /* CCallHelpers.h */,
3913
				0FD82E37141AB14200179C94 /* CompactJITCodeMap.h */,
3931
				0FD82E37141AB14200179C94 /* CompactJITCodeMap.h */,
3932
				0FF054F71AC35B4400E5BE57 /* ExecutableAllocationFuzz.cpp */,
3933
				0FF054F81AC35B4400E5BE57 /* ExecutableAllocationFuzz.h */,
3914
				A7B48DB60EE74CFC00DCBDB6 /* ExecutableAllocator.cpp */,
3934
				A7B48DB60EE74CFC00DCBDB6 /* ExecutableAllocator.cpp */,
3915
				A7B48DB50EE74CFC00DCBDB6 /* ExecutableAllocator.h */,
3935
				A7B48DB50EE74CFC00DCBDB6 /* ExecutableAllocator.h */,
3916
				86DB64630F95C6FC00D7D921 /* ExecutableAllocatorFixedVMPool.cpp */,
3936
				86DB64630F95C6FC00D7D921 /* ExecutableAllocatorFixedVMPool.cpp */,
Lines 3965-3970 a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj_sec4
3965
				6540C79F1B82D9CE000F6B79 /* RegisterAtOffset.h */,
3985
				6540C79F1B82D9CE000F6B79 /* RegisterAtOffset.h */,
3966
				6540C79C1B82D99D000F6B79 /* RegisterAtOffsetList.cpp */,
3986
				6540C79C1B82D99D000F6B79 /* RegisterAtOffsetList.cpp */,
3967
				6540C79D1B82D99D000F6B79 /* RegisterAtOffsetList.h */,
3987
				6540C79D1B82D99D000F6B79 /* RegisterAtOffsetList.h */,
3988
				623A37EB1B87A7BD00754209 /* RegisterMap.h */,
3968
				0F6B1CBB1861246A00845D97 /* RegisterPreservationWrapperGenerator.cpp */,
3989
				0F6B1CBB1861246A00845D97 /* RegisterPreservationWrapperGenerator.cpp */,
3969
				0F6B1CBC1861246A00845D97 /* RegisterPreservationWrapperGenerator.h */,
3990
				0F6B1CBC1861246A00845D97 /* RegisterPreservationWrapperGenerator.h */,
3970
				0FC3141418146D7000033232 /* RegisterSet.cpp */,
3991
				0FC3141418146D7000033232 /* RegisterSet.cpp */,
Lines 5654-5659 a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj_sec5
5654
				C4F4B6F41A05C944005CAB76 /* cpp_generator.py in Headers */,
5675
				C4F4B6F41A05C944005CAB76 /* cpp_generator.py in Headers */,
5655
				A532439418569709002ED692 /* generate-combined-inspector-json.py in Headers */,
5676
				A532439418569709002ED692 /* generate-combined-inspector-json.py in Headers */,
5656
				A5840E27187C981E00843B10 /* cssmin.py in Headers */,
5677
				A5840E27187C981E00843B10 /* cssmin.py in Headers */,
5678
				62D755D71B84FB4A001801FA /* CallFrameShuffler.h in Headers */,
5657
				A5EA710419F6DE720098F5EC /* generate_objc_backend_dispatcher_implementation.py in Headers */,
5679
				A5EA710419F6DE720098F5EC /* generate_objc_backend_dispatcher_implementation.py in Headers */,
5658
				C4703CD5192844CC0013FBEA /* generator_templates.py in Headers */,
5680
				C4703CD5192844CC0013FBEA /* generator_templates.py in Headers */,
5659
				A5EA710519F6DE740098F5EC /* generate_objc_configuration_header.py in Headers */,
5681
				A5EA710519F6DE740098F5EC /* generate_objc_configuration_header.py in Headers */,
Lines 5809-5814 a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj_sec6
5809
				0F3B3A281544C997003ED0FF /* DFGCFGSimplificationPhase.h in Headers */,
5831
				0F3B3A281544C997003ED0FF /* DFGCFGSimplificationPhase.h in Headers */,
5810
				A77A424017A0BBFD00A8DB81 /* DFGClobberize.h in Headers */,
5832
				A77A424017A0BBFD00A8DB81 /* DFGClobberize.h in Headers */,
5811
				A77A424217A0BBFD00A8DB81 /* DFGClobberSet.h in Headers */,
5833
				A77A424217A0BBFD00A8DB81 /* DFGClobberSet.h in Headers */,
5834
				62EC9BB71B7EB07C00303AD1 /* CallFrameShuffleData.h in Headers */,
5812
				0F7B294D14C3CD4C007C3DB1 /* DFGCommon.h in Headers */,
5835
				0F7B294D14C3CD4C007C3DB1 /* DFGCommon.h in Headers */,
5813
				0FEA0A32170D40BF00BB722C /* DFGCommonData.h in Headers */,
5836
				0FEA0A32170D40BF00BB722C /* DFGCommonData.h in Headers */,
5814
				0F38B01817CFE75500B144D3 /* DFGCompilationKey.h in Headers */,
5837
				0F38B01817CFE75500B144D3 /* DFGCompilationKey.h in Headers */,
Lines 6113-6118 a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj_sec7
6113
				FEF68361174343CC00A32E25 /* JITStubsX86.h in Headers */,
6136
				FEF68361174343CC00A32E25 /* JITStubsX86.h in Headers */,
6114
				FEF68360174343CC00A32E25 /* JITStubsX86_64.h in Headers */,
6137
				FEF68360174343CC00A32E25 /* JITStubsX86_64.h in Headers */,
6115
				ADDB1F6318D77DBE009B58A8 /* OpaqueRootSet.h in Headers */,
6138
				ADDB1F6318D77DBE009B58A8 /* OpaqueRootSet.h in Headers */,
6139
				623A37EC1B87A7C000754209 /* RegisterMap.h in Headers */,
6116
				A7A4AE1017973B4D005612B1 /* JITStubsX86Common.h in Headers */,
6140
				A7A4AE1017973B4D005612B1 /* JITStubsX86Common.h in Headers */,
6117
				0F5EF91F16878F7D003E5C25 /* JITThunks.h in Headers */,
6141
				0F5EF91F16878F7D003E5C25 /* JITThunks.h in Headers */,
6118
				0FC712E317CD8793008CC93C /* JITToDFGDeferredCompilationCallback.h in Headers */,
6142
				0FC712E317CD8793008CC93C /* JITToDFGDeferredCompilationCallback.h in Headers */,
Lines 7104-7109 a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj_sec8
7104
				0FF0F19D16B72A08005DF95B /* DFGCommon.cpp in Sources */,
7128
				0FF0F19D16B72A08005DF95B /* DFGCommon.cpp in Sources */,
7105
				0FEA0A31170D40BF00BB722C /* DFGCommonData.cpp in Sources */,
7129
				0FEA0A31170D40BF00BB722C /* DFGCommonData.cpp in Sources */,
7106
				0F38B01717CFE75500B144D3 /* DFGCompilationKey.cpp in Sources */,
7130
				0F38B01717CFE75500B144D3 /* DFGCompilationKey.cpp in Sources */,
7131
				62EC9BB61B7EB07C00303AD1 /* CallFrameShuffleData.cpp in Sources */,
7107
				0F38B01917CFE75500B144D3 /* DFGCompilationMode.cpp in Sources */,
7132
				0F38B01917CFE75500B144D3 /* DFGCompilationMode.cpp in Sources */,
7108
				0F3B3A1A153E68F2003ED0FF /* DFGConstantFoldingPhase.cpp in Sources */,
7133
				0F3B3A1A153E68F2003ED0FF /* DFGConstantFoldingPhase.cpp in Sources */,
7109
				0FBE0F7216C1DB030082C5E8 /* DFGCPSRethreadingPhase.cpp in Sources */,
7134
				0FBE0F7216C1DB030082C5E8 /* DFGCPSRethreadingPhase.cpp in Sources */,
Lines 7153-7158 a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj_sec9
7153
				0FF0F19C16B72A03005DF95B /* DFGNode.cpp in Sources */,
7178
				0FF0F19C16B72A03005DF95B /* DFGNode.cpp in Sources */,
7154
				0FA581BA150E952C00B9A2D9 /* DFGNodeFlags.cpp in Sources */,
7179
				0FA581BA150E952C00B9A2D9 /* DFGNodeFlags.cpp in Sources */,
7155
				86EC9DCF1328DF82002B2AD7 /* DFGOperations.cpp in Sources */,
7180
				86EC9DCF1328DF82002B2AD7 /* DFGOperations.cpp in Sources */,
7181
				62D755D61B84FB46001801FA /* CallFrameShuffler.cpp in Sources */,
7156
				A7D89CFD17A0B8CC00773AD8 /* DFGOSRAvailabilityAnalysisPhase.cpp in Sources */,
7182
				A7D89CFD17A0B8CC00773AD8 /* DFGOSRAvailabilityAnalysisPhase.cpp in Sources */,
7157
				0FD82E56141DAF0800179C94 /* DFGOSREntry.cpp in Sources */,
7183
				0FD82E56141DAF0800179C94 /* DFGOSREntry.cpp in Sources */,
7158
				0FD8A32517D51F5700CA2C40 /* DFGOSREntrypointCreationPhase.cpp in Sources */,
7184
				0FD8A32517D51F5700CA2C40 /* DFGOSREntrypointCreationPhase.cpp in Sources */,
Lines 7275-7280 a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj_sec10
7275
				147F39CB107EC37600427A48 /* FunctionConstructor.cpp in Sources */,
7301
				147F39CB107EC37600427A48 /* FunctionConstructor.cpp in Sources */,
7276
				0FF0F19F16B72A17005DF95B /* FunctionExecutableDump.cpp in Sources */,
7302
				0FF0F19F16B72A17005DF95B /* FunctionExecutableDump.cpp in Sources */,
7277
				52B310FD1974AE870080857C /* FunctionHasExecutedCache.cpp in Sources */,
7303
				52B310FD1974AE870080857C /* FunctionHasExecutedCache.cpp in Sources */,
7304
				62D755D51B84FB40001801FA /* CallFrameShuffler32_64.cpp in Sources */,
7278
				147F39CC107EC37600427A48 /* FunctionPrototype.cpp in Sources */,
7305
				147F39CC107EC37600427A48 /* FunctionPrototype.cpp in Sources */,
7279
				0F64B2711A784BAF006E4E66 /* BinarySwitch.cpp in Sources */,
7306
				0F64B2711A784BAF006E4E66 /* BinarySwitch.cpp in Sources */,
7280
				0F766D2F15A8DCE0008F363E /* GCAwareJITStubRoutine.cpp in Sources */,
7307
				0F766D2F15A8DCE0008F363E /* GCAwareJITStubRoutine.cpp in Sources */,
Lines 7396-7401 a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj_sec11
7396
				A72700900DAC6BBC00E548D7 /* JSNotAnObject.cpp in Sources */,
7423
				A72700900DAC6BBC00E548D7 /* JSNotAnObject.cpp in Sources */,
7397
				147F39D4107EC37600427A48 /* JSObject.cpp in Sources */,
7424
				147F39D4107EC37600427A48 /* JSObject.cpp in Sources */,
7398
				1482B7E40A43076000517CFC /* JSObjectRef.cpp in Sources */,
7425
				1482B7E40A43076000517CFC /* JSObjectRef.cpp in Sources */,
7426
				62D755D41B84FB3D001801FA /* CallFrameShuffler64.cpp in Sources */,
7399
				A7F993600FD7325100A0B2D0 /* JSONObject.cpp in Sources */,
7427
				A7F993600FD7325100A0B2D0 /* JSONObject.cpp in Sources */,
7400
				0FFB6C381AF48DDC00DB1BF7 /* TypeofType.cpp in Sources */,
7428
				0FFB6C381AF48DDC00DB1BF7 /* TypeofType.cpp in Sources */,
7401
				95F6E6950E5B5F970091E860 /* JSProfilerPrivate.cpp in Sources */,
7429
				95F6E6950E5B5F970091E860 /* JSProfilerPrivate.cpp in Sources */,
- a/Source/JavaScriptCore/assembler/ARM64Assembler.h -8 / +8 lines
Lines 469-476 namespace ARM64Registers { a/Source/JavaScriptCore/assembler/ARM64Assembler.h_sec1
469
        q31,
469
        q31,
470
    } FPRegisterID;
470
    } FPRegisterID;
471
471
472
    static bool isSp(RegisterID reg) { return reg == sp; }
472
    static constexpr bool isSp(RegisterID reg) { return reg == sp; }
473
    static bool isZr(RegisterID reg) { return reg == zr; }
473
    static constexpr bool isZr(RegisterID reg) { return reg == zr; }
474
}
474
}
475
475
476
class ARM64Assembler {
476
class ARM64Assembler {
Lines 478-492 public: a/Source/JavaScriptCore/assembler/ARM64Assembler.h_sec2
478
    typedef ARM64Registers::RegisterID RegisterID;
478
    typedef ARM64Registers::RegisterID RegisterID;
479
    typedef ARM64Registers::FPRegisterID FPRegisterID;
479
    typedef ARM64Registers::FPRegisterID FPRegisterID;
480
    
480
    
481
    static RegisterID firstRegister() { return ARM64Registers::x0; }
481
    static constexpr RegisterID firstRegister() { return ARM64Registers::x0; }
482
    static RegisterID lastRegister() { return ARM64Registers::sp; }
482
    static constexpr RegisterID lastRegister() { return ARM64Registers::sp; }
483
    
483
    
484
    static FPRegisterID firstFPRegister() { return ARM64Registers::q0; }
484
    static constexpr FPRegisterID firstFPRegister() { return ARM64Registers::q0; }
485
    static FPRegisterID lastFPRegister() { return ARM64Registers::q31; }
485
    static constexpr FPRegisterID lastFPRegister() { return ARM64Registers::q31; }
486
486
487
private:
487
private:
488
    static bool isSp(RegisterID reg) { return ARM64Registers::isSp(reg); }
488
    static constexpr bool isSp(RegisterID reg) { return ARM64Registers::isSp(reg); }
489
    static bool isZr(RegisterID reg) { return ARM64Registers::isZr(reg); }
489
    static constexpr bool isZr(RegisterID reg) { return ARM64Registers::isZr(reg); }
490
490
491
public:
491
public:
492
    ARM64Assembler()
492
    ARM64Assembler()
- a/Source/JavaScriptCore/assembler/ARMAssembler.h -4 / +4 lines
Lines 138-148 namespace JSC { a/Source/JavaScriptCore/assembler/ARMAssembler.h_sec1
138
138
139
        ARMBuffer& buffer() { return m_buffer; }
139
        ARMBuffer& buffer() { return m_buffer; }
140
140
141
        static RegisterID firstRegister() { return ARMRegisters::r0; }
141
        static constexpr RegisterID firstRegister() { return ARMRegisters::r0; }
142
        static RegisterID lastRegister() { return ARMRegisters::r15; }
142
        static constexpr RegisterID lastRegister() { return ARMRegisters::r15; }
143
143
144
        static FPRegisterID firstFPRegister() { return ARMRegisters::d0; }
144
        static constexpr FPRegisterID firstFPRegister() { return ARMRegisters::d0; }
145
        static FPRegisterID lastFPRegister() { return ARMRegisters::d31; }
145
        static constexpr FPRegisterID lastFPRegister() { return ARMRegisters::d31; }
146
146
147
        // ARM conditional constants
147
        // ARM conditional constants
148
        typedef enum {
148
        typedef enum {
- a/Source/JavaScriptCore/assembler/AbortReason.h +1 lines
Lines 63-68 enum AbortReason { a/Source/JavaScriptCore/assembler/AbortReason.h_sec1
63
    JITGetByValResultIsNotEmpty                       = 250,
63
    JITGetByValResultIsNotEmpty                       = 250,
64
    JITNotSupported                                   = 260,
64
    JITNotSupported                                   = 260,
65
    JITOffsetIsNotOutOfLine                           = 270,
65
    JITOffsetIsNotOutOfLine                           = 270,
66
    JITUnexpectedCallFrameSize                        = 275,
66
    JITUnreasonableLoopHintJumpTarget                 = 280,
67
    JITUnreasonableLoopHintJumpTarget                 = 280,
67
    RPWUnreasonableJumpTarget                         = 290,
68
    RPWUnreasonableJumpTarget                         = 290,
68
    RepatchIneffectiveWatchpoint                      = 300,
69
    RepatchIneffectiveWatchpoint                      = 300,
- a/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h -4 / +4 lines
Lines 103-113 public: a/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h_sec1
103
    typedef typename AssemblerType::RegisterID RegisterID;
103
    typedef typename AssemblerType::RegisterID RegisterID;
104
    typedef typename AssemblerType::FPRegisterID FPRegisterID;
104
    typedef typename AssemblerType::FPRegisterID FPRegisterID;
105
    
105
    
106
    static RegisterID firstRegister() { return AssemblerType::firstRegister(); }
106
    static constexpr RegisterID firstRegister() { return AssemblerType::firstRegister(); }
107
    static RegisterID lastRegister() { return AssemblerType::lastRegister(); }
107
    static constexpr RegisterID lastRegister() { return AssemblerType::lastRegister(); }
108
108
109
    static FPRegisterID firstFPRegister() { return AssemblerType::firstFPRegister(); }
109
    static constexpr FPRegisterID firstFPRegister() { return AssemblerType::firstFPRegister(); }
110
    static FPRegisterID lastFPRegister() { return AssemblerType::lastFPRegister(); }
110
    static constexpr FPRegisterID lastFPRegister() { return AssemblerType::lastFPRegister(); }
111
111
112
    // Section 1: MacroAssembler operand types
112
    // Section 1: MacroAssembler operand types
113
    //
113
    //
- a/Source/JavaScriptCore/assembler/MIPSAssembler.h -4 / +4 lines
Lines 151-161 public: a/Source/JavaScriptCore/assembler/MIPSAssembler.h_sec1
151
    typedef MIPSRegisters::FPRegisterID FPRegisterID;
151
    typedef MIPSRegisters::FPRegisterID FPRegisterID;
152
    typedef SegmentedVector<AssemblerLabel, 64> Jumps;
152
    typedef SegmentedVector<AssemblerLabel, 64> Jumps;
153
153
154
    static RegisterID firstRegister() { return MIPSRegisters::r0; }
154
    static constexpr RegisterID firstRegister() { return MIPSRegisters::r0; }
155
    static RegisterID lastRegister() { return MIPSRegisters::r31; }
155
    static constexpr RegisterID lastRegister() { return MIPSRegisters::r31; }
156
156
157
    static FPRegisterID firstFPRegister() { return MIPSRegisters::f0; }
157
    static constexpr FPRegisterID firstFPRegister() { return MIPSRegisters::f0; }
158
    static FPRegisterID lastFPRegister() { return MIPSRegisters::f31; }
158
    static constexpr FPRegisterID lastFPRegister() { return MIPSRegisters::f31; }
159
159
160
    MIPSAssembler()
160
    MIPSAssembler()
161
        : m_indexOfLastWatchpoint(INT_MIN)
161
        : m_indexOfLastWatchpoint(INT_MIN)
- a/Source/JavaScriptCore/assembler/MacroAssembler.h -8 / +8 lines
Lines 69-110 namespace JSC { a/Source/JavaScriptCore/assembler/MacroAssembler.h_sec1
69
class MacroAssembler : public MacroAssemblerBase {
69
class MacroAssembler : public MacroAssemblerBase {
70
public:
70
public:
71
71
72
    static RegisterID nextRegister(RegisterID reg)
72
    static constexpr RegisterID nextRegister(RegisterID reg)
73
    {
73
    {
74
        return static_cast<RegisterID>(reg + 1);
74
        return static_cast<RegisterID>(reg + 1);
75
    }
75
    }
76
    
76
    
77
    static FPRegisterID nextFPRegister(FPRegisterID reg)
77
    static constexpr FPRegisterID nextFPRegister(FPRegisterID reg)
78
    {
78
    {
79
        return static_cast<FPRegisterID>(reg + 1);
79
        return static_cast<FPRegisterID>(reg + 1);
80
    }
80
    }
81
    
81
    
82
    static unsigned numberOfRegisters()
82
    static constexpr unsigned numberOfRegisters()
83
    {
83
    {
84
        return lastRegister() - firstRegister() + 1;
84
        return lastRegister() - firstRegister() + 1;
85
    }
85
    }
86
    
86
    
87
    static unsigned registerIndex(RegisterID reg)
87
    static constexpr unsigned registerIndex(RegisterID reg)
88
    {
88
    {
89
        return reg - firstRegister();
89
        return reg - firstRegister();
90
    }
90
    }
91
    
91
    
92
    static unsigned numberOfFPRegisters()
92
    static constexpr unsigned numberOfFPRegisters()
93
    {
93
    {
94
        return lastFPRegister() - firstFPRegister() + 1;
94
        return lastFPRegister() - firstFPRegister() + 1;
95
    }
95
    }
96
    
96
    
97
    static unsigned fpRegisterIndex(FPRegisterID reg)
97
    static constexpr unsigned fpRegisterIndex(FPRegisterID reg)
98
    {
98
    {
99
        return reg - firstFPRegister();
99
        return reg - firstFPRegister();
100
    }
100
    }
101
    
101
    
102
    static unsigned registerIndex(FPRegisterID reg)
102
    static constexpr unsigned registerIndex(FPRegisterID reg)
103
    {
103
    {
104
        return fpRegisterIndex(reg) + numberOfRegisters();
104
        return fpRegisterIndex(reg) + numberOfRegisters();
105
    }
105
    }
106
    
106
    
107
    static unsigned totalNumberOfRegisters()
107
    static constexpr unsigned totalNumberOfRegisters()
108
    {
108
    {
109
        return numberOfRegisters() + numberOfFPRegisters();
109
        return numberOfRegisters() + numberOfFPRegisters();
110
    }
110
    }
- a/Source/JavaScriptCore/assembler/SH4Assembler.h -4 / +4 lines
Lines 327-337 public: a/Source/JavaScriptCore/assembler/SH4Assembler.h_sec1
327
    static const RegisterID scratchReg2 = SH4Registers::r11;
327
    static const RegisterID scratchReg2 = SH4Registers::r11;
328
    static const uint32_t maxInstructionSize = 16;
328
    static const uint32_t maxInstructionSize = 16;
329
329
330
    static RegisterID firstRegister() { return SH4Registers::r0; }
330
    static constexpr RegisterID firstRegister() { return SH4Registers::r0; }
331
    static RegisterID lastRegister() { return SH4Registers::r15; }
331
    static constexpr RegisterID lastRegister() { return SH4Registers::r15; }
332
332
333
    static FPRegisterID firstFPRegister() { return SH4Registers::dr0; }
333
    static constexpr FPRegisterID firstFPRegister() { return SH4Registers::dr0; }
334
    static FPRegisterID lastFPRegister() { return SH4Registers::dr14; }
334
    static constexpr FPRegisterID lastFPRegister() { return SH4Registers::dr14; }
335
335
336
    enum {
336
    enum {
337
        padForAlign8 = 0x00,
337
        padForAlign8 = 0x00,
- a/Source/JavaScriptCore/assembler/X86Assembler.h -4 / +4 lines
Lines 123-130 class X86Assembler { a/Source/JavaScriptCore/assembler/X86Assembler.h_sec1
123
public:
123
public:
124
    typedef X86Registers::RegisterID RegisterID;
124
    typedef X86Registers::RegisterID RegisterID;
125
    
125
    
126
    static RegisterID firstRegister() { return X86Registers::eax; }
126
    static constexpr RegisterID firstRegister() { return X86Registers::eax; }
127
    static RegisterID lastRegister()
127
    static constexpr RegisterID lastRegister()
128
    {
128
    {
129
#if CPU(X86_64)
129
#if CPU(X86_64)
130
        return X86Registers::r15;
130
        return X86Registers::r15;
Lines 136-143 public: a/Source/JavaScriptCore/assembler/X86Assembler.h_sec2
136
    typedef X86Registers::XMMRegisterID XMMRegisterID;
136
    typedef X86Registers::XMMRegisterID XMMRegisterID;
137
    typedef XMMRegisterID FPRegisterID;
137
    typedef XMMRegisterID FPRegisterID;
138
    
138
    
139
    static FPRegisterID firstFPRegister() { return X86Registers::xmm0; }
139
    static constexpr FPRegisterID firstFPRegister() { return X86Registers::xmm0; }
140
    static FPRegisterID lastFPRegister()
140
    static constexpr FPRegisterID lastFPRegister()
141
    {
141
    {
142
#if CPU(X86_64)
142
#if CPU(X86_64)
143
        return X86Registers::xmm15;
143
        return X86Registers::xmm15;
- a/Source/JavaScriptCore/bytecode/CallLinkInfo.h +12 lines
Lines 26-31 a/Source/JavaScriptCore/bytecode/CallLinkInfo.h_sec1
26
#ifndef CallLinkInfo_h
26
#ifndef CallLinkInfo_h
27
#define CallLinkInfo_h
27
#define CallLinkInfo_h
28
28
29
#include "CallFrameShuffleData.h"
29
#include "CallMode.h"
30
#include "CallMode.h"
30
#include "CodeLocation.h"
31
#include "CodeLocation.h"
31
#include "CodeSpecializationKind.h"
32
#include "CodeSpecializationKind.h"
Lines 329-334 public: a/Source/JavaScriptCore/bytecode/CallLinkInfo.h_sec2
329
330
330
    void visitWeak(RepatchBuffer&);
331
    void visitWeak(RepatchBuffer&);
331
332
333
    void setFrameShuffleData(const CallFrameShuffleData& shuffleData)
334
    {
335
        m_frameShuffleData = std::make_unique<CallFrameShuffleData>(shuffleData);
336
    }
337
338
    const CallFrameShuffleData* frameShuffleData()
339
    {
340
        return m_frameShuffleData.get();
341
    }
342
332
private:
343
private:
333
    CodeLocationNearCall m_callReturnLocation;
344
    CodeLocationNearCall m_callReturnLocation;
334
    CodeLocationDataLabelPtr m_hotPathBegin;
345
    CodeLocationDataLabelPtr m_hotPathBegin;
Lines 337-342 private: a/Source/JavaScriptCore/bytecode/CallLinkInfo.h_sec3
337
    WriteBarrier<JSFunction> m_lastSeenCallee;
348
    WriteBarrier<JSFunction> m_lastSeenCallee;
338
    RefPtr<PolymorphicCallStubRoutine> m_stub;
349
    RefPtr<PolymorphicCallStubRoutine> m_stub;
339
    RefPtr<JITStubRoutine> m_slowStub;
350
    RefPtr<JITStubRoutine> m_slowStub;
351
    std::unique_ptr<CallFrameShuffleData> m_frameShuffleData;
340
    unsigned m_registerPreservationMode : 1; // Real type is RegisterPreservationMode
352
    unsigned m_registerPreservationMode : 1; // Real type is RegisterPreservationMode
341
    bool m_hasSeenShouldRepatch : 1;
353
    bool m_hasSeenShouldRepatch : 1;
342
    bool m_hasSeenClosure : 1;
354
    bool m_hasSeenClosure : 1;
- a/Source/JavaScriptCore/bytecode/ValueRecovery.cpp +3 lines
Lines 86-91 void ValueRecovery::dumpInContext(PrintStream& out, DumpContext* context) const a/Source/JavaScriptCore/bytecode/ValueRecovery.cpp_sec1
86
    case InFPR:
86
    case InFPR:
87
        out.print(fpr());
87
        out.print(fpr());
88
        return;
88
        return;
89
    case UnboxedDoubleInFPR:
90
        out.print("double(", fpr(), ")");
91
        return;
89
#if USE(JSVALUE32_64)
92
#if USE(JSVALUE32_64)
90
    case InPair:
93
    case InPair:
91
        out.print("pair(", tagGPR(), ", ", payloadGPR(), ")");
94
        out.print("pair(", tagGPR(), ", ", payloadGPR(), ")");
- a/Source/JavaScriptCore/bytecode/ValueRecovery.h -12 / +102 lines
Lines 55-60 enum ValueRecoveryTechnique { a/Source/JavaScriptCore/bytecode/ValueRecovery.h_sec1
55
    InPair,
55
    InPair,
56
#endif
56
#endif
57
    InFPR,
57
    InFPR,
58
    UnboxedDoubleInFPR,
58
    // It's in the stack, but at a different location.
59
    // It's in the stack, but at a different location.
59
    DisplacedInJSStack,
60
    DisplacedInJSStack,
60
    // It's in the stack, at a different location, and it's unboxed.
61
    // It's in the stack, at a different location, and it's unboxed.
Lines 82-87 public: a/Source/JavaScriptCore/bytecode/ValueRecovery.h_sec2
82
    
83
    
83
    bool isSet() const { return m_technique != DontKnow; }
84
    bool isSet() const { return m_technique != DontKnow; }
84
    bool operator!() const { return !isSet(); }
85
    bool operator!() const { return !isSet(); }
86
    explicit operator bool() const { return isSet(); }
85
    
87
    
86
    static ValueRecovery inGPR(MacroAssembler::RegisterID gpr, DataFormat dataFormat)
88
    static ValueRecovery inGPR(MacroAssembler::RegisterID gpr, DataFormat dataFormat)
87
    {
89
    {
Lines 117-126 public: a/Source/JavaScriptCore/bytecode/ValueRecovery.h_sec3
117
    }
119
    }
118
#endif
120
#endif
119
121
120
    static ValueRecovery inFPR(MacroAssembler::FPRegisterID fpr)
122
    static ValueRecovery inFPR(MacroAssembler::FPRegisterID fpr, DataFormat dataFormat)
121
    {
123
    {
124
        ASSERT(dataFormat == DataFormatDouble || dataFormat & DataFormatJS);
122
        ValueRecovery result;
125
        ValueRecovery result;
123
        result.m_technique = InFPR;
126
        if (dataFormat == DataFormatDouble)
127
            result.m_technique = UnboxedDoubleInFPR;
128
        else
129
            result.m_technique = InFPR;
124
        result.m_source.fpr = fpr;
130
        result.m_source.fpr = fpr;
125
        return result;
131
        return result;
126
    }
132
    }
Lines 185-196 public: a/Source/JavaScriptCore/bytecode/ValueRecovery.h_sec4
185
        result.m_source.nodeID = id.bits();
191
        result.m_source.nodeID = id.bits();
186
        return result;
192
        return result;
187
    }
193
    }
188
    
194
189
    ValueRecoveryTechnique technique() const { return m_technique; }
195
    ValueRecoveryTechnique technique() const { return m_technique; }
190
    
196
    
191
    bool isConstant() const { return m_technique == Constant; }
197
    bool isConstant() const { return m_technique == Constant; }
192
    
198
193
    bool isInRegisters() const
199
    bool isInGPR() const
194
    {
200
    {
195
        switch (m_technique) {
201
        switch (m_technique) {
196
        case InGPR:
202
        case InGPR:
Lines 199-217 public: a/Source/JavaScriptCore/bytecode/ValueRecovery.h_sec5
199
        case UnboxedCellInGPR:
205
        case UnboxedCellInGPR:
200
        case UnboxedInt52InGPR:
206
        case UnboxedInt52InGPR:
201
        case UnboxedStrictInt52InGPR:
207
        case UnboxedStrictInt52InGPR:
202
#if USE(JSVALUE32_64)
208
            return true;
203
        case InPair:
209
        default:
204
#endif
210
            return false;
211
        }
212
    }
213
214
    bool isInFPR() const
215
    {
216
        switch (m_technique) {
205
        case InFPR:
217
        case InFPR:
218
        case UnboxedDoubleInFPR:
219
            return true;
220
        default:
221
            return false;
222
        }
223
    }
224
    
225
    bool isInRegisters() const
226
    {
227
        return isInJSValueRegs() || isInGPR() || isInFPR();
228
    }
229
230
    bool isInJSStack() const
231
    {
232
        switch (m_technique) {
233
        case DisplacedInJSStack:
234
        case Int32DisplacedInJSStack:
235
        case Int52DisplacedInJSStack:
236
        case StrictInt52DisplacedInJSStack:
237
        case DoubleDisplacedInJSStack:
238
        case CellDisplacedInJSStack:
239
        case BooleanDisplacedInJSStack:
206
            return true;
240
            return true;
207
        default:
241
        default:
208
            return false;
242
            return false;
209
        }
243
        }
210
    }
244
    }
245
246
    DataFormat dataFormat() const
247
    {
248
        switch (m_technique) {
249
        case InGPR:
250
        case InFPR:
251
        case DisplacedInJSStack:
252
        case Constant:
253
#if USE(JSVALUE32_64)
254
        case InPair:
255
#endif
256
            return DataFormatJS;
257
        case UnboxedInt32InGPR:
258
        case Int32DisplacedInJSStack:
259
            return DataFormatInt32;
260
        case UnboxedInt52InGPR:
261
        case Int52DisplacedInJSStack:
262
            return DataFormatInt52;
263
        case UnboxedStrictInt52InGPR:
264
        case StrictInt52DisplacedInJSStack:
265
            return DataFormatStrictInt52;
266
        case UnboxedBooleanInGPR:
267
        case BooleanDisplacedInJSStack:
268
            return DataFormatBoolean;
269
        case UnboxedCellInGPR:
270
        case CellDisplacedInJSStack:
271
            return DataFormatCell;
272
        case UnboxedDoubleInFPR:
273
        case DoubleDisplacedInJSStack:
274
            return DataFormatDouble;
275
        default:
276
            return DataFormatNone;
277
        }
278
    }
211
    
279
    
212
    MacroAssembler::RegisterID gpr() const
280
    MacroAssembler::RegisterID gpr() const
213
    {
281
    {
214
        ASSERT(m_technique == InGPR || m_technique == UnboxedInt32InGPR || m_technique == UnboxedBooleanInGPR || m_technique == UnboxedInt52InGPR || m_technique == UnboxedStrictInt52InGPR || m_technique == UnboxedCellInGPR);
282
        ASSERT(isInGPR());
215
        return m_source.gpr;
283
        return m_source.gpr;
216
    }
284
    }
217
    
285
    
Lines 227-243 public: a/Source/JavaScriptCore/bytecode/ValueRecovery.h_sec6
227
        ASSERT(m_technique == InPair);
295
        ASSERT(m_technique == InPair);
228
        return m_source.pair.payloadGPR;
296
        return m_source.pair.payloadGPR;
229
    }
297
    }
298
299
    bool isInJSValueRegs() const
300
    {
301
        return m_technique == InPair;
302
    }
303
304
    JSValueRegs jsValueRegs() const
305
    {
306
        ASSERT(isInJSValueRegs());
307
        return JSValueRegs(tagGPR(), payloadGPR());
308
    }
309
#else
310
    bool isInJSValueRegs() const
311
    {
312
        return isInGPR();
313
    }
314
315
    JSValueRegs jsValueRegs() const
316
    {
317
        ASSERT(isInGPR());
318
        return JSValueRegs(gpr());
319
    }
230
#endif
320
#endif
231
    
321
    
232
    MacroAssembler::FPRegisterID fpr() const
322
    MacroAssembler::FPRegisterID fpr() const
233
    {
323
    {
234
        ASSERT(m_technique == InFPR);
324
        ASSERT(isInFPR());
235
        return m_source.fpr;
325
        return m_source.fpr;
236
    }
326
    }
237
    
327
    
238
    VirtualRegister virtualRegister() const
328
    VirtualRegister virtualRegister() const
239
    {
329
    {
240
        ASSERT(m_technique == DisplacedInJSStack || m_technique == Int32DisplacedInJSStack || m_technique == DoubleDisplacedInJSStack || m_technique == CellDisplacedInJSStack || m_technique == BooleanDisplacedInJSStack || m_technique == Int52DisplacedInJSStack || m_technique == StrictInt52DisplacedInJSStack);
330
        ASSERT(isInJSStack());
241
        return VirtualRegister(m_source.virtualReg);
331
        return VirtualRegister(m_source.virtualReg);
242
    }
332
    }
243
    
333
    
Lines 264-270 public: a/Source/JavaScriptCore/bytecode/ValueRecovery.h_sec7
264
    
354
    
265
    JSValue constant() const
355
    JSValue constant() const
266
    {
356
    {
267
        ASSERT(m_technique == Constant);
357
        ASSERT(isConstant());
268
        return JSValue::decode(m_source.constant);
358
        return JSValue::decode(m_source.constant);
269
    }
359
    }
270
    
360
    
- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp -1 / +1 lines
Lines 3264-3270 bool ByteCodeParser::parseBlock(unsigned limit) a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp_sec1
3264
                // We could be the dummy jump to a return after a non-inlined, non-emulated tail call in a ternary operator
3264
                // We could be the dummy jump to a return after a non-inlined, non-emulated tail call in a ternary operator
3265
                Node* terminal = m_currentBlock->terminal();
3265
                Node* terminal = m_currentBlock->terminal();
3266
                ASSERT_UNUSED(terminal, terminal->op() == TailCall || terminal->op() == TailCallVarargs);
3266
                ASSERT_UNUSED(terminal, terminal->op() == TailCall || terminal->op() == TailCallVarargs);
3267
                LAST_OPCODE(op_ret);
3267
                LAST_OPCODE(op_jmp);
3268
            }
3268
            }
3269
            int relativeOffset = currentInstruction[1].u.operand;
3269
            int relativeOffset = currentInstruction[1].u.operand;
3270
            addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset));
3270
            addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset));
- a/Source/JavaScriptCore/dfg/DFGGenerationInfo.h +23 lines
Lines 378-383 public: a/Source/JavaScriptCore/dfg/DFGGenerationInfo.h_sec1
378
        return m_useCount;
378
        return m_useCount;
379
    }
379
    }
380
380
381
    ValueRecovery recovery(VirtualRegister spillSlot) const
382
    {
383
        if (m_isConstant)
384
            return ValueRecovery::constant(m_node->constant()->value());
385
386
        if (m_registerFormat == DataFormatDouble)
387
            return ValueRecovery::inFPR(u.fpr, DataFormatDouble);
388
389
#if USE(JSVALUE32_64)
390
        if (m_registerFormat & DataFormatJS) {
391
            if (m_registerFormat == DataFormatJS)
392
                return ValueRecovery::inPair(u.v.tagGPR, u.v.payloadGPR);
393
            return ValueRecovery::inGPR(u.v.payloadGPR, static_cast<DataFormat>(m_registerFormat & ~DataFormatJS));
394
        }
395
#endif
396
        if (m_registerFormat)
397
            return ValueRecovery::inGPR(u.gpr, m_registerFormat);
398
399
        ASSERT(m_spillFormat);
400
401
        return ValueRecovery::displacedInJSStack(spillSlot, m_spillFormat);
402
    }
403
381
private:
404
private:
382
    void appendBirth(VariableEventStream& stream)
405
    void appendBirth(VariableEventStream& stream)
383
    {
406
    {
- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp -1 / +3 lines
Lines 191-196 void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp_sec1
191
        const ValueRecovery& recovery = operands[index];
191
        const ValueRecovery& recovery = operands[index];
192
        
192
        
193
        switch (recovery.technique()) {
193
        switch (recovery.technique()) {
194
        case UnboxedDoubleInFPR:
194
        case InFPR:
195
        case InFPR:
195
            m_jit.move(AssemblyHelpers::TrustedImmPtr(scratch + index), GPRInfo::regT0);
196
            m_jit.move(AssemblyHelpers::TrustedImmPtr(scratch + index), GPRInfo::regT0);
196
            m_jit.storeDouble(recovery.fpr(), MacroAssembler::Address(GPRInfo::regT0));
197
            m_jit.storeDouble(recovery.fpr(), MacroAssembler::Address(GPRInfo::regT0));
Lines 261-266 void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp_sec2
261
        switch (recovery.technique()) {
262
        switch (recovery.technique()) {
262
        case InPair:
263
        case InPair:
263
        case DisplacedInJSStack:
264
        case DisplacedInJSStack:
265
        case InFPR:
264
            m_jit.load32(
266
            m_jit.load32(
265
                &bitwise_cast<EncodedValueDescriptor*>(scratch + index)->asBits.tag,
267
                &bitwise_cast<EncodedValueDescriptor*>(scratch + index)->asBits.tag,
266
                GPRInfo::regT0);
268
                GPRInfo::regT0);
Lines 275-281 void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp_sec3
275
                AssemblyHelpers::payloadFor(operand));
277
                AssemblyHelpers::payloadFor(operand));
276
            break;
278
            break;
277
            
279
            
278
        case InFPR:
280
        case UnboxedDoubleInFPR:
279
        case DoubleDisplacedInJSStack:
281
        case DoubleDisplacedInJSStack:
280
            m_jit.move(AssemblyHelpers::TrustedImmPtr(scratch + index), GPRInfo::regT0);
282
            m_jit.move(AssemblyHelpers::TrustedImmPtr(scratch + index), GPRInfo::regT0);
281
            m_jit.loadDouble(MacroAssembler::Address(GPRInfo::regT0), FPRInfo::fpRegT0);
283
            m_jit.loadDouble(MacroAssembler::Address(GPRInfo::regT0), FPRInfo::fpRegT0);
- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp -1 / +3 lines
Lines 209-214 void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp_sec1
209
        const ValueRecovery& recovery = operands[index];
209
        const ValueRecovery& recovery = operands[index];
210
        
210
        
211
        switch (recovery.technique()) {
211
        switch (recovery.technique()) {
212
        case UnboxedDoubleInFPR:
212
        case InFPR:
213
        case InFPR:
213
            m_jit.move(AssemblyHelpers::TrustedImmPtr(scratch + index), GPRInfo::regT0);
214
            m_jit.move(AssemblyHelpers::TrustedImmPtr(scratch + index), GPRInfo::regT0);
214
            m_jit.storeDouble(recovery.fpr(), MacroAssembler::Address(GPRInfo::regT0));
215
            m_jit.storeDouble(recovery.fpr(), MacroAssembler::Address(GPRInfo::regT0));
Lines 277-282 void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp_sec2
277
        case DisplacedInJSStack:
278
        case DisplacedInJSStack:
278
        case CellDisplacedInJSStack:
279
        case CellDisplacedInJSStack:
279
        case BooleanDisplacedInJSStack:
280
        case BooleanDisplacedInJSStack:
281
        case InFPR:
280
            m_jit.load64(scratch + index, GPRInfo::regT0);
282
            m_jit.load64(scratch + index, GPRInfo::regT0);
281
            m_jit.store64(GPRInfo::regT0, AssemblyHelpers::addressFor(operand));
283
            m_jit.store64(GPRInfo::regT0, AssemblyHelpers::addressFor(operand));
282
            break;
284
            break;
Lines 305-311 void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp_sec3
305
            m_jit.store64(GPRInfo::regT0, AssemblyHelpers::addressFor(operand));
307
            m_jit.store64(GPRInfo::regT0, AssemblyHelpers::addressFor(operand));
306
            break;
308
            break;
307
            
309
            
308
        case InFPR:
310
        case UnboxedDoubleInFPR:
309
        case DoubleDisplacedInJSStack:
311
        case DoubleDisplacedInJSStack:
310
            m_jit.move(AssemblyHelpers::TrustedImmPtr(scratch + index), GPRInfo::regT0);
312
            m_jit.move(AssemblyHelpers::TrustedImmPtr(scratch + index), GPRInfo::regT0);
311
            m_jit.loadDouble(MacroAssembler::Address(GPRInfo::regT0), FPRInfo::fpRegT0);
313
            m_jit.loadDouble(MacroAssembler::Address(GPRInfo::regT0), FPRInfo::fpRegT0);
- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp -38 / +64 lines
Lines 30-35 a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp_sec1
30
#if ENABLE(DFG_JIT)
30
#if ENABLE(DFG_JIT)
31
31
32
#include "ArrayPrototype.h"
32
#include "ArrayPrototype.h"
33
#include "CallFrameShuffler.h"
33
#include "DFGAbstractInterpreterInlines.h"
34
#include "DFGAbstractInterpreterInlines.h"
34
#include "DFGCallArrayAllocatorSlowPathGenerator.h"
35
#include "DFGCallArrayAllocatorSlowPathGenerator.h"
35
#include "DFGOperations.h"
36
#include "DFGOperations.h"
Lines 703-708 void SpeculativeJIT::emitCall(Node* node) a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp_sec2
703
    }
704
    }
704
705
705
    Edge calleeEdge = m_jit.graph().child(node, 0);
706
    Edge calleeEdge = m_jit.graph().child(node, 0);
707
    GPRReg calleeTagGPR;
708
    GPRReg calleePayloadGPR;
709
    CallFrameShuffleData shuffleData;
706
    
710
    
707
    // Gotta load the arguments somehow. Varargs is trickier.
711
    // Gotta load the arguments somehow. Varargs is trickier.
708
    if (isVarargs || isForwardVarargs) {
712
    if (isVarargs || isForwardVarargs) {
Lines 794-828 void SpeculativeJIT::emitCall(Node* node) a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp_sec3
794
        // receiver (method call). subsequent children are the arguments.
798
        // receiver (method call). subsequent children are the arguments.
795
        int numPassedArgs = node->numChildren() - 1;
799
        int numPassedArgs = node->numChildren() - 1;
796
800
797
        m_jit.store32(MacroAssembler::TrustedImm32(numPassedArgs), m_jit.calleeFramePayloadSlot(JSStack::ArgumentCount));
801
        if (node->op() == TailCall) {
802
            JSValueOperand callee(this, calleeEdge);
803
            calleeTagGPR = callee.tagGPR();
804
            calleePayloadGPR = callee.payloadGPR();
805
            use(calleeEdge);
806
807
            shuffleData.numLocals = m_jit.graph().frameRegisterCount();
808
            shuffleData.callee = ValueRecovery::inPair(calleeTagGPR, calleePayloadGPR);
809
            shuffleData.args.resize(numPassedArgs);
810
811
            for (int i = 0; i < numPassedArgs; ++i) {
812
                Edge argEdge = m_jit.graph().varArgChild(node, i + 1);
813
                GenerationInfo& info = generationInfo(argEdge.node());
814
                use(argEdge);
815
                shuffleData.args[i] = info.recovery(argEdge->virtualRegister());
816
            }
817
        } else {
818
            m_jit.store32(MacroAssembler::TrustedImm32(numPassedArgs), m_jit.calleeFramePayloadSlot(JSStack::ArgumentCount));
798
        
819
        
799
        for (int i = 0; i < numPassedArgs; i++) {
820
            for (int i = 0; i < numPassedArgs; i++) {
800
            Edge argEdge = m_jit.graph().m_varArgChildren[node->firstChild() + 1 + i];
821
                Edge argEdge = m_jit.graph().m_varArgChildren[node->firstChild() + 1 + i];
801
            JSValueOperand arg(this, argEdge);
822
                JSValueOperand arg(this, argEdge);
802
            GPRReg argTagGPR = arg.tagGPR();
823
                GPRReg argTagGPR = arg.tagGPR();
803
            GPRReg argPayloadGPR = arg.payloadGPR();
824
                GPRReg argPayloadGPR = arg.payloadGPR();
804
            use(argEdge);
825
                use(argEdge);
805
            
826
            
806
            m_jit.store32(argTagGPR, m_jit.calleeArgumentTagSlot(i));
827
                m_jit.store32(argTagGPR, m_jit.calleeArgumentTagSlot(i));
807
            m_jit.store32(argPayloadGPR, m_jit.calleeArgumentPayloadSlot(i));
828
                m_jit.store32(argPayloadGPR, m_jit.calleeArgumentPayloadSlot(i));
829
            }
808
        }
830
        }
809
    }
831
    }
810
832
811
    JSValueOperand callee(this, calleeEdge);
833
    if (node->op() != TailCall) {
812
    GPRReg calleeTagGPR = callee.tagGPR();
834
        JSValueOperand callee(this, calleeEdge);
813
    GPRReg calleePayloadGPR = callee.payloadGPR();
835
        calleeTagGPR = callee.tagGPR();
814
    use(calleeEdge);
836
        calleePayloadGPR = callee.payloadGPR();
815
    m_jit.store32(calleePayloadGPR, m_jit.calleeFramePayloadSlot(JSStack::Callee));
837
        use(calleeEdge);
816
    m_jit.store32(calleeTagGPR, m_jit.calleeFrameTagSlot(JSStack::Callee));
838
        m_jit.store32(calleePayloadGPR, m_jit.calleeFramePayloadSlot(JSStack::Callee));
839
        m_jit.store32(calleeTagGPR, m_jit.calleeFrameTagSlot(JSStack::Callee));
817
840
818
    // FIXME: We should do an efficient move of the arguments into
819
    // their target stack position instead of building then memmoving
820
    // the callee frame.
821
    // https://bugs.webkit.org/show_bug.cgi?id=147508
822
    if (isTail)
823
        ASSERT(isFlushed());
824
    else
825
        flushRegisters();
841
        flushRegisters();
842
    }
826
843
827
    GPRFlushedCallResult resultPayload(this);
844
    GPRFlushedCallResult resultPayload(this);
828
    GPRFlushedCallResult2 resultTag(this);
845
    GPRFlushedCallResult2 resultTag(this);
Lines 842-857 void SpeculativeJIT::emitCall(Node* node) a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp_sec4
842
    
859
    
843
    CallLinkInfo* info = m_jit.codeBlock()->addCallLinkInfo();
860
    CallLinkInfo* info = m_jit.codeBlock()->addCallLinkInfo();
844
861
845
    slowPath.append(m_jit.branchIfNotCell(callee.jsValueRegs()));
862
    if (isTail && node->op() != TailCall)
863
        m_jit.emitRestoreCalleeSaves();
864
865
    slowPath.append(m_jit.branchIfNotCell(JSValueRegs(calleeTagGPR, calleePayloadGPR)));
846
    slowPath.append(m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleePayloadGPR, targetToCheck));
866
    slowPath.append(m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleePayloadGPR, targetToCheck));
847
867
848
    if (isTail) {
868
    if (isTail) {
849
        m_jit.emitRestoreCalleeSaves();
869
        if (node->op() == TailCall) {
850
        // FIXME: We should do an efficient move of the arguments into
870
            info->setFrameShuffleData(shuffleData);
851
        // their target stack position instead of building then memmoving
871
            CallFrameShuffler(m_jit, shuffleData).prepareForTailCall();
852
        // the callee frame.
872
        } else
853
        // https://bugs.webkit.org/show_bug.cgi?id=147508
873
            m_jit.prepareForTailCallSlow();
854
        m_jit.prepareForTailCallSlow();
855
    }
874
    }
856
875
857
    JITCompiler::Call fastCall = isTail ? m_jit.nearTailCall() : m_jit.nearCall();
876
    JITCompiler::Call fastCall = isTail ? m_jit.nearTailCall() : m_jit.nearCall();
Lines 860-876 void SpeculativeJIT::emitCall(Node* node) a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp_sec5
860
879
861
    slowPath.link(&m_jit);
880
    slowPath.link(&m_jit);
862
881
863
    // Callee payload needs to be in regT0, tag in regT1
882
    if (node->op() == TailCall) {
864
    if (calleeTagGPR == GPRInfo::regT0) {
883
        CallFrameShuffler callFrameShuffler(m_jit, shuffleData);
865
        if (calleePayloadGPR == GPRInfo::regT1)
884
        callFrameShuffler.setCalleeJSValueRegs(JSValueRegs(
866
            m_jit.swap(GPRInfo::regT1, GPRInfo::regT0);
885
            GPRInfo::regT1, GPRInfo::regT0));
867
        else {
886
        callFrameShuffler.prepareForSlowPath();
868
            m_jit.move(calleeTagGPR, GPRInfo::regT1);
887
    } else {
888
        // Callee payload needs to be in regT0, tag in regT1
889
        if (calleeTagGPR == GPRInfo::regT0) {
890
            if (calleePayloadGPR == GPRInfo::regT1)
891
                m_jit.swap(GPRInfo::regT1, GPRInfo::regT0);
892
            else {
893
                m_jit.move(calleeTagGPR, GPRInfo::regT1);
894
                m_jit.move(calleePayloadGPR, GPRInfo::regT0);
895
            }
896
        } else {
869
            m_jit.move(calleePayloadGPR, GPRInfo::regT0);
897
            m_jit.move(calleePayloadGPR, GPRInfo::regT0);
898
            m_jit.move(calleeTagGPR, GPRInfo::regT1);
870
        }
899
        }
871
    } else {
872
        m_jit.move(calleePayloadGPR, GPRInfo::regT0);
873
        m_jit.move(calleeTagGPR, GPRInfo::regT1);
874
    }
900
    }
875
    m_jit.move(MacroAssembler::TrustedImmPtr(info), GPRInfo::regT2);
901
    m_jit.move(MacroAssembler::TrustedImmPtr(info), GPRInfo::regT2);
876
    JITCompiler::Call slowCall = m_jit.nearCall();
902
    JITCompiler::Call slowCall = m_jit.nearCall();
- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp -34 / +56 lines
Lines 29-34 a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp_sec1
29
#if ENABLE(DFG_JIT)
29
#if ENABLE(DFG_JIT)
30
30
31
#include "ArrayPrototype.h"
31
#include "ArrayPrototype.h"
32
#include "CallFrameShuffler.h"
32
#include "DFGAbstractInterpreterInlines.h"
33
#include "DFGAbstractInterpreterInlines.h"
33
#include "DFGCallArrayAllocatorSlowPathGenerator.h"
34
#include "DFGCallArrayAllocatorSlowPathGenerator.h"
34
#include "DFGOperations.h"
35
#include "DFGOperations.h"
Lines 688-694 void SpeculativeJIT::emitCall(Node* node) a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp_sec2
688
        break;
689
        break;
689
    }
690
    }
690
691
691
    Edge calleeEdge = m_jit.graph().child(node, 0);
692
    GPRReg calleeGPR;
693
    CallFrameShuffleData shuffleData;
692
    
694
    
693
    // Gotta load the arguments somehow. Varargs is trickier.
695
    // Gotta load the arguments somehow. Varargs is trickier.
694
    if (isVarargs || isForwardVarargs) {
696
    if (isVarargs || isForwardVarargs) {
Lines 775-808 void SpeculativeJIT::emitCall(Node* node) a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp_sec3
775
        // arguments.
777
        // arguments.
776
        int numPassedArgs = node->numChildren() - 1;
778
        int numPassedArgs = node->numChildren() - 1;
777
779
778
        m_jit.store32(MacroAssembler::TrustedImm32(numPassedArgs), JITCompiler::calleeFramePayloadSlot(JSStack::ArgumentCount));
780
        if (node->op() == TailCall) {
779
    
781
            Edge calleeEdge = m_jit.graph().child(node, 0);
780
        for (int i = 0; i < numPassedArgs; i++) {
782
            JSValueOperand callee(this, calleeEdge);
781
            Edge argEdge = m_jit.graph().m_varArgChildren[node->firstChild() + 1 + i];
783
            calleeGPR = callee.gpr();
782
            JSValueOperand arg(this, argEdge);
784
            callee.use();
783
            GPRReg argGPR = arg.gpr();
785
784
            use(argEdge);
786
            shuffleData.numLocals = m_jit.graph().frameRegisterCount();
785
        
787
            shuffleData.callee = ValueRecovery::inGPR(calleeGPR, DataFormatJS);
786
            m_jit.store64(argGPR, JITCompiler::calleeArgumentSlot(i));
788
            shuffleData.args.resize(numPassedArgs);
789
            
790
            for (int i = 0; i < numPassedArgs; ++i) {
791
                Edge argEdge = m_jit.graph().varArgChild(node, i + 1);
792
                GenerationInfo& info = generationInfo(argEdge.node());
793
                use(argEdge);
794
                shuffleData.args[i] = info.recovery(argEdge->virtualRegister());
795
            }
796
797
            shuffleData.setupCalleeSaveRegisters(m_jit.codeBlock());
798
        } else {
799
            m_jit.store32(MacroAssembler::TrustedImm32(numPassedArgs), JITCompiler::calleeFramePayloadSlot(JSStack::ArgumentCount));
800
801
            for (int i = 0; i < numPassedArgs; i++) {
802
                Edge argEdge = m_jit.graph().m_varArgChildren[node->firstChild() + 1 + i];
803
                JSValueOperand arg(this, argEdge);
804
                GPRReg argGPR = arg.gpr();
805
                use(argEdge);
806
807
                m_jit.store64(argGPR, JITCompiler::calleeArgumentSlot(i));
808
            }
787
        }
809
        }
788
    }
810
    }
789
811
790
    JSValueOperand callee(this, calleeEdge);
812
    if (node->op() != TailCall) {
791
    GPRReg calleeGPR = callee.gpr();
813
        Edge calleeEdge = m_jit.graph().child(node, 0);
792
    callee.use();
814
        JSValueOperand callee(this, calleeEdge);
793
    m_jit.store64(calleeGPR, JITCompiler::calleeFrameSlot(JSStack::Callee));
815
        calleeGPR = callee.gpr();
816
        callee.use();
817
        m_jit.store64(calleeGPR, JITCompiler::calleeFrameSlot(JSStack::Callee));
794
818
795
    // FIXME: We should do an efficient move of the arguments into
796
    // their target stack position instead of building then memmoving
797
    // the callee frame.
798
    // https://bugs.webkit.org/show_bug.cgi?id=147508
799
    if (isTail)
800
        ASSERT(isFlushed());
801
    else
802
        flushRegisters();
819
        flushRegisters();
803
820
    }
804
    GPRFlushedCallResult result(this);
805
    GPRReg resultGPR = result.gpr();
806
821
807
    CodeOrigin staticOrigin = node->origin.semantic;
822
    CodeOrigin staticOrigin = node->origin.semantic;
808
    ASSERT(!isTail || !staticOrigin.inlineCallFrame || !staticOrigin.inlineCallFrame->getCallerSkippingDeadFrames());
823
    ASSERT(!isTail || !staticOrigin.inlineCallFrame || !staticOrigin.inlineCallFrame->getCallerSkippingDeadFrames());
Lines 814-829 void SpeculativeJIT::emitCall(Node* node) a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp_sec4
814
    
829
    
815
    CallLinkInfo* callLinkInfo = m_jit.codeBlock()->addCallLinkInfo();
830
    CallLinkInfo* callLinkInfo = m_jit.codeBlock()->addCallLinkInfo();
816
831
832
    if (isTail && node->op() != TailCall)
833
        m_jit.emitRestoreCalleeSaves();
834
817
    JITCompiler::DataLabelPtr targetToCheck;
835
    JITCompiler::DataLabelPtr targetToCheck;
818
    JITCompiler::Jump slowPath = m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleeGPR, targetToCheck, MacroAssembler::TrustedImmPtr(0));
836
    JITCompiler::Jump slowPath = m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleeGPR, targetToCheck, MacroAssembler::TrustedImmPtr(0));
819
837
820
    if (isTail) {
838
    if (isTail) {
821
        m_jit.emitRestoreCalleeSaves();
839
        if (node->op() == TailCall) {
822
        // FIXME: We should do an efficient move of the arguments into
840
            callLinkInfo->setFrameShuffleData(shuffleData);
823
        // their target stack position instead of building then memmoving
841
            CallFrameShuffler(m_jit, shuffleData).prepareForTailCall();
824
        // the callee frame.
842
        } else
825
        // https://bugs.webkit.org/show_bug.cgi?id=147508
843
            m_jit.prepareForTailCallSlow();
826
        m_jit.prepareForTailCallSlow();
827
    }
844
    }
828
845
829
    JITCompiler::Call fastCall = isTail ? m_jit.nearTailCall() : m_jit.nearCall();
846
    JITCompiler::Call fastCall = isTail ? m_jit.nearTailCall() : m_jit.nearCall();
Lines 831-841 void SpeculativeJIT::emitCall(Node* node) a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp_sec5
831
    JITCompiler::Jump done = m_jit.jump();
848
    JITCompiler::Jump done = m_jit.jump();
832
    
849
    
833
    slowPath.link(&m_jit);
850
    slowPath.link(&m_jit);
834
    
835
    if (isTail)
836
        m_jit.emitRestoreCalleeSaves();
837
851
838
    m_jit.move(calleeGPR, GPRInfo::regT0); // Callee needs to be in regT0
852
    if (node->op() == TailCall) {
853
        CallFrameShuffler callFrameShuffler(m_jit, shuffleData);
854
        callFrameShuffler.setCalleeJSValueRegs(JSValueRegs(GPRInfo::regT0));
855
        callFrameShuffler.prepareForSlowPath();
856
    } else
857
        m_jit.move(calleeGPR, GPRInfo::regT0); // Callee needs to be in regT0
858
839
    m_jit.move(MacroAssembler::TrustedImmPtr(callLinkInfo), GPRInfo::regT2); // Link info needs to be in regT2
859
    m_jit.move(MacroAssembler::TrustedImmPtr(callLinkInfo), GPRInfo::regT2); // Link info needs to be in regT2
840
    JITCompiler::Call slowCall = m_jit.nearCall();
860
    JITCompiler::Call slowCall = m_jit.nearCall();
841
861
Lines 844-849 void SpeculativeJIT::emitCall(Node* node) a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp_sec6
844
    if (isTail)
864
    if (isTail)
845
        m_jit.abortWithReason(JITDidReturnFromTailCall);
865
        m_jit.abortWithReason(JITDidReturnFromTailCall);
846
    else {
866
    else {
867
        GPRFlushedCallResult result(this);
868
        GPRReg resultGPR = result.gpr();
847
        m_jit.move(GPRInfo::returnValueGPR, resultGPR);
869
        m_jit.move(GPRInfo::returnValueGPR, resultGPR);
848
870
849
        jsValueResult(resultGPR, m_currentNode, DataFormatJS, UseChildrenCalledExplicitly);
871
        jsValueResult(resultGPR, m_currentNode, DataFormatJS, UseChildrenCalledExplicitly);
- a/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp -1 / +1 lines
Lines 208-214 void VariableEventStream::reconstruct( a/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp_sec1
208
        
208
        
209
        if (info.filled) {
209
        if (info.filled) {
210
            if (info.format == DataFormatDouble) {
210
            if (info.format == DataFormatDouble) {
211
                valueRecoveries[i] = ValueRecovery::inFPR(info.u.fpr);
211
                valueRecoveries[i] = ValueRecovery::inFPR(info.u.fpr, DataFormatDouble);
212
                continue;
212
                continue;
213
            }
213
            }
214
#if USE(JSVALUE32_64)
214
#if USE(JSVALUE32_64)
- a/Source/JavaScriptCore/jit/CallFrameShuffleData.cpp +73 lines
Line 0 a/Source/JavaScriptCore/jit/CallFrameShuffleData.cpp_sec1
1
/*
2
 * Copyright (C) 2015 Apple Inc. All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 * 1. Redistributions of source code must retain the above copyright
8
 *    notice, this list of conditions and the following disclaimer.
9
 * 2. Redistributions in binary form must reproduce the above copyright
10
 *    notice, this list of conditions and the following disclaimer in the
11
 *    documentation and/or other materials provided with the distribution.
12
 *
13
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24
 */
25
26
#include "config.h"
27
#include "CallFrameShuffleData.h"
28
29
#if ENABLE(JIT)
30
31
#include "CCallHelpers.h"
32
#include "CodeBlock.h"
33
34
namespace JSC {
35
36
#if USE(JSVALUE64)
37
38
void CallFrameShuffleData::setupCalleeSaveRegisters(CodeBlock* codeBlock)
39
{
40
    RegisterSet calleeSaveRegisters { RegisterSet::allVMCalleeSaveRegisters() };
41
    RegisterAtOffsetList* registerSaveLocations = codeBlock->calleeSaveRegisters();
42
43
    for (size_t i { 0 }; i < registerSaveLocations->size(); ++i) {
44
        RegisterAtOffset entry { registerSaveLocations->at(i) };
45
        if (!calleeSaveRegisters.get(entry.reg()))
46
            continue;
47
48
        ASSERT(entry.reg().isGPR());
49
50
        VirtualRegister saveSlot { entry.offsetAsIndex() };
51
        registers[entry.reg()]
52
            = ValueRecovery::displacedInJSStack(saveSlot, DataFormatJS);
53
    }
54
55
    for (Reg reg { Reg::first() }; reg <= Reg::last(); reg = reg.next()) {
56
        if (!calleeSaveRegisters.get(reg))
57
            continue;
58
59
        if (registers[reg])
60
            continue;
61
62
        ASSERT(reg.isGPR());
63
64
        registers[reg]
65
            = ValueRecovery::inGPR(reg.gpr(), DataFormatJS);
66
    }
67
}
68
69
#endif // USE(JSVALUE64)
70
71
} // namespace JSC
72
73
#endif // ENABLE(JIT)
- a/Source/JavaScriptCore/jit/CallFrameShuffleData.h +51 lines
Line 0 a/Source/JavaScriptCore/jit/CallFrameShuffleData.h_sec1
1
/*
2
 * Copyright (C) 2015 Apple Inc. All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 * 1. Redistributions of source code must retain the above copyright
8
 *    notice, this list of conditions and the following disclaimer.
9
 * 2. Redistributions in binary form must reproduce the above copyright
10
 *    notice, this list of conditions and the following disclaimer in the
11
 *    documentation and/or other materials provided with the distribution.
12
 *
13
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24
 */
25
26
#ifndef CallFrameShuffleData_h
27
#define CallFrameShuffleData_h
28
29
#if ENABLE(JIT)
30
31
#include "RegisterMap.h"
32
#include "ValueRecovery.h"
33
34
namespace JSC {
35
36
struct CallFrameShuffleData {
37
    unsigned numLocals;
38
    ValueRecovery callee;
39
    Vector<ValueRecovery> args;
40
#if USE(JSVALUE64)
41
    RegisterMap<ValueRecovery> registers;
42
43
    void setupCalleeSaveRegisters(CodeBlock*);
44
#endif
45
};
46
47
} // namespace JSC
48
49
#endif // ENABLE(JIT)
50
51
#endif // CallFrameShuffleData_h
- a/Source/JavaScriptCore/jit/CallFrameShuffler.cpp +703 lines
Line 0 a/Source/JavaScriptCore/jit/CallFrameShuffler.cpp_sec1
1
/*
2
 * Copyright (C) 2015 Apple Inc. All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 * 1. Redistributions of source code must retain the above copyright
8
 *    notice, this list of conditions and the following disclaimer.
9
 * 2. Redistributions in binary form must reproduce the above copyright
10
 *    notice, this list of conditions and the following disclaimer in the
11
 *    documentation and/or other materials provided with the distribution.
12
 *
13
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24
 */
25
26
#include "config.h"
27
#include "CallFrameShuffler.h"
28
29
#if ENABLE(JIT)
30
31
#include "CCallHelpers.h"
32
#include "CodeBlock.h"
33
34
namespace JSC {
35
36
CallFrameShuffler::CallFrameShuffler(CCallHelpers& jit, const CallFrameShuffleData& data)
37
    : m_jit(jit)
38
    , m_oldFrame(data.numLocals + JSStack::CallerFrameAndPCSize, nullptr)
39
    , m_newFrame(data.args.size() + JSStack::CallFrameHeaderSize, nullptr)
40
    , m_alignedOldFrameSize(JSStack::CallFrameHeaderSize
41
        + roundArgumentCountToAlignFrame(jit.codeBlock()->numParameters()))
42
    , m_alignedNewFrameSize(JSStack::CallFrameHeaderSize
43
        + roundArgumentCountToAlignFrame(data.args.size()))
44
    , m_lockedRegisters(RegisterSet::allRegisters())
45
{
46
    // We are allowed all the usual registers...
47
    for (unsigned i { GPRInfo::numberOfRegisters }; i--; )
48
        m_lockedRegisters.clear(GPRInfo::toRegister(i));
49
    for (unsigned i { FPRInfo::numberOfRegisters }; i--; )
50
        m_lockedRegisters.clear(FPRInfo::toRegister(i));
51
    // ... as well as the runtime registers.
52
    m_lockedRegisters.exclude(RegisterSet::runtimeRegisters());
53
54
    ASSERT(!data.callee.isInJSStack() || data.callee.virtualRegister().isLocal());
55
    addNew(VirtualRegister(JSStack::Callee), data.callee);
56
57
    for (size_t i { 0 }; i < data.args.size(); ++i) {
58
        ASSERT(!data.args[i].isInJSStack() || data.args[i].virtualRegister().isLocal());
59
        addNew(virtualRegisterForArgument(i), data.args[i]);
60
    }
61
62
#if USE(JSVALUE64)
63
    for (Reg reg { Reg::first() }; reg <= Reg::last(); reg = reg.next()) {
64
        if (!data.registers[reg].isSet())
65
            continue;
66
67
        RELEASE_ASSERT(reg.isGPR());
68
69
        addNew(JSValueRegs(reg.gpr()),
70
            data.registers[reg]);
71
    }
72
#endif
73
}
74
75
void CallFrameShuffler::dump(PrintStream& out) const
76
{
77
    static const char* delimiter             = " +-------------------------------+ ";
78
    static const char* dangerDelimiter       = " X-------------------------------X ";
79
    static const char* dangerBoundsDelimiter = " XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ";
80
    static const char* emptySpace            = "                                   ";
81
    ASSERT(m_alignedNewFrameSize <= numLocals());
82
    out.print("          ");
83
    out.print("           Old frame               ");
84
    out.print("           New frame               ");
85
    out.print("\n");
86
    for (int i { 0 }; i < m_alignedOldFrameSize + numLocals() + 3; ++i) {
87
        VirtualRegister old { m_alignedOldFrameSize - i - 1 };
88
        VirtualRegister newReg { old + m_frameDelta };
89
90
        if (!isValidOld(old) && old != firstOld() - 1
91
            && !isValidNew(newReg) && newReg != firstNew() - 1)
92
            continue;
93
94
        out.print("        ");
95
        if (dangerFrontier() >= firstNew()
96
            && (newReg == dangerFrontier() || newReg == firstNew() - 1))
97
            out.print(dangerBoundsDelimiter);
98
        else if (isValidOld(old))
99
            out.print(isValidNew(newReg) && isDangerNew(newReg) ? dangerDelimiter : delimiter);
100
        else if (old == firstOld() - 1)
101
            out.print(delimiter);
102
        else
103
            out.print(emptySpace);
104
        if (dangerFrontier() >= firstNew()
105
            && (newReg == dangerFrontier() || newReg == firstNew() - 1))
106
            out.print(dangerBoundsDelimiter);
107
        else if (isValidNew(newReg) || newReg == firstNew() - 1)
108
            out.print(isDangerNew(newReg) ? dangerDelimiter : delimiter);
109
        else
110
            out.print(emptySpace);
111
        out.print("\n");
112
        if (old == firstOld())
113
            out.print(" sp --> ");
114
        else if (!old.offset())
115
            out.print(" fp --> ");
116
        else
117
            out.print("        ");
118
        if (isValidOld(old)) {
119
            if (getOld(old)) {
120
                auto str = toCString(old);
121
                if (isValidNew(newReg) && isDangerNew(newReg))
122
                    out.printf(" X      %18s       X ", str.data());
123
                else
124
                    out.printf(" |      %18s       | ", str.data());
125
            } else if (isValidNew(newReg) && isDangerNew(newReg))
126
                out.printf(" X%30s X ", "");
127
            else
128
                out.printf(" |%30s | ", "");
129
        } else
130
            out.print(emptySpace);
131
        if (isValidNew(newReg)) {
132
            const char d = isDangerNew(newReg) ? 'X' : '|';
133
            auto str = toCString(newReg);
134
            if (getNew(newReg)) {
135
                if (getNew(newReg)->recovery().isConstant())
136
                    out.printf(" %c%8s <-           constant %c ", d, str.data(), d);
137
                else {
138
                    auto recoveryStr = toCString(getNew(newReg)->recovery());
139
                    out.printf(" %c%8s <- %18s %c ", d, str.data(),
140
                        recoveryStr.data(), d);
141
                }
142
            } else if (newReg == VirtualRegister { JSStack::ArgumentCount })
143
                out.printf(" %c%8s <- %18zu %c ", d, str.data(), argCount(), d);
144
            else
145
                out.printf(" %c%30s %c ", d, "", d);
146
        } else
147
            out.print(emptySpace);
148
        if (newReg == firstNew() - m_newFrameOffset && !isSlowPath())
149
            out.print(" <-- new sp before jump (current ", m_newFrameBase, ") ");
150
        if (newReg == firstNew())
151
            out.print(" <-- new fp after prologue");
152
        out.print("\n");
153
    }
154
    out.print("          ");
155
    out.print("        Live registers             ");
156
    out.print("        Wanted registers           ");
157
    out.print("\n");
158
    for (Reg reg { Reg::first() }; reg <= Reg::last(); reg = reg.next()) {
159
        if (!reg.isGPR())
160
            continue;
161
162
        CachedRecovery* oldCachedRecovery { m_registers[reg.gpr()] };
163
        CachedRecovery* newCachedRecovery { m_newRegisters[reg.gpr()] };
164
        if (!oldCachedRecovery && !newCachedRecovery)
165
            continue;
166
        out.print("          ");
167
        if (oldCachedRecovery) {
168
            auto str = toCString(reg.gpr());
169
            out.printf("         %8s                  ", str.data());
170
        } else
171
            out.print(emptySpace);
172
#if USE(JSVALUE32_64)
173
        if (newCachedRecovery) {
174
            JSValueRegs wantedJSValueRegs { newCachedRecovery->wantedJSValueRegs() };
175
            if (reg.gpr() == wantedJSValueRegs.tagGPR())
176
                out.print(reg.gpr(), " <- tag(", newCachedRecovery->recovery(), ")");
177
            else
178
                out.print(reg.gpr(), " <- payload(", newCachedRecovery->recovery(), ")");
179
        }
180
#else
181
        if (newCachedRecovery)
182
            out.print("         ", reg.gpr(), " <- ", newCachedRecovery->recovery());
183
#endif
184
        out.print("\n");
185
    }
186
    out.print("  Locked registers: ");
187
    bool firstLocked { true };
188
    for (Reg reg { Reg::first() }; reg <= Reg::last(); reg = reg.next()) {
189
        if (!reg.isGPR())
190
            continue;
191
192
        if (m_lockedRegisters.get(reg.gpr())) {
193
            out.print(firstLocked ? "" : ", ", reg.gpr());
194
            firstLocked = false;
195
        }
196
    }
197
    out.print("\n");
198
199
    if (isSlowPath())
200
        out.print("  Using fp-relative addressing for slow path call\n");
201
    else
202
        out.print("  Using sp-relative addressing for jump (using ", m_newFrameBase, " as new sp)\n");
203
    if (m_oldFrameOffset)
204
        out.print("   Old frame offset is ", m_oldFrameOffset, "\n");
205
    if (m_newFrameOffset)
206
        out.print("   New frame offset is ", m_newFrameOffset, "\n");
207
}
208
209
CachedRecovery* CallFrameShuffler::getCachedRecovery(ValueRecovery recovery)
210
{
211
    ASSERT(!recovery.isConstant());
212
    if (recovery.isInGPR())
213
        return m_registers[recovery.gpr()];
214
    if (recovery.isInFPR())
215
        return m_registers[recovery.fpr()];
216
#if USE(JSVALUE32_64)
217
    if (recovery.technique() == InPair) {
218
        ASSERT(m_registers[recovery.tagGPR()] == m_registers[recovery.payloadGPR()]);
219
        return m_registers[recovery.payloadGPR()];
220
    }
221
#endif
222
    ASSERT(recovery.isInJSStack());
223
    return getOld(recovery.virtualRegister());
224
}
225
226
CachedRecovery* CallFrameShuffler::setCachedRecovery(ValueRecovery recovery, CachedRecovery* cachedRecovery)
227
{
228
    ASSERT(!recovery.isConstant());
229
    if (recovery.isInGPR())
230
        return m_registers[recovery.gpr()] = cachedRecovery;
231
    if (recovery.isInFPR())
232
        return m_registers[recovery.fpr()] = cachedRecovery;
233
#if USE(JSVALUE32_64)
234
    if (recovery.technique() == InPair) {
235
        m_registers[recovery.tagGPR()] = cachedRecovery;
236
        return m_registers[recovery.payloadGPR()] = cachedRecovery;
237
    }
238
#endif
239
    ASSERT(recovery.isInJSStack());
240
    setOld(recovery.virtualRegister(), cachedRecovery);
241
    return cachedRecovery;
242
}
243
244
void CallFrameShuffler::spill(CachedRecovery& cachedRecovery)
245
{
246
    ASSERT(!isSlowPath());
247
    ASSERT(cachedRecovery.recovery().isInRegisters());
248
249
    VirtualRegister spillSlot { 0 };
250
    for (VirtualRegister slot { firstOld() }; slot <= lastOld(); slot -= 1) {
251
        ASSERT(slot < newAsOld(firstNew()));
252
        if (getOld(slot))
253
            continue;
254
255
        spillSlot = slot;
256
        break;
257
    }
258
    // We must have enough slots to be able to fit the whole
259
    // callee's frame for the slow path.
260
    RELEASE_ASSERT(spillSlot.isLocal());
261
262
    if (verbose)
263
        dataLog("   * Spilling ", cachedRecovery.recovery(), " into ", spillSlot, "\n");
264
    auto format = emitStore(cachedRecovery, addressForOld(spillSlot));
265
    ASSERT(format != DataFormatNone);
266
    updateRecovery(cachedRecovery, ValueRecovery::displacedInJSStack(spillSlot, format));
267
}
268
269
void CallFrameShuffler::emitDeltaCheck()
270
{
271
    if (!ASSERT_DISABLED)
272
        return;
273
274
    GPRReg scratchGPR { getFreeGPR() };
275
    if (scratchGPR != InvalidGPRReg) {
276
        if (verbose)
277
            dataLog("  Using ", scratchGPR, " for the fp-sp delta check\n");
278
        m_jit.move(GPRInfo::callFrameRegister, scratchGPR);
279
        m_jit.subPtr(MacroAssembler::stackPointerRegister, scratchGPR);
280
        MacroAssembler::Jump ok = m_jit.branch32(
281
            MacroAssembler::Equal, scratchGPR,
282
            MacroAssembler::TrustedImm32(
283
                static_cast<size_t>(sizeof(Register) * numLocals())));
284
        m_jit.abortWithReason(JITUnexpectedCallFrameSize);
285
        ok.link(&m_jit);
286
    } else if (verbose)
287
        dataLog("  Skipping the fp-sp delta check since there is too much pressure");
288
}
289
290
void CallFrameShuffler::prepareForSlowPath()
291
{
292
    ASSERT(isUndecided());
293
    emitDeltaCheck();
294
295
    m_frameDelta = numLocals() + JSStack::CallerFrameAndPCSize;
296
    m_newFrameBase = MacroAssembler::stackPointerRegister;
297
    m_newFrameOffset = -JSStack::CallerFrameAndPCSize;
298
299
    if (verbose)
300
        dataLog("\n\nPreparing frame for slow path call:\n", *this);
301
302
    prepareAny();
303
304
    if (verbose)
305
        dataLog("Ready for slow path call!\n");
306
}
307
308
void CallFrameShuffler::prepareForTailCall()
309
{
310
    ASSERT(isUndecided());
311
    emitDeltaCheck();
312
313
    // We'll use sp-based indexing so that we can load the
314
    // caller's frame pointer into the fpr immediately
315
    m_oldFrameBase = MacroAssembler::stackPointerRegister;
316
    m_oldFrameOffset = numLocals();
317
    m_newFrameBase = acquireGPR();
318
#if CPU(X86)
319
    // We load the frame pointer manually, but we need to ask the
320
    // algorithm to move the return PC for us (it'd probably
321
    // require a write to the danger zone). Since it'd be awkward
322
    // to ask for half a value move, we ask that the whole thing
323
    // be moved for us.
324
    addNew(VirtualRegister { 0 },
325
        ValueRecovery::displacedInJSStack(VirtualRegister(0), DataFormatJS));
326
327
    // sp will point to head0 and we will move it up half a slot
328
    // manually
329
    m_newFrameOffset = 0;
330
#elif CPU(ARM) || CPU(SH4) || CPU(MIPS)
331
    // We load the the frame pointer and link register
332
    // manually. We could ask the algorithm to load them for us,
333
    // and it would allow us to use the link register as an extra
334
    // temporary - but it'd mean that the frame pointer can also
335
    // be used as an extra temporary, so we keep the link register
336
    // locked instead.
337
338
    // sp will point to head1 since the callee's prologue pushes
339
    // the call frame and link register.
340
    m_newFrameOffset = -1;
341
#elif CPU(ARM64)
342
    // We load the frame pointer and link register manually. We
343
    // could ask the algorithm to load the link register for us
344
    // (which would allow for its use as an extra temporary), but
345
    // since its not in GPRInfo, we can't do it.
346
347
    // sp will point to head2 since the callee's prologue pushes the
348
    // call frame and link register
349
    m_newFrameOffset = -2;
350
#elif CPU(X86_64)
351
    // We load the frame pointer manually, but we ask the
352
    // algorithm to move the return PC for us (it'd probably
353
    // require a write in the danger zone)
354
    addNew(VirtualRegister { 1 },
355
        ValueRecovery::displacedInJSStack(VirtualRegister(1), DataFormatJS));
356
357
    // sp will point to head1 since the callee's prologue pushes
358
    // the call frame register
359
    m_newFrameOffset = -1;
360
#else
361
    UNREACHABLE_FOR_PLATFORM();
362
#endif
363
364
    if (verbose)
365
        dataLog("  Emitting code for computing the new frame base\n");
366
367
    // We compute the new frame base by first computing the top of the
368
    // old frame (taking into account an argument count higher than
369
    // the number of parameters), then substracting to it the aligned
370
    // new frame size (adjusted).
371
    m_jit.load32(MacroAssembler::Address(GPRInfo::callFrameRegister, JSStack::ArgumentCount * static_cast<int>(sizeof(Register)) + PayloadOffset), m_newFrameBase);
372
    MacroAssembler::Jump argumentCountOK =
373
        m_jit.branch32(MacroAssembler::BelowOrEqual, m_newFrameBase,
374
            MacroAssembler::TrustedImm32(m_jit.codeBlock()->numParameters()));
375
    m_jit.add32(MacroAssembler::TrustedImm32(stackAlignmentRegisters() - 1 + JSStack::CallFrameHeaderSize), m_newFrameBase);
376
    m_jit.and32(MacroAssembler::TrustedImm32(-stackAlignmentRegisters()), m_newFrameBase);
377
    m_jit.mul32(MacroAssembler::TrustedImm32(sizeof(Register)), m_newFrameBase, m_newFrameBase);
378
    MacroAssembler::Jump done = m_jit.jump();
379
    argumentCountOK.link(&m_jit);
380
    m_jit.move(
381
        MacroAssembler::TrustedImm32(m_alignedOldFrameSize * sizeof(Register)),
382
        m_newFrameBase);
383
    done.link(&m_jit);
384
385
    m_jit.addPtr(GPRInfo::callFrameRegister, m_newFrameBase);
386
    m_jit.subPtr(
387
        MacroAssembler::TrustedImm32(
388
            (m_alignedNewFrameSize + m_newFrameOffset) * sizeof(Register)), 
389
        m_newFrameBase);
390
391
    // We want the frame pointer to always point to a valid frame, and
392
    // we are going to trash the current one. Let's make it point to
393
    // our caller's frame, since that's what we want to end up with.
394
    m_jit.loadPtr(MacroAssembler::Address(MacroAssembler::framePointerRegister),
395
        MacroAssembler::framePointerRegister);
396
397
    // We load the link register manually for architectures that have one
398
#if CPU(ARM) || CPU(SH4) || CPU(ARM64)
399
    m_jit.loadPtr(MacroAssembler::Address(MacroAssembler::framePointerRegister, sizeof(void*)),
400
        MacroAssembler::linkRegister);
401
#elif CPU(MIPS)
402
    m_jit.loadPtr(MacroAssembler::Address(MacroAssembler::framePointerRegister, sizeof(void*)),
403
        MacroAssembler::returnAddressRegister);
404
#endif
405
406
    if (verbose)
407
        dataLog("Preparing frame for tail call:\n", *this);
408
409
    prepareAny();
410
411
#if CPU(X86)
412
    if (verbose)
413
        dataLog("  Simulating pop of the call frame register\n");
414
    m_jit.addPtr(MacroAssembler::TrustedImm32(sizeof(void*)), MacroAssembler::stackPointerRegister);
415
#endif
416
417
    if (verbose)
418
        dataLog("Ready for tail call!\n");
419
}
420
421
bool CallFrameShuffler::tryWrites(CachedRecovery& cachedRecovery)
422
{
423
    ASSERT(m_newFrameBase != InvalidGPRReg);
424
425
    // If the value is already set up correctly, we don't have
426
    // anything to do.
427
    if (isSlowPath() && cachedRecovery.recovery().isInJSStack()
428
        && cachedRecovery.targets().size() == 1
429
        && (newAsOld(cachedRecovery.targets()[0])
430
            == cachedRecovery.recovery().virtualRegister())) {
431
        cachedRecovery.clearTargets();
432
        if (!cachedRecovery.wantedJSValueRegs())
433
            clearCachedRecovery(cachedRecovery.recovery());
434
        return true;
435
    }
436
437
    if (!canLoadAndBox(cachedRecovery))
438
        return false;
439
440
    emitLoad(cachedRecovery);
441
    emitBox(cachedRecovery);
442
    ASSERT(cachedRecovery.recovery().isInRegisters()
443
        || cachedRecovery.recovery().isConstant());
444
445
    if (verbose)
446
        dataLog("   * Storing ", cachedRecovery.recovery());
447
    for (size_t i { 0 }; i < cachedRecovery.targets().size(); ++i) {
448
        VirtualRegister target { cachedRecovery.targets()[i] };
449
        ASSERT(!isDangerNew(target));
450
        if (verbose)
451
            dataLog(!i ? " into " : ", and ", "NEW ", target);
452
        emitStore(cachedRecovery, addressForNew(target));
453
        setNew(target, nullptr);
454
    }
455
    if (verbose)
456
        dataLog("\n");
457
    cachedRecovery.clearTargets();
458
    if (!cachedRecovery.wantedJSValueRegs())
459
        clearCachedRecovery(cachedRecovery.recovery());
460
461
    return true;
462
}
463
464
bool CallFrameShuffler::performSafeWrites()
465
{
466
    VirtualRegister firstSafe;
467
    VirtualRegister end { lastNew() + 1 };
468
    Vector<VirtualRegister> failures;
469
470
    // For all cachedRecoveries that writes to the safe zone, if it
471
    // doesn't also write to the danger zone, we try to perform
472
    // the writes. This may free up danger slots, so we iterate
473
    // again until it doesn't happen anymore.
474
    //
475
    // Note that even though we have a while block, we look at
476
    // each slot of the new call frame at most once since in each
477
    // iteration beyond the first, we only load up the portion of
478
    // the new call frame that was dangerous and became safe due
479
    // to the previous iteration.
480
    do {
481
        firstSafe = dangerFrontier() + 1;
482
        if (verbose)
483
            dataLog("  Trying safe writes (between NEW ", firstSafe, " and NEW ", end - 1, ")\n");
484
        bool didProgress = false;
485
        for (VirtualRegister reg { firstSafe }; reg < end; reg += 1) {
486
            CachedRecovery* cachedRecovery = getNew(reg);
487
            if (!cachedRecovery) {
488
                if (verbose)
489
                    dataLog("   + ", reg, " is OK.\n");
490
                continue;
491
            }
492
            if (!hasOnlySafeWrites(*cachedRecovery)) {
493
                if (verbose) {
494
                    dataLog("   - ", cachedRecovery->recovery(), " writes to NEW ", reg,
495
                        " but also has dangerous writes.\n");
496
                }
497
                continue;
498
            }
499
            if (cachedRecovery->wantedJSValueRegs()) {
500
                if (verbose) {
501
                    dataLog("   - ", cachedRecovery->recovery(), " writes to NEW ", reg,
502
                        " but is also needed in registers.\n");
503
                }
504
                continue;
505
            }
506
            if (!tryWrites(*cachedRecovery)) {
507
                if (verbose)
508
                    dataLog("   - Unable to write to NEW ", reg, " from ", cachedRecovery->recovery(), "\n");
509
                failures.append(reg);
510
            }
511
            didProgress = true;
512
        }
513
        end = firstSafe;
514
515
        // If we have cachedRecoveries that failed to write, it is
516
        // because they are on the stack and we didn't have enough
517
        // registers available at the time to load them into. If
518
        // we have a free register, we should try again because it
519
        // could free up some danger slots.
520
        if (didProgress && hasFreeRegister()) {
521
            Vector<VirtualRegister> stillFailing;
522
            for (VirtualRegister failed : failures) {
523
                CachedRecovery* cachedRecovery = getNew(failed);
524
                // It could have been handled later if it had
525
                // several targets
526
                if (!cachedRecovery)
527
                    continue;
528
529
                ASSERT(hasOnlySafeWrites(*cachedRecovery)
530
                    && !cachedRecovery->wantedJSValueRegs());
531
                if (!tryWrites(*cachedRecovery))
532
                    stillFailing.append(failed);
533
            }
534
            failures = WTF::move(stillFailing);
535
        }
536
        if (verbose && firstSafe != dangerFrontier() + 1)
537
            dataLog("  We freed up danger slots!\n");
538
    } while (firstSafe != dangerFrontier() + 1);
539
540
    return failures.isEmpty();
541
}
542
543
void CallFrameShuffler::prepareAny()
544
{
545
    ASSERT(!isUndecided());
546
547
    updateDangerFrontier();
548
549
    // First, we try to store any value that goes above the danger
550
    // frontier. This will never use more registers since we are only
551
    // loading+storing if we ensure that any register used for the load
552
    // will be freed up after the stores (i.e., all stores are above
553
    // the danger frontier, and there is no wanted register).
554
    performSafeWrites();
555
556
    // At this point, we couldn't have more available registers than
557
    // we have withouth spilling: all values currently in registers
558
    // either require a write to the danger zone, or have a wanted
559
    // register, which means that in any case they will have to go
560
    // through registers again.
561
562
    // We now slowly free up the danger zone by first loading the old
563
    // value on the danger frontier, spilling as many registers as
564
    // needed to do so and ensuring that the corresponding slot in the
565
    // new frame is now ready to be written. Then, we store the old
566
    // value to its target location if possible (we could have failed
567
    // to load it previously due to high pressure). Finally, we write
568
    // to any of the newly safe slots that we can, which could free up
569
    // registers (hence why we do it eagerly).
570
    for (VirtualRegister reg { dangerFrontier() }; reg >= firstNew(); reg -= 1) {
571
        if (reg == dangerFrontier()) {
572
            if (verbose)
573
                dataLog("  Next slot (NEW ", reg, ") is the danger frontier\n");
574
            CachedRecovery* cachedRecovery { getOld(newAsOld(dangerFrontier())) };
575
            ASSERT(cachedRecovery);
576
            ensureLoad(*cachedRecovery);
577
            emitLoad(*cachedRecovery);
578
            ensureBox(*cachedRecovery);
579
            emitBox(*cachedRecovery);
580
            if (hasOnlySafeWrites(*cachedRecovery))
581
                tryWrites(*cachedRecovery);
582
        } else if (verbose)
583
            dataLog("  Next slot is NEW ", reg, "\n");
584
585
        ASSERT(!isDangerNew(reg));
586
        CachedRecovery* cachedRecovery = getNew(reg);
587
        // This could be one of the header slots we don't care about.
588
        if (!cachedRecovery) {
589
            if (verbose)
590
                dataLog("   + ", reg, " is OK\n");
591
            continue;
592
        }
593
594
        if (canLoadAndBox(*cachedRecovery) && hasOnlySafeWrites(*cachedRecovery)
595
            && !cachedRecovery->wantedJSValueRegs()) {
596
            emitLoad(*cachedRecovery);
597
            emitBox(*cachedRecovery);
598
            bool writesOK = tryWrites(*cachedRecovery);
599
            ASSERT(writesOK);
600
        } else if (verbose)
601
            dataLog("   - ", cachedRecovery->recovery(), " can't be handled just yet.\n");
602
    }
603
    ASSERT(dangerFrontier() < firstNew());
604
605
    // Now, the danger zone is empty, but we still have a couple of
606
    // things to do:
607
    //
608
    // 1) There could be remaining safe writes that failed earlier due
609
    //    to high register pressure and had nothing to do with the
610
    //    danger zone whatsoever.
611
    //
612
    // 2) Some wanted registers could have to be loaded (this could
613
    //    happen either when making a call to a new function with a
614
    //    lower number of arguments - since above here, we only load
615
    //    wanted registers when they are at the danger frontier -, or
616
    //    if a wanted register got spilled).
617
    //
618
    // 3) Some wanted registers could have been loaded in the wrong
619
    //    registers
620
    //
621
    // 4) We have to take care of some bookkeeping - namely, storing
622
    //    the argument count and updating the stack pointer.
623
624
    // At this point, we must have enough registers available for
625
    // handling 1). None of the loads can fail because we have been
626
    // eagerly freeing up registers in all the previous phases - so
627
    // the only values that are in registers at this point must have
628
    // wanted registers.
629
    if (verbose)
630
        dataLog("  Danger zone is clear, performing remaining writes.\n");
631
    for (VirtualRegister reg { firstNew() }; reg <= lastNew(); reg += 1) {
632
        CachedRecovery* cachedRecovery { getNew(reg) };
633
        if (!cachedRecovery)
634
            continue;
635
636
        emitLoad(*cachedRecovery);
637
        emitBox(*cachedRecovery);
638
        bool writesOK = tryWrites(*cachedRecovery);
639
        ASSERT(writesOK);
640
    }
641
642
    // Handle 2) by loading all registers. We don't have to do any
643
    // writes, since they have been taken care of above.
644
    if (verbose)
645
        dataLog("  Loading wanted GPRs into registers\n");
646
    for (Reg reg { Reg::first() }; reg <= Reg::last(); reg = reg.next()) {
647
        CachedRecovery* cachedRecovery { m_newRegisters[reg] };
648
        if (!cachedRecovery)
649
            continue;
650
        ASSERT(reg.isGPR());
651
652
        emitLoad(*cachedRecovery);
653
        emitBox(*cachedRecovery);
654
        ASSERT(cachedRecovery->targets().isEmpty());
655
    }
656
657
    // At this point, we have read everything we cared about from the
658
    // stack, and written everything we had to to the stack.
659
    if (verbose)
660
        dataLog("  Callee frame is fully set up\n");
661
    if (!ASSERT_DISABLED) {
662
        for (VirtualRegister reg { firstNew() }; reg <= lastNew(); reg += 1)
663
            ASSERT_UNUSED(reg, !getNew(reg));
664
665
        for (CachedRecovery* cachedRecovery : m_cachedRecoveries) {
666
            ASSERT_UNUSED(cachedRecovery, cachedRecovery->targets().isEmpty());
667
            ASSERT(!cachedRecovery->recovery().isInJSStack());
668
        }
669
    }
670
671
    // We need to handle 4) first because it implies releasing
672
    // m_newFrameBase, which could be a wanted register.
673
    if (verbose)
674
        dataLog("   * Storing the argument count into ", VirtualRegister { JSStack::ArgumentCount }, "\n");
675
    m_jit.store32(MacroAssembler::TrustedImm32(0),
676
        addressForNew(VirtualRegister { JSStack::ArgumentCount }).withOffset(TagOffset));
677
    m_jit.store32(MacroAssembler::TrustedImm32(argCount()),
678
        addressForNew(VirtualRegister { JSStack::ArgumentCount }).withOffset(PayloadOffset));
679
680
    if (!isSlowPath()) {
681
        ASSERT(m_newFrameBase != MacroAssembler::stackPointerRegister);
682
        if (verbose)
683
            dataLog("  Releasing the new frame base pointer\n");
684
        m_jit.move(m_newFrameBase, MacroAssembler::stackPointerRegister);
685
        releaseGPR(m_newFrameBase);
686
    }
687
688
    // Finally we handle 3)
689
    if (verbose)
690
        dataLog("  Ensuring wanted registers are in the right register\n");
691
    for (Reg reg { Reg::first() }; reg <= Reg::last(); reg = reg.next()) {
692
        CachedRecovery* cachedRecovery { m_newRegisters[reg] };
693
        if (!cachedRecovery)
694
            continue;
695
        ASSERT(reg.isGPR());
696
697
        emitDisplace(*cachedRecovery);
698
    }
699
}
700
701
} // namespace JSC
702
703
#endif // ENABLE(JIT)
- a/Source/JavaScriptCore/jit/CallFrameShuffler.h +803 lines
Line 0 a/Source/JavaScriptCore/jit/CallFrameShuffler.h_sec1
1
/*
2
 * Copyright (C) 2015 Apple Inc. All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 * 1. Redistributions of source code must retain the above copyright
8
 *    notice, this list of conditions and the following disclaimer.
9
 * 2. Redistributions in binary form must reproduce the above copyright
10
 *    notice, this list of conditions and the following disclaimer in the
11
 *    documentation and/or other materials provided with the distribution.
12
 *
13
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24
 */
25
26
#ifndef CallFrameShuffler_h
27
#define CallFrameShuffler_h
28
29
#if ENABLE(JIT)
30
31
#include "CallFrameShuffleData.h"
32
#include "MacroAssembler.h"
33
#include "RegisterSet.h"
34
#include "StackAlignment.h"
35
#include "ValueRecovery.h"
36
#include "VirtualRegister.h"
37
#include <wtf/Vector.h>
38
39
namespace JSC {
40
41
// A CachedRecovery is a simple wrapper around a ValueRecovery that 
42
class CachedRecovery {
43
public:
44
    CachedRecovery(ValueRecovery recovery)
45
        : m_recovery { recovery }
46
    {
47
    }
48
49
    CachedRecovery(CachedRecovery&) = delete;
50
    CachedRecovery(CachedRecovery&&) = delete;
51
    CachedRecovery& operator=(CachedRecovery&) = delete;
52
    CachedRecovery& operator=(CachedRecovery&&) = delete;
53
54
    const Vector<VirtualRegister, 1>& targets() const { return m_targets; }
55
56
    void addTarget(VirtualRegister reg)
57
    {
58
        ASSERT(m_targets.isEmpty() || m_targets.last() < reg);
59
        m_targets.append(reg);
60
    }
61
62
    void removeTarget(VirtualRegister reg)
63
    {
64
        ASSERT(m_targets.last() == reg);
65
        m_targets.shrink(m_targets.size() - 1);
66
    }
67
68
    void clearTargets()
69
    {
70
        m_targets.clear();
71
    }
72
73
    void setWantedJSValueRegs(JSValueRegs jsValueRegs)
74
    {
75
        m_wantedJSValueRegs = jsValueRegs;
76
    }
77
78
    // Determine whether converting this recovery into a JSValue will
79
    // require additional GPRs and/or FPRs.
80
    // This is guaranteed to only depend on the DataFormat, and the
81
    // result of these calls will stay valid after loads and/or stores.
82
    bool boxingRequiresGPR() const
83
    {
84
#if USE(JSVALUE64)
85
        return recovery().dataFormat() == DataFormatDouble;
86
#else
87
        return false;
88
#endif
89
    }
90
    bool boxingRequiresFPR() const
91
    {
92
#if USE(JSVALUE64)
93
        switch (recovery().dataFormat()) {
94
        case DataFormatInt52:
95
        case DataFormatStrictInt52:
96
            return true;
97
98
        default:
99
            return false;
100
        }
101
#else
102
        return false;
103
#endif
104
    }
105
    
106
107
    // This is used to determine what kind of register we need to be
108
    // able to load a recovery. We only use it when a direct load is
109
    // currently impossible, to determine whether we should spill a
110
    // GPR or an FPR for loading this value.
111
    bool loadsIntoGPR() const;
112
    bool loadsIntoFPR() const;
113
114
    ValueRecovery recovery() const { return m_recovery; }
115
116
    void setRecovery(ValueRecovery recovery) { m_recovery = recovery; }
117
118
    JSValueRegs wantedJSValueRegs() const { return m_wantedJSValueRegs; }
119
private:
120
    ValueRecovery m_recovery;
121
    JSValueRegs m_wantedJSValueRegs;
122
    Vector<VirtualRegister, 1> m_targets;
123
};
124
125
class CallFrameShuffler {
126
public:
127
    CallFrameShuffler(CCallHelpers&, const CallFrameShuffleData&);
128
129
    void dump(PrintStream&) const;
130
131
    // Any register that has been locked or acquired must be released
132
    // before calling prepareForTailCall() or prepareForSlowPath().
133
    void lockGPR(GPRReg gpr)
134
    {
135
        ASSERT(!m_lockedRegisters.get(gpr));
136
        m_lockedRegisters.set(gpr);
137
        if (verbose)
138
            dataLog("   * Locking ", gpr, "\n");
139
    }
140
141
    GPRReg acquireGPR()
142
    {
143
        ensureGPR();
144
        GPRReg gpr { getFreeGPR() };
145
        ASSERT(!m_registers[gpr]);
146
        lockGPR(gpr);
147
        return gpr;
148
    }
149
150
    void releaseGPR(GPRReg gpr)
151
    {
152
        if (verbose) {
153
            if (m_lockedRegisters.get(gpr))
154
                dataLog("   * Releasing ", gpr, "\n");
155
            else
156
                dataLog("   * ", gpr, " was not locked\n");
157
        }
158
        m_lockedRegisters.clear(gpr);
159
    }
160
161
    // You can only take a snapshot if the recovery has not started
162
    // yet. The only operations that are valid before taking a
163
    // snapshot are lockGPR(), acquireGPR() and releaseGPR().
164
    //
165
    // Locking status is *NOT* preserved by the snapshot: it only
166
    // contains information about where the
167
    // arguments/callee/callee-save registers are by taking into
168
    // account any spilling that acquireGPR() could have done.
169
    CallFrameShuffleData snapshot() const
170
    {
171
        ASSERT(isUndecided());
172
173
        CallFrameShuffleData data;
174
        data.numLocals = numLocals();
175
        data.callee = getNew(VirtualRegister { JSStack::Callee })->recovery();
176
        data.args.resize(argCount());
177
        for (size_t i { 0 }; i < argCount(); ++i)
178
            data.args[i] = getNew(virtualRegisterForArgument(i))->recovery();
179
        for (Reg reg { Reg::first() }; reg <= Reg::last(); reg = reg.next()) {
180
            CachedRecovery* cachedRecovery { m_newRegisters[reg] };
181
            if (!cachedRecovery)
182
                continue;
183
184
#if USE(JSVALUE64)
185
            data.registers[reg] = cachedRecovery->recovery();
186
#else
187
            RELEASE_ASSERT_NOT_REACHED();
188
#endif
189
        }
190
        return WTF::move(data);
191
    }
192
193
    // Ask the shuffler to put the callee into some registers once the
194
    // shuffling is done. You should call this before any of the
195
    // prepare() methods, and must not take a snapshot afterwards, as
196
    // this would crash 32bits platforms.
197
    void setCalleeJSValueRegs(JSValueRegs jsValueRegs)
198
    {
199
        ASSERT(isUndecided());
200
        ASSERT(!getNew(jsValueRegs));
201
        CachedRecovery* cachedRecovery { getNew(VirtualRegister(JSStack::Callee)) };
202
        ASSERT(cachedRecovery);
203
        addNew(jsValueRegs, cachedRecovery->recovery());
204
    }
205
206
    // Ask the suhffler to assume the callee has already be checked to
207
    // be a cell. This is a no-op on 64bit platforms, but allows to
208
    // free up a GPR on 32bit platforms.
209
    // You obviously must have ensured that this is the case before
210
    // running any of the prepare methods.
211
    void assumeCalleeIsCell()
212
    {
213
#if USE(JSVALUE32_64)
214
        CachedRecovery& calleeCachedRecovery { *getNew(VirtualRegister(JSStack::Callee)) };
215
        switch (calleeCachedRecovery.recovery().technique()) {
216
        case InPair:
217
            updateRecovery(
218
                calleeCachedRecovery,
219
                ValueRecovery::inGPR(
220
                    calleeCachedRecovery.recovery().payloadGPR(),
221
                    DataFormatCell));
222
            break;
223
        case DisplacedInJSStack:
224
            updateRecovery(
225
                calleeCachedRecovery,
226
                ValueRecovery::displacedInJSStack(
227
                    calleeCachedRecovery.recovery().virtualRegister(),
228
                    DataFormatCell));
229
            break;
230
        case InFPR:
231
        case UnboxedCellInGPR:
232
        case CellDisplacedInJSStack:
233
            break;
234
        case Constant:
235
            ASSERT(calleeCachedRecovery.recovery().constant().isCell());
236
            break;
237
        default:
238
            RELEASE_ASSERT_NOT_REACHED();
239
            break;
240
        }
241
#endif
242
    }
243
244
    // This will emit code to build the new frame over the old one.
245
    void prepareForTailCall();
246
247
    // This will emit code to build the new frame as if performing a
248
    // regular call. However, the callee save registers will be
249
    // restored, and any locals (not the header or arguments) of the
250
    // current frame can be overwritten.
251
    //
252
    // A frame built using prepareForSlowPath() should be used either
253
    // to throw an exception in, or destroyed using
254
    // CCallHelpers::prepareForTailCallSlow() followed by a tail call.
255
    void prepareForSlowPath();
256
257
private:
258
    static const bool verbose = false;
259
260
    CCallHelpers& m_jit;
261
262
    void prepareAny();
263
264
    void spill(CachedRecovery&);
265
266
    // "box" is arguably a bad name here. The meaning is that after
267
    // calling emitBox(), your ensure that subsequently calling
268
    // emitStore() will be able to store the value without additional
269
    // transformation. In particular, this is a no-op for constants,
270
    // and is a complete no-op on 32bits since any unboxed value can
271
    // still be stored by storing the payload and a statically known
272
    // tag.
273
    void emitBox(CachedRecovery&);
274
    bool canBox(CachedRecovery& cachedRecovery)
275
    {
276
        if (cachedRecovery.boxingRequiresGPR() && getFreeGPR() == InvalidGPRReg)
277
            return false;
278
279
        if (cachedRecovery.boxingRequiresFPR() && getFreeFPR() == InvalidFPRReg)
280
            return false;
281
282
        return true;
283
    }
284
    void ensureBox(CachedRecovery& cachedRecovery)
285
    {
286
        if (canBox(cachedRecovery))
287
            return;
288
289
        if (cachedRecovery.boxingRequiresGPR())
290
            ensureGPR();
291
292
        if (cachedRecovery.boxingRequiresFPR())
293
            ensureFPR();
294
    }
295
296
    void emitLoad(CachedRecovery&);
297
    bool canLoad(CachedRecovery&);
298
    void ensureLoad(CachedRecovery& cachedRecovery)
299
    {
300
        if (canLoad(cachedRecovery))
301
            return;
302
303
        ASSERT(cachedRecovery.loadsIntoGPR() || cachedRecovery.loadsIntoFPR());
304
305
        if (cachedRecovery.loadsIntoFPR()) {
306
            if (cachedRecovery.loadsIntoGPR())
307
                ensureRegister();
308
            else
309
                ensureFPR();
310
        } else
311
            ensureGPR();
312
    }
313
314
    bool canLoadAndBox(CachedRecovery& cachedRecovery)
315
    {
316
        // We don't have interfering loads & boxes
317
        ASSERT(!cachedRecovery.loadsIntoFPR() || !cachedRecovery.boxingRequiresFPR());
318
        ASSERT(!cachedRecovery.loadsIntoGPR() || !cachedRecovery.boxingRequiresGPR());
319
320
        return canLoad(cachedRecovery) && canBox(cachedRecovery);
321
    }
322
323
    DataFormat emitStore(CachedRecovery&, MacroAssembler::Address);
324
325
    void emitDisplace(CachedRecovery&);
326
327
    void emitDeltaCheck();
328
329
    Bag<CachedRecovery> m_cachedRecoveries;
330
331
    void updateRecovery(CachedRecovery& cachedRecovery, ValueRecovery recovery)
332
    {
333
        clearCachedRecovery(cachedRecovery.recovery());
334
        cachedRecovery.setRecovery(recovery);
335
        setCachedRecovery(recovery, &cachedRecovery);
336
    }
337
338
    CachedRecovery* getCachedRecovery(ValueRecovery);
339
340
    CachedRecovery* setCachedRecovery(ValueRecovery, CachedRecovery*);
341
342
    void clearCachedRecovery(ValueRecovery recovery)
343
    {
344
        if (!recovery.isConstant())
345
            setCachedRecovery(recovery, nullptr);
346
    }
347
348
    CachedRecovery* addCachedRecovery(ValueRecovery recovery)
349
    {
350
        if (recovery.isConstant())
351
            return m_cachedRecoveries.add(recovery);
352
        CachedRecovery* cachedRecovery = getCachedRecovery(recovery);
353
        if (!cachedRecovery)
354
            return setCachedRecovery(recovery, m_cachedRecoveries.add(recovery));
355
        return cachedRecovery;
356
    }
357
358
    // This is the current recoveries present in the old frame's
359
    // slots. A null CachedRecovery means we can trash the current
360
    // value as we don't care about it.
361
    Vector<CachedRecovery*> m_oldFrame;
362
363
    int numLocals() const
364
    {
365
        return m_oldFrame.size() - JSStack::CallerFrameAndPCSize;
366
    }
367
368
    CachedRecovery* getOld(VirtualRegister reg) const
369
    {
370
        return m_oldFrame[JSStack::CallerFrameAndPCSize - reg.offset() - 1];
371
    }
372
373
    void setOld(VirtualRegister reg, CachedRecovery* cachedRecovery)
374
    {
375
        m_oldFrame[JSStack::CallerFrameAndPCSize - reg.offset() - 1] = cachedRecovery;
376
    }
377
378
    VirtualRegister firstOld() const
379
    {
380
        return VirtualRegister { static_cast<int>(-numLocals()) };
381
    }
382
383
    VirtualRegister lastOld() const
384
    {
385
        return VirtualRegister { JSStack::CallerFrameAndPCSize - 1 };
386
    }
387
388
    bool isValidOld(VirtualRegister reg) const
389
    {
390
        return reg >= firstOld() && reg <= lastOld();
391
    }
392
393
    // This stores, for each slot in the new frame, information about
394
    // the recovery for the value that should eventually go into that
395
    // slot.
396
    //
397
    // Once the slot has been written, the corresponding entry in
398
    // m_newFrame will be empty.
399
    Vector<CachedRecovery*> m_newFrame;
400
401
    size_t argCount() const
402
    {
403
        return m_newFrame.size() - JSStack::CallFrameHeaderSize;
404
    }
405
406
    CachedRecovery* getNew(VirtualRegister newRegister) const
407
    {
408
        return m_newFrame[newRegister.offset()];
409
    }
410
411
    void setNew(VirtualRegister newRegister, CachedRecovery* cachedRecovery)
412
    {
413
        m_newFrame[newRegister.offset()] = cachedRecovery;
414
    }
415
416
    void addNew(VirtualRegister newRegister, ValueRecovery recovery)
417
    {
418
        CachedRecovery* cachedRecovery = addCachedRecovery(recovery);
419
        cachedRecovery->addTarget(newRegister);
420
        setNew(newRegister, cachedRecovery);
421
    }
422
423
    VirtualRegister firstNew() const
424
    {
425
        return VirtualRegister { 0 };
426
    }
427
428
    VirtualRegister lastNew() const
429
    {
430
        return VirtualRegister { static_cast<int>(m_newFrame.size()) - 1 };
431
    }
432
433
    bool isValidNew(VirtualRegister reg) const
434
    {
435
        return reg >= firstNew() && reg <= lastNew();
436
    }
437
438
439
    int m_alignedOldFrameSize;
440
    int m_alignedNewFrameSize;
441
442
    // This is the distance, in slots, between the base of the new
443
    // frame and the base of the old frame. It could be negative when
444
    // preparing for a tail call to a function with smaller argument
445
    // count.
446
    //
447
    // We will overwrite this appropriately for slow path calls, but
448
    // we initialize it as if doing a fast path for the spills we
449
    // could do while undecided (typically while calling acquireGPR()
450
    // for a polymorphic call).
451
    int m_frameDelta { m_alignedNewFrameSize - m_alignedOldFrameSize };
452
453
    VirtualRegister newAsOld(VirtualRegister reg) const
454
    {
455
        return reg - m_frameDelta;
456
    }
457
458
    // This stores the set of locked registers, i.e. registers for
459
    // which we have an implicit requirement that they are not changed.
460
    //
461
    // This will usually contains the link register on architectures
462
    // that have one, any scratch register used by the macro assembler
463
    // (e.g. r11 on X86_64), as well as any register that we use for
464
    // addressing (see m_oldFrameBase and m_newFrameBase).
465
    //
466
    // We also use this to lock registers temporarily, for instance to
467
    // ensure that we have at least 2 available registers for loading
468
    // a pair on 32bits.
469
    RegisterSet m_lockedRegisters;
470
471
    // This stores the current recoveries present in registers. A null
472
    // CachedRecovery means we can trash the current value as we don't
473
    // care about it. 
474
    RegisterMap<CachedRecovery*> m_registers;
475
476
    // This stores, for each register, information about the recovery
477
    // for the value that should eventually go into that register. The
478
    // only registers that have a target recovery will be callee-save
479
    // registers, as well as possibly one JSValueRegs for holding the
480
    // callee.
481
    //
482
    // Once the correct value has been put into the registers, and
483
    // contrary to what we do with m_newFrame, we keep the entry in
484
    // m_newRegisters to simplify spilling.
485
    //
486
    // FIXME: Contrary to what the name suggests, we only support GPRs
487
    // for now.
488
    RegisterMap<CachedRecovery*> m_newRegisters;
489
490
    template<typename CheckFunctor>
491
    Reg getFreeRegister(const CheckFunctor& check) const
492
    {
493
        Reg nonTemp { };
494
        for (Reg reg { Reg::first() }; reg <= Reg::last(); reg = reg.next()) {
495
            if (m_lockedRegisters.get(reg))
496
                continue;
497
498
            if (!check(reg))
499
                continue;
500
501
            if (!m_registers[reg]) {
502
                if (!m_newRegisters[reg])
503
                    return reg;
504
                if (!nonTemp)
505
                    nonTemp = reg;
506
            }
507
        }
508
        return nonTemp;
509
    }
510
511
    GPRReg getFreeGPR() const
512
    {
513
        Reg freeGPR { getFreeRegister([] (Reg reg) { return reg.isGPR(); }) };
514
        if (!freeGPR)
515
            return InvalidGPRReg;
516
        return freeGPR.gpr();
517
    }
518
519
    FPRReg getFreeFPR() const
520
    {
521
        Reg freeFPR { getFreeRegister([] (Reg reg) { return reg.isFPR(); }) };
522
        if (!freeFPR)
523
            return InvalidFPRReg;
524
        return freeFPR.fpr();
525
    }
526
527
    bool hasFreeRegister() const
528
    {
529
        return static_cast<bool>(getFreeRegister([] (Reg) { return true; }));
530
    }
531
532
    // This frees up a register satisfying the check functor (this
533
    // functor could theoretically have any kind of logic, but it must
534
    // ensure that it will only return true for registers - spill
535
    // assumes and asserts that it is passed a cachedRecovery stored in a
536
    // register).
537
    template<typename CheckFunctor>
538
    void ensureRegister(const CheckFunctor& check)
539
    {
540
        // If we can spill a callee-save, that's best, because it will
541
        // free up a register that would otherwise been taken for the
542
        // longest amount of time.
543
        //
544
        // We could try to bias towards those that are not in their
545
        // target registers yet, but the gain is probably super
546
        // small. Unless you have a huge number of argument (at least
547
        // around twice the number of available registers on your
548
        // architecture), no spilling is going to take place anyways.
549
        for (Reg reg { Reg::first() }; reg <= Reg::last(); reg = reg.next()) {
550
            if (m_lockedRegisters.get(reg))
551
                continue;
552
553
            CachedRecovery* cachedRecovery { m_newRegisters[reg] };
554
            if (!cachedRecovery)
555
                continue;
556
557
            if (check(*cachedRecovery)) {
558
                if (verbose)
559
                    dataLog("  ", cachedRecovery->recovery(), " looks like a good spill candidate\n");
560
                spill(*cachedRecovery);
561
                return;
562
            }
563
        }
564
565
        // We use the cachedRecovery associated with the first new slot we
566
        // can, because that is the one for which a write will be
567
        // possible the latest, i.e. that is the one that we would
568
        // have had to retain in registers for the longest.
569
        for (VirtualRegister reg { firstNew() }; reg <= lastNew(); reg += 1) {
570
            CachedRecovery* cachedRecovery { getNew(reg) };
571
            if (!cachedRecovery)
572
                continue;
573
574
            if (check(*cachedRecovery)) {
575
                spill(*cachedRecovery);
576
                return;
577
            }
578
        }
579
580
        RELEASE_ASSERT_NOT_REACHED();
581
    }
582
583
    void ensureRegister()
584
    {
585
        if (hasFreeRegister())
586
            return;
587
588
        if (verbose)
589
            dataLog("  Finding a register to spill\n");
590
        ensureRegister(
591
            [this] (const CachedRecovery& cachedRecovery) {
592
                if (cachedRecovery.recovery().isInGPR())
593
                    return !m_lockedRegisters.get(cachedRecovery.recovery().gpr());
594
                if (cachedRecovery.recovery().isInFPR())
595
                    return !m_lockedRegisters.get(cachedRecovery.recovery().fpr());
596
#if USE(JSVALUE32_64)
597
                if (cachedRecovery.recovery().technique() == InPair) {
598
                    return !m_lockedRegisters.get(cachedRecovery.recovery().tagGPR())
599
                        && !m_lockedRegisters.get(cachedRecovery.recovery().payloadGPR());
600
                }
601
#endif
602
                return false;
603
            });
604
    }
605
606
    void ensureGPR()
607
    {
608
        if (getFreeGPR() != InvalidGPRReg)
609
            return;
610
611
        if (verbose)
612
            dataLog("  Finding a GPR to spill\n");
613
        ensureRegister(
614
            [this] (const CachedRecovery& cachedRecovery) {
615
                if (cachedRecovery.recovery().isInGPR())
616
                    return !m_lockedRegisters.get(cachedRecovery.recovery().gpr());
617
#if USE(JSVALUE32_64)
618
                if (cachedRecovery.recovery().technique() == InPair) {
619
                    return !m_lockedRegisters.get(cachedRecovery.recovery().tagGPR())
620
                        && !m_lockedRegisters.get(cachedRecovery.recovery().payloadGPR());
621
                }
622
#endif
623
                return false;
624
            });
625
    }
626
627
    void ensureFPR()
628
    {
629
        if (getFreeFPR() != InvalidFPRReg)
630
            return;
631
632
        if (verbose)
633
            dataLog("  Finding an FPR to spill\n");
634
        ensureRegister(
635
            [this] (const CachedRecovery& cachedRecovery) {
636
                if (cachedRecovery.recovery().isInFPR())
637
                    return !m_lockedRegisters.get(cachedRecovery.recovery().fpr());
638
                return false;
639
            });
640
    }
641
642
    CachedRecovery* getNew(JSValueRegs jsValueRegs) const
643
    {
644
#if USE(JSVALUE64)
645
        return m_newRegisters[jsValueRegs.gpr()];
646
#else
647
        ASSERT(
648
            jsValueRegs.tagGPR() == InvalidGPRReg || jsValueRegs.payloadGPR() == InvalidGPRReg
649
            || m_newRegisters[jsValueRegs.payloadGPR()] == m_newRegisters[jsValueRegs.tagGPR()]);
650
        if (jsValueRegs.payloadGPR() == InvalidGPRReg)
651
            return m_newRegisters[jsValueRegs.tagGPR()];
652
        return m_newRegisters[jsValueRegs.payloadGPR()];
653
#endif
654
    }
655
656
    void addNew(JSValueRegs jsValueRegs, ValueRecovery recovery)
657
    {
658
        ASSERT(jsValueRegs && !getNew(jsValueRegs));
659
        CachedRecovery* cachedRecovery = addCachedRecovery(recovery);
660
        ASSERT(!cachedRecovery->wantedJSValueRegs());
661
        cachedRecovery->setWantedJSValueRegs(jsValueRegs);
662
#if USE(JSVALUE64)
663
        m_newRegisters[jsValueRegs.gpr()] = cachedRecovery;
664
#else
665
        if (jsValueRegs.payloadGPR() != InvalidGPRReg)
666
            m_newRegisters[jsValueRegs.payloadGPR()] = cachedRecovery;
667
        if (jsValueRegs.tagGPR() != InvalidGPRReg)
668
            m_newRegisters[jsValueRegs.tagGPR()] = cachedRecovery;
669
#endif
670
    }
671
672
    // m_oldFrameBase is the register relative to which we access
673
    // slots in the old call frame, with an additional offset of
674
    // m_oldFrameOffset.
675
    //
676
    //  - For an actual tail call, m_oldFrameBase is the stack
677
    //    pointer, and m_oldFrameOffset is the number of locals of the
678
    //    tail caller's frame. We use such stack pointer-based
679
    //    addressing because it allows us to load the tail caller's
680
    //    caller's frame pointer in the frame pointer register
681
    //    immediately instead of awkwardly keeping it around on the
682
    //    stack.
683
    //
684
    //  - For a slow path call, m_oldFrameBase is just the frame
685
    //    pointer, and m_oldFrameOffset is 0. We could 
686
    GPRReg m_oldFrameBase { MacroAssembler::framePointerRegister };
687
    int m_oldFrameOffset { 0 };
688
689
    MacroAssembler::Address addressForOld(VirtualRegister reg) const
690
    {
691
        return MacroAssembler::Address(m_oldFrameBase,
692
            (m_oldFrameOffset + reg.offset()) * sizeof(Register));
693
    }
694
695
    // m_newFrameBase is the register relative to which we access
696
    // slots in the new call frame, and we always make it point to
697
    // wherever the stack pointer will be right before making the
698
    // actual call/jump. The actual base of the new frame is at offset
699
    // m_newFrameOffset relative to m_newFrameBase.
700
    //
701
    //  - For an actual tail call, m_newFrameBase is computed
702
    //    dynamically, and m_newFrameOffset varies between 0 and -2
703
    //    depending on the architecture's calling convention (see
704
    //    prepareForTailCall).
705
    //
706
    //  - For a slow path call, m_newFrameBase is the actual stack
707
    //    pointer, and m_newFrameOffset is - CallerFrameAndPCSize,
708
    //    following the convention for a regular call.
709
    GPRReg m_newFrameBase { InvalidGPRReg };
710
    int m_newFrameOffset { 0};
711
712
    bool isUndecided() const
713
    {
714
        return m_newFrameBase == InvalidGPRReg;
715
    }
716
717
    bool isSlowPath() const
718
    {
719
        return m_newFrameBase == MacroAssembler::stackPointerRegister;
720
    }
721
722
    MacroAssembler::Address addressForNew(VirtualRegister reg) const
723
    {
724
        return MacroAssembler::Address(m_newFrameBase,
725
            (m_newFrameOffset + reg.offset()) * sizeof(Register));
726
    }
727
728
    // We use a concept of "danger zone". The danger zone consists of
729
    // all the writes in the new frame that could overlap with reads
730
    // in the old frame.
731
    //
732
    // Because we could have a higher actual number of arguments than
733
    // parameters, when preparing a tail call, we need to assume that
734
    // writing to a slot on the new frame could overlap not only with
735
    // the corresponding slot in the old frame, but also with any slot
736
    // above it. Thus, the danger zone consists of all writes between
737
    // the first write and what I call the "danger frontier": the
738
    // highest slot in the old frame we still care about. Thus, the
739
    // danger zone contains all the slots between the first slot of
740
    // the new frame and the danger frontier. Because the danger
741
    // frontier is related to the new frame, it is stored as a virtual
742
    // register *in the new frame*.
743
    VirtualRegister m_dangerFrontier;
744
745
    VirtualRegister dangerFrontier() const
746
    {
747
        ASSERT(!isUndecided());
748
749
        return m_dangerFrontier;
750
    }
751
752
    bool isDangerNew(VirtualRegister reg) const
753
    {
754
        ASSERT(!isUndecided() && isValidNew(reg));
755
        return reg <= dangerFrontier();
756
    }
757
758
    void updateDangerFrontier()
759
    {
760
        ASSERT(!isUndecided());
761
762
        m_dangerFrontier = firstNew() - 1;
763
        for (VirtualRegister reg { lastNew() }; reg >= firstNew(); reg -= 1) {
764
            if (!getNew(reg) || !isValidOld(newAsOld(reg)) || !getOld(newAsOld(reg)))
765
                continue;
766
767
            m_dangerFrontier = reg;
768
            if (verbose)
769
                dataLog("  Danger frontier now at NEW ", m_dangerFrontier, "\n");
770
            break;
771
        }
772
        if (verbose)
773
            dataLog("  All clear! Danger zone is empty.\n");
774
    }
775
776
    // A safe write is a write that never writes into the danger zone.
777
    bool hasOnlySafeWrites(CachedRecovery& cachedRecovery) const
778
    {
779
        for (VirtualRegister target : cachedRecovery.targets()) {
780
            if (isDangerNew(target))
781
                return false;
782
        }
783
        return true;
784
    }
785
786
    // You must ensure that there is no dangerous writes before
787
    // calling this function.
788
    bool tryWrites(CachedRecovery&);
789
790
    // This function tries to ensure that there is no longer any
791
    // possible safe write, i.e. all remaining writes are either to
792
    // the danger zone or callee save restorations.
793
    //
794
    // It returns false if it was unable to perform some safe writes
795
    // due to high register pressure.
796
    bool performSafeWrites();
797
};
798
799
} // namespace JSC
800
801
#endif // ENABLE(JIT)
802
803
#endif // CallFrameShuffler_h
- a/Source/JavaScriptCore/jit/CallFrameShuffler32_64.cpp +331 lines
Line 0 a/Source/JavaScriptCore/jit/CallFrameShuffler32_64.cpp_sec1
1
/*
2
 * Copyright (C) 2015 Apple Inc. All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 * 1. Redistributions of source code must retain the above copyright
8
 *    notice, this list of conditions and the following disclaimer.
9
 * 2. Redistributions in binary form must reproduce the above copyright
10
 *    notice, this list of conditions and the following disclaimer in the
11
 *    documentation and/or other materials provided with the distribution.
12
 *
13
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
 */
25
26
#include "config.h"
27
#include "CallFrameShuffler.h"
28
29
#if ENABLE(JIT) && USE(JSVALUE32_64)
30
31
#include "CCallHelpers.h"
32
#include "DataFormat.h"
33
#include "JSCJSValue.h"
34
35
namespace JSC {
36
37
DataFormat CallFrameShuffler::emitStore(CachedRecovery& location, MacroAssembler::Address address)
38
{
39
    ASSERT(!location.recovery().isInJSStack());
40
41
    switch (location.recovery().technique()) {
42
    case UnboxedInt32InGPR:
43
        m_jit.store32(MacroAssembler::TrustedImm32(JSValue::Int32Tag),
44
            address.withOffset(TagOffset));
45
        m_jit.store32(location.recovery().gpr(), address.withOffset(PayloadOffset));
46
        return DataFormatInt32;
47
    case UnboxedCellInGPR:
48
        m_jit.store32(MacroAssembler::TrustedImm32(JSValue::CellTag),
49
            address.withOffset(TagOffset));
50
        m_jit.store32(location.recovery().gpr(), address.withOffset(PayloadOffset));
51
        return DataFormatCell;
52
    case Constant:
53
        m_jit.storeTrustedValue(location.recovery().constant(), address);
54
        return DataFormatJS;
55
    case InPair:
56
        m_jit.storeValue(location.recovery().jsValueRegs(), address);
57
        return DataFormatJS;
58
    case UnboxedBooleanInGPR:
59
        m_jit.store32(MacroAssembler::TrustedImm32(JSValue::BooleanTag),
60
            address.withOffset(TagOffset));
61
        m_jit.store32(location.recovery().gpr(), address.withOffset(PayloadOffset));
62
        return DataFormatBoolean;
63
    case InFPR:
64
    case UnboxedDoubleInFPR:
65
        m_jit.storeDouble(location.recovery().fpr(), address);
66
        return DataFormatJS;
67
    default:
68
        RELEASE_ASSERT_NOT_REACHED();
69
    }
70
}
71
72
void CallFrameShuffler::emitBox(CachedRecovery& location)
73
{
74
    // Nothing to do, we're good! JSValues and doubles can be stored
75
    // immediately, and other formats don't need any transformation -
76
    // just storing a constant tag separately.
77
    ASSERT(canBox(location));
78
}
79
80
void CallFrameShuffler::emitLoad(CachedRecovery& location)
81
{
82
    if (!location.recovery().isInJSStack())
83
        return;
84
85
    if (verbose)
86
        dataLog("   * Loading ", location.recovery(), " into ");
87
    VirtualRegister reg { location.recovery().virtualRegister() };
88
    MacroAssembler::Address address { addressForOld(reg) };
89
90
    bool tryFPR { true };
91
    JSValueRegs wantedJSValueRegs { location.wantedJSValueRegs() };
92
    if (wantedJSValueRegs) {
93
        if (wantedJSValueRegs.payloadGPR() != InvalidGPRReg
94
            && !m_registers[wantedJSValueRegs.payloadGPR()]
95
            && !m_lockedRegisters.get(wantedJSValueRegs.payloadGPR()))
96
            tryFPR = false;
97
        if (wantedJSValueRegs.tagGPR() != InvalidGPRReg
98
            && !m_registers[wantedJSValueRegs.tagGPR()]
99
            && !m_lockedRegisters.get(wantedJSValueRegs.tagGPR()))
100
            tryFPR = false;
101
    }
102
103
    if (tryFPR && location.loadsIntoFPR()) {
104
        FPRReg resultFPR = getFreeFPR();
105
        if (resultFPR != InvalidFPRReg) {
106
            m_jit.loadDouble(address, resultFPR);
107
            DataFormat dataFormat = DataFormatJS;
108
            if (location.recovery().dataFormat() == DataFormatDouble)
109
                dataFormat = DataFormatDouble;
110
            updateRecovery(location, 
111
                ValueRecovery::inFPR(resultFPR, dataFormat));
112
            if (verbose)
113
                dataLog(location.recovery(), "\n");
114
            if (reg == newAsOld(dangerFrontier()))
115
                updateDangerFrontier();
116
            return;
117
        }
118
    }
119
120
    if (location.loadsIntoGPR()) {
121
        GPRReg resultGPR { wantedJSValueRegs.payloadGPR() };
122
        if (resultGPR == InvalidGPRReg || m_registers[resultGPR] || m_lockedRegisters.get(resultGPR))
123
            resultGPR = getFreeGPR();
124
        ASSERT(resultGPR != InvalidGPRReg);
125
        m_jit.loadPtr(address.withOffset(PayloadOffset), resultGPR);
126
        updateRecovery(location, 
127
            ValueRecovery::inGPR(resultGPR, location.recovery().dataFormat()));
128
        if (verbose)
129
            dataLog(location.recovery(), "\n");
130
        if (reg == newAsOld(dangerFrontier()))
131
            updateDangerFrontier();
132
        return;
133
    }
134
135
    ASSERT(location.recovery().technique() == DisplacedInJSStack);
136
    GPRReg payloadGPR { wantedJSValueRegs.payloadGPR() };
137
    GPRReg tagGPR { wantedJSValueRegs.tagGPR() };
138
    if (payloadGPR == InvalidGPRReg || m_registers[payloadGPR] || m_lockedRegisters.get(payloadGPR))
139
        payloadGPR = getFreeGPR();
140
    m_lockedRegisters.set(payloadGPR);
141
    if (tagGPR == InvalidGPRReg || m_registers[tagGPR] || m_lockedRegisters.get(tagGPR))
142
        tagGPR = getFreeGPR();
143
    m_lockedRegisters.clear(payloadGPR);
144
    ASSERT(payloadGPR != InvalidGPRReg && tagGPR != InvalidGPRReg && tagGPR != payloadGPR);
145
    m_jit.loadPtr(address.withOffset(PayloadOffset), payloadGPR);
146
    m_jit.loadPtr(address.withOffset(TagOffset), tagGPR);
147
    updateRecovery(location, 
148
        ValueRecovery::inPair(tagGPR, payloadGPR));
149
    if (verbose)
150
        dataLog(location.recovery(), "\n");
151
    if (reg == newAsOld(dangerFrontier()))
152
        updateDangerFrontier();
153
}
154
155
bool CallFrameShuffler::canLoad(CachedRecovery& location)
156
{
157
    if (!location.recovery().isInJSStack())
158
        return true;
159
160
    if (location.loadsIntoFPR() && getFreeFPR() != InvalidFPRReg)
161
        return true;
162
163
    if (location.loadsIntoGPR() && getFreeGPR() != InvalidGPRReg)
164
        return true;
165
166
    if (location.recovery().technique() == DisplacedInJSStack) {
167
        GPRReg payloadGPR { getFreeGPR() };
168
        if (payloadGPR == InvalidGPRReg)
169
            return false;
170
        m_lockedRegisters.set(payloadGPR);
171
        GPRReg tagGPR { getFreeGPR() };
172
        m_lockedRegisters.clear(payloadGPR);
173
        return tagGPR != InvalidGPRReg;
174
    }
175
176
    return false;
177
}
178
179
// We prefer loading doubles and undetermined JSValues into FPRs
180
// because it would otherwise use up two GPRs.
181
bool CachedRecovery::loadsIntoFPR() const
182
{
183
    switch (recovery().technique()) {
184
    case DoubleDisplacedInJSStack:
185
    case DisplacedInJSStack:
186
        return true;
187
188
    default:
189
        return false;
190
    }
191
}
192
193
// Integers, booleans and cells can be loaded into a single GPR
194
bool CachedRecovery::loadsIntoGPR() const
195
{
196
    switch (recovery().technique()) {
197
    case Int32DisplacedInJSStack:
198
    case BooleanDisplacedInJSStack:
199
    case CellDisplacedInJSStack:
200
        return true;
201
202
    default:
203
        return false;
204
    }
205
}
206
207
void CallFrameShuffler::emitDisplace(CachedRecovery& location)
208
{
209
    ASSERT(location.recovery().isInRegisters());
210
    JSValueRegs wantedJSValueRegs { location.wantedJSValueRegs() };
211
    ASSERT(wantedJSValueRegs);
212
213
    GPRReg wantedTagGPR { wantedJSValueRegs.tagGPR() };
214
    GPRReg wantedPayloadGPR { wantedJSValueRegs.payloadGPR() };
215
    
216
    if (wantedTagGPR != InvalidGPRReg) {
217
        ASSERT(!m_lockedRegisters.get(wantedTagGPR));
218
        if (CachedRecovery* currentTag { m_registers[wantedTagGPR] }) {
219
            if (currentTag == &location) {
220
                if (verbose)
221
                    dataLog("   + ", wantedTagGPR, " is OK\n");
222
            } else {
223
                // This can never happen on 32bit platforms since we
224
                // have at most one wanted JSValueRegs, for the
225
                // callee, and no callee-save registers.
226
                RELEASE_ASSERT_NOT_REACHED();
227
            }
228
        }
229
    }
230
231
    if (wantedPayloadGPR != InvalidGPRReg) {
232
        ASSERT(!m_lockedRegisters.get(wantedPayloadGPR));
233
        if (CachedRecovery* currentPayload { m_registers[wantedPayloadGPR] }) {
234
            if (currentPayload == &location) {
235
                if (verbose)
236
                    dataLog("   + ", wantedPayloadGPR, " is OK\n");
237
            } else {
238
                // See above
239
                RELEASE_ASSERT_NOT_REACHED();
240
            }
241
        }
242
    }
243
244
    if (location.recovery().technique() == InPair
245
        || location.recovery().isInGPR()) {
246
        GPRReg payloadGPR;
247
        if (location.recovery().technique() == InPair)
248
            payloadGPR = location.recovery().payloadGPR();
249
        else
250
            payloadGPR = location.recovery().gpr();
251
252
        if (wantedPayloadGPR == InvalidGPRReg)
253
            wantedPayloadGPR = payloadGPR;
254
255
        if (payloadGPR != wantedPayloadGPR) {
256
            if (location.recovery().technique() == InPair
257
                && wantedPayloadGPR == location.recovery().tagGPR()) {
258
                if (verbose)
259
                    dataLog("   * Swapping ", payloadGPR, " and ", wantedPayloadGPR, "\n");
260
                m_jit.swap(payloadGPR, wantedPayloadGPR);
261
                updateRecovery(location, 
262
                    ValueRecovery::inPair(payloadGPR, wantedPayloadGPR));
263
            } else {
264
                if (verbose)
265
                    dataLog("   * Moving ", payloadGPR, " into ", wantedPayloadGPR, "\n");
266
                m_jit.move(payloadGPR, wantedPayloadGPR);
267
                if (location.recovery().technique() == InPair) {
268
                    updateRecovery(location,
269
                        ValueRecovery::inPair(location.recovery().tagGPR(),
270
                            wantedPayloadGPR));
271
                } else {
272
                    updateRecovery(location, 
273
                        ValueRecovery::inGPR(wantedPayloadGPR, location.recovery().dataFormat()));
274
                }
275
            }
276
        }
277
278
        if (wantedTagGPR == InvalidGPRReg)
279
            wantedTagGPR = getFreeGPR();
280
        switch (location.recovery().dataFormat()) {
281
        case DataFormatInt32:
282
            if (verbose)
283
                dataLog("   * Moving int32 tag into ", wantedTagGPR, "\n");
284
            m_jit.move(MacroAssembler::TrustedImm32(JSValue::Int32Tag),
285
                wantedTagGPR);
286
            break;
287
        case DataFormatCell:
288
            if (verbose)
289
                dataLog("   * Moving cell tag into ", wantedTagGPR, "\n");
290
            m_jit.move(MacroAssembler::TrustedImm32(JSValue::CellTag),
291
                wantedTagGPR);
292
            break;
293
        case DataFormatBoolean:
294
            if (verbose)
295
                dataLog("   * Moving boolean tag into ", wantedTagGPR, "\n");
296
            m_jit.move(MacroAssembler::TrustedImm32(JSValue::BooleanTag),
297
                wantedTagGPR);
298
            break;
299
        case DataFormatJS:
300
            ASSERT(wantedTagGPR != location.recovery().payloadGPR());
301
            if (wantedTagGPR != location.recovery().tagGPR()) {
302
                if (verbose)
303
                    dataLog("   * Moving ", location.recovery().tagGPR(), " into ", wantedTagGPR, "\n");
304
                m_jit.move(location.recovery().tagGPR(), wantedTagGPR);
305
            }
306
            break;
307
308
        default:
309
            RELEASE_ASSERT_NOT_REACHED();
310
        }
311
    } else {
312
        ASSERT(location.recovery().isInFPR());
313
        if (wantedTagGPR == InvalidGPRReg) {
314
            ASSERT(wantedPayloadGPR != InvalidGPRReg);
315
            m_lockedRegisters.set(wantedPayloadGPR);
316
            wantedTagGPR = getFreeGPR();
317
            m_lockedRegisters.clear(wantedPayloadGPR);
318
        }
319
        if (wantedPayloadGPR == InvalidGPRReg) {
320
            m_lockedRegisters.set(wantedTagGPR);
321
            wantedPayloadGPR = getFreeGPR();
322
            m_lockedRegisters.clear(wantedTagGPR);
323
        }
324
        m_jit.boxDouble(location.recovery().fpr(), wantedTagGPR, wantedPayloadGPR);
325
    }
326
    updateRecovery(location, ValueRecovery::inPair(wantedTagGPR, wantedPayloadGPR));
327
}
328
329
} // namespace JSC
330
331
#endif // ENABLE(JIT) && USE(JSVALUE32_64)
- a/Source/JavaScriptCore/jit/CallFrameShuffler64.cpp +341 lines
Line 0 a/Source/JavaScriptCore/jit/CallFrameShuffler64.cpp_sec1
1
/*
2
 * Copyright (C) 2015 Apple Inc. All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 * 1. Redistributions of source code must retain the above copyright
8
 *    notice, this list of conditions and the following disclaimer.
9
 * 2. Redistributions in binary form must reproduce the above copyright
10
 *    notice, this list of conditions and the following disclaimer in the
11
 *    documentation and/or other materials provided with the distribution.
12
 *
13
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24
 */
25
26
#include "config.h"
27
#include "CallFrameShuffler.h"
28
29
#if ENABLE(JIT) && USE(JSVALUE64)
30
31
#include "CCallHelpers.h"
32
#include "DataFormat.h"
33
34
namespace JSC {
35
36
DataFormat CallFrameShuffler::emitStore(
37
    CachedRecovery& cachedRecovery, MacroAssembler::Address address)
38
{
39
    ASSERT(!cachedRecovery.recovery().isInJSStack());
40
41
    switch (cachedRecovery.recovery().technique()) {
42
    case InGPR:
43
        m_jit.storePtr(cachedRecovery.recovery().gpr(), address);
44
        return DataFormatJS;
45
    case UnboxedInt32InGPR:
46
        m_jit.store32(cachedRecovery.recovery().gpr(), address.withOffset(PayloadOffset));
47
        return DataFormatInt32;
48
    case UnboxedInt52InGPR:
49
        m_jit.rshift64(MacroAssembler::TrustedImm32(JSValue::int52ShiftAmount),
50
            cachedRecovery.recovery().gpr());
51
        FALLTHROUGH;
52
    case UnboxedStrictInt52InGPR:
53
        m_jit.storePtr(cachedRecovery.recovery().gpr(), address);
54
        return DataFormatStrictInt52;
55
    case UnboxedBooleanInGPR:
56
        m_jit.storePtr(cachedRecovery.recovery().gpr(), address);
57
        return DataFormatBoolean;
58
    case UnboxedCellInGPR:
59
        m_jit.storePtr(cachedRecovery.recovery().gpr(), address);
60
        return DataFormatCell;
61
    case UnboxedDoubleInFPR:
62
        m_jit.storeDouble(cachedRecovery.recovery().fpr(), address);
63
        return DataFormatDouble;
64
    case InFPR:
65
        m_jit.storeDouble(cachedRecovery.recovery().fpr(), address);
66
        return DataFormatJS;
67
    case Constant:
68
        m_jit.storeTrustedValue(cachedRecovery.recovery().constant(), address);
69
        return DataFormatJS;
70
    default:
71
        RELEASE_ASSERT_NOT_REACHED();
72
    }
73
}
74
75
void CallFrameShuffler::emitBox(CachedRecovery& cachedRecovery)
76
{
77
    ASSERT(canBox(cachedRecovery));
78
    if (cachedRecovery.recovery().isConstant())
79
        return;
80
81
    if (cachedRecovery.recovery().isInGPR()) {
82
        switch (cachedRecovery.recovery().dataFormat()) {
83
        case DataFormatInt32:
84
            if (verbose)
85
                dataLog("   * Boxing ", cachedRecovery.recovery());
86
            m_jit.zeroExtend32ToPtr(
87
                cachedRecovery.recovery().gpr(),
88
                cachedRecovery.recovery().gpr());
89
            // We have to do this the hard way.
90
            m_jit.or64(MacroAssembler::TrustedImm64(TagTypeNumber),
91
                cachedRecovery.recovery().gpr());
92
            cachedRecovery.setRecovery(
93
                ValueRecovery::inGPR(cachedRecovery.recovery().gpr(), DataFormatJS));
94
            if (verbose)
95
                dataLog(" into ", cachedRecovery.recovery(), "\n");
96
            return;
97
        case DataFormatInt52:
98
            if (verbose)
99
                dataLog("   * Boxing ", cachedRecovery.recovery());
100
            m_jit.rshift64(MacroAssembler::TrustedImm32(JSValue::int52ShiftAmount),
101
                cachedRecovery.recovery().gpr());
102
            cachedRecovery.setRecovery(
103
                ValueRecovery::inGPR(cachedRecovery.recovery().gpr(), DataFormatStrictInt52));
104
            if (verbose)
105
                dataLog(" into ", cachedRecovery.recovery(), "\n");
106
            FALLTHROUGH;
107
        case DataFormatStrictInt52: {
108
            if (verbose)
109
                dataLog("   * Boxing ", cachedRecovery.recovery());
110
            FPRReg resultFPR = getFreeFPR();
111
            ASSERT(resultFPR != InvalidFPRReg);
112
            m_jit.convertInt64ToDouble(cachedRecovery.recovery().gpr(), resultFPR);
113
            updateRecovery(cachedRecovery, ValueRecovery::inFPR(resultFPR, DataFormatDouble));
114
            if (verbose)
115
                dataLog(" into ", cachedRecovery.recovery(), "\n");
116
            break;
117
        }
118
        case DataFormatBoolean:
119
            if (verbose)
120
                dataLog("   * Boxing ", cachedRecovery.recovery());
121
            m_jit.add32(MacroAssembler::TrustedImm32(ValueFalse),
122
                cachedRecovery.recovery().gpr());
123
            cachedRecovery.setRecovery(
124
                ValueRecovery::inGPR(cachedRecovery.recovery().gpr(), DataFormatJS));
125
            if (verbose)
126
                dataLog(" into ", cachedRecovery.recovery(), "\n");
127
            return;
128
        default:
129
            return;
130
        }
131
    }
132
133
    if (cachedRecovery.recovery().isInFPR()) {
134
        if (cachedRecovery.recovery().dataFormat() == DataFormatDouble) {
135
            if (verbose)
136
                dataLog("   * Boxing ", cachedRecovery.recovery());
137
            GPRReg resultGPR = cachedRecovery.wantedJSValueRegs().gpr();
138
            if (resultGPR == InvalidGPRReg || m_registers[resultGPR])
139
                resultGPR = getFreeGPR();
140
            ASSERT(resultGPR != InvalidGPRReg);
141
            m_jit.purifyNaN(cachedRecovery.recovery().fpr());
142
            m_jit.moveDoubleTo64(cachedRecovery.recovery().fpr(), resultGPR);
143
            m_jit.sub64(MacroAssembler::TrustedImm64(TagTypeNumber), resultGPR);
144
            updateRecovery(cachedRecovery, ValueRecovery::inGPR(resultGPR, DataFormatJS));
145
            if (verbose)
146
                dataLog(" into ", cachedRecovery.recovery(), "\n");
147
            return;
148
        }
149
        ASSERT(cachedRecovery.recovery().dataFormat() == DataFormatJS);
150
        return;
151
    }
152
153
    RELEASE_ASSERT_NOT_REACHED();
154
}
155
156
void CallFrameShuffler::emitLoad(CachedRecovery& cachedRecovery)
157
{
158
    if (!cachedRecovery.recovery().isInJSStack())
159
        return;
160
161
    if (verbose)
162
        dataLog("   * Loading ", cachedRecovery.recovery(), " into ");
163
164
    VirtualRegister reg = cachedRecovery.recovery().virtualRegister();
165
    MacroAssembler::Address address { addressForOld(reg) };
166
    bool tryFPR { true };
167
    GPRReg resultGPR { cachedRecovery.wantedJSValueRegs().gpr() };
168
169
    // If we want a GPR and it's available, that's better than loading
170
    // into an FPR.
171
    if (resultGPR != InvalidGPRReg && !m_registers[resultGPR]
172
        && !m_lockedRegisters.get(resultGPR) && cachedRecovery.loadsIntoGPR())
173
        tryFPR = false;
174
175
    // Otherwise, we prefer loading into FPRs if possible
176
    if (tryFPR && cachedRecovery.loadsIntoFPR()) {
177
        FPRReg resultFPR = getFreeFPR();
178
        if (resultFPR != InvalidFPRReg) {
179
            m_jit.loadDouble(address, resultFPR);
180
            DataFormat dataFormat = DataFormatJS;
181
            // We could be transforming a DataFormatCell into a
182
            // DataFormatJS here - but that's OK.
183
            if (cachedRecovery.recovery().dataFormat() == DataFormatDouble)
184
                dataFormat = DataFormatDouble;
185
            updateRecovery(cachedRecovery,
186
                ValueRecovery::inFPR(resultFPR, dataFormat));
187
            if (verbose)
188
                dataLog(cachedRecovery.recovery(), "\n");
189
            if (reg == newAsOld(dangerFrontier()))
190
                updateDangerFrontier();
191
            return;
192
        }
193
    }
194
195
    ASSERT(cachedRecovery.loadsIntoGPR());
196
    if (resultGPR == InvalidGPRReg || m_registers[resultGPR] || m_lockedRegisters.get(resultGPR))
197
        resultGPR = getFreeGPR();
198
    ASSERT(resultGPR != InvalidGPRReg);
199
    m_jit.loadPtr(address, resultGPR);
200
    updateRecovery(cachedRecovery,
201
        ValueRecovery::inGPR(resultGPR, cachedRecovery.recovery().dataFormat()));
202
    if (verbose)
203
        dataLog(cachedRecovery.recovery(), "\n");
204
    if (reg == newAsOld(dangerFrontier()))
205
        updateDangerFrontier();
206
}
207
208
bool CallFrameShuffler::canLoad(CachedRecovery& cachedRecovery)
209
{
210
    if (!cachedRecovery.recovery().isInJSStack())
211
        return true;
212
213
    ASSERT(cachedRecovery.loadsIntoFPR() || cachedRecovery.loadsIntoGPR());
214
215
    if (cachedRecovery.loadsIntoFPR() && getFreeFPR() != InvalidFPRReg)
216
        return true;
217
218
    if (cachedRecovery.loadsIntoGPR() && getFreeGPR() != InvalidGPRReg)
219
        return true;
220
221
    return false;
222
}
223
224
bool CachedRecovery::loadsIntoFPR() const
225
{
226
    switch (recovery().technique()) {
227
    case DoubleDisplacedInJSStack:
228
    case DisplacedInJSStack:
229
    case CellDisplacedInJSStack:
230
        return true;
231
232
    default:
233
        return false;
234
    }
235
}
236
237
bool CachedRecovery::loadsIntoGPR() const
238
{
239
    switch (recovery().technique()) {
240
    case Int32DisplacedInJSStack:
241
    case Int52DisplacedInJSStack:
242
    case StrictInt52DisplacedInJSStack:
243
    case BooleanDisplacedInJSStack:
244
    case DisplacedInJSStack:
245
    case CellDisplacedInJSStack:
246
        return true;
247
248
    default:
249
        return false;
250
    }
251
}
252
253
void CallFrameShuffler::emitDisplace(CachedRecovery& cachedRecovery)
254
{
255
    ASSERT(cachedRecovery.recovery().isInRegisters());
256
    GPRReg wantedGPR { cachedRecovery.wantedJSValueRegs().gpr() };
257
    ASSERT(wantedGPR != InvalidGPRReg);
258
    ASSERT(!m_lockedRegisters.get(wantedGPR));
259
260
    if (CachedRecovery* current = m_registers[wantedGPR]) {
261
        if (current == &cachedRecovery) {
262
            if (verbose)
263
                dataLog("   + ", wantedGPR, " is OK\n");
264
            return;
265
        }
266
        // We could do a more complex thing by finding cycles
267
        // etc. in that case.
268
        // However, ending up in this situation will be super
269
        // rare, and should actually be outright impossible for
270
        // non-FTL tiers, since:
271
        //  (a) All doubles have been converted into JSValues with
272
        //      ValueRep nodes, so FPRs are initially free
273
        //
274
        //  (b) The only recoveries with wanted registers are the
275
        //      callee (which always starts out in a register) and
276
        //      the callee-save registers
277
        //
278
        //  (c) The callee-save registers are the first things we
279
        //      load (after the return PC), and they are loaded as JSValues
280
        //
281
        //  (d) We prefer loading JSValues into FPRs if their
282
        //      wanted GPR is not available
283
        //
284
        //  (e) If we end up spilling some registers with a
285
        //      target, we won't load them again before the very
286
        //      end of the algorithm
287
        //
288
        // Combined, this means that we will never load a recovery
289
        // with a wanted GPR into any GPR other than its wanted
290
        // GPR. The callee could however have been initially in
291
        // one of the callee-save registers - but since the wanted
292
        // GPR for the callee is always regT0, it will be the
293
        // first one to be displaced, and we won't see it when
294
        // handling any of the callee-save registers.
295
        //
296
        // Thus, the only way we could ever reach this path is in
297
        // the FTL, when there is so much pressure that we
298
        // absolutely need to load the callee-save registers into
299
        // different GPRs initially but not enough pressure to
300
        // then have to spill all of them. And even in that case,
301
        // depending on the order in which LLVM saves the
302
        // callee-saves, we will probably still be safe. Anyway,
303
        // the couple extra move instructions compared to an
304
        // efficient cycle-based algorithm are not going to hurt
305
        // us.
306
        GPRReg tempGPR = getFreeGPR();
307
        if (verbose)
308
            dataLog("  * Moving ", wantedGPR, " into ", tempGPR, "\n");
309
        m_jit.move(wantedGPR, tempGPR);
310
        updateRecovery(*current,
311
            ValueRecovery::inGPR(tempGPR, current->recovery().dataFormat()));
312
    }
313
    ASSERT(!m_registers[wantedGPR]);
314
315
    if (cachedRecovery.recovery().isInGPR()) {
316
        if (verbose)
317
            dataLog("   * Moving ", cachedRecovery.recovery().gpr(), " into ", wantedGPR, "\n");
318
        m_jit.move(cachedRecovery.recovery().gpr(), wantedGPR);
319
        updateRecovery(cachedRecovery,
320
            ValueRecovery::inGPR(wantedGPR, cachedRecovery.recovery().dataFormat()));
321
    } else {
322
        ASSERT(cachedRecovery.recovery().isInFPR());
323
        if (cachedRecovery.recovery().dataFormat() == DataFormatDouble) {
324
            // This will automatically pick the wanted GPR
325
            emitBox(cachedRecovery);
326
        } else {
327
            if (verbose)
328
                dataLog("   * Moving ", cachedRecovery.recovery().fpr(), " into ", wantedGPR, "\n");
329
            m_jit.moveDoubleTo64(cachedRecovery.recovery().fpr(), wantedGPR);
330
            updateRecovery(cachedRecovery,
331
                ValueRecovery::inGPR(wantedGPR, cachedRecovery.recovery().dataFormat()));
332
        }
333
    }
334
335
    ASSERT(m_registers[wantedGPR] == &cachedRecovery);
336
    ASSERT(cachedRecovery.recovery().gpr() == wantedGPR);
337
}
338
339
} // namespace JSC
340
341
#endif // ENABLE(JIT) && USE(JSVALUE64)
- a/Source/JavaScriptCore/jit/GPRInfo.h -7 / +21 lines
Lines 65-70 public: a/Source/JavaScriptCore/jit/GPRInfo.h_sec1
65
    }
65
    }
66
    
66
    
67
    bool operator!() const { return m_gpr == InvalidGPRReg; }
67
    bool operator!() const { return m_gpr == InvalidGPRReg; }
68
    explicit operator bool() const { return m_gpr != InvalidGPRReg; }
69
70
    bool operator==(JSValueRegs other) { return m_gpr == other.m_gpr; }
71
    bool operator!=(JSValueRegs other) { return !(*this == other); }
68
    
72
    
69
    GPRReg gpr() const { return m_gpr; }
73
    GPRReg gpr() const { return m_gpr; }
70
    GPRReg tagGPR() const { return InvalidGPRReg; }
74
    GPRReg tagGPR() const { return InvalidGPRReg; }
Lines 110-115 public: a/Source/JavaScriptCore/jit/GPRInfo.h_sec2
110
    }
114
    }
111
    
115
    
112
    bool operator!() const { return m_base == InvalidGPRReg; }
116
    bool operator!() const { return m_base == InvalidGPRReg; }
117
    explicit operator bool() const { return m_base != InvalidGPRReg; }
113
    
118
    
114
    bool isAddress() const { return m_offset != notAddress(); }
119
    bool isAddress() const { return m_offset != notAddress(); }
115
    
120
    
Lines 166-176 public: a/Source/JavaScriptCore/jit/GPRInfo.h_sec3
166
        return JSValueRegs(InvalidGPRReg, gpr);
171
        return JSValueRegs(InvalidGPRReg, gpr);
167
    }
172
    }
168
    
173
    
169
    bool operator!() const
174
    bool operator!() const { return !static_cast<bool>(*this); }
175
    explicit operator bool() const
176
    {
177
        return static_cast<GPRReg>(m_tagGPR) != InvalidGPRReg
178
            || static_cast<GPRReg>(m_payloadGPR) != InvalidGPRReg;
179
    }
180
181
    bool operator==(JSValueRegs other) const
170
    {
182
    {
171
        return static_cast<GPRReg>(m_tagGPR) == InvalidGPRReg
183
        return m_tagGPR == other.m_tagGPR
172
            && static_cast<GPRReg>(m_payloadGPR) == InvalidGPRReg;
184
            && m_payloadGPR == other.m_payloadGPR;
173
    }
185
    }
186
    bool operator!=(JSValueRegs other) const { return !(*this == other); }
174
    
187
    
175
    GPRReg tagGPR() const { return static_cast<GPRReg>(m_tagGPR); }
188
    GPRReg tagGPR() const { return static_cast<GPRReg>(m_tagGPR); }
176
    GPRReg payloadGPR() const { return static_cast<GPRReg>(m_payloadGPR); }
189
    GPRReg payloadGPR() const { return static_cast<GPRReg>(m_payloadGPR); }
Lines 238-248 public: a/Source/JavaScriptCore/jit/GPRInfo.h_sec4
238
        result.m_tagType = static_cast<int8_t>(JSValue::CellTag);
251
        result.m_tagType = static_cast<int8_t>(JSValue::CellTag);
239
        return result;
252
        return result;
240
    }
253
    }
241
    
254
242
    bool operator!() const
255
    bool operator!() const { return !static_cast<bool>(*this); }
256
    explicit operator bool() const
243
    {
257
    {
244
        return static_cast<GPRReg>(m_baseOrTag) == InvalidGPRReg
258
        return static_cast<GPRReg>(m_baseOrTag) != InvalidGPRReg
245
            && static_cast<GPRReg>(m_payload) == InvalidGPRReg;
259
            || static_cast<GPRReg>(m_payload) != InvalidGPRReg;
246
    }
260
    }
247
    
261
    
248
    bool isAddress() const
262
    bool isAddress() const
- a/Source/JavaScriptCore/jit/JITCall.cpp -4 / +27 lines
Lines 29-34 a/Source/JavaScriptCore/jit/JITCall.cpp_sec1
29
#if USE(JSVALUE64)
29
#if USE(JSVALUE64)
30
#include "JIT.h"
30
#include "JIT.h"
31
31
32
#include "CallFrameShuffler.h"
32
#include "CodeBlock.h"
33
#include "CodeBlock.h"
33
#include "JITInlines.h"
34
#include "JITInlines.h"
34
#include "JSArray.h"
35
#include "JSArray.h"
Lines 167-172 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned ca a/Source/JavaScriptCore/jit/JITCall.cpp_sec2
167
    
168
    
168
        addPtr(TrustedImm32(registerOffset * sizeof(Register) + sizeof(CallerFrameAndPC)), callFrameRegister, stackPointerRegister);
169
        addPtr(TrustedImm32(registerOffset * sizeof(Register) + sizeof(CallerFrameAndPC)), callFrameRegister, stackPointerRegister);
169
        store32(TrustedImm32(argCount), Address(stackPointerRegister, JSStack::ArgumentCount * static_cast<int>(sizeof(Register)) + PayloadOffset - sizeof(CallerFrameAndPC)));
170
        store32(TrustedImm32(argCount), Address(stackPointerRegister, JSStack::ArgumentCount * static_cast<int>(sizeof(Register)) + PayloadOffset - sizeof(CallerFrameAndPC)));
171
170
    } // SP holds newCallFrame + sizeof(CallerFrameAndPC), with ArgumentCount initialized.
172
    } // SP holds newCallFrame + sizeof(CallerFrameAndPC), with ArgumentCount initialized.
171
    
173
    
172
    uint32_t bytecodeOffset = instruction - m_codeBlock->instructions().begin();
174
    uint32_t bytecodeOffset = instruction - m_codeBlock->instructions().begin();
Lines 181-189 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned ca a/Source/JavaScriptCore/jit/JITCall.cpp_sec3
181
        return;
183
        return;
182
    }
184
    }
183
185
184
    if (opcodeID == op_tail_call || opcodeID == op_tail_call_varargs)
185
        emitRestoreCalleeSaves();
186
187
    DataLabelPtr addressOfLinkedFunctionCheck;
186
    DataLabelPtr addressOfLinkedFunctionCheck;
188
    Jump slowCase = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, TrustedImmPtr(0));
187
    Jump slowCase = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, TrustedImmPtr(0));
189
    addSlowCase(slowCase);
188
    addSlowCase(slowCase);
Lines 194-200 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned ca a/Source/JavaScriptCore/jit/JITCall.cpp_sec4
194
    m_callCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
193
    m_callCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
195
    m_callCompilationInfo[callLinkInfoIndex].callLinkInfo = info;
194
    m_callCompilationInfo[callLinkInfoIndex].callLinkInfo = info;
196
195
197
    if (opcodeID == op_tail_call || opcodeID == op_tail_call_varargs) {
196
    if (opcodeID == op_tail_call) {
197
        CallFrameShuffleData shuffleData;
198
        shuffleData.numLocals =
199
            instruction[4].u.operand - sizeof(CallerFrameAndPC) / sizeof(Register);
200
        shuffleData.args.resize(instruction[3].u.operand);
201
        for (int i { 0 }; i < instruction[3].u.operand; ++i) {
202
            shuffleData.args[i] =
203
                ValueRecovery::displacedInJSStack(
204
                    virtualRegisterForArgument(i) - instruction[4].u.operand,
205
                    DataFormatJS);
206
        }
207
        shuffleData.callee =
208
            ValueRecovery::inGPR(regT0, DataFormatJS);
209
        shuffleData.setupCalleeSaveRegisters(m_codeBlock);
210
        info->setFrameShuffleData(shuffleData);
211
        CallFrameShuffler(*this, shuffleData).prepareForTailCall();
212
        m_callCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedTailCall();
213
        return;
214
    }
215
216
    if (opcodeID == op_tail_call_varargs) {
217
        emitRestoreCalleeSaves();
198
        prepareForTailCallSlow();
218
        prepareForTailCallSlow();
199
        m_callCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedTailCall();
219
        m_callCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedTailCall();
200
        return;
220
        return;
Lines 219-224 void JIT::compileOpCallSlowCase(OpcodeID opcodeID, Instruction* instruction, Vec a/Source/JavaScriptCore/jit/JITCall.cpp_sec5
219
239
220
    linkSlowCase(iter);
240
    linkSlowCase(iter);
221
241
242
    if (opcodeID == op_tail_call || opcodeID == op_tail_call_varargs)
243
        emitRestoreCalleeSaves();
244
222
    move(TrustedImmPtr(m_callCompilationInfo[callLinkInfoIndex].callLinkInfo), regT2);
245
    move(TrustedImmPtr(m_callCompilationInfo[callLinkInfoIndex].callLinkInfo), regT2);
223
246
224
    m_callCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_vm->getCTIStub(linkCallThunkGenerator).code());
247
    m_callCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_vm->getCTIStub(linkCallThunkGenerator).code());
- a/Source/JavaScriptCore/jit/Reg.h +1 lines
Lines 101-106 public: a/Source/JavaScriptCore/jit/Reg.h_sec1
101
    
101
    
102
    bool isSet() const { return m_index != invalid(); }
102
    bool isSet() const { return m_index != invalid(); }
103
    bool operator!() const { return !isSet(); }
103
    bool operator!() const { return !isSet(); }
104
    explicit operator bool() const { return isSet(); }
104
    
105
    
105
    bool isGPR() const
106
    bool isGPR() const
106
    {
107
    {
- a/Source/JavaScriptCore/jit/RegisterMap.h +111 lines
Line 0 a/Source/JavaScriptCore/jit/RegisterMap.h_sec1
1
/*
2
 * Copyright (C) 2015 Apple Inc. All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 * 1. Redistributions of source code must retain the above copyright
8
 *    notice, this list of conditions and the following disclaimer.
9
 * 2. Redistributions in binary form must reproduce the above copyright
10
 *    notice, this list of conditions and the following disclaimer in the
11
 *    documentation and/or other materials provided with the distribution.
12
 *
13
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24
 */
25
26
#ifndef RegisterMap_h
27
#define RegisterMap_h
28
29
#if ENABLE(JIT)
30
31
#include "MacroAssembler.h"
32
#include "Reg.h"
33
34
namespace JSC {
35
36
template<typename T>
37
class RegisterMap {
38
public:
39
    T& operator[](Reg reg)
40
    {
41
        return m_map[reg.index()];
42
    }
43
44
    T& operator[](GPRReg gpr)
45
    {
46
        return m_map[MacroAssembler::registerIndex(gpr)];
47
    }
48
49
    T& operator[](FPRReg fpr)
50
    {
51
        return m_map[MacroAssembler::registerIndex(fpr)];
52
    }
53
54
    const T& operator[](Reg reg) const
55
    {
56
        return m_map[reg.index()];
57
    }
58
59
    const T& operator[](GPRReg gpr) const
60
    {
61
        return m_map[MacroAssembler::registerIndex(gpr)];
62
    }
63
64
    const T& operator[](FPRReg fpr) const
65
    {
66
        return m_map[MacroAssembler::registerIndex(fpr)];
67
    }
68
69
private:
70
    std::array<T, MacroAssembler::totalNumberOfRegisters()> m_map { };
71
};
72
73
template<typename T>
74
class GPRMap {
75
public:
76
    T& operator[](GPRReg gpr)
77
    {
78
        return m_map[MacroAssembler::registerIndex(gpr)];
79
    }
80
81
    const T& operator[](GPRReg gpr) const
82
    {
83
        return m_map[MacroAssembler::registerIndex(gpr)];
84
    }
85
86
private:
87
    std::array<T, MacroAssembler::numberOfRegisters()> m_map { };
88
};
89
90
template<typename T>
91
class FPRMap {
92
public:
93
    T& operator[](FPRReg fpr)
94
    {
95
        return m_map[MacroAssembler::fpRegisterIndex(fpr)];
96
    }
97
98
    const T& operator[](FPRReg fpr) const
99
    {
100
        return m_map[MacroAssembler::fpRegisterIndex(fpr)];
101
    }
102
103
private:
104
    std::array<T, MacroAssembler::numberOfFPRegisters()> m_map { };
105
};
106
107
} // namespace JSC
108
109
#endif // ENABLE(JIT)
110
111
#endif // RegisterMap_h
- a/Source/JavaScriptCore/jit/Repatch.cpp -21 / +49 lines
Lines 31-36 a/Source/JavaScriptCore/jit/Repatch.cpp_sec1
31
#include "AccessorCallJITStubRoutine.h"
31
#include "AccessorCallJITStubRoutine.h"
32
#include "BinarySwitch.h"
32
#include "BinarySwitch.h"
33
#include "CCallHelpers.h"
33
#include "CCallHelpers.h"
34
#include "CallFrameShuffler.h"
34
#include "DFGOperations.h"
35
#include "DFGOperations.h"
35
#include "DFGSpeculativeJIT.h"
36
#include "DFGSpeculativeJIT.h"
36
#include "FTLThunks.h"
37
#include "FTLThunks.h"
Lines 1787-1812 void linkPolymorphicCall( a/Source/JavaScriptCore/jit/Repatch.cpp_sec2
1787
    
1788
    
1788
    CCallHelpers::JumpList slowPath;
1789
    CCallHelpers::JumpList slowPath;
1789
    
1790
    
1790
    ptrdiff_t offsetToFrame = -sizeof(CallerFrameAndPC);
1791
    std::unique_ptr<CallFrameShuffler> frameShuffler;
1791
1792
    if (callLinkInfo.frameShuffleData()) {
1792
    if (!ASSERT_DISABLED) {
1793
        ASSERT(callLinkInfo.isTailCall());
1793
        CCallHelpers::Jump okArgumentCount = stubJit.branch32(
1794
        frameShuffler = std::make_unique<CallFrameShuffler>(stubJit, *callLinkInfo.frameShuffleData());
1794
            CCallHelpers::Below, CCallHelpers::Address(CCallHelpers::stackPointerRegister, static_cast<ptrdiff_t>(sizeof(Register) * JSStack::ArgumentCount) + offsetToFrame + PayloadOffset), CCallHelpers::TrustedImm32(10000000));
1795
#if USE(JSVALUE32_64)
1795
        stubJit.abortWithReason(RepatchInsaneArgumentCount);
1796
        // We would have already checked that the callee is a cell, and we can
1796
        okArgumentCount.link(&stubJit);
1797
        // use the additional register this buys us.
1798
        frameShuffler->assumeCalleeIsCell();
1799
#endif
1800
        frameShuffler->lockGPR(calleeGPR);
1797
    }
1801
    }
1798
    
1799
    GPRReg scratch = AssemblyHelpers::selectScratchGPR(calleeGPR);
1800
    GPRReg comparisonValueGPR;
1802
    GPRReg comparisonValueGPR;
1801
    
1803
    
1802
    if (isClosureCall) {
1804
    if (isClosureCall) {
1803
        // Verify that we have a function and stash the executable in scratch.
1805
        GPRReg scratchGPR;
1806
        if (frameShuffler)
1807
            scratchGPR = frameShuffler->acquireGPR();
1808
        else
1809
            scratchGPR = AssemblyHelpers::selectScratchGPR(calleeGPR);
1810
        // Verify that we have a function and stash the executable in scratchGPR.
1804
1811
1805
#if USE(JSVALUE64)
1812
#if USE(JSVALUE64)
1806
        // We can safely clobber everything except the calleeGPR. We can't rely on tagMaskRegister
1813
        // We can't rely on tagMaskRegister being set, so we do this the hard
1807
        // being set. So we do this the hard way.
1814
        // way.
1808
        stubJit.move(MacroAssembler::TrustedImm64(TagMask), scratch);
1815
        stubJit.move(MacroAssembler::TrustedImm64(TagMask), scratchGPR);
1809
        slowPath.append(stubJit.branchTest64(CCallHelpers::NonZero, calleeGPR, scratch));
1816
        slowPath.append(stubJit.branchTest64(CCallHelpers::NonZero, calleeGPR, scratchGPR));
1810
#else
1817
#else
1811
        // We would have already checked that the callee is a cell.
1818
        // We would have already checked that the callee is a cell.
1812
#endif
1819
#endif
Lines 1819-1827 void linkPolymorphicCall( a/Source/JavaScriptCore/jit/Repatch.cpp_sec3
1819
    
1826
    
1820
        stubJit.loadPtr(
1827
        stubJit.loadPtr(
1821
            CCallHelpers::Address(calleeGPR, JSFunction::offsetOfExecutable()),
1828
            CCallHelpers::Address(calleeGPR, JSFunction::offsetOfExecutable()),
1822
            scratch);
1829
            scratchGPR);
1823
        
1830
        
1824
        comparisonValueGPR = scratch;
1831
        comparisonValueGPR = scratchGPR;
1825
    } else
1832
    } else
1826
        comparisonValueGPR = calleeGPR;
1833
        comparisonValueGPR = calleeGPR;
1827
    
1834
    
Lines 1863-1870 void linkPolymorphicCall( a/Source/JavaScriptCore/jit/Repatch.cpp_sec4
1863
        caseValues[i] = newCaseValue;
1870
        caseValues[i] = newCaseValue;
1864
    }
1871
    }
1865
    
1872
    
1866
    GPRReg fastCountsBaseGPR =
1873
    GPRReg fastCountsBaseGPR;
1867
        AssemblyHelpers::selectScratchGPR(calleeGPR, comparisonValueGPR, GPRInfo::regT3);
1874
    if (frameShuffler)
1875
        fastCountsBaseGPR = frameShuffler->acquireGPR();
1876
    else {
1877
        fastCountsBaseGPR =
1878
            AssemblyHelpers::selectScratchGPR(calleeGPR, comparisonValueGPR, GPRInfo::regT3);
1879
    }
1868
    stubJit.move(CCallHelpers::TrustedImmPtr(fastCounts.get()), fastCountsBaseGPR);
1880
    stubJit.move(CCallHelpers::TrustedImmPtr(fastCounts.get()), fastCountsBaseGPR);
1869
    
1881
    
1870
    BinarySwitch binarySwitch(comparisonValueGPR, caseValues, BinarySwitch::IntPtr);
1882
    BinarySwitch binarySwitch(comparisonValueGPR, caseValues, BinarySwitch::IntPtr);
Lines 1884-1890 void linkPolymorphicCall( a/Source/JavaScriptCore/jit/Repatch.cpp_sec5
1884
                CCallHelpers::TrustedImm32(1),
1896
                CCallHelpers::TrustedImm32(1),
1885
                CCallHelpers::Address(fastCountsBaseGPR, caseIndex * sizeof(uint32_t)));
1897
                CCallHelpers::Address(fastCountsBaseGPR, caseIndex * sizeof(uint32_t)));
1886
        }
1898
        }
1887
        if (callLinkInfo.isTailCall()) {
1899
        if (frameShuffler) {
1900
            CallFrameShuffler(stubJit, frameShuffler->snapshot()).prepareForTailCall();
1901
            calls[caseIndex].call = stubJit.nearTailCall();
1902
        } else if (callLinkInfo.isTailCall()) {
1888
            stubJit.emitRestoreCalleeSaves();
1903
            stubJit.emitRestoreCalleeSaves();
1889
            stubJit.prepareForTailCallSlow();
1904
            stubJit.prepareForTailCallSlow();
1890
            calls[caseIndex].call = stubJit.nearTailCall();
1905
            calls[caseIndex].call = stubJit.nearTailCall();
Lines 1896-1905 void linkPolymorphicCall( a/Source/JavaScriptCore/jit/Repatch.cpp_sec6
1896
    
1911
    
1897
    slowPath.link(&stubJit);
1912
    slowPath.link(&stubJit);
1898
    binarySwitch.fallThrough().link(&stubJit);
1913
    binarySwitch.fallThrough().link(&stubJit);
1899
    stubJit.move(calleeGPR, GPRInfo::regT0);
1914
1915
    if (frameShuffler) {
1916
        frameShuffler->releaseGPR(calleeGPR);
1917
        frameShuffler->releaseGPR(comparisonValueGPR);
1918
        frameShuffler->releaseGPR(fastCountsBaseGPR);
1900
#if USE(JSVALUE32_64)
1919
#if USE(JSVALUE32_64)
1901
    stubJit.move(CCallHelpers::TrustedImm32(JSValue::CellTag), GPRInfo::regT1);
1920
        frameShuffler->setCalleeJSValueRegs(JSValueRegs(GPRInfo::regT1, GPRInfo::regT0));
1921
#else
1922
        frameShuffler->setCalleeJSValueRegs(JSValueRegs(GPRInfo::regT0));
1902
#endif
1923
#endif
1924
        frameShuffler->prepareForSlowPath();
1925
    } else {
1926
        stubJit.move(calleeGPR, GPRInfo::regT0);
1927
#if USE(JSVALUE32_64)
1928
        stubJit.move(CCallHelpers::TrustedImm32(JSValue::CellTag), GPRInfo::regT1);
1929
#endif
1930
    }
1903
    stubJit.move(CCallHelpers::TrustedImmPtr(&callLinkInfo), GPRInfo::regT2);
1931
    stubJit.move(CCallHelpers::TrustedImmPtr(&callLinkInfo), GPRInfo::regT2);
1904
    stubJit.move(CCallHelpers::TrustedImmPtr(callLinkInfo.callReturnLocation().executableAddress()), GPRInfo::regT4);
1932
    stubJit.move(CCallHelpers::TrustedImmPtr(callLinkInfo.callReturnLocation().executableAddress()), GPRInfo::regT4);
1905
    
1933
    

Return to Bug 147508