I've got some ideas on how to tweak the embedding API, but I want to
see what performance impact they have first, so this adds a little
benchmark that just calls a foreign method a ton of times.
This is the first step towards dynamically grown stacks. We don't want
to check for stack overflow on every single push, so we store the max
number of slots a function might need and (in later patches) ensure
at function call time that that many slots are available.
If we ever support custom string templates, we'll need to go back to
compiling them to functions. But, for now, they can be evaluated
eagerly, leading to simpler code.
This allows "%(...)" inside a string literal to interpolate the
stringified result of an expression.
It doesn't support custom interpolators or format strings, but we can
consider extending that later.
- Rename "Expressions" -> "Method Calls".
- Organize "Types" and "Language" into a single linear narrative.
- Mobile-specific navigation to handle the longer guide.
- Rename "Fibers" -> "Concurrency".
- Get rid of duplicate stuff about signatures in "Classes".
- Add next/prev links to each page in the guide.
- Move "Contributing" and "Community" up to the top level.
- Move the precendence table to a separate "Grammar" page.
- Lots of other little stuff.
- Make sure it handles an empty gray set.
- Make sure growing the gray stack doesn't itself trigger a GC.
- Make sure it works when stress testing is enabled.
- Ensure the tests kick off a GC.
The previous GC implementation used a recursive mark method. This can
result in stack overflows when attempting to mark deeply nested objects.
This commit replaces the recursive approach with an iteritive one,
moving the state stack from the C call stack to the `WrenVM` structure.
As objects are 'grayed' they are pushed onto the VM's gray stack. When
we have grayed all of the root objects we iterate until the stack is
empty graying any obejcts which haven't been marked as dark before. At
the end of the process we clean up all unmarked objects as before.
This commit also adds a few new tests which check garbage collection by
allocating some new deeply nested objects and triggering the GC a few
times in the process.