porffor 0.20.5 → 0.20.7

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.
@@ -154,7 +154,7 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
154
154
  encodeVector([ [
155
155
  0x00,
156
156
  Opcodes.i32_const, 0, Opcodes.end,
157
- ...encodeVector(funcs.map(x => x.index))
157
+ ...encodeVector(funcs.map(x => unsignedLEB128(x.index)))
158
158
  ] ])
159
159
  );
160
160
 
@@ -36,6 +36,13 @@ export const __Array_from = (arg: any, mapFn: any): any[] => {
36
36
  return out;
37
37
  };
38
38
 
39
+ export const __Porffor_fastPush = (_this: any[], el: any) => {
40
+ let len: i32 = _this.length;
41
+ _this[len] = el;
42
+ _this.length = ++len;
43
+ return len;
44
+ };
45
+
39
46
  export const __Array_prototype_push = (_this: any[], ...items: any[]) => {
40
47
  let len: i32 = _this.length;
41
48
  const itemsLen: i32 = items.length;
@@ -1,8 +1,143 @@
1
1
  import type {} from './porffor.d.ts';
2
2
 
3
+ export const __Object_keys = (obj: any): any[] => {
4
+ if (obj == null) throw new TypeError('Argument is nullish, expected object');
5
+
6
+ const out: any[] = Porffor.allocate();
7
+
8
+ const t: i32 = Porffor.rawType(obj);
9
+ if (t == Porffor.TYPES.object) {
10
+ const keys: Set = Porffor.wasm.i32.load(obj, 0, 0);
11
+ const size: i32 = Porffor.wasm.i32.load(keys, 0, 0);
12
+ out.length = size;
13
+
14
+ for (let i: i32 = 0; i < size; i++) {
15
+ out[i] = Porffor.set.read(keys, i);
16
+ }
17
+ } else if (Porffor.fastOr(
18
+ t == Porffor.TYPES.array,
19
+ t == Porffor.TYPES.bytestring,
20
+ t == Porffor.TYPES.string
21
+ )) {
22
+ const len: i32 = obj.length;
23
+ out.length = len;
24
+
25
+ for (let i: i32 = 0; i < len; i++) {
26
+ out[i] = __Number_prototype_toString(i);
27
+ }
28
+ }
29
+
30
+ return out;
31
+ };
32
+
33
+ export const __Object_values = (obj: any): any[] => {
34
+ if (obj == null) throw new TypeError('Argument is nullish, expected object');
35
+
36
+ const out: any[] = Porffor.allocate();
37
+
38
+ const t: i32 = Porffor.rawType(obj);
39
+ if (t == Porffor.TYPES.object) {
40
+ const size: i32 = Porffor.wasm.i32.load(Porffor.wasm.i32.load(obj, 0, 0), 0, 0);
41
+ const vals: any[] = Porffor.wasm.i32.load(obj, 0, 4);
42
+
43
+ out.length = size;
44
+ for (let i: i32 = 0; i < size; i++) {
45
+ out[i] = vals[i];
46
+ }
47
+ } else if (Porffor.fastOr(
48
+ t == Porffor.TYPES.array,
49
+ t == Porffor.TYPES.bytestring,
50
+ t == Porffor.TYPES.string
51
+ )) {
52
+ const len: i32 = obj.length;
53
+ out.length = len;
54
+
55
+ for (let i: i32 = 0; i < len; i++) {
56
+ out[i] = obj[i];
57
+ }
58
+ }
59
+
60
+ return out;
61
+ };
62
+
63
+ export const __Object_entries = (obj: any): any[] => {
64
+ const out: any[] = Porffor.allocate();
65
+
66
+ const keys: any[] = __Object_keys(obj);
67
+ const vals: any[] = __Object_values(obj);
68
+
69
+ const size: i32 = keys.length;
70
+ out.length = size;
71
+
72
+ for (let i: i32 = 0; i < size; i++) {
73
+ // what is memory efficiency anyway?
74
+ const entry: any[] = Porffor.allocate();
75
+
76
+ entry.length = 2;
77
+ entry[0] = keys[i];
78
+ entry[1] = vals[i];
79
+
80
+ out[i] = entry;
81
+ }
82
+
83
+ return out;
84
+ };
85
+
86
+ export const __Object_fromEntries = (iterable: any): object => {
87
+ const out: object = {};
88
+
89
+ for (const x of iterable) {
90
+ if (Porffor.rawType(x) < 0x06) throw new TypeError('Iterator contains non-object');
91
+ out[ecma262.ToPropertyKey(x[0])] = x[1];
92
+ }
93
+
94
+ return out;
95
+ };
96
+
97
+
98
+ export const __Object_prototype_hasOwnProperty = (_this: any, prop: any) => {
99
+ const p: any = ecma262.ToPropertyKey(prop);
100
+
101
+ const t: i32 = Porffor.rawType(_this);
102
+ if (t == Porffor.TYPES.object) {
103
+ const keys: Set = Porffor.wasm.i32.load(_this, 0, 0);
104
+ return __Set_prototype_has(keys, p);
105
+ }
106
+
107
+ const keys: any[] = __Object_keys(_this);
108
+ return __Array_prototype_includes(keys, p);
109
+ };
110
+
111
+ export const __Object_hasOwn = (obj: any, prop: any) => {
112
+ // todo: not spec compliant lol
113
+ return __Object_prototype_hasOwnProperty(obj, prop);
114
+ };
115
+
116
+
117
+ export const __Object_assign = (target: any, ...sources: any[]) => {
118
+ if (target == null) throw new TypeError('Argument is nullish, expected object');
119
+
120
+ for (const x of sources) {
121
+ const keys: any[] = __Object_keys(x);
122
+ const vals: any[] = __Object_values(x);
123
+
124
+ const len: i32 = keys.length;
125
+ for (let i: i32 = 0; i < len; i++) {
126
+ target[keys[i]] = vals[i];
127
+ }
128
+ }
129
+
130
+ return target;
131
+ };
132
+
133
+
3
134
  export const __Object_prototype_toString = (_this: object) => {
4
135
  let out: bytestring = '[object Object]';
5
136
  return out;
6
137
  };
7
138
 
8
- export const __Object_prototype_toLocaleString = (_this: object) => __Object_prototype_toLocaleString(_this);
139
+ export const __Object_prototype_toLocaleString = (_this: object) => __Object_prototype_toLocaleString(_this);
140
+
141
+ export const __Object_prototype_valueOf = (_this: object) => {
142
+ return _this;
143
+ };
@@ -81,6 +81,7 @@ declare global {
81
81
  const ecma262: {
82
82
  ToIntegerOrInfinity(argument: unknown): number;
83
83
  ToString(argument: unknown): bytestring;
84
+ ToPropertyKey(argument: unknown): any;
84
85
  }
85
86
 
86
87
  const print: (arg: any) => void;
@@ -76,7 +76,7 @@ export const __Set_prototype_values = (_this: Set) => {
76
76
  const out: any[] = __Porffor_allocate();
77
77
  for (let i: number = 0; i < size; i++) {
78
78
  const val: any = __Porffor_set_read(_this, i);
79
- out.push(val);
79
+ Porffor.fastPush(out, val);
80
80
  }
81
81
 
82
82
  return out;
@@ -184,10 +184,7 @@ export const Set = function (iterable: any): Set {
184
184
 
185
185
  const out: Set = __Porffor_allocate();
186
186
 
187
- if (Porffor.fastAnd(
188
- Porffor.rawType(iterable) != Porffor.TYPES.undefined,
189
- iterable !== null
190
- )) for (const x of iterable) {
187
+ if (iterable != null) for (const x of iterable) {
191
188
  __Set_prototype_add(out, x);
192
189
  }
193
190
 
@@ -17,12 +17,7 @@ export const Symbol = (description: any): Symbol => {
17
17
  }
18
18
 
19
19
  // 4. Return a new Symbol whose [[Description]] is descString.
20
- let len: i32 = descStore.length;
21
- descStore[len] = descString;
22
- descStore.length = ++len;
23
-
24
- // 1-based so always truthy as numeric value
25
- const sym: Symbol = len;
20
+ const sym: Symbol = Porffor.fastPush(descStore, descString);
26
21
  return sym;
27
22
  };
28
23
 
@@ -3,7 +3,7 @@ import type {} from './porffor.d.ts';
3
3
  export const WeakRef = function (target: any): WeakRef {
4
4
  if (!new.target) throw new TypeError("Constructor WeakRef requires 'new'");
5
5
 
6
- if (Porffor.rawType(target) < 0x04) throw new TypeError('Target for WeakRef needs to be an object or symbol');
6
+ if (Porffor.rawType(target) < 0x05) throw new TypeError('Target for WeakRef needs to be an object or symbol');
7
7
 
8
8
  const out: WeakRef = Porffor.allocateBytes(9);
9
9
 
@@ -62,4 +62,20 @@ export const __ecma262_ToString = (argument: unknown): bytestring => {
62
62
  // 11. Assert: primValue is not an Object.
63
63
  // 12. Return ? ToString(primValue).
64
64
  return argument.toString();
65
+ };
66
+
67
+ // 7.1.19 ToPropertyKey (argument)
68
+ // https://tc39.es/ecma262/#sec-topropertykey
69
+ export const __ecma262_ToPropertyKey = (argument: any): any => {
70
+ // 1. Let key be ? ToPrimitive(argument, string).
71
+ const key: any = argument;
72
+
73
+ // 2. If key is a Symbol, then
74
+ if (Porffor.rawType(key) == Porffor.TYPES.symbol) {
75
+ // a. Return key.
76
+ return key;
77
+ }
78
+
79
+ // 3. Return ! ToString(key).
80
+ return __ecma262_ToString(key);
65
81
  };
@@ -40,7 +40,7 @@ export const __Map_prototype_set = (_this: Map, key: any, value: any) => {
40
40
  Porffor.wasm.i32.store(keys, size + 1, 0, 0);
41
41
 
42
42
  // write new key at end
43
- __Porffor_set_write(keys, size, key);
43
+ Porffor.set.write(keys, size, key);
44
44
 
45
45
  // write new value at end
46
46
  vals[size] = value;
@@ -97,10 +97,8 @@ export const Map = function (iterable: any): Map {
97
97
  const vals: any[] = Porffor.allocate();
98
98
  Porffor.wasm.i32.store(out, vals, 0, 4);
99
99
 
100
- if (Porffor.fastAnd(
101
- Porffor.rawType(iterable) != Porffor.TYPES.undefined,
102
- iterable !== null
103
- )) for (const x of iterable) {
100
+ if (iterable != null) for (const x of iterable) {
101
+ if (Porffor.rawType(x) < 0x06) throw new TypeError('Iterator contains non-object');
104
102
  __Map_prototype_set(out, x[0], x[1]);
105
103
  }
106
104
 
@@ -112,18 +110,19 @@ export const __Map_prototype_keys = (_this: Map) => {
112
110
  const out: any[] = Porffor.allocate();
113
111
 
114
112
  for (const x of keys) {
115
- out.push(x);
113
+ Porffor.fastPush(out, x);
116
114
  }
117
115
 
118
116
  return out;
119
117
  };
120
118
 
121
119
  export const __Map_prototype_values = (_this: Map) => {
122
- const vals: Set = Porffor.wasm.i32.load(_this, 0, 4);
120
+ const size: i32 = Porffor.wasm.i32.load(Porffor.wasm.i32.load(_this, 0, 0), 0, 0);
121
+ const vals: any[] = Porffor.wasm.i32.load(_this, 0, 4);
123
122
  const out: any[] = Porffor.allocate();
124
123
 
125
- for (const x of vals) {
126
- out.push(x);
124
+ for (let i: i32 = 0; i < size; i++) {
125
+ Porffor.fastPush(out, vals[i]);
127
126
  }
128
127
 
129
128
  return out;
@@ -3,7 +3,7 @@ import type {} from './porffor.d.ts';
3
3
  export const __WeakMap_prototype_has = (_this: WeakMap, key: any) => __Map_prototype_has(_this, key);
4
4
 
5
5
  export const __WeakMap_prototype_set = (_this: WeakMap, key: any, value: any) => {
6
- if (Porffor.rawType(key) < 0x04) throw new TypeError('Value in WeakSet needs to be an object or symbol');
6
+ if (Porffor.rawType(key) < 0x05) throw new TypeError('Value in WeakSet needs to be an object or symbol');
7
7
 
8
8
  __Map_prototype_set(_this, key, value);
9
9
  return _this;
@@ -22,10 +22,8 @@ export const WeakMap = function (iterable: any): WeakMap {
22
22
  const vals: any[] = Porffor.allocate();
23
23
  Porffor.wasm.i32.store(out, vals, 0, 4);
24
24
 
25
- if (Porffor.fastAnd(
26
- Porffor.rawType(iterable) != Porffor.TYPES.undefined,
27
- iterable !== null
28
- )) for (const x of iterable) {
25
+ if (iterable != null) for (const x of iterable) {
26
+ if (Porffor.rawType(x) < 0x06) throw new TypeError('Iterator contains non-object');
29
27
  __WeakMap_prototype_set(out, x[0], x[1]);
30
28
  }
31
29
 
@@ -3,7 +3,7 @@ import type {} from './porffor.d.ts';
3
3
  export const __WeakSet_prototype_has = (_this: WeakSet, value: any) => __Set_prototype_has(_this, value);
4
4
 
5
5
  export const __WeakSet_prototype_add = (_this: WeakSet, value: any) => {
6
- if (Porffor.rawType(value) < 0x04) throw new TypeError('Value in WeakSet needs to be an object or symbol');
6
+ if (Porffor.rawType(value) < 0x05) throw new TypeError('Value in WeakSet needs to be an object or symbol');
7
7
 
8
8
  __Set_prototype_add(_this, value);
9
9
  return _this;
@@ -16,10 +16,7 @@ export const WeakSet = function (iterable: any): WeakSet {
16
16
 
17
17
  const out: WeakSet = __Porffor_allocate();
18
18
 
19
- if (Porffor.fastAnd(
20
- Porffor.rawType(iterable) != Porffor.TYPES.undefined,
21
- iterable !== null
22
- )) for (const x of iterable) {
19
+ if (iterable != null) for (const x of iterable) {
23
20
  __WeakSet_prototype_add(out, x);
24
21
  }
25
22
 
@@ -713,7 +713,7 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMod
713
713
  if (truthyMode === 'full') return [
714
714
  // if value != 0 or NaN
715
715
  ...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
716
- ...(intIn ? [ ] : [ Opcodes.i32_to ]),
716
+ ...(intIn ? [] : [ Opcodes.i32_to ]),
717
717
 
718
718
  [ Opcodes.i32_eqz ],
719
719
  [ Opcodes.i32_eqz ],
@@ -820,6 +820,7 @@ const nullish = (scope, wasm, type, intIn = false, intOut = false) => {
820
820
  ...typeSwitch(scope, type, {
821
821
  [TYPES.undefined]: [
822
822
  // undefined
823
+ ...(!useTmp ? [ [ Opcodes.drop ] ] : []),
823
824
  ...number(1, intOut ? Valtype.i32 : valtypeBinary)
824
825
  ],
825
826
  [TYPES.object]: [
@@ -831,6 +832,7 @@ const nullish = (scope, wasm, type, intIn = false, intOut = false) => {
831
832
  ],
832
833
  default: [
833
834
  // not
835
+ ...(!useTmp ? [ [ Opcodes.drop ] ] : []),
834
836
  ...number(0, intOut ? Valtype.i32 : valtypeBinary)
835
837
  ]
836
838
  }, intOut ? Valtype.i32 : valtypeBinary)
@@ -1082,6 +1084,13 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
1082
1084
  ]);
1083
1085
  };
1084
1086
 
1087
+ const knownNullish = decl => {
1088
+ if (decl.type === 'Literal' && decl.value === null) return true;
1089
+ if (decl.type === 'Identifier' && decl.name === 'undefined') return true;
1090
+
1091
+ return false;
1092
+ };
1093
+
1085
1094
  const generateBinaryExp = (scope, decl, _global, _name) => {
1086
1095
  if (decl.operator === 'instanceof') {
1087
1096
  // very hacky basic instanceof
@@ -1110,8 +1119,24 @@ const generateBinaryExp = (scope, decl, _global, _name) => {
1110
1119
  return out;
1111
1120
  }
1112
1121
 
1113
- const out = performOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right), getNodeType(scope, decl.left), getNodeType(scope, decl.right), _global, _name);
1122
+ // opt: == null|undefined -> nullish
1123
+ if (decl.operator === '==' || decl.operator === '!=') {
1124
+ if (knownNullish(decl.right)) {
1125
+ const out = nullish(scope, generate(scope, decl.left), getNodeType(scope, decl.left), false, true);
1126
+ if (decl.operator === '!=') out.push([ Opcodes.i32_eqz ]);
1127
+ out.push(Opcodes.i32_from_u);
1128
+ return out;
1129
+ }
1114
1130
 
1131
+ if (knownNullish(decl.left)) {
1132
+ const out = nullish(scope, generate(scope, decl.right), getNodeType(scope, decl.right), false, true);
1133
+ if (decl.operator === '!=') out.push([ Opcodes.i32_eqz ]);
1134
+ out.push(Opcodes.i32_from_u);
1135
+ return out;
1136
+ }
1137
+ }
1138
+
1139
+ const out = performOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right), getNodeType(scope, decl.left), getNodeType(scope, decl.right), _global, _name);
1115
1140
  if (valtype !== 'i32' && ['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(decl.operator)) out.push(Opcodes.i32_from_u);
1116
1141
 
1117
1142
  return out;
@@ -1307,7 +1332,7 @@ const isExistingProtoFunc = name => {
1307
1332
  const getType = (scope, _name) => {
1308
1333
  const name = mapName(_name);
1309
1334
 
1310
- // if (scope.locals[name] && !scope.locals[name + '#type']) console.log(name);
1335
+ if (Object.hasOwn(builtinVars, name)) return number(builtinVars[name].type ?? TYPES.number, Valtype.i32);
1311
1336
 
1312
1337
  if (typedInput && scope.locals[name]?.metadata?.type != null) return number(scope.locals[name].metadata.type, Valtype.i32);
1313
1338
  if (Object.hasOwn(scope.locals, name)) return [ [ Opcodes.local_get, scope.locals[name + '#type'].idx ] ];
@@ -1315,13 +1340,13 @@ const getType = (scope, _name) => {
1315
1340
  if (typedInput && globals[name]?.metadata?.type != null) return number(globals[name].metadata.type, Valtype.i32);
1316
1341
  if (Object.hasOwn(globals, name)) return [ [ Opcodes.global_get, globals[name + '#type'].idx ] ];
1317
1342
 
1318
- let type = TYPES.undefined;
1319
- if (Object.hasOwn(builtinVars, name)) type = builtinVars[name].type ?? TYPES.number;
1320
- if (Object.hasOwn(builtinFuncs, name) || Object.hasOwn(importedFuncs, name) || Object.hasOwn(funcIndex, name) || Object.hasOwn(internalConstrs, name)) type = TYPES.function;
1343
+ if (Object.hasOwn(builtinFuncs, name) || Object.hasOwn(importedFuncs, name) ||
1344
+ Object.hasOwn(funcIndex, name) || Object.hasOwn(internalConstrs, name))
1345
+ return number(TYPES.function, Valtype.i32);
1321
1346
 
1322
- if (isExistingProtoFunc(name)) type = TYPES.function;
1347
+ if (isExistingProtoFunc(name)) return number(TYPES.function, Valtype.i32);
1323
1348
 
1324
- return number(type, Valtype.i32);
1349
+ return number(TYPES.undefined, Valtype.i32);
1325
1350
  };
1326
1351
 
1327
1352
  const setType = (scope, _name, type) => {
@@ -1563,7 +1588,6 @@ const generateLiteral = (scope, decl, global, name) => {
1563
1588
  return number(decl.value);
1564
1589
 
1565
1590
  case 'boolean':
1566
- // hack: bool as int (1/0)
1567
1591
  return number(decl.value ? 1 : 0);
1568
1592
 
1569
1593
  case 'string':
@@ -2839,9 +2863,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2839
2863
  value: decl.left.property.name
2840
2864
  };
2841
2865
 
2842
- includeBuiltin(scope, '__Map_prototype_get');
2843
- includeBuiltin(scope, '__Map_prototype_set');
2844
-
2845
2866
  return [
2846
2867
  ...typeSwitch(scope, getNodeType(scope, decl.left.object), {
2847
2868
  [TYPES.array]: [
@@ -2879,23 +2900,26 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2879
2900
  ...getNodeType(scope, object),
2880
2901
 
2881
2902
  ...generate(scope, property),
2882
- ...(op === '=' ? [] : [ [ Opcodes.local_tee, localTmp(scope, '#objset_property') ] ]),
2883
2903
  ...getNodeType(scope, property),
2904
+ ...toPropertyKey(scope),
2905
+ ...(op === '=' ? [] : [ [ Opcodes.local_set, localTmp(scope, '#objset_property_type', Valtype.i32) ] ]),
2906
+ ...(op === '=' ? [] : [ [ Opcodes.local_tee, localTmp(scope, '#objset_property') ] ]),
2907
+ ...(op === '=' ? [] : [ [ Opcodes.local_get, localTmp(scope, '#objset_property_type', Valtype.i32) ] ]),
2884
2908
 
2885
2909
  ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2886
2910
  [ Opcodes.local_get, localTmp(scope, '#objset_object') ],
2887
2911
  ...getNodeType(scope, object),
2888
2912
 
2889
2913
  [ Opcodes.local_get, localTmp(scope, '#objset_property') ],
2890
- ...getNodeType(scope, property),
2914
+ [ Opcodes.local_get, localTmp(scope, '#objset_property_type', Valtype.i32) ],
2891
2915
 
2892
- [ Opcodes.call, ...unsignedLEB128(funcIndex.__Map_prototype_get) ],
2916
+ [ Opcodes.call, ...unsignedLEB128(includeBuiltin(scope, '__Map_prototype_get').index) ],
2893
2917
  ...setLastType(scope)
2894
2918
  ], generate(scope, decl.right), getLastType(scope), getNodeType(scope, decl.right), false, name, true)),
2895
2919
  [ Opcodes.local_tee, newValueTmp ],
2896
2920
  ...getNodeType(scope, decl),
2897
2921
 
2898
- [ Opcodes.call, ...unsignedLEB128(funcIndex.__Map_prototype_set) ],
2922
+ [ Opcodes.call, ...unsignedLEB128(includeBuiltin(scope, '__Map_prototype_set').index) ],
2899
2923
  [ Opcodes.drop ],
2900
2924
 
2901
2925
  ...setLastType(scope, getNodeType(scope, decl)),
@@ -3406,16 +3430,22 @@ const generateForOf = (scope, decl) => {
3406
3430
  // get length
3407
3431
  [ Opcodes.local_get, pointer ],
3408
3432
  [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
3409
- [ Opcodes.local_set, length ]
3433
+ [ Opcodes.local_tee, length ],
3434
+
3435
+ [ Opcodes.if, Blocktype.void ]
3410
3436
  );
3411
3437
 
3438
+ depth.push('if');
3412
3439
  depth.push('forof');
3440
+ depth.push('block');
3441
+ depth.push('block');
3413
3442
 
3414
3443
  // setup local for left
3415
3444
  generate(scope, decl.left);
3416
3445
 
3417
3446
  let leftName = decl.left.declarations?.[0]?.id?.name;
3418
3447
  if (!leftName && decl.left.name) {
3448
+ // todo: should be sloppy mode only
3419
3449
  leftName = decl.left.name;
3420
3450
 
3421
3451
  generateVar(scope, { kind: 'var', _bare: true, declarations: [ { id: { name: leftName } } ] })
@@ -3426,9 +3456,6 @@ const generateForOf = (scope, decl) => {
3426
3456
  const [ local, isGlobal ] = lookupName(scope, leftName);
3427
3457
  if (!local) return todo(scope, 'for of failed to get left local (probably destructure)');
3428
3458
 
3429
- depth.push('block');
3430
- depth.push('block');
3431
-
3432
3459
  // // todo: we should only do this for strings but we don't know at compile-time :(
3433
3460
  // hack: this is naughty and will break things!
3434
3461
  let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
@@ -3571,12 +3598,6 @@ const generateForOf = (scope, decl) => {
3571
3598
  ...generate(scope, decl.body),
3572
3599
  [ Opcodes.end ],
3573
3600
 
3574
- // increment iter pointer
3575
- // [ Opcodes.local_get, pointer ],
3576
- // ...number(1, Valtype.i32),
3577
- // [ Opcodes.i32_add ],
3578
- // [ Opcodes.local_set, pointer ],
3579
-
3580
3601
  // increment counter by 1
3581
3602
  [ Opcodes.local_get, counter ],
3582
3603
  ...number(1, Valtype.i32),
@@ -3734,6 +3755,8 @@ const generateForOf = (scope, decl) => {
3734
3755
  default: internalThrow(scope, 'TypeError', `Tried for..of on non-iterable type`)
3735
3756
  }, Blocktype.void));
3736
3757
 
3758
+ out.push([ Opcodes.end ]); // end if
3759
+
3737
3760
  depth.pop();
3738
3761
  depth.pop();
3739
3762
  depth.pop();
@@ -4310,9 +4333,12 @@ const generateArray = (scope, decl, global = false, name = '$undeclared', initEm
4310
4333
  return makeArray(scope, decl, global, name, initEmpty, valtype, false, true)[0];
4311
4334
  };
4312
4335
 
4336
+ const toPropertyKey = scope => Prefs.fastObject ? [] : [
4337
+ [ Opcodes.call, ...unsignedLEB128(includeBuiltin(scope, '__ecma262_ToPropertyKey').index) ]
4338
+ ];
4339
+
4313
4340
  const generateObject = (scope, decl, global = false, name = '$undeclared') => {
4314
4341
  includeBuiltin(scope, 'Map');
4315
- includeBuiltin(scope, '__Map_prototype_set');
4316
4342
 
4317
4343
  // todo: optimize const objects
4318
4344
  const tmp = localTmp(scope, `#objectexpr${randId()}`);
@@ -4332,7 +4358,8 @@ const generateObject = (scope, decl, global = false, name = '$undeclared') => {
4332
4358
  const { method, shorthand, computed, kind, key, value } = x;
4333
4359
  if (kind !== 'init') return todo(scope, 'complex objects are not supported yet', true);
4334
4360
 
4335
- const k = computed ? key : {
4361
+ let k = key;
4362
+ if (!computed && key.type !== 'Literal') k = {
4336
4363
  type: 'Literal',
4337
4364
  value: key.name
4338
4365
  };
@@ -4343,11 +4370,12 @@ const generateObject = (scope, decl, global = false, name = '$undeclared') => {
4343
4370
 
4344
4371
  ...generate(scope, k),
4345
4372
  ...getNodeType(scope, k),
4373
+ ...toPropertyKey(scope),
4346
4374
 
4347
4375
  ...generate(scope, value),
4348
4376
  ...getNodeType(scope, value),
4349
4377
 
4350
- [ Opcodes.call, ...unsignedLEB128(funcIndex.__Map_prototype_set) ],
4378
+ [ Opcodes.call, ...unsignedLEB128(includeBuiltin(scope, '__Map_prototype_set').index) ],
4351
4379
 
4352
4380
  [ Opcodes.drop ],
4353
4381
  [ Opcodes.drop ]
@@ -4503,8 +4531,6 @@ const generateMember = (scope, decl, _global, _name) => {
4503
4531
  }, _global, _name, true, 'i16', true);
4504
4532
  }
4505
4533
 
4506
- includeBuiltin(scope, '__Map_prototype_get');
4507
-
4508
4534
  const out = typeSwitch(scope, getNodeType(scope, object), {
4509
4535
  [TYPES.array]: [
4510
4536
  ...loadArray(scope, objectWasm, propertyWasm),
@@ -4580,8 +4606,9 @@ const generateMember = (scope, decl, _global, _name) => {
4580
4606
 
4581
4607
  ...propertyWasm,
4582
4608
  ...getNodeType(scope, property),
4609
+ ...toPropertyKey(scope),
4583
4610
 
4584
- [ Opcodes.call, ...unsignedLEB128(funcIndex.__Map_prototype_get) ],
4611
+ [ Opcodes.call, ...unsignedLEB128(includeBuiltin(scope, '__Map_prototype_get').index) ],
4585
4612
  ...setLastType(scope)
4586
4613
  ],
4587
4614