-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathcephes-wrapper.js
117 lines (97 loc) · 3.11 KB
/
cephes-wrapper.js
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
112
113
114
115
116
117
const WASM_CODE = Buffer.from(require('./cephes.wasm.base64.json'), 'base64');
const {errorMappings} = require('./utils.js');
const TOTAL_STACK = 1024 * 1024; // 1MB
class CephesWrapper {
constructor(sync) {
// Compile and export program
if (sync) {
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
const codemsg = errorMappings[code] || 'unknown error';
const fnname = this._AsciiToString(name);
const message = 'cephes reports "' + codemsg + '" in ' + fnname;
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._emscripten_stack_alloc;
this.stackRestore = program.exports._emscripten_stack_restore;
this.stackSave = program.exports.emscripten_stack_get_current;
// export memory
this._wasmMemory = program.exports.memory;
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);
}
// export helper functions
getValue(ptr, type = 'i18') {
if (type.charAt(type.length-1) === '*') {
type = 'i32'; // pointers are 32-bit
}
const getValueMapping = {
i1: () => this._HEAP8[((ptr)>>0)],
i8: () => this._HEAP8[((ptr)>>0)],
i16: () => this._HEAP16[((ptr)>>1)],
i32: () => this._HEAP32[((ptr)>>2)],
i64: () => this._HEAP32[((ptr)>>2)],
float: () => this._HEAPF32[((ptr)>>2)],
double: () => this._HEAPF64[((ptr)>>3)],
}
const fn = getValueMapping[type];
if (!fn) {
throw new Error('invalid type for getValue: ' + type);
}
return fn();
}
writeArrayToMemory(array, buffer) {
this._HEAP8.set(array, buffer);
}
}
module.exports = CephesWrapper;