libxml2-wasm
Version:
WebAssembly-based libxml2 javascript wrapper
114 lines • 3.57 kB
JavaScript
const noopTracker = {
trackAllocate() {
},
trackDeallocate() {
},
report() {
},
};
function callstack(numSkip) {
const { stack } = new Error();
if (!stack)
return undefined;
let pos = 0;
// each line is one function call
// remove two extract lines, error message and call to this function
for (let i = numSkip + 2; i > 0; i -= 1) {
pos = stack.indexOf('\n', pos) + 1;
}
return stack.substring(pos);
}
class MemTrackerImpl {
constructor(callerDetail, callerStats) {
this.callerDetail = callerDetail;
this.callerStats = callerStats;
this.idCounter = 0;
this.disposableId = new WeakMap();
this.disposableInfo = new Map();
}
trackAllocate(obj) {
this.idCounter += 1;
this.disposableId.set(obj, this.idCounter);
const info = {
object: new WeakRef(obj),
classname: obj.constructor.name,
};
if (this.callerDetail || this.callerStats) {
info.callstack = callstack(2);
}
this.disposableInfo.set(this.idCounter, info);
}
trackDeallocate(obj) {
const id = this.disposableId.get(obj);
if (id) { // the object may be created before the diagnosis enabled
this.disposableInfo.delete(id);
this.disposableId.delete(obj);
}
}
report() {
const memReport = {};
this.disposableInfo.forEach((info) => {
// eslint-disable-next-line no-multi-assign
const classReport = memReport[info.classname] ||= {
garbageCollected: 0,
totalInstances: 0,
instances: [],
};
classReport.totalInstances += 1;
const obj = info.object.deref();
if (obj != null) {
const instanceInfo = { instance: obj };
if (this.callerDetail) {
instanceInfo.caller = info.callstack;
}
classReport.instances.push(instanceInfo);
}
else {
classReport.garbageCollected += 1;
}
if (this.callerStats) {
const callers = (classReport.callers ||= {}); // eslint-disable-line no-multi-assign
callers[info.callstack] = (callers[info.callstack] || 0) + 1;
}
});
return memReport;
}
}
/**
* Set up memory diagnostic helpers.
*
* When enabled,
* these helpers will record allocated {@link disposable.XmlDisposable} objects
* (and their subclass objects)
* and track whether the {@link disposable.XmlDisposable#dispose} method is called.
*
* Note that the allocation of these objects will not be monitored
* before memory diagnostics is enabled.
*
* @param options
* @see {@link report}
*/
export function configure(options) {
if (options.enabled) {
memTracker = new MemTrackerImpl(options.callerDetail === true, options.callerStats === true);
}
else {
memTracker = noopTracker;
}
}
/**
* Obtain the report containing information about un-disposed objects.
* @returns The report (in JSON format) whose format may vary according to the settings,
* and is subject to change.
* If memory diagnostic is not enabled, the report will be undefined.
* @see {@link configure}
*/
export function report() {
return memTracker.report();
}
let memTracker = noopTracker;
/** @internal */
export function tracker() {
return memTracker;
}
//# sourceMappingURL=diag.mjs.map