Coverage Report

Created: 2025-10-28 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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