porffor 0.18.21 → 0.18.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -21,6 +21,36 @@ const chHint = (topTier, baselineTier, strategy) => {
21
21
  return (strategy | (baselineTier << 2) | (topTier << 4));
22
22
  };
23
23
 
24
+ const encodeNames = (funcs) => {
25
+ const encodeSection = (id, section) => [
26
+ id,
27
+ ...unsignedLEB128(section.length),
28
+ ...section
29
+ ];
30
+
31
+ const moduleSection = encodeString('js'); // TODO: filename?
32
+ const functionsSection = encodeVector(
33
+ funcs.map((x) => unsignedLEB128(x.index).concat(encodeString(x.name))),
34
+ );
35
+ const localsSection = encodeVector(
36
+ funcs.map((x) =>
37
+ unsignedLEB128(x.index).concat(
38
+ encodeVector(
39
+ Object.entries(x.locals).map(([name, local]) =>
40
+ unsignedLEB128(local.idx).concat(encodeString(name)),
41
+ ),
42
+ ),
43
+ ),
44
+ ),
45
+ );
46
+
47
+ return [
48
+ ...encodeSection(0, moduleSection),
49
+ ...encodeSection(1, functionsSection),
50
+ ...encodeSection(2, localsSection),
51
+ ];
52
+ }
53
+
24
54
  export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) => {
25
55
  const types = [], typeCache = {};
26
56
 
@@ -112,6 +142,8 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
112
142
  encodeVector(funcs.map(x => getType(x.params, x.returns))) // type indexes
113
143
  );
114
144
 
145
+ const nameSection = Prefs.d ? customSection('name', encodeNames(funcs)) : [];
146
+
115
147
  const tableSection = !funcs.table ? [] : createSection(
116
148
  Section.table,
117
149
  encodeVector([ [ Reftype.funcref, 0x00, funcs.length ] ])
@@ -302,6 +334,7 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
302
334
  ...elementSection,
303
335
  ...dataCountSection,
304
336
  ...codeSection,
305
- ...dataSection
337
+ ...dataSection,
338
+ ...nameSection
306
339
  ]);
307
340
  };
@@ -1,9 +1,40 @@
1
1
  import type {} from './porffor.d.ts';
2
2
 
3
3
  export const __Array_isArray = (x: unknown): boolean =>
4
- // Porffor.wasm`local.get ${x+1}` == Porffor.TYPES.array;
5
4
  Porffor.rawType(x) == Porffor.TYPES.array;
6
5
 
6
+ export const __Array_from = (arg: any, mapFn: any): any[] => {
7
+ let out: any[] = Porffor.allocate();
8
+ let len: i32 = 0;
9
+
10
+ const type = Porffor.rawType(arg);
11
+ if (Porffor.fastOr(
12
+ type == Porffor.TYPES.array,
13
+ type == Porffor.TYPES.string, type == Porffor.TYPES.bytestring,
14
+ type == Porffor.TYPES.set,
15
+ Porffor.fastAnd(type >= Porffor.TYPES.uint8array, type <= Porffor.TYPES.float64array)
16
+ )) {
17
+ const hasMapFn = Porffor.rawType(mapFn) != Porffor.TYPES.undefined;
18
+
19
+ let i: i32 = 0;
20
+ if (hasMapFn) {
21
+ if (Porffor.rawType(mapFn) != Porffor.TYPES.function) throw new TypeError('Called Array.from with a non-function mapFn');
22
+
23
+ for (const x of arg) {
24
+ out[i] = mapFn(x, i);
25
+ i++;
26
+ }
27
+ } else {
28
+ for (const x of arg) {
29
+ out[i++] = x;
30
+ }
31
+ }
32
+ len = i;
33
+ }
34
+
35
+ out.length = len;
36
+ return out;
37
+ };
7
38
 
8
39
  export const __Array_prototype_slice = (_this: any[], start: number, end: number) => {
9
40
  const len: i32 = _this.length;
@@ -0,0 +1,249 @@
1
+ import type {} from './porffor.d.ts';
2
+
3
+ export const __ArrayBuffer_isView = function (value: any): boolean {
4
+ if (value.buffer) return true;
5
+ return false;
6
+ };
7
+
8
+ export const ArrayBuffer = function (length: number): ArrayBuffer {
9
+ if (!new.target) throw new TypeError("Constructor ArrayBuffer requires 'new'");
10
+
11
+ if (length < 0) throw new RangeError('Invalid ArrayBuffer length (negative)');
12
+ if (length > 4294967295) throw new RangeError('Invalid ArrayBuffer length (over 32 bit address space)');
13
+
14
+ length |= 0;
15
+
16
+ const out: ArrayBuffer = Porffor.allocateBytes(length + 4);
17
+ Porffor.wasm.i32.store(out, length, 0, 0);
18
+
19
+ return out;
20
+ };
21
+
22
+ export const __ArrayBuffer_prototype_byteLength$get = (_this: ArrayBuffer) => {
23
+ Porffor.wasm`
24
+ local read i32
25
+ local.get ${_this}
26
+ i32.to_u
27
+ i32.load 0 0
28
+ local.tee read
29
+ i32.const 0
30
+ local.get read
31
+ i32.const 0
32
+ i32.ge_s
33
+ select
34
+ i32.from_u
35
+ i32.const 0
36
+ return`;
37
+ };
38
+
39
+ export const __ArrayBuffer_prototype_maxByteLength$get = (_this: ArrayBuffer) => {
40
+ Porffor.wasm`
41
+ local read i32
42
+ local.get ${_this}
43
+ i32.to_u
44
+ i32.load 0 0
45
+ local.tee read
46
+ i32.const 0
47
+ local.get read
48
+ i32.const 0
49
+ i32.ge_s
50
+ select
51
+ i32.from_u
52
+ i32.const 0
53
+ return`;
54
+ };
55
+
56
+ export const __ArrayBuffer_prototype_detached$get = (_this: ArrayBuffer) => {
57
+ Porffor.wasm`
58
+ local.get ${_this}
59
+ i32.to_u
60
+ i32.load 0 0
61
+ i32.const 4294967295
62
+ i32.eq
63
+ i32.from_u
64
+ i32.const 1
65
+ return`;
66
+ };
67
+
68
+ export const __ArrayBuffer_prototype_resizable$get = (_this: ArrayBuffer) => {
69
+ return false;
70
+ };
71
+
72
+ export const __ArrayBuffer_prototype_slice = (_this: ArrayBuffer, start: number, end: any) => {
73
+ if (_this.detached) throw new TypeError('Called ArrayBuffer.prototype.slice on a detached ArrayBuffer');
74
+
75
+ const len: i32 = Porffor.wasm.i32.load(_this, 0, 0);
76
+ if (Porffor.rawType(end) == Porffor.TYPES.undefined) end = len;
77
+
78
+ start |= 0;
79
+ end |= 0;
80
+
81
+ if (start < 0) {
82
+ start = len + start;
83
+ if (start < 0) start = 0;
84
+ }
85
+ if (start > len) start = len;
86
+ if (end < 0) {
87
+ end = len + end;
88
+ if (end < 0) end = 0;
89
+ }
90
+ if (end > len) end = len;
91
+
92
+ const out: ArrayBuffer = Porffor.allocateBytes(4 + (end - start));
93
+ Porffor.wasm.i32.store(out, end - start, 0, 0);
94
+
95
+ Porffor.wasm`
96
+ ;; dst = out + 4
97
+ local.get ${out}
98
+ i32.to_u
99
+ i32.const 4
100
+ i32.add
101
+
102
+ ;; src = this + 4 + start
103
+ local.get ${_this}
104
+ i32.to_u
105
+ i32.const 4
106
+ i32.add
107
+ local.get ${start}
108
+ i32.to_u
109
+ i32.add
110
+
111
+ ;; size = end - start
112
+ local.get ${end}
113
+ i32.to_u
114
+ local.get ${start}
115
+ i32.to_u
116
+ i32.sub
117
+
118
+ memory.copy 0 0`;
119
+
120
+ return out;
121
+ };
122
+
123
+
124
+ export const __ArrayBuffer_prototype_transfer = (_this: ArrayBuffer, newLength: any) => {
125
+ if (_this.detached) throw new TypeError('Called ArrayBuffer.prototype.transfer on a detached ArrayBuffer');
126
+
127
+ const len: i32 = Porffor.wasm.i32.load(_this, 0, 0);
128
+ if (Porffor.rawType(newLength) == Porffor.TYPES.undefined) newLength = len;
129
+
130
+ // make new arraybuffer
131
+ const out: ArrayBuffer = new ArrayBuffer(newLength);
132
+ Porffor.wasm.i32.store(out, newLength, 0, 0);
133
+
134
+ // copy data to it
135
+ Porffor.wasm`
136
+ ;; dst = out + 4
137
+ local.get ${out}
138
+ i32.to_u
139
+ i32.const 4
140
+ i32.add
141
+
142
+ ;; src = this + 4
143
+ local.get ${_this}
144
+ i32.to_u
145
+ i32.const 4
146
+ i32.add
147
+
148
+ ;; size = min(newLength, len)
149
+ local.get ${newLength}
150
+ local.get ${len}
151
+ f64.min
152
+ i32.to_u
153
+
154
+ memory.copy 0 0`;
155
+
156
+ // mark as detached by setting length = "-1"
157
+ Porffor.wasm.i32.store(_this, 4294967295, 0, 0);
158
+
159
+ return out;
160
+ };
161
+
162
+ export const __ArrayBuffer_prototype_transferToFixedLength = (_this: ArrayBuffer, newLength: any) => __ArrayBuffer_prototype_transfer(_this, newLength);
163
+
164
+ export const __ArrayBuffer_prototype_resize = (_this: ArrayBuffer, newLength: any) => {
165
+ // todo: resizable not implemented yet so just always fail
166
+ throw new TypeError('Called ArrayBuffer.prototype.resize on a non-resizable ArrayBuffer');
167
+ };
168
+
169
+
170
+ export const SharedArrayBuffer = function (length: number): SharedArrayBuffer {
171
+ if (!new.target) throw new TypeError("Constructor SharedArrayBuffer requires 'new'");
172
+
173
+ if (length < 0) throw new RangeError('Invalid SharedArrayBuffer length (negative)');
174
+ if (length > 4294967295) throw new RangeError('Invalid SharedArrayBuffer length (over 32 bit address space)');
175
+
176
+ length |= 0;
177
+
178
+ const out: SharedArrayBuffer = Porffor.allocateBytes(length + 4);
179
+ Porffor.wasm.i32.store(out, length, 0, 0);
180
+
181
+ return out;
182
+ };
183
+
184
+ export const __SharedArrayBuffer_prototype_byteLength$get = (_this: SharedArrayBuffer) => {
185
+ return Porffor.wasm.i32.load(_this, 0, 0);
186
+ };
187
+
188
+ export const __SharedArrayBuffer_prototype_maxByteLength$get = (_this: SharedArrayBuffer) => {
189
+ return Porffor.wasm.i32.load(_this, 0, 0);
190
+ };
191
+
192
+ export const __SharedArrayBuffer_prototype_growable$get = (_this: SharedArrayBuffer) => {
193
+ return false;
194
+ };
195
+
196
+
197
+ export const __SharedArrayBuffer_prototype_slice = (_this: SharedArrayBuffer, start: number, end: any) => {
198
+ const len: i32 = Porffor.wasm.i32.load(_this, 0, 0);
199
+ if (Porffor.rawType(end) == Porffor.TYPES.undefined) end = len;
200
+
201
+ start |= 0;
202
+ end |= 0;
203
+
204
+ if (start < 0) {
205
+ start = len + start;
206
+ if (start < 0) start = 0;
207
+ }
208
+ if (start > len) start = len;
209
+ if (end < 0) {
210
+ end = len + end;
211
+ if (end < 0) end = 0;
212
+ }
213
+ if (end > len) end = len;
214
+
215
+ const out: SharedArrayBuffer = Porffor.allocateBytes(4 + (end - start));
216
+ Porffor.wasm.i32.store(out, end - start, 0, 0);
217
+
218
+ Porffor.wasm`
219
+ ;; dst = out + 4
220
+ local.get ${out}
221
+ i32.to_u
222
+ i32.const 4
223
+ i32.add
224
+
225
+ ;; src = this + 4 + start
226
+ local.get ${_this}
227
+ i32.to_u
228
+ i32.const 4
229
+ i32.add
230
+ local.get ${start}
231
+ i32.to_u
232
+ i32.add
233
+
234
+ ;; size = end - start
235
+ local.get ${end}
236
+ i32.to_u
237
+ local.get ${start}
238
+ i32.to_u
239
+ i32.sub
240
+
241
+ memory.copy 0 0`;
242
+
243
+ return out;
244
+ };
245
+
246
+ export const __SharedArrayBuffer_prototype_grow = (_this: SharedArrayBuffer, newLength: any) => {
247
+ // todo: growable not implemented yet so just always fail
248
+ throw new TypeError('Called SharedArrayBuffer.prototype.grow on a non-growable SharedArrayBuffer');
249
+ };
@@ -58,6 +58,8 @@ type PorfforGlobal = {
58
58
  bytestring: i32;
59
59
  date: i32;
60
60
  set: i32;
61
+
62
+ [key: string]: i32;
61
63
  }
62
64
 
63
65
  clone(source: any, destination: any): void;
@@ -6,12 +6,13 @@ export default async () => {
6
6
 
7
7
  // TypedArrays are stored like this in memory:
8
8
  // length (i32)
9
- // bufferPtr (i32)
9
+ // bufferPtr (i32) - buffer + byteOffset
10
+ // byteOffset (i32) - only used for getter
10
11
 
11
12
  const constr = name => out += `export const ${name} = function (arg: any, byteOffset: any, length: any): ${name} {
12
13
  if (!new.target) throw new TypeError("Constructor ${name} requires 'new'");
13
14
 
14
- const out: ${name} = Porffor.allocateBytes(8);
15
+ const out: ${name} = Porffor.allocateBytes(12);
15
16
  const outPtr: i32 = Porffor.wasm\`local.get \${out}\`;
16
17
 
17
18
  let len: i32 = 0;
@@ -21,8 +22,26 @@ export default async () => {
21
22
  if (type == Porffor.TYPES.arraybuffer) {
22
23
  bufferPtr = Porffor.wasm\`local.get \${arg}\`;
23
24
 
25
+ if (arg.detached) throw new TypeError('Constructed ${name} with a detached ArrayBuffer');
26
+
27
+ let offset: i32 = 0;
28
+ if (Porffor.rawType(byteOffset) != Porffor.TYPES.undefined) offset = Math.trunc(byteOffset);
29
+ Porffor.wasm.i32.store(outPtr, offset, 0, 8);
30
+
31
+ Porffor.wasm.i32.store(outPtr, bufferPtr + offset, 0, 4);
32
+
33
+ if (Porffor.rawType(length) == Porffor.TYPES.undefined) {
34
+ const bufferLen: i32 = Porffor.wasm.i32.load(bufferPtr, 0, 0);
35
+ len = (bufferLen - byteOffset) / ${name}.BYTES_PER_ELEMENT;
36
+
37
+ if (!Number.isInteger(len)) throw new RangeError('byte length of ${name} should be divisible by BYTES_PER_ELEMENT');
38
+ } else len = Math.trunc(length);
39
+ } else if (type == Porffor.TYPES.sharedarraybuffer) {
40
+ bufferPtr = Porffor.wasm\`local.get \${arg}\`;
41
+
24
42
  let offset: i32 = 0;
25
43
  if (Porffor.rawType(byteOffset) != Porffor.TYPES.undefined) offset = Math.trunc(byteOffset);
44
+ Porffor.wasm.i32.store(outPtr, offset, 0, 8);
26
45
 
27
46
  Porffor.wasm.i32.store(outPtr, bufferPtr + offset, 0, 4);
28
47
 
@@ -39,7 +58,8 @@ export default async () => {
39
58
  if (Porffor.fastOr(
40
59
  type == Porffor.TYPES.array,
41
60
  type == Porffor.TYPES.string, type == Porffor.TYPES.bytestring,
42
- type == Porffor.TYPES.set
61
+ type == Porffor.TYPES.set,
62
+ Porffor.fastAnd(type >= Porffor.TYPES.uint8array, type <= Porffor.TYPES.float64array)
43
63
  )) {
44
64
  let i: i32 = 0;
45
65
  for (const x of arg) {
@@ -54,12 +74,48 @@ export default async () => {
54
74
  }
55
75
 
56
76
  if (len < 0) throw new RangeError('Invalid TypedArray length (negative)');
57
- if (len > 34359738368) throw new RangeError('Invalid TypedArray length (>32GiB)');
77
+ if (len > 4294967295) throw new RangeError('Invalid ArrayBuffer length (over 32 bit address space)');
58
78
 
59
79
  Porffor.wasm.i32.store(outPtr, len, 0, 0);
60
80
  return out;
61
81
  };
62
82
 
83
+ export const __${name}_of = (...items: any[]): ${name} => new ${name}(items);
84
+
85
+ export const __${name}_from = (arg: any, mapFn: any): ${name} => {
86
+ const arr: any[] = Porffor.allocate();
87
+ let len: i32 = 0;
88
+
89
+ const type = Porffor.rawType(arg);
90
+ if (Porffor.fastOr(
91
+ type == Porffor.TYPES.array,
92
+ type == Porffor.TYPES.string, type == Porffor.TYPES.bytestring,
93
+ type == Porffor.TYPES.set,
94
+ Porffor.fastAnd(type >= Porffor.TYPES.uint8array, type <= Porffor.TYPES.float64array)
95
+ )) {
96
+ const hasMapFn = Porffor.rawType(mapFn) != Porffor.TYPES.undefined;
97
+
98
+ let i: i32 = 0;
99
+ if (hasMapFn) {
100
+ if (Porffor.rawType(mapFn) != Porffor.TYPES.function) throw new TypeError('Called Array.from with a non-function mapFn');
101
+
102
+ for (const x of arg) {
103
+ arr[i] = mapFn(x, i);
104
+ i++;
105
+ }
106
+ } else {
107
+ for (const x of arg) {
108
+ arr[i++] = x;
109
+ }
110
+ }
111
+ len = i;
112
+ }
113
+
114
+ arr.length = len;
115
+
116
+ return new ${name}(arr);
117
+ };
118
+
63
119
  export const __${name}_prototype_buffer$get = (_this: ${name}) => {
64
120
  const out: ArrayBuffer = Porffor.wasm.i32.load(_this, 0, 4);
65
121
  return out;
@@ -69,6 +125,10 @@ export const __${name}_prototype_byteLength$get = (_this: ${name}) => {
69
125
  return _this.length * ${name}.BYTES_PER_ELEMENT;
70
126
  };
71
127
 
128
+ export const __${name}_prototype_byteOffset$get = (_this: ${name}) => {
129
+ return Porffor.wasm.i32.load(_this, 0, 8);
130
+ };
131
+
72
132
  export const __${name}_prototype_at = (_this: ${name}, index: number) => {
73
133
  const len: i32 = _this.length;
74
134
  index |= 0;
@@ -99,7 +159,7 @@ export const __${name}_prototype_slice = (_this: ${name}, start: number, end: nu
99
159
  }
100
160
  if (end > len) end = len;
101
161
 
102
- let out: ${name} = Porffor.allocate();
162
+ const out: ${name} = Porffor.allocate();
103
163
 
104
164
  if (start > end) return out;
105
165
 
@@ -52,6 +52,12 @@ export const importedFuncs = [
52
52
  import: 'q',
53
53
  params: 2,
54
54
  returns: 1
55
+ },
56
+ {
57
+ name: 'debugger',
58
+ import: 'b',
59
+ params: 0,
60
+ returns: 0,
55
61
  }
56
62
  ];
57
63
 
@@ -137,7 +137,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
137
137
 
138
138
  case 'DebuggerStatement':
139
139
  // todo: hook into terminal debugger
140
- return [];
140
+ return [[ Opcodes.call, importedFuncs.debugger ]];
141
141
 
142
142
  case 'ArrayExpression':
143
143
  return generateArray(scope, decl, global, name);
@@ -4233,7 +4233,7 @@ const generateMember = (scope, decl, _global, _name) => {
4233
4233
  }
4234
4234
 
4235
4235
  // todo: generate this array procedurally during builtinFuncs creation
4236
- if (['size', 'description', 'byteLength', 'buffer'].includes(decl.property.name)) {
4236
+ if (['size', 'description', 'byteLength', 'byteOffset', 'buffer', 'detached', 'resizable', 'growable', 'maxByteLength'].includes(decl.property.name)) {
4237
4237
  const bc = {};
4238
4238
  const cands = Object.keys(builtinFuncs).filter(x => x.startsWith('__') && x.endsWith('_prototype_' + decl.property.name + '$get'));
4239
4239
 
@@ -4441,7 +4441,7 @@ const objectHack = node => {
4441
4441
  if (!objectName) objectName = objectHack(node.object)?.name?.slice?.(2);
4442
4442
 
4443
4443
  // if .name or .length, give up (hack within a hack!)
4444
- if (['name', 'length', 'size', 'description', 'byteLength', 'buffer'].includes(node.property.name)) {
4444
+ if (['name', 'length', 'size', 'description', 'byteLength', 'byteOffset', 'buffer', 'detached', 'resizable', 'growable', 'maxByteLength'].includes(node.property.name)) {
4445
4445
  node.object = objectHack(node.object);
4446
4446
  return;
4447
4447
  }