123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- const fs = require('fs');
- const TOTAL_STACK = 1024 * 1024; // 1MB
- const TOTAL_MEMORY = 2 * 1024 * 1024; // 1MB
- const WASM_PAGE_SIZE = 64 * 1024; // Defined in WebAssembly specs
- const WASM_CODE = Buffer.from(require('./cephes.wasm.base64.json'), 'base64');
- class CephesWrapper {
- constructor(sync) {
- // Initialize the runtime's memory
- this._wasmMemory = new WebAssembly.Memory({
- 'initial': TOTAL_MEMORY / WASM_PAGE_SIZE,
- 'maximum': TOTAL_MEMORY / WASM_PAGE_SIZE
- });
- this._HEAP8 = new Int8Array(this._wasmMemory.buffer);
- this._HEAP16 = new Int16Array(this._wasmMemory.buffer);
- this._HEAP32 = new Int32Array(this._wasmMemory.buffer);
- this._HEAPF32 = new Float32Array(this._wasmMemory.buffer);
- this._HEAPF64 = new Float64Array(this._wasmMemory.buffer);
- // Compile and export program
- if (sync) {
- // compile synchronously
- const program = this._compileSync();
- this._exportProgram(program);
- // create a dummy compile promise
- this.compiled = Promise.resolve();
- } else {
- // create a singleton compile promise
- this.compiled = this._compileAsync()
- .then((program) => this._exportProgram(program));
- }
- }
- _AsciiToString(ptr) {
- let str = '';
- while (1) {
- const ch = this._HEAP8[((ptr++)>>0)];
- if (ch === 0) return str;
- str += String.fromCharCode(ch);
- }
- }
- _mtherr(name /* char* */, code /* int */) {
- // from mtherr.c
- let codemsg = '';
- switch (code) {
- case 1: codemsg = 'argument domain error'; break;
- case 2: codemsg = 'function singularity'; break;
- case 3: codemsg = 'overflow range error'; break;
- case 4: codemsg = 'underflow range error'; break;
- case 5: codemsg = 'total loss of precision'; break;
- case 6: codemsg = 'partial loss of precision'; break;
- case 33: codemsg = 'Unix domain error code'; break;
- case 34: codemsg = 'Unix range error code'; break;
- default: codemsg = 'unknown error';
- }
- const fnname = this._AsciiToString(name);
- const message = 'cephes reports "' + codemsg + '" in ' + fnname;
- // Restore stack to the STACKTOP before throwing. This only works because
- // all the exported cephes functions are plain functions.
- this.stackRestore(0);
- if (code == 1) {
- throw new RangeError(message);
- } else {
- throw new Error(message);
- }
- }
- _wasmImports() {
- return {
- 'env': {
- // cephes error handler
- "_mtherr": this._mtherr.bind(this),
- // memory
- "memory": this._wasmMemory,
- "STACKTOP": 0,
- "STACK_MAX": TOTAL_STACK
- }
- };
- }
- _compileSync() {
- return new WebAssembly.Instance(
- new WebAssembly.Module(WASM_CODE),
- this._wasmImports()
- );
- }
- _compileAsync() {
- return WebAssembly.instantiate(
- WASM_CODE,
- this._wasmImports()
- ).then((results) => results.instance);
- }
- _exportProgram(program) {
- // export cephes functions
- for (const key of Object.keys(program.exports)) {
- if (key.startsWith('_cephes_')) {
- this[key] = program.exports[key];
- }
- }
- // export special stack functions
- this.stackAlloc = program.exports.stackAlloc;
- this.stackRestore = program.exports.stackRestore;
- this.stackSave = program.exports.stackSave;
- }
- // export helper functions
- getValue(ptr, type) {
- type = type || 'i8';
- if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
- switch(type) {
- case 'i1': return this._HEAP8[((ptr)>>0)];
- case 'i8': return this._HEAP8[((ptr)>>0)];
- case 'i16': return this._HEAP16[((ptr)>>1)];
- case 'i32': return this._HEAP32[((ptr)>>2)];
- case 'i64': return this._HEAP32[((ptr)>>2)];
- case 'float': return this._HEAPF32[((ptr)>>2)];
- case 'double': return this._HEAPF64[((ptr)>>3)];
- default: throw new Error('invalid type for getValue: ' + type);
- }
- return null;
- }
- writeArrayToMemory(array, buffer) {
- this._HEAP8.set(array, buffer);
- }
- }
- module.exports = CephesWrapper;
|