5 ms·
Integers are hardly the worry. Any custom types the user makes are the problem.
by hacker_9 10y ago
Integers are hardly the worry. Any custom types the user makes are the problem.
- Klathmon 10y agoIntegers are the worry. the JIT being able to say "This here is an int, which means that this function takes an in and returns an int always, i'm going to compile it that way" means that now that function is "C-Speed". If your program were filled with functions similar to that where the compiler is easily able to optimize the shit out of it, then it will run suprisingly close to "C-Speed". Custom types (which I took to mean different data storage formats) aren't really something that the compiler can help with (any compiler). If you use a hashmap, you've got a hashmap, if you use a doubly-linked-list you've got a doubly-linked-list. C or JS iterating over an entire hashmap is going to be slower than iterating over memory addresses. But luckily JS has stuff like TypedArrays which are basically C arrays with bounds checking. And if you loop over it in a way that the compiler can determine you won't go out of bounds (say, with a simple for loop that runs while x < arr.length), you've got memory access at C speeds. So you "can" (technically, on paper) make a JS program that would run at C speeds in most cases, but at the end of the day some part of your stack is going to begin using the dynamic parts of the language, and then you get the big speed roadblocks again. (by the way, the above is basically what ASM.js is, a well curated subset of JS which doesn't allow anything dynamic so that the JIT can compile it to run at "C speeds") The benefits of a static language aren't in what they allow, but what they don't. Tying your hands and saying "No, you can't make an array of half strings and half integers" lets the compiler be simpler and not have to worry about those "edge cases", which means that it can focus on the "fast path" more. (in practice this almost always shows up as a faster language because JITs aren't perfect, so they can get confused by code that could technically be compiled more optimally but won't because the JIT can't identify it) It's also why adding optional static typing to a language won't make it faster on it's own (after all, the JIT already knows what types variables are at calling time, telling it that again won't solve anything...)
- hacker_9 10y agoI don't think you are getting it. Here is a custom type in C#: public class CustomType { public int A; public int B; public CustomType2 C; } At runtime this will mean any instance of this type is 32bit * 3 = 96 bits, plus the size of any metadata. Any code that accesses an instance member such as 'customType.B' will simply need to deref the address of customType, then add 32bits, and then deref the address of 'B' to get straight to the value. Now let's do the same in JS: var list = []; for (i = 0; i < userSpecifiedLength; i++) { var customType = {}; customType.A = i; customType.B = i * 10; if (i % 2 == 0) customType.C = { } list.push(customType); } Perfectly normal dynamic JS code, but now at runtime the JS engine has no idea what 'customType' could possibly be, until is has attempted some sort of static analysis at runtime to figure out the fields. Additionally 'C' is optional, and whereas in C# that mean it may be null, in JS that means it could be undefined too. There is also no guarantee that 'customType' is left as is and more fields aren't added to it later. All this leads to having to use dictionaries to store the information, which then require hash lookups every time you access a member. Fast, but not remotely near as fast as the C# runtime who has already mapped everything to an address.
- Klathmon 10y agoThat's almost the exact scenario I am talking about. Your custom type there is perfect in JS. The JIT will VERY quickly determine that i is always an integer (actually before the code is first run it will have figured it out), and will "unbox" that to treat it as such (and not a JS "number" type). Objects in JS have a "hidden class" where they can be stamped out literally just like the C# example, so the JIT will be working with the exact same thing. A memory-mapped custom type. Read up on "Hidden classes" [0] which can give you some insight into how it works. Basically as long as you treat a JS object like you'd treat that C# "custom type" (don't dynamically add or remove properties, stick to one type per property), it will instantly treat it identically to how C# would treat it until it changes (at which point it bails out and tries again, and if that happens too much, it will then default back to fully-dynamic). But even if that weren't the case, you could still write your own data storage in JS that works like that. You could do something like this: const customType = new Uint32Array(3) const A = customType[0] const B = customType[1] const C = customType[2] That storage will not only be typed, but will also have LESS overhead than the C# example, at the expense of clarity (after all, that's basically a C array there). This is basically how asm.js works, and what the code looks like when you compile C code into JS. Obviously you don't want to do that in most cases, but if the JS engine is your bottleneck and your data storage is causing slowness, then it might help. JITs have come a LONG way in the past 5-10 years. It's pretty incredible what they can do, and it's actually not that hard any more to make smaller functions that can run at C speeds in V8 and SpiderMonkey. [0] https://github.com/v8/v8/wiki/Design%20Elements https://github.com/v8/v8/wiki/Design%20Elements