On Mon, Apr 14, 2025 at 6:06 PM GregRos <work.gr...@gmail.com> wrote:
>
> I'm developing a new version of my parser library (https://parjs.org/), so 
> I'm writing kind of low-level CPU-bound code.
>
> It's a parser combinator library, so parsers are composed of building blocks 
> and combinators that work like a tree. Each combinator "class" has different 
> logic and properties.
>
> However, their external interface is the same, with a single `parse` method 
> that applies whatever logic the class has.
>
> A combinator like "many" can potentially apply any parser repeatedly, and so 
> different instances will have different parser inputs. For example, you can 
> have:
>
> new Many(new Digit()) parses multiple digits
> new Many(new String("abc")) parses multiple literals "abc"
> new Many(new Letter()) parses multiple letters
>
> Inside the code of `Many`, you'd have a call like `child.parse(input)`
>
> In the previous version, profiling and diagnostics revealed that performance 
> was dominated by function call overhead, and almost all the method calls 
> turned out to be megamorphic because when `child.parse` was called in the 
> same location, `child` was a different type of object.
>
> In this new version, I'm trying to figure out if it's possible to avoid that. 
> My idea is to pass around functions instead of objects with methods. By doing 
> this, I'm hoping that method resolution can be avoided, and that the code 
> won't need to be megamorphic because all the objects are sufficiently similar.
>
> These functions still need internal parameters, which includes input parser 
> objects.
>
> The nicest idea is to use closures.
> But another solution could be doing something like 
> `parser.parse.bind(parser)` and passing that around.
>
> Will something like this allow me to avoid megamorphism? Is there something 
> else I can do?

Yes, closures will work for that. Other approaches that can work (but
are maybe less robust, more cumbersome, etc.) are:

1. using arrays instead of objects (indexed vs. named properties) so
you don't get the "exploding hidden classes" thing; caveat: not 100%
foolproof, V8 has different array representations

2. guarding property accesses behind instanceof checks to keep inline
caches monomorphic: if (obj instanceof Foo) obj.x = 42; else if (obj
instanceof Bar) obj.x = 42; - the instanceof checks can become
expensive(ish) though

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/v8-users/CAHQurc82hWRYsUtpi-GpikdgHtbHjeTqgf%2BR80e2B7i7xG1d3A%40mail.gmail.com.

Reply via email to