Calling js_call with n < 0 led to us popping a negative number of items
from the stack, which could make us miss the stack size check.
Sanitize all uses of function.length in Function.prototype.apply and
Function.prototype.bind.
The object in the 'this' slot may be overwritten if the constructor converts
it to a primitive value. Save the original object in an explicit stack slot
to keep it safe for returning afterwards.
Check string length when creating strings to not exceed a maximum,
so we avoid integer overflows when concatenating strings.
The string limit must be small enough that we'll not integer overflow
in one concatenation (A + B + 1 must not overflow while still
exceeding the string limit).
Set the limit to 64KB for now.
If we need 2GB strings then we will have to use double or int64 variables
when calculating string lengths.
The underlying string of the "source" property of a regular expression
object can be freed if the regexp is garbage collected.
This could lead to a use-after-free, because the accessor incorrectly
assumed that the regexp source was an interned (thus never freed) string.
Fix this by calling js_pushstring instead of the faster but unsafe
js_pushliteral.
Many thanks to Connor Nelson for spotting this!
Use a specialized array initializer that pushes values to the end
of the array instead of using a lot of setprop. This avoids the need
to create a lot of number constants for the array indices.
The problem with a fixed count value is that it result in varying
degrees of performance and memory impact proportions depending on
the usage pattern of each script.
E.g. if a script keeps using the same 1M objects, then a threshold of
10K objects will result in GC cycles which free only 1% of objects,
which is hugely wasteful in terms of performance. On the other hand,
if a script only uses 100 objects then a threshold of 10K means it
uses 100 times more memory than it actually needs before GC triggers.
Now the threshold is a target memory usage factor (of the minimum
needed memory) which GC tries to aim at. This makes the GC impact
have constant proportions.
The default aims at a memory usage factor of 5, i.e. 80% garbage
and 20% remaining on each GC cycle.
The factor is only a target/goal because the actual overhead is not
known until GC completes. However, most scripts exhibit consistent
enough behavior such that the real overhead is within 10% or less of
the goal even when the usage pattern changes over time.
Within the v8 bench test suite, the actual GC threshold count varies
between ~50K to ~500K, where only one test (raytrace.js) stabilizes on
less than 10K (the previous fixed default) - at about 9K and its score
decreases by ~5%.
The splay.js score increases about x12 fold (or x50 fold from the
previous commit which counts properties), other tests quite a bit
less or none at all, and the overall score increases by nearly 40%.
Also, change the count type from int to unsigned int to get twice the
range. Preferably we should make it even bigger, maybe uint64_t.
For instance the splay.js v8 bench test surpasses million non-garbage
allocations within few seconds (that's why its score increased so much
with a proportional overhead), and the default GC threshold is 5 times
that number.
We're supposed to check whether a string turned into an integer and back
is itself, while also returning the value of the integer. We were
unintentionally allowing integers with leading zero through.
Only create an iterator for coercible types in OP_ITERATOR, and then
detect the lack of a real iterator in OP_NEXTITER.
Thus we don't need to allocate and push an empty iterator object for
these cases.
The temporary array we use for sorting cannot be seen by the GC, and that
violates the constraint that all js_Value values must always be reachable
from the stack or global environment.
Temporarily turning off the GC will let us use the temporary array for
fast sorting using qsort(), without tripping over this violation.
Don't distinguish lax mode code by pushing the global object.
Always push undefined and let the calling code promote an undefined
this to the global object instead.
As a side effect when changing to using regular integers (and avoid the
nightmare of mixing signed and unsigned) we accidentally allowed negative
array lengths.
Make sure to make a copy of the source pattern string.
A case we missed when adding short and memory strings to the runtime.
The code assumed all strings passed to it were either literal or interned.