> Other languages, like JavaScript, are weakly typed, which means that the programmer doesn’t have to worry about such piffling minutiae; you can just write some code and let the compiler do the heavy lifting.
JavaScript isn't weakly typed, you can't for example "cast" a number to a string. There is automatic coercion but that's a different thing. I think he means dynamically typed in this case, that or duck typing.
> Type inference fills in the gap between strong and weak typing so that you can still write sloppy code, but reap some of the speed boost.
I don't even know what to say about this. Following this faulty logic might lead one to believe that Haskell has type inference to make all that sloppy Haskell code perform well. Type inference doesn't have anything to do with strong and weak typing, it has to do with manifest and implicit (or inherent) typing.
Automatic coercion is a part of weak typing [1], and JavaScript certainly is weakly typed ([2], first line). If you define the ability to cast as weak typing, then even C++ would be so. Obviously this definition does not hold.
I don't get how the type inference remark is faulty logic either. Haskell is orthogonal because it is statically typed, but type inference when applied to dynamically typed languages certainly can provide a performance boost.
> If you define the ability to cast as weak typing, then even C++ would be so.
Which is funny because your first link states: "In C++, a weakly typed language, you can cast memory to any type freely as long as you do so explicitly."
I'm pretty sure the last time I read that article it said that there is no generally accepted definition of weak typing. This discussion seems to echo that.
> I'm pretty sure the last time I read that article it said that there is no generally accepted definition of weak typing. This discussion seems to echo that.
Agreed. There ARE definitions but they aren't terribly specific, useful, or even very consistent. Funnily enough, the wikipedia article on strong typing includes C and C++ as an example of strong typing.
In this case anyway, I think it's clear that the author was really talking about the static vs dynamic distinction, and should have used those terms instead:
> Some languages are strongly typed, which means that the programmer must define the type of every class, function, and variable that he uses; tiresome, but it can have big pay-offs in terms of overall speed. Other languages, like JavaScript, are weakly typed, which means that the programmer doesn’t have to worry about such piffling minutiae; you can just write some code and let the compiler do the heavy lifting.
Funnily enough, that definition (whether applied to static or strong typing) would exclude Haskell, one of the most strongly and statically typed languages known to man.
Whether or not a language is strongly typed has no effect on whether the programmer has to define the type of everything. You defined what a statically typed language is, not what a strongly typed language is.
In fact if a language is strongly typed not defining anything will not necessarily have an impact on speed because it is possible to infer types statically at compile time like GHC does for Haskell.
What? C++ is weakly typed; it has one type called "big block of memory". Everything on top of that is just an annotation that the compiler uses to generate code, and the compiler will not do any checking to ensure that what it's generating makes sense.
That description was meant for those who don't understand programming, weak & strong typing, & type inference. It is a good enough description for those who don't know and will never care to know more.
I understand the importance of defining thing correctly, but does the average person need to care or worry about the difference between strongly/weakly typed & statically/dynamically typed?
Probably not, that's certainly a fair point. But in that case why go into it at all? Just say it's magic "faster" juice (and don't post it to HN).
One thing I'm curious about as a developer is how this is different than the type inference that SpiderMonkey already did. The JIT certainly didn't represent numbers as strings in memory or something equally silly prior to this new type inference. Is it better inference that optimizes away boxing or can optimize across function calls or something?
(Just musing "out loud", I don't expect answers to these questions here on HN.)
Agree. Can one say Mediumly Typed? To me a strongly typed language is very stern - you trade some slight annoyance for some slight sanity checks. For example strong typing would not let you say 5 + 5.0 because float <> int.
>> Type inference fills in the gap between strong and weak typing so that you can still write sloppy code, but reap some of the speed boost.
>I don't even know what to say about this. Following this faulty logic might lead one to believe that Haskell has type inference to make all that sloppy Haskell code perform well. Type inference doesn't have anything to do with strong and weak typing, it has to do with manifest and implicit (or inherent) typing.
I'm not sure even manifest typing would be the correct term as he mentions performance. So it looks like he is looking for static vs dynamic.
Dynamic typing but inferring types statically where possible. It is interesting that type inference in a statically typed language leads to less noise and type inference in a dynamic language leads to some speed boost.
If you're interested in the relative performance of the current crop of JS engines, you may like to check http://arewefastyet.com/?a=b&view=regress for commit by commit benchmarking over time.
First, making it fast is extremely difficult. JavaScript compilers are under extreme pressure to compile code quickly, unlike any other type-inferring compiler, because JS compilation keeps the user from seeing the page.
Second, in order to be useful, type inference for JavaScript has to be speculative. JS's semantics require that ints overflow into doubles, for example, meaning that a conservative type inference engine would have to assume every number can potentially be a double. This is too imprecise to be useful, so the inference engine speculates. If the engine guesses wrong, the compiler must not only recompile the function under the new assumptions but also (since this is a global analysis) potentially update every other function that the function called.
Finally, the presence of eval() and the like mean that almost no inference can be totally sound, requiring even more dynamic checks.
There's a reason that (despite what some others are saying in this thread) V8 and Chakra haven't done this yet: it takes a long time to get right.
> JavaScript compilers are under extreme pressure to compile code quickly, unlike any other type-inferring compiler, because JS compilation keeps the user from seeing the page
You only run type inference after you detect the hot loops. Same with other expensive optimizations. This is something that all JITs out there do -- you start with simple interpretation (or extremely cheap compilation, in the case of V8), and then when you detect that you're spending a whole lot of time in one section of code, you replace it with a highly optimized version.
Type inference is not that expensive compared to several more interesting optimizations done on several JITs that are in production systems. In some long running JITs, the compilation of some hot loops takes far longer than static compilations, running in a low priority thread in the background (while the less optimized code keeps going in the foreground).
Finally, if anything, JITs allow more time to run heavy optimizations because they can leave those running in the background without affecting the use of the program or hurting developer productivity.
> JS's semantics require that ints overflow into doubles, for example
On recent x86 processors, you would just use doubles in most cases. It turns out that they're on par with integers for speed, although I believe there were some differences on latency. I'd have to look back at the Intel opt manual to confirm, though. However, if you really want to solve the issue (say, on ARM where integer/float performance actually matters -- especially since lots of architectures are still on softfloat), then you'd use a combination of guards, versioning, and VRP to solve the issue, not type inference.
> Finally, the presence of eval() and the like mean that almost no inference can be totally sound, requiring even more dynamic checks.
Yep, eval is a terrible language feature if you care about making things fast. Regardless of whether you have type inference or not.
Actually, empirical data gathered in Tracemonkey shows that specializing to integers where possible is a performance win even on x86.
This is especially the case in the common situation of code computing array indices. Since those end up being treated as integers in the end, if you have them as doubles for the arithmetic step you have to keep paying double-to-integer conversion costs. The same considerations apply for some DOM methods that take an integer, and similar considerations apply to cases when numbers need to be converted to strings (e.g. when setting .style.top on an element): this is a lot cheaper to do for integers than for doubles.
> You only run type inference after you detect the hot loops.
That is the traditional approach, yes. But it will only get you so far. If you just analyze the current piece of code, you will miss out on a lot of potential optimizations.
For example, the types of the variables in the current function may be always of the same type, but without analyzing all the callers you wouldn't notice that - which means you would need to check the type each time you enter. With a more global analysis you could detect that once and be much faster.
There are a lot of other optimizations of that sort, like global variables - you can prove statically the type of many of them, just by looking in the whole program.
What is cool about this new Type Inference engine is that it is a hybrid approach. It does both local and global, and both static and dynamic analyses. You are very correct that local/dynamic type inference is a known thing, and JITs like TraceMonkey have done a form of it for a long time. But this new engine is something much better.
> If you just analyze the current piece of code, you will miss out on a lot of potential optimizations.
I didn't say that you only analyze the current piece of code. Type inference is, by nature, a global optimization. However, you don't do it until you've identified the hot spots, and you've established that it's worth investing time into it.
First, however, you get something quick running so that there are no delays, and the cost doesn't matter much to the user.
In any case, this is far from low-hanging fruit. It's very difficult to to properly, so it isn't surprising that this is the first mainstream JS engine to do it. It began as a research project - it wasn't clear it would ever end up succeeding at all.
On recent x86 processors, you would just use doubles in most cases. It turns out that they're on par with integers for speed, although I believe there were some differences on latency.
Integer operations have 2-3x the throughput and 4-5x better latency than floating-point operations on recent Intel CPUs.
According to the Intel optimization manual, there's a 5 cycle latency for doubles (4 for floats), but both fp multiply/add and alu ops have a one operation per cycle throughput.
I guess it comes down to how effectively you can schedule stuff.
On the other hand, most of the dynamic checks (type assertion barriers) will be there anyway as the JIT-generated code needs them (for type-specialized traces).
Static type inference may even allow for doing away with some, if it's possible to statically prove types are fully known at compile time for a code section.
Yeah the biggest problem is that there are millions of pre-existing codebases all over the web that mozilla needs to make sure don't break. Since it is a speculative engine, the possibility of breaking even a small percentage of those codebases becomes very likely, so it's really not an easy thing to do.
I'll be curious if it's good enough to enable by default, or if the developer needs to flag the engine somehow to enable the feature.
Since this type inference is speculative and dynamic, if the speculative type optimizations fail you can fall back to less optimized code, or interpreted JS, that handles the badly-typed code. Nothing will break.
It's not, and it's much harder to integrate in a JITted environment than type-specialized paths (where the types are observed at runtime). Strongtalk, for instance, discards pretty much all of its static type information before JITing. HotSpot may very well do the same thing, since it arose from Strongtalk's work.
I almost wish I hadn't learned the distinction between strong/weak and static/dynamic typing, because it drives me crazy when people use the incorrect terminology.
You're confusing Crankshaft with type inference. Crankshaft, which landed around Chrome 10, is an SSA-based optimization infrastructure. Type inference augments an optimization infrastructure with additional information. The two are complementary. V8 does not use type inference.
I don't think that's quite correct. IonMonkey also uses an SSA-based intermediate representation, and Crankshaft does generate type specialized code (as does TraceMonkey).
The big thing that IonMonkey is adding is type inference through static analysis, which is a big deal for JavaScript.
He's correct. This type inference is actually being added to JaegerMonkey according to the article, though IonMonkey will have it too when it's ready.
Crankshaft uses type feedback, not type inference. Ie: it will monitor the types of objects to generate type-specialized code, but will not do static type inference on the code to generate type-specialized code.
> Type Optimizations: One of the most important aspects of enabling performance on JavaScript is to create an efficient type system. The IE9 script engine uses many of the techniques common in modern dynamic language implementations, including type representation, polymorphic inline caching (also called type evolution or hidden classes), and efficient implementation of machine types.
> By the time Firefox 9 reaches the Aurora channel at the end of September, though, type inference should just make your web surfing 20-30% faster — period.
Mmm.. I think they've forgot to factor in the ratio of JavaScript involvement in overall web surfing experience?
Since it's firefox we're talking about, this will likely (positively) impact the browser's own chrome and any extension you've installed, as well as in-page javascript.
Mobile optimization fail. Their ipad-optimized version cuts off part of the content, and the well-hidden link to go to the desktop version doesn't work. And that's even sidestepping the whole issue that the interaction model of their ipad version is worse than that of a regular website.
But it's nice to see that the race is still on, with each browser leapfrogging the others every once in a while.
JavaScript isn't weakly typed, you can't for example "cast" a number to a string. There is automatic coercion but that's a different thing. I think he means dynamically typed in this case, that or duck typing.
> Type inference fills in the gap between strong and weak typing so that you can still write sloppy code, but reap some of the speed boost.
I don't even know what to say about this. Following this faulty logic might lead one to believe that Haskell has type inference to make all that sloppy Haskell code perform well. Type inference doesn't have anything to do with strong and weak typing, it has to do with manifest and implicit (or inherent) typing.