/src/moddable/xs/sources/xsProxy.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2016-2017 Moddable Tech, Inc. |
3 | | * |
4 | | * This file is part of the Moddable SDK Runtime. |
5 | | * |
6 | | * The Moddable SDK Runtime is free software: you can redistribute it and/or modify |
7 | | * it under the terms of the GNU Lesser General Public License as published by |
8 | | * the Free Software Foundation, either version 3 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * The Moddable SDK Runtime is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public License |
17 | | * along with the Moddable SDK Runtime. If not, see <http://www.gnu.org/licenses/>. |
18 | | * |
19 | | * This file incorporates work covered by the following copyright and |
20 | | * permission notice: |
21 | | * |
22 | | * Copyright (C) 2010-2016 Marvell International Ltd. |
23 | | * Copyright (C) 2002-2010 Kinoma, Inc. |
24 | | * |
25 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
26 | | * you may not use this file except in compliance with the License. |
27 | | * You may obtain a copy of the License at |
28 | | * |
29 | | * http://www.apache.org/licenses/LICENSE-2.0 |
30 | | * |
31 | | * Unless required by applicable law or agreed to in writing, software |
32 | | * distributed under the License is distributed on an "AS IS" BASIS, |
33 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
34 | | * See the License for the specific language governing permissions and |
35 | | * limitations under the License. |
36 | | */ |
37 | | |
38 | | #include "xsAll.h" |
39 | | |
40 | | static txSlot* fxNewProxyInstance(txMachine* the); |
41 | | static txSlot* fxCheckProxyFunction(txMachine* the, txSlot* proxy, txID index); |
42 | | |
43 | | static void fxProxyCall(txMachine* the, txSlot* instance, txSlot* _this, txSlot* arguments); |
44 | | static void fxProxyConstruct(txMachine* the, txSlot* instance, txSlot* arguments, txSlot* target); |
45 | | static txBoolean fxProxyDefineOwnProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txSlot* slot, txFlag mask); |
46 | | static txBoolean fxProxyDeleteProperty(txMachine* the, txSlot* instance, txID id, txIndex index); |
47 | | static txBoolean fxProxyGetOwnProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txSlot* slot); |
48 | | static txSlot* fxProxyGetProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txFlag flag); |
49 | | static txBoolean fxProxyGetPropertyValue(txMachine* the, txSlot* instance, txID id, txIndex index, txSlot* receiver, txSlot* value); |
50 | | static txBoolean fxProxyGetPrototype(txMachine* the, txSlot* instance, txSlot* result); |
51 | | static txBoolean fxProxyHasProperty(txMachine* the, txSlot* instance, txID id, txIndex index); |
52 | | static txBoolean fxProxyIsExtensible(txMachine* the, txSlot* instance); |
53 | | static void fxProxyOwnKeys(txMachine* the, txSlot* instance, txFlag flag, txSlot* list); |
54 | | static txBoolean fxProxyPreventExtensions(txMachine* the, txSlot* instance); |
55 | | static txSlot* fxProxySetProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txFlag flag); |
56 | | static txBoolean fxProxySetPropertyValue(txMachine* the, txSlot* instance, txID id, txIndex index, txSlot* value, txSlot* receiver); |
57 | | static txBoolean fxProxySetPrototype(txMachine* the, txSlot* instance, txSlot* prototype); |
58 | | |
59 | | const txBehavior ICACHE_FLASH_ATTR gxProxyBehavior = { |
60 | | fxProxyGetProperty, |
61 | | fxProxySetProperty, |
62 | | fxProxyCall, |
63 | | fxProxyConstruct, |
64 | | fxProxyDefineOwnProperty, |
65 | | fxProxyDeleteProperty, |
66 | | fxProxyGetOwnProperty, |
67 | | fxProxyGetPropertyValue, |
68 | | fxProxyGetPrototype, |
69 | | fxProxyHasProperty, |
70 | | fxProxyIsExtensible, |
71 | | fxProxyOwnKeys, |
72 | | fxProxyPreventExtensions, |
73 | | fxProxySetPropertyValue, |
74 | | fxProxySetPrototype, |
75 | | }; |
76 | | |
77 | | void fxBuildProxy(txMachine* the) |
78 | 35.3k | { |
79 | 35.3k | txSlot* slot; |
80 | | |
81 | 35.3k | fxNewHostFunction(the, mxCallback(fxProxyGetter), 0, XS_NO_ID, XS_NO_ID); |
82 | 35.3k | fxNewHostFunction(the, mxCallback(fxProxySetter), 1, XS_NO_ID, XS_NO_ID); |
83 | 35.3k | mxPushUndefined(); |
84 | 35.3k | the->stack->flag = XS_DONT_DELETE_FLAG; |
85 | 35.3k | the->stack->kind = XS_ACCESSOR_KIND; |
86 | 35.3k | the->stack->value.accessor.getter = (the->stack + 2)->value.reference; |
87 | 35.3k | the->stack->value.accessor.setter = (the->stack + 1)->value.reference; |
88 | 35.3k | mxPull(mxProxyAccessor); |
89 | 35.3k | the->stack += 2; |
90 | | |
91 | 35.3k | slot = fxBuildHostFunction(the, mxCallback(fx_Proxy), 2, mxID(_Proxy)); |
92 | 35.3k | slot->flag |= XS_CAN_CONSTRUCT_FLAG; |
93 | 35.3k | mxProxyConstructor = *the->stack; |
94 | 35.3k | slot = fxLastProperty(the, slot); |
95 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Proxy_revocable), 2, mxID(_revocable), XS_DONT_ENUM_FLAG); |
96 | 35.3k | mxPop(); |
97 | | |
98 | 35.3k | mxPush(mxObjectPrototype); |
99 | 35.3k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
100 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Reflect_apply), 3, mxID(_apply), XS_DONT_ENUM_FLAG); |
101 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Reflect_construct), 2, mxID(_construct), XS_DONT_ENUM_FLAG); |
102 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Reflect_defineProperty), 3, mxID(_defineProperty), XS_DONT_ENUM_FLAG); |
103 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Reflect_deleteProperty), 2, mxID(_deleteProperty), XS_DONT_ENUM_FLAG); |
104 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Reflect_get), 2, mxID(_get), XS_DONT_ENUM_FLAG); |
105 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Reflect_getOwnPropertyDescriptor), 2, mxID(_getOwnPropertyDescriptor), XS_DONT_ENUM_FLAG); |
106 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Reflect_getPrototypeOf), 1, mxID(_getPrototypeOf), XS_DONT_ENUM_FLAG); |
107 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Reflect_has), 2, mxID(_has), XS_DONT_ENUM_FLAG); |
108 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Reflect_isExtensible), 1, mxID(_isExtensible), XS_DONT_ENUM_FLAG); |
109 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Reflect_ownKeys), 1, mxID(_ownKeys), XS_DONT_ENUM_FLAG); |
110 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Reflect_preventExtensions), 1, mxID(_preventExtensions), XS_DONT_ENUM_FLAG); |
111 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Reflect_set), 3, mxID(_set), XS_DONT_ENUM_FLAG); |
112 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Reflect_setPrototypeOf), 2, mxID(_setPrototypeOf), XS_DONT_ENUM_FLAG); |
113 | 35.3k | slot = fxNextStringXProperty(the, slot, "Reflect", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG); |
114 | 35.3k | mxPull(mxReflectObject); |
115 | 35.3k | } |
116 | | |
117 | | txSlot* fxNewProxyInstance(txMachine* the) |
118 | 724k | { |
119 | 724k | txSlot* prototype; |
120 | 724k | txSlot* instance; |
121 | 724k | txSlot* property; |
122 | 724k | txSlot* slot; |
123 | | |
124 | 724k | prototype = mxIsReference(the->stack) ? the->stack->value.reference : C_NULL; |
125 | | |
126 | 724k | instance = fxNewSlot(the); |
127 | 724k | instance->flag = XS_EXOTIC_FLAG; |
128 | 724k | instance->kind = XS_INSTANCE_KIND; |
129 | 724k | instance->value.instance.garbage = C_NULL; |
130 | 724k | instance->value.instance.prototype = C_NULL; |
131 | 724k | the->stack->kind = XS_REFERENCE_KIND; |
132 | 724k | the->stack->value.reference = instance; |
133 | | |
134 | 724k | property = instance->next = fxNewSlot(the); |
135 | 724k | property->flag = XS_INTERNAL_FLAG; |
136 | 724k | property->kind = XS_PROXY_KIND; |
137 | 724k | property->ID = XS_PROXY_BEHAVIOR; |
138 | 724k | if (prototype && ((slot = prototype->next)) && (slot->kind = XS_PROXY_KIND)) { |
139 | 0 | property->value.proxy.handler = slot->value.proxy.handler; |
140 | 0 | property->value.proxy.target = slot->value.proxy.target; |
141 | 0 | } |
142 | 724k | else { |
143 | 724k | property->value.proxy.handler = C_NULL; |
144 | 724k | property->value.proxy.target = C_NULL; |
145 | 724k | } |
146 | | |
147 | 724k | return instance; |
148 | 724k | } |
149 | | |
150 | | #define mxProxyDeclarations(ID) \ |
151 | 914k | txSlot* proxy = instance->next; \ |
152 | 914k | txSlot* function = fxCheckProxyFunction(the, proxy, ID); \ |
153 | 914k | txSlot* handler = the->stack + 1; \ |
154 | 914k | txSlot* target = the->stack + 2 |
155 | | |
156 | | #define mxProxyPop() \ |
157 | 912k | mxPop(); \ |
158 | 912k | mxPop(); \ |
159 | 914k | mxPop() |
160 | | |
161 | | txSlot* fxCheckProxyFunction(txMachine* the, txSlot* proxy, txID index) |
162 | 914k | { |
163 | 914k | txSlot* function; |
164 | 914k | mxCheckCStack(); |
165 | 914k | if (!proxy->value.proxy.handler) |
166 | 13 | mxTypeError("(proxy).%s: no handler", fxName(the, mxID(index))); |
167 | 914k | if (!proxy->value.proxy.target) |
168 | 0 | mxTypeError("(proxy).%s: no target", fxName(the, mxID(index))); |
169 | 914k | mxPushReference(proxy->value.proxy.target); |
170 | 914k | mxPushReference(proxy->value.proxy.handler); |
171 | 914k | mxDub(); |
172 | 914k | mxGetID(mxID(index)); |
173 | 914k | function = the->stack; |
174 | 914k | if (mxIsUndefined(function) || (mxIsNull(function))) |
175 | 710k | function = C_NULL; |
176 | 204k | else if (!fxIsCallable(the, function)) |
177 | 7 | mxTypeError("(proxy).%s: not a function", fxName(the, mxID(index))); |
178 | 914k | return function; |
179 | 914k | } |
180 | | |
181 | | void fxProxyGetter(txMachine* the) |
182 | 95.1k | { |
183 | 95.1k | txSlot* instance = fxToInstance(the, mxThis); |
184 | 206k | while (instance) { |
185 | 206k | if (mxIsProxy(instance)) |
186 | 95.1k | break; |
187 | 111k | instance = fxGetPrototype(the, instance); |
188 | 111k | } |
189 | 95.1k | if (instance) { |
190 | 95.1k | txID id = the->scratch.value.at.id; |
191 | 95.1k | txIndex index = the->scratch.value.at.index; |
192 | 95.1k | fxProxyGetPropertyValue(the, instance, id, index, mxThis, mxResult); |
193 | 95.1k | } |
194 | 95.1k | } |
195 | | |
196 | | void fxProxySetter(txMachine* the) |
197 | 219k | { |
198 | 219k | txSlot* instance = fxToInstance(the, mxThis); |
199 | 508k | while (instance) { |
200 | 508k | if (mxIsProxy(instance)) |
201 | 219k | break; |
202 | 288k | instance = fxGetPrototype(the, instance); |
203 | 288k | } |
204 | 219k | if (instance) { |
205 | 219k | txID id = the->scratch.value.at.id; |
206 | 219k | txIndex index = the->scratch.value.at.index; |
207 | 219k | txBoolean result = fxProxySetPropertyValue(the, instance, id, index, mxArgv(0), mxThis); |
208 | 219k | if (!result) { |
209 | 16 | if (the->frame->next->flag & XS_STRICT_FLAG) |
210 | 8 | mxTypeError("(proxy).set: not extensible or not writable"); |
211 | 16 | } |
212 | 219k | } |
213 | 219k | } |
214 | | |
215 | | void fxProxyCall(txMachine* the, txSlot* instance, txSlot* _this, txSlot* arguments) |
216 | 21.8k | { |
217 | 21.8k | mxProxyDeclarations(_apply); |
218 | 21.8k | if (function) { |
219 | | /* THIS */ |
220 | 3 | mxPushSlot(handler); |
221 | | /* FUNCTION */ |
222 | 3 | mxPushSlot(function); |
223 | 3 | mxCall(); |
224 | | /* ARGUMENTS */ |
225 | 3 | mxPushSlot(target); |
226 | 3 | mxPushSlot(_this); |
227 | 3 | mxPushSlot(arguments); |
228 | 3 | mxRunCount(3); |
229 | 3 | mxPullSlot(mxResult); |
230 | 3 | } |
231 | 21.7k | else |
232 | 21.7k | mxBehaviorCall(the, target->value.reference, _this, arguments); |
233 | 21.8k | mxProxyPop(); |
234 | 21.8k | } |
235 | | |
236 | | void fxProxyConstruct(txMachine* the, txSlot* instance, txSlot* arguments, txSlot* newTarget) |
237 | 12 | { |
238 | 12 | mxProxyDeclarations(_construct); |
239 | 12 | if (function) { |
240 | | /* THIS */ |
241 | 2 | mxPushSlot(handler); |
242 | | /* FUNCTION */ |
243 | 2 | mxPushSlot(function); |
244 | 2 | mxCall(); |
245 | | /* ARGUMENTS */ |
246 | 2 | mxPushSlot(target); |
247 | 2 | mxPushSlot(arguments); |
248 | 2 | mxPushSlot(newTarget); |
249 | 2 | mxRunCount(3); |
250 | 2 | mxPullSlot(mxResult); |
251 | 2 | if (!mxIsReference(mxResult)) |
252 | 1 | mxTypeError("(proxy).construct: not an object"); |
253 | 2 | } |
254 | 10 | else |
255 | 10 | mxBehaviorConstruct(the, target->value.reference, arguments, newTarget); |
256 | 12 | mxProxyPop(); |
257 | 11 | } |
258 | | |
259 | | txBoolean fxProxyDefineOwnProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txSlot* slot, txFlag mask) |
260 | 3.39k | { |
261 | 3.39k | txBoolean result; |
262 | 3.39k | mxProxyDeclarations(_defineProperty); |
263 | 3.39k | if (function) { |
264 | | /* THIS */ |
265 | 3.24k | mxPushSlot(handler); |
266 | | /* FUNCTION */ |
267 | 3.24k | mxPushSlot(function); |
268 | 3.24k | mxCall(); |
269 | | /* ARGUMENTS */ |
270 | 3.24k | mxPushSlot(target); |
271 | 3.24k | mxPushUndefined(); |
272 | 3.24k | fxKeyAt(the, id, index, the->stack); |
273 | 3.24k | fxDescribeProperty(the, slot, mask); |
274 | 3.24k | mxRunCount(3); |
275 | 3.24k | result = fxToBoolean(the, the->stack); |
276 | 3.24k | mxPop(); |
277 | 3.24k | if (result) { |
278 | 2.62k | mxPushUndefined(); |
279 | 2.62k | if (mxBehaviorGetOwnProperty(the, target->value.reference, id, index, the->stack)) { |
280 | 2.61k | if (fxIsPropertyCompatible(the, the->stack, slot, mask)) { |
281 | 2.61k | if ((mask & XS_DONT_DELETE_FLAG) && (slot->flag & XS_DONT_DELETE_FLAG)) { |
282 | 15 | if (!(the->stack->flag & XS_DONT_DELETE_FLAG)) |
283 | 1 | mxTypeError("(proxy).defineProperty: true with non-configurable descriptor for configurable property"); |
284 | 15 | } |
285 | 2.61k | if (the->stack->flag & XS_DONT_DELETE_FLAG) { |
286 | 15 | if ((mask & XS_DONT_SET_FLAG) && (slot->flag & XS_DONT_SET_FLAG) && !(the->stack->flag & XS_DONT_SET_FLAG)) |
287 | 1 | mxTypeError("(proxy).defineProperty: true with non-writable descriptor for non-configurable writable property"); |
288 | 15 | } |
289 | 2.61k | } |
290 | 1 | else |
291 | 1 | mxTypeError("(proxy).defineProperty: true with incompatible descriptor for existent property"); |
292 | 2.61k | } |
293 | 14 | else if (mxBehaviorIsExtensible(the, target->value.reference)) { |
294 | 13 | if ((mask & XS_DONT_DELETE_FLAG) && (slot->flag & XS_DONT_DELETE_FLAG)) |
295 | 1 | mxTypeError("(proxy).defineProperty: true with non-configurable descriptor for non-existent property"); |
296 | 13 | } |
297 | 1 | else |
298 | 1 | mxTypeError("(proxy).defineProperty: true with descriptor for non-existent property of non-extensible object"); |
299 | 2.62k | mxPop(); |
300 | 2.62k | } |
301 | 3.24k | } |
302 | 148 | else |
303 | 148 | result = mxBehaviorDefineOwnProperty(the, target->value.reference, id, index, slot, mask); |
304 | 3.39k | mxProxyPop(); |
305 | 3.38k | return result; |
306 | 3.39k | } |
307 | | |
308 | | txBoolean fxProxyDeleteProperty(txMachine* the, txSlot* instance, txID id, txIndex index) |
309 | 97 | { |
310 | 97 | txBoolean result; |
311 | 97 | mxProxyDeclarations(_deleteProperty); |
312 | 97 | if (function) { |
313 | | /* THIS */ |
314 | 24 | mxPushSlot(handler); |
315 | | /* FUNCTION */ |
316 | 24 | mxPushSlot(function); |
317 | 24 | mxCall(); |
318 | | /* ARGUMENTS */ |
319 | 24 | mxPushSlot(target); |
320 | 24 | mxPushUndefined(); |
321 | 24 | fxKeyAt(the, id, index, the->stack); |
322 | 24 | mxRunCount(2); |
323 | 24 | result = fxToBoolean(the, the->stack); |
324 | 24 | mxPop(); |
325 | 24 | if (result) { |
326 | 17 | mxPushUndefined(); |
327 | 17 | if (mxBehaviorGetOwnProperty(the, target->value.reference, id, index, the->stack)) { |
328 | 5 | if (the->stack->flag & XS_DONT_DELETE_FLAG) |
329 | 1 | mxTypeError("(proxy).deleteProperty: true for non-configurable property"); |
330 | 4 | if (!mxBehaviorIsExtensible(the, target->value.reference)) |
331 | 2 | mxTypeError("(proxy).deleteProperty: true for non-extensible object"); |
332 | 4 | } |
333 | 14 | mxPop(); |
334 | 14 | } |
335 | 24 | } |
336 | 73 | else |
337 | 73 | result = mxBehaviorDeleteProperty(the, target->value.reference, id, index); |
338 | 97 | mxProxyPop(); |
339 | 94 | return result; |
340 | 97 | } |
341 | | |
342 | | txBoolean fxProxyGetOwnProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txSlot* slot) |
343 | 4.94k | { |
344 | 4.94k | txBoolean result; |
345 | 4.94k | mxProxyDeclarations(_getOwnPropertyDescriptor); |
346 | 4.94k | if (function) { |
347 | 1.63k | txFlag mask; |
348 | | /* THIS */ |
349 | 1.63k | mxPushSlot(handler); |
350 | | /* FUNCTION */ |
351 | 1.63k | mxPushSlot(function); |
352 | 1.63k | mxCall(); |
353 | | /* ARGUMENTS */ |
354 | 1.63k | mxPushSlot(target); |
355 | 1.63k | mxPushUndefined(); |
356 | 1.63k | fxKeyAt(the, id, index, the->stack); |
357 | 1.63k | mxRunCount(2); |
358 | 1.63k | mxPullSlot(slot); |
359 | 1.63k | mxPushUndefined(); |
360 | 1.63k | if (slot->kind == XS_UNDEFINED_KIND) { |
361 | 47 | if (mxBehaviorGetOwnProperty(the, target->value.reference, id, index, the->stack)) { |
362 | 22 | if (the->stack->flag & XS_DONT_DELETE_FLAG) |
363 | 2 | mxTypeError("(proxy).getOwnPropertyDescriptor: no descriptor for non-configurable property"); |
364 | 20 | if (!mxBehaviorIsExtensible(the, target->value.reference)) |
365 | 1 | mxTypeError("(proxy).getOwnPropertyDescriptor: no descriptor for existent property of non-extensible object"); |
366 | 20 | } |
367 | 44 | result = 0; |
368 | 44 | } |
369 | 1.58k | else { |
370 | 1.58k | mask = fxDescriptorToSlot(the, slot); |
371 | 1.58k | if (!(mask & XS_DONT_DELETE_FLAG)) { |
372 | 3 | mask |= XS_DONT_DELETE_FLAG; |
373 | 3 | slot->flag |= XS_DONT_DELETE_FLAG; |
374 | 3 | } |
375 | 1.58k | if (!(mask & XS_DONT_ENUM_FLAG)) { |
376 | 10 | mask |= XS_DONT_ENUM_FLAG; |
377 | 10 | slot->flag |= XS_DONT_ENUM_FLAG; |
378 | 10 | } |
379 | 1.58k | if (!(mask & (XS_GETTER_FLAG | XS_SETTER_FLAG))) { |
380 | 59 | if (!(mask & XS_DONT_SET_FLAG)) { |
381 | 5 | mask |= XS_DONT_SET_FLAG; |
382 | 5 | slot->flag |= XS_DONT_SET_FLAG; |
383 | 5 | } |
384 | 59 | if (slot->kind == XS_UNINITIALIZED_KIND) |
385 | 4 | slot->kind = XS_UNDEFINED_KIND; |
386 | 59 | } |
387 | 1.58k | if (mxBehaviorGetOwnProperty(the, target->value.reference, id, index, the->stack)) { |
388 | 38 | if (fxIsPropertyCompatible(the, the->stack, slot, mask)) { |
389 | 37 | if ((mask & XS_DONT_DELETE_FLAG) && (slot->flag & XS_DONT_DELETE_FLAG)) { |
390 | 14 | if (!(the->stack->flag & XS_DONT_DELETE_FLAG)) |
391 | 1 | mxTypeError("(proxy).getOwnPropertyDescriptor: non-configurable descriptor for configurable property"); |
392 | 14 | } |
393 | 36 | if (the->stack->flag & XS_DONT_DELETE_FLAG) { |
394 | 13 | if ((mask & XS_DONT_SET_FLAG) && (slot->flag & XS_DONT_SET_FLAG) && !(the->stack->flag & XS_DONT_SET_FLAG)) |
395 | 1 | mxTypeError("(proxy).getOwnPropertyDescriptor: true with non-writable descriptor for non-configurable writable property"); |
396 | 13 | } |
397 | 36 | } |
398 | 1 | else |
399 | 1 | mxTypeError("(proxy).getOwnPropertyDescriptor: incompatible descriptor for existent property"); |
400 | 38 | } |
401 | 1.55k | else if (mxBehaviorIsExtensible(the, target->value.reference)) { |
402 | 20 | if ((mask & XS_DONT_DELETE_FLAG) && (slot->flag & XS_DONT_DELETE_FLAG)) |
403 | 1 | mxTypeError("(proxy).getOwnPropertyDescriptor: non-configurable descriptor for non-existent property"); |
404 | 20 | } |
405 | 1.53k | else |
406 | 1.53k | mxTypeError("(proxy).getOwnPropertyDescriptor: descriptor for non-existent property of non-extensible object"); |
407 | 54 | result = 1; |
408 | 54 | } |
409 | 98 | mxPop(); |
410 | 98 | } |
411 | 3.31k | else |
412 | 3.31k | result = mxBehaviorGetOwnProperty(the, target->value.reference, id, index, slot); |
413 | 4.94k | mxProxyPop(); |
414 | 3.40k | return result; |
415 | 4.94k | } |
416 | | |
417 | | txSlot* fxProxyGetProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txFlag flag) |
418 | 309k | { |
419 | 309k | the->scratch.value.at.id = id; |
420 | 309k | the->scratch.value.at.index = index; |
421 | 309k | return &mxProxyAccessor; |
422 | 309k | } |
423 | | |
424 | | txBoolean fxProxyGetPropertyValue(txMachine* the, txSlot* instance, txID id, txIndex index, txSlot* receiver, txSlot* slot) |
425 | 95.2k | { |
426 | 95.2k | txBoolean result; |
427 | 95.2k | mxProxyDeclarations(_get); |
428 | 95.2k | if (function) { |
429 | | /* THIS */ |
430 | 1.92k | mxPushSlot(handler); |
431 | | /* FUNCTION */ |
432 | 1.92k | mxPushSlot(function); |
433 | 1.92k | mxCall(); |
434 | | /* ARGUMENTS */ |
435 | 1.92k | mxPushSlot(target); |
436 | 1.92k | mxPushUndefined(); |
437 | 1.92k | fxKeyAt(the, id, index, the->stack); |
438 | 1.92k | mxPushSlot(receiver); |
439 | 1.92k | mxRunCount(3); |
440 | 1.92k | mxPullSlot(slot); |
441 | 1.92k | mxPushUndefined(); |
442 | 1.92k | if (mxBehaviorGetOwnProperty(the, target->value.reference, id, index, the->stack)) { |
443 | 154 | txSlot* property = the->stack; |
444 | 154 | if (property->flag & XS_DONT_DELETE_FLAG) { |
445 | 109 | if (property->kind == XS_ACCESSOR_KIND) { |
446 | 9 | if ((property->value.accessor.getter == C_NULL) && (slot->kind != XS_UNDEFINED_KIND)) |
447 | 6 | mxTypeError("(proxy).get: different getter for non-configurable property"); |
448 | 9 | } |
449 | 100 | else { |
450 | 100 | if ((property->flag & XS_DONT_SET_FLAG) && (!fxIsSameValue(the, property, slot, 0))) |
451 | 3 | mxTypeError("(proxy).get: different value for non-configurable, non-writable property"); |
452 | 100 | } |
453 | 109 | } |
454 | 154 | } |
455 | 1.91k | result = 1; |
456 | 1.91k | mxPop(); |
457 | 1.91k | } |
458 | 93.3k | else |
459 | 93.3k | result = mxBehaviorGetPropertyValue(the, target->value.reference, id, index, receiver, slot); |
460 | 95.2k | mxProxyPop(); |
461 | 95.2k | return result; |
462 | 95.2k | } |
463 | | |
464 | | txBoolean fxProxyGetPrototype(txMachine* the, txSlot* instance, txSlot* slot) |
465 | 4.51k | { |
466 | 4.51k | txBoolean result; |
467 | 4.51k | mxProxyDeclarations(_getPrototypeOf); |
468 | 4.51k | if (function) { |
469 | | /* THIS */ |
470 | 8 | mxPushSlot(handler); |
471 | | /* FUNCTION */ |
472 | 8 | mxPushSlot(function); |
473 | 8 | mxCall(); |
474 | | /* ARGUMENTS */ |
475 | 8 | mxPushSlot(target); |
476 | 8 | mxRunCount(1); |
477 | 8 | mxPullSlot(slot); |
478 | 8 | if ((slot->kind == XS_NULL_KIND) || (slot->kind == XS_REFERENCE_KIND)) { |
479 | 6 | if (!mxBehaviorIsExtensible(the, target->value.reference)) { |
480 | 3 | mxPushUndefined(); |
481 | 3 | mxBehaviorGetPrototype(the, target->value.reference, the->stack); |
482 | 3 | if (!fxIsSameValue(the, slot, the->stack, 0)) |
483 | 1 | mxTypeError("(proxy).getPrototypeOf: different prototype for non-extensible object"); |
484 | 2 | mxPop(); |
485 | 2 | } |
486 | 6 | } |
487 | 2 | else |
488 | 2 | mxTypeError("(proxy).getPrototypeOf: neither object nor null"); |
489 | 5 | result = (slot->kind == XS_NULL_KIND) ? 0 : 1; |
490 | 5 | } |
491 | 4.50k | else |
492 | 4.50k | result = mxBehaviorGetPrototype(the, target->value.reference, slot); |
493 | 4.51k | mxProxyPop(); |
494 | 4.51k | return result; |
495 | 4.51k | } |
496 | | |
497 | | txBoolean fxProxyHasProperty(txMachine* the, txSlot* instance, txID id, txIndex index) |
498 | 550k | { |
499 | 550k | txBoolean result; |
500 | 550k | mxProxyDeclarations(_has); |
501 | 550k | if (function) { |
502 | | /* THIS */ |
503 | 123k | mxPushSlot(handler); |
504 | | /* FUNCTION */ |
505 | 123k | mxPushSlot(function); |
506 | 123k | mxCall(); |
507 | | /* ARGUMENTS */ |
508 | 123k | mxPushSlot(target); |
509 | 123k | mxPushUndefined(); |
510 | 123k | fxKeyAt(the, id, index, the->stack); |
511 | 123k | mxRunCount(2); |
512 | 123k | result = fxToBoolean(the, the->stack); |
513 | 123k | mxPop(); |
514 | 123k | if (!result) { |
515 | 39.3k | mxPushUndefined(); |
516 | 39.3k | if (mxBehaviorGetOwnProperty(the, target->value.reference, id, index, the->stack)) { |
517 | 9 | if (the->stack->flag & XS_DONT_DELETE_FLAG) |
518 | 1 | mxTypeError("(proxy).has: false for non-configurable property"); |
519 | 8 | if (!mxBehaviorIsExtensible(the, target->value.reference)) |
520 | 1 | mxTypeError("(proxy).has: false for property of not extensible object"); |
521 | 8 | } |
522 | 39.3k | mxPop(); |
523 | 39.3k | } |
524 | 123k | } |
525 | 426k | else |
526 | 426k | result = mxBehaviorHasProperty(the, target->value.reference, id, index); |
527 | 550k | mxProxyPop(); |
528 | 550k | return result; |
529 | 550k | } |
530 | | |
531 | | txBoolean fxProxyIsExtensible(txMachine* the, txSlot* instance) |
532 | 45 | { |
533 | 45 | txBoolean result; |
534 | 45 | mxProxyDeclarations(_isExtensible); |
535 | 45 | if (function) { |
536 | | /* THIS */ |
537 | 15 | mxPushSlot(handler); |
538 | | /* FUNCTION */ |
539 | 15 | mxPushSlot(function); |
540 | 15 | mxCall(); |
541 | | /* ARGUMENTS */ |
542 | 15 | mxPushSlot(target); |
543 | 15 | mxRunCount(1); |
544 | 15 | result = fxToBoolean(the, the->stack); |
545 | 15 | mxPop(); |
546 | 15 | if (mxBehaviorIsExtensible(the, target->value.reference)) { |
547 | 12 | if (!result) |
548 | 1 | mxTypeError("(proxy).isExtensible: false for extensible object"); |
549 | 12 | } |
550 | 3 | else { |
551 | 3 | if (result) |
552 | 1 | mxTypeError("(proxy).isExtensible: true for non-extensible object"); |
553 | 3 | } |
554 | 15 | } |
555 | 30 | else |
556 | 30 | result = mxBehaviorIsExtensible(the, target->value.reference); |
557 | 45 | mxProxyPop(); |
558 | 43 | return result; |
559 | 45 | } |
560 | | |
561 | | void fxProxyOwnKeys(txMachine* the, txSlot* instance, txFlag flag, txSlot* list) |
562 | 14.6k | { |
563 | 14.6k | mxProxyDeclarations(_ownKeys); |
564 | 14.6k | if (function) { |
565 | 42 | txIndex length; |
566 | 42 | txSlot* reference; |
567 | 42 | txSlot* item; |
568 | 42 | txIndex index; |
569 | 42 | txSlot* at; |
570 | 42 | txBoolean test; |
571 | 42 | txSlot* property; |
572 | | /* THIS */ |
573 | 42 | mxPushSlot(handler); |
574 | | /* FUNCTION */ |
575 | 42 | mxPushSlot(function); |
576 | 42 | mxCall(); |
577 | | /* ARGUMENTS */ |
578 | 42 | mxPushSlot(target); |
579 | 42 | mxRunCount(1); |
580 | 42 | reference = the->stack; |
581 | 42 | mxPushSlot(reference); |
582 | 42 | mxGetID(mxID(_length)); |
583 | 42 | length = fxToInteger(the, the->stack++); |
584 | 42 | item = list; |
585 | 42 | index = 0; |
586 | 134 | while (index < length) { |
587 | 100 | mxPushSlot(reference); |
588 | 100 | mxGetIndex(index); |
589 | 100 | at = the->stack; |
590 | 100 | test = (at->kind == XS_SYMBOL_KIND) ? 1 : 0; |
591 | 100 | if (test || (at->kind == XS_STRING_KIND) || (at->kind == XS_STRING_X_KIND)) { |
592 | 99 | fxAt(the, at); |
593 | 99 | property = list; |
594 | 198 | while ((property = property->next)) { |
595 | 106 | if ((at->value.at.id == property->value.at.id) && (at->value.at.index == property->value.at.index)) |
596 | 7 | break; |
597 | 106 | } |
598 | 99 | if (property) |
599 | 7 | mxTypeError("(proxy).ownKeys: duplicate key"); |
600 | 92 | item = item->next = fxNewSlot(the); |
601 | 92 | mxPullSlot(item); |
602 | 92 | if (test) |
603 | 10 | item->flag |= XS_INTERNAL_FLAG; |
604 | 92 | } |
605 | 1 | else |
606 | 1 | mxTypeError("(proxy).ownKeys: key is neither string nor symbol"); |
607 | 92 | index++; |
608 | 92 | } |
609 | 34 | mxPop(); |
610 | | |
611 | 34 | test = mxBehaviorIsExtensible(the, target->value.reference) ? 1 : 0; |
612 | 34 | at = fxNewInstance(the); |
613 | 34 | mxBehaviorOwnKeys(the, target->value.reference, XS_EACH_NAME_FLAG | XS_EACH_SYMBOL_FLAG, at); |
614 | 34 | mxPushUndefined(); |
615 | 34 | property = the->stack; |
616 | 47 | while ((at = at->next)) { |
617 | 17 | mxBehaviorGetOwnProperty(the, target->value.reference, at->value.at.id, at->value.at.index, property); |
618 | 17 | item = list; |
619 | 34 | while ((item = item->next)) { |
620 | 26 | if ((at->value.at.id == item->value.at.id) && (at->value.at.index == item->value.at.index)) { |
621 | 9 | length--; |
622 | 9 | break; |
623 | 9 | } |
624 | 26 | } |
625 | 17 | if (!item) { |
626 | 8 | if (property->flag & XS_DONT_DELETE_FLAG) |
627 | 2 | mxTypeError("(proxy).ownKeys: no key for non-configurable property"); |
628 | 6 | if (!test) |
629 | 2 | mxTypeError("(proxy).ownKeys: no key for property of non-extensible object"); |
630 | 6 | } |
631 | 17 | } |
632 | 30 | if (!test && length) |
633 | 2 | mxTypeError("(proxy).ownKeys: key for non-existent property of non-extensible object"); |
634 | 28 | mxPop(); |
635 | 28 | mxPop(); |
636 | | |
637 | 28 | item = list; |
638 | 85 | while ((property = item->next)) { |
639 | 57 | if (property->flag & XS_INTERNAL_FLAG) { |
640 | 6 | property->flag &= ~XS_INTERNAL_FLAG; |
641 | 6 | if (flag & XS_EACH_SYMBOL_FLAG) |
642 | 5 | item = property; |
643 | 1 | else |
644 | 1 | item->next = property->next; |
645 | 6 | } |
646 | 51 | else { |
647 | 51 | if (flag & XS_EACH_NAME_FLAG) |
648 | 44 | item = property; |
649 | 7 | else |
650 | 7 | item->next = property->next; |
651 | 51 | } |
652 | 57 | } |
653 | 28 | } |
654 | 14.5k | else |
655 | 14.5k | mxBehaviorOwnKeys(the, target->value.reference, flag, list); |
656 | 14.6k | mxProxyPop(); |
657 | 14.6k | } |
658 | | |
659 | | txBoolean fxProxyPreventExtensions(txMachine* the, txSlot* instance) |
660 | 24 | { |
661 | 24 | txBoolean result; |
662 | 24 | mxProxyDeclarations(_preventExtensions); |
663 | 24 | if (function) { |
664 | | /* THIS */ |
665 | 8 | mxPushSlot(handler); |
666 | | /* FUNCTION */ |
667 | 8 | mxPushSlot(function); |
668 | 8 | mxCall(); |
669 | | /* ARGUMENTS */ |
670 | 8 | mxPushSlot(target); |
671 | 8 | mxRunCount(1); |
672 | 8 | result = fxToBoolean(the, the->stack); |
673 | 8 | mxPop(); |
674 | 8 | if (result) { |
675 | 2 | if (mxBehaviorIsExtensible(the, target->value.reference)) |
676 | 1 | mxTypeError("(proxy).preventExtensions: true for extensible object"); |
677 | 2 | } |
678 | 8 | } |
679 | 16 | else |
680 | 16 | result = mxBehaviorPreventExtensions(the, target->value.reference); |
681 | 24 | mxProxyPop(); |
682 | 23 | return result; |
683 | 24 | } |
684 | | |
685 | | txSlot* fxProxySetProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txFlag flag) |
686 | 4.81k | { |
687 | 4.81k | the->scratch.value.at.id = id; |
688 | 4.81k | the->scratch.value.at.index = index; |
689 | 4.81k | return &mxProxyAccessor; |
690 | 4.81k | } |
691 | | |
692 | | txBoolean fxProxySetPropertyValue(txMachine* the, txSlot* instance, txID id, txIndex index, txSlot* slot, txSlot* receiver) |
693 | 219k | { |
694 | 219k | txBoolean result; |
695 | 219k | mxProxyDeclarations(_set); |
696 | 219k | if (function) { |
697 | | /* THIS */ |
698 | 73.6k | mxPushSlot(handler); |
699 | | /* FUNCTION */ |
700 | 73.6k | mxPushSlot(function); |
701 | 73.6k | mxCall(); |
702 | | /* ARGUMENTS */ |
703 | 73.6k | mxPushSlot(target); |
704 | 73.6k | mxPushUndefined(); |
705 | 73.6k | fxKeyAt(the, id, index, the->stack); |
706 | 73.6k | mxPushSlot(slot); |
707 | 73.6k | mxPushSlot(receiver); |
708 | 73.6k | mxRunCount(4); |
709 | 73.6k | result = fxToBoolean(the, the->stack); |
710 | 73.6k | mxPop(); |
711 | 73.6k | if (result) { |
712 | 72.0k | mxPushUndefined(); |
713 | 72.0k | if (mxBehaviorGetOwnProperty(the, target->value.reference, id, index, the->stack)) { |
714 | 9 | txSlot* property = the->stack; |
715 | 9 | if (property->flag & XS_DONT_DELETE_FLAG) { |
716 | 8 | if (property->kind == XS_ACCESSOR_KIND) { |
717 | 4 | if (property->value.accessor.setter == C_NULL) |
718 | 3 | mxTypeError("(proxy).set: true for non-configurable property with different setter"); |
719 | 4 | } |
720 | 4 | else { |
721 | 4 | if ((property->flag & XS_DONT_SET_FLAG) && (!fxIsSameValue(the, property, slot, 0))) |
722 | 3 | mxTypeError("(proxy).set: true for non-configurable, non-writable property with different value"); |
723 | 4 | } |
724 | 8 | } |
725 | 9 | } |
726 | 72.0k | mxPop(); |
727 | 72.0k | } |
728 | 73.6k | } |
729 | 146k | else |
730 | 146k | result = mxBehaviorSetPropertyValue(the, target->value.reference, id, index, slot, receiver); |
731 | 219k | mxProxyPop(); |
732 | 219k | return result; |
733 | 219k | } |
734 | | |
735 | | txBoolean fxProxySetPrototype(txMachine* the, txSlot* instance, txSlot* prototype) |
736 | 56 | { |
737 | 56 | txBoolean result; |
738 | 56 | mxProxyDeclarations(_setPrototypeOf); |
739 | 56 | if (function) { |
740 | | /* THIS */ |
741 | 33 | mxPushSlot(handler); |
742 | | /* FUNCTION */ |
743 | 33 | mxPushSlot(function); |
744 | 33 | mxCall(); |
745 | | /* ARGUMENTS */ |
746 | 33 | mxPushSlot(target); |
747 | 33 | mxPushSlot(prototype); |
748 | 33 | mxRunCount(2); |
749 | 33 | result = fxToBoolean(the, the->stack); |
750 | 33 | mxPop(); |
751 | 33 | if (result) { |
752 | 23 | if (!mxBehaviorIsExtensible(the, target->value.reference)) { |
753 | 7 | mxPushUndefined(); |
754 | 7 | mxBehaviorGetPrototype(the, target->value.reference, the->stack); |
755 | 7 | if (!fxIsSameValue(the, prototype, the->stack, 0)) |
756 | 3 | mxTypeError("(proxy).setPrototypeOf: true for non-extensible object with different prototype"); |
757 | 4 | mxPop(); |
758 | 4 | } |
759 | 23 | } |
760 | 33 | } |
761 | 23 | else |
762 | 23 | result = mxBehaviorSetPrototype(the, target->value.reference, prototype); |
763 | 56 | mxProxyPop(); |
764 | 53 | return result; |
765 | 56 | } |
766 | | |
767 | | void fx_Proxy(txMachine* the) |
768 | 631k | { |
769 | 631k | txSlot* instance; |
770 | 631k | txSlot* proxy; |
771 | 631k | txSlot* target; |
772 | 631k | txSlot* handler; |
773 | 631k | if (mxIsUndefined(mxTarget)) |
774 | 1 | mxTypeError("call: Proxy"); |
775 | 631k | mxPushUndefined(); |
776 | 631k | instance = fxNewProxyInstance(the); |
777 | 631k | mxPullSlot(mxResult); |
778 | 631k | proxy = instance->next; |
779 | 631k | if (!proxy || (proxy->kind != XS_PROXY_KIND)) |
780 | 0 | mxTypeError("this: not a Proxy instance"); |
781 | | #if mxHostFunctionPrimitive |
782 | | if ((mxArgc > 0) && (mxArgv(0)->kind == XS_HOST_FUNCTION_KIND)) |
783 | | fxToInstance(the, mxArgv(0)); |
784 | | if ((mxArgc > 1) && (mxArgv(1)->kind == XS_HOST_FUNCTION_KIND)) |
785 | | fxToInstance(the, mxArgv(1)); |
786 | | #endif |
787 | 631k | if ((mxArgc < 1) || (mxArgv(0)->kind != XS_REFERENCE_KIND)) |
788 | 3 | mxTypeError("target: not an object"); |
789 | 631k | target = mxArgv(0)->value.reference; |
790 | 631k | if ((mxArgc < 2) || (mxArgv(1)->kind != XS_REFERENCE_KIND)) |
791 | 2 | mxTypeError("handler: not an object"); |
792 | 631k | handler = mxArgv(1)->value.reference; |
793 | 631k | instance->flag |= target->flag & (XS_CAN_CALL_FLAG | XS_CAN_CONSTRUCT_FLAG); |
794 | 631k | proxy->value.proxy.target = target; |
795 | 631k | proxy->value.proxy.handler = handler; |
796 | 631k | } |
797 | | |
798 | | void fx_Proxy_revocable(txMachine* the) |
799 | 92.8k | { |
800 | 92.8k | txSlot* target; |
801 | 92.8k | txSlot* handler; |
802 | 92.8k | txSlot* property; |
803 | 92.8k | txSlot* instance; |
804 | 92.8k | txSlot* slot; |
805 | | |
806 | | #if mxHostFunctionPrimitive |
807 | | if ((mxArgc > 0) && (mxArgv(0)->kind == XS_HOST_FUNCTION_KIND)) |
808 | | fxToInstance(the, mxArgv(0)); |
809 | | if ((mxArgc > 1) && (mxArgv(1)->kind == XS_HOST_FUNCTION_KIND)) |
810 | | fxToInstance(the, mxArgv(1)); |
811 | | #endif |
812 | 92.8k | if ((mxArgc < 1) || (mxArgv(0)->kind != XS_REFERENCE_KIND)) |
813 | 2 | mxTypeError("target: not an object"); |
814 | 92.8k | target = mxArgv(0)->value.reference; |
815 | 92.8k | if ((mxArgc < 2) || (mxArgv(1)->kind != XS_REFERENCE_KIND)) |
816 | 2 | mxTypeError("handler: not an object"); |
817 | 92.8k | handler = mxArgv(1)->value.reference; |
818 | | |
819 | 92.8k | mxPush(mxObjectPrototype); |
820 | 92.8k | property = fxLastProperty(the, fxNewObjectInstance(the)); |
821 | 92.8k | mxPullSlot(mxResult); |
822 | | |
823 | 92.8k | mxPushUndefined(); |
824 | 92.8k | instance = fxNewProxyInstance(the); |
825 | 92.8k | instance->flag |= target->flag & (XS_CAN_CALL_FLAG | XS_CAN_CONSTRUCT_FLAG); |
826 | 92.8k | slot = instance->next; |
827 | 92.8k | slot->value.proxy.target = target; |
828 | 92.8k | slot->value.proxy.handler = handler; |
829 | 92.8k | property = fxNextSlotProperty(the, property, the->stack, mxID(_proxy), XS_GET_ONLY); |
830 | | |
831 | 92.8k | slot = fxLastProperty(the, fxNewHostFunction(the, mxCallback(fx_Proxy_revoke), 0, XS_NO_ID, XS_NO_ID)); |
832 | 92.8k | slot = fxNextSlotProperty(the, slot, the->stack + 1, mxID(_proxy), XS_GET_ONLY); |
833 | 92.8k | property = fxNextSlotProperty(the, property, the->stack, mxID(_revoke), XS_GET_ONLY); |
834 | | |
835 | 92.8k | the->stack += 2; |
836 | 92.8k | } |
837 | | |
838 | | void fx_Proxy_revoke(txMachine* the) |
839 | 753 | { |
840 | 753 | txSlot* property = mxBehaviorGetProperty(the, mxFunction->value.reference, mxID(_proxy), 0, XS_ANY); |
841 | 753 | if (property && (property->kind == XS_REFERENCE_KIND)) { |
842 | 36 | txSlot* instance = property->value.reference; |
843 | 36 | txSlot* proxy = instance->next; |
844 | 36 | if (!proxy || (proxy->kind != XS_PROXY_KIND)) |
845 | 0 | mxTypeError("(proxy).revoke: not a Proxy instance"); |
846 | 36 | if (proxy->flag & XS_MARK_FLAG) |
847 | 0 | mxTypeError("(proxy).revoke: read-only Proxy instance"); |
848 | 36 | proxy->value.proxy.target = C_NULL; |
849 | 36 | proxy->value.proxy.handler = C_NULL; |
850 | 36 | property->kind = XS_NULL_KIND; |
851 | 36 | } |
852 | 753 | } |
853 | | |
854 | | void fx_Reflect_apply(txMachine* the) |
855 | 56.2k | { |
856 | 56.2k | if ((mxArgc < 1) || !(fxIsCallable(the, mxArgv(0)))) |
857 | 14 | mxTypeError("target: not a function"); |
858 | 56.2k | if ((mxArgc < 3) || (mxArgv(2)->kind != XS_REFERENCE_KIND)) |
859 | 2 | mxTypeError("argumentsList: not an object"); |
860 | 56.2k | mxBehaviorCall(the, fxToInstance(the, mxArgv(0)), mxArgv(1), mxArgv(2)); |
861 | 56.2k | } |
862 | | |
863 | | void fx_Reflect_construct(txMachine* the) |
864 | 145 | { |
865 | 145 | txSlot* target; |
866 | 145 | if ((mxArgc < 1) || !mxIsReference(mxArgv(0)) || !mxIsConstructor(mxArgv(0)->value.reference)) |
867 | 21 | mxTypeError("target: not a constructor"); |
868 | 124 | if ((mxArgc < 2) || (mxArgv(1)->kind != XS_REFERENCE_KIND)) |
869 | 2 | mxTypeError("argumentsList: not an object"); |
870 | 122 | if (mxArgc < 3) |
871 | 5 | target = mxArgv(0); |
872 | 117 | else if (!mxIsReference(mxArgv(2)) || !mxIsConstructor(mxArgv(2)->value.reference)) |
873 | 21 | mxTypeError("newTarget: not a constructor"); |
874 | 96 | else |
875 | 96 | target = mxArgv(2); |
876 | 101 | mxBehaviorConstruct(the, fxToInstance(the, mxArgv(0)), mxArgv(1), target); |
877 | 101 | } |
878 | | |
879 | | void fx_Reflect_defineProperty(txMachine* the) |
880 | 2.66k | { |
881 | 2.66k | txSlot* at; |
882 | 2.66k | txFlag mask; |
883 | 2.66k | if ((mxArgc < 1) || (mxArgv(0)->kind != XS_REFERENCE_KIND)) |
884 | 10 | mxTypeError("target: not an object"); |
885 | 2.65k | if (mxArgc < 2) |
886 | 1 | mxTypeError("no key"); |
887 | 2.65k | at = fxAt(the, mxArgv(1)); |
888 | 2.65k | if ((mxArgc < 3) || (mxArgv(2)->kind != XS_REFERENCE_KIND)) |
889 | 2 | mxTypeError("invalid descriptor"); |
890 | 2.65k | mask = fxDescriptorToSlot(the, mxArgv(2)); |
891 | 2.65k | mxResult->value.boolean = mxBehaviorDefineOwnProperty(the, mxArgv(0)->value.reference, at->value.at.id, at->value.at.index, mxArgv(2), mask); |
892 | 2.65k | mxResult->kind = XS_BOOLEAN_KIND; |
893 | 2.65k | } |
894 | | |
895 | | void fx_Reflect_deleteProperty(txMachine* the) |
896 | 901 | { |
897 | 901 | txSlot* at; |
898 | 901 | if ((mxArgc < 1) || (mxArgv(0)->kind != XS_REFERENCE_KIND)) |
899 | 861 | mxTypeError("target: not an object"); |
900 | 40 | if (mxArgc < 2) |
901 | 0 | mxTypeError("no key"); |
902 | 40 | at = fxAt(the, mxArgv(1)); |
903 | 40 | mxResult->value.boolean = mxBehaviorDeleteProperty(the, mxArgv(0)->value.reference, at->value.at.id, at->value.at.index); |
904 | 40 | mxResult->kind = XS_BOOLEAN_KIND; |
905 | 40 | } |
906 | | |
907 | | void fx_Reflect_get(txMachine* the) |
908 | 871 | { |
909 | 871 | txSlot* at; |
910 | 871 | if ((mxArgc < 1) || (mxArgv(0)->kind != XS_REFERENCE_KIND)) |
911 | 12 | mxTypeError("target: not an object"); |
912 | 859 | if (mxArgc < 2) |
913 | 0 | mxTypeError("no key"); |
914 | 859 | at = fxAt(the, mxArgv(1)); |
915 | 859 | mxBehaviorGetPropertyValue(the, mxArgv(0)->value.reference, at->value.at.id, at->value.at.index, mxArgc < 3 ? mxArgv(0) : mxArgv(2), mxResult); |
916 | 859 | } |
917 | | |
918 | | void fx_Reflect_getOwnPropertyDescriptor(txMachine* the) |
919 | 60 | { |
920 | 60 | txSlot* at; |
921 | 60 | if ((mxArgc < 1) || (mxArgv(0)->kind != XS_REFERENCE_KIND)) |
922 | 11 | mxTypeError("target: not an object"); |
923 | 49 | if (mxArgc < 2) |
924 | 0 | mxTypeError("no key"); |
925 | 49 | at = fxAt(the, mxArgv(1)); |
926 | 49 | mxPushUndefined(); |
927 | 49 | if (mxBehaviorGetOwnProperty(the, mxArgv(0)->value.reference, at->value.at.id, at->value.at.index, the->stack)) { |
928 | 36 | fxDescribeProperty(the, the->stack, XS_GET_ONLY); |
929 | 36 | mxPullSlot(mxResult); |
930 | 36 | } |
931 | 49 | mxPop(); |
932 | 49 | } |
933 | | |
934 | | void fx_Reflect_getPrototypeOf(txMachine* the) |
935 | 13 | { |
936 | 13 | if ((mxArgc < 1) || (mxArgv(0)->kind != XS_REFERENCE_KIND)) |
937 | 10 | mxTypeError("target: not an object"); |
938 | 3 | mxBehaviorGetPrototype(the, mxArgv(0)->value.reference, mxResult); |
939 | 3 | } |
940 | | |
941 | | void fx_Reflect_has(txMachine* the) |
942 | 80.7k | { |
943 | 80.7k | txSlot* at; |
944 | 80.7k | if ((mxArgc < 1) || (mxArgv(0)->kind != XS_REFERENCE_KIND)) |
945 | 10 | mxTypeError("target: not an object"); |
946 | 80.7k | if (mxArgc < 2) |
947 | 0 | mxTypeError("no key"); |
948 | 80.7k | at = fxAt(the, mxArgv(1)); |
949 | 80.7k | mxResult->value.boolean = mxBehaviorHasProperty(the, mxArgv(0)->value.reference, at->value.at.id, at->value.at.index); |
950 | 80.7k | mxResult->kind = XS_BOOLEAN_KIND; |
951 | 80.7k | } |
952 | | |
953 | | void fx_Reflect_isExtensible(txMachine* the) |
954 | 15 | { |
955 | 15 | if ((mxArgc < 1) || (mxArgv(0)->kind != XS_REFERENCE_KIND)) |
956 | 11 | mxTypeError("target: not an object"); |
957 | 4 | mxResult->value.boolean = mxBehaviorIsExtensible(the, mxArgv(0)->value.reference); |
958 | 4 | mxResult->kind = XS_BOOLEAN_KIND; |
959 | 4 | } |
960 | | |
961 | | void fx_Reflect_ownKeys(txMachine* the) |
962 | 27 | { |
963 | 27 | txSlot* result; |
964 | 27 | txSlot* array; |
965 | 27 | txSlot* item; |
966 | 27 | if ((mxArgc < 1) || (mxArgv(0)->kind != XS_REFERENCE_KIND)) |
967 | 10 | mxTypeError("target: not an object"); |
968 | 17 | mxPush(mxArrayPrototype); |
969 | 17 | result = fxNewArrayInstance(the); |
970 | 17 | mxPullSlot(mxResult); |
971 | 17 | array = result->next; |
972 | 17 | mxBehaviorOwnKeys(the, mxArgv(0)->value.reference, XS_EACH_NAME_FLAG | XS_EACH_SYMBOL_FLAG, array); |
973 | 17 | item = array; |
974 | 63 | while ((item = item->next)) { |
975 | 46 | array->value.array.length++; |
976 | 46 | fxKeyAt(the, item->value.at.id, item->value.at.index, item); |
977 | 46 | } |
978 | 17 | fxCacheArray(the, result); |
979 | 17 | } |
980 | | |
981 | | void fx_Reflect_preventExtensions(txMachine* the) |
982 | 22 | { |
983 | 22 | if ((mxArgc < 1) || (mxArgv(0)->kind != XS_REFERENCE_KIND)) |
984 | 10 | mxTypeError("target: not an object"); |
985 | 12 | mxResult->value.boolean = mxBehaviorPreventExtensions(the, mxArgv(0)->value.reference); |
986 | 12 | mxResult->kind = XS_BOOLEAN_KIND; |
987 | 12 | } |
988 | | |
989 | | void fx_Reflect_set(txMachine* the) |
990 | 55 | { |
991 | 55 | txSlot* at; |
992 | 55 | if ((mxArgc < 1) || (mxArgv(0)->kind != XS_REFERENCE_KIND)) |
993 | 10 | mxTypeError("target: not an object"); |
994 | 45 | if (mxArgc < 2) |
995 | 1 | mxTypeError("no key"); |
996 | 44 | at = fxAt(the, mxArgv(1)); |
997 | 44 | if (mxArgc < 3) |
998 | 1 | mxPushUndefined(); |
999 | 43 | else |
1000 | 43 | mxPushSlot(mxArgv(2)); |
1001 | 44 | mxResult->value.boolean = mxBehaviorSetPropertyValue(the, mxArgv(0)->value.reference, at->value.at.id, at->value.at.index, the->stack, mxArgc < 4 ? mxArgv(0) : mxArgv(3)); |
1002 | 44 | mxResult->kind = XS_BOOLEAN_KIND; |
1003 | 44 | mxPop(); |
1004 | 44 | } |
1005 | | |
1006 | | void fx_Reflect_setPrototypeOf(txMachine* the) |
1007 | 81 | { |
1008 | 81 | if ((mxArgc < 1) || (mxArgv(0)->kind != XS_REFERENCE_KIND)) |
1009 | 13 | mxTypeError("target: not an object"); |
1010 | 68 | if ((mxArgc < 2) || ((mxArgv(1)->kind != XS_NULL_KIND) && (mxArgv(1)->kind != XS_REFERENCE_KIND))) |
1011 | 10 | mxTypeError("invalid prototype"); |
1012 | 58 | mxResult->value.boolean = mxBehaviorSetPrototype(the, mxArgv(0)->value.reference, mxArgv(1)); |
1013 | 58 | mxResult->kind = XS_BOOLEAN_KIND; |
1014 | 58 | } |