porffor 0.20.8 → 0.20.9
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.
- package/compiler/builtins/_internal_object.ts +91 -0
- package/compiler/builtins/object.ts +51 -14
- package/compiler/builtins/weakref.ts +1 -1
- package/compiler/builtins/z_ecma262.ts +1 -2
- package/compiler/builtins/z_map.ts +1 -1
- package/compiler/builtins/z_weakmap.ts +2 -2
- package/compiler/builtins/z_weakset.ts +1 -1
- package/compiler/codegen.js +4 -3
- package/compiler/generated_builtins.js +51 -22
- package/compiler/precompile.js +3 -2
- package/compiler/wrap.js +9 -3
- package/package.json +1 -1
- package/runner/index.js +1 -1
@@ -128,4 +128,95 @@ export const __Porffor_object_set = (_this: object, key: any, value: any): any =
|
|
128
128
|
0, 12);
|
129
129
|
|
130
130
|
return value;
|
131
|
+
};
|
132
|
+
|
133
|
+
export const __Porffor_object_define = (_this: object, key: any, value: any, flags: any): any => {
|
134
|
+
let entryPtr: i32 = __Porffor_object_lookup(_this, key);
|
135
|
+
if (entryPtr == -1) {
|
136
|
+
// add new entry
|
137
|
+
// bump size +1
|
138
|
+
const size: i32 = Porffor.wasm.i32.load(_this, 0, 0);
|
139
|
+
Porffor.wasm.i32.store(_this, size + 1, 0, 0);
|
140
|
+
|
141
|
+
// entryPtr = current end of object
|
142
|
+
entryPtr = Porffor.wasm`local.get ${_this}` + 4 + size * 14;
|
143
|
+
|
144
|
+
// encode key type, set MSB if regular string
|
145
|
+
let keyEnc: i32 = Porffor.wasm`local.get ${key}`;
|
146
|
+
if (Porffor.wasm`local.get ${key+1}` == Porffor.TYPES.string) keyEnc |= 0x80000000;
|
147
|
+
|
148
|
+
// write key value and type (MSB)
|
149
|
+
Porffor.wasm.i32.store(entryPtr, keyEnc, 0, 0);
|
150
|
+
} else {
|
151
|
+
// existing entry, check and maybe modify it
|
152
|
+
const tail: i32 = Porffor.wasm.i32.load16_u(entryPtr, 0, 12);
|
153
|
+
|
154
|
+
if ((tail & 0b0010) == 0) {
|
155
|
+
// not already configurable, check to see if we can redefine
|
156
|
+
if ((tail & 0b1111) != flags) {
|
157
|
+
// flags have changed, perform checks
|
158
|
+
let err: boolean = false;
|
159
|
+
|
160
|
+
// descriptor type (accessor/data) and/or flags (other than writable) have changed
|
161
|
+
if ((tail & 0b0111) != flags) err = true;
|
162
|
+
else if (!(tail & 0b0001) && !(tail & 0b1000)) {
|
163
|
+
// data descriptor and already non-writable only checks
|
164
|
+
// trying to change writable false -> true
|
165
|
+
if (flags & 0b1000) {
|
166
|
+
err = true;
|
167
|
+
} else {
|
168
|
+
// if already non-writable, check value isn't being changed
|
169
|
+
Porffor.wasm`
|
170
|
+
local.get ${entryPtr}
|
171
|
+
f64.load 0 4
|
172
|
+
local.get ${value}
|
173
|
+
f64.ne
|
174
|
+
|
175
|
+
local.get ${entryPtr}
|
176
|
+
i32.load8_u 0 13
|
177
|
+
local.get ${value+1}
|
178
|
+
i32.ne
|
179
|
+
i32.or
|
180
|
+
local.set ${err}`;
|
181
|
+
}
|
182
|
+
}
|
183
|
+
|
184
|
+
if (err) throw new TypeError('Cannot redefine property');
|
185
|
+
}
|
186
|
+
}
|
187
|
+
}
|
188
|
+
|
189
|
+
// write new value value (lol)
|
190
|
+
Porffor.wasm.f64.store(entryPtr, value, 0, 4);
|
191
|
+
|
192
|
+
// write new tail (value type + flags)
|
193
|
+
Porffor.wasm.i32.store16(entryPtr,
|
194
|
+
flags + (Porffor.wasm`local.get ${value+1}` << 8),
|
195
|
+
0, 12);
|
196
|
+
};
|
197
|
+
|
198
|
+
export const __Porffor_object_isEnumerable = (ptr: i32): boolean => {
|
199
|
+
return Porffor.wasm.i32.load8_u(ptr, 0, 12) & 0b0100;
|
200
|
+
};
|
201
|
+
|
202
|
+
export const __Porffor_object_isObject = (arg: any): boolean => {
|
203
|
+
const t: i32 = Porffor.wasm`local.get ${arg+1}`;
|
204
|
+
return Porffor.fastAnd(
|
205
|
+
arg != 0, // null
|
206
|
+
t > 0x05,
|
207
|
+
t != Porffor.TYPES.undefined,
|
208
|
+
t != Porffor.TYPES.string,
|
209
|
+
t != Porffor.TYPES.bytestring,
|
210
|
+
);
|
211
|
+
};
|
212
|
+
|
213
|
+
export const __Porffor_object_isObjectOrSymbol = (arg: any): boolean => {
|
214
|
+
const t: i32 = Porffor.wasm`local.get ${arg+1}`;
|
215
|
+
return Porffor.fastAnd(
|
216
|
+
arg != 0, // null
|
217
|
+
t > 0x04,
|
218
|
+
t != Porffor.TYPES.undefined,
|
219
|
+
t != Porffor.TYPES.string,
|
220
|
+
t != Porffor.TYPES.bytestring,
|
221
|
+
);
|
131
222
|
};
|
@@ -21,15 +21,12 @@ export const __Object_keys = (obj: any): any[] => {
|
|
21
21
|
|
22
22
|
const t: i32 = Porffor.rawType(obj);
|
23
23
|
if (t == Porffor.TYPES.object) {
|
24
|
-
const size: i32 = Porffor.wasm.i32.load(obj, 0, 0);
|
25
|
-
let len: i32 = size;
|
26
|
-
|
27
24
|
let ptr: i32 = Porffor.wasm`local.get ${obj}` + 4;
|
28
|
-
const endPtr: i32 = ptr +
|
25
|
+
const endPtr: i32 = ptr + Porffor.wasm.i32.load(obj, 0, 0) * 14;
|
29
26
|
|
30
27
|
let i: i32 = 0;
|
31
28
|
for (; ptr < endPtr; ptr += 14) {
|
32
|
-
|
29
|
+
if (!Porffor.object.isEnumerable(ptr)) continue;
|
33
30
|
|
34
31
|
let key: any;
|
35
32
|
Porffor.wasm`local raw i32
|
@@ -60,7 +57,7 @@ local.set ${key}`;
|
|
60
57
|
out[i++] = key;
|
61
58
|
}
|
62
59
|
|
63
|
-
out.length =
|
60
|
+
out.length = i;
|
64
61
|
} else if (Porffor.fastOr(
|
65
62
|
t == Porffor.TYPES.array,
|
66
63
|
t == Porffor.TYPES.bytestring,
|
@@ -84,15 +81,12 @@ export const __Object_values = (obj: any): any[] => {
|
|
84
81
|
|
85
82
|
const t: i32 = Porffor.rawType(obj);
|
86
83
|
if (t == Porffor.TYPES.object) {
|
87
|
-
const size: i32 = Porffor.wasm.i32.load(obj, 0, 0);
|
88
|
-
let len: i32 = size;
|
89
|
-
|
90
84
|
let ptr: i32 = Porffor.wasm`local.get ${obj}` + 4;
|
91
|
-
const endPtr: i32 = ptr +
|
85
|
+
const endPtr: i32 = ptr + Porffor.wasm.i32.load(obj, 0, 0) * 14;
|
92
86
|
|
93
87
|
let i: i32 = 0;
|
94
88
|
for (; ptr < endPtr; ptr += 14) {
|
95
|
-
|
89
|
+
if (!Porffor.object.isEnumerable(ptr)) continue;
|
96
90
|
|
97
91
|
let val: any;
|
98
92
|
Porffor.wasm`local ptr32 i32
|
@@ -110,7 +104,7 @@ local.set ${val+1}`;
|
|
110
104
|
out[i++] = val;
|
111
105
|
}
|
112
106
|
|
113
|
-
out.length =
|
107
|
+
out.length = i;
|
114
108
|
} else if (Porffor.fastOr(
|
115
109
|
t == Porffor.TYPES.array,
|
116
110
|
t == Porffor.TYPES.bytestring,
|
@@ -154,7 +148,7 @@ export const __Object_fromEntries = (iterable: any): object => {
|
|
154
148
|
const out: object = {};
|
155
149
|
|
156
150
|
for (const x of iterable) {
|
157
|
-
if (Porffor.
|
151
|
+
if (!Porffor.object.isObject(x)) throw new TypeError('Iterator contains non-object');
|
158
152
|
out[ecma262.ToPropertyKey(x[0])] = x[1];
|
159
153
|
}
|
160
154
|
|
@@ -167,7 +161,7 @@ export const __Object_prototype_hasOwnProperty = (_this: any, prop: any) => {
|
|
167
161
|
|
168
162
|
const t: i32 = Porffor.rawType(_this);
|
169
163
|
if (t == Porffor.TYPES.object) {
|
170
|
-
return
|
164
|
+
return Porffor.object.lookup(_this, p) != -1;
|
171
165
|
}
|
172
166
|
|
173
167
|
const keys: any[] = __Object_keys(_this);
|
@@ -196,6 +190,49 @@ export const __Object_assign = (target: any, ...sources: any[]) => {
|
|
196
190
|
return target;
|
197
191
|
};
|
198
192
|
|
193
|
+
export const __Object_defineProperty = (target: any, prop: any, descriptor: any) => {
|
194
|
+
if (!Porffor.object.isObject(target)) throw new TypeError('Target is a non-object');
|
195
|
+
|
196
|
+
// if (Porffor.rawType(descriptor) < 0x06) {
|
197
|
+
if (Porffor.rawType(descriptor) != Porffor.TYPES.object) {
|
198
|
+
throw new TypeError('Descriptor is a non-object');
|
199
|
+
}
|
200
|
+
|
201
|
+
const p: any = ecma262.ToPropertyKey(prop);
|
202
|
+
|
203
|
+
const desc: object = descriptor;
|
204
|
+
|
205
|
+
// base keys
|
206
|
+
const configurable: any = desc.configurable; // defaults to false/undefined
|
207
|
+
const enumerable: any = desc.enumerable; // defaults to false/undefined
|
208
|
+
|
209
|
+
// data descriptor keys
|
210
|
+
const value: any = desc.value;
|
211
|
+
const writable: any = desc.writable;
|
212
|
+
|
213
|
+
const get: any = desc.get;
|
214
|
+
const set: any = desc.set;
|
215
|
+
|
216
|
+
let accessor: boolean = false;
|
217
|
+
|
218
|
+
if (get || set) {
|
219
|
+
if (value || writable) {
|
220
|
+
throw new TypeError('Descriptor cannot define both accessor and data descriptor attributes');
|
221
|
+
}
|
222
|
+
|
223
|
+
accessor = true;
|
224
|
+
}
|
225
|
+
|
226
|
+
let flags: i32 = 0b0000;
|
227
|
+
if (accessor) flags |= 0b0001;
|
228
|
+
if (configurable) flags |= 0b0010;
|
229
|
+
if (enumerable) flags |= 0b0100;
|
230
|
+
if (writable) flags |= 0b1000;
|
231
|
+
|
232
|
+
Porffor.object.define(target, p, value, flags);
|
233
|
+
return target;
|
234
|
+
};
|
235
|
+
|
199
236
|
|
200
237
|
export const __Object_prototype_toString = (_this: object) => {
|
201
238
|
let out: bytestring = '[object Object]';
|
@@ -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.
|
6
|
+
if (!Porffor.object.isObjectOrSymbol(target)) 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
|
|
@@ -22,10 +22,9 @@ export const __ecma262_ToIntegerOrInfinity = (argument: unknown): number => {
|
|
22
22
|
return number;
|
23
23
|
};
|
24
24
|
|
25
|
-
// todo: support non-bytestring properly
|
26
25
|
// 7.1.17 ToString (argument)
|
27
26
|
// https://tc39.es/ecma262/#sec-tostring
|
28
|
-
export const __ecma262_ToString = (argument: unknown):
|
27
|
+
export const __ecma262_ToString = (argument: unknown): any => {
|
29
28
|
const type: i32 = Porffor.rawType(argument);
|
30
29
|
|
31
30
|
// 1. If argument is a String, return argument.
|
@@ -98,7 +98,7 @@ export const Map = function (iterable: any): Map {
|
|
98
98
|
Porffor.wasm.i32.store(out, vals, 0, 4);
|
99
99
|
|
100
100
|
if (iterable != null) for (const x of iterable) {
|
101
|
-
if (Porffor.
|
101
|
+
if (!Porffor.object.isObject(x)) throw new TypeError('Iterator contains non-object');
|
102
102
|
__Map_prototype_set(out, x[0], x[1]);
|
103
103
|
}
|
104
104
|
|
@@ -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.
|
6
|
+
if (!Porffor.object.isObjectOrSymbol(key)) 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;
|
@@ -23,7 +23,7 @@ export const WeakMap = function (iterable: any): WeakMap {
|
|
23
23
|
Porffor.wasm.i32.store(out, vals, 0, 4);
|
24
24
|
|
25
25
|
if (iterable != null) for (const x of iterable) {
|
26
|
-
if (Porffor.
|
26
|
+
if (!Porffor.object.isObject(x)) throw new TypeError('Iterator contains non-object');
|
27
27
|
__WeakMap_prototype_set(out, x[0], x[1]);
|
28
28
|
}
|
29
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.
|
6
|
+
if (!Porffor.object.isObjectOrSymbol(value)) 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;
|
package/compiler/codegen.js
CHANGED
@@ -2918,7 +2918,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2918
2918
|
...(op === '=' ? [] : [ [ Opcodes.local_tee, localTmp(scope, '#objset_object', Valtype.i32) ] ]),
|
2919
2919
|
...getNodeType(scope, object),
|
2920
2920
|
|
2921
|
-
...generate(scope, property),
|
2921
|
+
...generate(scope, property, false, '#member_prop'),
|
2922
2922
|
...getNodeType(scope, property),
|
2923
2923
|
...toPropertyKey(scope, op === '='),
|
2924
2924
|
...(op === '=' ? [] : [ [ Opcodes.local_set, localTmp(scope, '#objset_property_type', Valtype.i32) ] ]),
|
@@ -4212,6 +4212,7 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
4212
4212
|
const local = global ? globals[name] : scope.locals[name];
|
4213
4213
|
if (
|
4214
4214
|
Prefs.data && firstAssign && useRawElements &&
|
4215
|
+
name !== '#member_prop' &&
|
4215
4216
|
(!globalThis.precompile || !global)
|
4216
4217
|
) {
|
4217
4218
|
makeData(scope, elements, rawPtr, itemType, initEmpty);
|
@@ -4727,7 +4728,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
4727
4728
|
[ Opcodes.br, 1 ],
|
4728
4729
|
[ Opcodes.end ],
|
4729
4730
|
|
4730
|
-
...generate(scope, property),
|
4731
|
+
...generate(scope, property, false, '#member_prop'),
|
4731
4732
|
[ Opcodes.local_set, localTmp(scope, '#member_prop') ]
|
4732
4733
|
);
|
4733
4734
|
|
@@ -4739,7 +4740,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
4739
4740
|
...generate(scope, object),
|
4740
4741
|
[ Opcodes.local_set, localTmp(scope, '#member_obj') ],
|
4741
4742
|
|
4742
|
-
...generate(scope, property),
|
4743
|
+
...generate(scope, property, false, '#member_prop'),
|
4743
4744
|
[ Opcodes.local_set, localTmp(scope, '#member_prop') ]
|
4744
4745
|
);
|
4745
4746
|
}
|