After removing the unwind context stack, ExecutionContextRareData only
held two GC::Ptr fields — both trivially destructible. The indirection
cost more than it saved: a GC cell allocation per EC, an extra pointer
chase on every source range lookup, and unnecessary complexity.
Replace the rare data cell with two inline fields on ExecutionContext:
cached_source_range and context_owner.
When passing a Vector<JS::Value> to the MarkingVisitor, we were
iterating over the vector and visiting one value at a time. This led
to a very inefficient way of building up the GC's work queue.
By adding a new visit_impl() virtual to Cell::Visitor, we can now
grow the work queue capacity once, and then add without incrementally
growing the storage.
We treat any mention of [[ArrayBufferByteLengthData]] and related
atomic operations as FIXMEs to be fixed at a later date. We also add the
HostGrowSharedArrayBuffer abstract operation, which will be overridden
by LibWeb to grow shared WebAssembly memories.
test262-runner needs to make a clean slate VM for each test, so let's
relax the enforcement here a little bit. As long as there is only one
JS::VM instantiated, we're good.
In our process architecture, there's only ever one JS::VM per process.
This allows us to have a VM::the() singleton getter that optimizes
down to a single global access everywhere.
Seeing 1-2% speed-up on all JS benchmarks from this.
This was causing a fair bit of root registration churn on pages that
throw lots of errors.
Since there's no need for these pointers to float around freely, we can
just visit them during the mark phase as usual.
Instead of having ExecutionContext track function names separately,
we give FunctionObject a virtual function that returns an appropriate
name string for use in call stacks.
This commits puts the strict mode flag in the header of every bytecode
instruction. This allows us to check for strict mode without looking at
the currently running execution context.
We are often forced to convert numbers to strings inside LibJS, e.g when
iterating over the property names of an array, but it's also just a very
common operation in general.
This patch adds a 1000-entry string cache for the numbers 0-999 since
those appear to be by far the most common ones we convert.
This has quite a lot of fall out. But the majority of it is just type or
UDL substitution, where the changes just fall through to other function
calls.
By changing property key storage to UTF-16, the main affected areas are:
* NativeFunction names must now be UTF-16
* Bytecode identifiers must now be UTF-16
* Module/binding names must now be UTF-16
This is an active proposal at stage 3 of the TC39 proposal process.
See: https://tc39.es/proposal-dynamic-code-brand-checks/
See: https://github.com/tc39/proposal-dynamic-code-brand-checks
This proposal essentially adds support for the TrustedScript type from
the Trusted Types specification to eval and Function. This in turn
pipes support for the type into the CSP hook to check if the CSP allows
dynamic code compilation.
However, it currently doesn't support ShadowRealms, so the
implementation here is a close approximation, using PerformEval as the
basis.
See: https://github.com/tc39/proposal-dynamic-code-brand-checks/issues/19
This is required to support the new function signature for the CSP
hook, and will allow us to slot in Trusted Types support in the future.
This way it's always automatically correct, and we don't have to
manually flush it in push_execution_context().
~7% speedup on the MicroBench/call* tests :^)
Most of the time there are no queued promise jobs to run after exiting
a stack frame. By moving the check inline, leaving a function call gets
a measurable speedup in the common case.
This helps unwind a niggly depedency where the VM owns and constructs
the Heap and the Agent. But the agent wants to have customized
construction that depends on the heap. Solve this by defering
the initialization of the Agent to after we have constructed the
VM and the heap.
similar-origin window agents have the [[CanBlock]] flag set to false.
Achieve this by hooking up JS's concept with an agent to HTML::Agent.
For now, this is only hooked up to the similar-origin window agent
case but should be extended to the other agent types in the future.
This is very frequently returned by Object.prototype.toString(),
so we benefit from caching it instead of recreating it every time.
Takes Speedometer2.1/EmberJS-Debug-TodoMVC from ~4000ms to ~3700ms
on my M3 MacBook Pro.
PrimitiveString is now internally either UTF-8, UTF-16, or both.
We no longer convert them to/from ByteString anywhere, nor does VM have
a ByteString cache.
Linking a module has assertions about the module's state, namely that
the state is not "new". The state remains "new" if loading the module
has failed. See: https://tc39.es/ecma262/#figure-module-graph-missing
In any case, this exception causes a loading failure, which results
in A's [[Status]] remaining new.
So we must propagate that failure, instead of blindly moving on to the
linking steps.
Resulting in a massive rename across almost everywhere! Alongside the
namespace change, we now have the following names:
* JS::NonnullGCPtr -> GC::Ref
* JS::GCPtr -> GC::Ptr
* JS::HeapFunction -> GC::Function
* JS::CellImpl -> GC::Cell
* JS::Handle -> GC::Root
Instead, smuggle it in as a `void*` private data and let Javascript
aware code cast out that pointer to a VM&.
In order to make this split, rename JS::Cell to JS::CellImpl. Once we
have a LibGC, this will become GC::Cell. CellImpl then has no specific
knowledge of the VM& and Realm&. That knowledge is instead put into
JS::Cell, which inherits from CellImpl. JS::Cell is responsible for
JavaScript's realm initialization, as well as converting of the void*
private data to what it knows should be the VM&.
Now that the heap has no knowledge about a JavaScript realm and is
purely for managing the memory of the heap, it does not make sense
to name this function to say that it is a non-realm variant.
This changes the remaining uses of the following functions across LibJS:
- String::format() => String::formatted()
- dbg() => dbgln()
- printf() => out(), outln()
- fprintf() => warnln()
I also removed the relevant 'LogStream& operator<<' overloads as they're
not needed anymore.