Earlier quoted context omitted.
Is there a list of common language poison pills? I'd like to learn more.
The poison-pills are implementation dependent. At the end of the day it is just a matter of the JIT not optimizing a certain programming pattern. Sometimes it is just because the authors didn't get around to that yet. Sometimes there is a more fundamental reason why optimizing that pattern would be hard. I am most familiar with LuaJIT. It has wiki page with a list of things that force it to fall back to the interpret…
What I Learned Making My Own JIT Language
111–120 of 120 posts
Re: What I Learned Making My Own JIT Language
#112Earlier quoted context omitted.
Is it not fair to say that this is the same thing? My impression was that in designing a compiler you're explicitly determining the rules for language, which is the same as designing the language itself? Or do you mean that technically the compiler, not the language, is JIT? This is a new area for me so apologies if I'm just misunderstanding the mechanics here!
In theory the programming language is independent from the implementation. You could write an alternate implementation if you wanted. JIT-ness is a concept related to the implementation, not to the language.
Re: What I Learned Making My Own JIT Language
#113Title should say 'JIT compiler'.
Used as "a JIT," the term is given new meaning (to refer to a compiler implicitly). And used as "JIT language," its giving the term a new meating (to refer to the fact that the language designed to be JITted).
Re: What I Learned Making My Own JIT Language
#114Earlier quoted context omitted.
How many "better designed" dynamic languages are there even out there? Julia is one such language and is substantially faster than V8, at least for idiomatic code. The problem is that most dynamic languages (like JS) are never designed with speed and efficiency in mind. JS just happens to be the fastest of that bunch (other than Lua) because browser makers have invested substantial effort into making it fast - far mo…
I don't understand interest in dynamic languages. I have worked with them extensively, but I find them to be handicapped without benefit. However, JS specifically was not designed at all to begin with, but just thrown together, and core concepts have stayed since this first iteration. These core concepts are its primary handicap.
But yes, in general the same lack of static guarantees that makes dynamic languages slow also makes code in dynamic languages hard to maintain. I think a lot of programmers tinker with code in dynamic languages and end up liking them as a result, but don't realize the difficulty of working in such a language in a much more complex codebase.
Re: What I Learned Making My Own JIT Language
#115A while back, it looked like v8 deopt type guards, for at least monomorphic call sites, were consistently ending up off of the processor speculative execution mainline. They were "free"-ish. Then speculative execution attacks and mitigations hit. Does anyone know the current state of play? I've wanted fast multiple dispatch in js for many years. V8's handling of inlining budgets improved, and guards seemed off mainli…
Not really familiar with v8 internals, aren't there ways to do deopts without relying on guards? The JVM deopts methods by hotpatching the start of them to be a jump to runtime handlers.
Yes, in general. But I was basically hoping to craft a javascript multiple dispatch implementation that mostly landed on V8's existing dispatch fast path.
A polymorphic inline cache for a call site, starts with a check(s) that the object is an expected type. And a bit of inlined code, may start with checks that the inlining assumptions (types of arguments, etc) are still valid. In the JITed assembly, it looks like a bunch of test and jump instructions that come before the real work. But the processor's branch prediction, ideally recognizes that the common case is a still-valid cache/inlining. So the processor's speculative execution, ideally proceeds immediately with the real work. The checks happen off to the side - they don't delay the real work.
One way to do dynamic multiple dispatch is a dispatch tree of similar checks. As with regular dispatch, most multiple dispatch call sites are monomorphic. So if the dispatch checks gets inlined, you would have an extended version of the usual checks. And V8 changed how it allocates it's inlining budget, in a way that made arranging for inlining of dispatch seem more plausible than it once was. My hope was the dispatch checks would also happen off mainline. So multiple dispatch might be as fast as single dispatch.
But then speculative execution implementation flaws were recognized as a security threat, and jits began intentionally disabling or constraining speculative execution. Which might be sufficient to invalidate the whole idea. Since those mitigations seem an ongoing work in progress, and in the past I've found it expensive to tool up for v8 jit code analysis, I thought I'd see if anyone already had a feel for where we're at/headed.
Re: What I Learned Making My Own JIT Language
#116Earlier quoted context omitted.
Common Lisp (CL) as a language is highly dynamic. However the typical implementation is incrementally AOT compiled (when you define a function, it is compiled, but you can redefine functions with few limitations). CL as a language is essentially untyped[1], but does provide some provision for type hints in the standard. Some implementations extend this to the point where they can generate code as efficient as a typed…
> consider CL to be a static language without horribly misunderstanding the term If you look at the file compilation spec in the standard, the compiler is allowed to inline functions and it can assume that a function in the same file can't be redefined later. -> no late binding for the calls in the file. A function declared by the developers to be inlined, makes them also no longer use late-binding for calls. Specifi…
Common Lisp as a standard is highly dynamic. Common Lisp as actually implemented and used is sometimes much less dynamic.
Does the existence of Cython mean that Python is a static language? Most python programmers will never use it so I would argue not.
Re: What I Learned Making My Own JIT Language
#117Earlier quoted context omitted.
> consider CL to be a static language without horribly misunderstanding the term If you look at the file compilation spec in the standard, the compiler is allowed to inline functions and it can assume that a function in the same file can't be redefined later. -> no late binding for the calls in the file. A function declared by the developers to be inlined, makes them also no longer use late-binding for calls. Specifi…
While I see your point, I wonder where to draw the line. Lisp has a stronger history of implementations that limit dynamicism. Common Lisp as a standard is highly dynamic. Common Lisp as actually implemented and used is sometimes much less dynamic. Does the existence of Cython mean that Python is a static language? Most python programmers will never use it so I would argue not.
The CL standard is describing more 'static' options than usual for Lisp. Lexical binding is more static than Dynamic Binding. Macros are more static than Fexprs. A file compiler is more static than an interpreter.
Common Lisp was already designed with support for higher-performance implementations on stock hardware.
Python is not a 'language' - but for most people it is the combination of a language and its implementation. In this Python one of the main (THE main?) ways to get better performance is to write the code in C.
Not so Common Lisp - it is a language and a bunch of more or less conforming implementations. There the first and most important way to get better performance always has been to use an optimizing to-C or a to-Machine-Code compiler, code hints and compiler switches (SPEED, SAFETY, DEBUG, ...).
For example the developers of a large CAD system written mostly in Lisp (iCAD, PTC, ...) did not compete with Python at that time, but with C++ based CAD systems. Having a dynamic CLOS implementation is then often a burden: how many objects can be created per second? How many generic function calls are possible per second?
For example LispWorks allows the slot-value function to call a generic function slot-value-using-class. This is slow. Thus by default it is shut off.
Clozure CL has I/O functions over streams. By default streams are not CLOS objects / functions. One can get them as CLOS objects, but one has to do that.
There are many other examples where the implementation provides a dynamic version and a more static version.
The typical example in Common Lisp, the language itself: structures and CLOS classes.
Structures are efficiently compiled with inline access, no slot information, no updates on structure changes, efficient access into the slot (-> no multiple inheritance with changing slot otder).
CLOS classes OTOH are the opposite. More dyanamic, especially in an implementation with the Meta-object Protocol supported.
Whenever you decide to use structures in your program, then you choose 'static & fast'. When you choose CLOS classes then you choose: runtime dynamism and generally slower.
The standard itself does not talk about a specific implementation - the implementations in use and the needs of the developer for their application delivery determines then how 'static' the implementation can be or needs to be.
Re: What I Learned Making My Own JIT Language
#118Sure, there are things that can be "poison pills" for performance, even in JITs. For example, another reason why my fib benchmark beats V8 is that V8 has to continually check if the fib function was redefined as a deoptimization check. I don't allow that in Vaiven, so I can produce faster code. Dart was designed to have fewer of these poison pills, for instance. Note to language designers: Reduce your language's pois…
I say screw deoptimization checks, and put the burden in the redefinition processing. When you redefine something, you stop the world at safepoints and update prior baked assumptions that are registered on the old definition. These redefinitions usually happen during development and initialization, not during performance-sensitive runtime. It would add more to the memory footprint, but that information is not accesse…
> you stop the world at safepoints
But that's how deoptimisation checks work.
Re: What I Learned Making My Own JIT Language
#119Earlier quoted context omitted.
I would be intrigued to see a modern attempt at a dynamic language like Python or Ruby, but with attention paid from day one to ensure that only very JIT-able constructs were used, and with an eye towards the language helping the user stick to those and be aware of when they deviate, rather than designing a language, setting "runs fast" somewhere around the third or fourth priority, then trying to JIT it after 10-15…
perl6 on MoarVM is starting to grow a JIT
What it just got recently is a pluggable specializer that allows more interesting optimizations to be written in a higher level language (NQP). Since this is closer to Perl 6 than the VM it has more information with which to decide how to optimize code. (Note that it also means you can do the same with any other language that runs on MoarVM, even if it is very different from Perl 6)
Re: What I Learned Making My Own JIT Language
#120I'm impressed that people didn't mention https://www.gnu.org/software/libjit/ it's a small well designed library with a very good interpreter. I wish more people put some effort on improving it and all of us could benefit form it without reinventing the whell again and again.
On the first page of the documentation for libjit is this:
“Only a very small proportion of the work is concerned with language specifics.”
The thing is that Perl 6 tends to break more of the established rules than it follows.For example, most normal operators in Perl 6 are just subroutines with a special name:
a + b == &infix:«+»(a,b)
put &infix:«+».candidates.elems; # 26
There is currently 26 multi subs with the same name for handling the numeric infix addition operator.
(27 if you count the proto sub)That is among the easiest of things to optimize in Perl 6.
I would also like to know if it is a JIT that profiles and compiles the optimized code on another thread like MoarVM does. Is there a plugin system that allows high level code to influence what code gets JIT compiled like MoarVM recently received?
I'm sure that for just about every other dynamic language libjit would be very suitable. It's just that I imagine it would quickly strain under the weight that is Perl 6.
(Perl 6 brings in many varied features from many languages, and combines them in a way that it feel like they have always belonged together.)