|
It should mean compiling (a lot) less code in the best cases. (JITs compile early and often.) Roughly, today: 1. JIT sees a function take a lot of objects {x: int, y: int} 2. JIT compiles a hot path of that function for {x: int, y: int} 3. JIT sees an object of {x: int, y: int, z: int}, goes to a slow uncompiled (deoptimized) path of that function 4. Over time JIT sees a bunch more of {x: int, y: int, z: int} and compiles a hot path for that function 5. Over time the JIT sees that the compiled hot paths of {x: int, y: int} and {x: int, y: int, z: int} share a bunch of code and get called roughly evenly and further compiles an even more optimized shared hot path of {x: int, y: int, z?: int} Note that this isn't the case in every JIT, or every runtime and mileage always varies when talking about JIT optimizations, but that's a roughly common way to look at that. In theory, knowing ahead of time that expected/preferred shape is {x: int, y: int, z?: int}, the JIT could skip steps 1-4, start from step 5, just one "perfect" hot path for the most common expected object shapes, and see fast code for every {x: int, y: int} and {x: int, y: int, z: int} object the function takes, right from "the beginning" of run time. (It might still fall back to a deoptimized path for a strange, rare {x: string, y: int} or something like that, but it still has a better hot path for what should be the more common/likely arguments. Which is why worst case and possibly average case having type knowledge doesn't perform better than existing JITs. But it can still enhance the best case.) (ETA: Of course, Step 0 is determining that function is on a hot path in the first place. That is assumed to be the same in both cases with/without type information.) |