For new experimenters of languages, "array" is the perfect word to use. It's a very common word that everyone learns whenever they start with C or Java. All the people looking to try things will use that term first before learning the proper terms.
Someone who never used rust will search for "rust array". Someone who did will search for "rust vec". You're trying to figure out trends for people who have never used the language.
> You're trying to figure out trends for people who have never used the language.
But you're not filtering out experienced users in the other languages, where "array" is a common term for all levels. So that argument doesn't hold either, unless you included other keywords like "what is" or "how do I" or "what's the equivalent to" to target learners no yet accustomed to the terminology.
It would be interesting to see 1-1 comparison with LuaJIT interpreter _without corresponding runtime changes_. That would given a meaningful baseline for how much you potentially loose/gain using this approach.
Current measurement presents comparison of two wildly different implementation strategies: LuaJIT Remake uses IC and hidden classes while LuaJIT proper does not. It's a well known fact that ICs+hidden classes can lead to major performance improvements. That insight originated in Smalltalk world and was brought to dynamic language mainstream by V8† - but unfortunately it muddles the comparison here.
† V8 was open sourced on September 2, 2008... Coincidentally (though probably not :)) JSC landed their first IC prototype on September 1, 2008.
I agree with your point, but I want to point out that Deegen also provided APIs to hide all the details of inline caching. The bytecode only specifies the body lambda and the effect lambdas, and Deegen lowers it to an efficient implementation automatically, including exotic optimizations that fuses the cached IC effect into the opcode so one indirect branch can be avoided.
If LuaJIT interpreter were to employ IC, it would have to undergo a major rewrite (due to its assembly nature) to have the equally efficient code as LJR (that we generate automatically). This is one advantage of our meta-compiler approach.
Finally, although no experiment is made, my subjective opinion is already in the article:
> LuaJIT’s hand-written assembly interpreter is highly optimized already. Our interpreter generated by Deegen is also highly optimized, and in many cases, slightly better-optimized than LuaJIT. However, the gain from those low-level optimizations are simply not enough to beat LuaJIT by a significant margin, especially on a modern CPU with very good instruction-level parallelism, where having a few more instructions, a few longer instructions, or even a few more L1-hitting loads have negligible impact on performance. The support of inline caching is one of the most important high-level optimizations we employed that contributes to our performance advantage over LuaJIT.
That is, if you compare the assembly between LJR and LuaJIT interpreter, I believe LJR's assembly is slightly better (though I would anticipate only marginal performance difference). But that's also because we employed a different boxing scheme (again...). If you force LJR to use LuaJIT's boxing scheme, I guess the assembly code would also be similar since LJR's hand-written assembly is already optimal or at least very close to optimal.
> The JIT still performs better, but the AOT code starts up faster.
I should update that side note because a lot of things has changed. It should probably say something like:
> Theoretically, Dart VM JIT should have best peak performance, while Dart VM AOT has best startup time. In reality the comparison is quite complicated. AOT has seen a lot of work in the last few years, which made it faster than JIT in some aspects e.g. both direct and highly polymorphic method calls are usually faster in AOT. JIT's peak performance has been languishing in a state of neglect, but it still runs circles around AOT in some cases due to aggressive inlining.
> what's interesting is that static typing buys you somewhat minimal gains in performance.
There are a lot of caveats here. You could potentially claim "minimal gains in peak performance if you can apply adaptive JIT compilation techniques", but even that is stretching it somewhat.
Adaptive JITing comes at a price in terms of warmup, memory usage and implementation complexity. Fixed object shapes help somewhat to reduce the amount of checks needed but they don't take you all the way there. Optimising numerics remains challenging (e.g. think about optimising the case where a field always contains a `double` floating-point value or a field that always contains a 64-bit integer value). Knowing the shape of the container does not yield any information about the shape of elements which implies that some checks have to stay behind in the loops. Yes, monomorphic checks are usually simple (compare+branch) but polymorphic are not. And so on and so forth.
Yes, Dart 1 is easier to compile into efficient code compared to JavaScript. Dart 2 is even easier though - because it is more statically typed.
> but fear that it painted itself into a corner by first targeting memory managed languages.
I've not been tuned in. Is there some good forward progress there? It along with threads felt stalled out. I'd love to see GC adopted as that would, IMO, turn WASM into something close to a universal bytecode. It would significantly expand the number of languages that could reasonably target WASM.
The extension has recently reached Stage 2 - most of the questions around type system have been resolved. V8 has a working implementation. We have build `dart2wasm` compiler targeting this and it shows good numbers.
`dart2native` just concatenates two binaries together: AOT runtime binary and AOT snapshot binary. AOT snapshot is an ELF binary which contains native code generated from your original Dart code.
The approach is not pretty but was chosen as an implementation shortcut.
That's why `strip` does not actually do good things to the binary.
There is no reason to run `strip` on such binaries - because they don't contain anything strippable.
We are planning to fix it some time in the future, we really only expected moderate usage of `dart2native` and only on Linux. Turns out that there is demand for using it all over the place, which includes Mac and Windows and requires things like signing support... And to make executable signable we need to make them real Mach-O / PE executables and not weird concatenations of bytes.
Dart is planning to have a sound non-nullability which means that if something has static type `SomeType` then it is guaranteed to be a value that is actually `SomeType` and not something else.
Thus you can't take `SomeType?` and just cast it to `SomeType` because `SomeType?` can be null and `SomeType` can't be null.
This means this cast has to perform a check and throw if your value is null.
This also means that if you have `e1` and `e1` has non-nullable static type then `e1` would never be null in the NNBD world - which is a very good property (e.g. for optimizations).
Short answer: there are a lot of different editors in the world, but Dart team is not large enough and does not posses necessary expertise to develop top-notch integration with all of them. So it makes sense
to focus on the very popular ones (and both VSCode and IDEA are very popular) and provide very good support for those.
We hope that community can take and support other editors. That is why we provide tools (e.g. dart analyzer which has an LSP wrapper) that make it easy to build Dart plugins for any editor you like to use.
DDC stands for Dart Development Compiler. It is a fast modular compiler that you use for quick edit&refresh development in the browser. It does not do any global optimizations, unlike dart2js - which is what you use for deployment.
It's actually the very same main.dart.js (dart2js compiler does not have ability to target a specific browser, its output is supposed to work in every supported browser).
359kb is its compressed size, 990k is its uncompressed size.
Firefox shows compressed size in the "Transferred" column and uncompressed size in "Size" column.
In Chrome by default you see compressed size only, but if you click "Use large request rows" then you will see both compressed and uncompressed size.