Guile 3: Faster programs via just-in-time compilation
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Title of Series | ||
Number of Parts | 561 | |
Author | ||
License | CC Attribution 2.0 Belgium: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor. | |
Identifiers | 10.5446/44309 (DOI) | |
Publisher | ||
Release Date | ||
Language |
Content Metadata
Subject Area | ||
Genre | ||
Abstract |
|
00:00
Compilation albumComputer programSoftware bugCompilerComputer programmingSource codeGoodness of fitMultiplication signTerm (mathematics)BitRight angleRun time (program lifecycle phase)Software maintenanceComputer animationLecture/Conference
01:00
Computer programElement (mathematics)Term (mathematics)Expandierender GraphElement (mathematics)Vector spaceSource codeMultiplication signMacro (computer science)ResultantTask (computing)ProgrammschleifeComputer animation
01:30
Software testingObservational studyComputer programmingComputer scienceResultantOntologyDifferent (Kate Ryan album)Lecture/Conference
02:02
CodeNumbering schemeComputer programNumbering schemeProfil (magazine)Computer programmingCodeCompilerLogic synthesisRun time (program lifecycle phase)Different (Kate Ryan album)Multiplication signSource codeFigurate numberMathematical analysisComputer animation
02:45
Source codeThermal expansionPrimitive (album)Macro (computer science)Form (programming)Mathematical analysisPhase transitionNumbering schemeCuboidMultiplication signInterpreter (computing)Computer animation
03:10
Execution unitReal numberForm (programming)Numbering schemeMaxima and minimaInterpreter (computing)Primitive (album)Macro (computer science)Multiplication signRun time (program lifecycle phase)Lecture/ConferenceComputer animation
03:44
Phase transitionThermal expansionMultiplication signGreen's functionPhysicalismFunctional programmingComputer programmingCompilation albumComputer programmingElectric generatorCodeMathematical optimizationRight angleMathematical analysisMacro (computer science)Lecture/Conference
04:11
CodeVirtual machineTape driveInterpreter (computing)CompilerComputer programThermal expansionMathematical optimizationCodeLevel (video gaming)Electric generatorBytecodeVirtual machineRight angleDirection (geometry)Medical imagingCASE <Informatik>Computer programmingDiagramComputer programmingHookingInterpreter (computing)Ideal (ethics)GodSystem programmingTuring-MaschineBefehlsprozessorMachine codeLine (geometry)Set (mathematics)Computer animation
05:38
CompilerRight angleWeb crawlerCompilation albumLecture/Conference
05:58
Formal languageNumbering schemePrimitive (album)Compilation albumAnalytic continuationRepresentation (politics)Level (video gaming)TowerMathematical optimizationPhase transitionHypermediaCodeComputer animationProgram flowchart
06:25
TowerDifferent (Kate Ryan album)BytecodeMathematical optimizationLevel (video gaming)Direction (geometry)Formal languageLecture/Conference
06:52
Front and back endsFormal languageComputer programmingCompilerFormal languageForm (programming)Multiplication signComputer programmingDebuggerFront and back endsBitSubject indexingCompilerComputer animation
07:32
Set (mathematics)Subject indexingCompilerLibrary (computing)Instance (computer science)Compilation albumRight angleComputer clusterMultiplication signPoint (geometry)Lecture/Conference
08:06
Machine codeCodeLevel (video gaming)TowerMachine codeJust-in-Time-CompilerNumberMedical imagingCodeFormal languageVirtual machineProgram flowchart
08:37
CodeLimit (category theory)Kolmogorov complexityComputing platformImplementationComplex (psychology)Virtual machineImplementationBytecodeLevel (video gaming)Machine codeFormal languageCodeProjective planeBefehlsprozessorCompilerOrder (biology)Multiplication signMereology2 (number)Cross-platformRight angleComputer animation
09:51
Maximum likelihoodInterrupt <Informatik>CodeLambda calculusVector spaceRange (statistics)Machine codeBitMereologyRight angleNumberSelf-organizationElement (mathematics)Functional programmingLevel (video gaming)Parameter (computer programming)Just-in-Time-CompilerPerspective (visual)Vector spaceStack (abstract data type)Control flowInterrupt <Informatik>Set (mathematics)Game controllerLecture/ConferenceComputer animation
11:01
Control flowMachine codeMathematical optimizationSubject indexingVirtualizationRight angleComputer programmingType theoryObject-oriented programmingMachine codeNumberGame controllerVector spaceLevel (video gaming)CompilerBound stateControl flowVirtual machineProjective planeRaw image formatComputer animation
11:30
Mathematical optimizationComputer programmingSubject indexingCompilerCodeQuicksortVector spaceMereologyBound stateMultiplication signLevel (video gaming)Lecture/Conference
12:01
CompilerCompilerCodeInterpreter (computing)Daylight saving timeSet (mathematics)WeightLogical constantBytecodeComputer programmingImplementationGreatest elementVirtual machineRun time (program lifecycle phase)CompilerMachine codeBitInterpreter (computing)Overhead (computing)Intermediate languageCodeComputer animation
12:45
CodeCompilerInterpreter (computing)SequenceJust-in-Time-CompilerInterpreter (computing)WordMachine codeStructural loadMathematical optimizationCompilerSoftware testingMultiplication signDirection (geometry)Complete metric spaceOrder (biology)CodeComputer animation
13:20
Thread (computing)Correspondence (mathematics)CodeProjective planeJust-in-Time-CompilerComputer architectureMachine codeComputer animationLecture/Conference
13:58
ArchitectureCodeResource allocationOperations researchInterpreter (computing)Thread (computing)Resource allocationMultiplication signCorrespondence (mathematics)Machine codeOperator (mathematics)Interpreter (computing)Just-in-Time-CompilerSemiconductor memoryPoint (geometry)CodeStack (abstract data type)HypermediaFunctional programmingControl flowGoodness of fitResultantComputer animation
14:44
Multiplication signTerm (mathematics)QuicksortLine (geometry)PhysicalismPointer (computer programming)NumberJust-in-Time-CompilerMachine codeBitImplementationCodeBytecodeFunctional programmingRun time (program lifecycle phase)Power (physics)Client (computing)Sign (mathematics)Process (computing)Axiom of choiceLecture/Conference
15:25
Code generationCodeFunction (mathematics)IterationLoop (music)Computer configurationMultitier architectureThresholding (image processing)Mathematical optimizationComputing platformWellenwiderstand <Strömungsmechanik>Crash (computing)Resource allocationCodeResource allocationMathematicsExecution unitFunctional programmingComplex (psychology)BitDifferent (Kate Ryan album)Loop (music)Right angleFile formatHazard (2005 film)BytecodeRun time (program lifecycle phase)Wellenwiderstand <Strömungsmechanik>Projective planeRevision controlJust-in-Time-CompilerMultiplication signComputing platformBuffer solutionLibrary (computing)Electric generatorSheaf (mathematics)Machine codeAxiom of choiceCorrespondence (mathematics)Interpreter (computing)Computer fileThresholding (image processing)Range (statistics)Goodness of fitArithmetic meanOrder (biology)Point (geometry)Formal languageSystem callBenchmarkDataflowLine (geometry)Macro (computer science)Object-oriented programmingImage registrationDiscounts and allowancesSequenceLattice (order)CodeArmWindows Registry2 (number)Term (mathematics)System programmingDivisorCategory of beingGraph (mathematics)Computer animation
19:46
Term (mathematics)TelecommunicationMultiplication signLevel (video gaming)Wage labourProjective planeNumbering schemeBenchmarkWeb browserDivisorCompilerHacker (term)Standard deviationForm (programming)BitComputer programmingMemory managementType theoryKey (cryptography)Process (computing)CodeSpring (hydrology)Descriptive statisticsFormal languageLogistic distributionMetropolitan area networkLabour Party (Malta)Cellular automatonRepresentation (politics)Lecture/Conference
21:41
Hacker (term)Computer animation
22:05
Level (video gaming)ECosSpeicherbereinigungRight angleAxiom of choiceMathematicsMultiplication signDecision theoryNumbering schemeFormal languageTerm (mathematics)Lecture/Conference
23:37
ImplementationFormal languageFront and back endsPerspective (visual)Axiom of choiceLecture/Conference
24:37
BitRun time (program lifecycle phase)Ocean currentGeneric programmingCoroutineCodePresentation of a groupTerm (mathematics)Forcing (mathematics)MeasurementNumbering schemeGraph (mathematics)Image resolutionRight anglePort scannerLecture/Conference
25:16
Lecture/ConferenceComputer animation
Transcript: English(auto-generated)
00:11
All right, all right. Oi, oi, oi, oi, oi.
00:23
Yeah. Hi, thanks for coming, thanks for hanging out here. My name is Andy Wingo and I co-maintain Guile along with Ludovic Cortez and Mark Weaver. And I've been mostly working on compiler runtime stuff. And I've been, I'm the worst maintainer
00:40
in terms of bugs, like don't ask me about bugs. All right, so this talk is going to be about Guile 3. It's an upcoming new major release in Guile. Right now we're at Guile 2.2. It's the next incremental step. It's essentially source compatible. Your programs will run in the same way, only faster. So then we're going to talk a little bit more
01:01
about how we got there and where we're going next. But I'm going to skip to the end of the talk already with some results. So like if you're summing a 10 million element vector of pack floats or something, it runs 2.7 times as fast as Guile 2.2. If you take a task, which is less computational
01:22
in terms of tight loops, but still very general purpose, like running the macro expander on this sSACS source file, it's about one and a half times as fast. And then I was going to give it a try with Geeks. And I think I got it, but I don't really understand what I'm testing. So I don't know how fast it is there.
01:41
Yeah, but the thing is it's only going to get faster from here on. That's really the deliverable of Guile 3, so to speak. It's just same thing, but faster. And how do we do that? And how are we here? I didn't study computer science. I just had Guile programs that were running slow.
02:01
And this was around 2006. I had audio synthesizers and different stuff. And I looked into it. I tried everything. I would cache results, like just be very lazy about computing stuff, would drop out and just see if I needed to do particular things. I built a statistical profiler. And in the end, it turned out that the problem
02:23
with my programs was that Guile simply ran scheme code too slow. And Guile should run scheme code faster. And that's how I picked up some compiler work that was sitting around, unmerged, and ended up maintaining the compiler and runtime in Guile. So to give you a sense, I know that there's some small text
02:44
here, that Guile in 2006, which is about Guile 1.8, 1.6 this time, you have your scheme source code on the top. And what would happen is at runtime, you always start from the source code. You would never cache any kind of compiled analysis about what your source code was.
03:01
So you'd go through an expansion phase in which all your macros were expanded out. And then you would have this kind of primitive scheme form. That's the second box there. And at runtime, you just keep interpreting these primitive scheme forms. And we were very proud of our interpreter then. We felt like we had a fast interpreter. And we felt like we were at some kind of local maximum.
03:21
And I guess we were, but it was very local and not very maximum. So what we ended up adding was we separated things into compile time and runtime. And I know this is incredibly basic here, but on this primitive scheme form, we would expand at compile time. So you wouldn't have to, also in old Guile,
03:42
you had to write your macros with performance in mind. You had to write these programs that run on your programs knowing that they're going to run every time you run the program. Whereas in actuality, it's a program that runs on your program. It's a function of your program, not of when you run it. So with adding a compilation phase, we were able to run macro expansion and analysis
04:02
and optimization at compile time, so that at runtime, you would have a byte code, which would then be interpreted. So I know we have red-green accessibility issues here, but the green things would be the expansion phase, optimization phase, the code generation to the byte code. All this happens at compile time. And then at runtime, you just interpret that byte code.
04:24
And I say interpret, there's levels of interpretation in your system. So it was a byte code interpreter interpreting your program. And I know you've all seen those diagrams of ideal Turing machines with the thing and the strip of images and whatever.
04:42
So here, the machine is the virtual machine in Guile, and the strip of images is your byte code. And that machine was implemented by VM.C interpreting your program. And sometimes that machine is called a virtual machine, because the instructions it operates on are not machine instructions.
05:00
They're somehow at a higher level. And you'll see that as Guile develops, we just keep dropping these levels down and down. It's still all virtual. And even to your CPU, the x86 instructions aren't really what your CPU runs, right? Those are expanded out as well in a similar fashion. Right. So the thing is that when Guile becomes faster,
05:21
you can write more things in Guile, right? And I got kind of interested in this. It expands a set of programs that Guile could deal with. I don't think Geeks, a program of half a million lines of code, could be able to start up as fast as it does right now in the old kind of Guile. And the other thing that happened
05:40
as I worked on this is I got hooked. So happily, for me, my work on the Guile compiler has, that's what I do now professionally. Currently, I'm working on Spider Monkey and Firefox. Right. So kept on evolving. And a couple years ago, we released Guile 2.2,
06:02
which is the one that's out, right? It's the one that folks are using, especially in Geeks. And we added just one more phase in here. It turned out that the primitive scheme language that we did optimizations on in the past wasn't actually a great language for doing optimizations. So we have a continuation passing style intermediate representation, which we call CPS soup.
06:22
And it's kind of like SSA for people that work on compilers. And so you do that level of optimization. We still bottom out in byte code, but it's a lower level byte code. So it's a different kind of byte code in Guile 2.2 versus 2.0. But otherwise, it's similar. You can see that the tower is getting taller.
06:41
That's kind of where we're going here. And if you think about Guile 2.2, like where do we need to go? What do we need to do in the language? Like what's our goal? What's our direction? What's our purpose? I think on one side, the language itself needs to do a bit of evolving. We haven't really changed the language that Guile implements in a long time.
07:02
And so we need to update a bit. And I think probably for me, we need to approach Racket. We need to be closer to Racket somehow. That's all front end work, mostly. I've been working mostly on the back end. Guile itself could be faster. I think more kinds of programs could be written in Guile if Guile were faster. And that's what I've been working on.
07:20
And because Guile's compiler, many of you experience Guile in the form of Geeks. How many of you use Geeks here? And when you run Geeks pull, and it has to compile all those damn things, and you're waiting for a long time. Many of you have this experience, I think. Specifically when Geeks is compiling the set of packages
07:42
that it has in its library, which are implemented in Scheme, that's running Guile's compiler, which is written in Guile itself. So speeding up Guile's compiler will speed up all instances of compilation. Users of Guile right now have sometimes a feeling of slow compilation. So speeding up Guile will make that experience better.
08:01
And then otherwise, I just keep working on it, because I'm kind of a junkie. So Guile in 2019, which is Guile 3, we released a pre-release a couple months ago. And this Guile 3 will come out at some point. It's just another level. And so instead of stopping at byte code, we stop at a lower level byte code,
08:21
and then emit corresponding machine code. So simply adding a JIT to the tower. But the fact getting this to work in a maintainable way involved a number of compromises. So I want to explain them, because they will affect how you work with Guile. And I want to emphasize again that it's just
08:42
an incremental step. On a language level, you won't perceive essentially any change. OK. So if you want to stop interpreting virtual instructions, and instead emit native instructions to have the CPU interpret those instructions, because the CPU is interpreting in the end,
09:02
then it's challenging in a small project like ours. Because you don't want to have a lot of code duplication in the compiler. You don't want to add a lot of complexity. You want to keep things simple. So at the same time, Guile's a very cross-platform project. People use it on really weird machines. And I want to actually keep this.
09:20
I don't want to force those users away. So to implement this, and also you don't want to generate too much native code. Many of you remember the Python Unladen Swallow project from back in the day. And in the end, it failed to succeed, as far as I understand, because of complexity and because of code bloat. This is a thing that can happen to language implementations.
09:42
So in order to meet these goals, we had two steps. One, to lower to a lower level bytecode than we had in Guile 2.2, and then second, to actually generate corresponding native code. The first part took much more time. The second part was quite easy. So as an example, this is at the Guile REPL.
10:03
I know it's a little bit hard to read. I think the height of it is going to be the salient fact, though. At the prompt above, I disassemble a function that just references the first element of a vector. And in Guile 2.2, we assert that we have the right number of arguments coming in. We do the vector ref. We handle any interrupts if needed,
10:22
which is like the stack check in JSVMs, for example. And then we return the value. So pretty straightforward. In Guile 3, it's horrible. Or good, depending on your perspective here. It's not really understandable, but it's taller. What it means is that each of these instructions does less.
10:42
The set of instructions is more orthogonal so that that JIT compiler can be smaller, because it has to do less for each instruction. Additionally, it exposes some more control flow that wasn't there before. And it's all just at a much lower level.
11:03
And so you have instructions which are closer to machine code. It's closer to a low level virtual machine, if you will. LLVM. You have more instructions for a given program. In that byte code, you have more control flow. The compiler can do more, though.
11:21
So for example, in that vector ref instruction, it has to do a number of things. It has to check that the vector is a heap object. It has to check that it has the right vector type tag. It has to check that the index is within bounds for the vector. It has to check that the index is actually an integer, all these sort of things. In Gal 3.0 byte code, this is all separate.
11:42
And so it means that if you have a hot part of your code, then the compiler can omit certain parts of these. You don't have to repeat them all. And so this prevents code bloat. But it does mean that the optimizer has a bigger program to work on. And so there's more work for the optimizer to do.
12:01
So on the downside, compile time could be longer. Did we succeed? Maybe not. Because more instructions in the program, a bigger, lower level, intermediate representation means that it's more work for the compiler. And the runtime could be longer also. Because if you think in a virtual machine where you're interpreting byte code, every byte code you execute
12:22
has a bit of overhead for the interpretation, for the dispatch. And so if you add more of them, you might be slowing your program down, even though each one of them is smaller. However, it's easy to generate native code for this. So for example, this is two implementations of the same thing. The top is the byte code interpreter
12:41
for loading a constant, a small constant. And the bottom is emitting machine code for this. So I've put a couple things in bold that's hard to see. Basically, you have an incoming instruction, which is encoded as a 32-bit word. You have to parse out which constant you're going to load and where you're going to put it. Whereas at JIT compilation time, you
13:02
know exactly which constant you're going to materialize into the native machine instruction sequence. And you know exactly where you're going to put it. Likewise, you have to dispatch to the next instruction in the interpreter. Whereas with native code, you don't. You just fall through to the next thing. So although the optimizer and compiler
13:22
has to do more work, the underlying engine is going to run a lot faster once JIT code is generated. And so the bet is that it's going to pay off always. And in my test, that's almost always true. And I'll get to that in just a minute. We use GNU Lightning.
13:42
GNU Lightning is a project which exposes an API. When you run JIT underscore MAVI, it emits corresponding machine code to load an immediate into a register. And it has back ends for every architecture that's used today. And so on that side, it's really good.
14:01
The native code that Guile emits right now does the corresponding operations on the Guile stack that the interpreter would. And I don't have time to go into how the Guile stack is represented, but it means that every instruction, if it takes operands, it will load them from memory.
14:21
And if it produces results, it will write them back to corresponding slots currently. There's no register allocation. It's a next step, and it's a necessary next step. However, this does mean that because there is this correspondence between every interpretation of an instruction and every JIT corresponding native code
14:41
for that instruction, it means you can switch between the two at any time you want. So at any time that you determine that a function is hot and you need to emit native code, you can do so and then jump into the corresponding place in that emitted machine code. And if at any time you determine, actually, I need to do some debugging, I need to set a breakpoint, I need to do whatever, you can jump down from machine code
15:01
into the corresponding byte code. So on that side, we preserve a bit of simplicity on the implementation side. And the JIT itself is only 5,000 lines of code. Not even source lines, like physical lines of code. And we did pretty good in terms of number of reserve registers. There's only one that really needs to be preserved. And there's a stack register, which
15:21
is a sort of base pointer for writing values. That one can be reloaded, but it's usually always there as well. So the thing is, when you generate native code, when do you do it? You have lots of choices. And you generate native code with GCC, for example, ahead of time. You run your compile phase, and then at runtime,
15:41
there's no code generation. We can do this, and this is entirely possible. It's not yet implemented, but as I mentioned, currently, the native code that we generate is a pure function of the byte code to which it corresponds. And so we can simply cache this emitted code in the ELF file that we produce already
16:00
in a separate section. Because GAO's object file format is ELF, and it's one of these formats that you can have a bunch of different sections, and that's fine. And the byte code that GAO emits is done in such a way that this is not really a linking hazard. You don't have to do a lot of relocations
16:20
when you load the code at runtime. But as I mentioned, it's not yet implemented. Currently, what we have is just-in-time code emission, JIT code emission, meaning at some point, we determined that it would be a good idea to emit native code for this piece of byte code for this function and its corresponding byte code, and we do that.
16:42
And specifically, we do this, we need to avoid emitting JIT code for code that's only run once, for example. Because if we emit JIT code for everything in the system, it means that stuff that's not important will undergo the cost of emitting the JIT code plus the cost of running the instruction, which
17:00
is usually more than the cost of simply interpreting an instruction. And that leads to slower startup time. And I want to keep things in the 10 millisecond, 15 millisecond range. And a lot of GAO is written in itself, also. This is a fundamental bit of this that doesn't apply to a lot of other language implementations, like JavaScript implementations, for example.
17:21
So what we have is a counter associated with each function. The function is the unit for which we emit byte code. And this counter is incremented every time a function is called. And additionally, at any loop back edge, or at any target of a loop back edge, rather. And so when this counter overflows some threshold, then that function gets its corresponding native code
17:42
emitted, and we jump into the corresponding native code. And currently, that tier-up threshold, it's called tiering up when you move from the byte code interpreter into corresponding native code and tiering down otherwise. That's a configurable threshold.
18:01
So status, where we at? We have some impedance problems with GNU Lightning, unfortunately. So GNU Lightning, when I remembered it, when I thought about what it was, it was this project where it was almost written entirely in C++ macros, or C macros, CPP macros.
18:21
They would just emit code into a buffer when you run the thing. But it turns out that GNU Lightning had a major version change in which the API was kept mostly the same. But instead of emitting code directly, it built up a graph of nodes, which it would then proceed to optimize and do register allocation for in order to optimize, especially, calls.
18:42
And unfortunately, that's just not what we need. I don't need this thing to do register allocation. I don't want this complexity lying underneath what I'm working on. And it crashes, and I don't understand why. And I've spent a lot of time on this. And it takes time. So I need to abandon Lightning 2.
19:00
I would go back to 1, except it doesn't have a lot of platform support. So currently, unfortunately, I'm looking at writing another stupid chip library. And if anyone knows of good, appropriate libraries, talk to me afterwards. I'd be interested in hearing your experiences.
19:21
Right. And so next, the quality of the code that we emit is not great. And partly, this is because of Lightning. But it's mostly because of lack of good register allocation. And so that's a definite next step. And this is a totally well trodden path for VMs, like doing register allocation over function unit byte code.
19:43
And I want to get us to a point at which we have consistently comparable performance to Shea. We beat them only a couple of times in a couple of the standard benchmarks now, but usually we're 4 to 10 times slower than Shea. And so I want to be consistently within a factor of 1 in terms of speed
20:02
compared to Shea's scheme. Given that the compiler has a lower level byte code, a lower level intermediate representation, it works with your programs on a lower level. Another obvious thing is we don't always run programs these days in the form of compiled C code, for example. Most of the programs many of us run are written in JavaScript
20:22
and deployed via a web browser. And it seems pretty obvious to target the WebAssembly standard that probably most of you all know about. There's a proposal, which I have to check on its status, called the GC proposal, which introduces a typed heap to WebAssembly, which is something that WebAssembly doesn't have yet.
20:41
And I would like to depend on that if that manages to progress. Obviously, I think we need to evolve the length. Well, I don't know if it's obvious. It's obvious to me. I would like to evolve Guile a bit more. And that means moving closer to Racket in some way. And what that means and how to do it is a long-term project. But I want to do it. And then otherwise, Guile is this project
21:02
that I'm kind of a solitary creature. And I have had some support from work on this in a kind of 20%, 20%, 30% time. But it's a project that I enjoy doing for myself. And I perceive communication as emotional labor.
21:23
Because emotional labor is anything you don't want to do. And self-care is the things you do want to do. So I need to figure out how this can scale better than just some dude hacking on the thing. But I'm really gratified, especially about the geeks community, that you all are just doing so many amazing things with Guile without my being there at all.
21:42
So yeah, any questions? Check it out. We're on Guile on Freenode. I am there. You can ping me as Wingo. Otherwise, we'll be trying to get out some pre-releases. I said in the talk summary in spring, I don't know. I think it might be maybe fall.
22:00
But yeah, that's it. So I'll take any questions. Thank you. In the back. The original Guile garbage collector, PDWC,
22:22
how do you evaluate that decision now? So the question was, in the switch from Guile 1.8 to 2.0, among the things that changed was we adopted the bone collector. And for any one of you, this is a conservative garbage collector.
22:42
I think I am satisfied with it right now. I'm unsatisfied with it on a peak performance level and on a pause time level. This is my performance junkie talking here. But I think these things can be fixed in the future.
23:00
As we get less C code, change becomes more possible. I think it was the right choice then. But that's a personal opinion. I'll be happy to talk about that later. Yes? So you mentioned that you want to move Guile closer to Racket on the front end, so in terms of the language itself. Yes.
23:21
Racket recently, you can also compare what you did to Shea's scheme. It so happens that Racket itself is moving to Shea's scheme under the hood. So why not do that? The question is, why not, because we're interested in moving closer to Racket, which I think
23:43
Chris will have many thoughts on. And Racket itself is rebasing its implementation on top of Shea. Why not rebase on top of Shea? For me, I enjoy the language implementation work, and I want to beat Shea. I think I can, but we'll see. But the back end is not the incredibly interesting thing.
24:01
From a user perspective, it's the language you implement. So I want to make the language itself, I think that's a higher priority than what's running underneath is kind of an imitation detail in some way. Whether it's a good or bad imitation detail choices, well, that's arguable, right?
24:21
But it's not essential, I don't think. One more, yeah. Oh, no, no, no, no.
24:41
I mean, we have a bit of an idea in terms of calling convention between scheme code. Obviously, you need the native calling convention when you call out to generic runtime routines. But the calling convention kind of forces a bit how you think about it.
25:01
I think it didn't like that resolution. Yeah, right. It did this earlier for a related presentation. I don't have huge ideas, no. I keep getting convinced by various people saying, oh, I like linear scan. Oh, I like graph coalescing. Oh, I like iterative whatever. So I don't really know. OK, I'm going to pass the mic over to Chris.
25:22
Thank you very much.