Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typescript type annotations as comments #9694

Open
nojvek opened this issue Jul 13, 2016 · 56 comments
Open

Typescript type annotations as comments #9694

nojvek opened this issue Jul 13, 2016 · 56 comments
Labels
Domain: JavaScript The issue relates to JavaScript specifically Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. Suggestion An idea for TypeScript

Comments

@nojvek
Copy link
Contributor

nojvek commented Jul 13, 2016

Typescript’s goal is simply be Javascript + Types.

There are many use cases where one might want to use the excellent typechecker but not really have any emit stage.

Projects already written in javascript work with allowJS. Typescript already supports parsing types from jsdoc comments.

What would be really awesome is just comment annotating your javascript with types and the project gets the benefit of being type checked. This could be a boon for a lot of existing javascript projects. Getting intellisense, VSCode typechecking on the fly and a lot of language server awesomeness.

e.g.

/// <reference path="..." />

class Hello {
    /*:: private*/ hello(message /*: string*/) /*: Promise<{}>*/{
                const promise /*: Promise<void>*/ = null 
        return /*:: <Promise<{}>>*/ null;
    }
}

i.e

/: [type] */
/
:: [tscode] */

@mhegazy mhegazy added Suggestion An idea for TypeScript Salsa labels Jul 13, 2016
@nojvek
Copy link
Contributor Author

nojvek commented Jul 14, 2016

https://flowtype.org/blog/2015/02/20/Flow-Comments.html

Flow has a descent spec. It was a major feature request on their end too.

I think the big value add is typescript's language service. Being able to annotate an existing js code base and get on the fly error checking + code completion is pure awesomeness.

No source mapping needed, Browser/node reads the same code. Don't need to wait for a transpiling step. Node_modules written in this flavor don't need a separate typings install since source+types is same file.

@pardonmyenglish
Copy link

+1 I really love this aspect of flow and wish that TS supports something similar.

@eggers
Copy link

eggers commented Dec 15, 2016

I haven't used it myself, but since 2.0, TypeScript supports jsdoc for typedef: JSDoc support in JavaScript

@pardonmyenglish
Copy link

In my view, the difference is that the JSDoc approach does not resemble the standard TS approach. Take the example in the tutorial: http://www.typescriptlang.org/docs/tutorial.html

function greeter(person) {
    return "Hello, " + person;
}

The recommended TS according to the docs:

function greeter(person: string) {
    return "Hello, " + person;
}

The comment-based approach that flow supports really resembles what you would write -- the type annotation is basically wrapped in a C-style comment:

function greeter(person/*: string*/) {
    return "Hello, " + person;
}

The JSDoc approach technically supports this case, but it is very different from the canonical TS approach:

/**
 * @param {string}  person  
 */
function greeter(person){
    return "Hello, " + person;
}

@nojvek
Copy link
Contributor Author

nojvek commented Dec 15, 2016 via email

@akdor1154
Copy link

It seems there is often resistance to adding a build step in projects where previously was none - at my workplace I am using Flow to provide static analysis over Typescript precisely because of this, and the amount of community support this feature has in Flow suggests this scenario is reasonably common.
If Typescript supported annotations in comments I believe it would pick up a lot of this use, as it's generally considered on the whole to be more powerful than Flow. I know I'd rather use it.
This also shouldn't be specific to Salsa (I guess), my dream implementation of this feature would be that tsc or a ts language service in my IDE of choice would just load .js files with TS comments and treat them as if they were typescript.

@nojvek
Copy link
Contributor Author

nojvek commented Jan 10, 2017 via email

@akdor1154
Copy link

First shot at implementing this. It currently only looks at .ts files (pretty useless, we need it to work with .js). It may also benefit from some equivalent of //@flow, otherwise ts is likely to go parsing everything it can find in node_modules. However, the basic functionality is there and working.

@abenhamdine
Copy link

abenhamdine commented Jan 12, 2017

IMHO, I think this feature is not very necessary (and this is also for future readers who would were eagerly looking for this feature).

At the beginning, I was also shy to add a compilation step in our projects, and considered using Flow only for the benefit of comment syntax. But a few tries whith ts, I realized that :

  • the compilation step in Typescript is quite fast, simple and reliable
  • the js code generate is very readable. Actually, the code transpiled by Typescript is nearly the same that i would have written ! (minus some line breaks removed, etc...). It means that if you want, at any moment, you could stop using ts, and revert back to the js files.

Otherwise, you juste have to rename .js file to .ts file in order to have type checking.

FWIW, our project is a very complex application developped with node and extjs, and we migrate nearly 60% of server code to Typescript in 2 weeks.

@nojvek
Copy link
Contributor Author

nojvek commented Jan 12, 2017 via email

@abenhamdine
Copy link

abenhamdine commented Jan 12, 2017

Thx for you detailled answer !

I have to admit your arguments are quite valid, and probably my feedback too brief (mainly because I'm not a native english speaker).

My feedback is more "hey, you can jump into ts without syntax comment, you should not choose beetween TS and Flow just basing your decision upon the existence of this syntax in Flow".
Because it was exactly the situation where we were two months ago.

Concerning sourcemap, so far, we didn't have too much problems in VSCode. For instance, node debugging has always run perfectly (while again : it's a very complex project). And in case of error in prod, it's not so too difficult to map the .js line to the .ts line (even if it's indeed a waste of time).

However, we have only migrated server code to ts, we don't consider migrate browser code at the moment.

An other caveat is indeed the use of VS Code for editing .js files : we used to be on ST3 for js files, and we switched to VS Code after a poor experience with ST Typescript plugin. We found VS Code less fast and convenient than ST is.
However, VS Code is evolving quickly, and in the right direction IMO.

@aluanhaddad
Copy link
Contributor

Then there will be two type syntaxes embedded in comments, actually three if you include Flow types. JSDoc already has multiple interpretations. Throw TypeScript types into comments and even more complexity is introduced.

@nojvek
Copy link
Contributor Author

nojvek commented Jan 13, 2017 via email

@aluanhaddad
Copy link
Contributor

Want to clarify. I don't think commented types in Typescript bring much

Thanks I wasn't sure if this was intended to apply to JavaScript and TypeScript or just JavaScript.

Commented types in javascript (.JS) are useful. In that scenario, there
are only two types. Jsdoc and flow.

Perhaps but there are different interpretations of JSDoc, TypeScript is one interpretation, Closure is another, JSDoc v3 is yet another.

Flow types are just Typescript types wrapped in comments.

E.g /:string/ and /::/(someValue)

I so wish that were true. Unfortunately the syntax is subtly different. More significantly the meaning can be radically different.

This means having a tsconfig with allowJs should give a very close
experience to Typescript. Both type checker and vscode ide.

That would be a great indeed.

@zspitz
Copy link
Contributor

zspitz commented Jan 14, 2017

@aluanhaddad Could you provide some examples of the differences between the three flavors of commented types?

@aluanhaddad
Copy link
Contributor

aluanhaddad commented Jan 15, 2017

Flow:

type T = { name: string }
Array<U: T>

TypeScript:

type T = { name: string }
Array<U extends T>

JSDoc:

@typedef T { name: string }
@template U implements T
Array<U>

The difference in interpretation is more what I'm concerned about.

@aluanhaddad
Copy link
Contributor

That last example is not yet supported by closure and I'm not even sure if that's how you would write it it's hypothetical syntax

@pardonmyenglish
Copy link

@aluanhaddad I think you are confused about the proposal. The idea isn't to introduce the exact flow syntax into typescript, but rather to introduce a special comment form which JS engines ignore but tsc and typescript parsers interpret as valid TS code.

I gave an example in #9694 (comment) but it wasn't that clear so I will try another example from the tutorial.

Let's say you have an existing JS codebase:

function greeter(person) {
    return "Hello, " + person.firstName + " " + person.lastName;
}

var user = { firstName: "Jane", lastName: "User" };

document.body.innerHTML = greeter(user);

The TS form that defines the person interface looks like:

interface Person {
    firstName: string;
    lastName: string;
}

function greeter(person: Person) {
    return "Hello, " + person.firstName + " " + person.lastName;
}

var user = { firstName: "Jane", lastName: "User" };

document.body.innerHTML = greeter(user);

The comment form which we are discussing is a series of comments atop the JS form that aligns with the TS form:

/*::
interface Person { // <-- this is the same exact code you would write if you fully bought into TS
    firstName: string;
    lastName: string;
}
*/
function greeter(person/*: Person*/) { // <-- the type annotation is in a C-style comment that JS ignores but TS would parse
    return "Hello, " + person.firstName + " " + person.lastName;
}

var user = { firstName: "Jane", lastName: "User" };

document.body.innerHTML = greeter(user);

The ability to write snippets of typescript and embed them in comments would enable developers to slowly annotate their JS code without changing their minified JS output and without having to buy into TS from the onset. This is important for adoption. We ended up adopting flow for a 50kloc JS project because it was incredibly easy to demonstrate the power of flow and incremental type annotations without actually changing the existing workflows or existing live JS.

@aluanhaddad
Copy link
Contributor

I am sorry, I am not trying to be stubborn. I do understand the use case and I agree it is both valid and valuable. I am talking about the way tools behave. If a tool uses a heuristic to find Flow types in comments, it could choke on this. The same is true for JSDoc, but this is probably easier to disambiguate.

@akdor1154
Copy link

akdor1154 commented Jan 15, 2017

@aluanhaddad a heuristic to pick up flow types would be unlikely to pick up these hypothetical typescript types by mistake - flow-annotated-js needs to contain a // @flow comment to trigger processing.

@nojvek
Copy link
Contributor Author

nojvek commented Jan 15, 2017 via email

@abenhamdine
Copy link

abenhamdine commented Mar 6, 2017

And in case of error in prod, it's not so too difficult to map the .js line to the .ts line (even if it's indeed a waste of time).

For the future reader : I correct myself, with https://github.com/evanw/node-source-map-support, we can have the line number in the .ts file, and it works perfectly for us.

@pitaj
Copy link

pitaj commented May 28, 2017

Any updates on this?

Is there a way to implement this as a plugin or something? I'm thinking of just pushing the source code through something like this:

return source
  .replace(/\/\*::([\s\S]*?)\*\//g, '$1')
  .replace(/\/\*:([\s\S]*?)\*\//g, ':$1');

and then passing that to TS, but I'm primarily focused on VS Code support

@nojvek
Copy link
Contributor Author

nojvek commented May 30, 2017

I do like function syntax e.g

function hello(greeting /*: string */, notify /*: boolean */) {
}

Rather than jsdoc comments which are verbose and require duplication of param name.

Currently not supported but I feel that it should be pretty easy to add.

https://github.com/Microsoft/TypeScript/wiki/JSDoc-support-in-JavaScript

@nojvek
Copy link
Contributor Author

nojvek commented Jul 31, 2018

Yeah the hardest part is really convincing Typescript team (cc @DanielRosenwasser) that this is a good idea. TS is essentially a superset of JS, so technically this should be quite straightforward to implement it such that the superset-ness of TS is literally just comments in a JS file.

@RyanCavanaugh RyanCavanaugh added the Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. label Jul 31, 2018
@maranomynet
Copy link

The inability to gradually introduce proper TypeScript annotations into existing JavaScript modules without having to add a compile step for each and every one, is pretty much the only thing holding me and my team back from switching from Flow to TypeScript.

A comment-based annotation option (in .js files flagged with // @ts-check) also dramatically lowers the threshold for developers to do "drive-by-guerrilla-typing" on older projects and smaller modules.

@weswigham weswigham added Domain: JavaScript The issue relates to JavaScript specifically and removed Salsa labels Nov 29, 2018
@TomasHubelbauer
Copy link

The support for allowJs+checkJs with JSDoc has gotten me personally quite far with type checking in JavaScript files, which is why I personally am interested in this feature.

However, a big, big, drawback of using JSDoc is that it differs from TypeScript too much. There are a lot of patterns (especially dealing with generics, overloads, inference etc.) which I know how to type in TypeScript very well, but can't for the life of me figure out in JSDoc.

On top of that, the JSDoc documentation is very poor and overall it is just a different type system, so you don't really get TypeScript, just a super basic version of it.

This is why I'd like to see actual TypeScript type annotations supported in JavaScript files. I don't know if there is "philosophical" opposition to this from the TypeScript developers or it is just not seen as high-enough value, so the only thing I can do is to chime in and say I'd use it - a lot.

@kdmadej
Copy link

kdmadej commented Jun 3, 2019

I just found myself in a similar situation as @TomasHubelbauer did.

I need to use more advanced concepts like mapped types or conditional types but I can't figure out a way to define the aforementioned concepts using JSDoc.

I'm currently working on a project that doesn't use TS but I'd love to get some type checking in VSCode based on type annotations in comments.
Adding support for type annotations in comments would be a life-saver for people who would like to get the benefits of TS but the decision about the techs used in the project is not made by them.

@DanielRosenwasser
Copy link
Member

For situations where you need a more advanced type that isn't supported in JSDoc, you can declare the types in a .d.ts file and then reference the types back in the JSDoc.

@luciotato
Copy link

For anyone coming here looking to add TypeScript type-annotations within comments, I've made a fork with a hack to allow exactly that:
https://github.com/luciotato/plus-typescript/blob/master/README.md
https://github.com/luciotato/plus-typescript
@kdmadej @TomasHubelbauer @maranomynet @nojvek @joeytwiddle Maintainers are welcomed

@nojvek
Copy link
Contributor Author

nojvek commented Oct 12, 2020

Holy moly. This is incredibly cool @luciotato . What I love about this is it supports full breadth of TS syntax. The current jsdoc annotations that typescript team recommends is really a hodge podge of quirks. I've invested 6 months of my life converting our existing js to jsdoc only to realize there are so many little things missing.

@martinheidegger
Copy link

@DanielRosenwasser

For situations where you need a more advanced type...

This is about 2 minutes into trying to define types. I basically have no code that does not use Generics... It becomes a really expensive problem once you realize that 50% of the code needs to be in the .d.ts file. Not only that, but trying to memorize two different syntax is not good for productivity.

@ixis-doug
Copy link

Like others who joined late to the party, let me start by saying how much I appreciate the effort that's gone into Typescript. It's an incredible tool, and to be commenting at all on an issue is a testament to that.

The nearly 6 years this issue has been open is a bit discouraging. The use cases and value have been established, @luciotato built a working prototype, and Flow has long supported this, so there are real users of this feature in the wild. Part of what "opt-in types" ought to mean is that you can start using types in a project that's not ready to be converted to Typescript, even if that conversion is rightly considered easy. The value of writing new libraries in TS is limited by the inability to fully exploit the value of those types in vanilla JS consuming code (and I say "fully exploit" to deliberately cover what one cannot accomplish by telling the editor to treat JS files like typescript and other ways of seeing the types of 3rd party libraries in a vacuum, without defining types in the vanilla JS calling code).

@joeytwiddle
Copy link

joeytwiddle commented Mar 10, 2022

There appears to be some movement in the form of:

https://devblogs.microsoft.com/typescript/a-proposal-for-type-syntax-in-javascript/

... which proposes to redefine what is a comment in future ES.

@ixis-doug
Copy link

There appears to be some movement in the form of:

https://devblogs.microsoft.com/typescript/a-proposal-for-type-syntax-in-javascript/

... which proposes to redefine what is a comment in future ES.

This is indeed related and very exciting, but considering there are browsers that haven't hit EOL that don't even support ES2015 (looking at you IE 11), I think this is a potential solution for 2030 javascript/typescript developers, not 2022 javascript/typescript developers. The typescript language being able to find meaning within comments would be a much more powerful solution when backwards compatibility requirements are considered.

@maranomynet
Copy link

Also: "We decided to lobby for TypeScript officially becoming JavaScript, but still pretend that's not what we're doing"

🤪

@DanielRosenwasser
Copy link
Member

but considering there are browsers that haven't hit EOL that don't even support ES2015 (looking at you IE 11) I think this is a potential solution for 2030

Types can always be stripped away/"downleveled" for older browsers. Considering the proposal will take years of work if it does proceed, 2030 might be when you actually get the feature!

@ixis-doug
Copy link

ixis-doug commented Mar 10, 2022

@DanielRosenwasser

Types can always be stripped away/"downleveled" for older browsers.

Stated differently, could we say "well you could still run your code through a typescript compiler to strip the types"? If so, this leaves us in the in the same position we're currently in, no?

@HolgerJeromin
Copy link
Contributor

I think one of the use case is:
Develop with your fancy new browser and develop faster without compile.
But in production you still use the transpiled/stripped/minified output even for some ie8 if you like/must.

@DanielRosenwasser
Copy link
Member

Well if you're targeting Node, Deno, or primarily evergreen browsers, you can run as-is (especially for the development-time scenarios that @HolgerJeromin just mentioned). If you really need to accommodate older runtimes, you can add this as a production-time build step.

@joeytwiddle
Copy link

joeytwiddle commented Mar 11, 2022

By the way, I have tried using JSDoc in a project, and I learned something I didn't know before:

We don't have to stick to the JSDoc way of declaring types, which usually involves lots of @ tags, and splitting up of objects.

We can instead use TypeScript types inside the JSDocs, to keep things small and familiar!

Here is an example with a function that accepts two strings, and returns an object whose two properties are dictionaries.

This is how we might expect to annotate the function using JSDoc

/**
 * @typedef {Object} MemberGroupsResponse
 * @property {Object.<string, MemberGroup>} memberGroups
 * @property {Object.<string, Array.<string>>} memberGroupsByUser
 *
 * @function getMemberGroupsUncached
 * @async
 * @param {string} month
 * @param {string} memberGroupsSheet
 * @returns {Promise.<MemberGroupsResponse>}
 */
async function getMemberGroupsUncached(month, memberGroupsSheet) { /* ... */ }

But actually we can annotate the function more simply, using a single TypeScript type!

/**
 * @type {(month: string, memberGroupSheet: string) => Promise<{
 *   memberGroups: Record<string, MemberGroup>;
 *   memberGroupsByUser: Record<string, string[]>;
 * }>}
 */
async function getMemberGroupsUncached(month, memberGroupsSheet) { /* ... */ }

Advantage:

  • This is much more concise!

We can also put comments like /** @type string | number */ above a variable

Disadvantages:

  • This isn't really valid JSDoc, so this format isn't suitable for tools which only understand traditional JSDoc
  • Basically these annotations are only really useful in TypeScript-based development environments
  • Still not as short as actual TypeScript, or the inline comments people suggest in this thread
  • I don't know how to lazily omit the return type, so TypeScript can derive it for me
  • In VSCode, there is currently no syntax highlighting for these TS-types-inside-JSDoc
  • In VSCode, autocomplete support works better inside JSDoc than it does for these TS-types-inside-JSDoc

So if you don't need traditional JSDoc but you would like some TS-checking in your JavaScript files, this hybrid approach might work for you.

(I am using TypeScript type checking in VSCode, with the option js/ts.implicitProjectConfig.checkJs but // @ts-check would also work.)

@ShadSterling
Copy link

I'm trying to use tsc to generate .d.ts files for my fork of a JavaScript project, making minimal changes to the original .js files. For almost everything tsc's inference is good enough, and for most of the rest adding comments as described by @joeytwiddle fills in the gaps. But here's one that fails:

The original code:

delete Number.prototype.then;

Types that work in TypeScript:

interface MaybeThenable { then?: Function }
delete (Number.prototype as Number & MaybeThenable).then;

The same types in JSDoc annotation in a .js file:

/** @typedef { { then?: Function } } MaybeThenable */
/** @type { Number & MaybeThenable } */
var klass = Number.prototype;
delete klass.then;

Is rejected by tsc:

Type 'Number' is not assignable to type '{ then?: Function; } & number'.
  Type 'Number' is not assignable to type 'number'.
    'number' is a primitive, but 'Number' is a wrapper object. Prefer using 'number' when possible.

73             var klass = Number.prototype;
                   ~~~~~

It seems that tsc doesn't respect wrapper types given in TSDoc annotations

@ShadSterling
Copy link

Turns out it works if I go to constructors, but it would be better if tsc handled types the same way in both TypeScript annotations and JSDoc annotations

/** @typedef { { prototype: Object & { then?: Function } } } MaybeThenableConstructor */
/** @type { NumberConstructor & MaybeThenableConstructor } */
var konstructor = Number
delete konstructor.prototype.then;

wincent added a commit to wincent/masochist that referenced this issue Aug 6, 2023
As you can see, I also tried to simplify the AST post-processing by
removing explicit TS type annotations in favor of TSDoc comments, but
sadly, `tsc` won't read from those, complaining about implicit `any`
types:

- https://github.com/microsoft/TypeScript/issues/9694

I tried this historically too, and forgot about it, but yeah, it still
doesn't work.

Anyway, numbers (best of 3)...

Before:

    $ node lib/benchmark-static-lexer.js
    Read 5160 bytes
    ┌─────────┬────────────┬───────────┬───────────┬───────────┬──────────────┐
    │ (index) │    rss     │ heapTotal │ heapUsed  │ external  │ arrayBuffers │
    ├─────────┼────────────┼───────────┼───────────┼───────────┼──────────────┤
    │  start  │ '26.78 MB' │ '5.86 MB' │ '5.22 MB' │ '0.35 MB' │  '0.05 MB'   │
    │ warm-up │ '35.89 MB' │ '7.36 MB' │ '5.16 MB' │ '0.32 MB' │  '0.02 MB'   │
    │ finish  │ '35.90 MB' │ '7.36 MB' │ '5.55 MB' │ '0.32 MB' │  '0.02 MB'   │
    └─────────┴────────────┴───────────┴───────────┴───────────┴──────────────┘
    Warm-up: 733.6131200045347ms
    Test: 709.1680589914322ms

After:

    $ node lib/benchmark-static-lexer.js
    Read 5160 bytes
    ┌─────────┬────────────┬───────────┬───────────┬───────────┬──────────────┐
    │ (index) │    rss     │ heapTotal │ heapUsed  │ external  │ arrayBuffers │
    ├─────────┼────────────┼───────────┼───────────┼───────────┼──────────────┤
    │  start  │ '26.78 MB' │ '5.86 MB' │ '5.21 MB' │ '0.34 MB' │  '0.04 MB'   │
    │ warm-up │ '34.78 MB' │ '7.36 MB' │ '5.14 MB' │ '0.32 MB' │  '0.02 MB'   │
    │ finish  │ '34.79 MB' │ '7.36 MB' │ '5.50 MB' │ '0.32 MB' │  '0.02 MB'   │
    └─────────┴────────────┴───────────┴───────────┴───────────┴──────────────┘
    Warm-up: 667.0908890068531ms
    Test: 651.192603006959ms

Reference:

    $ node lib/benchmark-reference-lexer.js
    Read 5160 bytes
    ┌─────────┬────────────┬────────────┬───────────┬───────────┬──────────────┐
    │ (index) │    rss     │ heapTotal  │ heapUsed  │ external  │ arrayBuffers │
    ├─────────┼────────────┼────────────┼───────────┼───────────┼──────────────┤
    │  start  │ '36.47 MB' │ '10.86 MB' │ '6.75 MB' │ '0.44 MB' │  '0.05 MB'   │
    │ warm-up │ '44.52 MB' │ '15.61 MB' │ '7.79 MB' │ '0.42 MB' │  '0.03 MB'   │
    │ finish  │ '52.53 MB' │ '23.61 MB' │ '9.75 MB' │ '0.42 MB' │  '0.03 MB'   │
    └─────────┴────────────┴────────────┴───────────┴───────────┴──────────────┘
    Warm-up: 716.122205004096ms
    Test: 678.240804001689ms

ie. we're finally beating the reference lexer, and this commit improves
perf by 8.1%.

To know why we might look at the optimization output:

    Before:

        $ node --trace-opt --trace-deopt-verbose lib/benchmark-static-lexer.js
        Read 5160 bytes
        [marking 0x176199d66181 <JSFunction next (sfi = 0x1761244d61e9)> for optimization to TURBOFAN, ConcurrencyMode::kConcurrent, reason: hot and stable]
        [compiling method 0x176199d66181 <JSFunction next (sfi = 0x1761244d61e9)> (target TURBOFAN) using TurboFan]
        [marking 0x176199d65fc1 <JSFunction Token (sfi = 0x1761244d8891)> for optimization to TURBOFAN, ConcurrencyMode::kConcurrent, reason: small function]
        [compiling method 0x176199d65fc1 <JSFunction Token (sfi = 0x1761244d8891)> (target TURBOFAN) using TurboFan]
        [optimizing 0x1761c8e84279 <JSFunction Token (sfi = 0x1761244d8891)> (target TURBOFAN) - took 0.013, 1.708, 0.024 ms]
        [completed optimizing 0x1761c8e84279 <JSFunction Token (sfi = 0x1761244d8891)> (target TURBOFAN)]
        [marking 0x1761c8e82b09 <JSFunction lex (sfi = 0x1761244d60f9)> for optimization to TURBOFAN, ConcurrencyMode::kConcurrent, reason: hot and stable]
        [compiling method 0x1761c8e82b09 <JSFunction lex (sfi = 0x1761244d60f9)> (target TURBOFAN) using TurboFan]
        [optimizing 0x1761c8e82b09 <JSFunction lex (sfi = 0x1761244d60f9)> (target TURBOFAN) - took 0.006, 1.804, 0.038 ms]
        [completed optimizing 0x1761c8e82b09 <JSFunction lex (sfi = 0x1761244d60f9)> (target TURBOFAN)]
        [marking 0x1761c8e84071 <JSFunction test (sfi = 0x1761244d9a79)> for optimization to TURBOFAN, ConcurrencyMode::kConcurrent, reason: hot and stable]
        [compiling method 0x1761b1504841 <JSFunction test (sfi = 0x1761244d9a79)> (target TURBOFAN) using TurboFan OSR]
        [optimizing 0x1761b1504841 <JSFunction test (sfi = 0x1761244d9a79)> (target TURBOFAN) - took 0.007, 1.708, 0.030 ms]
        [optimizing 0x1761b1504751 <JSFunction next (sfi = 0x1761244d61e9)> (target TURBOFAN) - took 0.031, 17.427, 0.061 ms]
        [completed optimizing 0x1761b1504751 <JSFunction next (sfi = 0x1761244d61e9)> (target TURBOFAN)]
        [marking 0x1761b1504841 <JSFunction test (sfi = 0x1761244d9a79)> for optimization to TURBOFAN, ConcurrencyMode::kConcurrent, reason: hot and stable]
        [found optimized code for 0x1761b1504841 <JSFunction test (sfi = 0x1761244d9a79)> (target TURBOFAN) at OSR bytecode offset 139]

    After:

        $ node --trace-opt --trace-deopt-verbose lib/benchmark-static-lexer.js
        Read 5160 bytes
        [marking 0x3e0f76ca5489 <JSFunction next (sfi = 0x3e0fd2616241)> for optimization to TURBOFAN, ConcurrencyMode::kConcurrent, reason: hot and stable]
        [compiling method 0x3e0f76ca5489 <JSFunction next (sfi = 0x3e0fd2616241)> (target TURBOFAN) using TurboFan]
        [marking 0x3e0f76ca5451 <JSFunction emit (sfi = 0x3e0fd26161f1)> for optimization to TURBOFAN, ConcurrencyMode::kConcurrent, reason: small function]
        [compiling method 0x3e0f76ca5451 <JSFunction emit (sfi = 0x3e0fd26161f1)> (target TURBOFAN) using TurboFan]
        [optimizing 0x3e0f76ca5451 <JSFunction emit (sfi = 0x3e0fd26161f1)> (target TURBOFAN) - took 0.012, 1.221, 0.042 ms]
        [completed optimizing 0x3e0f76ca5451 <JSFunction emit (sfi = 0x3e0fd26161f1)> (target TURBOFAN)]
        [marking 0x3e0f74043ff1 <JSFunction lex (sfi = 0x3e0fd2616101)> for optimization to TURBOFAN, ConcurrencyMode::kConcurrent, reason: hot and stable]
        [compiling method 0x3e0f74043ff1 <JSFunction lex (sfi = 0x3e0fd2616101)> (target TURBOFAN) using TurboFan]
        [optimizing 0x3e0f74043ff1 <JSFunction lex (sfi = 0x3e0fd2616101)> (target TURBOFAN) - took 0.006, 1.335, 0.024 ms]
        [completed optimizing 0x3e0f74043ff1 <JSFunction lex (sfi = 0x3e0fd2616101)> (target TURBOFAN)]
        [marking 0x3e0f740440a9 <JSFunction test (sfi = 0x3e0fd26199a9)> for optimization to TURBOFAN, ConcurrencyMode::kConcurrent, reason: hot and stable]
        [compiling method 0x3e0f83dc3f29 <JSFunction test (sfi = 0x3e0fd26199a9)> (target TURBOFAN) using TurboFan OSR]
        [optimizing 0x3e0f83dc3f29 <JSFunction test (sfi = 0x3e0fd26199a9)> (target TURBOFAN) - took 0.006, 1.951, 0.054 ms]
        [optimizing 0x3e0f83dc3e39 <JSFunction next (sfi = 0x3e0fd2616241)> (target TURBOFAN) - took 0.033, 14.472, 0.064 ms]
        [completed optimizing 0x3e0f83dc3e39 <JSFunction next (sfi = 0x3e0fd2616241)> (target TURBOFAN)]
        [marking 0x3e0f83dc3f29 <JSFunction test (sfi = 0x3e0fd26199a9)> for optimization to TURBOFAN, ConcurrencyMode::kConcurrent, reason: hot and stable]
        [found optimized code for 0x3e0f83dc3f29 <JSFunction test (sfi = 0x3e0fd26199a9)> (target TURBOFAN) at OSR bytecode offset 139]

What's happening in there?

- Both start by compiling `next()` ("hot and stable").
- The old code then compiles `Token()` ("small function") and optimizes
  it.
- In contrast new code compiles `emit()` ("small function") and
  optimizes it.
- It never looks at `Token()` (presumably that gets inlined).
- Both then compile `lex()` ("hot and stable").
- Both the optimize `lex()`.
- Old code compiles `test()`, optimizes `test()`, optimizes `next()`.
- Old code finished by optimizing `test()`.

Caveat: this is happening over a single run and letting either of these
run with higher `DEFAULT_ITERATIONS` might allow more optimizations to
eventually occur.

Evidently, the value of optimizing `emit()` way outweighs that of
optimizing `Token()`. We could look at JITed code to get a better idea
of what's going on here if we had the time.

We can also run `yarn profile:static:lexer` to compare where time is
being spent, although to be honest, the output is too verbose and I
can't see any smoking guns in here:

    Before:

        $ node --trace-warnings --prof --no-logfile-per-isolate lib/benchmark-static-lexer.js && node --prof-process v8.log
        Read 5160 bytes
        ┌─────────┬────────────┬───────────┬───────────┬───────────┬──────────────┐
        │ (index) │    rss     │ heapTotal │ heapUsed  │ external  │ arrayBuffers │
        ├─────────┼────────────┼───────────┼───────────┼───────────┼──────────────┤
        │  start  │ '28.06 MB' │ '6.11 MB' │ '5.46 MB' │ '0.35 MB' │  '0.05 MB'   │
        │ warm-up │ '36.94 MB' │ '7.61 MB' │ '5.44 MB' │ '0.32 MB' │  '0.02 MB'   │
        │ finish  │ '36.95 MB' │ '7.61 MB' │ '5.89 MB' │ '0.32 MB' │  '0.02 MB'   │
        └─────────┴────────────┴───────────┴───────────┴───────────┴──────────────┘
        Warm-up: 36.8138709962368ms
        Test: 7.950203999876976ms
        (node:75930) ExperimentalWarning: VM Modules is an experimental feature. This feature could change at any time
        (Use `node --trace-warnings ...` to show where the warning was created)
        Statistical profiling result from v8.log, (169 ticks, 4 unaccounted, 0 excluded).

         [Shared libraries]:
           ticks  total  nonlib   name
             25   14.8%          /usr/lib/system/libsystem_pthread.dylib
             16    9.5%          /usr/lib/system/libsystem_c.dylib
              7    4.1%          /usr/lib/libc++.1.dylib
              6    3.6%          /usr/lib/system/libsystem_kernel.dylib
              4    2.4%          /usr/lib/system/libsystem_platform.dylib

         [JavaScript]:
           ticks  total  nonlib   name
              8    4.7%    7.2%  LazyCompile: *next /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:21:9
              4    2.4%    3.6%  Function: ^next /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:21:9
              2    1.2%    1.8%  LazyCompile: *lex /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:629:14

         [C++]:
           ticks  total  nonlib   name
             40   23.7%   36.0%  T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
             31   18.3%   27.9%  T node::native_module::NativeModuleEnv::CompileFunction(v8::FunctionCallbackInfo<v8::Value> const&)
             11    6.5%    9.9%  T _host_request_notification
              2    1.2%    1.8%  t std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> > std::__1::__pad_and_output<char, std::__1::char_traits<char> >(std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> >, char const*, char const*, char const*, std::__1::ios_base&, char)
              2    1.2%    1.8%  t std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::__put_character_sequence<char, std::__1::char_traits<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, char const*, unsigned long)
              2    1.2%    1.8%  T node::contextify::ContextifyContext::CompileFunction(v8::FunctionCallbackInfo<v8::Value> const&)
              1    0.6%    0.9%  t node::fs::ReadLink(v8::FunctionCallbackInfo<v8::Value> const&)
              1    0.6%    0.9%  t node::fs::Open(v8::FunctionCallbackInfo<v8::Value> const&)
              1    0.6%    0.9%  T node::binding::GetInternalBinding(v8::FunctionCallbackInfo<v8::Value> const&)
              1    0.6%    0.9%  T _shm_open
              1    0.6%    0.9%  T _mach_msg_destroy

         [Summary]:
           ticks  total  nonlib   name
             14    8.3%   12.6%  JavaScript
             93   55.0%   83.8%  C++
              3    1.8%    2.7%  GC
             58   34.3%          Shared libraries
              4    2.4%          Unaccounted

         [C++ entry points]:
           ticks    cpp   total   name
            123  100.0%   72.8%  T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)

         [Bottom up (heavy) profile]:
          Note: percentage shows a share of a particular caller in the total
          amount of its parent calls.
          Callers occupying less than 1.0% are not shown.

           ticks parent  name
             40   23.7%  T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
             19   47.5%    T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              2   10.5%      LazyCompile: ~WriteStream node:tty:84:21
              2  100.0%        LazyCompile: ~createWritableStdioStream node:internal/bootstrap/switches/is_main_thread:41:35
              2  100.0%          LazyCompile: ~getStdout node:internal/bootstrap/switches/is_main_thread:136:19
              2  100.0%            LazyCompile: ~get node:internal/console/constructor:203:14
              2   10.5%      Function: ^test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              2  100.0%        LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              2  100.0%          T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1    5.3%      LazyCompile: ~value node:internal/console/constructor:223:20
              1  100.0%        LazyCompile: ~initializeGlobalConsole node:internal/console/constructor:672:33
              1  100.0%          LazyCompile: ~patchProcessObject node:internal/bootstrap/pre_execution:102:28
              1  100.0%            LazyCompile: ~prepareMainThreadExecution node:internal/bootstrap/pre_execution:30:36
              1    5.3%      LazyCompile: ~strEscape node:internal/util/inspect:475:19
              1  100.0%        LazyCompile: ~formatPrimitive node:internal/util/inspect:1519:25
              1  100.0%          LazyCompile: ~formatValue node:internal/util/inspect:745:21
              1  100.0%            LazyCompile: ~inspect node:internal/util/inspect:292:17
              1    5.3%      LazyCompile: ~setupFetch node:internal/bootstrap/pre_execution:176:20
              1  100.0%        LazyCompile: ~prepareMainThreadExecution node:internal/bootstrap/pre_execution:30:36
              1  100.0%          Function: ~<anonymous> node:internal/main/run_main_module:1:1
              1    5.3%      LazyCompile: ~realpathSync node:fs:2439:22
              1  100.0%        LazyCompile: ~toRealPath node:internal/modules/cjs/loader:394:20
              1  100.0%          LazyCompile: ~Module._findPath node:internal/modules/cjs/loader:495:28
              1  100.0%            LazyCompile: ~resolveMainPath node:internal/modules/run_main:15:25
              1    5.3%      LazyCompile: ~prepareMainThreadExecution node:internal/bootstrap/pre_execution:30:36
              1  100.0%        Function: ~<anonymous> node:internal/main/run_main_module:1:1
              1    5.3%      LazyCompile: ~lex /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:629:14
              1  100.0%        T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1  100.0%          LazyCompile: ~test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              1  100.0%            LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              1    5.3%      LazyCompile: ~initializeGlobalConsole node:internal/console/constructor:672:33
              1  100.0%        LazyCompile: ~patchProcessObject node:internal/bootstrap/pre_execution:102:28
              1  100.0%          LazyCompile: ~prepareMainThreadExecution node:internal/bootstrap/pre_execution:30:36
              1  100.0%            Function: ~<anonymous> node:internal/main/run_main_module:1:1
              1    5.3%      LazyCompile: ~get /Users/wincent/code/masochist-experimental/packages/lexer/lib/index.js:8:77
              1  100.0%        Function: ~<anonymous> /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-static-lexer.js:1:1
              1  100.0%          LazyCompile: ~Module._compile node:internal/modules/cjs/loader:1059:37
              1  100.0%            LazyCompile: ~Module._extensions..js node:internal/modules/cjs/loader:1114:37
              1    5.3%      LazyCompile: ~compileFunction node:vm:308:25
              1  100.0%        LazyCompile: ~wrapSafe node:internal/modules/cjs/loader:1017:18
              1  100.0%          LazyCompile: ~Module._compile node:internal/modules/cjs/loader:1059:37
              1  100.0%            LazyCompile: ~Module._extensions..js node:internal/modules/cjs/loader:1114:37
              1    5.3%      LazyCompile: ~compileForInternalLoader node:internal/bootstrap/loaders:315:27
              1  100.0%        Function: ^nativeModuleRequire node:internal/bootstrap/loaders:348:29
              1  100.0%          Function: ~<anonymous> node:internal/modules/esm/get_format:1:1
              1  100.0%            LazyCompile: ~compileForInternalLoader node:internal/bootstrap/loaders:315:27
              1    5.3%      LazyCompile: ~afterWriteDispatched node:internal/stream_base_commons:155:30
              1  100.0%        LazyCompile: ~writeGeneric node:internal/stream_base_commons:147:22
              1  100.0%          LazyCompile: ~Socket._writeGeneric node:net:797:42
              1  100.0%            LazyCompile: ~Socket._write node:net:834:35
              1    5.3%      LazyCompile: ~EventEmitterMixin node:internal/event_target:958:27
              1  100.0%        Function: ~<anonymous> node:internal/fs/promises:1:1
              1  100.0%          LazyCompile: ~compileForInternalLoader node:internal/bootstrap/loaders:315:27
              1  100.0%            Function: ^nativeModuleRequire node:internal/bootstrap/loaders:348:29
              1    5.3%      Function: ~<anonymous> node:internal/modules/cjs/loader:1:1
              1  100.0%        LazyCompile: ~compileForInternalLoader node:internal/bootstrap/loaders:315:27
              1  100.0%          Function: ^nativeModuleRequire node:internal/bootstrap/loaders:348:29
              1  100.0%            LazyCompile: ~initializeCJSLoader node:internal/bootstrap/pre_execution:514:29
              1    5.3%      Function: ~<anonymous> node:internal/fs/rimraf:1:1
              1  100.0%        LazyCompile: ~compileForInternalLoader node:internal/bootstrap/loaders:315:27
              1  100.0%          Function: ^nativeModuleRequire node:internal/bootstrap/loaders:348:29
              1  100.0%            Function: ~<anonymous> node:internal/fs/promises:1:1
              1    5.3%      Function: ~<anonymous> /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:1:1
              1  100.0%        LazyCompile: ~Module._compile node:internal/modules/cjs/loader:1059:37
              1  100.0%          LazyCompile: ~Module._extensions..js node:internal/modules/cjs/loader:1114:37
              1  100.0%            LazyCompile: ~Module.load node:internal/modules/cjs/loader:969:33
              2    5.0%    LazyCompile: *lex /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:629:14
              2  100.0%      T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1   50.0%        LazyCompile: *test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              1  100.0%          LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              1  100.0%            T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1   50.0%        Function: ^test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              1  100.0%          LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              1  100.0%            T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              2    5.0%    Function: ^next /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:21:9
              2  100.0%      LazyCompile: ~lex /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:629:14
              2  100.0%        T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              2  100.0%          LazyCompile: ~test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              2  100.0%            LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              2    5.0%    Function: ^lex /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:629:14
              2  100.0%      T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              2  100.0%        Function: ^test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              2  100.0%          LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              2  100.0%            T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1    2.5%    LazyCompile: ~test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              1  100.0%      LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              1  100.0%        T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1    2.5%    LazyCompile: ~nextTick node:internal/process/task_queues:103:18
              1  100.0%      LazyCompile: ~onwrite node:internal/streams/writable:426:17
              1  100.0%        LazyCompile: ~afterWriteDispatched node:internal/stream_base_commons:155:30
              1  100.0%          LazyCompile: ~writeGeneric node:internal/stream_base_commons:147:22
              1  100.0%            LazyCompile: ~Socket._writeGeneric node:net:797:42
              1    2.5%    LazyCompile: ~lex /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:629:14
              1  100.0%      T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1  100.0%        LazyCompile: ~test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              1  100.0%          LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              1  100.0%            T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1    2.5%    LazyCompile: *next /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:21:9
              1  100.0%      LazyCompile: *lex /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:629:14
              1  100.0%        T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1  100.0%          LazyCompile: *test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              1  100.0%            LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              1    2.5%    Function: ^Token /Users/wincent/code/masochist-experimental/packages/lexer/lib/Token.js:4:16
              1  100.0%      Function: ^next /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:21:9
              1  100.0%        LazyCompile: ~lex /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:629:14
              1  100.0%          T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1  100.0%            LazyCompile: ~test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14

             31   18.3%  T node::native_module::NativeModuleEnv::CompileFunction(v8::FunctionCallbackInfo<v8::Value> const&)
             31  100.0%    T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
             28   90.3%      LazyCompile: ~compileForInternalLoader node:internal/bootstrap/loaders:315:27
             25   89.3%        Function: ^nativeModuleRequire node:internal/bootstrap/loaders:348:29
              5   20.0%          Function: ~<anonymous> node:internal/modules/esm/fetch_module:1:1
              5  100.0%            LazyCompile: ~compileForInternalLoader node:internal/bootstrap/loaders:315:27
              4   16.0%          LazyCompile: ~initializeCJSLoader node:internal/bootstrap/pre_execution:514:29
              4  100.0%            LazyCompile: ~prepareMainThreadExecution node:internal/bootstrap/pre_execution:30:36
              4   16.0%          Function: ~<anonymous> node:internal/modules/esm/loader:1:1
              4  100.0%            LazyCompile: ~compileForInternalLoader node:internal/bootstrap/loaders:315:27
              3   12.0%          Function: ~<anonymous> node:internal/process/esm_loader:1:1
              3  100.0%            LazyCompile: ~compileForInternalLoader node:internal/bootstrap/loaders:315:27
              3   12.0%          Function: ~<anonymous> node:internal/modules/esm/get_source:1:1
              3  100.0%            LazyCompile: ~compileForInternalLoader node:internal/bootstrap/loaders:315:27
              1    4.0%          LazyCompile: ~initializeSourceMapsHandlers node:internal/bootstrap/pre_execution:553:38
              1  100.0%            LazyCompile: ~prepareMainThreadExecution node:internal/bootstrap/pre_execution:30:36
              1    4.0%          Function: ~<anonymous> node:internal/source_map/source_map_cache:1:1
              1  100.0%            LazyCompile: ~compileForInternalLoader node:internal/bootstrap/loaders:315:27
              1    4.0%          Function: ~<anonymous> node:internal/modules/esm/resolve:1:1
              1  100.0%            LazyCompile: ~compileForInternalLoader node:internal/bootstrap/loaders:315:27
              1    4.0%          Function: ~<anonymous> node:internal/modules/esm/module_map:1:1
              1  100.0%            LazyCompile: ~compileForInternalLoader node:internal/bootstrap/loaders:315:27
              1    4.0%          Function: ~<anonymous> node:internal/fs/promises:1:1
              1  100.0%            LazyCompile: ~compileForInternalLoader node:internal/bootstrap/loaders:315:27
              1    4.0%          Function: ~<anonymous> node:internal/blocklist:1:1
              1  100.0%            LazyCompile: ~compileForInternalLoader node:internal/bootstrap/loaders:315:27
              3   10.7%        LazyCompile: ~nativeModuleRequire node:internal/bootstrap/loaders:348:29
              2   66.7%          Function: ~<anonymous> node:internal/main/run_main_module:1:1
              1   33.3%          LazyCompile: ~setupInspectorHooks node:internal/bootstrap/pre_execution:325:29
              1  100.0%            LazyCompile: ~prepareMainThreadExecution node:internal/bootstrap/pre_execution:30:36
              3    9.7%      Function: ^compileForInternalLoader node:internal/bootstrap/loaders:315:27
              3  100.0%        Function: ^nativeModuleRequire node:internal/bootstrap/loaders:348:29
              1   33.3%          LazyCompile: ~table node:internal/console/constructor:482:8
              1  100.0%            T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1   33.3%          LazyCompile: ~lazyLoadStreams node:fs:2872:25
              1  100.0%            LazyCompile: ~get ReadStream node:fs:3015:17
              1   33.3%          Function: ~<anonymous> node:tty:1:1
              1  100.0%            Function: ^compileForInternalLoader node:internal/bootstrap/loaders:315:27

             25   14.8%  /usr/lib/system/libsystem_pthread.dylib
             23   92.0%    T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              4   17.4%      LazyCompile: ~toRealPath node:internal/modules/cjs/loader:394:20
              4  100.0%        LazyCompile: ~Module._findPath node:internal/modules/cjs/loader:495:28
              4  100.0%          LazyCompile: ~resolveMainPath node:internal/modules/run_main:15:25
              4  100.0%            LazyCompile: ~executeUserEntryPoint node:internal/modules/run_main:70:31
              3   13.0%      LazyCompile: ~patchProcessObject node:internal/bootstrap/pre_execution:102:28
              3  100.0%        LazyCompile: ~prepareMainThreadExecution node:internal/bootstrap/pre_execution:30:36
              3  100.0%          Function: ~<anonymous> node:internal/main/run_main_module:1:1
              2    8.7%      LazyCompile: ~realpathSync node:fs:2439:22
              2  100.0%        LazyCompile: ~toRealPath node:internal/modules/cjs/loader:394:20
              2  100.0%          LazyCompile: ~Module._findPath node:internal/modules/cjs/loader:495:28
              2  100.0%            LazyCompile: ~resolveMainPath node:internal/modules/run_main:15:25
              2    8.7%      Function: ~<anonymous> node:internal/fs/promises:1:1
              2  100.0%        LazyCompile: ~compileForInternalLoader node:internal/bootstrap/loaders:315:27
              2  100.0%          Function: ^nativeModuleRequire node:internal/bootstrap/loaders:348:29
              2  100.0%            Function: ~<anonymous> node:internal/modules/esm/get_source:1:1
              1    4.3%      LazyCompile: ~setImmediate node:timers:278:22
              1  100.0%        LazyCompile: ~queuePending node:internal/perf/observe:104:22
              1  100.0%          LazyCompile: ~<anonymous> node:internal/perf/observe:298:17
              1  100.0%            LazyCompile: ~enqueue node:internal/perf/observe:329:17
              1    4.3%      LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              1  100.0%        T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1    4.3%      LazyCompile: ~readFileSync node:fs:455:22
              1  100.0%        LazyCompile: ~Module._extensions..js node:internal/modules/cjs/loader:1114:37
              1  100.0%          LazyCompile: ~Module.load node:internal/modules/cjs/loader:969:33
              1  100.0%            LazyCompile: ~Module._load node:internal/modules/cjs/loader:759:24
              1    4.3%      LazyCompile: ~queuePending node:internal/perf/observe:104:22
              1  100.0%        LazyCompile: ~<anonymous> node:internal/perf/observe:298:17
              1  100.0%          LazyCompile: ~enqueue node:internal/perf/observe:329:17
              1  100.0%            LazyCompile: ~measure node:internal/perf/usertiming:151:17
              1    4.3%      LazyCompile: ~processTicksAndRejections node:internal/process/task_queues:67:35
              1    4.3%      LazyCompile: ~prepareMainThreadExecution node:internal/bootstrap/pre_execution:30:36
              1  100.0%        Function: ~<anonymous> node:internal/main/run_main_module:1:1
              1    4.3%      LazyCompile: ~next /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:21:9
              1  100.0%        LazyCompile: ~lex /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:629:14
              1  100.0%          T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1  100.0%            LazyCompile: ~test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              1    4.3%      LazyCompile: ~get node:internal/console/constructor:203:14
              1  100.0%        LazyCompile: ~value node:internal/console/constructor:321:20
              1  100.0%          LazyCompile: ~log node:internal/console/constructor:359:6
              1  100.0%            T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1    4.3%      LazyCompile: ~createWritableStdioStream node:internal/bootstrap/switches/is_main_thread:41:35
              1  100.0%        LazyCompile: ~getStdout node:internal/bootstrap/switches/is_main_thread:136:19
              1  100.0%          LazyCompile: ~get node:internal/console/constructor:203:14
              1  100.0%            LazyCompile: ~value node:internal/console/constructor:321:20
              1    4.3%      LazyCompile: ~Socket node:net:291:16
              1  100.0%        LazyCompile: ~WriteStream node:tty:84:21
              1  100.0%          LazyCompile: ~createWritableStdioStream node:internal/bootstrap/switches/is_main_thread:41:35
              1  100.0%            LazyCompile: ~getStdout node:internal/bootstrap/switches/is_main_thread:136:19
              1    4.3%      LazyCompile: ~Module._load node:internal/modules/cjs/loader:759:24
              1  100.0%        LazyCompile: ~executeUserEntryPoint node:internal/modules/run_main:70:31
              1  100.0%          Function: ~<anonymous> node:internal/main/run_main_module:1:1
              1    4.3%      LazyCompile: *test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              1  100.0%        LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              1  100.0%          T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)

             16    9.5%  /usr/lib/system/libsystem_c.dylib
             15   93.8%    T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              2   13.3%      LazyCompile: ~value node:internal/console/constructor:321:20
              2  100.0%        LazyCompile: ~log node:internal/console/constructor:359:6
              2  100.0%          T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              2  100.0%            LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              2   13.3%      LazyCompile: ~realpathSync node:fs:2439:22
              2  100.0%        LazyCompile: ~toRealPath node:internal/modules/cjs/loader:394:20
              2  100.0%          LazyCompile: ~Module._findPath node:internal/modules/cjs/loader:495:28
              2  100.0%            LazyCompile: ~resolveMainPath node:internal/modules/run_main:15:25
              2   13.3%      LazyCompile: ~prepareMainThreadExecution node:internal/bootstrap/pre_execution:30:36
              2  100.0%        Function: ~<anonymous> node:internal/main/run_main_module:1:1
              1    6.7%      LazyCompile: ~wrapSafe node:internal/modules/cjs/loader:1017:18
              1  100.0%        LazyCompile: ~Module._compile node:internal/modules/cjs/loader:1059:37
              1  100.0%          LazyCompile: ~Module._extensions..js node:internal/modules/cjs/loader:1114:37
              1  100.0%            LazyCompile: ~Module.load node:internal/modules/cjs/loader:969:33
              1    6.7%      LazyCompile: ~syncExports node:internal/bootstrap/loaders:303:14
              1  100.0%        LazyCompile: ~<anonymous> node:internal/bootstrap/loaders:289:15
              1  100.0%          T node::loader::ModuleWrap::Evaluate(v8::FunctionCallbackInfo<v8::Value> const&)
              1  100.0%            LazyCompile: ~getESMFacade node:internal/bootstrap/loaders:280:15
              1    6.7%      LazyCompile: ~patchProcessObject node:internal/bootstrap/pre_execution:102:28
              1  100.0%        LazyCompile: ~prepareMainThreadExecution node:internal/bootstrap/pre_execution:30:36
              1  100.0%          Function: ~<anonymous> node:internal/main/run_main_module:1:1
              1    6.7%      LazyCompile: ~nextTick node:internal/process/task_queues:103:18
              1  100.0%        LazyCompile: ~onwrite node:internal/streams/writable:426:17
              1  100.0%          LazyCompile: ~afterWriteDispatched node:internal/stream_base_commons:155:30
              1  100.0%            LazyCompile: ~writeGeneric node:internal/stream_base_commons:147:22
              1    6.7%      LazyCompile: ~_write node:internal/streams/writable:284:16
              1  100.0%        LazyCompile: ~Writable.write node:internal/streams/writable:334:36
              1  100.0%          LazyCompile: ~value node:internal/console/constructor:258:20
              1  100.0%            LazyCompile: ~log node:internal/console/constructor:359:6
              1    6.7%      LazyCompile: ~Module._load node:internal/modules/cjs/loader:759:24
              1  100.0%        LazyCompile: ~executeUserEntryPoint node:internal/modules/run_main:70:31
              1  100.0%          Function: ~<anonymous> node:internal/main/run_main_module:1:1
              1    6.7%      LazyCompile: ~Duplex node:internal/streams/duplex:54:16
              1  100.0%        LazyCompile: ~Socket node:net:291:16
              1  100.0%          LazyCompile: ~WriteStream node:tty:84:21
              1  100.0%            LazyCompile: ~createWritableStdioStream node:internal/bootstrap/switches/is_main_thread:41:35
              1    6.7%      LazyCompile: ~<anonymous> node:path:1082:10
              1  100.0%        LazyCompile: ~resolve node:path:1091:10
              1  100.0%          LazyCompile: ~patchProcessObject node:internal/bootstrap/pre_execution:102:28
              1  100.0%            LazyCompile: ~prepareMainThreadExecution node:internal/bootstrap/pre_execution:30:36
              1    6.7%      LazyCompile: *test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              1  100.0%        LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              1  100.0%          T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)

             11    6.5%  T _host_request_notification
              4   36.4%    T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1   25.0%      T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1  100.0%        LazyCompile: ~table node:internal/cli_table:55:15
              1  100.0%          LazyCompile: ~final node:internal/console/constructor:490:19
              1  100.0%            LazyCompile: ~table node:internal/console/constructor:482:8
              1   25.0%      LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              1  100.0%        T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1   25.0%      LazyCompile: ~executeUserEntryPoint node:internal/modules/run_main:70:31
              1  100.0%        Function: ~<anonymous> node:internal/main/run_main_module:1:1
              1   25.0%      LazyCompile: ~afterWriteTick node:internal/streams/writable:483:24
              1  100.0%        LazyCompile: ~processTicksAndRejections node:internal/process/task_queues:67:35

              8    4.7%  LazyCompile: *next /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:21:9
              8  100.0%    LazyCompile: *lex /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:629:14
              8  100.0%      T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              7   87.5%        LazyCompile: *test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              7  100.0%          LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              7  100.0%            T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1   12.5%        Function: ^test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              1  100.0%          LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              1  100.0%            T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)

              7    4.1%  /usr/lib/libc++.1.dylib
              3   42.9%    T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1   33.3%      LazyCompile: ~createWritableStdioStream node:internal/bootstrap/switches/is_main_thread:41:35
              1  100.0%        LazyCompile: ~getStdout node:internal/bootstrap/switches/is_main_thread:136:19
              1  100.0%          LazyCompile: ~get node:internal/console/constructor:203:14
              1  100.0%            LazyCompile: ~value node:internal/console/constructor:321:20
              1   33.3%      LazyCompile: ~Readable node:internal/streams/readable:186:18
              1  100.0%        LazyCompile: ~Duplex node:internal/streams/duplex:54:16
              1  100.0%          LazyCompile: ~Socket node:net:291:16
              1  100.0%            LazyCompile: ~WriteStream node:tty:84:21
              1   33.3%      LazyCompile: *test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              1  100.0%        LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              1  100.0%          T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)

              6    3.6%  /usr/lib/system/libsystem_kernel.dylib
              5   83.3%    T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              2   40.0%      LazyCompile: ~setupWarningHandler node:internal/bootstrap/pre_execution:165:29
              2  100.0%        LazyCompile: ~prepareMainThreadExecution node:internal/bootstrap/pre_execution:30:36
              2  100.0%          Function: ~<anonymous> node:internal/main/run_main_module:1:1
              1   20.0%      LazyCompile: ~nextTick node:internal/process/task_queues:103:18
              1  100.0%        LazyCompile: ~onwrite node:internal/streams/writable:426:17
              1  100.0%          LazyCompile: ~afterWriteDispatched node:internal/stream_base_commons:155:30
              1  100.0%            LazyCompile: ~writeGeneric node:internal/stream_base_commons:147:22
              1   20.0%      LazyCompile: *test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              1  100.0%        LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              1  100.0%          T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1   20.0%      Function: ~<anonymous> node:internal/main/run_main_module:1:1

              4    2.4%  UNKNOWN
              4  100.0%    T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              2   50.0%      LazyCompile: ~value node:internal/console/constructor:321:20
              2  100.0%        LazyCompile: ~log node:internal/console/constructor:359:6
              2  100.0%          T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              2  100.0%            LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              1   25.0%      LazyCompile: *test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              1  100.0%        LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              1  100.0%          T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1   25.0%      Function: ~<anonymous> node:internal/fs/rimraf:1:1
              1  100.0%        LazyCompile: ~compileForInternalLoader node:internal/bootstrap/loaders:315:27
              1  100.0%          Function: ^nativeModuleRequire node:internal/bootstrap/loaders:348:29
              1  100.0%            Function: ~<anonymous> node:internal/fs/promises:1:1

              4    2.4%  Function: ^next /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:21:9
              4  100.0%    LazyCompile: *lex /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:629:14
              4  100.0%      T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              4  100.0%        Function: ^test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              4  100.0%          LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              4  100.0%            T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)

              4    2.4%  /usr/lib/system/libsystem_platform.dylib
              3   75.0%    T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1   33.3%      LazyCompile: ~value node:internal/console/constructor:321:20
              1  100.0%        LazyCompile: ~log node:internal/console/constructor:359:6
              1  100.0%          T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1  100.0%            LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              1   33.3%      LazyCompile: ~openSync node:fs:581:18
              1  100.0%        LazyCompile: ~readFileSync node:fs:455:22
              1  100.0%          LazyCompile: ~Module._extensions..js node:internal/modules/cjs/loader:1114:37
              1  100.0%            LazyCompile: ~Module.load node:internal/modules/cjs/loader:969:33
              1   33.3%      LazyCompile: ~lex /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:629:14
              1  100.0%        T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1  100.0%          LazyCompile: ~test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              1  100.0%            LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19

              2    1.2%  t std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> > std::__1::__pad_and_output<char, std::__1::char_traits<char> >(std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> >, char const*, char const*, char const*, std::__1::ios_base&, char)
              2  100.0%    T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1   50.0%      LazyCompile: ~toRealPath node:internal/modules/cjs/loader:394:20
              1  100.0%        LazyCompile: ~Module._findPath node:internal/modules/cjs/loader:495:28
              1  100.0%          LazyCompile: ~resolveMainPath node:internal/modules/run_main:15:25
              1  100.0%            LazyCompile: ~executeUserEntryPoint node:internal/modules/run_main:70:31
              1   50.0%      LazyCompile: ~setupFetch node:internal/bootstrap/pre_execution:176:20
              1  100.0%        LazyCompile: ~prepareMainThreadExecution node:internal/bootstrap/pre_execution:30:36
              1  100.0%          Function: ~<anonymous> node:internal/main/run_main_module:1:1

              2    1.2%  t std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::__put_character_sequence<char, std::__1::char_traits<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, char const*, unsigned long)
              2  100.0%    T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1   50.0%      LazyCompile: ~patchProcessObject node:internal/bootstrap/pre_execution:102:28
              1  100.0%        LazyCompile: ~prepareMainThreadExecution node:internal/bootstrap/pre_execution:30:36
              1  100.0%          Function: ~<anonymous> node:internal/main/run_main_module:1:1
              1   50.0%      LazyCompile: ~createWritableStdioStream node:internal/bootstrap/switches/is_main_thread:41:35
              1  100.0%        LazyCompile: ~getStdout node:internal/bootstrap/switches/is_main_thread:136:19
              1  100.0%          LazyCompile: ~get node:internal/console/constructor:203:14
              1  100.0%            LazyCompile: ~value node:internal/console/constructor:321:20

              2    1.2%  T node::contextify::ContextifyContext::CompileFunction(v8::FunctionCallbackInfo<v8::Value> const&)
              2  100.0%    T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              2  100.0%      LazyCompile: ~compileFunction node:vm:308:25
              2  100.0%        LazyCompile: ~wrapSafe node:internal/modules/cjs/loader:1017:18
              2  100.0%          LazyCompile: ~Module._compile node:internal/modules/cjs/loader:1059:37
              2  100.0%            LazyCompile: ~Module._extensions..js node:internal/modules/cjs/loader:1114:37

              2    1.2%  LazyCompile: *lex /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:629:14
              2  100.0%    T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              2  100.0%      LazyCompile: *test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              2  100.0%        LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              2  100.0%          T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)

    After:

        $ node --trace-warnings --prof --no-logfile-per-isolate lib/benchmark-static-lexer.js && node --prof-process v8.log
        Read 5160 bytes
        ┌─────────┬────────────┬───────────┬───────────┬───────────┬──────────────┐
        │ (index) │    rss     │ heapTotal │ heapUsed  │ external  │ arrayBuffers │
        ├─────────┼────────────┼───────────┼───────────┼───────────┼──────────────┤
        │  start  │ '28.13 MB' │ '6.11 MB' │ '5.46 MB' │ '0.34 MB' │  '0.04 MB'   │
        │ warm-up │ '36.66 MB' │ '7.61 MB' │ '5.43 MB' │ '0.32 MB' │  '0.02 MB'   │
        │ finish  │ '36.66 MB' │ '7.61 MB' │ '5.87 MB' │ '0.32 MB' │  '0.02 MB'   │
        └─────────┴────────────┴───────────┴───────────┴───────────┴──────────────┘
        Warm-up: 32.25229199230671ms
        Test: 6.697618007659912ms
        (node:76184) ExperimentalWarning: VM Modules is an experimental feature. This feature could change at any time
        (Use `node --trace-warnings ...` to show where the warning was created)
        Statistical profiling result from v8.log, (166 ticks, 0 unaccounted, 0 excluded).

         [Shared libraries]:
           ticks  total  nonlib   name
             24   14.5%          /usr/lib/system/libsystem_pthread.dylib
             13    7.8%          /usr/lib/system/libsystem_c.dylib
              9    5.4%          /usr/lib/libc++.1.dylib
              3    1.8%          /usr/lib/system/libsystem_malloc.dylib
              3    1.8%          /usr/lib/system/libsystem_kernel.dylib
              2    1.2%          /usr/lib/system/libsystem_platform.dylib

         [JavaScript]:
           ticks  total  nonlib   name
              6    3.6%    5.4%  LazyCompile: *next /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:35:9
              4    2.4%    3.6%  Function: ^next /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:35:9
              2    1.2%    1.8%  LazyCompile: *emit /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:29:9
              1    0.6%    0.9%  LazyCompile: *test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14

         [C++]:
           ticks  total  nonlib   name
             46   27.7%   41.1%  T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
             28   16.9%   25.0%  T node::native_module::NativeModuleEnv::CompileFunction(v8::FunctionCallbackInfo<v8::Value> const&)
             16    9.6%   14.3%  T _host_request_notification
              3    1.8%    2.7%  T node::contextify::ContextifyContext::CompileFunction(v8::FunctionCallbackInfo<v8::Value> const&)
              2    1.2%    1.8%  t std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::__put_character_sequence<char, std::__1::char_traits<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, char const*, unsigned long)
              2    1.2%    1.8%  T _shm_open
              1    0.6%    0.9%  t node::fs::LStat(v8::FunctionCallbackInfo<v8::Value> const&)
              1    0.6%    0.9%  T _mach_msg_destroy

         [Summary]:
           ticks  total  nonlib   name
             13    7.8%   11.6%  JavaScript
             99   59.6%   88.4%  C++
              5    3.0%    4.5%  GC
             54   32.5%          Shared libraries

         [C++ entry points]:
           ticks    cpp   total   name
            118  100.0%   71.1%  T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)

         [Bottom up (heavy) profile]:
          Note: percentage shows a share of a particular caller in the total
          amount of its parent calls.
          Callers occupying less than 1.0% are not shown.

           ticks parent  name
             46   27.7%  T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
             23   50.0%    T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              2    8.7%      LazyCompile: ~WriteStream node:tty:84:21
              2  100.0%        LazyCompile: ~createWritableStdioStream node:internal/bootstrap/switches/is_main_thread:41:35
              2  100.0%          LazyCompile: ~getStdout node:internal/bootstrap/switches/is_main_thread:136:19
              2  100.0%            LazyCompile: ~get node:internal/console/constructor:203:14
              1    4.3%      T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1  100.0%        Function: ^next /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:35:9
              1  100.0%          LazyCompile: *lex /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:583:14
              1  100.0%            T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1    4.3%      LazyCompile: ~wrapSafe node:internal/modules/cjs/loader:1017:18
              1  100.0%        LazyCompile: ~Module._compile node:internal/modules/cjs/loader:1059:37
              1  100.0%          LazyCompile: ~Module._extensions..js node:internal/modules/cjs/loader:1114:37
              1  100.0%            LazyCompile: ~Module.load node:internal/modules/cjs/loader:969:33
              1    4.3%      LazyCompile: ~test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              1  100.0%        LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              1  100.0%          T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1    4.3%      LazyCompile: ~setImmediate node:timers:278:22
              1  100.0%        LazyCompile: ~queuePending node:internal/perf/observe:104:22
              1  100.0%          LazyCompile: ~<anonymous> node:internal/perf/observe:298:17
              1  100.0%            LazyCompile: ~enqueue node:internal/perf/observe:329:17
              1    4.3%      LazyCompile: ~readFileAfterStat node:fs:331:27
              1    4.3%      LazyCompile: ~promisify node:internal/util:324:19
              1  100.0%        Function: ~<anonymous> node:internal/fs/promises:1:1
              1  100.0%          LazyCompile: ~compileForInternalLoader node:internal/bootstrap/loaders:315:27
              1  100.0%            Function: ^nativeModuleRequire node:internal/bootstrap/loaders:348:29
              1    4.3%      LazyCompile: ~prepareMainThreadExecution node:internal/bootstrap/pre_execution:30:36
              1  100.0%        Function: ~<anonymous> node:internal/main/run_main_module:1:1
              1    4.3%      LazyCompile: ~patchProcessObject node:internal/bootstrap/pre_execution:102:28
              1  100.0%        LazyCompile: ~prepareMainThreadExecution node:internal/bootstrap/pre_execution:30:36
              1  100.0%          Function: ~<anonymous> node:internal/main/run_main_module:1:1
              1    4.3%      LazyCompile: ~mark node:internal/perf/usertiming:94:14
              1  100.0%        LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              1  100.0%          T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1    4.3%      LazyCompile: ~initializeCJSLoader node:internal/bootstrap/pre_execution:514:29
              1  100.0%        LazyCompile: ~prepareMainThreadExecution node:internal/bootstrap/pre_execution:30:36
              1  100.0%          Function: ~<anonymous> node:internal/main/run_main_module:1:1
              1    4.3%      LazyCompile: ~getOptionValue node:internal/options:44:24
              1  100.0%        LazyCompile: ~setupWarningHandler node:internal/bootstrap/pre_execution:165:29
              1  100.0%          LazyCompile: ~prepareMainThreadExecution node:internal/bootstrap/pre_execution:30:36
              1  100.0%            Function: ~<anonymous> node:internal/main/run_main_module:1:1
              1    4.3%      LazyCompile: ~getCLIOptionsFromBinding node:internal/options:18:34
              1  100.0%        LazyCompile: ~getOptionValue node:internal/options:44:24
              1  100.0%          LazyCompile: ~patchProcessObject node:internal/bootstrap/pre_execution:102:28
              1  100.0%            LazyCompile: ~prepareMainThreadExecution node:internal/bootstrap/pre_execution:30:36
              1    4.3%      LazyCompile: ~formatWithOptions node:internal/util/inspect:2024:27
              1  100.0%        LazyCompile: ~value node:internal/console/constructor:321:20
              1  100.0%          LazyCompile: ~log node:internal/console/constructor:359:6
              1  100.0%            T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1    4.3%      LazyCompile: ~formatPrimitive node:internal/util/inspect:1519:25
              1  100.0%        LazyCompile: ~formatValue node:internal/util/inspect:745:21
              1  100.0%          LazyCompile: ~inspect node:internal/util/inspect:292:17
              1  100.0%            LazyCompile: ~_inspect node:internal/console/constructor:492:22
              1    4.3%      LazyCompile: ~createWritableStdioStream node:internal/bootstrap/switches/is_main_thread:41:35
              1  100.0%        LazyCompile: ~getStdout node:internal/bootstrap/switches/is_main_thread:136:19
              1  100.0%          LazyCompile: ~get node:internal/console/constructor:203:14
              1  100.0%            LazyCompile: ~value node:internal/console/constructor:321:20
              1    4.3%      LazyCompile: ~compileForInternalLoader node:internal/bootstrap/loaders:315:27
              1  100.0%        LazyCompile: ~nativeModuleRequire node:internal/bootstrap/loaders:348:29
              1  100.0%          Function: ~<anonymous> node:internal/main/run_main_module:1:1
              1    4.3%      LazyCompile: ~Socket node:net:291:16
              1  100.0%        LazyCompile: ~WriteStream node:tty:84:21
              1  100.0%          LazyCompile: ~createWritableStdioStream node:internal/bootstrap/switches/is_main_thread:41:35
              1  100.0%            LazyCompile: ~getStdout node:internal/bootstrap/switches/is_main_thread:136:19
              1    4.3%      LazyCompile: ~Readable.removeListener node:internal/streams/readable:916:45
              1  100.0%        LazyCompile: ~value node:internal/console/constructor:258:20
              1  100.0%          LazyCompile: ~log node:internal/console/constructor:359:6
              1  100.0%            T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1    4.3%      LazyCompile: ~Module._load node:internal/modules/cjs/loader:759:24
              1  100.0%        LazyCompile: ~executeUserEntryPoint node:internal/modules/run_main:70:31
              1  100.0%          Function: ~<anonymous> node:internal/main/run_main_module:1:1
              1    4.3%      LazyCompile: ~<instance_members_initializer> node:internal/perf/observe:199:1
              1  100.0%        LazyCompile: ~PerformanceObserver node:internal/perf/observe:205:14
              1  100.0%          LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              1  100.0%            T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1    4.3%      Function: ^test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              1  100.0%        LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              1  100.0%          T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              2    4.3%    LazyCompile: ~lex /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:583:14
              2  100.0%      T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              2  100.0%        LazyCompile: ~test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              2  100.0%          LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              2  100.0%            T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              2    4.3%    LazyCompile: *lex /Users/wincent/code/masochist-experimental/packages/lexer/lib/lex.js:583:14
              2  100.0%      T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              2  100.0%        Function: ^test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              2  100.0%          LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              2  100.0%            T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1    2.2%    LazyCompile: ~getCLIOptionsFromBinding node:internal/options:18:34
              1  100.0%      Function: ^getOptionValue node:internal/options:44:24
              1  100.0%        Function: ~<anonymous> node:internal/modules/esm/resolve:1:1
              1  100.0%          LazyCompile: ~compileForInternalLoader node:internal/bootstrap/loaders:315:27
              1  100.0%            Function: ^nativeModuleRequire node:internal/bootstrap/loaders:348:29
              1    2.2%    LazyCompile: ~get node:internal/console/constructor:203:14
              1  100.0%      LazyCompile: ~value node:internal/console/constructor:321:20
              1  100.0%        LazyCompile: ~log node:internal/console/constructor:359:6
              1  100.0%          T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1  100.0%            LazyCompile: ~<anonymous> /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:45:54
              1    2.2%    Function: ^test /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:32:14
              1  100.0%      LazyCompile: ~run /Users/wincent/code/masochist-experimental/packages/benchmark/lib/benchmark-lexer.js:39:19
              1  100.0%        T node::options_parser::GetCLIOptions(v8::FunctionCallbackInfo<v8::Value> const&)
              1    2.2%    Function: ^resolve node:path:1091:10
              1  100.0%      LazyCompile: ~realpathSync node:fs:2439:22
              1  100.0%        LazyCompile: ~toRealPath node:internal/modules/cjs/loader:394:20
              1  100.0%          LazyCompi…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Domain: JavaScript The issue relates to JavaScript specifically Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests