This patch rethinks the way indexed property storage works:
Instead of having a cut-off point at 200 elements where we always move
to generic property storage, we now allow arrays to stay in simple mode
as long as we don't create a gap/hole larger than 200 elements.
We also simplify generic storage to only have a hash map (for now)
instead of juggling both a vector and a hash map. This is mostly fine
since the vast majority of arrays get to stay simple now.
This is a huge speedup on anything that uses basic JS arrays with more
than 200 elements in them. :^)
Otherwise we continuously lose the first sparse element (at index
SPARSE_ARRAY_THRESHOLD) without noticing, as we overwrite all indices
with the value at index+1.
Fixes#5884.
Instead of counting the number of call frames on the VM stack, we now
always fake the "arguments" object when the current call frame has
a callee value.
This fixes an issue with DOM event handlers in LibWeb not being able
to access "arguments" since they were called without an outer frame.
Checking for the existence of a call frame is not enough to check if
we're in a function call, as the global execution context is a regular
call frame as well.
Found by OSS-Fuzz, where simply accessing "arguments" in the global
scope would crash due to call_frame().callee being an empty value
(https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=32115).
https://tc39.es/ecma262/#sec-function.prototype.tostring - this is how
the spec wants us to do it. :^)
Also change the function name behaviour to only provide a name for
NativeFunctions, which matches other engines - presumably to not expose
Proxy objects, and to prevent "function bound foo() { [native code] }".
There are three JS::Function types that are not ScriptFunction:
NativeFunction, BoundFunction and ProxyObject. We were only checking for
the first two when determining whether to reconstruct the function's
source code, which was leading to a bad cast to ScriptFunction.
Since only ScriptFunction has the [[SourceText]] internal slot, I simply
swapped the branches here.
Fixes#5775.
- We were not passing the to_string()'d argument to the exec function
but the original argument
- We were leaking an empty value in two cases, which almost certainly
will crash something down the line
- We were not checking for exceptions after to_string() and get(), which
both may throw. If the getter is an accessor, it'll assert upon being
called with the VM already storing an exception.
This is basically just for consistency, it's quite strange to see
multiple AK container types next to each other, some with and some
without the namespace prefix - we're 'using AK::Foo;' a lot and should
leverage that. :^)
https://tc39.es/ecma262/#sec-properties-of-the-regexp-prototype-object
The RegExp prototype object:
- is an ordinary object.
- is not a RegExp instance and does not have a [[RegExpMatcher]]
internal slot or any of the other internal slots of RegExp instance
objects.
In other words: no need to have RegExpPrototype inherit from
RegExpObject (we weren't even calling its initialize()).
https://tc39.es/ecma262/#sec-properties-of-the-array-prototype-object
The Array prototype object: [...] is an Array exotic object and has the
internal methods specified for such objects.
NOTE: The Array prototype object is specified to be an Array exotic
object to ensure compatibility with ECMAScript code that was created
prior to the ECMAScript 2015 specification.
(...and ASSERT_NOT_REACHED => VERIFY_NOT_REACHED)
Since all of these checks are done in release builds as well,
let's rename them to VERIFY to prevent confusion, as everyone is
used to assertions being compiled out in release.
We can introduce a new ASSERT macro that is specifically for debug
checks, but I'm doing this wholesale conversion first since we've
accumulated thousands of these already, and it's not immediately
obvious which ones are suitable for ASSERT.
This was not implementing the following part of the spec correctly:
27. For each integer i such that i ≥ 1 and i ≤ n, do
a. Let captureI be ith element of r's captures List.
b. If captureI is undefined, let capturedValue be undefined.
Expecting a capture group match to exist for each of the RegExp's
capture groups would assert in Vector's operator[] if that's not the
case, for example:
/(foo)(bar)?/.exec("foo")
Append undefined instead.
Fixes#5256.