esprima-dotnet icon indicating copy to clipboard operation
esprima-dotnet copied to clipboard

Use System.Span

Open lahma opened this issue 6 years ago • 6 comments

Opening for tracking. My masterpiece where Slice tries to match common keywords will come much simpler. This will affect a lot of public API by having ReadOnlySpan instead of string, but all should become quite alloc-free.

lahma avatar Apr 10 '18 05:04 lahma

I'm leaning towards having custom TextSpan like Parlot has and then allowing span-based operations via it's Span property.

Span can be used where the methods take it as input, like number parsing, but there's so much performance overhead trying to handle Memory<T> and span against backing string script.

lahma avatar Dec 19 '21 09:12 lahma

@Xicy I might have some prototype in some branch, I probably need to check if it's any good starting point and how far away from current main...

lahma avatar Jun 09 '22 05:06 lahma

I'm leaning towards having custom TextSpan like Parlot has and then allowing span-based operations via it's Span property.

Isn't TextSpan practically the same as ReadOnlyMemory<char>? Though I don't know if the underlying object needs to be accessed. If so, then there's another built in type, StringSegment in the framework.

adams85 avatar Jun 09 '22 12:06 adams85

Hmm, didn't know about StringSegment, thanks for sharing. It's a bit heavy to bring a dependency package just for that though. What I remember from Memory<T>, it brought quite the overhead, might have used it wrong too tough.

It's safe to say that original string is always around and ok to keep in memory for the lifetime of the Program (Script/Module), needs a lightweight way to access it. Memory/Span approach becomes problematic when the value needs to be stored as dictionary key (which Jint does a lot), span cannot be used as a key - TextSpan/StringSegment can. From Jint's perspective having to do .ToString() to gain usable key would make change meaningless (Memory/Span).

lahma avatar Jun 09 '22 12:06 lahma

What I remember from Memory, it brought quite the overhead, might have used it wrong too tough.

I'm also not an expert on (ReadOnly)Memory<T> but at first glance it just stores the same info (object, index, length) and being an ordinary struct, it can be used as dictionary key as well. Converting it to a (ReadOnly)Span<T> looks like a bit complicated though. Maybe that's where the overhead come from?

One further thing I'm aware of: Span<T> and co. have worse performance on .NET Framework than on .NET Core as they're implemented differently. Here's some additional resource on the topic. (Disclaimer: despite the similar name, I'm not the author of the article 😄)

EDIT: I consistently used Memory<T> in my comments but our use case probably would need ReadOnlyMemory<T> instead.

adams85 avatar Jun 09 '22 13:06 adams85

I've tested this with StringSegment and memory benefits are very little as long as Token instances dominate allocations.

lahma avatar Jul 21 '22 19:07 lahma

In the light of work done recently we can consider this done, right?

adams85 avatar Aug 21 '22 18:08 adams85

Indeed!

lahma avatar Aug 21 '22 18:08 lahma