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

inspector: --inspect-brk for ES6 modules #17360

Closed
wants to merge 1 commit into from
Closed

inspector: --inspect-brk for ES6 modules #17360

wants to merge 1 commit into from

Conversation

eugeneo
Copy link
Contributor

@eugeneo eugeneo commented Nov 27, 2017

Fixes: #17340

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines
Affected core subsystem(s)

ES6 module loader, test: added a hook to break on module init and a test

@nodejs-github-bot nodejs-github-bot added the module Issues and PRs related to the module subsystem. label Nov 27, 2017
@eugeneo eugeneo added inspector Issues and PRs related to the V8 inspector protocol test Issues and PRs related to the tests. labels Nov 27, 2017
@bmeck
Copy link
Member

bmeck commented Nov 28, 2017

Should this be during eval instead of instantiate?

@eugeneo
Copy link
Contributor Author

eugeneo commented Nov 28, 2017

I did not dig deep, only did manual test. What I saw was that breaking during eval will actually break later then desired - e.g. for this example (console.log) it will actually break in the getter for the console. Variable declarations will also be skipped. Breaking during initialize worked as expected.

@guybedford
Copy link
Contributor

Nice to see this.

@eugeneo it may be worth trying some alternative wrapper functions as instantiate does sound fairly arbitrary as it does no module execution. Would job.run() at https://github.com/nodejs/node/pull/17360/files#diff-e6f2798544dae1f6ec863621e745489aR141 work perhaps?

The other thing that seems non-ideal is having that extra propery from within the ModuleJob class, it would be nice to be able to attach something from outside that way like:

initWrapper(moduleJob.run, moduleJob)

Let me know if any of these adjustments might work.

@eugeneo
Copy link
Contributor Author

eugeneo commented Nov 28, 2017

The main problem is that the breakpoint set from the C++ code will be hit when next JS instruction is executed. This means that we need to call this immediately before the user code is invoked. Otherwise breakpoint will be hit in the Node.js JS code and confuse/scare the user :)

E.g., replacing process.binding('inspector').callAndPauseOnStart(this.module.instantiate, this.module) with process.binding('inspector').callAndPauseOnStart(() => this.module.instantiate(), null) results in a break in the arrow function, revealing gritty implementation details.

From V8 and inspector pov, there is no difference between framework code (e.j. ModuleJob#run) and user code. But DevTools really want to break in the user code.

@TimothyGu
Copy link
Member

@eugeneo Is there a way to blackbox the inspector scripts by default?

@eugeneo
Copy link
Contributor Author

eugeneo commented Nov 28, 2017

Is there a way to blackbox the inspector scripts by default?

Chrome does not use blackboxing in scenarios like this so it had been designed to be controlled by the front-end. Currently blackboxing is per-session and is only available through the inspector protocol. E.g. Node would have to intercept Debugger.enable call and insert a bunch of new messages into the message stream. It is doable, but it might be risky and prone to breakages and may have sideffects.

@guybedford
Copy link
Contributor

@eugeneo thanks for the clarification, I guess I'm just completely not understanding how instantiate could be working here then, because instantiate does not do any execution, apart from initializing bindings and function declarations.

@eugeneo
Copy link
Contributor Author

eugeneo commented Nov 28, 2017

One of the tests I did was this script:

const a = 1;
const b = a + 1;

export default function() {
	console.log(10);
}

Breaking on initialization correctly steps over initialization of the a and b, allowing to see values. It also allows setting a breakpoint in the default export function.

@bmeck
Copy link
Member

bmeck commented Nov 28, 2017

@eugeneo I think that might be because you were breaking on the top level instead of the deepest leaf. Since ESM evaluates in post order traversal, the deepest leaf evaluates first.

@eugeneo
Copy link
Contributor Author

eugeneo commented Nov 28, 2017

This break is supposed to break once before any code was executed. There should be no modules loaded but the main one.

@bmeck
Copy link
Member

bmeck commented Nov 28, 2017

@eugeneo compiled locally and played around, I think this timing is the most consistent to how CJS --inspect-brk works. LGTM

Copy link
Contributor

@cjihrig cjihrig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with some test nits.

const { NodeInstance } = require('../common/inspector-helper.js');

function checkListResponse(response) {
assert.strictEqual(1, response.length);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small nit: reverse the argument order here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, here and below.

'Browser': `node.js/${process.version}`,
'Protocol-Version': '1.1',
};
assert.strictEqual(JSON.stringify(response),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assert.deepStrictEqual() without the JSON.stringify()s?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


function checkBadPath(err) {
assert(err instanceof SyntaxError);
assert(/Unexpected token/.test(err.message), err.message);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error comes from the engine, not Node, right? If so, we shouldn't validate the message, as it could be different from V8 to Chakra.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a hardcoded string - but there's no reason to test this here, it is covered by the main inspector test. I removed it.

}

function assertNoUrlsWhileConnected(response) {
assert.strictEqual(1, response.length);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverse the argument order here please.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

unmatched.delete(actual['name']);
}
}
if (unmatched.size)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you write this as assert.strictEqual(unmatched.size, 0)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to comparison to an empty array.

const unmatched = new Set(Object.keys(expected));
for (const actual of result) {
const value = expected[actual['name']];
if (value) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this if necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. Removed.

}
});

assert.strictEqual(1002, result['value']);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll stop mentioning it, but could you switch the order of the arguments here and in other places so that it is actual then expected.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor

@guybedford guybedford left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great, and works perfectly!

It does worry me that instantiate ends up being the break point over module.execute though, that seems a v8 bug to me.

@TimothyGu TimothyGu added the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label Nov 29, 2017
@TimothyGu
Copy link
Member

@addaleax addaleax removed the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label Nov 30, 2017
@TimothyGu
Copy link
Member

@eugeneo
Copy link
Contributor Author

eugeneo commented Nov 30, 2017

Script URL format is different on different configurations. I will make the test more resilient, but it looks like there's an issue in the Node core.

@eugeneo
Copy link
Contributor Author

eugeneo commented Nov 30, 2017

@bcoe
Copy link
Contributor

bcoe commented Dec 3, 2017

@eugeneo this looks good, thanks for digging into this. I'm about to check out this branch and test whether the inspector stops in time for detailed coverage to be enabled in the inspector.


const _MAINSCRIPT = fixtures.path('loop.js');
const DEBUG = false;
const TIMEOUT = common.platformTimeout(15 * 1000);

function filePathToUrl(path) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use require('internal/url').getURLFromFilePath instead.

}

scriptURL() {
return new URL(this.scriptPath(), 'file:').toString();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

@TimothyGu
Copy link
Member

Windows CI is still unhappy. https://ci.nodejs.org/job/node-test-binary-windows/13277/

@guybedford
Copy link
Contributor

guybedford commented Jan 15, 2018

Just wondering what stalled here? Would be great to see this moving.

Btw @chrisdickinson has an interesting variation on this approach which may be a little bit more sensible, see 1d771f5#diff-46b46cfa0c77bff7ab6ed3fcb584e728R102.

@jpike88
Copy link

jpike88 commented Jan 16, 2018

It's probably worth someone closing related issues, it's not easy to navigate through the dupes of this one

@TimothyGu
Copy link
Member

@guybedford, @chrisdickinson's changes look good to me if you can file a separate PR, with the caveat that _breakFirstLine should be deleted right after the if clause.

@guybedford
Copy link
Contributor

@TimothyGu I tested out the approach and it seems to have the same problem as mentioned before of not exactly getting exactly the first line but instead getting loader internals. So this still remains the best approach it seems.

@guybedford guybedford added the esm Issues and PRs related to the ECMAScript Modules implementation. label Jan 16, 2018
guybedford added a commit to guybedford/node that referenced this pull request Jan 22, 2018
Reworked rebase of PR nodejs#17360 with feedback
guybedford added a commit that referenced this pull request Jan 22, 2018
Reworked rebase of PR #17360 with feedback

PR-URL: #18194
Fixes: #17340
Reviewed-By: Eugene Ostroukhov <eostroukhov@google.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
@guybedford
Copy link
Contributor

Landed through reworked PR in e7ff00d.

@guybedford guybedford closed this Jan 22, 2018
@jpike88
Copy link

jpike88 commented Jan 23, 2018

Awesome. Does anyone know when the next release will occur? I'm drooling over this one

MylesBorins pushed a commit that referenced this pull request Feb 20, 2018
Reworked rebase of PR #17360 with feedback

PR-URL: #18194
Fixes: #17340
Reviewed-By: Eugene Ostroukhov <eostroukhov@google.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
MylesBorins pushed a commit that referenced this pull request Feb 21, 2018
Reworked rebase of PR #17360 with feedback

PR-URL: #18194
Fixes: #17340
Reviewed-By: Eugene Ostroukhov <eostroukhov@google.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
MylesBorins pushed a commit that referenced this pull request Feb 21, 2018
Reworked rebase of PR #17360 with feedback

PR-URL: #18194
Fixes: #17340
Reviewed-By: Eugene Ostroukhov <eostroukhov@google.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
@eugeneo eugeneo deleted the 17340-esm-inspect-brk branch April 26, 2018 17:34
MayaLekova pushed a commit to MayaLekova/node that referenced this pull request May 8, 2018
Reworked rebase of PR nodejs#17360 with feedback

PR-URL: nodejs#18194
Fixes: nodejs#17340
Reviewed-By: Eugene Ostroukhov <eostroukhov@google.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
esm Issues and PRs related to the ECMAScript Modules implementation. inspector Issues and PRs related to the V8 inspector protocol module Issues and PRs related to the module subsystem. test Issues and PRs related to the tests. wip Issues and PRs that are still a work in progress.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

--inspect-brk does not work with ESM
9 participants