Compare commits

...

3 Commits

Author SHA1 Message Date
Alistair Smith
91d026dd06 experiment: remap to ISDIR ?? 2025-07-03 13:31:39 -07:00
Alistair Smith
c62eafad9b Merge branch 'main' of github.com:oven-sh/bun into test-heapdump 2025-07-03 12:20:57 -07:00
Alistair Smith
74050fb154 v8 + test-heapdump.js 2025-07-02 14:26:49 -07:00
3 changed files with 125 additions and 6 deletions

View File

@@ -4,7 +4,7 @@
const { hideFromStack, throwNotImplemented } = require("internal/shared");
const jsc: typeof import("bun:jsc") = require("bun:jsc");
function notimpl(message) {
function notimpl(message: string) {
throwNotImplemented("node:v8 " + message);
}
@@ -29,8 +29,15 @@ class GCProfiler {
function cachedDataVersionTag() {
notimpl("cachedDataVersionTag");
}
var HeapSnapshotReadable_;
function getHeapSnapshot() {
var HeapSnapshotReadable_: typeof import("node:stream").Readable;
function getHeapSnapshot(_options?: import("node:v8").HeapSnapshotOptions) {
if (_options !== undefined) {
if (typeof _options !== "object" || _options === null || $isArray(_options)) {
throw $ERR_INVALID_ARG_TYPE("options", "object", _options);
}
}
if (!HeapSnapshotReadable_) {
const Readable = require("node:stream").Readable;
class HeapSnapshotReadable extends Readable {
@@ -40,6 +47,7 @@ function getHeapSnapshot() {
this.push(null);
}
}
HeapSnapshotReadable_ = HeapSnapshotReadable;
}
@@ -124,12 +132,18 @@ function getDefaultHeapSnapshotPath() {
return `Heap-${yyyy}${mm}${dd}-${hh}${MM}${ss}-${process.pid}-${thread_id}.heapsnapshot`;
}
let fs;
let fs: typeof import("./fs").default;
function writeHeapSnapshot(path?: string, _options?: import("node:v8").HeapSnapshotOptions) {
if (_options !== undefined) {
if (typeof _options !== "object" || _options === null || $isArray(_options)) {
throw $ERR_INVALID_ARG_TYPE("options", "object", _options);
}
}
function writeHeapSnapshot(path, _options) {
if (path !== undefined) {
if (typeof path !== "string") {
throw $ERR_INVALID_ARG_TYPE("path", "string", path);
throw $ERR_INVALID_ARG_TYPE("path", "string or an instance of Buffer or URL", path);
}
if (!path) {
@@ -142,6 +156,7 @@ function writeHeapSnapshot(path, _options) {
if (!fs) {
fs = require("node:fs");
}
fs.writeFileSync(path, Bun.generateHeapSnapshot("v8"), "utf-8");
return path;

View File

@@ -1466,6 +1466,19 @@ pub fn openFileAtWindowsNtPath(
},
else => |code| {
if (code.toSystemErrno()) |sys_err| {
if ((code == .ALREADY_EXISTS or code == .FILE_EXISTS) and
(options.access_mask & w.GENERIC_WRITE != 0 or options.access_mask & w.FILE_APPEND_DATA != 0))
{
if (directoryExistsAt(dir, path).asValue() orelse false) {
return .{
.err = .{
.errno = @intFromEnum(E.ISDIR),
.syscall = .open,
},
};
}
}
return .{
.err = .{
.errno = @intFromEnum(sys_err),

View File

@@ -0,0 +1,91 @@
'use strict';
const common = require('../common');
const { isMainThread } = require('worker_threads');
if (!isMainThread) {
common.skip('process.chdir is not available in Workers');
}
const { writeHeapSnapshot, getHeapSnapshot } = require('v8');
const assert = require('assert');
const fs = require('fs');
const { promises: { pipeline }, PassThrough } = require('stream');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
process.chdir(tmpdir.path);
{
writeHeapSnapshot('my.heapdump');
fs.accessSync('my.heapdump');
}
{
const heapdump = writeHeapSnapshot();
assert.strictEqual(typeof heapdump, 'string');
fs.accessSync(heapdump);
}
{
const directory = 'directory';
fs.mkdirSync(directory);
assert.throws(() => {
writeHeapSnapshot(directory);
}, (e) => {
assert.ok(e, 'writeHeapSnapshot should error');
assert.strictEqual(e.code, 'EISDIR');
assert.strictEqual(e.syscall, 'open');
return true;
});
}
[1, true, {}, [], null, Infinity, NaN].forEach((i) => {
assert.throws(() => writeHeapSnapshot(i), {
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "path" argument must be of type string or an instance of ' +
'Buffer or URL.' +
common.invalidArgTypeHelper(i)
});
});
[1, true, [], null, Infinity, NaN].forEach((i) => {
assert.throws(() => writeHeapSnapshot('test.heapsnapshot', i), {
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "options" argument must be of type object.' +
common.invalidArgTypeHelper(i)
});
});
[1, true, [], null, Infinity, NaN].forEach((i) => {
assert.throws(() => getHeapSnapshot(i), {
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "options" argument must be of type object.' +
common.invalidArgTypeHelper(i)
});
});
{
let data = '';
const snapshot = getHeapSnapshot();
snapshot.setEncoding('utf-8');
snapshot.on('data', common.mustCallAtLeast((chunk) => {
data += chunk.toString();
}));
snapshot.on('end', common.mustCall(() => {
JSON.parse(data);
}));
}
{
const passthrough = new PassThrough();
passthrough.on('data', common.mustCallAtLeast(1));
pipeline(
getHeapSnapshot(),
passthrough,
).then(common.mustCall());
}