/src/moddable/xs/sources/xsLockdown.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2020-2022 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 | | #include "xsScript.h" |
40 | | |
41 | | void fxSetHostFunctionProperty(txMachine* the, txSlot* property, txCallback call, txInteger length, txID id) |
42 | 63 | { |
43 | 63 | txSlot* home = the->stack; |
44 | 63 | txSlot* function = fxNewHostFunction(the, call, length, id, XS_NO_ID); |
45 | 63 | txSlot* slot = mxFunctionInstanceHome(function); |
46 | 63 | slot->value.home.object = home->value.reference; |
47 | 63 | property->kind = the->stack->kind; |
48 | 63 | property->value = the->stack->value; |
49 | 63 | mxPop(); |
50 | 63 | } |
51 | | |
52 | | static void fx_lockdown_aux(txMachine* the, txInteger length, txSlot* prototype, txSlot* slot) |
53 | 126 | { |
54 | 126 | if (slot) { |
55 | 126 | txSlot* constructor; |
56 | 126 | txSlot* instance; |
57 | 126 | txSlot* property; |
58 | 126 | fxDuplicateInstance(the, mxThrowTypeErrorFunction.value.reference); |
59 | 126 | constructor = the->stack; |
60 | 126 | instance = constructor->value.reference; |
61 | 126 | instance->flag |= XS_CAN_CONSTRUCT_FLAG; |
62 | 126 | mxFunctionInstanceCode(instance)->ID = XS_NO_ID; |
63 | 126 | mxFunctionInstanceHome(instance)->value.home.object = NULL; |
64 | 126 | property = mxBehaviorGetProperty(the, instance, mxID(_length), 0, XS_OWN); |
65 | 126 | property->value.integer = length; |
66 | 126 | property = fxLastProperty(the, instance); |
67 | 126 | fxNextSlotProperty(the, property, prototype, mxID(_prototype), XS_GET_ONLY); |
68 | 126 | slot->kind = constructor->kind; |
69 | 126 | slot->value = constructor->value; |
70 | 126 | mxPop(); |
71 | 126 | } |
72 | 126 | } |
73 | | |
74 | | void fx_lockdown(txMachine* the) |
75 | 21 | { |
76 | 21 | #define mxHardenBuiltInCall \ |
77 | 2.18k | mxPush(mxGlobal); \ |
78 | 2.18k | mxPushSlot(harden); \ |
79 | 2.18k | mxCall() |
80 | 21 | #define mxHardenBuiltInRun \ |
81 | 2.18k | mxRunCount(1); \ |
82 | 2.18k | mxPop() |
83 | | |
84 | 21 | txSlot* instance; |
85 | 21 | txSlot* property; |
86 | 21 | txSlot* item; |
87 | 21 | txSlot* harden; |
88 | 21 | txInteger id; |
89 | | |
90 | 21 | if (mxProgram.value.reference->flag & XS_DONT_MARSHALL_FLAG) |
91 | 0 | mxTypeError("lockdown already called"); |
92 | 21 | mxProgram.value.reference->flag |= XS_DONT_MARSHALL_FLAG; |
93 | | |
94 | 21 | property = mxBehaviorSetProperty(the, mxAsyncFunctionPrototype.value.reference, mxID(_constructor), 0, XS_OWN); |
95 | 21 | fx_lockdown_aux(the, 1, &mxAsyncFunctionPrototype, property); |
96 | 21 | property = mxBehaviorSetProperty(the, mxAsyncGeneratorFunctionPrototype.value.reference, mxID(_constructor), 0, XS_OWN); |
97 | 21 | fx_lockdown_aux(the, 1, &mxAsyncGeneratorFunctionPrototype, property); |
98 | 21 | property = mxBehaviorSetProperty(the, mxFunctionPrototype.value.reference, mxID(_constructor), 0, XS_OWN); |
99 | 21 | fx_lockdown_aux(the, 1, &mxFunctionPrototype, property); |
100 | 21 | property = mxBehaviorSetProperty(the, mxGeneratorFunctionPrototype.value.reference, mxID(_constructor), 0, XS_OWN); |
101 | 21 | fx_lockdown_aux(the, 1, &mxGeneratorFunctionPrototype, property); |
102 | 21 | property = mxBehaviorSetProperty(the, mxCompartmentPrototype.value.reference, mxID(_constructor), 0, XS_OWN); |
103 | 21 | fx_lockdown_aux(the, 1, &mxCompartmentPrototype, property); |
104 | | |
105 | 21 | instance = fxNewArray(the, _Compartment); |
106 | 21 | property = the->stackIntrinsics - 1; |
107 | 21 | item = instance->next->value.array.address; |
108 | 357 | for (id = 0; id < XS_SYMBOL_ID_COUNT; id++) { |
109 | 336 | *((txIndex*)item) = id; |
110 | 336 | property--; |
111 | 336 | item++; |
112 | 336 | } |
113 | 1.36k | for (; id < _Compartment; id++) { |
114 | 1.34k | *((txIndex*)item) = id; |
115 | 1.34k | item->kind = property->kind; |
116 | 1.34k | item->value = property->value; |
117 | 1.34k | property--; |
118 | 1.34k | item++; |
119 | 1.34k | } |
120 | | |
121 | 21 | fxDuplicateInstance(the, mxDateConstructor.value.reference); |
122 | 21 | property = mxFunctionInstanceCode(the->stack->value.reference); |
123 | 21 | property->value.callback.address = mxCallback(fx_Date_secure); |
124 | 21 | property = mxBehaviorSetProperty(the, the->stack->value.reference, mxID(_now), 0, XS_OWN); |
125 | 21 | fxSetHostFunctionProperty(the, property, mxCallback(fx_Date_now_secure), 0, mxID(_now)); |
126 | 21 | property = mxBehaviorSetProperty(the, mxDatePrototype.value.reference, mxID(_constructor), 0, XS_OWN); |
127 | 21 | fx_lockdown_aux(the, 7, &mxDatePrototype, property); |
128 | 21 | mxPull(instance->next->value.array.address[_Date]); |
129 | | |
130 | 21 | fxDuplicateInstance(the, mxMathObject.value.reference); |
131 | 21 | property = mxBehaviorSetProperty(the, the->stack->value.reference, mxID(_random), 0, XS_OWN); |
132 | 21 | fxSetHostFunctionProperty(the, property, mxCallback(fx_Math_random_secure), 0, mxID(_random)); |
133 | 21 | #if mxECMAScript2023 |
134 | 21 | property = mxBehaviorSetProperty(the, the->stack->value.reference, mxID(_irandom), 0, XS_OWN); |
135 | 21 | fxSetHostFunctionProperty(the, property, mxCallback(fx_Math_irandom_secure), 0, mxID(_irandom)); |
136 | 21 | #endif |
137 | 21 | mxPull(instance->next->value.array.address[_Math]); |
138 | | |
139 | 21 | mxPull(mxCompartmentGlobal); |
140 | | |
141 | 21 | mxTemporary(harden); |
142 | 21 | mxPush(mxGlobal); |
143 | 21 | fxGetID(the, fxID(the, "harden")); |
144 | 21 | mxPullSlot(harden); |
145 | | |
146 | 1.30k | for (id = XS_SYMBOL_ID_COUNT; id < _Infinity; id++) { |
147 | 1.28k | mxHardenBuiltInCall; mxPush(the->stackIntrinsics[-1 - id]); mxHardenBuiltInRun; |
148 | 1.28k | } |
149 | 105 | for (id = _Compartment; id < XS_INTRINSICS_COUNT; id++) { |
150 | 84 | mxHardenBuiltInCall; mxPush(the->stackIntrinsics[-1 - id]); mxHardenBuiltInRun; |
151 | 84 | } |
152 | | |
153 | 21 | mxHardenBuiltInCall; mxPush(mxArgumentsSloppyPrototype); mxHardenBuiltInRun; |
154 | 21 | mxHardenBuiltInCall; mxPush(mxArgumentsStrictPrototype); mxHardenBuiltInRun; |
155 | 21 | mxHardenBuiltInCall; mxPush(mxArrayIteratorPrototype); mxHardenBuiltInRun; |
156 | 21 | mxHardenBuiltInCall; mxPush(mxAsyncFromSyncIteratorPrototype); mxHardenBuiltInRun; |
157 | 21 | mxHardenBuiltInCall; mxPush(mxAsyncFunctionPrototype); mxHardenBuiltInRun; |
158 | 21 | mxHardenBuiltInCall; mxPush(mxAsyncGeneratorFunctionPrototype); mxHardenBuiltInRun; |
159 | 21 | mxHardenBuiltInCall; mxPush(mxAsyncGeneratorPrototype); mxHardenBuiltInRun; |
160 | 21 | mxHardenBuiltInCall; mxPush(mxAsyncIteratorPrototype); mxHardenBuiltInRun; |
161 | 21 | mxHardenBuiltInCall; mxPush(mxGeneratorFunctionPrototype); mxHardenBuiltInRun; |
162 | 21 | mxHardenBuiltInCall; mxPush(mxGeneratorPrototype); mxHardenBuiltInRun; |
163 | 21 | mxHardenBuiltInCall; mxPush(mxHostPrototype); mxHardenBuiltInRun; |
164 | 21 | mxHardenBuiltInCall; mxPush(mxIteratorPrototype); mxHardenBuiltInRun; |
165 | 21 | mxHardenBuiltInCall; mxPush(mxMapIteratorPrototype); mxHardenBuiltInRun; |
166 | 21 | mxHardenBuiltInCall; mxPush(mxModulePrototype); mxHardenBuiltInRun; |
167 | 21 | mxHardenBuiltInCall; mxPush(mxRegExpStringIteratorPrototype); mxHardenBuiltInRun; |
168 | 21 | mxHardenBuiltInCall; mxPush(mxSetIteratorPrototype); mxHardenBuiltInRun; |
169 | 21 | mxHardenBuiltInCall; mxPush(mxStringIteratorPrototype); mxHardenBuiltInRun; |
170 | 21 | mxHardenBuiltInCall; mxPush(mxTransferPrototype); mxHardenBuiltInRun; |
171 | 21 | mxHardenBuiltInCall; mxPush(mxTypedArrayPrototype); mxHardenBuiltInRun; |
172 | | |
173 | 21 | mxHardenBuiltInCall; mxPush(mxAssignObjectFunction); mxHardenBuiltInRun; |
174 | 21 | mxHardenBuiltInCall; mxPush(mxCopyObjectFunction); mxHardenBuiltInRun; |
175 | 21 | mxHardenBuiltInCall; mxPush(mxEnumeratorFunction); mxHardenBuiltInRun; |
176 | 21 | mxHardenBuiltInCall; mxPush(mxInitializeRegExpFunction); mxHardenBuiltInRun; |
177 | 21 | mxHardenBuiltInCall; mxPush(mxOnRejectedPromiseFunction); mxHardenBuiltInRun; |
178 | 21 | mxHardenBuiltInCall; mxPush(mxOnResolvedPromiseFunction); mxHardenBuiltInRun; |
179 | 21 | mxHardenBuiltInCall; mxPush(mxOnThenableFunction); mxHardenBuiltInRun; |
180 | | |
181 | 21 | mxHardenBuiltInCall; mxPushReference(mxArrayLengthAccessor.value.accessor.getter); mxHardenBuiltInRun; |
182 | 21 | mxHardenBuiltInCall; mxPushReference(mxArrayLengthAccessor.value.accessor.setter); mxHardenBuiltInRun; |
183 | 21 | mxHardenBuiltInCall; mxPushReference(mxModuleAccessor.value.accessor.getter); mxHardenBuiltInRun; |
184 | 21 | mxHardenBuiltInCall; mxPushReference(mxStringAccessor.value.accessor.getter); mxHardenBuiltInRun; |
185 | 21 | mxHardenBuiltInCall; mxPushReference(mxStringAccessor.value.accessor.setter); mxHardenBuiltInRun; |
186 | 21 | if (mxProxyAccessor.value.accessor.getter) { |
187 | 21 | mxHardenBuiltInCall; mxPushReference(mxProxyAccessor.value.accessor.getter); mxHardenBuiltInRun; |
188 | 21 | } |
189 | 21 | if (mxProxyAccessor.value.accessor.setter) { |
190 | 21 | mxHardenBuiltInCall; mxPushReference(mxProxyAccessor.value.accessor.setter); mxHardenBuiltInRun; |
191 | 21 | } |
192 | 21 | mxHardenBuiltInCall; mxPushReference(mxTypedArrayAccessor.value.accessor.getter); mxHardenBuiltInRun; |
193 | 21 | mxHardenBuiltInCall; mxPushReference(mxTypedArrayAccessor.value.accessor.setter); mxHardenBuiltInRun; |
194 | | |
195 | 21 | mxHardenBuiltInCall; mxPush(mxArrayPrototype); fxGetID(the, mxID(_Symbol_unscopables)); mxHardenBuiltInRun; |
196 | | |
197 | 21 | mxHardenBuiltInCall; mxPush(mxCompartmentGlobal); mxHardenBuiltInRun; |
198 | | |
199 | 21 | mxHardenBuiltInCall; mxPushSlot(harden); mxHardenBuiltInRun; |
200 | 21 | mxHardenBuiltInCall; mxPushSlot(mxFunction); mxHardenBuiltInRun; |
201 | | |
202 | 21 | mxFunctionInstanceCode(mxThrowTypeErrorFunction.value.reference)->ID = XS_NO_ID; |
203 | 21 | mxFunctionInstanceHome(mxThrowTypeErrorFunction.value.reference)->value.home.object = NULL; |
204 | | |
205 | 21 | mxPop(); |
206 | 21 | } |
207 | | |
208 | | static void fx_hardenQueue(txMachine* the, txSlot* list, txSlot* instance, txFlag flag) |
209 | 34.5k | { |
210 | 34.5k | txSlot* item; |
211 | 34.5k | if (instance->flag & flag) |
212 | 19.8k | return; |
213 | 14.7k | item = fxNewSlot(the); |
214 | 14.7k | item->value.reference = instance; |
215 | 14.7k | item->kind = XS_REFERENCE_KIND; |
216 | 14.7k | list->value.list.last->next = item; |
217 | 14.7k | list->value.list.last = item; |
218 | 14.7k | } |
219 | | |
220 | | static void fx_hardenFreezeAndTraverse(txMachine* the, txSlot* reference, txSlot* freeze, txSlot* list, txFlag flag) |
221 | 16.6k | { |
222 | 16.6k | txSlot* instance = reference->value.reference; |
223 | 16.6k | txSlot* property; |
224 | 16.6k | txBoolean useIndexes = 1; |
225 | 16.6k | txSlot* at; |
226 | | // txSlot* slot; |
227 | | |
228 | 16.6k | if (!mxBehaviorPreventExtensions(the, instance)) |
229 | 0 | mxTypeError("extensible object"); |
230 | | |
231 | 16.6k | property = instance->next; |
232 | 16.6k | if (property && (property->flag & XS_INTERNAL_FLAG) && (property->kind == XS_TYPED_ARRAY_KIND)) { |
233 | 0 | useIndexes = 0; |
234 | 0 | } |
235 | | |
236 | 16.6k | at = fxNewInstance(the); |
237 | 16.6k | mxBehaviorOwnKeys(the, instance, XS_EACH_NAME_FLAG | XS_EACH_SYMBOL_FLAG, at); |
238 | 16.6k | mxPushUndefined(); |
239 | 16.6k | property = the->stack; |
240 | 67.8k | while ((at = at->next)) { |
241 | 51.2k | if ((at->value.at.id != XS_NO_ID) || useIndexes) { |
242 | 51.2k | if (mxBehaviorGetOwnProperty(the, instance, at->value.at.id, at->value.at.index, property)) { |
243 | 51.2k | txFlag mask = XS_DONT_DELETE_FLAG; |
244 | 51.2k | property->flag |= XS_DONT_DELETE_FLAG; |
245 | 51.2k | if (property->kind != XS_ACCESSOR_KIND) { |
246 | 49.9k | mask |= XS_DONT_SET_FLAG; |
247 | 49.9k | property->flag |= XS_DONT_SET_FLAG; |
248 | 49.9k | } |
249 | 51.2k | property->kind = XS_UNINITIALIZED_KIND; |
250 | 51.2k | if (!mxBehaviorDefineOwnProperty(the, instance, at->value.at.id, at->value.at.index, property, mask)) |
251 | 0 | mxTypeError("cannot configure property"); |
252 | 51.2k | } |
253 | 51.2k | } |
254 | 51.2k | } |
255 | 16.6k | mxPop(); |
256 | 16.6k | mxPop(); |
257 | | |
258 | | // if (flag == XS_DONT_MODIFY_FLAG) { |
259 | | // property = instance->next; |
260 | | // while (property) { |
261 | | // if (property->flag & XS_INTERNAL_FLAG) { |
262 | | // switch (property->kind) { |
263 | | // case XS_ARRAY_BUFFER_KIND: |
264 | | // case XS_DATE_KIND: |
265 | | // case XS_MAP_KIND: |
266 | | // case XS_SET_KIND: |
267 | | // case XS_WEAK_MAP_KIND: |
268 | | // case XS_WEAK_SET_KIND: |
269 | | // property->flag |= XS_DONT_SET_FLAG; |
270 | | // break; |
271 | | // case XS_PRIVATE_KIND: |
272 | | // slot = property->value.private.first; |
273 | | // while (slot) { |
274 | | // if (slot->kind != XS_ACCESSOR_KIND) |
275 | | // slot->flag |= XS_DONT_SET_FLAG; |
276 | | // slot->flag |= XS_DONT_DELETE_FLAG; |
277 | | // slot = slot->next; |
278 | | // } |
279 | | // break; |
280 | | // } |
281 | | // } |
282 | | // property = property->next; |
283 | | // } |
284 | | // } |
285 | 16.6k | instance->flag |= flag; |
286 | | |
287 | 16.6k | at = fxNewInstance(the); |
288 | 16.6k | mxBehaviorOwnKeys(the, instance, XS_EACH_NAME_FLAG | XS_EACH_SYMBOL_FLAG, at); |
289 | | |
290 | 16.6k | mxTemporary(property); |
291 | 16.6k | mxBehaviorGetPrototype(the, instance, property); |
292 | 16.6k | if (property->kind == XS_REFERENCE_KIND) |
293 | 16.5k | fx_hardenQueue(the, list, property->value.reference, flag); |
294 | | |
295 | 67.8k | while ((at = at->next)) { |
296 | 51.2k | if (mxBehaviorGetOwnProperty(the, instance, at->value.at.id, at->value.at.index, property)) { |
297 | 51.2k | if (property->kind == XS_REFERENCE_KIND) |
298 | 16.5k | fx_hardenQueue(the, list, property->value.reference, flag); |
299 | 34.7k | else if (property->kind == XS_ACCESSOR_KIND) { |
300 | 1.25k | if (property->value.accessor.getter) |
301 | 1.25k | fx_hardenQueue(the, list, property->value.accessor.getter, flag); |
302 | 1.25k | if (property->value.accessor.setter) |
303 | 225 | fx_hardenQueue(the, list, property->value.accessor.setter, flag); |
304 | 1.25k | } |
305 | 51.2k | } |
306 | 51.2k | } |
307 | | |
308 | | // if (flag == XS_DONT_MODIFY_FLAG) { |
309 | | // property = instance->next; |
310 | | // while (property) { |
311 | | // if (property->flag & XS_INTERNAL_FLAG) { |
312 | | // if (property->kind == XS_PRIVATE_KIND) { |
313 | | // txSlot* item = property->value.private.first; |
314 | | // while (item) { |
315 | | // if (property->kind == XS_REFERENCE_KIND) |
316 | | // fx_hardenQueue(the, list, property->value.reference, flag); |
317 | | // else if (property->kind == XS_ACCESSOR_KIND) { |
318 | | // if (property->value.accessor.getter) |
319 | | // fx_hardenQueue(the, list, property->value.accessor.getter, flag); |
320 | | // if (property->value.accessor.setter) |
321 | | // fx_hardenQueue(the, list, property->value.accessor.setter, flag); |
322 | | // } |
323 | | // item = item->next; |
324 | | // } |
325 | | // } |
326 | | // else if (property->kind == XS_DATA_VIEW_KIND) { |
327 | | // property = property->next; |
328 | | // fx_hardenQueue(the, list, property->value.reference, flag); |
329 | | // } |
330 | | // } |
331 | | // property = property->next; |
332 | | // } |
333 | | // } |
334 | | |
335 | 16.6k | mxPop(); |
336 | 16.6k | mxPop(); |
337 | 16.6k | } |
338 | | |
339 | | void fx_harden(txMachine* the) |
340 | 2.20k | { |
341 | 2.20k | txFlag flag = XS_DONT_MARSHALL_FLAG; |
342 | 2.20k | txSlot* freeze; |
343 | 2.20k | txSlot* slot; |
344 | 2.20k | txSlot* list; |
345 | 2.20k | txSlot* item; |
346 | | |
347 | | // if (!(mxProgram.value.reference->flag & XS_DONT_MARSHALL_FLAG)) |
348 | | // mxTypeError("call lockdown before harden"); |
349 | | |
350 | 2.20k | if (mxArgc == 0) |
351 | 0 | return; |
352 | | |
353 | 2.20k | *mxResult = *mxArgv(0); |
354 | | |
355 | 2.20k | slot = mxArgv(0); |
356 | 2.20k | if (slot->kind != XS_REFERENCE_KIND) |
357 | 22 | return; |
358 | | // if (mxArgc > 1) { |
359 | | // txString string = fxToString(the, mxArgv(1)); |
360 | | // if (c_strcmp(string, "freeze") == 0) |
361 | | // flag = XS_DONT_MARSHALL_FLAG; |
362 | | // else if (c_strcmp(string, "petrify") == 0) |
363 | | // flag = XS_DONT_MODIFY_FLAG; |
364 | | // else |
365 | | // mxTypeError("invalid integrity"); |
366 | | // } |
367 | 2.17k | slot = slot->value.reference; |
368 | 2.17k | if (slot->flag & flag) |
369 | 273 | return; |
370 | | |
371 | 1.90k | mxTemporary(freeze); |
372 | 1.90k | mxPush(mxObjectConstructor); |
373 | 1.90k | mxGetID(mxID(_freeze)); |
374 | 1.90k | mxPullSlot(freeze); |
375 | | |
376 | 1.90k | mxTemporary(list); |
377 | 1.90k | list->value.list.first = C_NULL; |
378 | 1.90k | list->value.list.last = C_NULL; |
379 | 1.90k | list->kind = XS_LIST_KIND; |
380 | | |
381 | 1.90k | item = fxNewSlot(the); |
382 | 1.90k | item->value.reference = slot; |
383 | 1.90k | item->kind = XS_REFERENCE_KIND; |
384 | 1.90k | list->value.list.first = item; |
385 | 1.90k | list->value.list.last = item; |
386 | | |
387 | 1.90k | { |
388 | 1.90k | mxTry(the) { |
389 | 18.5k | while (item) { |
390 | 16.6k | fx_hardenFreezeAndTraverse(the, item, freeze, list, flag); |
391 | 16.6k | item = item->next; |
392 | 16.6k | } |
393 | 1.90k | } |
394 | 1.90k | mxCatch(the) { |
395 | 0 | item = list->value.list.first; |
396 | 0 | while (item) { |
397 | 0 | item->value.reference->flag &= ~flag; |
398 | 0 | item = item->next; |
399 | 0 | } |
400 | 0 | fxJump(the); |
401 | 0 | } |
402 | 1.90k | } |
403 | | |
404 | 1.90k | mxPop(); |
405 | 1.90k | mxPop(); |
406 | 1.90k | } |
407 | | |
408 | | void fx_petrify(txMachine* the) |
409 | 0 | { |
410 | 0 | txSlot* slot; |
411 | 0 | txSlot* instance; |
412 | 0 | txBoolean useIndexes = 1; |
413 | 0 | txSlot* at; |
414 | 0 | txSlot* property; |
415 | 0 | if (mxArgc == 0) |
416 | 0 | return; |
417 | 0 | slot = mxArgv(0); |
418 | 0 | *mxResult = *slot; |
419 | 0 | if (slot->kind != XS_REFERENCE_KIND) |
420 | 0 | return; |
421 | 0 | instance = slot->value.reference; |
422 | 0 | if (!mxBehaviorPreventExtensions(the, instance)) |
423 | 0 | mxTypeError("extensible object"); |
424 | 0 | slot = instance->next; |
425 | 0 | if (slot && (slot->flag & XS_INTERNAL_FLAG)) { |
426 | 0 | if ((slot->kind == XS_STRING_KIND) || (slot->kind == XS_STRING_X_KIND) || (slot->kind == XS_TYPED_ARRAY_KIND)) |
427 | 0 | useIndexes = 0; |
428 | 0 | } |
429 | | |
430 | 0 | at = fxNewInstance(the); |
431 | 0 | mxBehaviorOwnKeys(the, instance, XS_EACH_NAME_FLAG | XS_EACH_SYMBOL_FLAG, at); |
432 | 0 | mxPushUndefined(); |
433 | 0 | property = the->stack; |
434 | 0 | while ((at = at->next)) { |
435 | 0 | if ((at->value.at.id != XS_NO_ID) || useIndexes) { |
436 | 0 | if (mxBehaviorGetOwnProperty(the, instance, at->value.at.id, at->value.at.index, property)) { |
437 | 0 | txFlag mask = XS_DONT_DELETE_FLAG; |
438 | 0 | property->flag |= XS_DONT_DELETE_FLAG; |
439 | 0 | if (property->kind != XS_ACCESSOR_KIND) { |
440 | 0 | mask |= XS_DONT_SET_FLAG; |
441 | 0 | property->flag |= XS_DONT_SET_FLAG; |
442 | 0 | } |
443 | 0 | property->kind = XS_UNINITIALIZED_KIND; |
444 | 0 | if (!mxBehaviorDefineOwnProperty(the, instance, at->value.at.id, at->value.at.index, property, mask)) |
445 | 0 | mxTypeError("cannot configure property"); |
446 | 0 | } |
447 | 0 | } |
448 | 0 | } |
449 | 0 | mxPop(); |
450 | | |
451 | 0 | property = instance->next; |
452 | 0 | while (property) { |
453 | 0 | if (property->flag & XS_INTERNAL_FLAG) { |
454 | 0 | switch (property->kind) { |
455 | 0 | case XS_ARRAY_BUFFER_KIND: |
456 | 0 | case XS_DATE_KIND: |
457 | 0 | case XS_MAP_KIND: |
458 | 0 | case XS_SET_KIND: |
459 | 0 | case XS_WEAK_MAP_KIND: |
460 | 0 | case XS_WEAK_SET_KIND: |
461 | 0 | property->flag |= XS_DONT_SET_FLAG; |
462 | 0 | break; |
463 | 0 | case XS_PRIVATE_KIND: |
464 | 0 | slot = property->value.private.first; |
465 | 0 | while (slot) { |
466 | 0 | if (slot->kind != XS_ACCESSOR_KIND) |
467 | 0 | slot->flag |= XS_DONT_SET_FLAG; |
468 | 0 | slot->flag |= XS_DONT_DELETE_FLAG; |
469 | 0 | slot = slot->next; |
470 | 0 | } |
471 | 0 | break; |
472 | 0 | } |
473 | 0 | } |
474 | 0 | property = property->next; |
475 | 0 | } |
476 | 0 | } |
477 | | |
478 | | static void fxVerifyCode(txMachine* the, txSlot* list, txSlot* path, txByte* codeBuffer, txSize codeSize); |
479 | | static void fxVerifyError(txMachine* the, txSlot* path, txID id, txIndex index, txString name); |
480 | | static void fxVerifyErrorString(txMachine* the, txSlot* slot, txID id, txIndex index, txString name); |
481 | | static void fxVerifyInstance(txMachine* the, txSlot* list, txSlot* path, txSlot* instance); |
482 | | static void fxVerifyProperty(txMachine* the, txSlot *list, txSlot *path, txSlot* property, txID id); |
483 | | static void fxVerifyPropertyError(txMachine* the, txSlot *list, txSlot *path, txSlot* property, txID id, txIndex index); |
484 | | static void fxVerifyQueue(txMachine* the, txSlot* list, txSlot* path, txSlot* instance, txID id, txIndex index, txString name); |
485 | | |
486 | | void fx_mutabilities(txMachine* the) |
487 | 0 | { |
488 | 0 | txSlot* instance; |
489 | 0 | txSlot* module; |
490 | 0 | txSlot* realm; |
491 | 0 | txSlot* slot; |
492 | 0 | txSlot* list; |
493 | 0 | txSlot* item; |
494 | | |
495 | 0 | fxVars(the, 2); |
496 | | |
497 | 0 | mxPush(mxArrayPrototype); |
498 | 0 | instance = fxNewArrayInstance(the); |
499 | 0 | mxPullSlot(mxResult); |
500 | |
|
501 | 0 | fxNewHostObject(the, NULL); |
502 | 0 | fxSetHostChunk(the, the->stack, NULL, the->keyIndex); |
503 | 0 | mxPullSlot(mxVarv(0)); |
504 | | |
505 | 0 | module = mxFunctionInstanceHome(mxFunction->value.reference)->value.home.module; |
506 | 0 | if (!module) module = mxProgram.value.reference; |
507 | 0 | realm = mxModuleInstanceInternal(module)->value.module.realm; |
508 | 0 | mxPushSlot(mxRealmGlobal(realm)); |
509 | 0 | mxPullSlot(mxVarv(1)); |
510 | |
|
511 | 0 | if (mxArgc == 0) |
512 | 0 | return; |
513 | 0 | slot = mxArgv(0); |
514 | 0 | if (slot->kind != XS_REFERENCE_KIND) |
515 | 0 | return; |
516 | | |
517 | 0 | mxTemporary(list); |
518 | 0 | list->value.list.first = C_NULL; |
519 | 0 | list->value.list.last = C_NULL; |
520 | 0 | list->kind = XS_LIST_KIND; |
521 | | |
522 | 0 | item = fxNewSlot(the); |
523 | 0 | item->value.list.first = C_NULL; |
524 | 0 | item->value.list.last = slot->value.reference; |
525 | 0 | item->kind = XS_LIST_KIND; |
526 | 0 | list->value.list.first = item; |
527 | 0 | list->value.list.last = item; |
528 | | |
529 | 0 | { |
530 | 0 | mxTry(the) { |
531 | 0 | while (item) { |
532 | 0 | fxVerifyInstance(the, list, item->value.list.first, item->value.list.last); |
533 | 0 | item = item->next; |
534 | 0 | } |
535 | 0 | item = list->value.list.first; |
536 | 0 | while (item) { |
537 | 0 | item->value.list.last->flag &= ~XS_LEVEL_FLAG; |
538 | 0 | item = item->next; |
539 | 0 | } |
540 | 0 | } |
541 | 0 | mxCatch(the) { |
542 | 0 | item = list->value.list.first; |
543 | 0 | while (item) { |
544 | 0 | item->value.list.last->flag &= ~XS_LEVEL_FLAG; |
545 | 0 | item = item->next; |
546 | 0 | } |
547 | 0 | fxJump(the); |
548 | 0 | } |
549 | 0 | } |
550 | | |
551 | 0 | mxPop(); // list |
552 | | |
553 | 0 | fxCacheArray(the, instance); |
554 | 0 | mxPushSlot(mxResult); |
555 | 0 | mxPushSlot(mxResult); |
556 | 0 | mxGetID(mxID(_sort)); |
557 | 0 | mxCall(); |
558 | 0 | mxRunCount(0); |
559 | 0 | mxPullSlot(mxResult); |
560 | 0 | } |
561 | | |
562 | | void fxVerifyCode(txMachine* the, txSlot* list, txSlot* path, txByte* codeBuffer, txSize codeSize) |
563 | 0 | { |
564 | 0 | const txS1* bytes = gxCodeSizes; |
565 | 0 | txByte* p = codeBuffer; |
566 | 0 | txByte* q = p + codeSize; |
567 | 0 | txU1 byte; |
568 | 0 | txS1 offset; |
569 | 0 | txID id; |
570 | 0 | txInteger count = 0; |
571 | 0 | txByte flag = 0; |
572 | 0 | txByte* flags = fxGetHostChunk(the, mxVarv(0)); |
573 | 0 | while (p < q) { |
574 | | // fprintf(stderr, "%s", gxCodeNames[*((txU1*)p)]); |
575 | 0 | byte = (txU1)c_read8(p); |
576 | 0 | offset = (txS1)c_read8(bytes + byte); |
577 | 0 | if (0 < offset) { |
578 | 0 | p += offset; |
579 | 0 | } |
580 | 0 | else if (0 == offset) { |
581 | 0 | p++; |
582 | 0 | mxDecodeID(p, id); |
583 | 0 | if (byte == XS_CODE_PROGRAM_REFERENCE) { |
584 | 0 | flag = 1; |
585 | 0 | flags[id] = 1; |
586 | 0 | } |
587 | 0 | } |
588 | 0 | else if (-1 == offset) { |
589 | 0 | txU1 index; |
590 | 0 | p++; |
591 | 0 | index = *((txU1*)p); |
592 | 0 | p += 1 + index; |
593 | 0 | } |
594 | 0 | else if (-2 == offset) { |
595 | 0 | txU2 index; |
596 | 0 | p++; |
597 | 0 | mxDecode2(p, index); |
598 | 0 | p += index; |
599 | 0 | } |
600 | 0 | else if (-4 == offset) { |
601 | 0 | txS4 index; |
602 | 0 | p++; |
603 | 0 | mxDecode4(p, index); |
604 | 0 | p += index; |
605 | 0 | } |
606 | | // fprintf(stderr, "\n"); |
607 | 0 | if ((XS_CODE_BEGIN_SLOPPY <= byte) && (byte <= XS_CODE_BEGIN_STRICT_FIELD)) { |
608 | 0 | count++; |
609 | 0 | } |
610 | 0 | else if ((XS_CODE_END <= byte) && (byte <= XS_CODE_END_DERIVED)) { |
611 | 0 | count--; |
612 | 0 | if (count == 0) |
613 | 0 | break; |
614 | 0 | } |
615 | 0 | } |
616 | 0 | if (flag) { |
617 | 0 | txSlot* instance = fxGetInstance(the, mxVarv(1)); |
618 | 0 | txSlot* item; |
619 | 0 | txSlot* name; |
620 | | |
621 | 0 | mxTemporary(item); |
622 | | |
623 | 0 | item->value.list.first = name = fxNewSlot(the); |
624 | 0 | item->value.list.last = C_NULL; |
625 | 0 | item->kind = XS_LIST_KIND; |
626 | |
|
627 | 0 | name->value.string = "GlobalEnvironment"; |
628 | 0 | name->kind = XS_STRING_X_KIND; |
629 | 0 | name->next = path; |
630 | | |
631 | 0 | flags = fxGetHostChunk(the, mxVarv(0)); |
632 | 0 | id = 0; |
633 | 0 | while (id < the->keyIndex) { |
634 | 0 | if (flags[id]) { |
635 | 0 | txSlot* property = mxBehaviorGetProperty(the, instance, id, 0, XS_OWN); |
636 | 0 | if (property) |
637 | 0 | fxVerifyProperty(the, list, name, property, id); |
638 | 0 | flags = fxGetHostChunk(the, mxVarv(0)); |
639 | 0 | flags[id]= 0; |
640 | 0 | } |
641 | 0 | id++; |
642 | 0 | } |
643 | | |
644 | 0 | mxPop(); |
645 | 0 | } |
646 | 0 | } |
647 | | |
648 | | void fxVerifyError(txMachine* the, txSlot* path, txID id, txIndex index, txString string) |
649 | 0 | { |
650 | 0 | txSlot* array; |
651 | 0 | txSlot* slot; |
652 | 0 | txSlot* stack; |
653 | | |
654 | 0 | array = mxResult->value.reference->next; |
655 | 0 | slot = fxNewSlot(the); |
656 | 0 | slot->next = array->next; |
657 | 0 | array->next = slot; |
658 | 0 | array->value.array.length++; |
659 | 0 | fxString(the, slot, ""); |
660 | | |
661 | 0 | stack = the->stack; |
662 | 0 | while (path) { |
663 | 0 | mxPushSlot(path); |
664 | 0 | path = path->next; |
665 | 0 | } |
666 | 0 | while (the->stack < stack) { |
667 | 0 | if (the->stack->kind == XS_STRING_X_KIND) { |
668 | 0 | fxVerifyErrorString(the, slot, XS_NO_ID, 0, the->stack->value.string); |
669 | 0 | } |
670 | 0 | else { |
671 | 0 | fxVerifyErrorString(the, slot, the->stack->value.at.id, the->stack->value.at.index, C_NULL); |
672 | 0 | } |
673 | 0 | mxPop(); |
674 | 0 | } |
675 | 0 | fxVerifyErrorString(the, slot, id, index, string); |
676 | | |
677 | | |
678 | | // current = path; |
679 | | // next = C_NULL; |
680 | | // previous = C_NULL; |
681 | | // while (current) { |
682 | | // next = current->next; |
683 | | // current->next = previous; |
684 | | // previous = current; |
685 | | // current = next; |
686 | | // } |
687 | | // |
688 | | // path = previous; |
689 | | // current = path; |
690 | | // while (current) { |
691 | | // if (current->kind == XS_STRING_X_KIND) { |
692 | | // fxVerifyErrorString(the, slot, XS_NO_ID, 0, current->value.string); |
693 | | // } |
694 | | // else { |
695 | | // fxVerifyErrorString(the, slot, current->value.at.id, current->value.at.index, C_NULL); |
696 | | // } |
697 | | // current = current->next; |
698 | | // } |
699 | | // fxVerifyErrorString(the, slot, id, index, string); |
700 | | // |
701 | | // current = path; |
702 | | // next = C_NULL; |
703 | | // previous = C_NULL; |
704 | | // while (current) { |
705 | | // next = current->next; |
706 | | // current->next = previous; |
707 | | // previous = current; |
708 | | // current = next; |
709 | | // } |
710 | 0 | } |
711 | | |
712 | | void fxVerifyErrorString(txMachine* the, txSlot* slot, txID id, txIndex index, txString string) |
713 | 0 | { |
714 | 0 | if (string) { |
715 | 0 | fxConcatStringC(the, slot, "[["); |
716 | 0 | fxConcatStringC(the, slot, string); |
717 | 0 | fxConcatStringC(the, slot, "]]"); |
718 | 0 | } |
719 | 0 | else if (id != XS_NO_ID) { |
720 | 0 | txBoolean adorn; |
721 | 0 | txString string = fxGetKeyString(the, id, &adorn); |
722 | 0 | txString buffer = the->nameBuffer; |
723 | 0 | size_t count = c_snprintf(buffer, sizeof(the->nameBuffer), "%s", string); |
724 | 0 | if (count >= sizeof(the->nameBuffer)) { |
725 | 0 | buffer = c_malloc(count + 1); |
726 | 0 | if (!buffer) |
727 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
728 | 0 | c_memcpy(buffer, string, count + 1); |
729 | 0 | } |
730 | 0 | if (adorn) { |
731 | 0 | fxConcatStringC(the, slot, "[Symbol("); |
732 | 0 | fxConcatStringC(the, slot, buffer); |
733 | 0 | fxConcatStringC(the, slot, ")]"); |
734 | 0 | } |
735 | 0 | else { |
736 | 0 | fxConcatStringC(the, slot, "."); |
737 | 0 | fxConcatStringC(the, slot, buffer); |
738 | 0 | } |
739 | 0 | if (buffer != the->nameBuffer) |
740 | 0 | c_free(buffer); |
741 | 0 | } |
742 | 0 | else { |
743 | 0 | fxNumberToString(the, index, the->nameBuffer, sizeof(the->nameBuffer), 0, 0); |
744 | 0 | fxConcatStringC(the, slot, "["); |
745 | 0 | fxConcatStringC(the, slot, the->nameBuffer); |
746 | 0 | fxConcatStringC(the, slot, "]"); |
747 | 0 | } |
748 | 0 | } |
749 | | |
750 | | void fxVerifyInstance(txMachine* the, txSlot* list, txSlot* path, txSlot* instance) |
751 | 0 | { |
752 | 0 | txSlot* property; |
753 | 0 | txSlot* prototype; |
754 | | |
755 | 0 | instance->flag |= XS_LEVEL_FLAG; |
756 | | |
757 | 0 | if (instance->next && (instance->next->ID == XS_ENVIRONMENT_BEHAVIOR)) { |
758 | 0 | property = instance->next->next; |
759 | 0 | while (property) { |
760 | 0 | if ((property->kind == XS_CLOSURE_KIND) && (property->ID != XS_NO_ID)) { // skip private fields initializers |
761 | 0 | txSlot* closure = property->value.closure; |
762 | 0 | if (!(closure->flag & XS_DONT_SET_FLAG)) { |
763 | 0 | fxVerifyError(the, path, property->ID, 0, C_NULL); |
764 | 0 | } |
765 | 0 | if (closure->kind == XS_REFERENCE_KIND) { |
766 | 0 | fxVerifyQueue(the, list, path, closure->value.reference, property->ID, 0, C_NULL); |
767 | 0 | } |
768 | 0 | } |
769 | 0 | property = property->next; |
770 | 0 | } |
771 | 0 | return; |
772 | 0 | } |
773 | | |
774 | 0 | if (!(instance->flag & XS_DONT_PATCH_FLAG)) { |
775 | 0 | fxVerifyError(the, path, XS_NO_ID, 0, "Extensible"); |
776 | 0 | } |
777 | |
|
778 | 0 | prototype = fxGetPrototype(the, instance); |
779 | 0 | if (prototype) { |
780 | 0 | fxVerifyQueue(the, list, path, prototype, mxID(___proto__), 0, C_NULL); |
781 | 0 | } |
782 | | |
783 | 0 | property = instance->next; |
784 | 0 | while (property) { |
785 | 0 | if (property->flag & XS_INTERNAL_FLAG) { |
786 | 0 | switch (property->kind) { |
787 | 0 | case XS_ARRAY_KIND: |
788 | 0 | { |
789 | 0 | txSlot* address = property->value.array.address; |
790 | 0 | if (address) { |
791 | 0 | txIndex index, offset = 0, size = (((txChunk*)(((txByte*)address) - sizeof(txChunk)))->size) / sizeof(txSlot); |
792 | 0 | while (offset < size) { |
793 | 0 | address = property->value.array.address + offset; |
794 | 0 | index = *((txIndex*)address); |
795 | 0 | fxVerifyPropertyError(the, list, path, address, XS_NO_ID, index); |
796 | 0 | address = property->value.array.address + offset; |
797 | 0 | if (address->kind == XS_REFERENCE_KIND) |
798 | 0 | fxVerifyQueue(the, list, path, address->value.reference, XS_NO_ID, index, C_NULL); |
799 | 0 | else if (address->kind == XS_ACCESSOR_KIND) { |
800 | 0 | if (address->value.accessor.getter) |
801 | 0 | fxVerifyQueue(the, list, path, address->value.accessor.getter, XS_NO_ID, index, C_NULL); |
802 | 0 | address = property->value.array.address + offset; |
803 | 0 | if (address->value.accessor.setter) |
804 | 0 | fxVerifyQueue(the, list, path, address->value.accessor.setter, XS_NO_ID, index, C_NULL); |
805 | 0 | } |
806 | 0 | offset++; |
807 | 0 | } |
808 | 0 | } |
809 | 0 | } |
810 | 0 | break; |
811 | 0 | case XS_ARRAY_BUFFER_KIND: |
812 | 0 | if (!(property->flag & XS_DONT_SET_FLAG)) { |
813 | 0 | if (property->value.arrayBuffer.address != C_NULL) |
814 | 0 | fxVerifyError(the, path, XS_NO_ID, 0, "ArrayBufferData"); |
815 | 0 | } |
816 | 0 | break; |
817 | 0 | case XS_CODE_KIND: |
818 | 0 | if (property->value.code.closures) |
819 | 0 | fxVerifyQueue(the, list, path, property->value.code.closures, XS_NO_ID, 0, "Environment"); |
820 | 0 | fxVerifyCode(the, list, path, property->value.code.address, ((txChunk*)(((txByte*)(property->value.code.address)) - sizeof(txChunk)))->size); |
821 | 0 | break; |
822 | 0 | case XS_CODE_X_KIND: |
823 | 0 | break; |
824 | 0 | case XS_DATA_VIEW_KIND: |
825 | 0 | property = property->next; |
826 | 0 | fxVerifyQueue(the, list, path, property->value.reference, XS_NO_ID, 0, "ViewedArrayBuffer"); |
827 | 0 | break; |
828 | 0 | case XS_DATE_KIND: |
829 | 0 | if (!(property->flag & XS_DONT_SET_FLAG)) |
830 | 0 | fxVerifyError(the, path, XS_NO_ID, 0, "DateValue"); |
831 | 0 | break; |
832 | 0 | case XS_REGEXP_KIND: |
833 | 0 | break; |
834 | 0 | case XS_MAP_KIND: |
835 | 0 | if (!(property->flag & XS_DONT_SET_FLAG)) |
836 | 0 | fxVerifyError(the, path, XS_NO_ID, 0, "MapData"); |
837 | 0 | break; |
838 | 0 | case XS_MODULE_KIND: |
839 | 0 | { |
840 | 0 | txSlot* exports = mxModuleInstanceExports(instance); |
841 | 0 | if (mxIsReference(exports)) { |
842 | 0 | txSlot* property = exports->value.reference->next; |
843 | 0 | while (property) { |
844 | 0 | if (property->value.export.closure) { |
845 | 0 | txSlot* closure = property->value.export.closure; |
846 | 0 | closure->flag |= XS_DONT_DELETE_FLAG; |
847 | 0 | fxVerifyProperty(the, list, path, closure, property->ID); |
848 | 0 | closure->flag &= ~XS_DONT_DELETE_FLAG; |
849 | 0 | } |
850 | 0 | property = property->next; |
851 | 0 | } |
852 | 0 | } |
853 | 0 | } |
854 | 0 | break; |
855 | 0 | case XS_PRIVATE_KIND: |
856 | 0 | { |
857 | 0 | txSlot* item = property->value.private.first; |
858 | 0 | while (item) { |
859 | 0 | fxVerifyProperty(the, list, path, item, item->ID); |
860 | 0 | item = item->next; |
861 | 0 | } |
862 | 0 | } |
863 | 0 | break; |
864 | 0 | case XS_PROXY_KIND: |
865 | 0 | if (property->value.proxy.handler) { |
866 | 0 | fxVerifyQueue(the, list, path, property->value.proxy.target, XS_NO_ID, 0, "ProxyHandler"); |
867 | 0 | } |
868 | 0 | if (property->value.proxy.target) { |
869 | 0 | fxVerifyQueue(the, list, path, property->value.proxy.target, XS_NO_ID, 0, "ProxyTarget"); |
870 | 0 | } |
871 | 0 | break; |
872 | 0 | case XS_SET_KIND: |
873 | 0 | if (!(property->flag & XS_DONT_SET_FLAG)) |
874 | 0 | fxVerifyError(the, path, XS_NO_ID, 0, "SetData"); |
875 | 0 | break; |
876 | 0 | case XS_WEAK_MAP_KIND: |
877 | 0 | if (!(property->flag & XS_DONT_SET_FLAG)) |
878 | 0 | fxVerifyError(the, path, XS_NO_ID, 0, "WeakMapData"); |
879 | 0 | break; |
880 | 0 | case XS_WEAK_SET_KIND: |
881 | 0 | if (!(property->flag & XS_DONT_SET_FLAG)) |
882 | 0 | fxVerifyError(the, path, XS_NO_ID, 0, "WeakSetData"); |
883 | 0 | break; |
884 | 0 | } |
885 | 0 | } |
886 | 0 | else { |
887 | 0 | fxVerifyProperty(the, list, path, property, property->ID); |
888 | 0 | } |
889 | 0 | property = property->next; |
890 | 0 | } |
891 | 0 | } |
892 | | |
893 | | void fxVerifyProperty(txMachine* the, txSlot *list, txSlot *path, txSlot* property, txID id) |
894 | 0 | { |
895 | 0 | fxVerifyPropertyError(the, list, path, property, id, 0); |
896 | 0 | if (property->kind == XS_REFERENCE_KIND) |
897 | 0 | fxVerifyQueue(the, list, path, property->value.reference, id, 0, C_NULL); |
898 | 0 | else if (property->kind == XS_ACCESSOR_KIND) { |
899 | 0 | if (property->value.accessor.getter) |
900 | 0 | fxVerifyQueue(the, list, path, property->value.accessor.getter, id, 0, C_NULL); |
901 | 0 | if (property->value.accessor.setter) |
902 | 0 | fxVerifyQueue(the, list, path, property->value.accessor.setter, id, 0, C_NULL); |
903 | 0 | } |
904 | 0 | } |
905 | | |
906 | | void fxVerifyPropertyError(txMachine* the, txSlot *list, txSlot *path, txSlot* property, txID id, txIndex index) |
907 | 0 | { |
908 | 0 | txBoolean immutable = 1; |
909 | 0 | if (property->kind != XS_ACCESSOR_KIND) |
910 | 0 | if (!(property->flag & XS_DONT_SET_FLAG)) |
911 | 0 | immutable = 0; |
912 | 0 | if (!(property->flag & XS_DONT_DELETE_FLAG)) |
913 | 0 | immutable = 0; |
914 | 0 | if (!immutable) |
915 | 0 | fxVerifyError(the, path, id, index, C_NULL); |
916 | 0 | } |
917 | | |
918 | | void fxVerifyQueue(txMachine* the, txSlot* list, txSlot* path, txSlot* instance, txID id, txIndex index, txString string) |
919 | 0 | { |
920 | 0 | txSlot* item; |
921 | 0 | txSlot* name; |
922 | 0 | if (instance->kind != XS_INSTANCE_KIND) |
923 | 0 | return; |
924 | 0 | if (instance->flag & XS_LEVEL_FLAG) |
925 | 0 | return; |
926 | 0 | item = fxNewSlot(the); |
927 | 0 | item->value.list.first = C_NULL; |
928 | 0 | item->value.list.last = instance; |
929 | 0 | item->kind = XS_LIST_KIND; |
930 | 0 | list->value.list.last->next = item; |
931 | 0 | list->value.list.last = item; |
932 | | |
933 | 0 | item->value.list.first = name = fxNewSlot(the); |
934 | 0 | if (string) { |
935 | 0 | name->value.string = string; |
936 | 0 | name->kind = XS_STRING_X_KIND; |
937 | 0 | } |
938 | 0 | else { |
939 | 0 | name->value.at.id = id; |
940 | 0 | name->value.at.index = index; |
941 | 0 | name->kind = XS_AT_KIND; |
942 | 0 | } |
943 | 0 | name->next = path; |
944 | 0 | } |
945 | | |
946 | | void fx_unicodeCompare(txMachine* the) |
947 | 0 | { |
948 | 0 | txString aString; |
949 | 0 | txString bString; |
950 | |
|
951 | 0 | if (mxArgc < 1) |
952 | 0 | aString = "undefined"; |
953 | 0 | else |
954 | 0 | aString = fxToString(the, mxArgv(0)); |
955 | 0 | if (mxArgc < 2) |
956 | 0 | bString = "undefined"; |
957 | 0 | else |
958 | 0 | bString = fxToString(the, mxArgv(1)); |
959 | 0 | #ifdef mxMetering |
960 | 0 | { |
961 | 0 | txSize aLength = fxUnicodeLength(aString, C_NULL); |
962 | 0 | txSize bLength = fxUnicodeLength(bString, C_NULL); |
963 | 0 | if (aLength < bLength) { |
964 | 0 | the->meterIndex += aLength * XS_STRING_METERING; |
965 | 0 | } |
966 | 0 | else { |
967 | 0 | the->meterIndex += bLength * XS_STRING_METERING; |
968 | 0 | } |
969 | 0 | } |
970 | 0 | #endif |
971 | 0 | mxResult->value.integer = mxStringUnicodeCompare(aString, bString); |
972 | 0 | mxResult->kind = XS_INTEGER_KIND; |
973 | 0 | } |
974 | | |