blob: fea766f28b78f7460c8c9625efd8bfc38141de54 [file] [log] [blame] [edit]
/**
* @license
* Copyright 2010 The Emscripten Authors
* SPDX-License-Identifier: MIT
*/
// "use strict";
// General JS utilities - things that might be useful in any JS project.
// Nothing specific to Emscripten appears here.
function safeQuote(x) {
return x.replace(/"/g, '\\"').replace(/'/g, "\\'");
}
function dump(item) {
let funcData;
try {
if (typeof item == 'object' && item != null && item.funcData) {
funcData = item.funcData;
item.funcData = null;
}
return '// ' + JSON.stringify(item, null, ' ').replace(/\n/g, '\n// ');
} catch (e) {
const ret = [];
for (const i in item) {
if (Object.prototype.hasOwnProperty.call(item, i)) {
const j = item[i];
if (typeof j == 'string' || typeof j == 'number') {
ret.push(i + ': ' + j);
} else {
ret.push(i + ': [?]');
}
}
}
return ret.join(',\n');
} finally {
if (funcData) item.funcData = funcData;
}
}
global.warnings = false;
global.currentFile = null;
function errorPrefix() {
if (currentFile) {
return currentFile + ': '
} else {
return '';
}
}
function warn(a, msg) {
global.warnings = true;
if (!msg) {
msg = a;
a = false;
}
if (!a) {
printErr(`warning: ${errorPrefix()}${msg}`);
}
}
function warnOnce(a, msg) {
if (!msg) {
msg = a;
a = false;
}
if (!a) {
if (!warnOnce.msgs) warnOnce.msgs = {};
if (msg in warnOnce.msgs) return;
warnOnce.msgs[msg] = true;
warn(msg);
}
}
global.abortExecution = false;
function error(msg) {
abortExecution = true;
printErr(`error: ${errorPrefix()}${msg}`);
}
function range(size) {
return Array.from(Array(size).keys());
}
function bind(self, func) {
return function(...args) {
func.apply(self, args);
};
}
function sum(x) {
return x.reduce((a, b) => a + b, 0);
}
// options is optional input object containing mergeInto params
// currently, it can contain
//
// key: noOverride, value: true
// if it is set, it prevents symbol redefinition and shows error
// in case of redefinition
//
// key: checkSig, value: true
// if it is set, __sig is checked for functions and error is reported
// if <function name>__sig is missing
function mergeInto(obj, other, options = null) {
if (options) {
// check for unintended symbol redefinition
if (options.noOverride) {
for (const key of Object.keys(other)) {
if (obj.hasOwnProperty(key)) {
error(`Symbol re-definition in JavaScript library: ${key}. Do not use noOverride if this is intended`);
return;
}
}
}
// check if sig is missing for added functions
if (options.checkSig) {
for (const [key, value] of Object.entries(other)) {
if (typeof value === 'function' && !other.hasOwnProperty(key + '__sig')) {
error(`__sig is missing for function: ${key}. Do not use checkSig if this is intended`);
return;
}
}
}
}
if (!options || !options.allowMissing) {
for (const ident of Object.keys(other)) {
if (isJsLibraryConfigIdentifier(ident)) {
const index = ident.lastIndexOf('__');
const basename = ident.slice(0, index);
if (!(basename in obj) && !(basename in other)) {
error(`Missing library element '${basename}' for library config '${ident}'`);
}
}
}
}
for (const key of Object.keys(other)) {
if (key.endsWith('__sig')) {
if (obj.hasOwnProperty(key)) {
const oldsig = obj[key];
const newsig = other[key];
if (oldsig == newsig) {
warn(`signature redefinition for: ${key}`);
} else {
error(`signature redefinition for: ${key}. (old=${oldsig} vs new=${newsig})`);
}
}
}
if (key.endsWith('__deps')) {
const deps = other[key];
if (!Array.isArray(deps)) {
error(`JS library directive ${key}=${deps.toString()} is of type ${typeof deps}, but it should be an array`);
}
}
}
return Object.assign(obj, other);
}
function isNumber(x) {
// XXX this does not handle 0xabc123 etc. We should likely also do x == parseInt(x) (which handles that), and remove hack |// handle 0x... as well|
return x == parseFloat(x) || (typeof x == 'string' && x.match(/^-?\d+$/)) || x == 'NaN';
}
function isJsLibraryConfigIdentifier(ident) {
suffixes = [
'__sig',
'__proxy',
'__asm',
'__inline',
'__deps',
'__postset',
'__docs',
'__nothrow',
'__noleakcheck',
'__internal',
'__user',
'__async',
];
return suffixes.some((suffix) => ident.endsWith(suffix));
}
function isPowerOfTwo(x) {
return x > 0 && ((x & (x - 1)) == 0);
}
/** @constructor */
function Benchmarker() {
const totals = {};
const ids = [];
const lastTime = 0;
this.start = function(id) {
const now = Date.now();
if (ids.length > 0) {
totals[ids[ids.length - 1]] += now - lastTime;
}
lastTime = now;
ids.push(id);
totals[id] = totals[id] || 0;
};
this.stop = function(id) {
const now = Date.now();
assert(id === ids[ids.length - 1]);
totals[id] += now - lastTime;
lastTime = now;
ids.pop();
};
this.print = function(text) {
const ids = Object.keys(totals);
if (ids.length > 0) {
ids.sort((a, b) => totals[b] - totals[a]);
printErr(text + ' times: \n' + ids.map((id) => id + ' : ' + totals[id] + ' ms').join('\n'));
}
};
}