Hacker News new | past | comments | ask | show | jobs | submit | IainIreland's comments login

I believe the technical term for the property that existing JS engines lack here is "safe for space". The V8 bug (https://issues.chromium.org/issues/41070945) has already been linked elsewhere).

Here's a long-standing SpiderMonkey bug: https://bugzilla.mozilla.org/show_bug.cgi?id=894971.

Here's a JSC equivalent: https://bugs.webkit.org/show_bug.cgi?id=224077.\

Both of those bugs (especially the JSC one) sketch out possible solutions and give some insight into why this is hard to implement efficiently. In general, it adds a lot of complexity to an already complicated (and performance-sensitive!) chunk of code.


I can't speak for any other engines, but in SpiderMonkey a BigInt is a GC-managed object with a one-word header containing the sign bit, the length, and some GC bookkeeping bits, along with a second word that is either a single inline 64-bit digit, or a pointer to an array of 64-bit digits. So the memory overhead of a BigInt that fits in 64 bits is "only" 2x, but doing math with BigInt requires more work than a native integer because it needs to handle larger numbers, manually manage sign bits, and so on.

(https://searchfox.org/mozilla-central/source/js/src/vm/BigIn...)


This seems unlikely, given that the moai were mostly carved from tuff from a specific crater (https://en.wikipedia.org/wiki/Rano_Raraku), whereas the stone gardens are made of "fresh basalt quarried at nearby valley rims" (https://evols.library.manoa.hawaii.edu/server/api/core/bitst...). There's a lot of research supporting the conclusion that these stone accumulations were agricultural.


IMAO, the stone gardens could have at least three reasonable uses.

It seems that they are distributed in coastal areas. It seems also that many moai were built or moved to those areas. Therefore there must be a place, somewhere in the island with a lot of accumulated rubble, but this place will not be just a lot of tuff gravel.

To cut a rock, you need something harder. Egyptians used metals, quarz sand and granite but you can't always find rhyolite in a volcanic island. I assume that there is not a source of granite on Eastern Island and that mining metals or diamonds is out of the table.

We could speculate that antique sculptors learned soon that basalt was the most convenient source of polishing moai. Can be found everywhere in a volcanic island, and is harder than tuff.

If we don't find art carved in basalt in that culture, that would suggest that the culture was restricted to carve soft rocks only, by lack of a source of tools harder than basalt in a significant amount.

Is also logical to assume that after a while the polishing material gets worn and must be discarded and replaced after shrinking to a size too small to be manageable.

If this size is the same of the gravel found in the stone gardens, we have a theory here about the origin of this rubble accumulations, even if they were recycled later for culturing sweet potato wines.


The whole point is that the sandbox is an approach that can be used in JIT code, where Rust doesn't help.

Take the fizzbuzz example with a missing bounds check. Rust can't prevent you from generating JIT code that omits a bounds check on an array and reads/writes out-of-bounds. The sandbox doesn't prevent out-of-bounds reads/writes, but it guarantees that they will only be able to access data inside the sandbox.

This means that logic bugs in the JIT compiler are no longer immediately exploitable. They must be combined with bugs in the sandbox implementation. The article's claim is that, unlike compiler bugs, sandbox bugs tend to be amenable to standard mitigation techniques.

This article isn't dismissing the value of memory-safe languages. It's identifying a problem space where current memory-safe languages can't help, and providing an alternative solution. Currently, every browser JS engine is written in C++, in part because Rust doesn't solve the big correctness problems. If the sandbox approach works, then using Rust for other parts of the engine becomes more appealing.


To be clear. I have no issue with the sandboxing as a technique. It's perfectly valid and a good idea. My issue is that sandbox escapes are significantly easier than they should be due to the C++ runtime. Rust 100% would help mitigate sandbox escapes more effectively even as the codebase evolves. We know through lots of practical experience that "standard mitigation techniques" for C++ don't actually work all that well (there's at least about an order of magnitude difference in number of exploits possible between that & Rust).


Those are the intended semantics of JS, but that doesn't help you when you're the one implementing JS. Somebody has to actually enforce those restrictions. Note that the code snippet is introduced with "JSArray::buffer_ can be thought of as a JSValue*, that is, a pointer to an array of JavaScript values", so there's no bounds checking on `buffer_[index]`.

It's easy enough to rewrite this C++ code to do the right bounds checking. Writing the code in Rust would give even stronger guarantees. The key point, though, is that those guarantees don't extend to any code that you generate at runtime via just-in-time compilation. Rust is smart, but not nearly smart enough to verify that the arbitrary instructions you've emitted will perform the necessary bounds checks. If your optimizing compiler decides it can omit a bounds check because the index is already guaranteed to be in-bounds, and it's wrong, then there's no backstop to swoop in and return undefined instead of reading arbitrary memory.

In short, JIT compilation means that it's ~impossible to make any safety guarantees about JS engines using compile-time static analysis, because a lot of the code they run doesn't exist until runtime.


>Those are the intended semantics of JS

They're actually not. Out of bounds indexing is fine, you just get undefined as the result.


> If your optimizing compiler decides it can omit a bounds check

What is the reason for omitting OOB checks at all? Is it a big performance hit?


It's the same as any code that won't run: there's no point in running it if it won't do anything.


Yes.

The speedometer graphic was inherited from Speedometer 2. When Speedometer 2 was released, scores were in a reasonable car-speed range. The combination of hardware and software improvements meant that early versions of Speedometer 3 (which includes a subset of Speedometer 2 tests) were consistently scoring above 140, so we adjusted the scaling factor (IIRC, by ~20x) to give plenty of room for future improvements.


"The score is a rescaled version of inverse time" is the key here.

If you run all the tests in half the time, your Speedometer score will double. If your score improves by 1%, it implies that you are 1% faster on the subtests.

(There are probably some subtleties here because we're using the geometric mean to avoid putting too much weight on any individual subtest, but the rough intuition should still hold.)


(I work on SpiderMonkey.)

Benchmarking is hard. It is very easy to write a benchmark where improving your score does not improve real-world performance, and over time even a good benchmark will become less useful as the important improvements are all made. This V8 blog post about Octane is a good description of some of the issues: https://v8.dev/blog/retiring-octane

Speedometer 3, in my experience, is the least bad browser benchmark. It hits code that we know from independent evidence is important for real-world performance. We've been targeting our performance work at Speedometer 3 for the last year, and we've seen good results. My favourite example: a few years ago, we decided that initial pageload performance was our performance priority for the year, and we spent some time trying to optimize for that. Speedometer 3 is not primarily a pageload benchmark. Nevertheless, our pageload telemetry improved more from targeting Speedometer 3 than it did when we were deliberately targeting pageload. (See the pretty graphs here: https://hacks.mozilla.org/2023/10/down-and-to-the-right-fire...) This is the advantage of having a good benchmark; it speeds up the iterative cycle of identifying a potential issue, writing a patch, and evaluating the results.


This doesn't say anything about what the scores mean.

21 is apparently better than 20, but how much better? You could say "1 better", tautologically, but how does that relate to the real world?

Driving a car 1 mile per hour faster may be better, in a sense, but even if you drove 24 hours straight, it would only gain you 24 total miles, which is almost negligible on such a long trip. Nobody would be impressed by that difference.


It means it is 5% faster. You are overcomplicating it.


Percentages are rarely informative without an absolute reference.

A 5% raise for someone who makes $20k per year is $1k, whereas a 5% raise for someone who makes $200k is $10k, which would be a 50% raise for the former.


You've demonstrated you understand how to use the score to compare both inter-browser performance (analogous to the amount each makes per year) as well as individual browser performance improvements (analogous to the amount of the raise). Seems pretty informative to me?


Iain explained that in a reply to your other comment: https://news.ycombinator.com/item?id=39672279

> "The score is a rescaled version of inverse time" is the key here.

> If you run all the tests in half the time, your Speedometer score will double. If your score improves by 1%, it implies that you are 1% faster on the subtests.

> (There are probably some subtleties here because we're using the geometric mean to avoid putting too much weight on any individual subtest, but the rough intuition should still hold.)



That's irrelevant. The speedometer reading is an absolute reference. The percentages being discussed are simply comparisons, and they're only being discussed to say "they behave like you'd expect."

To directly answer your original question: a reading of 21 is 5% better than a reading of 20 because 21 is 5% greater than 20, and this means that a 21 speed browser should do things 5% faster than a 20 speed browser.

TL;DR: They behave like you'd expect.


> The speedometer reading is an absolute reference.

To what?

I talked about driving a car. Miles and hours are an absolute reference. We still have no absolute reference for Speedometer.


To... itself? Go measure something. You now have a reference!

If you scratch out the labels of your car speedometer and forget which is which, it still measures speed. 80 is still 33% faster than 60, regardless of the units.


This reply is ridiculous. I'm done.


Suit yourself!

I suspect your questions would be answered better by playing around with the tool in question for a few minutes anyway, as you seem to be asking about capabilities the tool does not purport to have.


I guess that’s why it’s fairly interesting to see scores thrown out in this thread on random hardware. It’s anexdata, but gives a sense of the spread/variance of scores for common platforms. I don’t think this is a number that is ever going to make much sense for consumers to use because without this sort of context it’s just going to be like the spinal tap ‘this one goes to 11’ sort of problem.


It's hard to predict statically which branches will be dynamically unpredictable.

A seasoned hardware architect once told me that Intel went all-in on predication for Itanium, under the assumption that a Sufficiently Smart Compiler could figure it out, and then discovered to their horror that their compiler team's best efforts were not Sufficiently Smart. He implied that this was why Intel pushed to get a profile-guided optimization step added to the SPEC CPU benchmark, since profiling was the only way to get sufficiently accurate data.

I've never gone back to see whether the timeline checks out, but it's a good story.


The compiler doesn't do much of the predicting, it's done by the CPU in runtime.


Not prediction, predication: https://en.wikipedia.org/wiki/Predication_(computer_architec...

By avoiding conditional branches and essentially masking out some instructions, you can avoid stalls and mis-predictions and keep the pipeline full.

Actually I think @IainIreland mis-remembers what the seasoned architect told him about Itanium. While Itanium did support predicated instructions, the problematic static scheduling was actually because Itanium was a VLIW machine: https://en.wikipedia.org/wiki/VLIW .

TL;DR: dynamic scheduling on superscalar out-of-order processors with vector units works great and the transistor overhead got increasingly cheap, but static scheduling stayed really hard.


As I understand it, V8 keeps track of an ElementsKind for each array (or, more precisely, for the elements of every object; arrays are not special in this sense). If an array only contains floats, then they will all be stored unboxed and inline. See here: https://source.chromium.org/chromium/chromium/src/+/main:v8/...

I assume that integers are coerced to floats in this mode, and that there's a performance cliff if you store a non-number in such an array, but in both cases I'm just guessing.

In SpiderMonkey, as you say, we store all our values as doubles, and disguise the non-float values as NaNs.


thank you for the correction!


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: