DOM::Node now points to its LayoutNode with a WeakPtr.
LayoutNode points to its DOM::Node and DOM::Document with RefPtrs.
Layout trees come and go in response to various events, so the DOM tree
already has to deal with that. The DOM should always live at least as
long as the layout tree, so this patch enforces that assumption by
making layout nodes keep their corresponding DOM objects alive.
This may not be optimal, but it removes a lot of ambiguous raw pointer
action which is not worth accomodating.
Oops, it seems like I implemented all of the "nodes keep the document
alive" mechanism except the part where the functions are actually
called. :^)
Fixes#3811.
A large number of JS strings are a single ASCII character. This patch
adds a 128-entry cache for those strings to the VM. The cost of the
cache is 1536 byte of GC heap (all in same block) + 2304 bytes malloc.
This avoids a lot of GC heap allocations, and packing all of these
in the same heap block is nice for fragmentation as well.
This allows the user to start typing and highlighting and jumping
to a match in ColumnsView, IconView, TableView and TreeView if
the model supports it.
This fixes flipping between left/top and right/bottom when the rectangle
to make visible doesn't fit into the visible portion each time the
function is called.
Use the same logic for all variants for Painter::draw_text. Also,
add an overload that allows taking a callback function for custom
gylph drawing. This allows drawing some glyphs differently in the
correct location when drawing more complex strings (e.g. multi-line,
elisions, etc).
This reverts my previous commit in WebServer and fixes the whole issue
in a much better way. Instead of having the MIME type guesser take a
URL (which we don't actually have in the WebServer at that point),
just take a path as a StringView.
Also, make use of the case-insensitive StringView::ends_with() :^)
This allows us to provide better error messages as we can point the
syntax error location to the exact first invalid parameter instead of
always the end of the function within a object literal or class
definition.
Before this change:
const Foo = { set bar() {} }
^
Uncaught exception: [SyntaxError]: Object setter property must have one argument (line: 1, column: 28)
class Foo { set bar() {} }
^
Uncaught exception: [SyntaxError]: Class setter method must have one argument (line: 1, column: 26)
After this change:
const Foo = { set bar() {} }
^
Uncaught exception: [SyntaxError]: Setter function must have one argument (line: 1, column: 23)
class Foo { set bar() {} }
^
Uncaught exception: [SyntaxError]: Setter function must have one argument (line: 1, column: 21)
The only possible downside of this change is that class getters/setters
and functions in objects are not distinguished in the message anymore -
I don't think that's important though, and classes are (mostly) just
syntactic sugar anyway.
I'm about to add even more options and a bunch of unnamed true/false
arguments is really not helpful. Let's make this a single parse options
parameter using bit flags.
Instead of just ripping out the root of the layout tree from its RefPtr
in Document, actually go through the DOM and gather up all the layout
nodes. Then destroy them all in one swoop.
Also, make sure to do this when detaching Document from Frame,
to enforce the invariant that layout only occurs in framed documents.
Problem:
- `constexpr` functions are decorated with the `inline` specifier
keyword. This is redundant because `constexpr` functions are
implicitly `inline`.
- [dcl.constexpr], §7.1.5/2 in the C++11 standard): "constexpr
functions and constexpr constructors are implicitly inline (7.1.2)".
Solution:
- Remove the redundant `inline` keyword.
This provides a huge speed-up for objects with large numbers as property
keys in some situation. Previously we would simply iterate from 0-<max>
and check if there's a non-empty value at each index - now we're being
smarter and compute a list of non-empty indices upfront, by checking
each value in the packed elements vector and appending the sparse
elements hashmap keys (for GenericIndexedPropertyStorage).
Consider this example, an object with a single own property, which is a
number increasing by a factor of 10 each iteration:
for (let i = 0; i < 10; ++i) {
const o = {[10 ** i]: "foo"};
const start = Date.now();
Object.getOwnPropertyNames(o); // <-- IndexedPropertyIterator
const end = Date.now();
console.log(`${10 ** i} -> ${(end - start) / 1000}s`);
}
Before this change:
1 -> 0.0000s
10 -> 0.0000s
100 -> 0.0000s
1000 -> 0.0000s
10000 -> 0.0005s
100000 -> 0.0039s
1000000 -> 0.0295s
10000000 -> 0.2489s
100000000 -> 2.4758s
1000000000 -> 25.5669s
After this change:
1 -> 0.0000s
10 -> 0.0000s
100 -> 0.0000s
1000 -> 0.0000s
10000 -> 0.0000s
100000 -> 0.0000s
1000000 -> 0.0000s
10000000 -> 0.0000s
100000000 -> 0.0000s
1000000000 -> 0.0000s
Fixes#3805.
This reduces malloc()/free() calls in `disasm /bin/id` by 30%
according to LIBC_DUMP_MALLOC_STATS.
No measurable performance change (the number of empty block hits
remains unchanged, and that's what's slow), but maybe a nice
change regardless?
If there's a newline between the closing paren and arrow it's not a
valid arrow function, ASI should kick in instead (it'll then fail with
"Unexpected token Arrow")
This simplifies try_parse_arrow_function_expression() and fixes a few
cases that should not produce an arrow function AST but did:
(a,,) => {}
(a b) => {}
(a ...b) => {}
(...b a) => {}
The new parsing logic checks whether parens are expected and uses
parse_function_parameters() if so, rolling back if a new syntax error
occurs during that. Otherwise it's just an identifier in which case we
parse the single parameter ourselves.
These happen right after "DOMContentLoaded" for now, which is incorrect
since they should really wait until subresources have loaded.
However, this makes a bunch of things work already so let's do it.
It would be cool to solve this in a general way so that looking up
a string literal or StringView in a HashMap with String keys avoids
creating a temp string.
For now, this patch simply addresses the issue in JS::Lexer.
This is a 2-3% speed-up on test-js.
Instead of performing a prototype transition for every new object we
create via {}, prebake the object returned by Object::create_empty()
with a shape with ObjectPrototype as the prototype.
We also prebake the shape for the object assigned to the "prototype"
property of new ScriptFunction objects, since those are extremely
common and that code broke from this change anyway.
This avoid a large number of transitions and is a small speed-up on
test-js.
This is not actually necessary, since no GC allocations are made during
this process. If we ever make property tables into heap cells, we'd
have to rethink this.