[HN Gopher] Is WebAssembly magic performance pixie dust?
       ___________________________________________________________________
        
       Is WebAssembly magic performance pixie dust?
        
       Author : pimterry
       Score  : 313 points
       Date   : 2021-04-14 05:08 UTC (17 hours ago)
        
 (HTM) web link (surma.dev)
 (TXT) w3m dump (surma.dev)
        
       | blippage wrote:
       | Seems to me that the flaw with WebAssembly is that it tries to
       | fix the symptom, not the cause. As such, it's doomed to failure.
       | 
       | Just stop festooning a site with pop-ups, trackers, geolocation,
       | subscriptions and all the countless other crap that's
       | increasingly being shoved into web pages. The problem will go
       | away by itself.
        
       | maga wrote:
       | A few years ago I did similar comparison but in context of
       | Node.js and sans manual optimizations:
       | https://github.com/zandaqo/iswasmfast
       | 
       | In my work, I have come to conclusion that it seldom pays off to
       | go "native" when working with Node.js. More often than not,
       | rewriting some computationally heavy code in C and sticking it as
       | a native module yielded marginally better results when compared
       | with properly optimized js code. Though, that doesn't negate
       | other advantages of using said technologies: predictable
       | performance from the start and re-using existing code base.
        
       | not_knuth wrote:
       | Just you wait until Lars Bak [0] gets hired by some company to
       | make a fast WebAssembly runtime. Until that happens I won't take
       | any performance comparisons of WASM vs. X seriously :).
       | 
       | [0] https://en.wikipedia.org/wiki/Lars_Bak_(computer_programmer)
        
       | jokoon wrote:
       | I really wish python could be compiled to WASM.
       | 
       | I tried brython, and it's very very slow.
        
         | 0-_-0 wrote:
         | FWIW, Nim can be compiled to WASM.
        
           | francisl wrote:
           | yes but it mostly undocumented, unsupported and trouble
           | assured.
           | 
           | I tried several time and always got stuck somewhere.
           | 
           | Rust that has the reputation to be hard, but is way simpler
           | and faster to get into WebAssembly.
           | 
           | I wish they adopt nlvm as the default compiler, it would make
           | stuff like that way easier and probably boost adoption.
        
             | [deleted]
        
             | dom96 wrote:
             | Someone has to come in and make it supported. Adopting nlvm
             | isn't going to magically make it easier.
             | 
             | The reason it's easier in Rust is because someone that's
             | passionate about WASM came along and did the work up front
             | to document everything and make it as simple to compile to
             | WASM as possible, the same is certainly possible in Nim,
             | just need someone to put in some work :)
        
         | MaxBarraclough wrote:
         | WASM lacks garbage collection and is statically typed. You'd
         | have to write a whole Python interpreter, so I'd expect the end
         | result would be slower than the official Python interpreter.
         | 
         | I imagine it would make more sense to compile Python to
         | JavaScript and leverage the optimising JavaScript JIT engines,
         | but no doubt an efficient transpiler would be a significant
         | undertaking. The Transcrypt project [0] does something like
         | this but I don't think it emphasises performance.
         | 
         | [0] https://www.transcrypt.org/
        
       | RcouF1uZ4gsC wrote:
       | Looking at the C++ code, it seems like you could use
       | std::push_heap/pop_heap to implement your binary heap. The code
       | would be simpler, and there is a chance it could be faster since
       | a lot of the standard library algorithms are very heavily
       | optimized.
        
       | dahfizz wrote:
       | Is there a good comparison between different WASM languages /
       | compilers? I imagine that, since we are in the early days,
       | performance between compilers could vary significantly. Compare
       | to V8, which has had thousands of man-hours from high level
       | engineers.
        
       | 29athrowaway wrote:
       | JavaScript performance is completely vendor specific. There's no
       | reference implementation for a JavaScript VM.
       | 
       | So, it's more useful to talk about, let's say, v8 performance.
       | Much of v8 performance is also version specific, and not all of
       | it is documented.
       | 
       | Code running on v8 can be blazing fast, or it can be slow. It
       | depends on whether the code can be "optimized" (JIT compiled) and
       | kept that way (because code can also be "deoptimized", meaning,
       | the jitted version gets thrown away).
       | 
       | With JavaScript, if you want to ensure your code always runs fast
       | as it possibly can, you have to become acquainted with the rules
       | behind optimization and deoptimization, and start tracing
       | optimizations and deoptimizations to make sure that your code
       | gets optimized, and stays optimized. This process can be time
       | consuming and can make your JavaScript look non-idiomatic and
       | less readable.
       | 
       | In the other hand, WebAssembly performance is easier to reason
       | about with respect to what's described above.
        
       | als0 wrote:
       | Can someone explain to me why WebAssembly is restricted from
       | accessing the DOM or the Web APIs? I haven't been able to find a
       | reason.
        
         | k__ wrote:
         | I'd guess, the main reason is that the standard for doing so is
         | not fixed.
         | 
         | The idea seems that WASM tries to be a general compilation
         | target, so they don't wanna mess it up by integrating with the
         | web platform too soon.
         | 
         | Don't know when or if the interface types are released.
        
         | mantap wrote:
         | You can bridge through JavaScript. It's not a big deal in
         | practice. WASM is still very immature. You do not want to build
         | your whole app in WASM if you want to keep a full head of hair.
        
           | TheCoelacanth wrote:
           | It does limit a lot of use-cases from being viable in WASM.
           | 
           | Anything that needs to do a lot of DOM access will probably
           | see a big performance hit if you rewrite it in WASM because
           | there will be too much overhead from crossing the JS-WASM
           | border.
        
         | als0 wrote:
         | Not sure why I'm being downvoted - the answer doesn't seem
         | obvious?
        
         | brabel wrote:
         | Because before it can access the DOM, it needs to support:
         | 
         | * reference types * interface types * exception handling *
         | typed function references * garbage collection
         | 
         | I.e. most WASM proposals must be accepted before we can use the
         | DOM from WASM... by the pace it's been moving forward, I guess
         | this will take at least several years (3-4+).
         | 
         | https://github.com/WebAssembly/proposals
        
         | danielheath wrote:
         | Webassembly can access anything you give it access to, and only
         | that.
         | 
         | That's great from a trust perspective because it means you can
         | use a binary blob with confidence that it can't do anything it
         | isn't explicitly allowed to.
         | 
         | There's no reason to specify access to the DOM for webassembly
         | since you can grant that access from JS.
         | 
         | The hard bit is making it fast; ideally you could call between
         | WASM and browser code with zero trampolines, but going via JS
         | means you need two.
        
           | als0 wrote:
           | > There's no reason to specify access to the DOM for
           | webassembly since you can grant that access from JS.
           | 
           | There are reasons. If I could write web apps in a different
           | language without having to use any JS, I would. It would be
           | wonderful to be able to pick whatever language you want,
           | compile it, and then deploy it. Having a JS bridge just seems
           | like a clunky workaround that you have to live with.
           | 
           | > That's great from a trust perspective because it means you
           | can use a binary blob with confidence that it can't do
           | anything it isn't explicitly allowed to.
           | 
           | JavaScript is already sandboxed and can access only what you
           | allow it to. Why have a sandbox within a sandbox?
        
         | v8dev123 wrote:
         | You can access DOM and WebAPI using em_val. Emscripten provides
         | the support. WASM doesn't however. It's complicated.
        
       | kodablah wrote:
       | > As described above, it is important to "warm-up" JavaScript
       | when benchmarking, giving V8 a chance to optimize it. If you
       | don't do that, you may very well end up measuring a mixture of
       | the performance characteristics of interpreted JS and optimized
       | machine code.
       | 
       | Since unwarmed first execution is a very common use case on the
       | web, and a very intentional improvement for WASM, it seems
       | foolish to discard that when comparing. I understand for
       | benchmark determinism warming is important in long-running
       | systems, but when parsing/warming is a common part of every run,
       | it deserves to be factored in. I can make WASM look better by
       | removing intentional benefits from JS before comparing too.
        
         | dassurma wrote:
         | Author here!
         | 
         | You even included in the quote: It's important to warm-up the
         | code is so you don't measure a mixture of performance
         | characteristics between interpreted JS and compiled jS. How
         | long the warmup takes is _incredibly_ device dependent, so
         | instead I measured Ignition and SparkPlug independently so you
         | get a feel for the speedup. I did not discard that at all in
         | the comparison.
        
           | azernik wrote:
           | It is indeed in the earlier benchmarks, but:
           | 
           | * It's not in the later ones
           | 
           | * You present TurboFan performance as the speed of
           | JavaScript. e.g. your tables present JavaScript with Ignition
           | as ~40x slower _than JavaScript_ in certain test runs.
        
           | defaultname wrote:
           | It's a fantastic analysis, and I am a bit surprised by some
           | of the results. Thanks for doing the work and putting
           | together a great resource.
           | 
           | kodablah's point is a valid one generally. A parallel post
           | notes that a developer can't avoid the warm-up time, but they
           | can by using WASM.
           | 
           | As an aside, does v8 cache the optimized native code to any
           | degree? I know there is code caching in the major browsers to
           | presumably avoid reparsing Javascript, but if I had a
           | theoretical page with say an image blur function, would each
           | visit/load go through the same analysis/optimization process,
           | going from slow to fast?
        
             | rocqua wrote:
             | I imagine such caching is slowly being phased out because
             | it can be used to create 'super-cookies'. That is, you can
             | fingerprint a user by detecting whether certain bits of
             | javascript are or aren't cached. (Detection of being cached
             | is just a matter of measuring execution time).
        
               | dassurma wrote:
               | It _is_ cached, but the wasm binary itself as well as the
               | optimized version to improve startup times. The cache
               | however is per origin. So no other origin can make use of
               | the cache which prevents the fingerprinting aspect.
        
           | kodablah wrote:
           | My mistake if you are actually including the warm up times in
           | the benchmarks, I misunderstood. Arguably, single-execution-
           | from-scratch JS vs WASM benchmarks could have even more value
           | than repeated, warmed-up benchmarks as the former simulates a
           | common web use case. IMO you _should_ very well end up
           | measuring a mixture of the performance characteristics of
           | interpreted JS and optimized machine code if that represents
           | common use.
        
           | wnevets wrote:
           | Will be this on the next HTTP 203?
        
         | hajile wrote:
         | If you include "warmup" time in JS, then you must also include
         | compile time with WASM (EDIT: to be clear, time to pre-compile
         | wasm from generic bytecode into binary optimized for the
         | particular architecture -- NOT time to compile whatever
         | language into WASM in the first place).
         | 
         | If you're running a given piece of code only once, the
         | interpreted code is almost guaranteed to be MUCH faster than
         | compiling and then executing a large pile of code.
        
           | kodablah wrote:
           | That makes little sense (assuming you mean by "compilation"
           | the compilation to WASM from a higher-level language). The
           | entire point is (or rather should be) to measure runtime
           | impact on the user. If compilation (e.g. parsing, JIT, etc)
           | is part of runtime, you measure that. I wouldn't expect a JS
           | benchmark to measure optimizer/minifier time either.
        
             | hajile wrote:
             | WASM code is byte code that (after being downloaded) is
             | pre-compiled into (presumed) safe native code to be
             | executed. It is designed to be cross-platform and as such,
             | isn't particularly close to any given architecture. This
             | means that there is still room (and necessity) to optimize
             | for a particular architecture when compiling.
             | 
             | Let's say you have some trivial task. You write and compile
             | to wasm. You also write in JS. It'll be a couple kilobytes
             | for JS and probably a couple hundred kilobytes for wasm
             | with all your dependencies to get a usable environment.
             | 
             | Once downloaded, the JS and wasm bytecode must now be
             | parsed. The JS interpreter starts parsing and running.
             | Meanwhile the wasm code is pre-compiling into native code
             | so it can start execution.
             | 
             | The tiny bit of JS takes 10ms to run in the interpreter.
             | The larger WASM file takes 20ms to parse and 0.1ms to run.
             | Which was faster?
             | 
             | That depends on how long the software runs. WASM only makes
             | sense at the inflection point where the execution lasts
             | long enough to counteract the parse time. This shouldn't
             | come as a surprise. Compile lag is one reason why
             | interpreted languages saw real-world use in the first
             | place.
             | 
             | It's telling that v8 used to NOT have an interpreter, but
             | then added one. Everything was first converted to byte code
             | then run. This resulted in slower startup and slower
             | overall performance. Now, the browser starts interpreting
             | while also converting to bytecode in the background before
             | switching over execution. Functions don't actually need a
             | couple hundred runs in order for the optimizer to know what
             | types they receive. Most functions could be optimized with
             | a very high degree of success after only a couple
             | executions. This isn't done because the time cost of
             | optimizing would outweigh the benefit on code that isn't
             | executed frequently.
        
               | staticassertion wrote:
               | > Once downloaded, the JS and wasm bytecode must now be
               | parsed. The JS interpreter starts parsing and running.
               | Meanwhile the wasm code is pre-compiling into native code
               | so it can start execution.
               | 
               | I thought wasm's format was specifically designed so that
               | parsing and compiling could be performed in a streaming
               | fashion, so that you don't have to wait for the download
               | to finish.
        
               | hajile wrote:
               | JS can already be parsed as it is streamed (I think this
               | has been the case since around Chrome v40 and earlier for
               | Firefox). The JS binary AST proposal could make that even
               | more efficient.
               | 
               | My example assumed you were running the code locally. If
               | it's coming over the wire, larger WASM binaries will
               | suffer an additional penalty over the network because
               | download speed is _much_ slower than parse speed.
               | 
               | https://hacks.mozilla.org/2017/02/what-makes-webassembly-
               | fas...
               | 
               | https://hacks.mozilla.org/2018/01/making-webassembly-
               | even-fa...
        
         | hinkley wrote:
         | If you really want answers you should do both.
         | 
         | If I'm trying to improve boot time of my node app, then I must
         | benchmark the cold behavior, (the interpreter). If I'm judging
         | template engine performance, I probably want to do that with a
         | hot VM, because that's going to mostly be steady state
         | performance I'm looking at. The major exception to that may be
         | if I have an exceedingly aggressive caching strategy, where
         | most pages are generated shortly after a deployment (evict all
         | the old pages with whatever the new code generates as output).
        
         | tantalor wrote:
         | As a programmer, there's a lot you can do to make your JS run
         | faster under optimization (e.g. avoid deopt) but there's little
         | you can do about the warm up (besides reducing binary size).
         | 
         | So, when you're trying to progressively improve performance of
         | _specific_ code (e.g. boost FPS) the warm up time is better
         | ignored; it 's not under your control.
        
           | TheCoelacanth wrote:
           | Reducing size or switching to WASM are both things that you
           | can do.
           | 
           | You should measure the cases you actually care about. For a
           | long running app, start-up time is probably not the most
           | important thing, for other apps its very important.
        
           | throwaway894345 wrote:
           | I agree if the benchmark's use case were optimizing JS;
           | however, the question we're trying to answer is roughly "how
           | does JS compare to WASM?".
        
       | sesm wrote:
       | Here is a direct quote from the article: "WebAssembly, on the
       | other hand, is strongly typed. It can be turned into machine code
       | straight away."
       | 
       | Decide for yourself, whether this article is worth your time.
        
         | asimpletune wrote:
         | I think the author just meant their scripting language is
         | strongly typed, but they says wasm because that's the only
         | target for that language.
         | 
         | I wasn't confused by that statement when reading the article.
         | Obviously wasm isn't strongly typed but obviously that's not
         | literally what the author meant.
         | 
         | The article was interesting and they clearly spent a
         | substantial amount of time creating it.
        
         | hutzlibu wrote:
         | I have not decided, whether reading your comment was worth its
         | time, so maybe explain what you mean?
        
           | code-is-code wrote:
           | He is right. Implying that Webassembly is strongly typed is
           | garbage and tells much about the rest of the content.
        
             | hutzlibu wrote:
             | Why is that garbage?
             | 
             | Is this maybe something with academic definition of
             | strongly typed?
             | 
             | Because the way I understand Webassembly, it surely is
             | strongly typed.
             | 
             | edit:
             | 
             | "Strongly typed is a concept used to refer to a programming
             | language that enforces strict restrictions on intermixing
             | of values with differing data types."
             | 
             | https://www.techopedia.com/definition/24434/strongly-typed
             | 
             | Seems to back me up.
        
             | rickbutton wrote:
             | this is nonsense. WebAssembly is strongly typed.
             | 
             | either you don't understand type systems, or you don't
             | understand WebAssembly. in either case, I can encourage
             | reading the article, because it sheds some light on both
             | topics!
        
         | miloignis wrote:
         | WebAssembly _IS_ strongly typed, and that property _DOES_ help
         | it to generate machine code right away. Heck, even its if
         | statements and loops have types associated with them, and those
         | types can help compilation from a stack machine to a register
         | machine. The article even mentions a concrete reason later
         | down, that deopts because a type passed to a function changed
         | can 't happen in webassembly like it can in JIT compiled JS.
         | 
         | And indeed, this article does seem to be worth my time.
        
         | EMM_386 wrote:
         | > Decide for yourself, whether this article is worth your time.
         | 
         | Did you even read the article? It goes into a deep dive on
         | AssemblyScript and WASM including discussions on Rust's
         | std::vec and Go's slices, bump allocators,
         | TurboFan/Sparkplug/Ignition/Liftoff benchmarks, and -O3 versus
         | -O3s flags and contains links to a pull request to try to help
         | with one of the noticed performance issues.
         | 
         | This is a well-written dive into the technology, writing it off
         | because you don't like the definition of "strongly typed" in
         | this sentence is a bit premature.
        
       | bowd wrote:
       | Totally unrelated to the content (which was really great), I
       | found it interesting that he shared his benchmarking setup as a
       | _private_ gist
       | (https://gist.github.com/surma/40e632f57a1aec4439be6fa7db95bc...)
       | which is actually more like an opaque repository with multiple
       | files.
       | 
       | It has forks, revisions, probably some tooling built around (git
       | -> gist) but it's not indexed and can only be found by finding
       | the link somewhere (in most cases).
       | 
       | Is this a more wide-spread recent pattern? Wondering what's the
       | desired outcome in how it compares to just a public repo.
        
       | unnouinceput wrote:
       | Mayabe I'm a nitpicker by default, maybe it was so trivial that
       | the article's author didn't thought of including it in
       | methodology BUT before you test your speed of your port
       | (regardless from what language to what other one) you test that
       | end results are exactly the same.
       | 
       | I see no mention of his port of blur functionality where he
       | tested to see the results of original JavaScript blurring
       | algorithm be the same of the porting one. And believe me, image
       | manipulation can bite you in the proverbial rear at edge cases
       | the best, I've been there. What I want is to see also testing
       | included in the article, not just bench-marking his own solution.
       | Try testing at least the classic 256 cases, that's RGB(x,x,x)
       | (examples: RGB(0,0,0)-black...RGB(127, 127, 127)-gray...RGB(255,
       | 255, 255)-white) then a few thousand random images. Only after
       | that test you can safely move to benchmark for the speed.
        
         | dassurma wrote:
         | I did test that and maybe should have mentioned it in the
         | article :) The repo history actually still has an RGBA buffer
         | dump I think.
        
       | NohatCoder wrote:
       | I really think WebAssembly missed the target. What we really
       | needed was a language doing away with the dynamic nature of
       | JavaScript, while adding 64 bit integers and generic SIMD
       | instructions, and keeping high level features like strings and
       | automatic memory management.
       | 
       | Instead we got the most bare-bone language imaginable, making
       | everyone have to reinvent the wheel for everything. That is not
       | actually fast. If WebAssembly had stuff like basic string
       | manipulation, browsers could easily map that directly to
       | efficient implementations. But with the current rules everything
       | has to be provided as basic instructions that must be compiled
       | under much stricter security rules.
       | 
       | WebAssembly is not assembly, it is an intermediate representation
       | shared between two compilers, and it is actually pretty bad at
       | that.
        
         | flohofwoe wrote:
         | Eh, maybe that's what _you_ need, but not what _we_ need ;)
         | 
         | WASM is an exceptionally good standard compared to most other
         | things on the web platform.
         | 
         | The thing about WASM performance is that WASM _is_ fast (unless
         | you do stupid things), but what 's surprising to most people is
         | that Javascript isn't slow either (at an absurdly high
         | engineering and complexity cost compared to WASM though).
        
           | NohatCoder wrote:
           | What is the point of WASM if JavaScript is just as fast?
           | After reading the article I'm not left with the impression
           | that getting good performance out of WASM is particularly
           | easy either. WASM has most of the performance footguns from
           | C, requires including a lot of details and gunk, like memory
           | layout and an allocator, that the browser compiler would
           | probably be better off doing on its own.
        
             | hutzlibu wrote:
             | a) getting the best of other ecosystems as well
             | 
             | b) WASM _is_ faster today, if done right
             | 
             | c) be faster with WASM with ease ... in the future, after
             | it all and mostly tooling for it, gets stable
        
             | bzbarsky wrote:
             | Note that the article only tested V8. V8 did not have the
             | fastest WASM implementation last I checked.... Results may
             | well differ in other engines.
        
             | flohofwoe wrote:
             | WASM is a much better compilation target than Javascript
             | (and at least as important: it frees Javascript from being
             | a compilation target, instead JS can focus on being a
             | programming language written by humans again).
             | 
             | I'd argue that the main point of WASM is not the
             | performance gain, but that it opens up a fairly
             | straightforward path to use different languages on the web
             | (e.g. it was possible to upstream a WASM backend into LLVM,
             | but if the Emscripten team would have tried to upstream an
             | asm.js backend into LLVM, they'd be laughed out of the room
             | I'm sure - and asm.js also wasn't fast without special
             | handling by the Javascript engine either).
             | 
             | Also don't forget that the above blog post is mostly about
             | "WASM isn't as fast as it should be when using
             | AssemblyScript", which is more of a problem to solve for
             | AssemblyScript than WASM, because when used from C it's
             | fairly easy to get "near-native" performance.
             | 
             | PS: all the disadvantages you're listing (like the linear
             | memory layout) are actually massive advantages (for
             | instance when trying to optimize cache misses) ;)
        
             | cpleppert wrote:
             | WASM can be faster than JS but you need a language that
             | doesn't shoehorn a GC into the compiled binary. I'm not
             | really sure what the author expected here. Modern managed
             | runtimes usually give you the benefit of bump allocation in
             | the nursery for free with a generational GC and the runtime
             | has a lot more room to optimize the GC phase. None of this
             | is possible without a native GC for webassembly.
             | 
             | This isn't WebAssembly being slow the benchmarks just show
             | the overhead of the GC. If you are writing a
             | computationally expensive algorithm in Rust or C++ wasm can
             | be a lot faster but its hard to get close to native
             | performance(i.e. running on bare metal x86/arm).
             | 
             | Our webassembly prototype is about 3-4x faster in raw
             | computation(and that is targeting webassembly exclusively)
             | but has a much higher overhead when interacting with the
             | DOM. That is basically the limiting factor especially on
             | mobile.
        
             | throwaway894345 wrote:
             | From TFA:
             | 
             | > I want to be very clear: Any generalized, quantitative
             | take-away from this article would be ill-advised.
             | 
             | I don't think WASM and JS are "just as fast"--the author
             | only did a couple of microbenchmarks. There are almost
             | certainly many cases in which WASM would outperform JS, but
             | they probably aren't going to be tight loops over an array
             | or similar.
        
             | city41 wrote:
             | One nice thing about wasm is you can (sometimes) bring apps
             | to the web very quickly. I got an emulator written in C
             | fully ported to wasm in about an hour. To be fair this
             | particular app hit all of the sweet spots of Emscripten,
             | and you won't get that lucky with most apps.
        
         | saagarjha wrote:
         | I mean, it's a virtual machine like the JVM. It's just that the
         | code is already generally run through an optimizer, while Java
         | bytecode typically isn't.
        
           | NohatCoder wrote:
           | Yeah, that is a way to look at it. My point isn't what we
           | call it exactly, my point is that it is a hack job that is
           | fairly mediocre at doing what it is supposed to do.
           | 
           | The compiler in the browser is going to run its own
           | optimization anyway, preoptimizing the input isn't
           | necessarily going to help.
        
             | miloignis wrote:
             | Having read the spec and proposals recently when looking at
             | web assembly as a cross-platform bytecode, I have to
             | disagree, it seems very well designed to me. They started
             | with an MVP, and are continuously working on and adding
             | proposals to extend it with more features, including some
             | of the ones you want, I think. Why do you think it's a hack
             | job?
             | 
             | Additionally, I think optimized webassembly should normally
             | be a big benefit, helping both startup time and
             | optimizations the engine might miss (also helping the
             | engine focus on other optimizations / making simpler
             | engines performant).
             | 
             | edit: Indeed, optimization before webassembly makes a big
             | difference in the article's benchmarks, as you can see with
             | how C++/Rust was faster than the hand-crafted
             | AssemblyScript, theoretically because C++/Rust is going
             | through LLVM optimizations.
        
         | miloignis wrote:
         | Part of the reason it's bare bones is because they started with
         | an MVP, and are continuing to add features through a
         | community/standards process. Garbage Collection, reference
         | types, and Interface Types are popular proposals being worked
         | on that I think would address some of your issues. More here:
         | https://github.com/WebAssembly/proposals
        
       | dboreham wrote:
       | Assuming that WebAssembly is for performance is an invalid
       | assumption. The reason for WebAssembly is to provide a runtime
       | environment for AOT compiled languages such as C++, Rust. The
       | performance of programs written on those languages and compiled
       | to the Webasm target may or may not exceed the performance of a
       | program of the same functionality written in JS and executing in
       | the same V8. There's no reason to expect performance to be
       | radically different just because it's Wasm.
        
       | staticelf wrote:
       | I work on an application that could benefit from web assembly but
       | the biggest hurdle for me is that it's kind of complex.
       | 
       | The web used to be quite simple but now it sometimes feels like
       | you have to have a very large team in order to do anything. Sure,
       | I could probably do web assembly but that would take time from
       | other things that also is important.
       | 
       | I get that it is very useful for larger teams making larger
       | applications like Figma. But for small teams it feels like the
       | tooling isn't there yet to do anything useful in the timespan
       | that I need to.
       | 
       | That being said, assemblyscript seems very interesting and I
       | probably should look into it.
        
         | jillesvangurp wrote:
         | It looks complex until you sit down and do it and force
         | yourself to understand what you are doing. Most things are like
         | that.
         | 
         | The way I structure learning things like this in my team is by
         | organizing spikes. We commit to diving into some technology
         | with the goal of finding out how feasible it is for us to use
         | it and a secondary goal of maybe getting something useful
         | going. However the primary goal is finding out if it can work
         | and if so exactly how. If it works out it becomes a regular
         | thing we work on and integrate. This usually starts with
         | studying what is there, what the risks and benefits are, etc.
         | 
         | At some point you reach the point where the only way to learn
         | more is simply doing it. You can analyze something to death
         | without fully understanding it. Just sitting down and doing it
         | becomes the logical next step. The payoff is usually non
         | linear: you gain more if it works than you lose if it doesn't.
         | This is one of those things that you might suspect is valuable
         | like that. So your job is finding that out in an efficient way.
         | 
         | In your team, I would task one or two of your people with
         | spending a max of 2 days to validate that they can take a
         | simple bit of typescript, convert it to assembly script,
         | compile it and hook it up. Chances are pretty good that they'll
         | have working code at the end of those two days. Worst case you
         | lose two days. Best case you figure out it's easy and just
         | works and you move forward.
        
         | enos_feedler wrote:
         | I agree. Is there something specific that you found difficult
         | that should be simple?
        
         | root_axis wrote:
         | It's not that complex, anything in computers can seem complex
         | if you're not familiar with it. I would suggest that you're
         | just not familiar with it, and that's not a knock against you,
         | it's just something that you need to study like anything else.
         | It's not true that you need a large team to do anything on the
         | web these days, the same technology works today that has worked
         | for the last two decades, but if you want to leverage the
         | benefits of _new technology_ you need to invest the time to
         | understand how it works, that 's just the nature of
         | technological advancement.
        
           | rudi-c wrote:
           | Parent mentioned the lack of tooling, and that is indeed
           | where most of the cost of using WebAssembly lies.
           | 
           | You don't really need to learn the assembly language itself
           | since you'll probably just be calling emcc.
           | 
           | However, you may need to build code to marshall more than
           | just ints and strings to the JS code. Even after you do,
           | you'll run into the classical issues of keeping track of
           | object references across a GC & non-GC system.
           | 
           | You may need debugging and find that in-browser debuggers for
           | WASM are primitive/non-existent. You may need to figure out
           | how unmangle stack traces --- including mixed JS/WASM traces.
           | Third-party tools like Sentry for error reporting may not
           | have built support (they sort of recently have and is very
           | under-documented).
           | 
           | All solvable problems, but it's a lot of time spent not
           | building the product. There are plenty of good uses cases but
           | it's usually not the ones based on the false premise that
           | native is somehow always better than interpreted.
        
             | staticelf wrote:
             | Your answer is my thoughts perfectly put in text. Better
             | explanation than what I could come up with myself. Thanks!
        
             | hutzlibu wrote:
             | Also, with wasm you are now dealing with memory leaks and
             | hunting them down, is no fun at the moment.
        
       | dreamcompiler wrote:
       | I'm confused: The benchmarks seem to suggest you'll get best
       | speed in many cases by just writing JS or TS. What's the
       | advantage of AssemblyScript?
       | 
       | If the issue is warmup time, do there not exist AOT compilers for
       | JS (or TS) to WASM?
        
       | toastal wrote:
       | What about performance for SpiderMonkey and JavaScriptCore? I'm a
       | little disappointed that everything in the article from a V8-only
       | perspective. Is it too late to want a future where V8+Blink
       | aren't de facto?
       | 
       | edit: Just saw
       | 
       | > Web Advocate @Google.
        
         | self wrote:
         | > I'm a little disappointed that everything in the article from
         | a V8-only perspective.
         | 
         | The advantage of using v8 (d8) here is that the author could
         | benchmark different optimization strategies. I don't think jsc
         | lets you do that.
        
       | lovasoa wrote:
       | There was a project zero article on HN recently [1] that said
       | that bound check eliminations were removed from v8 because they
       | allowed attackers to easily turn a type confusion into a memory
       | read-write primitive:
       | 
       | > As a result, last year the V8 team issued a hardening patch
       | designed to prevent attackers from abusing bounds check
       | elimination. Instead of removing the checks, the compiler started
       | marking them as "aborting"
       | 
       | But this post, which also appears to be written by someone from
       | google with access to v8 developers, states that :
       | 
       | > You never go out of bounds. This means TurboFan does not need
       | to emit bounds checks [...]
       | 
       | Does someone here know more about bound checks eliminations in
       | TurboFan ? Are they removed in some cases but not others ?
       | 
       | [1] https://googleprojectzero.blogspot.com/2021/01/in-wild-
       | serie...
        
         | saagarjha wrote:
         | This ensures aborting bounds checks to some parts of the the
         | pipeline, but this doesn't mean that later optimizations can't
         | determine that the check is dead code and remove it. For
         | example:
         | https://doar-e.github.io/blog/2019/05/09/circumventing-chrom...
        
       | f00zz wrote:
       | > Luckily, AssemblyScript provides a magic unchecked() annotation
       | to indicate that we are taking responsibility for staying in-
       | bounds.
       | 
       | Isn't this a security risk?
        
         | vanderZwan wrote:
         | It definitely won't be able to break the WASM sandbox, so my
         | guess is that AssemblyScript itself adds runtime checks of its
         | own and that this is a hint that we don't need those.
        
         | ludamad wrote:
         | Not if you control all the memory around it
        
         | dj_mc_merlin wrote:
         | How so? What are you going to hack by writing to out of bounds
         | memory, your own browser?
        
           | Ar-Curunir wrote:
           | Er, depending on how it's implemented, you can use that to
           | execute arbitrary code outside the browser sandbox
        
             | RReverser wrote:
             | No, that's never allowed - that's the strength of Wasm. Any
             | unchecked helpers are for language-level semantic blocks
             | within Wasm memory itself, not for leaving the sandbox. So
             | worst case you might override and corrupt your own data.
        
           | [deleted]
        
           | TheCoelacanth wrote:
           | Could potentially be an XSS vulnerability.
           | 
           | Imagine an HN-like page is written in this and uses unchecked
           | in some code path for displaying user comments.
           | 
           | I comment something that exploits that code. Then when you
           | come along and view my comment. Now whatever my exploit does
           | is running with your permissions instead of mine.
        
             | vanderZwan wrote:
             | Wouldn't you already have access to the full WASM memory
             | object by the time you can write an exploit that affects a
             | WASM module?
        
               | TheCoelacanth wrote:
               | No, the exploit would be in the comment text. You're
               | exploiting a bug in the comment display code when it
               | displays your comment to another user to do something
               | that the comment display code isn't supposed to do.
               | 
               | Much like exploiting a C program that handles untrusted
               | text and doesn't bounds check it. You aren't supposed to
               | be able to run any code at all, but a vulnerability lets
               | you make the program do something it isn't supposed to.
               | 
               | Some of the easiest exploits would be prevented since you
               | probably can't overwrite code like you can (or used to be
               | able to, a lot of platforms have added protection against
               | this) in C, but some exploits are still possible just by
               | overwriting other variables with values that the program
               | doesn't expect.
        
       | fergie wrote:
       | Why does TypeScript use javascript as a compile target and not
       | web assembly?
        
         | kevingadd wrote:
         | TS predates WASM by years and WASM is also not adequate for
         | executing TS.
        
         | aikah wrote:
         | Because Typescript was designed to be a tool to write
         | Javascript with type annotations at first place and nothing
         | else.
        
         | FlyingSnake wrote:
         | Can TS be compiled directly to WASM? I don't think WASM and JS
         | are 1:1 compatible, but I'm out of my depth here.
        
           | Schampu wrote:
           | AssemblyScript initially targeted TS->WASM compilation, by
           | only supporting a strict subset of the TS language. But at
           | some point they dropped that idea and defined their own TS-
           | like language. I don't know the reason for this, but my guess
           | is that TS is too dynamic to just directly compile it to
           | WASM?
        
             | pjmlp wrote:
             | Microsoft has done exactly the same on their MakeCode IoT
             | compiler, using TypeScript and Python.
             | 
             | "MakeCode Languages: Blocks, Static TypeScript and Static
             | Python"
             | 
             | https://makecode.com/language
             | 
             | It is very hard to generate good AOT code when dealing with
             | dynamic languages, of any kind.
        
               | [deleted]
        
         | qeternity wrote:
         | WASM cannot manipulate the DOM.
        
           | jillesvangurp wrote:
           | It can indirectly by simply calling the javascript APIs via
           | bindings. That works well enough and is also how you can use
           | things like webgl, openal and other browser APIs.
           | 
           | But they are also working on more efficient bindings.
        
             | Schampu wrote:
             | This unfortunately introduces a lot of overhead and doesn't
             | scale well for larger applications. WebGL calls are already
             | incredibly slow compared to native, and the trampolining
             | between WASM and JS world adds on top.
             | 
             | When WASM got released (around 2017), there was already
             | that discussion to allow direct bindings without a JS
             | roundtrip, but AFAIK there is still no actual
             | implementation for this in any browser.
        
               | jillesvangurp wrote:
               | Doesn't seem to stop MS with Blazor (.Net), Rust, and a
               | few others from doing this. Also, there are plenty of
               | games running in web assembly using bindings for things
               | like WebGL and openal via similar bindings. As far as I
               | know the current situation is pretty workable already and
               | getting better. E.g. garbage collection is coming pretty
               | soon.
               | 
               | I guess it depends on what you are doing. For most people
               | doing web assembly, the point is avoiding dealing
               | with/minimizing the need for interacting with javascript.
               | But still, it seems there are some nice virtual dom
               | options for Rust: https://github.com/fitzgen/dodrio that
               | are allededly fast and performant (not a Rust programmer
               | myself).
        
               | flohofwoe wrote:
               | WebGL is slower than native mainly because of the
               | additional security-validations compared to a native GL
               | driver, e.g. it cannot simply forward calls into the
               | underlying 3D-API but instead WebGL needs to take
               | everything apart, look at each single piece to make sure
               | it's correct, reassamble everything and _then_ call the
               | underlying 3D-API (roughly speaking).
               | 
               | The calling overhead between WASM and JS is quite
               | negligable compared to that (at least since around 2018:
               | https://hacks.mozilla.org/2018/10/calls-between-
               | javascript-a...).
               | 
               | Another problem is that WebGL relies on garbage collected
               | Javascript objects, but this problem can't really be
               | solved on the WASM side, even with the "anyref" proposal
               | (this would just allow to remove the mapping layer
               | between integer ids and Javascript objects that's
               | currently needed).
        
           | ksec wrote:
           | Can anyone provide any pointer or update on this. I remember
           | reading it is coming for the past 3 years and never heard
           | anything. Google Search doesn't show any useful results.
        
         | jariel wrote:
         | Web assembly is very low level. It's not a VM, there are no
         | strings. It's designed to model 'assembly' style instructions.
         | 
         | To do TS on JS you'd have to build a VM on top of WA.
         | 
         | And that would probably be pointless of course.
        
           | dassurma wrote:
           | Idk man. webassembly.org -- the site authored by the
           | inventors -- literally starts with "WebAssembly (abbreviated
           | Wasm) is a binary instruction format for a stack-based
           | virtual machine."
        
             | jariel wrote:
             | My answer is correct.
             | 
             | Yes of course WASM is a VM of some kind, that should be
             | obvious enough i.e. people are not running machine code in
             | WASM.
             | 
             | My response indicated that if you want to run JS on WASM
             | _you have to build another VM_ on top of WASM (which you
             | indicated is already a VM, sure).
             | 
             | To do JS in WASM you'd have to build something like V8 (a
             | VM) on top of WASM.
        
               | pjmlp wrote:
               | Actually, they might. It just a matter of creating a FPGA
               | implementation.
        
           | crazypython wrote:
           | It is a VM. Most VMs use High-Level Intermediate
           | Representation (HIR or bytecode). WebAssembly uses a Low-
           | Level Intermediate Representation. (LIR) A LIR is not an
           | assembly.
        
         | paavohtl wrote:
         | Compiling TypeScript to JavaScript is essentially just removing
         | the type annotations. Compiling to a bytecode VM would be
         | orders of magnitude more work, especially since TS is defined
         | to have exactly the same runtime semantics as JavaScript.
        
           | sesm wrote:
           | Unfortunately, it's not.
           | 
           | TS classes are not JS classes, TS has it's own implementation
           | of async/await, etc. Just check any compiled TS code and
           | you'll see it. It's very frustrating when you want to quickly
           | patch a bug in 3rd-party library.
        
             | paavohtl wrote:
             | TS can target older versions of JS without modern features,
             | just like Babel. If you target a more recent latest release
             | of ES, the emitted JS should be pretty much the same as the
             | source TS, just without type annotations.
        
             | sime2009 wrote:
             | You are most likely looking at code which has been compiled
             | to target an older ES version which doesn't have these
             | features.
        
       | kevingadd wrote:
       | One important thing to note that this post kind of hints at:
       | JavaScript can be optimized _more_ than equivalent WebAssembly if
       | you give the JS runtime enough help, because it can use runtime-
       | only information to produce better-optimized JS. It can exploit
       | type information gathered during runtime to devirtualize method
       | calls and produce type-specialized code, while also doing things
       | like escape analysis to eliminate some allocations entirely. You
       | have to carefully identify places in your native code where you
       | can do unchecked array accesses, etc, but the JS runtime just
       | figures it out for you.
       | 
       | For any of those optimizations to happen for your WASM code, the
       | compiler has to be able to do it statically and that can be much
       | harder. Devirtualization in particular is essential for Java or
       | C# to run fast and some C++ codebases also benefit tremendously
       | from it. If you're interacting a lot with JS APIs from WASM (like
       | issuing network requests or creating DOM elements, etc) you're
       | going to be dealing with lots of dynamically typed data, and in
       | those scenarios handwritten JS may actually be faster than WASM
       | because the runtime can JIT optimal code with the right type
       | specializations.
       | 
       | Note that these optimizations will fail if you aren't careful
       | about how you write your JS: If a given function f(x,y) is passed
       | values of different types during execution, it probably won't be
       | fully optimized. If you have two functions f1(x,y) and f2(x,y)
       | and ensure that each one is only passed values of a certain type,
       | they will both be heavily optimized (iirc the JS runtime
       | terminology for these functions is 'monomorphic') Naturally, this
       | means uses of Function.apply and Function.call should be avoided
       | at all costs.
        
         | RcouF1uZ4gsC wrote:
         | I have seen much the same made about Java versus C++ for the
         | past 25 years that the Java byte code JIT would have more
         | information and thus be able to optimize and do stuff like
         | devirtualization better.
         | 
         | However, that has not planned out.
         | 
         | There are a few reasons for this. First C++ and Rust optimizers
         | can do amazing things when they are given time. In addition, I
         | think devirtualization is not as big a deal in C++ and Rust
         | because in general you avoid writing code that uses virtual
         | functions when you are writing performance sensitive code and
         | instead use things like templates/generics where there is no
         | indirect function calls.
        
           | kevingadd wrote:
           | Your argument basically boils down to "If you write fast C++
           | it will be fast", which is true. But a significant fraction
           | of code out there is not fast C++ written by experts to be
           | fast.
           | 
           | This is different than "Java will be faster than C++ because
           | of HotSpot" arguments, because java is competing with C++.
           | This is not a competition between JS and native C++, it's a
           | competition between JS and WASM.
        
             | v8dev123 wrote:
             | You don't have to be an expert to write Fast C++ that beats
             | Java. I wrote a simple for loop and when compiled with -O3
             | it beat the Java version of it.
             | 
             | You just need to know your tools, that's it. Plenty people
             | forget -O flag and existence of libraries like Folly.
             | 
             | If you combine PGO along with these must knows, you
             | seriously will become much more faster.
        
               | kaba0 wrote:
               | A for loop is not too interesting application -- it is
               | not what Java optimizes for, and chances are you didn't
               | benchmark it correctly.
               | 
               | To optimize your program in a low level language you have
               | to basically have a whole plan for the architecture of
               | your program beforehand, and every major change to that
               | will break your optimizations. Also, don't forget about
               | non-standard object life cycles, which is really common.
               | Complex C++ programs basically employ their own GCs,
               | which will be inferior to any one included in the JVM.
               | 
               | Of course low-level programs have their place (plenty
               | of), eg. audio processing, embedded, million other, but
               | the average business/CRUD app will be faster* both to
               | execute and to produce in Java, as well as better
               | maintainable.
               | 
               | * With enough time a competent team could of course write
               | a faster version of it in C++, but it's not a good use of
               | their time, and you would be surprised how hard it,
               | especially with ever-changing requirements.
        
               | v8dev123 wrote:
               | C++ is not just a low level language. It's consists both
               | high level and low level. C however a low level language.
               | 
               | I bench-marked using Intel vTune.
               | 
               | for loop is interesting. It's why Tensorflow Core written
               | in C++ instead Java.
               | 
               | I don't know any complex C++ program that employ their
               | own GCs when C++ has RAII which is superior to GC.
               | 
               | Just give a try for C++11/14/17 and you will see which
               | one is more maintainable and expressive.
               | 
               | Look at Chromium codebase. It's the most beautiful
               | codebase I've ever been to.
               | 
               | I've done a lot of CRUD web apps in C++ using expresscpp
               | [1] and I would say it's easy as ABC.
               | 
               | A lot of Java folks haven't tried C++11/14/17 (Modern
               | C++).
               | 
               | C++ is Zen of OOP.
               | 
               | [1] https://github.com/expresscpp/expresscpp
        
               | kaba0 wrote:
               | > C++ is not just a low level language
               | 
               | A language either cares about low level details or not.
               | You can't have it both ways. And c++ is absolutely a low
               | level language.
               | 
               | > I don't know any complex C++ program that employ their
               | own GCs when C++ has RAII which is superior to GC.
               | 
               | RAII is not at all a replacement for GC. It is only
               | suitable for a subset of object lifetimes. There are
               | plenty of cases where you can't really pinpoint a scope-
               | exit where this given object should be reclaimed.
               | 
               | A GC is a necessity in many concurrent algorithms that
               | simply could not be written without.
               | 
               | > Just give a try for C++11/14/17
               | 
               | I have and I like it. There are domains where I would not
               | even start writing Java, and vice versa with C++.
               | 
               | Your CRUD app may have been a breeze but what if the
               | requirement has changed now touching on a core of your
               | program. You have to refactor and it will be really
               | expensive, compared to a high level language. Every
               | memory allocation/deallocation have to be thought out
               | again and tested (and while rust can warn about it, you
               | still have to write a major refactor as it is another low
               | level lang)
        
               | v8dev123 wrote:
               | > A language either cares about low level details or not.
               | You can't have it both ways. And c++ is absolutely a low
               | level language.
               | 
               | Please tell me why you can't. C++ is both not one. It's a
               | multi paradigm language.
               | 
               | In Modern C++, the low level details invisible.
               | 
               | > Every memory allocation/deallocation have to be thought
               | out again and tested
               | 
               | True If you're writing C with Classes or Java Style C++.
               | 
               | >> C with Classes >>> malloc()
               | 
               | >> Java Style C++ >>> new and delete everywhere
               | 
               | > There are plenty of cases where you can't really
               | pinpoint a scope-exit where this given object should be
               | reclaimed.
               | 
               | Show me. I'd bet your case can be solved with xvalues.
               | 
               | > A GC is a necessity in many concurrent algorithms that
               | simply could not be written without.
               | 
               | Show me a concurrent algorithm that needs GC.
               | 
               | > but what if the requirement has changed now touching on
               | a core of your program.
               | 
               | C++ is a OOP language just like Java. You do it same way
               | as you do in Java. Use inheritance.
               | 
               | > major refactor as it is another low level lang
               | 
               | No. It's not a low level language if you write Modern
               | C++.
               | 
               | The case for Java very clear prior 2011 but now C++ has
               | caught up.
        
             | astrange wrote:
             | The main problems with Java aren't being JITted, it's that
             | it's not expressive enough. It doesn't have SIMD (yet) or
             | value types (yet...?).
             | 
             | I would expect a JIT to not really be able to find a lot of
             | magic optimization opportunities, though maybe there are
             | some, and it'd actually be annoying if it could. The most
             | important thing in a tool like that is predictability,
             | because you can't make development decisions based on
             | magic.
        
               | kaba0 wrote:
               | > The most important thing in a tool like that is
               | predictability, because you can't make development
               | decisions based on magic.
               | 
               | Fortunately you've got the best profiling tools
               | available, so you don't have to guess. And also you get
               | to see the relative importance of the function you try to
               | optimize, whether that actually is the bottleneck (and
               | actually people often guess wrongly where the bottleneck
               | is)
        
               | kevingadd wrote:
               | Optimizations like 'these two function arguments are
               | always int31' in v8 or spidermonkey are 100% predictable
               | at this point and result in all your type checks and
               | boxing being eliminated, and with the known types it also
               | becomes much cheaper/faster to create object instances
               | (since now if you store those values into properties of
               | an object, that object's shape is fully known). Various
               | properties like this can extend out into larger parts of
               | your JS application.
               | 
               | There's still a lot of magic you can't rely on, but you'd
               | be surprised how much you CAN rely on. Asm.js was built
               | on this observation: If you write your JS following some
               | basic rules it's actually pretty easy to land on
               | predictable, well-optimized paths. Of course, one of
               | WASM's advantages is that by design you're almost always
               | on those paths and don't have to worry.
        
               | pjmlp wrote:
               | It surely has had support for AVX for several releases,
               | although via the autovectorization support, and explicit
               | SIMD has been made available as preview on Java 16.
        
               | astrange wrote:
               | Autovectorization is the kind of magic you can't rely on.
               | It sort of works on a single platform but you will always
               | run into cases it doesn't handle even if you own your own
               | team of autovectorization engineers who tell you it's
               | perfect.
        
               | pjmlp wrote:
               | A magic shared with C, Fortran and C++ compilers, among
               | others, so support is there.
        
               | sudosysgen wrote:
               | Compiled autovectorization is miles more reliable than
               | JIT autovectorization.
        
               | kaba0 wrote:
               | At the other hand, the explicit Vector API will use the
               | correct "flavor" of SIMD instructions on the platform and
               | will gracefully fall back to non-simd version if it is
               | not supported. And as far as I know, the SIMD story is
               | quite bad with C.
        
               | sudosysgen wrote:
               | Yes it's quite bad with C. With C++ and Rust it's much
               | much better when you do it properly.
        
               | pjmlp wrote:
               | When you do it properly is the big question.
        
               | MaxBarraclough wrote:
               | > it's that it's not expressive enough
               | 
               | That may be part of it, but I imagine the JVM's safety
               | obligations are also a significant factor. If the JIT
               | can't elide array bounds checks, checks must be performed
               | at runtime. Runtime type checks might be needed. Runtime
               | arithmetic checks might also be needed. The JVM is also
               | more constraining regarding concurrency gone awry, than
               | the C/C++ memory model. [0] More broadly, the JVM's lack
               | of undefined behaviour constrains the optimiser in ways
               | the C/C++ approach does not (although I'm open to the
               | idea that it's overstated how much of a performance win
               | is owed to C and C++ having many kinds of undefined
               | behaviour).
               | 
               | And of course there's the GC and Java's high object-
               | churn, even where lifetimes are known statically. To my
               | knowledge, escape analysis (the relevant family of JIT
               | optimisations) still hasn't really addressed this.
               | 
               | [0]
               | https://softwareengineering.stackexchange.com/q/262428/
        
               | kaba0 wrote:
               | The JIT can elide array bound checks really often, and
               | most "low hanging" optimizations are solved quite
               | cleverly (it's way out of scope for my knowledge, but I
               | remember reading that null checks are elided by trapping
               | segfaults? Does it make sense?). There is no
               | over/underflow checks so I don't know what you mean by
               | arithmetic checks -- in pure number crunching the JVM is
               | insanely fast.
               | 
               | And you are right in that many Java libs/programs are
               | quite happy to create garbage, though with generational
               | GCs it is really cheap. Escape analysis is great, but
               | primitive classes in Project Valhalla will solve this
               | last problem of object locality.
        
               | MaxBarraclough wrote:
               | > null checks are elided by trapping segfaults
               | 
               | Sounds right. No need to generate instructions to perform
               | the check if you can rely on a hardware trap, by means of
               | signal-handling cleverness.
               | 
               | > There is no over/underflow checks so I don't know what
               | you mean by arithmetic checks -- in pure number crunching
               | the JVM is insanely fast.
               | 
               | Integer multiplication, addition, and subtraction, are
               | all defined in Java to have wrapping behaviour, and are
               | easily implemented. Whatever the input values, there's no
               | way those operations can fail. (Incidentally, this is a
               | terrible way of handling overflow. This turned up
               | recently in discussion. [0]) Division is trickier. In
               | Java, integer division by zero results in an exception
               | being thrown. Apparently JVMs can implement this with
               | signal-handling cleverness similar to dereferencing null
               | references. [1] Two's complement integer division has
               | another edge case, which is undefined behaviour in C/C++
               | but which, iirc, results in an exception in Java:
               | _INT_MIN / -1_. I believe the JIT has to emit
               | instructions to check for this, as it's not possible to
               | leverage signal-handling there.
               | 
               | I don't know how well modern Java performs in floating-
               | point arithmetic. Here's an old tirade about it [2] and
               | discussion. [3]
               | 
               | > with generational GCs it is really cheap.
               | 
               | At the risk of going off topic: doesn't Java tend to
               | perform somewhere around 60% the speed of C/C++, while
               | using considerably more memory? Perhaps the GC isn't to
               | blame, but clearly the blame belongs _somewhere_. It 's
               | like the way advocates of Electron will insist that
               | modern HTML rendering engines are fast and efficient, the
               | DOM is fast and efficient, and JavaScript is fast and
               | efficient... and yet here we are, with Electron-based
               | applications reliably taking several times the
               | computational resources of competing solutions using
               | conventional toolkits.
               | 
               | > primitive classes in Project Valhalla will solve this
               | last problem of object locality
               | 
               | Interesting, sounds like the kind of ambitious initiative
               | that will require deep changes to the JVM.
               | 
               | [0] https://news.ycombinator.com/item?id=26666013
               | 
               | [1] https://www.javaer101.com/en/article/3117893.html
               | 
               | [2] (PDF)
               | https://people.eecs.berkeley.edu/~wkahan/JAVAhurt.pdf
               | 
               | [3] https://news.ycombinator.com/item?id=6585828
        
           | pjmlp wrote:
           | Other than 3D AAA game engines, all the C++ software that I
           | replaced with either Java or .NET solutions has kept the
           | customers happy and lowered the TCO of their products.
           | 
           | This wasn't tiny CLI that occasionally lands on HN, rather
           | large scale desktop applications or distributed computing
           | clusters.
           | 
           | Winning micro-benchmarks is not everything, which is why
           | except for Windows with WinUI (which still remains to be seen
           | if it can move windevs away from Forms/WPF in its current
           | incomplete state), all OS vendors are migrating to other
           | languages for their App development SDKs, leaving C++ and
           | Rust only for low level OS components.
        
             | RcouF1uZ4gsC wrote:
             | > all the C++ software that I replaced with either Java or
             | .NET solutions has kept the customers happy and lowered the
             | TCO of their products.
             | 
             | Were your customers enterprises that made their employees
             | use those products, or were they end user, consumer
             | products?
             | 
             | In my experience, enterprises are happy to push slow,
             | laggy, hard to use corporate tools on their employees as
             | long as it saves them money.
        
               | pjmlp wrote:
               | The customers of the enterprises.
               | 
               | Many devs are too religious arguing for home team and
               | don't embrace polyglot programming.
               | 
               | Just because a product is mainly written in managed
               | language X, doesn't mean some library can't be written in
               | something else.
               | 
               | C and C++ devs have forgotten the days when their beloved
               | programs in 8 and 16 bit home computers, were a pile of
               | inline Assembly if performance was to be anywhere of an
               | acceptable level.
               | 
               | Embrace the safety and productivity of higher level
               | languages (with AOT and JIT compilers), and let a couple
               | of native libs be the "inline Assembly" if and only if, a
               | profiler proves it is actually required instead of
               | choosing a better data structure or algorithm.
        
             | v8dev123 wrote:
             | Are those C++ ones written in pre-C++11 ?
             | 
             | I don't think C++ and Rust are for just low-level. I've
             | build a lot of GUI apps and distributed ones with C++
             | 
             | QT is a beast.
             | 
             | The issue with Java is the reverse engineering. Back in
             | 90's, The main selling point for Java was to prevent it,
             | because at that time the bytecode was hard to understand at
             | least. Now tools has grown and it's fairly easy to reverse
             | engineer Java, even if one obfuscate it.
             | 
             | As for C++, Inline code and template code make it pain in
             | ass.
             | 
             | I'm sure big companies that care about intellectual
             | property would use C++ over Java anytime. C++ also has
             | mature obfuscation tools that make it even more difficult.
             | 
             | Java has it's place. It's great language if you use in
             | server side or isolated env (From commercial viewpoint).
             | 
             | Nevertheless, I've built many web apps using C++ too.
        
               | pjmlp wrote:
               | They were and are written in all sorts of C++ flavours,
               | including past C++11.
               | 
               | Reverse engineering is never an issue with Java if one
               | actually uses the right tooling, commercial AOT compilers
               | exisst since around 2000, it is a matter of buying them.
               | 
               | I assume JetBrains and Google are big companies.
        
               | v8dev123 wrote:
               | Google where I works at is largely a C++ shop despite
               | Android Java.
               | 
               | AOT compilers exists for Java, Net, Javascript. I however
               | doubt the user experience of those.
               | 
               | For example, GraalVM mentions the following,
               | 
               | "There is a small portion of Java features are not
               | susceptible to ahead-of-time compilation, and will
               | therefore miss out on the performance advantages. To be
               | able to build a highly optimized native executable,
               | GraalVM runs an aggressive static analysis that requires
               | a closed-world assumption, which means that all classes
               | and all bytecodes that are reachable at run time must be
               | known at build time. Therefore, it is not possible to
               | load new data that have not been available during ahead-
               | of-time compilation."
        
               | pjmlp wrote:
               | Not everyone is Google, and since you work there you are
               | surely aware of tooling like Ghidra and IDA.
               | 
               | GraalVM is not what I would pick for AOT Java projects,
               | there are other products since 2000.
               | 
               | In any case, this isn't a comparisasion of language
               | bullet points.
               | 
               | Just because a software product has been migrated from
               | C++ into Java, .NET or whatever language, it doesn't mean
               | it is a sacrilege to keep some native lib around, which
               | is exactly where all mainstream OSes are going, with C++
               | being left for the bottom layers.
               | 
               | How many desktop GUIs is Google shipping written in pure
               | C++?
        
               | RcouF1uZ4gsC wrote:
               | > How many desktop GUIs is Google shipping written in
               | pure C++?
               | 
               | You mean apart from the Chrome browser?
        
               | pjmlp wrote:
               | https://developer.chrome.com/blog/migrating-to-
               | typescript/
               | 
               | https://developer.chrome.com/blog/puppeteer-typescript/
               | 
               | https://chromium.googlesource.com/chromium/src/+/master/d
               | ocs...
               | 
               | Pure => not mixed with anything else
               | 
               | https://dictionary.cambridge.org/dictionary/english/pure?
               | q=P...
        
               | v8dev123 wrote:
               | "In 2017, the Qt Company estimated a community of about 1
               | million developers worldwide[18] in over 70 industries."
               | 
               | See list of companies using C++ QT for GUI,
               | 
               | https://en.wikipedia.org/wiki/Qt_(software)
        
               | pjmlp wrote:
               | 1 - Qt is not an OS SDK. Apparently you missed that part
               | of my comment.
               | 
               | 2 - Qt has been migrating away from pure C++, again you
               | also missed pure from my comment, modern Qt applications
               | are written in Qt Quick, a JavaScript dialect, with
               | underlying components written in C++.
               | 
               | C++ Widgets have hardly changed since Qt 4, other than
               | being updated to the underlying Qt infrastructure.
        
               | v8dev123 wrote:
               | 1. QT is cross platform.
               | 
               | 2. QT not moving away from pure C++.
               | 
               | C++ apps always been more responsive than java swing and
               | electron.
        
         | lilyball wrote:
         | Surely there's some way to do profile-guided optimization when
         | compiling to WASM?
        
           | kevingadd wrote:
           | Some WASM compiler toolchains have PGO available, yes.
        
       | DonHopkins wrote:
       | "Dynamic Deoptimization" should have been called "Dynamic
       | Pessimization".
       | 
       | Debugging Optimized Code with Dynamic Deoptimization
       | 
       | By Urs Holzle (Stanford University), Craig Chambers (University
       | of Washington) and David Ungar (Sun Microsystems Labs).
       | 
       | https://bibliography.selflanguage.org/_static/dynamic-deopti...
       | 
       | >Abstract: Self's debugging system provides complete source-level
       | debugging (expected behavior) with globally optimized code. It
       | shields the debugger from optimizations performed by the compiler
       | by dynamically deoptimizing code on demand. Deoptimization only
       | affects the procedure activations that are actively being
       | debugged; all other code runs at full speed. Deoptimization
       | requires the compiler to supply debugging information at discrete
       | interrupt points; the compiler can still perform extensive
       | optimizations between interrupt points without affecting
       | debuggability. At the same time, the inability to interrupt
       | between interrupt points is invisible to the user. Our debugging
       | system also handles programming changes during debugging. Again,
       | the system provides expected behavior: it is possible to change a
       | running program and immediately observe the effects of the
       | change. Dynamic deoptimization transforms old compiled code
       | (which may contain inlined copies of the old version of the
       | changed procedure) into new versions reflecting the current
       | source-level state. To the best of our knowledge, Self is the
       | first practical system providing full expected behavior with
       | globally optimized code.
       | 
       | >Proceedings of the ACM SIGPLAN '92 Conference on Programming
       | Language Design and Implementation, pp. 32-43, San Francisco,
       | June, 1992.
        
       | CuriouslyC wrote:
       | Try making realtime audio and video filters in JS vs WASM. There
       | are some domains were there is a very real difference, and it is
       | enough to put things in the realm of the viable.
        
       | hutzlibu wrote:
       | The headline is a bit missleading, as the main article is about
       | AssemblyScript, a typescript subset compiling to WebAssembler. So
       | it seems, quite some of the mentioned problems come from the
       | immaturity (or design problems?) of AssemblyScript and not
       | necessarily from wasm.
        
         | dassurma wrote:
         | Author here.
         | 
         | Using ASC was intentional, _because_ it is somewhat immature,
         | and still manages to outperform JavaScript in the first two
         | cases.
         | 
         | In the third case, where I couldn't get ASC to outperform
         | JavaScript, I tried Rust and C++ as well.
        
           | CyberDildonics wrote:
           | That seems to mean every bit of your title is nonsense. You
           | aren't benchmarking webasm at its best and 'magic pixie dust'
           | is already nonsense on its own.
        
       | tpetry wrote:
       | So AssemblyScript can beat JavaScript if you benchmark every
       | function and then optimize them by hand every time it is slower?
       | 
       | So most (all?) of the code posted which looked like a straight
       | port to AssemblyScript was slower than JavaScript before
       | optimizing it? I don't know how you feel, but i personally don't
       | want to optimize every function to get the promised speed :(
        
         | onion2k wrote:
         | If your app is doing most of the work it needs to do in 1ms,
         | but one path takes 200ms, then clearly you only need to
         | optimize things on the slow path. You don't have to optimize
         | _everything_ to get a huge perf improvement.
        
         | hackcasual wrote:
         | AssemblyScript is still in development, if you're interested in
         | WASM optimizing an app, Rust or C are better bets
        
       | hackcasual wrote:
       | AssemblyScript lacking support for closures really hampers it,
       | since so many typescript code patterns leverage them.
        
       | crazypython wrote:
       | Despite spending lots of time optimizing Rust and C++ versions,
       | he didn't optimize the JS version.
        
         | dassurma wrote:
         | That's the whole point. V8 is _really_ good at taking any form
         | of JS code and making it fast, without me having to apply
         | optimizations. The other languages only started being
         | competitive once I hand-optimized them.
        
           | crazypython wrote:
           | Thanks.
        
       | kohlerm wrote:
       | WASM is theoretically better for CPU intensive workload. As the
       | article states even for CPU intensive workloads there are still
       | quite a few limitations to take into account. What it is good for
       | ATM is IMHO mostly just reusing existing C, rust, whatever
       | (choose your WASM supported language here) code. Practically most
       | web applications are not slow because of CPU bottlenecks but more
       | because of too much communication, large code size etc. WASM at
       | its current state does not seem to have an good answer yet for
       | the code size issue.
        
       | [deleted]
        
       | moonchild wrote:
       | See also: 'Not So Fast: Analyzing the Performance of WebAssembly
       | vs. Native Code' -
       | https://www.usenix.org/system/files/atc19-jangda.pdf
        
         | justin66 wrote:
         | Two years old. I bet the "actionable guidance for future
         | optimization efforts" they provide has been acted upon.
        
           | vanderZwan wrote:
           | I'm sure it's _being_ acted upon, but these kinds of
           | developments take time so I 'm not sure if it has "landed"
           | yet.
        
       | Ashanmaril wrote:
       | That was a really informative read. I think myself and many
       | others figured the biggest issue with WASM right now is purely
       | the inconvenient development flow, and if you are willing to put
       | up with it you'd just automatically get better performance. But
       | there seems to be much more to it than that.
       | 
       | I hope WASM can continue to grow in both of those areas, cause I
       | still like the idea but it's clearly still an immature
       | technology.
        
       | TekMol wrote:
       | For me, the showstopper regarding WebAssembly is that browsers do
       | not support a textual version that I can just throw in where I
       | want to hand optimize a function.
       | 
       | If I could just replace my slowest Javascript function with
       | handcrafted WebAssembly code, that would be great.
       | 
       | But having to dabble with external compilers and splitting my
       | code into multiple files is too much of a burden.
        
         | kevingadd wrote:
         | You can pretty easily just ship a 1kb .wasm module and load it
         | and export a function from it to call from JS. Of course, then
         | all your data needs to live in wasm-accessible memory, and you
         | can't use strings or objects anymore...
        
         | candiodari wrote:
         | Shouldn't be too hard to make a library that would allow this.
         | Would you be interested in that ? So let's say something like
         | the following example, would you use it?
         | 
         | This should be possible:                   <script
         | src="some.url/gopherjs.js">         <script
         | type="application/golang">           package main
         | import "fmt"                func main() {
         | fmt.Printf("yeah baby\n") // Effectively console.log
         | }         </script>
         | 
         | Obviously this would take more than a bit of time to start up
         | (seconds), but the idea is of course that you don't do this
         | once you deploy to production, and replace by inline
         | webassembly.
        
           | TekMol wrote:
           | I would surely try it out!
           | 
           | What is "inline webassembly"?
        
       | debt93 wrote:
       | Honestly, the fact that AssemblyScript's Array implementation
       | does not double the internal capacity but instead adds just one
       | more slot when reallocating makes me worry about the quality of
       | the language as a whole.
       | 
       | I hope it is just an oversight, but come on...
        
         | gvb wrote:
         | Doubling the allocation is a "hack" that is helpful when
         | reallocations are common and thus is helpful for languages that
         | extend arrays very often (typical of dynamic languages with GC)
         | and where memory is cheap and plentiful.
         | 
         | One of the prime features of assembly language is that the
         | person (compiler) that is generating it expects tight control
         | over what it does. A 2*X allocation when you ask for X is
         | unexpected.
         | 
         | Imagine if, when you went to the ATM and withdrew $100, the
         | bank actually withdrew $200 from your account and held back the
         | extra $100 so that, the next time you went to the bank and
         | withdrew $20 it would take it out of the "held back" amount
         | rather than doing another withdraw. I would be very unhappy
         | with that algorithm.
        
           | joppy wrote:
           | In order for append-to-back to have O(1) amortised running
           | time, the capacity needs to be multiplied by some constant
           | >1. Any constant would do just fine in terms of complexity,
           | but 2 is the obvious simple choice, being the first integer
           | greater than 1.
           | 
           | If the capacity is only increased by some constant each time,
           | rather than multiplied, this leads to O(n^2) running time for
           | a sequence of n append-to-back operations, surely something
           | to be avoided.
        
           | TheCoelacanth wrote:
           | For `push` to extend capacity by just 1 is an absolutely
           | insane default.
           | 
           | There is no sensible usage for a method that does that. It
           | turns `for(let i = 0; i < n; i++) { arr.push(x); }` from
           | linear into quadratic.
           | 
           | If automatic resizing exists, then it should do it in a
           | sensible way. Otherwise it's just a footgun that you should
           | leave out of the language like C does.
        
           | debt93 wrote:
           | It is not a "hack". It is the behavior that I expect from a
           | dynamically resizable array.
           | 
           | std::vector in C++ does it, so does Vec in Rust, and they are
           | not dynamic languages with GC.
        
             | pjmlp wrote:
             | Which std::vector though?
             | 
             | ISO C++ places no such requirement on std::vector, each
             | implementation is free to choose their own implementation
             | provided it matches the O() notation requirements.
             | 
             | C++ is not like Rust where the implementation dictates the
             | semantics.
        
         | kohlerm wrote:
         | Also without an integrated GC, most modern languages do not run
         | well on ASM.
        
       | isaacimagine wrote:
       | ~lol, imagine not doubling the capacity of a dynamic array upon
       | allocation.~
       | 
       | In all seriousness, this is a great read, and I was mildly
       | surprised JS was about the same speed as Wasm once TurboFan kicks
       | in. As a compiler engineer, it's nice step back and appreciate
       | the myriad of runtime-based optimizations that can be done with
       | modern JIT compilers.
       | 
       | That being said, assembly script doesn't perform and high-level
       | optimizations upon compilation, so I wonder how fast it will be
       | once fully matured.
        
         | kevingadd wrote:
         | The correct growth rate is typically not actually 2x, but it's
         | certainly not +1 either :)
        
           | RicardoLuis0 wrote:
           | growth rate varies between use cases, too small and you pay
           | on performance overhead, too large and you pay on memory
           | overhead, 2x is a decent mid-spot
        
             | masklinn wrote:
             | Wasn't there some consideration that with 2x you could
             | never reuse previous contiguous allocations but at 1.4
             | (ish?) it was an option and improved fragmentation in some
             | cases?
             | 
             | Of course it depends on the behaviour and binning (or lack
             | thereof) of your allocator.
             | 
             | Edit: it's 1.5, any growth factor below 2 has this
             | property, how far below 2 regulates how quickly it happens,
             | https://github.com/facebook/folly/blob/master/folly/docs/FB
             | V...
             | 
             | > it can be mathematically proven that a growth factor of 2
             | is rigorously the worst possible because it never allows
             | the vector to reuse any of its previously-allocated memory.
             | 
             | > [...]
             | 
             | > choosing 1.5 as the factor allows memory reuse after 4
             | reallocations; 1.45 allows memory reuse after 3
             | reallocations; and 1.3 allows reuse after only 2
             | reallocations
        
               | dahfizz wrote:
               | I'm not sure I understand the benefit of this. With a
               | growth factor < 2, you have a chance of getting back
               | chunks of memory that were previously used. That doesn't
               | affect fragmentation / cache hits since all your data is
               | always in the current chunk. What am I missing?
        
           | adrusi wrote:
           | Eh, at the point you're tuning the growth factor, you might
           | consider just not using a dynamically sized array
        
             | eru wrote:
             | Depends on whether you are talking about tuning the growth
             | factor for a single instance, or whether you are talking
             | about tuning the default growth factor in general.
             | 
             | Eg Python has put a lot of thought into their dynamic array
             | (and dict) growth factors.
        
           | hansvm wrote:
           | I don't see this brought up very often, but you have a huge
           | world of flexibility in choosing growth rates beyond just
           | adding constants for an O(n) amortized append time or
           | multiplying by a constant for O(1).
           | 
           | E.g., if you choose x -> x(1+1/log(x)) then you get an
           | amortized append time of O(log(n)) while paying a memory
           | overhead approaching 0% for large datasets.
           | 
           | The distribution of (and SLOs for) appends relative to other
           | operations can make that kind of idea more or less
           | attractive, but even common data structures have a lot of
           | room for improvement if you can tailor them to your use case
           | a little bit.
        
         | brabel wrote:
         | > assembly script doesn't perform and high-level optimizations
         | upon compilation
         | 
         | IIRC it does because it uses binaryen[0] (as claimed in the
         | link) which is an optimizing compiler.
         | 
         | [0] https://github.com/WebAssembly/binaryen
        
           | dassurma wrote:
           | Author here.
           | 
           | It's a trade-off for simplicity. It's a small team and they
           | are still working towards feature completeness. Deferring
           | optimization to Binaryen is the easy way out at the cost of
           | not having high-level optimizations. If they finish their IR,
           | that will most likely change.
        
       | daninet wrote:
       | Still, you can archive significant speed-ups with WebAssembly at
       | some use cases.
       | 
       | For example, I have a hash function library
       | (https://github.com/Daninet/hash-wasm) where I was able to
       | archive 14x speedup at SHA-1 and 5x speedup at MD5 compared to
       | the best JS implementations.
       | 
       | You can run the benchmarks on your computer here:
       | https://daninet.github.io/hash-wasm-benchmark/
        
         | maxgraey wrote:
         | Yeah, WebAssembly have i64/u64 types as first class citizens
         | unlike JavaScript which should emulate it or use BigInt which
         | drastically slower than native 64-bit types. That's why crypto
         | algorithms got a lot of speed benefits. AssemblyScript also
         | show this. See this:
         | 
         | https://github.com/FriendlyCaptcha/friendly-pow
         | https://github.com/hugomrdias/rabin-wasm
        
         | hackcasual wrote:
         | A large part of that would be better support for integer math,
         | and 64 bit in particular for sha1
        
           | CodesInChaos wrote:
           | Why are 64-bit integers useful for SHA-1 which uses 32-bit
           | words?
        
             | vnorilo wrote:
             | The full product of 32-bit multiply is 64-bit.
        
         | Cthulhu_ wrote:
         | That's exactly the kind of thing I think WASM is good at -
         | small, computationally expensive libraries that are easy to
         | just plug in.
         | 
         | I'm more of a web developer and every time I think "hmm, could
         | I use this to build a webapp?", but quickly shrug it off
         | because it would create a big headache and the JS execution is
         | rarely the bottleneck (and if it is, it's likely developer
         | error and inefficiencies than the language / interpreter).
        
           | Black101 wrote:
           | I think WASM is also good at hiding the source code? which is
           | the main reason why I don't like it...
        
           | NohatCoder wrote:
           | Yeah, and most of the time if "JavaScript is slow" it is
           | because of DOM manipulation or network latency, WASM can't
           | even do those things.
        
             | zozbot234 wrote:
             | Network roundtrips are unavoidable, but WASM could be used
             | to parse a server response and generate custom HTML to use
             | in replacing some portion of the DOM. It would likely be a
             | lot faster than trying to do the same in pure JS, and it
             | would obviate the use of over-complicated hacks like
             | virtual DOM and the like.
        
               | underwater wrote:
               | Forcing the browser to continually parse HTML and
               | generate a new DOM tree, recalculate layout, etc.
               | shouldn't be faster than updating specific nodes than
               | need changes.
        
               | dahfizz wrote:
               | The first roundtrip is unavoidable. Making another
               | handful of roundtrips every time the user scrolls the
               | page is definitely avoidable.
        
               | NohatCoder wrote:
               | No, parsing the response is usually way too fast to make
               | a difference. Generating an HTML string is also usually
               | pretty fast. The slowness happens when you ask the
               | browser to parse that HTML string and generate the
               | appropriate DOM, WASM is not going to get you out of
               | that.
        
               | abacadaba wrote:
               | Na, the slowness comes from asking the browser to do that
               | 1000's of times in a loop every click :)
        
               | zozbot234 wrote:
               | > The slowness happens when you ask the browser to parse
               | that HTML string and generate the appropriate DOM
               | 
               | If you do it right, that step only has to happen once for
               | each user interaction. You can entirely dispense with the
               | need to do multiple edits to the DOM via pure JS.
        
               | baybal2 wrote:
               | Multiple edits on the HTML are by far not anywhere near
               | as performance devastating as they were a decade ago.
               | 
               | At the moment, the "virtual DOM" approach is actually
               | going against performance optimization.
               | 
               | JS frameworks like react, vue, angualr etc effectively
               | replicates a big portion of browser's internal logic for
               | nothing.
        
               | acdha wrote:
               | It's not "at the moment" but "continuously from the
               | creation of the virtual DOM concept" - often slower by
               | multiple orders of magnitude.
               | 
               | The misrepresentation of a virtual DOM as a performance
               | improvement came from two things: people who were
               | comparing virtual DOM code to sloppy unoptimized code
               | which was regenerating the DOM on every change and React
               | fans not wanting to believe their new favorite was a
               | regression in any way (not to be confused with the actual
               | React team who certainly knew how to do real benchmarks
               | and were quite open about limitations).
               | 
               | There's a line of argument that the extra overhead is
               | worth it if the average developer writes more efficient
               | code than they did with other approaches but I think
               | that's leaving a lot of room for alternatives which don't
               | have that much inefficiency baked into the design.
        
               | rapind wrote:
               | I think there's a bit more nuance to it. React (and other
               | vdom implementations) try do be as efficient as possible
               | when diffing / reconciling with the DOM. Sometimes this
               | can result in improved performance but there are also use
               | cases where you'll want to provide it with hints (keys,
               | when to be lazy, etc.).
               | https://reactjs.org/docs/reconciliation.html
               | 
               | Above all I would pragmatically argue (subjectively) that
               | the main advantage is enabling a more functional style of
               | programs w/ terrific state management (like Elm). This
               | can lead to fewer errors, easier debugging, and often
               | better performance with less effort.
        
               | acdha wrote:
               | > I think there's a bit more nuance to it. React (and
               | other vdom implementations) try do be as efficient as
               | possible when diffing / reconciling with the DOM.
               | Sometimes this can result in improved performance but
               | there are also use cases where you'll want to provide it
               | with hints (keys, when to be lazy, etc.).
               | https://reactjs.org/docs/reconciliation.html
               | 
               | The key part is remembering that every one of those
               | techniques can be done in normal DOM as well. This is
               | just rediscovering Amdahl's law: there is no way for
               | <virtual DOM> + <real DOM> to be smaller than <real DOM>
               | in the general case. React has improved since the time I
               | found a 5 order of magnitude performance disadvantage
               | (yes, after using keys) but the virtual DOM will always
               | add a substantial amount of overhead to run all of that
               | extra code and the memory footprint is similarly non-
               | trivial.
               | 
               | The better argument to make is your last one, namely that
               | React improves your _average_ code quality and makes it
               | easier for you to focus on the algorithmic improvements
               | which are probably more significant in many applications
               | and could be harder depending on the style. For example,
               | maybe on a large application you found that you were
               | thrashing the DOM because different components were
               | triggering update /measure/update/measure cycles forcing
               | recalculation and switching to React was easier than
               | using fastdom-style techniques to avoid that. Or simply
               | that while it's easy to beat React's performance you
               | found that your team saw enough additional bugs managing
               | things like DOM references that the developer
               | productivity was worth a modest performance impact. Those
               | are all reasonable conclusions but it's important not to
               | forget that there is a tradeoff being made and
               | periodically assess whether you still agree with it.
        
               | rapind wrote:
               | I agree. I am curious though about how substantial the
               | memory and diffing costs are. I don't mean that in an _I
               | doubt it's a big deal_ way, rather I'm genuinely curious
               | and haven't been able to find any literature on the
               | actual overhead compared to straight up DOM manipulation.
               | I would imagine batching updates to be an advantage of
               | the vdom but only if it's still that much lighter weight
               | (seeing as you can ignore a ton of stuff from the DOM).
        
               | acdha wrote:
               | > I would imagine batching updates to be an advantage of
               | the vdom but only if it's still that much lighter weight
               | (seeing as you can ignore a ton of stuff from the DOM).
               | 
               | There are two separate issues here: one is how well you
               | can avoid updating things which didn't change -- for
               | example, at one point I had a big table showing progress
               | for a number of asynchronous operations (hashing +
               | chunked uploads) and the approach I used was saving the
               | appropriate td element in scope so the JavaScript was
               | just doing elem.innerText = x, which is faster than
               | anything which involves regenerating the DOM or updating
               | any other property which the update didn't affect.
               | 
               | The other is how well you can order updates -- the DOM
               | doesn't have a batch update concept but what is really
               | critical is not interleaving updates with DOM calls which
               | require it to calculate the layout (e.g. measuring the
               | width or height of an element which depends on what you
               | just updated). You don't necessarily need to batch the
               | updates together logically as long as those reads happen
               | after the updates are completed. A virtual DOM can make
               | that easy but there are other options for queuing them
               | and perhaps doing something like tossing updates into a
               | queue which something like requestAnimationFrame
               | triggers.
        
               | scsilver wrote:
               | Frankly that just seems more difficult and handles an
               | issue I havent run into in 5 years that couldn't be
               | solved with js performance optimizations.
               | 
               | Does WASM really make sense for something that isnt
               | constantly doing high performance calculations? Do I gain
               | anything from using it in most SPA's?
        
             | miohtama wrote:
             | What would it take to make DOM manipulation faster?
        
             | onion2k wrote:
             | _DOM manipulation_
             | 
             | Browser vendors have done a lot of work on that over the
             | past decade or so. It's nowhere near as slow as it was in
             | the early days.
        
               | danShumway wrote:
               | Absolutely, it's been kind of incredible progress. But
               | it's still going to be a bottleneck more often than JS
               | execution (in my experience at least).
               | 
               | Not always; I have definitely run into applications where
               | parsing large amounts of data in code is a bottleneck,
               | especially when building large charts. But often.
        
           | throwaway894345 wrote:
           | It's very similar to the Python/C distinction. Python will
           | often drop into C for the use-cases you're describing.
           | However, unlike WASM, Python/C is the wild west:
           | 
           | - The whole CPython interpreter is the "C-extension
           | interface" which means that the CPython interpreter can
           | hardly change or be optimized or else it will break something
           | in the ecosystem (and for the same compatibility reason it's
           | virtually impossible for alternative optimized interpreters
           | to make headway), and because the interpreter is so poorly
           | optimized the ecosystem depends on C extensions for
           | performance. WASM presumably won't have this distinction.
           | 
           | - Without the abysmal build ecosystem that C and C++ projects
           | tend to bring with them, building and deploying WASM
           | applications will likely be pleasant and easy after a few
           | years. Of course, if your WASM is generated from C/C++ then
           | that's a real bummer, but fortunately this should be a much
           | smaller fraction of the ecosystem than it is with C/Python.
        
           | __s wrote:
           | Where in my case "small, computationally expensive library"
           | is a card game engine & its AI search
        
         | slx26 wrote:
         | And there might be other benefits besides performance. I'd like
         | to use WASM to be able to reuse server side code in languages
         | like Rust or Go in the client, so you don't have to re-
         | implement algorithms and tricky processing code in javascript.
        
           | xupybd wrote:
           | Dot net does this with Bolero. I need to give it a go.
        
           | edflsafoiewq wrote:
           | asm.js suffices for that.
        
             | TheCoelacanth wrote:
             | Asm.js is a non-standard precursor to wasm.
        
           | vbsteven wrote:
           | I experimented with this some weeks ago and it is certainly
           | possible.
           | 
           | I had a PoC where my server runs Rust, exposes a JSON Rest
           | API using serde to serialize my Rust structs to JSON. On the
           | web Client I compiled Rust to wasm and used the Reqwest crate
           | (http client that uses Fetch in wasm) to talk to my server,
           | Rust structs are shared between server and client.
           | 
           | For me, the beauty about Rust in this setup, is that cross
           | compiling/crossplatform is builtin into the tooling (Cargo).
           | For example the Reqwest crate compiles down to use the
           | browser Fetch api when running in Wasm, and the same crate on
           | the server uses a native implementation using openssl (or
           | rusttls).
        
             | kevincox wrote:
             | I did something making a game. The game logic runs server
             | side however in order to hide latency the clients also run
             | a WASM copy locally. Then once the server processes their
             | moves they check that everything was in-sync and if not
             | reload with the server state.
             | 
             | (In practice the validation is probably not necessary but
             | doesn't hurt to have).
        
             | rapsey wrote:
             | I even use druid for a simple browser gui on top of a rust
             | json rest service. For an internal tool. Serde on both
             | ends. Works great.
        
         | sime2009 wrote:
         | My general worry is that the performance gains from using some
         | WASM will just get eaten up by the overhead of jump between JS
         | and WASM and having to copy/convert data. You might be able
         | reduce the problem by porting more stuff from the JS side to
         | the WASM side, but then you risks pulling in huge chunks of
         | your app.
        
           | alpaca128 wrote:
           | Any real performance gains will easily be balanced out by
           | websites doubling their size once again, WASM or not.
        
           | elenchev wrote:
           | JS <--> WASM function calls are not an issue[1], passing
           | large amounts of data is though.
           | 
           | 1. https://hacks.mozilla.org/2018/10/calls-between-
           | javascript-a...
        
             | sime2009 wrote:
             | Does anyone know if that is also the case on V8?
        
               | flohofwoe wrote:
               | JS/WASM calls are fast in V8, and still seem to be
               | improved from time to time (e.g. see:
               | https://v8.dev/blog/v8-release-90#webassembly), not sure
               | about any large data optimizations (TBH I'm not sure what
               | this is about though, because usually one would use JS
               | slices into the WASM heap to avoid redundant copying)
        
               | cdcarter wrote:
               | That works if the data is already in the Wasm linear
               | memory and you need to access it from JS. If you have
               | strings (or whatever) in JS, you need to copy them into
               | the linear memory for the Wasm module to use.
        
       | admax88q wrote:
       | JavaScript is fast. The browser is fast. But communication
       | between the browser and javascript is really really slow.
       | 
       | They are written in languages with incompatible memory models, so
       | lots of data must be copied when communication. They are running
       | in different runtimes, so your javascript JIt can not inline
       | function calls into the DOM.
       | 
       | That's why to this day, if you want to render a bunch of html
       | from javascript, it is faster to generate a giant strin g of
       | markup and pass that to the browser in a single 'innerHTML =
       | "foo"' and let the browser parse all that, than it is to call a
       | bunch of "createElement(); setAttribute(); appendChild();" calls.
        
         | zemnmez wrote:
         | I benchmarked this recently and I am pretty sure this is not
         | true. Many of these 'single page site frameworks' work via this
         | method.
        
           | admax88q wrote:
           | You are correct, I just did my own benchmark, and the DOM
           | approach is no longer correct.
           | 
           | It used to be the case a number of years ago when I last
           | benchmarked.
        
         | tiltrus wrote:
         | Can you share any benchmarks indicating this?
        
           | admax88q wrote:
           | I whipped up one here with a random comment dump from HN. It
           | appears I'm no longer correct.
           | 
           | https://gist.github.com/adamvy/afcace8cbdbe56995626f59f6ea2b.
           | ..
           | 
           | Load this as a script tag in an html file to run.
           | 
           | Last time I benchmarked this it was true, but that was a
           | number of years ago.
        
             | admax88q wrote:
             | Actually, fun fact, if you remove the clearing of the body,
             | the HTML approach is faster.
             | 
             | At least in firefox here.
             | 
             | Benchmarking is difficult.
        
       | joppy wrote:
       | As anecdata, I've also found that using typed arrays does not
       | speed up (actually slows down, by 10% or so) code which uses
       | integer arrays. Making sure that arrays stay in packed-small-
       | integer format (which is not always obvious: for example one has
       | to replace x => -x with x => 0-x to avoid the old IEEE -0 from
       | kicking in) consistently outperforms typed arrays for me, by a
       | large margin if allocating many small arrays, and by a small
       | margin if allocating one large array.
       | 
       | I found similarly "meh" performance improvements when trying to
       | port my Javascript code to webassembly: either modern Javascript
       | implementations are absolutely amazing, or webassembly runtimes
       | still have a ways to go.
        
         | vanderZwan wrote:
         | This is most likely because _allocating_ typed arrays is
         | really, really slow in JavaScript. IIRC it has to do with the
         | fact that there is a lot of flexibility regarding backing
         | buffers or something; each typed array object has about 200
         | bytes of overhead compared to a dozen bytes for a plain array
         | or object (roughly).
         | 
         | Typed arrays are mainly faster in scenarios where you allocate
         | one or a few large TypedArrays once and then re-use them a lot.
         | 
         | That also explains your experience with many small arrays.
         | That's basically the worst way to use TypedArrays.
        
           | joppy wrote:
           | Yes, I did think it wasn't a good way to used typed arrays,
           | but I was still surprised that when allocating only a very
           | small number of large arrays, just plain Javascript arrays
           | outperformed typed arrays.
        
         | yuri91 wrote:
         | A good trick to convince JS engines that you are dealing with
         | integers is to use the "`|0` operator":
         | 
         | let a = 1; let b = 2; let c = a+b|0; // c is guaranteed to be a
         | 32 bit signed integer
         | 
         | This not only ensures correct 32 bit integer semantics (like
         | wrapping around), but also helps the engines to use actual
         | integer instructions in the generated machine code.
         | 
         | For unsigned 32 bit integers, there is `>>>0`, and for
         | multiplication, there is Math.imul().
        
           | cpleppert wrote:
           | >> This not only ensures correct 32 bit integer semantics
           | (like wrapping around), but also helps the engines to use
           | actual integer instructions in the generated machine code.
           | 
           | But there is only one type of number in javascript.
           | Everything is just a double(BigInt aside). You get a 32-bit
           | integer because the bitwise operator casts the result to one.
           | c has the exact same semantics as any other js number.
           | 
           | Yeah there are tricks to convince the engine you are using an
           | integral type but those unless you are doing a lot of
           | benchmarks they aren't really useful. Any compilation tier
           | can choose to use any intermediate representation it wants.
        
           | vanderZwan wrote:
           | One of my colleagues told me to stop doing that because in (I
           | think) V8 these values are immediately converted back to a
           | double nowadays. So annotating all code with |0 doesn't
           | really add speed benefits there, just extra conversions
           | between doubles and integers. Said colleague used to maintain
           | human-asmjs so I trust he knows what he's talking about.
           | 
           | [0] https://github.com/zbjornson/human-asmjs
        
       ___________________________________________________________________
       (page generated 2021-04-14 23:02 UTC)