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

src: implement v8 host weakref hooks #29874

Merged
merged 1 commit into from Oct 13, 2019
Merged

Conversation

devsnek
Copy link
Member

@devsnek devsnek commented Oct 7, 2019

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • commit message follows commit guidelines

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. tools Issues and PRs related to the tools directory. labels Oct 7, 2019
src/api/callback.cc Outdated Show resolved Hide resolved
src/api/environment.cc Outdated Show resolved Hide resolved
src/api/environment.cc Outdated Show resolved Hide resolved
@addaleax addaleax added v8 engine Issues and PRs related to the V8 dependency. and removed tools Issues and PRs related to the tools directory. labels Oct 7, 2019
@devsnek devsnek force-pushed the weakrefs branch 2 times, most recently from d6df190 to f4e1d29 Compare October 11, 2019 22:55
@nodejs-github-bot

This comment has been minimized.

@nodejs-github-bot

This comment has been minimized.

@nodejs-github-bot

This comment has been minimized.

@Trott

This comment has been minimized.

@nodejs-github-bot

This comment has been minimized.

@Trott

This comment has been minimized.

Copy link
Member

@bnoordhuis bnoordhuis 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 questions/suggestions.

src/env.cc Outdated Show resolved Hide resolved
src/env.cc Show resolved Hide resolved
src/env.cc Outdated Show resolved Hide resolved
@nodejs-github-bot
Copy link
Collaborator

PR-URL: nodejs#29874
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
@devsnek devsnek merged commit 545f728 into nodejs:master Oct 13, 2019
@devsnek devsnek deleted the weakrefs branch October 13, 2019 22:46
@addaleax
Copy link
Member

@devsnek This PR changed a bit since I reviewed … shouldn’t HostCleanupFinalizationGroupCallback register a task to run the finalization hooks? Is it okay that the remainder of the list is not processed if there’s an exception from it?

@devsnek
Copy link
Member Author

devsnek commented Oct 14, 2019

@addaleax all the behaviour is at least within the specification. we can definitely tune it more as people start using weakrefs.

@addaleax
Copy link
Member

@devsnek Yeah, but then again so is not running the finalization calllbacks at all, as I understand it 🙃 I’m happy to provide a PR myself, but that this doesn’t run callbacks scheduled from a regular GC (i.e. not global.gc();) seems like a bug in this to me.

@devsnek
Copy link
Member Author

devsnek commented Oct 14, 2019

@addaleax I'm not sure what change you're looking for exactly

@addaleax
Copy link
Member

@devsnek As I’ve said, HostCleanupFinalizationGroupCallback should schedule a task to run on the event loop to run the finalization hooks (as e.g. the browser would do for this).

@devsnek
Copy link
Member Author

devsnek commented Oct 14, 2019

@addaleax these should run at the end of the microtask (and technically nextTick) queue, as they currently do.

@mhofman
Copy link

mhofman commented Oct 14, 2019

@devsnek @addaleax, the behavior seems to be spec compliant and within the spirit of it.

From what I understand from the PR, if a cleanup callback throws, the rest of groups with pending finalization callbacks will simply be executed next tick. While that could cause delays, it's spec compliant and guarantees all callbacks are ultimately invoked.

I guess the only thing is the environment should avoid shutting down until all pending callbacks have been executed, if possible. I don't think anything prevents that right now.

Edit: I'll try to run my shim's test on the latest nightly.

@mhofman
Copy link

mhofman commented Oct 14, 2019

I got a crash running my shim's test in the latest nightly:

FATAL ERROR: v8::HandleScope::CreateHandle() Cannot create a handle without a HandleScope

https://github.com/mhofman/tc39-weakrefs-shim/tree/node12-experimental-weakrefs
run npm run test:node:esm:experimental

I managed to extract a reproduction. It's not simple and I'm not sure if a smaller repro is possible (I tried):

"use strict";

// Flags: --expose-gc --harmony-weak-refs

const common = require("../common");
const assert = require("assert");

const TRIGGER_CRASH = true;

function makeAsyncGc(gc, FinalizationGroup) {
    const finalizationGroup = new FinalizationGroup(holdings => {
        for (const holding of holdings) {
            holding.collected = true;
        }
    });

    return function asyncGc(target, trigger) {
        let checker = {};
        const checkerHolding = {
            collected: false,
        };
        const holding = target != null ? { collected: false } : checkerHolding;
        finalizationGroup.register(target || checker, holding, holding);
        finalizationGroup.register(checker, checkerHolding, checkerHolding);
        target = checker = undefined;
        return Promise.resolve(trigger)
            .then(() => {
                return gc();
            })
            .then(() => {
                try {
                    finalizationGroup.cleanupSome();
                    finalizationGroup.unregister(checkerHolding);
                    finalizationGroup.unregister(holding);
                } catch (err) {}
                if (!checkerHolding.collected) {
                    return Promise.reject(
                        new Error("Couldn't collect checker")
                    );
                }
                return holding.collected;
            });
    };
}

const asyncGc = makeAsyncGc(globalThis.gc, globalThis.FinalizationGroup);

let resolve;
const called = new Promise(r => {
    resolve = r;
});

let marker = {};

const fg = new globalThis.FinalizationGroup(
    common.mustCallAtLeast(i => {
        resolve();
    }, 1)
);

const collected = (function() {
    let obj = {};
    fg.register(obj, 42);
    const collected = asyncGc(obj);
    obj = undefined;
    return collected;
})();

collected
    .then(() => {
        globalThis.gc();
    })
    .then(() => called)
    .then(() => {
        if (!TRIGGER_CRASH) return;
        const collected = asyncGc(marker);
        marker = undefined;
        return collected;
    })
    .then(common.mustCall());

The crash seem to be a combination of resolving a promise in the callback and triggering a new gc() in the resolution chain of that promise.

@devsnek
Copy link
Member Author

devsnek commented Oct 14, 2019

@mhofman would you mind running lldb and seeing where the backtrace is from?

@mhofman
Copy link

mhofman commented Oct 15, 2019

I don't have much of a native dev environment setup. I basically got the nightly running by building a the alpine-node docker image pulling in the nightly source instead of dist.

Looks like lldb isn't available on alpine 3.9. I'll see what I can do, but it might be faster to run the test I provided. I made sure it could run as part of node's test suite.

@mhofman
Copy link

mhofman commented Oct 25, 2019

@devsnek, here is what I got running the test file above on the latest node 13.0.1:

node --expose-gc --harmony-weak-refs test/parallel/test-finalization-group-resolve.js 
FATAL ERROR: v8::HandleScope::CreateHandle() Cannot create a handle without a HandleScope
 1: 0x9e8320 node::Abort() [node]
 2: 0x9e9506 node::OnFatalError(char const*, char const*) [node]
 3: 0xb4310a v8::Utils::ReportApiFailure(char const*, char const*) [node]
 4: 0xcb86ba v8::internal::HandleScope::Extend(v8::internal::Isolate*) [node]
 5: 0xb448a1 v8::HandleScope::CreateHandle(v8::internal::Isolate*, unsigned long) [node]
 6: 0x98efac node::Environment::RunWeakRefCleanup() [node]
 7: 0x957c9a node::InternalCallbackScope::~InternalCallbackScope() [node]
 8: 0xa50d8e node::PerIsolatePlatformData::RunForegroundTask(std::unique_ptr<v8::Task, std::default_delete<v8::Task> >) [node]
 9: 0xa517e2 node::PerIsolatePlatformData::FlushForegroundTasksInternal() [node]
10: 0xa5352d node::NodePlatform::DrainTasks(v8::Isolate*) [node]
11: 0xa25acb node::NodeMainInstance::Run() [node]
12: 0x9b9ea1 node::Start(int, char**) [node]
13: 0x7cdcd7929b97 __libc_start_main [/lib/x86_64-linux-gnu/libc.so.6]
14: 0x956e65  [node]
Aborted (core dumped)
(lldb) bt
* thread #1, name = 'node', stop reason = signal SIGABRT
  * frame #0: 0x00007cdcd7946e97 libc.so.6`gsignal + 199
    frame #1: 0x00007cdcd7948801 libc.so.6`abort + 321
    frame #2: 0x00000000009e8331 node`node::Abort() + 33
    frame #3: 0x00000000009e9506 node`node::OnFatalError(char const*, char const*) + 166
    frame #4: 0x0000000000b4310a node`v8::Utils::ReportApiFailure(char const*, char const*) + 58
    frame #5: 0x0000000000cb86ba node`v8::internal::HandleScope::Extend(v8::internal::Isolate*) + 218
    frame #6: 0x0000000000b448a1 node`v8::HandleScope::CreateHandle(v8::internal::Isolate*, unsigned long) + 65
    frame #7: 0x000000000098efac node`node::Environment::RunWeakRefCleanup() + 140
    frame #8: 0x0000000000957c9a node`node::InternalCallbackScope::~InternalCallbackScope() + 538
    frame #9: 0x0000000000a50d8e node`node::PerIsolatePlatformData::RunForegroundTask(std::unique_ptr<v8::Task, std::default_delete<v8::Task> >) + 174
    frame #10: 0x0000000000a517e2 node`node::PerIsolatePlatformData::FlushForegroundTasksInternal() + 354
    frame #11: 0x0000000000a5352d node`node::NodePlatform::DrainTasks(v8::Isolate*) + 173
    frame #12: 0x0000000000a25acb node`node::NodeMainInstance::Run() + 827
    frame #13: 0x00000000009b9ea1 node`node::Start(int, char**) + 305
    frame #14: 0x00007cdcd7929b97 libc.so.6`__libc_start_main + 231
    frame #15: 0x0000000000956e65 node`_start + 41

Anything else I can provide ?

@devsnek
Copy link
Member Author

devsnek commented Oct 25, 2019

no that is enough, it seems that Environment::RunWeakRefCleanup is missing a HandleScope. I was considering rewriting this based on some feedback from anna anyway, so maybe it won't be a problem.

@mhofman
Copy link

mhofman commented Oct 25, 2019

If v8 7.8 does ends up backported to 12 LTS (#30109), it'd be great if this PR and fix could also be included.

@mhofman
Copy link

mhofman commented Oct 31, 2019

FYI, the pending integration changes for the chromium side can be found here: https://chromium-review.googlesource.com/c/chromium/src/+/1873754

@mhofman
Copy link

mhofman commented Oct 31, 2019

Also is there any chance #30130 might fix this issue too?

@devsnek
Copy link
Member Author

devsnek commented Oct 31, 2019

no that's unrelated

@targos
Copy link
Member

targos commented Nov 8, 2019

Should only land on v12.x if #30109 does.

MylesBorins pushed a commit that referenced this pull request Jan 8, 2020
PR-URL: #29874
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
BethGriggs pushed a commit that referenced this pull request Feb 6, 2020
PR-URL: #29874
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
@MylesBorins MylesBorins mentioned this pull request Feb 8, 2020
codebytere added a commit to electron/electron that referenced this pull request Feb 21, 2020
codebytere added a commit to electron/electron that referenced this pull request Feb 21, 2020
codebytere added a commit to electron/electron that referenced this pull request Feb 24, 2020
codebytere added a commit to electron/electron that referenced this pull request Feb 24, 2020
* chore: bump node in DEPS to v12.16.0

* Fixup asar support setup patch

nodejs/node#30862

* Fixup InternalCallbackScope patch

nodejs/node#30236

* Fixup GN buildfiles patch

nodejs/node#30755

* Fixup low-level hooks patch

nodejs/node#30466

* Fixup globals require patch

nodejs/node#31643

* Fixup process stream patch

nodejs/node#30862

* Fixup js2c modification patch

nodejs/node#30755

* Fixup internal fs override patch

nodejs/node#30610

* Fixup context-aware warn patch

nodejs/node#30336

* Fixup Node.js with ltcg config

nodejs/node#29388

* Fixup oaepLabel patch

nodejs/node#30917

* Remove redundant ESM test patch

nodejs/node#30997

* Remove redundant cli flag patch

nodejs/node#30466

* Update filenames.json

* Remove macro generation in GN build files

nodejs/node#30755

* Fix some compilation errors upstream

* Add uvwasi to deps

nodejs/node#30258

* Fix BoringSSL incompatibilities

* Fixup linked module patch

nodejs/node#30274

* Add missing sources to GN uv build

libuv/libuv#2347

* Patch some uvwasi incompatibilities

* chore: bump Node.js to v12.6.1

* Remove mark_arraybuffer_as_untransferable.patch

nodejs/node#30549

* Fix uvwasi build failure on win

* Fixup --perf-prof cli option error

* Fixup early cjs module loading

* fix: initialize diagnostics properly

nodejs/node#30025

* Disable new esm syntax specs

nodejs/node#30219

* Fixup v8 weakref hook spec

nodejs/node#29874

* Fix async context timer issue

* Disable monkey-patch-main spec

It relies on nodejs/node#29777, and we don't
override prepareStackTrace.

* Disable new tls specs

nodejs/node#23188

We don't support much of TLS owing to schisms between BoringSSL and
OpenSSL.

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ Issues and PRs that require attention from people who are familiar with C++. v8 engine Issues and PRs related to the V8 dependency.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants