aboutsummaryrefslogtreecommitdiff
path: root/packages/bun-polyfills/src/modules/jsc.ts
blob: 45062d339300a9bcfc14d154c80e4d0674728b53 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import type jsc from 'bun:jsc';
import v8 from 'node:v8';
//import { setRandomSeed, getRandomSeed } from './mathrandom.js';
import { NotImplementedError, getCallSites } from '../utils/errors.js';
import { gc } from './bun.js';

const STUB = () => void 0;

function jscSerialize(value: any, options?: { binaryType: 'nodebuffer'; }): Buffer;
function jscSerialize(value: any, options?: { binaryType?: 'arraybuffer'; }): SharedArrayBuffer;
function jscSerialize(value: any, options?: { binaryType?: string }): Buffer | SharedArrayBuffer {
    const serialized = v8.serialize(value);
    if (options?.binaryType === 'nodebuffer') return serialized;
    else return new SharedArrayBuffer(serialized.byteLength);
}
// TODO: Investigate ways of making these the actual JSC serialization format (probably Bun WASM)
// TODO: whilst this works for common use-cases like Node <-> Node it still does not make it
// TODO: possible for Node <-> Bun transfers of this kind of data, which might be interesting to have.
export const serialize = jscSerialize satisfies typeof jsc.serialize;
export const deserialize = (value => {
    if (value instanceof ArrayBuffer || value instanceof SharedArrayBuffer) return v8.deserialize(Buffer.from(value));
    else return v8.deserialize(value);
}) satisfies typeof jsc.deserialize;

export const setTimeZone = ((timeZone: string) => {
    const resolvedTZ = Intl.DateTimeFormat(undefined, { timeZone }).resolvedOptions().timeZone;
    return process.env.TZ = resolvedTZ;
}) satisfies typeof jsc.setTimeZone;

export const callerSourceOrigin = (() => {
    const callsites: NodeJS.CallSite[] = getCallSites(2);
    // This may be inaccurate with async code. Needs more testing.
    let lastSeenURL = '';
    for (const callsite of callsites) {
        const sourceURL = callsite.getScriptNameOrSourceURL();
        if (sourceURL.startsWith('file://')) lastSeenURL = sourceURL;
    }
    return lastSeenURL;
}) satisfies typeof jsc.callerSourceOrigin;

// TODO: Like with jsc.serialize/deserialize, these may be possible with Bun WASM.
export const jscDescribe = (() => { throw new NotImplementedError('jsc.jscDescribe', STUB); }) satisfies typeof jsc.jscDescribe;
export const jscDescribeArray = (() => { throw new NotImplementedError('jsc.jscDescribeArray', STUB); }) satisfies typeof jsc.jscDescribeArray;
// These are no longer documented but still exist.
export const describe = jscDescribe;
export const describeArray = jscDescribeArray;

// Node.js only provides a singular non-configurable global GC function, so we have to make do with that.
export const edenGC = gc satisfies typeof jsc.edenGC;
export const fullGC = gc satisfies typeof jsc.fullGC;
export const gcAndSweep = gc satisfies typeof jsc.gcAndSweep;

export const drainMicrotasks = STUB satisfies typeof jsc.drainMicrotasks; // no-op
export const releaseWeakRefs = STUB satisfies typeof jsc.releaseWeakRefs; // no-op
export const startSamplingProfiler = STUB satisfies typeof jsc.startSamplingProfiler; // no-op
//! likely broken but needs more testing
export const startRemoteDebugger = STUB satisfies typeof jsc.startRemoteDebugger; // no-op

//! this is a really poor polyfill but it's better than nothing
export const getProtectedObjects = (() => { return [globalThis]; }) satisfies typeof jsc.getProtectedObjects;

export const getRandomSeed = 0; // TODO
export const setRandomSeed = 0; // TODO

export const heapSize = (() => { return v8.getHeapStatistics().used_heap_size; }) satisfies typeof jsc.heapSize;
export const heapStats = (() => {
    const stats = v8.getHeapStatistics();
    return {
        heapSize: stats.used_heap_size,
        heapCapacity: stats.total_available_size,
        extraMemorySize: stats.external_memory ?? 0,
        objectCount: 1, // TODO: how to get this in node?
        protectedObjectCount: getProtectedObjects().length,
        globalObjectCount: 2, // TODO: this one is probably fine hardcoded but is there a way to get this in node?
        protectedGlobalObjectCount: 1, // TODO: ^
        objectTypeCounts: {}, //! can't really throw an error here, so just return an empty object (TODO: how to get this in node?)
        protectedObjectTypeCounts: {} //! can't really throw an error here, so just return an empty object (TODO: how to get this in node?)
    };
}) satisfies typeof jsc.heapStats;

//! doubtful anyone relies on the return of this for anything besides debugging
export const isRope = (() => false) satisfies typeof jsc.isRope;

export const memoryUsage = (() => {
    const stats = v8.getHeapStatistics();
    const resUse = process.resourceUsage();
    return {
        current: stats.malloced_memory,
        peak: stats.peak_malloced_memory,
        currentCommit: stats.malloced_memory,
        peakCommit: stats.malloced_memory,
        pageFaults: resUse.minorPageFault + resUse.majorPageFault
    };
}) satisfies typeof jsc.memoryUsage;

//! these are likely broken, seemingly always returning undefined which does not match the documented return types
export const noFTL = (() => { return void 0 as unknown as Function; }) satisfies typeof jsc.noFTL;
export const noOSRExitFuzzing = (() => { return void 0 as unknown as Function; }) satisfies typeof jsc.noOSRExitFuzzing;
//! likely broken, seems to always returns zero
export const totalCompileTime = (() => 0) satisfies typeof jsc.totalCompileTime;
//! likely broken, seem to always returns 0 if any arguments are passed, undefined otherwise
export const numberOfDFGCompiles = ((...args) => args.length ? 0 : void 0 as unknown as number) satisfies typeof jsc.numberOfDFGCompiles;
export const reoptimizationRetryCount = ((...args) => args.length ? 0 : void 0 as unknown as number) satisfies typeof jsc.reoptimizationRetryCount;

//! The following are very likely impossible to ever polyfill.
export const profile = (() => {
    throw new NotImplementedError('jsc.profile is not polyfillable', STUB, true);
}) satisfies typeof jsc.profile;
export const optimizeNextInvocation = (() => {
    throw new NotImplementedError('jsc.optimizeNextInvocation is not polyfillable', STUB, true);
}) satisfies typeof jsc.optimizeNextInvocation;