Skip to content

Commit ab55d86

Browse files
committed
Add the first part of the new Light Optimization Layer JIT
https://bugs.webkit.org/show_bug.cgi?id=304250 rdar://166615545 Reviewed by Marcus Plutowski and Yusuke Suzuki. This patch adds the outline of the new LOL JIT. LOL differs from the existing baseline in that we intend to do limited inter-bytecode optimizations. Namely, we're going to try to register allocate between bytecodes. To make slow paths efficient (and eventually OSR exiting possible without a huge memory regression) the plan is to make the register allocator replayable. This works by having the register alligator be templated, so that different backends can either generate code for the allocation or simply replay what was allocated the first time. To make testing of the bytecodes that I wrote possible whenever LOL JIT sees a bytecode that it doesn't know it will just flush all registers. This obviously generates poor code quality but as the number of bytecodes supported increases it should matter less and less. Each bytecode has an overload in LOL::RegisterAllocator which knows about the number of uses, defs and scratches a given bytecode needs. The other upside is that when tuning in the future we can precisely control the logic in one place. e.g. if we know that an IC uses x0-x4 we can always flush those registers and shuffle the result to x0 and any future replayers (i.e. slow paths/OSR) would see that change in the register state. I also added logging so we can see the register allocation state in disassembly, which has been very helpful in debugging. Some of the interesting cases I had to fix for this PR are: 1) The start of the next instruction and the slow-to-hot return point are now different. This is because the next instruction could be a jump target (or not supported) so we have to flush everything to the stack. 2) The current Baseline JIT only calls into BytecodeIndices that actually have a slow path. This differs from LOL JIT where we switch over every instruction to replay the register allocator. Canonical link: https://commits.webkit.org/304769@main
1 parent 8e30257 commit ab55d86

22 files changed

Lines changed: 2357 additions & 67 deletions

‎JSTests/stress/fused-jeq.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ function testJEQF(a, b)
5959
}
6060
noInline(testJEQF);
6161

62-
for (var i = 0; i < 1e4; ++i) {
62+
for (var i = 0; i < testLoopCount; ++i) {
6363
shouldBe(testJNEQ(0, 42), 30);
6464
shouldBe(testJEQ(0, 42), 42);
6565
shouldBe(testJNEQB(0, 0), 1);

‎Source/JavaScriptCore/CMakeLists.txt‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,9 @@ set(JavaScriptCore_PRIVATE_FRAMEWORK_HEADERS
973973
llint/LLIntPCRanges.h
974974
llint/LLIntThunks.h
975975

976+
lol/LOLJIT.h
977+
lol/LOLRegisterAllocator.h
978+
976979
parser/Lexer.h
977980
parser/ParserArena.h
978981
parser/ParserError.h

‎Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,6 +1016,7 @@
10161016
530A66C31FA3E78B0026A545 /* UnifiedSource144.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 530A66AD1FA3E7770026A545 /* UnifiedSource144.cpp */; };
10171017
530A66C41FA3E78B0026A545 /* UnifiedSource145.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 530A66B01FA3E77A0026A545 /* UnifiedSource145.cpp */; };
10181018
530A66CD1FB1346D0026A545 /* SuperSamplerBytecodeScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 530A66CC1FB1346D0026A545 /* SuperSamplerBytecodeScope.h */; };
1019+
530E4FAF2E3455E000479AEE /* LOLJIT.h in Headers */ = {isa = PBXBuildFile; fileRef = 530E4FAB2E34554A00479AEE /* LOLJIT.h */; };
10191020
530F0A982AE0607B00A0EEC0 /* LazyValueProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 530F0A962AE0606900A0EEC0 /* LazyValueProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
10201021
530FB3021E7A0B6E003C19DD /* WasmWorklist.h in Headers */ = {isa = PBXBuildFile; fileRef = 530FB3011E7A0B6E003C19DD /* WasmWorklist.h */; };
10211022
530FDE7521FAB00600059D65 /* testIncludes.m in Sources */ = {isa = PBXBuildFile; fileRef = 530FDE7321FAAFC600059D65 /* testIncludes.m */; };
@@ -4252,6 +4253,8 @@
42524253
530A66B71FA3E77D0026A545 /* UnifiedSource143.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnifiedSource143.cpp; path = "DerivedSources/JavaScriptCore/unified-sources/UnifiedSource143.cpp"; sourceTree = BUILT_PRODUCTS_DIR; };
42534254
530A66B81FA3E77E0026A545 /* UnifiedSource4-nonARC.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "UnifiedSource4-nonARC.mm"; path = "DerivedSources/JavaScriptCore/unified-sources/UnifiedSource4-nonARC.mm"; sourceTree = BUILT_PRODUCTS_DIR; };
42544255
530A66CC1FB1346D0026A545 /* SuperSamplerBytecodeScope.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SuperSamplerBytecodeScope.h; sourceTree = "<group>"; };
4256+
530E4FAB2E34554A00479AEE /* LOLJIT.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = LOLJIT.h; path = lol/LOLJIT.h; sourceTree = "<group>"; };
4257+
530E4FAC2E34554A00479AEE /* LOLJIT.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = LOLJIT.cpp; path = lol/LOLJIT.cpp; sourceTree = "<group>"; };
42554258
530F0A962AE0606900A0EEC0 /* LazyValueProfile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LazyValueProfile.h; sourceTree = "<group>"; };
42564259
530F0A972AE0606900A0EEC0 /* LazyValueProfile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LazyValueProfile.cpp; sourceTree = "<group>"; };
42574260
530FB3011E7A0B6E003C19DD /* WasmWorklist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmWorklist.h; sourceTree = "<group>"; };
@@ -6523,6 +6526,8 @@
65236526
45E12D8806A49B0F00E9DF84 /* jsc.cpp */,
65246527
A7C225CC139981F100FF1662 /* KeywordLookupGenerator.py */,
65256528
79D7B0E121152FD200FE7C64 /* entitlements.plist */,
6529+
530E4FAB2E34554A00479AEE /* LOLJIT.h */,
6530+
530E4FAC2E34554A00479AEE /* LOLJIT.cpp */,
65266531
1432EBD70A34CAD400717B9F /* API */,
65276532
9688CB120ED12B4E001D649F /* assembler */,
65286533
0FEC84B21BDACD5E0080FF74 /* b3 */,
@@ -11868,6 +11873,7 @@
1186811873
92B4EF902D71C3650068CB55 /* LLVMProfiling.h in Headers */,
1186911874
0F75A061200D26180038E2CF /* LocalAllocator.h in Headers */,
1187011875
0F75A060200D260B0038E2CF /* LocalAllocatorInlines.h in Headers */,
11876+
530E4FAF2E3455E000479AEE /* LOLJIT.h in Headers */,
1187111877
BC18C4370E16F5CD00B34460 /* Lookup.h in Headers */,
1187211878
0F4680CD14BBB17D00BFE272 /* LowLevelInterpreter.h in Headers */,
1187311879
981ED82328234D91BAECCADE /* MachineContext.h in Headers */,

‎Source/JavaScriptCore/Sources.txt‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,8 @@ jit/ThunkGenerators.cpp
693693
jit/JITTZoneImpls.cpp
694694
jit/Width.cpp
695695

696+
lol/LOLJIT.cpp
697+
696698
llint/InPlaceInterpreter.cpp
697699
llint/LLIntCLoop.cpp
698700
llint/LLIntData.cpp

‎Source/JavaScriptCore/bytecode/Operands.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ template<typename T> struct OperandValueTraits;
3838

3939
constexpr unsigned maxNumCheckpointTmps = 4;
4040

41-
// A OperandKind::Tmp is one that exists for exiting to a checkpoint but does not exist between bytecodes.
41+
// An OperandKind::Tmp is one that exists for exiting to a checkpoint but does not exist between bytecodes.
4242
enum class OperandKind : uint32_t { Argument, Local, Tmp }; // Keep bit-width in sync with Operand::operandKindBits' definition.
4343
static constexpr OperandKind lastOperandKind = OperandKind::Tmp;
4444

‎Source/JavaScriptCore/generator/GeneratedFile.rb‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ def self.license(file, template, dependencies)
8888

8989
comment = if template.multiline_comment.nil? then template.line_comment else template.multiline_comment[1] end
9090
write(file, $LICENSE.strip.split("\n").map { |line| "#{comment} #{line}" }.join("\n"), "\n\n")
91-
write(file, comment, " Autogenerated, do not modify.\n")
91+
write(file, comment, " Autogenerated by generator/main.rb, do not modify.\n")
9292

9393
unless template.multiline_comment.nil?
9494
write(file, template.multiline_comment[2], "\n")

‎Source/JavaScriptCore/jit/AssemblyHelpers.h‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1507,9 +1507,13 @@ class AssemblyHelpers : public MacroAssembler {
15071507
jitAssertIsJSDouble(gpr);
15081508
return unboxDoubleWithoutAssertions(gpr, resultGPR, fpr, mode);
15091509
}
1510+
void unboxDouble(JSValueRegs regs, GPRReg resultGPR, FPRReg fpr)
1511+
{
1512+
unboxDouble(regs.payloadGPR(), resultGPR, fpr);
1513+
}
15101514
void unboxDouble(JSValueRegs regs, FPRReg fpr)
15111515
{
1512-
unboxDouble(regs.tagGPR(), regs.payloadGPR(), fpr);
1516+
unboxDouble(regs.payloadGPR(), regs.payloadGPR(), fpr);
15131517
}
15141518
void boxDouble(FPRReg fpr, JSValueRegs regs, TagRegistersMode mode = HaveTagRegisters)
15151519
{

‎Source/JavaScriptCore/jit/BaselineJITPlan.cpp‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
#include "config.h"
2727
#include "BaselineJITPlan.h"
28+
#include "LOLJIT.h"
2829

2930
#include "JITSafepoint.h"
3031

@@ -47,9 +48,19 @@ auto BaselineJITPlan::compileInThreadImpl(JITCompilationEffort effort) -> Compil
4748
Safepoint safepoint(*this, result);
4849
safepoint.begin(false);
4950

50-
JIT jit(*m_vm, *this, m_codeBlock);
51-
auto jitCode = jit.compileAndLinkWithoutFinalizing(effort);
52-
m_jitCode = WTFMove(jitCode);
51+
if (Options::useLOLJIT()) {
52+
#if USE(JSVALUE64)
53+
LOL::LOLJIT jit(*m_vm, *this, m_codeBlock);
54+
auto jitCode = jit.compileAndLinkWithoutFinalizing(effort);
55+
m_jitCode = WTFMove(jitCode);
56+
#else
57+
RELEASE_ASSERT_NOT_REACHED();
58+
#endif
59+
} else {
60+
JIT jit(*m_vm, *this, m_codeBlock);
61+
auto jitCode = jit.compileAndLinkWithoutFinalizing(effort);
62+
m_jitCode = WTFMove(jitCode);
63+
}
5364
}
5465
if (result.didGetCancelled())
5566
return CancelPath;

‎Source/JavaScriptCore/jit/JIT.cpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -614,8 +614,8 @@ void JIT::privateCompileSlowCases()
614614
if (JITInternal::verbose)
615615
dataLog("At ", firstTo, " slow: ", iter - m_slowCases.begin(), "\n");
616616

617-
RELEASE_ASSERT_WITH_MESSAGE(iter == m_slowCases.end() || firstTo.offset() != iter->to.offset(), "Not enough jumps linked in slow case codegen.");
618-
RELEASE_ASSERT_WITH_MESSAGE(firstTo.offset() == (iter - 1)->to.offset(), "Too many jumps linked in slow case codegen.");
617+
RELEASE_ASSERT_WITH_MESSAGE(iter == m_slowCases.end() || firstTo.offset() != iter->to.offset(), "Not enough jumps linked in slow case codegen while handling %s.", toCString(currentInstruction->opcodeID()).data());
618+
RELEASE_ASSERT_WITH_MESSAGE(firstTo.offset() == (iter - 1)->to.offset(), "Too many jumps linked in slow case codegen while handling %s.", toCString(currentInstruction->opcodeID()).data());
619619

620620
jump().linkTo(fastPathResumePoint(), this);
621621
++bytecodeCountHavingSlowCase;

‎Source/JavaScriptCore/jit/JIT.h‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ namespace JSC {
6161
class StructureChain;
6262
class StructureStubInfo;
6363

64+
namespace LOL {
65+
class LOLJIT;
66+
}
67+
6468
template<typename> struct BaseInstruction;
6569
struct JSOpcodeTraits;
6670
using JSInstruction = BaseInstruction<JSOpcodeTraits>;
@@ -118,7 +122,7 @@ namespace JSC {
118122
struct SlowCaseEntry {
119123
MacroAssembler::Jump from;
120124
BytecodeIndex to;
121-
125+
122126
SlowCaseEntry(MacroAssembler::Jump f, BytecodeIndex t)
123127
: from(f)
124128
, to(t)
@@ -153,12 +157,13 @@ namespace JSC {
153157
BaselineUnlinkedCallLinkInfo* unlinkedCallLinkInfo;
154158
};
155159

156-
class JIT final : public JSInterfaceJIT {
160+
class JIT : public JSInterfaceJIT {
157161
WTF_MAKE_TZONE_NON_HEAP_ALLOCATABLE(JIT);
158162

159163
friend class JITSlowPathCall;
160164
friend class JITStubCall;
161165
friend class JITThunks;
166+
friend class LOL::LOLJIT;
162167

163168
using MacroAssembler::Jump;
164169
using MacroAssembler::JumpList;
@@ -335,6 +340,7 @@ namespace JSC {
335340
void emitJumpSlowCaseIfNotInt(RegisterID);
336341
#endif
337342

343+
void emitJumpSlowCaseIfNotInt(JSValueRegs, JSValueRegs, RegisterID scratch);
338344
void emitJumpSlowCaseIfNotInt(JSValueRegs);
339345

340346
void emitJumpSlowCaseIfNotJSCell(JSValueRegs);
@@ -671,12 +677,12 @@ namespace JSC {
671677
iter->from.link(this);
672678
++iter;
673679
}
674-
void linkAllSlowCasesForBytecodeIndex(Vector<SlowCaseEntry>& slowCases,
680+
void linkAllSlowCasesUpToBytecodeIndex(Vector<SlowCaseEntry>& slowCases,
675681
Vector<SlowCaseEntry>::iterator&, BytecodeIndex bytecodeOffset);
676682

677683
void linkAllSlowCases(Vector<SlowCaseEntry>::iterator& iter)
678684
{
679-
linkAllSlowCasesForBytecodeIndex(m_slowCases, iter, m_bytecodeIndex);
685+
linkAllSlowCasesUpToBytecodeIndex(m_slowCases, iter, m_bytecodeIndex);
680686
}
681687

682688
bool hasAnySlowCases(Vector<SlowCaseEntry>& slowCases, Vector<SlowCaseEntry>::iterator&, BytecodeIndex bytecodeOffset);

0 commit comments

Comments
 (0)