Coverage Report

Created: 2026-05-30 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/moddable/xs/sources/xsAPI.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016-2025  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
#define XS_PROFILE_COUNT (256 * 1024)
41
42
static txSlot* fxCheckHostObject(txMachine* the, txSlot* it);
43
44
#ifdef mxFrequency
45
static void fxReportFrequency(txMachine* the);
46
#endif
47
48
/* Slot */
49
50
txKind fxTypeOf(txMachine* the, txSlot* theSlot)
51
0
{
52
0
  if (theSlot->kind == XS_STRING_X_KIND)
53
0
    return XS_STRING_KIND;
54
0
  if (theSlot->kind == XS_BIGINT_X_KIND)
55
0
    return XS_BIGINT_KIND;
56
#if mxHostFunctionPrimitive
57
  if (theSlot->kind == XS_HOST_FUNCTION_KIND)
58
    return XS_REFERENCE_KIND;
59
#endif
60
0
  return theSlot->kind;
61
0
}
62
63
/* Primitives */
64
65
void fxUndefined(txMachine* the, txSlot* theSlot)
66
23.6k
{
67
23.6k
  theSlot->kind = XS_UNDEFINED_KIND;
68
23.6k
}
69
70
void fxNull(txMachine* the, txSlot* theSlot)
71
0
{
72
0
  theSlot->kind = XS_NULL_KIND;
73
0
}
74
75
void fxBoolean(txMachine* the, txSlot* theSlot, txBoolean theValue)
76
14.0k
{
77
14.0k
  theSlot->value.boolean = theValue;
78
14.0k
  theSlot->kind = XS_BOOLEAN_KIND;
79
14.0k
}
80
81
txBoolean fxToBoolean(txMachine* the, txSlot* theSlot)
82
19.3M
{
83
19.3M
  switch (theSlot->kind) {
84
1.83M
  case XS_UNDEFINED_KIND:
85
1.84M
  case XS_NULL_KIND:
86
1.84M
    theSlot->kind = XS_BOOLEAN_KIND;
87
1.84M
    theSlot->value.boolean = 0;
88
1.84M
    break;
89
12.9M
  case XS_BOOLEAN_KIND:
90
12.9M
    break;
91
2.22M
  case XS_INTEGER_KIND:
92
2.22M
    theSlot->kind = XS_BOOLEAN_KIND;
93
2.22M
    theSlot->value.boolean = (theSlot->value.integer == 0) ? 0 : 1;
94
2.22M
    break;
95
1.14M
  case XS_NUMBER_KIND:
96
1.14M
    theSlot->kind = XS_BOOLEAN_KIND;
97
1.14M
    switch (c_fpclassify(theSlot->value.number)) {
98
138k
    case C_FP_NAN:
99
332k
    case C_FP_ZERO:
100
332k
      theSlot->value.boolean = 0;
101
332k
      break;
102
817k
    default:
103
817k
      theSlot->value.boolean = 1;
104
817k
      break;
105
1.14M
    }
106
1.14M
    break;
107
1.14M
  case XS_BIGINT_KIND:
108
148k
  case XS_BIGINT_X_KIND:
109
148k
    if ((theSlot->value.bigint.size == 1) && (theSlot->value.bigint.data[0] == 0))
110
310
      theSlot->value.boolean = 0;
111
147k
    else
112
147k
      theSlot->value.boolean = 1;
113
148k
    theSlot->kind = XS_BOOLEAN_KIND;
114
148k
    break;
115
235k
  case XS_STRING_KIND:
116
235k
  case XS_STRING_X_KIND:
117
235k
    theSlot->kind = XS_BOOLEAN_KIND;
118
235k
    if (c_isEmpty(theSlot->value.string))
119
606
      theSlot->value.boolean = 0;
120
234k
    else
121
234k
      theSlot->value.boolean = 1;
122
235k
    break;
123
#if mxHostFunctionPrimitive
124
  case XS_HOST_FUNCTION_KIND:
125
#endif
126
1.27k
  case XS_SYMBOL_KIND:
127
732k
  case XS_REFERENCE_KIND:
128
732k
    theSlot->kind = XS_BOOLEAN_KIND;
129
732k
    theSlot->value.boolean = 1;
130
732k
    break;
131
8
  default:
132
8
    mxTypeError("cannot coerce to boolean");
133
0
    break;
134
19.3M
  }
135
19.3M
  return theSlot->value.boolean;
136
19.3M
}
137
138
txInteger fxArgc(txMachine* the)
139
1.49M
{
140
1.49M
  return (txInteger)(the->frame->ID);
141
1.49M
}
142
143
void fxInteger(txMachine* the, txSlot* theSlot, txInteger theValue)
144
1.81M
{
145
1.81M
  theSlot->value.integer = theValue;
146
1.81M
  theSlot->kind = XS_INTEGER_KIND;
147
1.81M
}
148
149
txInteger fxToInteger(txMachine* the, txSlot* theSlot)
150
19.9M
{
151
#if mxOptimize
152
  if (XS_INTEGER_KIND == theSlot->kind)
153
    return theSlot->value.integer;        // this is the case over 90% of the time, so avoid the switch
154
#endif
155
156
21.3M
again:
157
21.3M
  switch (theSlot->kind) {
158
1.72M
  case XS_UNDEFINED_KIND:
159
1.82M
  case XS_NULL_KIND:
160
1.82M
    theSlot->kind = XS_INTEGER_KIND;
161
1.82M
    theSlot->value.integer = 0;
162
1.82M
    break;
163
3.60M
  case XS_BOOLEAN_KIND:
164
3.60M
    theSlot->kind = XS_INTEGER_KIND;
165
3.60M
    if (theSlot->value.boolean == 0)
166
1.40M
      theSlot->value.integer = 0;
167
2.19M
    else
168
2.19M
      theSlot->value.integer = 1;
169
3.60M
    break;
170
11.4M
  case XS_INTEGER_KIND:
171
11.4M
    break;
172
3.07M
  case XS_NUMBER_KIND:
173
3.07M
    theSlot->kind = XS_INTEGER_KIND;
174
3.07M
    theSlot->value.integer = fxNumberToInteger(theSlot->value.number);
175
3.07M
    mxFloatingPointOp("number to integer");
176
3.07M
    break;
177
1.29M
  case XS_STRING_KIND:
178
1.29M
  case XS_STRING_X_KIND:
179
1.29M
    theSlot->kind = XS_NUMBER_KIND;
180
1.29M
    theSlot->value.number = fxStringToNumber(the, theSlot->value.string, 1);
181
1.29M
    mxMeterOne();
182
1.29M
    goto again;
183
1.26k
  case XS_SYMBOL_KIND:
184
1.26k
    mxTypeError("cannot coerce symbol to integer");
185
0
    break;
186
16.3k
  case XS_REFERENCE_KIND:
187
16.3k
    fxToPrimitive(the, theSlot, XS_NUMBER_HINT);
188
16.3k
    goto again;
189
1
  default:
190
1
    mxTypeError("cannot coerce to integer");
191
0
    break;
192
21.3M
  }
193
19.9M
  return theSlot->value.integer;
194
21.3M
}
195
196
void fxNumber(txMachine* the, txSlot* theSlot, txNumber theValue)
197
2.99k
{
198
2.99k
  theSlot->value.number = theValue;
199
2.99k
  theSlot->kind = XS_NUMBER_KIND;
200
2.99k
}
201
202
txNumber fxToNumber(txMachine* the, txSlot* theSlot)
203
49.4M
{
204
50.2M
again:
205
50.2M
  switch (theSlot->kind) {
206
7.72M
  case XS_UNDEFINED_KIND:
207
7.72M
    theSlot->kind = XS_NUMBER_KIND;
208
7.72M
    theSlot->value.number = C_NAN;
209
7.72M
    break;
210
726k
  case XS_NULL_KIND:
211
726k
    theSlot->kind = XS_NUMBER_KIND;
212
726k
    theSlot->value.number = 0;
213
726k
    break;
214
6.32M
  case XS_BOOLEAN_KIND:
215
6.32M
    theSlot->kind = XS_NUMBER_KIND;
216
6.32M
    if (theSlot->value.boolean == 0)
217
4.37M
      theSlot->value.number = 0;
218
1.94M
    else
219
1.94M
      theSlot->value.number = 1;
220
6.32M
    break;
221
15.6M
  case XS_INTEGER_KIND:
222
15.6M
    theSlot->kind = XS_NUMBER_KIND;
223
15.6M
    theSlot->value.number = theSlot->value.integer;
224
15.6M
    mxFloatingPointOp("integer to number");
225
15.6M
    break;
226
7.96M
  case XS_NUMBER_KIND:
227
7.96M
    break;
228
11.0M
  case XS_STRING_KIND:
229
11.0M
  case XS_STRING_X_KIND:
230
11.0M
    theSlot->kind = XS_NUMBER_KIND;
231
11.0M
    theSlot->value.number = fxStringToNumber(the, theSlot->value.string, 1);
232
11.0M
    mxMeterOne();
233
11.0M
    break;
234
2.79k
  case XS_SYMBOL_KIND:
235
2.79k
    mxTypeError("cannot coerce symbol to number");
236
0
    break;
237
830k
  case XS_REFERENCE_KIND:
238
830k
    fxToPrimitive(the, theSlot, XS_NUMBER_HINT);
239
830k
    goto again;
240
1.06k
  default:
241
1.06k
    mxTypeError("cannot coerce to number");
242
0
    break;
243
50.2M
  }
244
49.4M
  return theSlot->value.number;
245
50.2M
}
246
247
void fxString(txMachine* the, txSlot* theSlot, txString theValue)
248
0
{
249
0
  fxCopyStringC(the, theSlot, theValue);
250
0
}
251
252
void fxStringX(txMachine* the, txSlot* theSlot, txString theValue)
253
2.32M
{
254
2.32M
#ifdef mxSnapshot
255
2.32M
  fxCopyStringC(the, theSlot, theValue);
256
#else
257
  theSlot->value.string = theValue;
258
  theSlot->kind = XS_STRING_X_KIND;
259
#endif
260
2.32M
}
261
262
void fxStringBuffer(txMachine* the, txSlot* theSlot, txString theValue, txSize theSize)
263
24.6k
{
264
24.6k
  theSlot->value.string = (txString)fxNewChunk(the, fxAddChunkSizes(the, theSize, 1));
265
24.6k
  if (theValue)
266
0
    c_memcpy(theSlot->value.string, theValue, theSize);
267
24.6k
  else
268
24.6k
    theSlot->value.string[0] = 0;
269
24.6k
  theSlot->value.string[theSize] = 0;
270
24.6k
  theSlot->kind = XS_STRING_KIND;
271
24.6k
}
272
273
txString fxToString(txMachine* the, txSlot* theSlot)
274
59.6M
{
275
59.6M
  char aBuffer[256];
276
63.5M
again:
277
63.5M
  switch (theSlot->kind) {
278
2.14M
  case XS_UNDEFINED_KIND:
279
2.14M
    *theSlot = mxUndefinedString;
280
2.14M
    break;
281
148k
  case XS_NULL_KIND:
282
148k
    fxStringX(the, theSlot, "null");
283
148k
    break;
284
376k
  case XS_BOOLEAN_KIND:
285
376k
    if (theSlot->value.boolean == 0)
286
80.1k
      fxStringX(the, theSlot, "false");
287
295k
    else
288
295k
      fxStringX(the, theSlot, "true");
289
376k
    break;
290
5.18M
  case XS_INTEGER_KIND:
291
5.18M
    fxCopyStringC(the, theSlot, fxIntegerToString(the, theSlot->value.integer, aBuffer, sizeof(aBuffer)));
292
5.18M
    mxMeterOne();
293
5.18M
    break;
294
5.07M
  case XS_NUMBER_KIND:
295
5.07M
    fxCopyStringC(the, theSlot, fxNumberToString(the, theSlot->value.number, aBuffer, sizeof(aBuffer), 0, 0));
296
5.07M
    mxMeterOne();
297
5.07M
    break;
298
1.36k
  case XS_SYMBOL_KIND:
299
1.36k
    mxTypeError("cannot coerce symbol to string");
300
0
    break;
301
180k
  case XS_BIGINT_KIND:
302
180k
  case XS_BIGINT_X_KIND:
303
180k
    gxTypeBigInt.toString(the, theSlot, 0);
304
180k
    break;
305
46.5M
  case XS_STRING_KIND:
306
46.5M
  case XS_STRING_X_KIND:
307
46.5M
    break;
308
3.84M
  case XS_REFERENCE_KIND:
309
3.84M
    fxToPrimitive(the, theSlot, XS_STRING_HINT);
310
3.84M
    goto again;
311
0
  default:
312
0
    mxTypeError("cannot coerce to string");
313
0
    break;
314
63.5M
  }
315
59.6M
  return theSlot->value.string;
316
63.5M
}
317
318
txString fxToStringBuffer(txMachine* the, txSlot* theSlot, txString theBuffer, txSize theSize)
319
57.2k
{
320
57.2k
  char* aString;
321
57.2k
  txSize aSize;
322
323
57.2k
  aString = fxToString(the, theSlot);
324
57.2k
  aSize = mxStringLength(aString) + 1;
325
57.2k
  if (aSize > theSize)
326
0
    mxRangeError("cannot buffer string");
327
57.2k
  c_memcpy(theBuffer, aString, aSize);
328
57.2k
  return theBuffer;
329
57.2k
}
330
331
void fxUnsigned(txMachine* the, txSlot* theSlot, txUnsigned theValue)
332
1.57M
{
333
1.57M
  if (((txInteger)theValue) >= 0) {
334
1.20M
    theSlot->value.integer = theValue;
335
1.20M
    theSlot->kind = XS_INTEGER_KIND;
336
1.20M
  }
337
373k
  else {
338
373k
    theSlot->value.number = theValue;
339
373k
    theSlot->kind = XS_NUMBER_KIND;
340
373k
  }
341
1.57M
}
342
343
txUnsigned fxToUnsigned(txMachine* the, txSlot* theSlot)
344
3.05M
{
345
3.05M
  txUnsigned result;
346
3.05M
again:
347
3.05M
  switch (theSlot->kind) {
348
1.86k
  case XS_UNDEFINED_KIND:
349
1.90k
  case XS_NULL_KIND:
350
1.90k
    theSlot->kind = XS_INTEGER_KIND;
351
1.90k
    result = theSlot->value.integer = 0;
352
1.90k
    break;
353
1.49k
  case XS_BOOLEAN_KIND:
354
1.49k
    theSlot->kind = XS_INTEGER_KIND;
355
1.49k
    if (theSlot->value.boolean == 0)
356
423
      result = theSlot->value.integer = 0;
357
1.07k
    else
358
1.07k
      result = theSlot->value.integer = 1;
359
1.49k
    break;
360
1.63M
  case XS_INTEGER_KIND:
361
1.63M
    if (theSlot->value.integer >= 0)
362
1.22M
      return (txUnsigned)theSlot->value.integer;
363
409k
    theSlot->kind = XS_NUMBER_KIND;
364
409k
    theSlot->value.number = theSlot->value.integer;
365
    // continue
366
409k
    mxFallThrough;
367
1.82M
  case XS_NUMBER_KIND:
368
1.82M
    theSlot->kind = XS_INTEGER_KIND;
369
1.82M
    switch (c_fpclassify(theSlot->value.number)) {
370
142k
    case C_FP_INFINITE:
371
519k
    case C_FP_NAN:
372
965k
    case C_FP_ZERO:
373
965k
      result = theSlot->value.integer = 0;
374
965k
      break;
375
861k
    default: {
376
1.64M
      #define MODULO 4294967296.0
377
861k
      txNumber aNumber = c_fmod(c_trunc(theSlot->value.number), MODULO);
378
861k
      if (aNumber < 0)
379
781k
        aNumber += MODULO;
380
861k
      result = (txUnsigned)aNumber;
381
861k
      if (((txInteger)result) >= 0) {
382
80.2k
        theSlot->kind = XS_INTEGER_KIND;
383
80.2k
        theSlot->value.integer = (txInteger)result;
384
80.2k
      }
385
781k
      else {
386
781k
        theSlot->kind = XS_NUMBER_KIND;
387
781k
        theSlot->value.number = aNumber;
388
781k
      }
389
861k
      } break;
390
1.82M
    }
391
1.82M
    mxFloatingPointOp("number to unsigned");
392
1.82M
    break;
393
2.59k
  case XS_STRING_KIND:
394
2.59k
  case XS_STRING_X_KIND:
395
2.59k
    theSlot->kind = XS_NUMBER_KIND;
396
2.59k
    theSlot->value.number = fxStringToNumber(the, theSlot->value.string, 1);
397
2.59k
    mxMeterOne();
398
2.59k
    goto again;
399
2
  case XS_SYMBOL_KIND:
400
2
    result = 0;
401
2
    mxTypeError("cannot coerce symbol to unsigned");
402
0
    break;
403
2.01k
  case XS_REFERENCE_KIND:
404
2.01k
    fxToPrimitive(the, theSlot, XS_NUMBER_HINT);
405
2.01k
    goto again;
406
0
  default:
407
0
    result = 0;
408
0
    mxTypeError("cannot coerce to unsigned");
409
0
    break;
410
3.05M
  }
411
1.83M
  return result;
412
3.05M
}
413
414
/* Closures and References */
415
416
void fxClosure(txMachine* the, txSlot* theSlot, txSlot* theClosure)
417
0
{
418
0
  theSlot->value.closure = theClosure;
419
0
  theSlot->kind = XS_CLOSURE_KIND;
420
0
}
421
422
txSlot* fxToClosure(txMachine* the, txSlot* theSlot)
423
0
{
424
0
  if (theSlot->kind == XS_CLOSURE_KIND)
425
0
    return theSlot->value.closure;
426
0
  return NULL;
427
0
}
428
429
void fxReference(txMachine* the, txSlot* theSlot, txSlot* theReference)
430
0
{
431
0
  if (theReference) {
432
0
    theSlot->value.reference = theReference;
433
0
    theSlot->kind = XS_REFERENCE_KIND;
434
0
  }
435
0
  else
436
0
    theSlot->kind = XS_NULL_KIND;
437
0
}
438
439
txSlot* fxToReference(txMachine* the, txSlot* theSlot)
440
0
{
441
0
  if (theSlot->kind == XS_REFERENCE_KIND)
442
0
    return theSlot->value.reference;
443
0
  return NULL;
444
0
}
445
446
/* Instances and Prototypes */
447
448
txSlot* fxNewArray(txMachine* the, txIndex size)
449
5.96M
{
450
5.96M
  txSlot* instance;
451
5.96M
  txSlot* array;
452
5.96M
  mxPush(mxArrayPrototype);
453
5.96M
  instance = fxNewArrayInstance(the);
454
5.96M
  array = instance->next;
455
5.96M
  fxSetIndexSize(the, array, size, XS_CHUNK);
456
5.96M
  fxIndexArray(the, array);
457
5.96M
  return instance;
458
5.96M
}
459
460
txSlot* fxNewObject(txMachine* the)
461
4.13M
{
462
4.13M
  mxPush(mxObjectPrototype);
463
4.13M
  return fxNewObjectInstance(the);
464
4.13M
}
465
466
txBoolean fxIsInstanceOf(txMachine* the)
467
0
{
468
0
  txBoolean result = 0;
469
0
  txSlot* theInstance = the->stack++;
470
0
  txSlot* thePrototype = the->stack++;
471
472
0
  if (mxIsReference(theInstance) && mxIsReference(thePrototype)) {
473
0
    theInstance = fxGetInstance(the, theInstance);
474
0
    thePrototype = fxGetInstance(the, thePrototype);
475
0
    while (theInstance) {
476
0
      if (theInstance == thePrototype) {
477
0
        result = 1;
478
0
        break;
479
0
      }
480
0
      theInstance = fxGetPrototype(the, theInstance);
481
0
    }
482
0
  }
483
0
  return result;
484
0
}
485
486
void fxArrayCacheBegin(txMachine* the, txSlot* reference)
487
0
{
488
0
  txSlot* array = reference->value.reference->next;
489
0
  array->value.array.address = C_NULL;
490
0
  array->value.array.length = 0;
491
0
}
492
493
void fxArrayCacheEnd(txMachine* the, txSlot* reference)
494
0
{
495
0
  txSlot* array = reference->value.reference->next;
496
0
  txIndex length = array->value.array.length;
497
0
  if (length) {
498
0
    txSlot *srcSlot, *dstSlot;
499
0
    array->value.array.address = (txSlot*)fxNewChunk(the, fxMultiplyChunkSizes(the, length, sizeof(txSlot)));
500
0
    srcSlot = array->next;
501
0
    dstSlot = array->value.array.address + length;
502
0
    while (srcSlot) {
503
0
      dstSlot--;
504
0
      length--;
505
0
      dstSlot->next = C_NULL;
506
0
      dstSlot->ID = XS_NO_ID;
507
0
      dstSlot->flag = XS_NO_FLAG;
508
0
      dstSlot->kind = srcSlot->kind;
509
0
      dstSlot->value = srcSlot->value;
510
0
      *((txIndex*)dstSlot) = length;
511
0
      srcSlot = srcSlot->next;
512
0
    }
513
0
    array->next = C_NULL;
514
0
  }
515
0
}
516
517
void fxArrayCacheItem(txMachine* the, txSlot* reference, txSlot* item)
518
0
{
519
0
  txSlot* array = reference->value.reference->next;
520
0
  txSlot* slot = fxNewSlot(the);
521
0
  slot->next = array->next;
522
0
  slot->kind = item->kind;
523
0
  slot->value = item->value;
524
0
  array->next = slot;
525
0
  array->value.array.length++;
526
0
}
527
528
/* Host Constructors, Functions and Objects */
529
530
void fxNative(txMachine* the)
531
0
{
532
0
  if (mxHasTarget)
533
0
    mxPushSlot(mxTarget);
534
0
  else
535
0
    mxPushSlot(mxFunction);
536
0
  mxGetID(mxID(_prototype));
537
0
  fxNewHostInstance(the);
538
0
  mxPullSlot(mxResult);
539
0
}
540
541
void fxBuildHosts(txMachine* the, txInteger c, const txHostFunctionBuilder* builder)
542
0
{
543
0
  mxPushInteger(c);
544
0
  mxPushInteger(1);
545
0
  mxPush(mxArrayPrototype);
546
0
  fxNewArrayInstance(the);
547
0
  fxArrayCacheBegin(the, the->stack);
548
0
  while (c) {
549
0
    if (builder->length >= 0) {
550
    #if mxHostFunctionPrimitive
551
      mxPushUndefined();
552
      the->stack->kind = XS_HOST_FUNCTION_KIND;
553
      the->stack->value.hostFunction.builder = builder;
554
      the->stack->value.hostFunction.profileID = the->profileID;
555
      the->profileID++;
556
    #else
557
0
      fxNewHostFunction(the, builder->callback, builder->length, builder->id, XS_NO_ID);
558
0
    #endif
559
0
    }
560
0
    else
561
0
      fxNewHostObject(the, (txDestructor)builder->callback);
562
0
    fxArrayCacheItem(the, the->stack + 1, the->stack);
563
0
    mxPop();
564
0
    c--;
565
0
    builder++;
566
0
  }
567
0
  fxArrayCacheEnd(the, the->stack);
568
0
}
569
570
txSlot* fxNewHostConstructor(txMachine* the, txCallback theCallback, txInteger theLength, txInteger name)
571
1.30M
{
572
1.30M
  txSlot* aStack;
573
1.30M
  txSlot* instance;
574
1.30M
  txSlot* property;
575
576
1.30M
  fxToInstance(the, the->stack);
577
1.30M
  aStack = the->stack;
578
1.30M
  instance = fxNewHostFunction(the, theCallback, theLength, name, XS_NO_ID);
579
1.30M
  instance->flag |= XS_CAN_CONSTRUCT_FLAG;
580
1.30M
  property = fxLastProperty(the, instance);
581
1.30M
  fxNextSlotProperty(the, property, aStack, mxID(_prototype), XS_GET_ONLY);
582
1.30M
  property = mxBehaviorSetProperty(the, fxGetInstance(the, aStack), mxID(_constructor), 0, XS_OWN);
583
1.30M
  property->flag = XS_DONT_ENUM_FLAG;
584
1.30M
  property->kind = the->stack->kind;
585
1.30M
  property->value = the->stack->value;
586
1.30M
  *aStack = *the->stack;
587
1.30M
  mxPop();
588
1.30M
  return instance;
589
1.30M
}
590
591
txSlot* fxNewHostFunction(txMachine* the, txCallback theCallback, txInteger theLength, txInteger name, txInteger profileID)
592
18.2M
{
593
18.2M
  txSlot* instance;
594
18.2M
  txSlot* property;
595
596
18.2M
  mxPushUndefined();
597
18.2M
  instance = fxNewSlot(the);
598
18.2M
  instance->flag |= XS_CAN_CALL_FLAG;
599
18.2M
  instance->kind = XS_INSTANCE_KIND;
600
18.2M
  instance->value.instance.garbage = C_NULL;
601
18.2M
  instance->value.instance.prototype = mxFunctionPrototype.value.reference;
602
18.2M
  the->stack->value.reference = instance;
603
18.2M
  the->stack->kind = XS_REFERENCE_KIND;
604
605
  /* CALLBACK */
606
18.2M
  property = instance->next = fxNewSlot(the);
607
18.2M
  property->flag = XS_INTERNAL_FLAG;
608
18.2M
  property->kind = XS_CALLBACK_KIND;
609
18.2M
  property->value.callback.address = theCallback;
610
18.2M
  property->value.callback.closures = C_NULL;
611
612
  /* HOME */
613
18.2M
  property = property->next = fxNewSlot(the);
614
18.2M
  if (profileID != XS_NO_ID)
615
3.43M
    property->ID = profileID;
616
14.7M
  else
617
14.7M
    property->ID = fxGenerateProfileID(the);
618
18.2M
  property->flag = XS_INTERNAL_FLAG;
619
18.2M
  property->kind = XS_HOME_KIND;
620
18.2M
  property->value.home.object = C_NULL;
621
18.2M
  if (the->frame && (mxFunction->kind == XS_REFERENCE_KIND) && (mxIsFunction(mxFunction->value.reference))) {
622
3.29M
    txSlot* slot = mxFunctionInstanceHome(mxFunction->value.reference);
623
3.29M
    property->value.home.module = slot->value.home.module;
624
3.29M
  }
625
14.9M
  else
626
14.9M
    property->value.home.module = C_NULL;
627
628
  /* LENGTH */
629
18.2M
  if (gxDefaults.newFunctionLength)
630
18.2M
    gxDefaults.newFunctionLength(the, instance, theLength);
631
632
  /* NAME */
633
18.2M
  fxRenameFunction(the, instance, name, 0, XS_NO_ID, C_NULL);
634
635
18.2M
  return instance;
636
18.2M
}
637
638
txSlot* fxNewHostInstance(txMachine* the)
639
242k
{
640
242k
  txSlot* prototype = fxGetInstance(the, the->stack);
641
242k
  txSlot* instance = fxNewSlot(the);
642
242k
  instance->kind = XS_INSTANCE_KIND;
643
242k
  instance->value.instance.garbage = C_NULL;
644
242k
  instance->value.instance.prototype = prototype;
645
242k
  the->stack->value.reference = instance;
646
242k
  the->stack->kind = XS_REFERENCE_KIND;
647
242k
  if (prototype) {
648
242k
    txSlot* prototypeHost = prototype->next;
649
242k
    if (prototypeHost && (prototypeHost->kind == XS_HOST_KIND) && (prototypeHost->value.host.variant.destructor != fxReleaseSharedChunk)) {
650
24.5k
      txSlot* instanceHost = instance->next = fxNewSlot(the);
651
24.5k
      instanceHost->flag = XS_INTERNAL_FLAG;
652
24.5k
      instanceHost->kind = XS_HOST_KIND;
653
24.5k
      instanceHost->value.host.data = C_NULL;
654
24.5k
      if (prototypeHost->flag & XS_HOST_HOOKS_FLAG) {
655
0
        instanceHost->flag |= XS_HOST_HOOKS_FLAG;
656
0
        instanceHost->value.host.variant.hooks = prototypeHost->value.host.variant.hooks;
657
0
      }
658
24.5k
      else {
659
24.5k
        instanceHost->value.host.variant.destructor = prototypeHost->value.host.variant.destructor;
660
24.5k
      }
661
24.5k
    }
662
242k
  }
663
242k
  return instance;
664
242k
}
665
666
667
txSlot* fxCheckHostObject(txMachine* the, txSlot* it)
668
98.2k
{
669
98.2k
  txSlot* result = C_NULL;
670
98.2k
  if (it->kind == XS_REFERENCE_KIND) {
671
98.2k
    it = it->value.reference;
672
98.2k
    if (it->next) {
673
98.2k
      it = it->next;
674
98.2k
      if ((it->flag & XS_INTERNAL_FLAG) && (it->kind == XS_HOST_KIND))
675
98.2k
        result = it;
676
98.2k
    }
677
98.2k
  }
678
98.2k
  return result;
679
98.2k
}
680
681
txSlot* fxNewHostObject(txMachine* the, txDestructor theDestructor)
682
24.5k
{
683
24.5k
  txSlot* anInstance;
684
24.5k
  txSlot* aProperty;
685
686
24.5k
  mxPushUndefined();
687
688
24.5k
  anInstance = fxNewSlot(the);
689
24.5k
  anInstance->kind = XS_INSTANCE_KIND;
690
24.5k
  anInstance->value.instance.garbage = C_NULL;
691
24.5k
  anInstance->value.instance.prototype = mxObjectPrototype.value.reference;
692
24.5k
  the->stack->value.reference = anInstance;
693
24.5k
  the->stack->kind = XS_REFERENCE_KIND;
694
695
24.5k
  aProperty = anInstance->next = fxNewSlot(the);
696
24.5k
  aProperty->flag = XS_INTERNAL_FLAG;
697
24.5k
  aProperty->kind = XS_HOST_KIND;
698
24.5k
  aProperty->value.host.data = C_NULL;
699
24.5k
  aProperty->value.host.variant.destructor = theDestructor;
700
  
701
24.5k
  return anInstance;
702
24.5k
}
703
704
txInteger fxGetHostBufferLength(txMachine* the, txSlot* slot)
705
0
{
706
0
  txSlot* host = fxCheckHostObject(the, slot);
707
0
  if (host) {
708
0
    txSlot* bufferInfo = host->next;
709
0
    if (host->flag & XS_HOST_CHUNK_FLAG)
710
0
      mxSyntaxError("C: xsGetHostBufferLength: no host data");
711
0
    if (!bufferInfo || (bufferInfo->kind != XS_BUFFER_INFO_KIND))
712
0
      mxSyntaxError("C: xsGetHostBufferLength: not a host buffer");
713
0
    return bufferInfo->value.bufferInfo.length;
714
0
  }
715
0
  mxSyntaxError("C: xsGetHostData: not a host object");
716
0
  return 0;
717
0
}
718
719
void* fxGetHostChunk(txMachine* the, txSlot* slot)
720
49.1k
{
721
49.1k
  txSlot* host = fxCheckHostObject(the, slot);
722
49.1k
  if (host) {
723
49.1k
    if (host->flag & XS_HOST_CHUNK_FLAG)
724
49.1k
      return host->value.host.data;
725
49.1k
    mxSyntaxError("C: xsGetHostChunk: no host data");
726
49.1k
  }
727
49.1k
  mxSyntaxError("C: xsGetHostChunk: not a host object");
728
0
  return NULL;
729
49.1k
}
730
731
void* fxGetHostChunkIf(txMachine* the, txSlot* slot)
732
0
{
733
0
  txSlot* host = fxCheckHostObject(the, slot);
734
0
  if (host) {
735
0
    if (host->flag & XS_HOST_CHUNK_FLAG)
736
0
      return host->value.host.data;
737
0
  }
738
0
  return NULL;
739
0
}
740
741
void* fxGetHostChunkValidate(txMachine* the, txSlot* slot, void* validator)
742
0
{
743
0
  txSlot* host = fxCheckHostObject(the, slot);
744
0
  if (host) {
745
0
    if (host->flag & XS_HOST_CHUNK_FLAG) {
746
0
      if (validator == host->value.host.variant.destructor)
747
0
        return host->value.host.data;
748
0
      mxSyntaxError("C: xsGetHostChunk: invalid host data");
749
0
    }
750
0
    mxSyntaxError("C: xsGetHostChunk: no host data");
751
0
  }
752
0
  mxSyntaxError("C: xsGetHostChunk: not a host object");
753
0
  return NULL;
754
0
}
755
756
void* fxGetHostData(txMachine* the, txSlot* slot)
757
0
{
758
0
  txSlot* host = fxCheckHostObject(the, slot);
759
0
  if (host) {
760
0
    if (!(host->flag & XS_HOST_CHUNK_FLAG))
761
0
      return host->value.host.data;
762
0
    mxSyntaxError("C: xsGetHostData: no host data");
763
0
  }
764
0
  mxSyntaxError("C: xsGetHostData: not a host object");
765
0
  return NULL;
766
0
}
767
768
void* fxGetHostDataIf(txMachine* the, txSlot* slot)
769
0
{
770
0
  txSlot* host = fxCheckHostObject(the, slot);
771
0
  if (host) {
772
0
    if (!(host->flag & XS_HOST_CHUNK_FLAG))
773
0
      return host->value.host.data;
774
0
  }
775
0
  return NULL;
776
0
}
777
778
void* fxGetHostDataValidate(txMachine* the, txSlot* slot, void* validator)
779
0
{
780
0
  txSlot* host = fxCheckHostObject(the, slot);
781
0
  if (host) {
782
0
    if (!(host->flag & XS_HOST_CHUNK_FLAG)) {
783
0
      if (validator == host->value.host.variant.destructor)
784
0
        return host->value.host.data;
785
0
      mxSyntaxError("C: xsGetHostData: invalid host data");
786
0
    }
787
0
    mxSyntaxError("C: xsGetHostData: no host data");
788
0
  }
789
0
  mxSyntaxError("C: xsGetHostData: not a host object");
790
0
  return NULL;
791
0
}
792
793
txDestructor fxGetHostDestructor(txMachine* the, txSlot* slot)
794
0
{
795
0
  txSlot* host = fxCheckHostObject(the, slot);
796
0
  if (host) {
797
0
    if (!(host->flag & XS_HOST_HOOKS_FLAG))
798
0
      return host->value.host.variant.destructor;
799
0
    mxSyntaxError("C: xsGetHostDestructor: no host destructor");
800
0
  }
801
0
  mxSyntaxError("C: xsGetHostDestructor: not a host object");
802
0
  return NULL;
803
0
}
804
805
void* fxGetHostHandle(txMachine* the, txSlot* slot)
806
0
{
807
0
  txSlot* host = fxCheckHostObject(the, slot);
808
0
  if (host) {
809
0
    return &host->value.host.data;
810
0
  }
811
0
  mxSyntaxError("C: xsGetHostData: not a host object");
812
0
  return NULL;
813
0
}
814
815
txHostHooks* fxGetHostHooks(txMachine* the, txSlot* slot)
816
0
{
817
0
  txSlot* host = fxCheckHostObject(the, slot);
818
0
  if (host) {
819
0
    if (host->flag & XS_HOST_HOOKS_FLAG)
820
0
      return host->value.host.variant.hooks;
821
0
    mxSyntaxError("C: xsGetHostHooks: no host hooks");
822
0
  }
823
0
  mxSyntaxError("C: xsGetHostHooks: not a host object");
824
0
  return NULL;
825
0
}
826
827
txHostHooks* fxGetHostHooksIf(txMachine* the, txSlot* slot)
828
0
{
829
0
  txSlot* host = fxCheckHostObject(the, slot);
830
0
  if (host) {
831
0
    if (host->flag & XS_HOST_HOOKS_FLAG)
832
0
      return host->value.host.variant.hooks;
833
0
  }
834
0
  return NULL;
835
0
}
836
837
txHostHooks* fxGetHostHooksValidate(txMachine* the, txSlot* slot, txString validator)
838
0
{
839
0
  txSlot* host = fxCheckHostObject(the, slot);
840
0
  if (host) {
841
0
    if (host->flag & XS_HOST_HOOKS_FLAG) {
842
0
      txString signature = host->value.host.variant.hooks->signature;
843
0
      if ((signature != C_NULL) && (!c_strcmp(signature, validator)))
844
0
        return host->value.host.variant.hooks;
845
0
      mxSyntaxError("C: xsGetHostHooks: invalid");
846
0
    }
847
0
    mxSyntaxError("C: xsGetHostHooks: no host hooks");
848
0
  }
849
0
  mxSyntaxError("C: xsGetHostHooks: not a host object");
850
0
  return NULL;
851
0
}
852
853
void fxPetrifyHostBuffer(txMachine* the, txSlot* slot)
854
0
{
855
0
  txSlot* host = fxCheckHostObject(the, slot);
856
0
  if (!host)
857
0
    mxSyntaxError("C: xsPetrifyHostBuffer: not a host object");
858
0
  if (host->flag & XS_HOST_CHUNK_FLAG)
859
0
    mxSyntaxError("C: xsPetrifyHostBuffer: no host data");
860
0
  host->flag |= XS_DONT_SET_FLAG;
861
0
}
862
863
void fxSetHostBuffer(txMachine* the, txSlot* slot, void* theData, txSize theSize)
864
0
{
865
0
  txSlot* host = fxCheckHostObject(the, slot);
866
0
  if (host) {
867
0
    txSlot* bufferInfo = host->next;
868
0
    if (!bufferInfo || (bufferInfo->kind != XS_BUFFER_INFO_KIND)) {
869
0
      bufferInfo = fxNewSlot(the);
870
0
      bufferInfo->next = host->next;
871
0
      bufferInfo->flag = XS_INTERNAL_FLAG;
872
0
      bufferInfo->kind = XS_BUFFER_INFO_KIND;
873
0
      bufferInfo->value.bufferInfo.length = 0;
874
0
      bufferInfo->value.bufferInfo.maxLength = -1;
875
0
      host->next = bufferInfo;
876
0
    }
877
0
    host->flag &= ~XS_HOST_CHUNK_FLAG;
878
0
    host->value.host.data = theData;
879
0
    bufferInfo->value.bufferInfo.length = theSize;
880
0
  }
881
0
  else
882
0
    mxSyntaxError("C: xsSetHostBuffer: not a host object");
883
0
}
884
885
void *fxSetHostChunk(txMachine* the, txSlot* slot, void* theValue, txSize theSize)
886
24.5k
{
887
24.5k
  txSlot* host = fxCheckHostObject(the, slot);
888
24.5k
  if (host) {
889
24.5k
    host->flag |= XS_HOST_CHUNK_FLAG;
890
24.5k
    if (theSize) {
891
24.5k
      host->value.host.data = fxNewChunk(the, theSize);
892
24.5k
      if (theValue)
893
24.5k
        c_memcpy(host->value.host.data, theValue, theSize);
894
0
      else
895
0
        c_memset(host->value.host.data, 0, theSize);
896
24.5k
    }
897
0
    else
898
0
      host->value.host.data = NULL;
899
24.5k
    return host->value.host.data;
900
24.5k
  }
901
0
  else
902
0
    mxSyntaxError("C: fxSetHostChunk: not a host object");
903
904
0
  return NULL;
905
24.5k
}
906
907
void fxSetHostData(txMachine* the, txSlot* slot, void* theData)
908
0
{
909
0
  txSlot* host = fxCheckHostObject(the, slot);
910
0
  if (host) {
911
0
    host->flag &= ~XS_HOST_CHUNK_FLAG;
912
0
    host->value.host.data = theData;
913
0
  }
914
0
  else
915
0
    mxSyntaxError("C: xsSetHostData: not a host object");
916
0
}
917
918
void fxSetHostDestructor(txMachine* the, txSlot* slot, txDestructor theDestructor)
919
24.5k
{
920
24.5k
  txSlot* host = fxCheckHostObject(the, slot);
921
24.5k
  if (host) {
922
24.5k
    host->flag &= ~XS_HOST_HOOKS_FLAG;
923
24.5k
    host->value.host.variant.destructor = theDestructor;
924
24.5k
  }
925
0
  else
926
0
    mxSyntaxError("C: xsSetHostDestructor: not a host object");
927
24.5k
}
928
929
void fxSetHostHooks(txMachine* the, txSlot* slot, const txHostHooks* theHooks)
930
0
{
931
0
  txSlot* host = fxCheckHostObject(the, slot);
932
0
  if (host) {
933
0
    host->flag |= XS_HOST_HOOKS_FLAG;
934
0
    host->value.host.variant.hooks = (txHostHooks *) theHooks;
935
0
  }
936
0
  else
937
0
    mxSyntaxError("C: xsSetHostHooks: not a host object");
938
0
}
939
940
/* Identifiers */
941
942
txID fxID(txMachine* the, txString theName)
943
13.1M
{
944
13.1M
  return fxNewNameC(the, theName);
945
13.1M
}
946
947
txID fxFindID(txMachine* the, txString theName)
948
0
{
949
0
  return fxFindName(the, theName);
950
0
}
951
952
txS1 fxIsID(txMachine* the, txString theName)
953
0
{
954
0
  return fxFindName(the, theName) ? 1 : 0;
955
0
}
956
957
txID fxToID(txMachine* the, txSlot* theSlot)
958
430
{
959
430
  txString string = fxToString(the, theSlot);
960
430
  if (theSlot->kind == XS_STRING_KIND)
961
430
    return fxNewName(the, theSlot);
962
0
  return fxNewNameX(the, string);
963
430
}
964
965
txString fxName(txMachine* the, txID theID)
966
18
{
967
18
  return fxGetKeyName(the, theID);
968
18
}
969
970
/* Properties */
971
972
void fxEnumerate(txMachine* the) 
973
0
{
974
0
  mxPush(mxEnumeratorFunction);
975
0
  mxCall();
976
0
  mxRunCount(0);
977
0
}
978
979
void fxGetAll(txMachine* the, txSlot* stack, txID id, txIndex index)
980
192M
{
981
192M
  txBoolean flag = mxIsReference(stack) ? 1 : 0;
982
192M
  txSlot* instance = (flag) ? stack->value.reference : fxToInstance(the, stack);
983
192M
  txSlot* property = mxBehaviorGetProperty(the, instance, (txID)id, index, XS_ANY);
984
192M
  if (!property) {
985
26.7M
    the->stack = stack;
986
26.7M
    stack->kind = XS_UNDEFINED_KIND;
987
26.7M
  }
988
166M
  else if (property->kind == XS_ACCESSOR_KIND) {
989
36.9M
    txSlot* function = property->value.accessor.getter;
990
36.9M
    if (mxIsFunction(function)) {
991
36.9M
      txSlot* slot;
992
36.9M
      the->stack = stack;
993
36.9M
      mxOverflow(-3);
994
36.9M
            the->stack -= 3;
995
36.9M
      slot = the->stack;
996
36.9M
      mxInitSlotKind(slot++, XS_UNINITIALIZED_KIND);
997
36.9M
      mxInitSlotKind(slot++, XS_UNDEFINED_KIND);
998
36.9M
      slot->value.reference = function;
999
36.9M
      mxInitSlotKind(slot++, XS_REFERENCE_KIND);
1000
36.9M
      if (!flag) {
1001
24
        txSlot* primitive = instance->next;
1002
24
        slot->value = primitive->value;
1003
24
        mxInitSlotKind(slot, primitive->kind);
1004
24
      }
1005
36.9M
      mxRunCount(0);
1006
36.9M
    }
1007
9
    else {
1008
9
      the->stack = stack;
1009
9
      stack->kind = XS_UNDEFINED_KIND;
1010
9
    }
1011
36.9M
  }
1012
129M
  else {
1013
129M
    the->stack = stack;
1014
129M
    stack->kind = property->kind;
1015
129M
    stack->value = property->value;
1016
129M
  }
1017
192M
}
1018
1019
void fxGetAt(txMachine* the)
1020
3.91M
{
1021
3.91M
  txSlot* at = fxAt(the, the->stack);
1022
3.91M
  mxPop();
1023
3.91M
  mxGetAll(at->value.at.id, at->value.at.index);
1024
3.91M
}
1025
1026
void fxGetID(txMachine* the, txID id)
1027
102M
{
1028
102M
  mxGetAll(id, 0);
1029
102M
}
1030
1031
void fxGetIndex(txMachine* the, txIndex index)
1032
37.8M
{
1033
37.8M
  mxGetAll(XS_NO_ID, index);
1034
37.8M
}
1035
1036
txBoolean fxHasAll(txMachine* the, txSlot* stack, txID id, txIndex index)
1037
29.5M
{
1038
29.5M
  txSlot* instance = fxToInstance(the, stack);
1039
29.5M
  txBoolean result = mxBehaviorHasProperty(the, instance, id, index);
1040
29.5M
  the->stack = stack;
1041
29.5M
  mxPop();
1042
29.5M
  return result;
1043
29.5M
}
1044
1045
txBoolean fxHasAt(txMachine* the)
1046
10.7M
{
1047
10.7M
  txSlot* at = fxAt(the, the->stack);
1048
10.7M
  return fxHasAll(the, the->stack + 1, at->value.at.id, at->value.at.index);
1049
10.7M
}
1050
1051
txBoolean fxHasID(txMachine* the, txID id)
1052
4.58M
{
1053
4.58M
  return fxHasAll(the, the->stack, id, 0);
1054
4.58M
}
1055
1056
txBoolean fxHasIndex(txMachine* the, txIndex index)
1057
14.1M
{
1058
14.1M
  return fxHasAll(the, the->stack, XS_NO_ID, index);
1059
14.1M
}
1060
1061
void fxSetAll(txMachine* the, txSlot* stack, txID id, txIndex index)
1062
21.9M
{
1063
21.9M
  txSlot* value = stack + 1;
1064
21.9M
  txSlot* instance = fxToInstance(the, stack);
1065
21.9M
  txSlot* property = mxBehaviorSetProperty(the, instance, id, index, XS_ANY);
1066
21.9M
  if (!property)
1067
17
    mxDebugID(XS_TYPE_ERROR, "C: xsSet %s: not extensible", id);
1068
21.9M
  if (property->kind == XS_ACCESSOR_KIND) {
1069
721k
    txSlot* slot;
1070
721k
    txSlot* function = property->value.accessor.setter;
1071
721k
    if (!mxIsFunction(function))
1072
6
      mxDebugID(XS_TYPE_ERROR, "C: xsSet %s: no setter", id);
1073
721k
    the->stack = stack;
1074
721k
    mxOverflow(-3);
1075
721k
    the->stack -= 3;
1076
721k
    slot = the->stack;
1077
721k
    slot->value = value->value;
1078
721k
    mxInitSlotKind(slot++, value->kind);
1079
721k
    mxInitSlotKind(slot++, XS_UNINITIALIZED_KIND);
1080
721k
    slot->value = value->value;
1081
721k
    mxInitSlotKind(slot++, value->kind);
1082
721k
    slot->value.reference = function;
1083
721k
    mxInitSlotKind(slot++, XS_REFERENCE_KIND);
1084
721k
    slot->value.reference = instance;
1085
721k
    mxInitSlotKind(slot, XS_REFERENCE_KIND);
1086
721k
    mxRunCount(1);
1087
721k
  }
1088
21.1M
  else {
1089
21.1M
    if (property->flag & XS_DONT_SET_FLAG)
1090
16
      mxDebugID(XS_TYPE_ERROR, "C: xsSet %s: not writable", id);
1091
21.1M
    property->kind = value->kind;
1092
21.1M
    property->value = value->value;
1093
21.1M
    the->stack = stack;
1094
21.1M
    mxPop();
1095
21.1M
  }
1096
21.9M
}
1097
1098
void fxSetAt(txMachine* the)
1099
1.27M
{
1100
1.27M
  txSlot* at = fxAt(the, the->stack);
1101
1.27M
  fxSetAll(the, the->stack + 1, at->value.at.id, at->value.at.index);
1102
1.27M
}
1103
1104
void fxSetID(txMachine* the, txID id)
1105
20.4M
{
1106
20.4M
  fxSetAll(the, the->stack, id, 0);
1107
20.4M
}
1108
1109
void fxSetIndex(txMachine* the, txIndex index)
1110
223k
{
1111
223k
  fxSetAll(the, the->stack, XS_NO_ID, index);
1112
223k
}
1113
1114
void fxDeleteAll(txMachine* the, txSlot* stack, txID id, txIndex index)
1115
3.57M
{
1116
3.57M
  txSlot* instance = fxToInstance(the, stack);
1117
3.57M
  if (!mxBehaviorDeleteProperty(the, instance, id, index))
1118
5
    mxDebugID(XS_TYPE_ERROR, "delete %s: not configurable", id);
1119
3.57M
  the->stack = stack;
1120
3.57M
}
1121
1122
void fxDeleteAt(txMachine* the)
1123
3.51M
{
1124
3.51M
  txSlot* at = fxAt(the, the->stack);
1125
3.51M
  fxDeleteAll(the, the->stack + 1, at->value.at.id, at->value.at.index);
1126
3.51M
}
1127
1128
void fxDeleteID(txMachine* the, txID id)
1129
0
{
1130
0
  fxDeleteAll(the, the->stack, id, 0);
1131
0
}
1132
1133
void fxDeleteIndex(txMachine* the, txIndex index)
1134
61.1k
{
1135
61.1k
  fxDeleteAll(the, the->stack, XS_NO_ID, index);
1136
61.1k
}
1137
1138
void fxDefineAll(txMachine* the, txSlot* stack, txID id, txIndex index, txFlag flag, txFlag mask)
1139
10.0M
{
1140
10.0M
  txSlot* instance = fxToInstance(the, stack);
1141
10.0M
  txSlot* slot = stack + 1;
1142
10.0M
  if (mask & XS_GETTER_FLAG) {
1143
73.7k
    slot->value.accessor.getter = slot->value.reference;
1144
73.7k
    slot->value.accessor.setter = C_NULL;
1145
73.7k
    slot->kind = XS_ACCESSOR_KIND;
1146
73.7k
  }
1147
10.0M
  else if (mask & XS_SETTER_FLAG) {
1148
0
    slot->value.accessor.setter = slot->value.reference;
1149
0
    slot->value.accessor.getter = C_NULL;
1150
0
    slot->kind = XS_ACCESSOR_KIND;
1151
0
  }
1152
10.0M
  slot->flag = flag & XS_GET_ONLY;
1153
10.0M
  if (!mxBehaviorDefineOwnProperty(the, instance, id, index, slot, mask))
1154
13
    mxTypeError("define %ld: not configurable", id);
1155
10.0M
  the->stack = stack;
1156
10.0M
  mxPop();
1157
10.0M
}
1158
1159
void fxDefineAt(txMachine* the, txFlag flag, txFlag mask)
1160
3.69M
{
1161
3.69M
  txSlot* at = fxAt(the, the->stack);
1162
3.69M
  fxDefineAll(the, the->stack + 1, at->value.at.id, at->value.at.index, flag, mask);
1163
3.69M
}
1164
1165
void fxDefineID(txMachine* the, txID id, txFlag flag, txFlag mask)
1166
319k
{
1167
319k
  fxDefineAll(the, the->stack, id, 0, flag, mask);
1168
319k
}
1169
1170
void fxDefineIndex(txMachine* the, txIndex index, txFlag flag, txFlag mask)
1171
6.06M
{
1172
6.06M
  fxDefineAll(the, the->stack, XS_NO_ID, index, flag, mask);
1173
6.06M
}
1174
1175
void fxCall(txMachine* the)
1176
61.0M
{
1177
  // RESULT
1178
61.0M
  (--the->stack)->next = C_NULL;
1179
61.0M
  mxInitSlotKind(the->stack, XS_UNDEFINED_KIND);
1180
  // FRAME
1181
61.0M
  (--the->stack)->next = C_NULL;
1182
61.0M
  mxInitSlotKind(the->stack, XS_UNINITIALIZED_KIND);
1183
61.0M
}
1184
1185
void fxCallID(txMachine* the, txID theID)
1186
24.5k
{
1187
24.5k
  mxDub();
1188
24.5k
  mxGetID(theID);
1189
24.5k
  fxCall(the);
1190
24.5k
}
1191
1192
void fxCallFrame(txMachine* the)
1193
0
{
1194
0
  mxOverflow(-2);
1195
0
  fxCall(the);
1196
0
}
1197
1198
void fxNew(txMachine* the)
1199
1.54M
{
1200
1.54M
  txSlot* constructor = the->stack;
1201
1.54M
  txSlot* slot = constructor - 4;
1202
1.54M
  the->stack = slot;
1203
  // FRAME
1204
1.54M
  mxInitSlotKind(slot++, XS_UNINITIALIZED_KIND);
1205
  // RESULT
1206
1.54M
  mxInitSlotKind(slot++, XS_UNDEFINED_KIND);
1207
  // FUNCTION (copy of constructor)
1208
1.54M
  slot->value = constructor->value;
1209
1.54M
  mxInitSlotKind(slot++, constructor->kind);
1210
  // THIS (uninitialized marks as constructor)
1211
1.54M
  mxInitSlotKind(slot++, XS_UNINITIALIZED_KIND);
1212
  // TARGET (constructor = new.target, stays in place)
1213
1.54M
}
1214
1215
void fxNewID(txMachine* the, txID theID)
1216
24.5k
{
1217
24.5k
  mxGetID(theID);
1218
24.5k
  fxNew(the);
1219
24.5k
}
1220
1221
void fxNewFrame(txMachine* the)
1222
0
{
1223
0
  mxOverflow(-3);
1224
0
  fxNew(the);
1225
0
}
1226
1227
void fxRunCount(txMachine* the, txInteger count)
1228
1.53M
{
1229
1.53M
  fxRunID(the, C_NULL, count);
1230
1.53M
}
1231
1232
txSlot* fxTarget(txMachine* the)
1233
24.5k
{
1234
24.5k
  static const txSlot undefined = { 0 };
1235
24.5k
  if (the->frame->flag & XS_TARGET_FLAG)
1236
24.5k
    return the->frame + 4;
1237
0
  return (txSlot*)&undefined;
1238
24.5k
}
1239
1240
txBoolean fxRunTest(txMachine* the)
1241
6
{
1242
6
  txBoolean result;
1243
  
1244
6
  switch (the->stack->kind) {
1245
0
  case XS_UNDEFINED_KIND:
1246
0
  case XS_NULL_KIND:
1247
0
    result = 0;
1248
0
    break;
1249
6
  case XS_BOOLEAN_KIND:
1250
6
    result = the->stack->value.boolean;
1251
6
    break;
1252
0
  case XS_INTEGER_KIND:
1253
0
    result = (the->stack->value.integer == 0) ? 0 : 1;
1254
0
    break;
1255
0
  case XS_NUMBER_KIND:
1256
0
    switch (c_fpclassify(the->stack->value.number)) {
1257
0
    case C_FP_NAN:
1258
0
    case C_FP_ZERO:
1259
0
      result = 0;
1260
0
      break;
1261
0
    default:
1262
0
      result = 1;
1263
0
      break;
1264
0
    }
1265
0
    break;
1266
0
  case XS_STRING_KIND:
1267
0
  case XS_STRING_X_KIND:
1268
0
    if (c_isEmpty(the->stack->value.string))
1269
0
      result = 0;
1270
0
    else
1271
0
      result = 1;
1272
0
    break;
1273
0
  default:
1274
0
    result = 1;
1275
0
    break;
1276
6
  }
1277
6
  mxPop();
1278
6
  return result;
1279
6
}
1280
1281
/* Arguments and Variables */
1282
1283
void fxVars(txMachine* the, txInteger theCount)
1284
42.6k
{
1285
42.6k
  if (the->scope != the->stack)
1286
0
    mxSyntaxError("C: xsVars: too late");
1287
42.6k
  mxOverflow(theCount);
1288
42.6k
  the->scope->value.environment.variable.count = theCount;
1289
109k
  while (theCount) {
1290
67.2k
    mxPushUndefined();
1291
67.2k
    theCount--;
1292
67.2k
  }
1293
42.6k
}
1294
1295
txInteger fxCheckArg(txMachine* the, txInteger theIndex)
1296
1.58M
{
1297
1.58M
  if ((theIndex < 0) || (mxArgc <= theIndex))
1298
0
    mxSyntaxError("C: xsArg(%ld): invalid index", theIndex);
1299
1.58M
  return theIndex;
1300
1.58M
}
1301
1302
txInteger fxCheckVar(txMachine* the, txInteger theIndex)
1303
705k
{
1304
705k
  if ((theIndex < 0) || (mxVarc <= theIndex))
1305
0
    mxSyntaxError("C: xsVar(%ld): invalid index", theIndex);
1306
705k
  return theIndex;
1307
705k
}
1308
1309
void fxOverflow(txMachine* the, txInteger theCount, txString thePath, txInteger theLine)
1310
872M
{
1311
872M
  txSlot* aStack = the->stack + theCount;
1312
872M
  if (theCount < 0) {
1313
872M
    if (aStack < the->stackBottom) {
1314
74
      fxReport(the, "stack overflow (%ld)!\n", (the->stack - the->stackBottom) + theCount);
1315
74
      fxAbort(the, XS_JAVASCRIPT_STACK_OVERFLOW_EXIT);
1316
74
    }
1317
872M
  }
1318
67.2k
  else if (theCount > 0) {
1319
67.2k
    if (aStack > the->stackTop) {
1320
0
      fxReport(the, "stack overflow (%ld)!\n", theCount - (the->stackTop - the->stack));
1321
0
      fxAbort(the, XS_JAVASCRIPT_STACK_OVERFLOW_EXIT);
1322
0
    }
1323
67.2k
  }
1324
872M
}
1325
1326
/* Exceptions */
1327
1328
void fxThrow(txMachine* the, txString path, txInteger line)
1329
32
{
1330
32
#ifdef mxDebug
1331
32
  fxDebugThrow(the, path, line, "C: xsThrow");
1332
32
#endif
1333
32
  fxJump(the);
1334
32
}
1335
1336
void fxThrowMessage(txMachine* the, txString path, txInteger line, txError error, txString format, ...)
1337
1.59M
{
1338
1.59M
  char message[128] = "";
1339
1.59M
  txSize length = 0;
1340
1.59M
    va_list arguments;
1341
1.59M
    txSlot* slot;
1342
1.59M
    va_start(arguments, format);
1343
1.59M
    c_vsnprintf(message, sizeof(message), format, arguments);
1344
1.59M
    va_end(arguments);
1345
1346
  //??
1347
1.59M
  length = (txSize)c_strlen(message) - 1;
1348
1.59M
  while (length && (0x80 & message[length]))
1349
128
    message[length--] = 0;
1350
    
1351
1.59M
#ifdef mxDebug
1352
1.59M
  if (!the->debugEval) {
1353
1.59M
    c_strncat(message, " (in ", sizeof(message) - mxStringLength(message) - 1);
1354
1.59M
    length = (txSize)c_strlen(message);
1355
1.59M
    fxBufferFrameName(the, message + length, sizeof(message) - length, the->frame, ")");
1356
1.59M
  }
1357
1.59M
#endif
1358
1359
1.59M
  if ((error <= XS_NO_ERROR) || (XS_ERROR_COUNT <= error))
1360
0
    error = XS_UNKNOWN_ERROR;
1361
1362
1.59M
    slot = fxNewSlot(the);
1363
1.59M
    slot->kind = XS_INSTANCE_KIND;
1364
1.59M
    slot->value.instance.garbage = C_NULL;
1365
1.59M
    slot->value.instance.prototype = mxErrorPrototypes(error).value.reference;
1366
1.59M
  mxException.kind = XS_REFERENCE_KIND;
1367
1.59M
  mxException.value.reference = slot;
1368
1.59M
  slot = slot->next = fxNewSlot(the);
1369
1.59M
  slot->flag = XS_INTERNAL_FLAG;
1370
1.59M
  slot->kind = XS_ERROR_KIND;
1371
1.59M
  slot->value.error.info = C_NULL;
1372
1.59M
  slot->value.error.which = error;
1373
1.59M
  if (gxDefaults.captureErrorStack)
1374
1.59M
    gxDefaults.captureErrorStack(the, slot, the->frame);
1375
1.59M
  slot = fxNextStringProperty(the, slot, message, mxID(_message), XS_DONT_ENUM_FLAG);
1376
1.59M
#ifdef mxDebug
1377
1.59M
  fxDebugThrow(the, path, line, "throw");
1378
1.59M
#endif
1379
1.59M
  fxJump(the);
1380
1.59M
}
1381
1382
/* Debugger */
1383
1384
void fxDebugger(txMachine* the, txString thePath, txInteger theLine)
1385
0
{
1386
0
#ifdef mxDebug
1387
0
  fxDebugLoop(the, thePath, theLine, "C: xsDebugger");
1388
0
#endif
1389
0
}
1390
1391
/* Machine */
1392
1393
const txByte gxNoCode[3] ICACHE_FLASH_ATTR = { XS_CODE_BEGIN_STRICT, 0, XS_CODE_END };
1394
1395
txMachine* fxCreateMachine(txCreation* theCreation, txString theName, void* theContext, txID profileID)
1396
24.5k
{
1397
24.5k
  txMachine* the = (txMachine* )c_calloc(1, sizeof(txMachine));
1398
24.5k
  if (the) {
1399
24.5k
    txJump aJump;
1400
1401
24.5k
    aJump.nextJump = C_NULL;
1402
24.5k
    aJump.stack = C_NULL;
1403
24.5k
    aJump.scope = C_NULL;
1404
24.5k
    aJump.frame = C_NULL;
1405
24.5k
    aJump.code = C_NULL;
1406
24.5k
    aJump.flag = 0;
1407
24.5k
    the->firstJump = &aJump;
1408
24.5k
    if (c_setjmp(aJump.buffer) == 0) {
1409
24.5k
      txInteger id;
1410
24.5k
      txSlot* slot;
1411
1412
24.5k
      if (gxDefaults.initializeSharedCluster)
1413
24.5k
        gxDefaults.initializeSharedCluster(the);
1414
        
1415
24.5k
      the->context = theContext;
1416
24.5k
      fxCreateMachinePlatform(the);
1417
1418
24.5k
    #ifdef mxDebug
1419
24.5k
      the->name = theName;
1420
24.5k
    #endif
1421
24.5k
      the->profileID = (profileID != XS_NO_ID) ? profileID : mxBaseProfileID;
1422
24.5k
      fxAllocate(the, theCreation);
1423
1424
24.5k
            c_memset(the->nameTable, 0, the->nameModulo * sizeof(txSlot *));
1425
24.5k
      c_memset(the->symbolTable, 0, the->symbolModulo * sizeof(txSlot *));
1426
1427
      /* mxGlobal */
1428
24.5k
      mxPushUndefined();
1429
      /* mxException */
1430
24.5k
      mxPushUndefined();
1431
      /* mxProgram */
1432
24.5k
      mxPushNull();
1433
24.5k
      fxNewProgramInstance(the);
1434
      /* mxHosts */
1435
24.5k
      mxPushUndefined();
1436
      /* mxModuleQueue */
1437
24.5k
      fxNewInstance(the);
1438
      /* mxUnhandledPromises */
1439
24.5k
      fxNewInstance(the);
1440
      /* mxDuringJobs */
1441
24.5k
      fxNewInstance(the);
1442
      /* mxFinalizationRegistries */
1443
24.5k
      fxNewInstance(the);
1444
      /* mxPendingJobs */
1445
24.5k
      fxNewInstance(the);
1446
      /* mxRunningJobs */
1447
24.5k
      fxNewInstance(the);
1448
      /* mxBreakpoints */
1449
24.5k
      mxPushList();
1450
      /* mxHostInspectors */
1451
24.5k
      mxPushList();
1452
      /* mxInstanceInspectors */
1453
24.5k
      mxPushList();
1454
1455
3.58M
      for (id = mxInstanceInspectorsStackIndex + 1; id < mxEmptyCodeStackIndex; id++)
1456
3.56M
        mxPushUndefined();
1457
1458
      /* mxEmptyCode */
1459
24.5k
      mxPushUndefined();
1460
24.5k
      the->stack->value.code.address = (txByte*)gxNoCode;
1461
24.5k
      the->stack->value.code.closures = C_NULL;
1462
24.5k
      the->stack->kind = XS_CODE_X_KIND;  
1463
      /* mxEmptyString */
1464
24.5k
      mxPushStringX("");
1465
      /* mxEmptyRegExp */
1466
24.5k
      mxPushStringX("(?:)");
1467
      /* mxBigIntString */
1468
24.5k
      mxPushStringX("bigint");
1469
      /* mxBooleanString */
1470
24.5k
      mxPushStringX("boolean");
1471
      /* mxDefaultString */
1472
24.5k
      mxPushStringX("default");
1473
      /* mxFunctionString */
1474
24.5k
      mxPushStringX("function");
1475
      /* mxNumberString */
1476
24.5k
      mxPushStringX("number");
1477
      /* mxObjectString */
1478
24.5k
      mxPushStringX("object");
1479
      /* mxStringString */
1480
24.5k
      mxPushStringX("string");
1481
      /* mxSymbolString */
1482
24.5k
      mxPushStringX("symbol");
1483
      /* mxUndefinedString */
1484
24.5k
      mxPushStringX("undefined");
1485
1486
24.5k
      fxBuildKeys(the);
1487
24.5k
      fxBuildGlobal(the);
1488
24.5k
      fxBuildObject(the);
1489
24.5k
      fxBuildFunction(the);
1490
24.5k
      fxBuildGenerator(the);
1491
24.5k
      fxBuildArguments(the);
1492
24.5k
      fxBuildArray(the);
1493
24.5k
      fxBuildString(the);
1494
24.5k
      fxBuildBoolean(the);
1495
24.5k
      fxBuildNumber(the);
1496
24.5k
      fxBuildBigInt(the);
1497
24.5k
      fxBuildDate(the);
1498
24.5k
      fxBuildMath(the);
1499
24.5k
      fxBuildRegExp(the);
1500
24.5k
      fxBuildError(the);
1501
24.5k
      fxBuildJSON(the);
1502
24.5k
      fxBuildDataView(the);
1503
24.5k
      fxBuildAtomics(the);
1504
24.5k
      fxBuildPromise(the);
1505
24.5k
      fxBuildSymbol(the);
1506
24.5k
      fxBuildProxy(the);
1507
24.5k
      fxBuildMapSet(the);
1508
24.5k
      fxBuildModule(the);
1509
      
1510
24.5k
      mxPushUndefined();
1511
24.5k
      mxPush(mxObjectPrototype);
1512
  #ifdef mxLink
1513
      slot = fxLastProperty(the, fxNewObjectInstance(the));
1514
  #else
1515
24.5k
      slot = fxLastProperty(the, fxNewGlobalInstance(the));
1516
24.5k
  #endif
1517
1.52M
      for (id = XS_SYMBOL_ID_COUNT; id < _Infinity; id++)
1518
1.49M
        slot = fxNextSlotProperty(the, slot, &the->stackIntrinsics[-1 - id], mxID(id), XS_DONT_ENUM_FLAG);
1519
98.2k
      for (; id < _Compartment; id++)
1520
73.7k
        slot = fxNextSlotProperty(the, slot, &the->stackIntrinsics[-1 - id], mxID(id), XS_GET_ONLY);
1521
122k
      for (; id < XS_INTRINSICS_COUNT; id++)
1522
98.2k
        slot = fxNextSlotProperty(the, slot, &the->stackIntrinsics[-1 - id], mxID(id), XS_DONT_ENUM_FLAG);
1523
24.5k
      slot = fxNextSlotProperty(the, slot, the->stack, mxID(_global), XS_DONT_ENUM_FLAG);
1524
24.5k
      slot = fxNextSlotProperty(the, slot, the->stack, mxID(_globalThis), XS_DONT_ENUM_FLAG);
1525
24.5k
      mxGlobal.value = the->stack->value;
1526
24.5k
      mxGlobal.kind = the->stack->kind;
1527
24.5k
      fxNewInstance(the);
1528
24.5k
      fxNewInstance(the);
1529
24.5k
      mxPushUndefined();
1530
24.5k
      fxNewEnvironmentInstance(the, C_NULL);
1531
24.5k
      mxPushUndefined();
1532
24.5k
      mxPushUndefined();
1533
24.5k
      mxPushUndefined();
1534
24.5k
      mxPushUndefined();
1535
24.5k
      mxPushUndefined();
1536
24.5k
      mxModuleInstanceInternal(mxProgram.value.reference)->value.module.realm = fxNewRealmInstance(the);
1537
24.5k
      mxPop();
1538
1539
24.5k
            the->collectFlag = XS_COLLECTING_FLAG;
1540
      
1541
            /*{
1542
        int c = 32;
1543
        while (--c)
1544
          fxCollectGarbage(the);
1545
      }*/
1546
1547
24.5k
    #ifdef mxDebug
1548
24.5k
      fxLogin(the);
1549
24.5k
    #endif
1550
1551
24.5k
      the->firstJump = C_NULL;
1552
24.5k
    }
1553
0
    else {
1554
0
      if (gxDefaults.terminateSharedCluster)
1555
0
        gxDefaults.terminateSharedCluster(the);
1556
0
      fxFree(the);
1557
0
      c_free(the);
1558
0
      the = NULL;
1559
0
    }
1560
24.5k
  }
1561
24.5k
  return the;
1562
24.5k
}
1563
1564
void fxDeleteMachine(txMachine* the)
1565
24.5k
{
1566
24.5k
  txSlot* aSlot;
1567
24.5k
#ifndef mxLink
1568
24.5k
  txSlot* bSlot;
1569
24.5k
  txSlot* cSlot;
1570
24.5k
#endif
1571
1572
24.5k
  if (!(the->shared)) {
1573
  #ifdef mxFrequency
1574
    fxReportFrequency(the);
1575
  #endif
1576
24.5k
  #ifdef mxDebug
1577
24.5k
    fxLogout(the);
1578
24.5k
  #endif
1579
24.5k
  }
1580
24.5k
  the->context = C_NULL;
1581
24.5k
  aSlot = the->cRoot;
1582
24.5k
  while (aSlot) {
1583
1
    aSlot->flag |= XS_MARK_FLAG;
1584
1
    aSlot = aSlot->next;
1585
1
  }
1586
24.5k
#ifndef mxLink
1587
24.5k
  aSlot = the->firstHeap;
1588
50.9k
  while (aSlot) {
1589
26.3k
    bSlot = aSlot + 1;
1590
26.3k
    cSlot = aSlot->value.reference;
1591
863M
    while (bSlot < cSlot) {
1592
863M
      if ((bSlot->kind == XS_HOST_KIND) && (bSlot->value.host.variant.destructor)) {
1593
7.96k
        if (bSlot->flag & XS_HOST_HOOKS_FLAG) {
1594
0
          if (bSlot->value.host.variant.hooks->destructor)
1595
0
            (*(bSlot->value.host.variant.hooks->destructor))(bSlot->value.host.data);
1596
0
        }
1597
7.96k
        else
1598
7.96k
          (*(bSlot->value.host.variant.destructor))(bSlot->value.host.data);
1599
7.96k
      }
1600
863M
      bSlot++;
1601
863M
    }
1602
26.3k
    aSlot = aSlot->next;
1603
26.3k
  }
1604
24.5k
#endif
1605
24.5k
  fxDeleteMachinePlatform(the);
1606
24.5k
  if (gxDefaults.terminateSharedCluster)
1607
24.5k
    gxDefaults.terminateSharedCluster(the);
1608
24.5k
  fxFree(the);
1609
24.5k
  c_free(the);
1610
24.5k
}
1611
1612
#if mxAliasInstance
1613
txMachine* fxCloneMachine(txCreation* theCreation, txMachine* theMachine, txString theName, void* theContext)
1614
{
1615
  txMachine* the = (txMachine *)c_calloc(1, sizeof(txMachine));
1616
  if (the) {
1617
    txJump aJump;
1618
1619
    aJump.nextJump = C_NULL;
1620
    aJump.stack = C_NULL;
1621
    aJump.scope = C_NULL;
1622
    aJump.frame = C_NULL;
1623
    aJump.code = C_NULL;
1624
    aJump.flag = 0;
1625
    the->firstJump = &aJump;
1626
    if (c_setjmp(aJump.buffer) == 0) {
1627
      txSlot* sharedSlot;
1628
      txSlot* slot;
1629
1630
      if (gxDefaults.initializeSharedCluster)
1631
        gxDefaults.initializeSharedCluster(the);
1632
1633
      the->preparation = theMachine->preparation;
1634
      the->context = theContext;
1635
      the->sharedMachine = theMachine;
1636
      fxCreateMachinePlatform(the);
1637
1638
    #ifdef mxDebug
1639
      the->name = theName;
1640
    #endif
1641
      the->profileID = theMachine->profileID;
1642
      fxAllocate(the, theCreation);
1643
1644
            c_memcpy(the->nameTable, theMachine->nameTable, the->nameModulo * sizeof(txSlot *));
1645
      c_memcpy(the->symbolTable, theMachine->symbolTable, the->symbolModulo * sizeof(txSlot *));
1646
      the->colors = theMachine->colors;
1647
      the->keyCount = theMachine->keyIndex + (txID)theCreation->initialKeyCount;
1648
      the->keyIndex = theMachine->keyIndex;
1649
      the->keyOffset = the->keyIndex;
1650
      the->keyArrayHost = theMachine->keyArray;
1651
      
1652
      the->aliasCount = theMachine->aliasCount;
1653
      if (the->aliasCount) {
1654
        the->aliasArray = (txSlot **)c_malloc_uint32(the->aliasCount * sizeof(txSlot*));
1655
        if (!the->aliasArray)
1656
          fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT);
1657
        c_memset(the->aliasArray, 0, the->aliasCount * sizeof(txSlot*));
1658
      }
1659
1660
      /* mxGlobal */
1661
      mxPushUndefined();
1662
      /* mxException */
1663
      mxPushUndefined();
1664
      /* mxProgram */
1665
      mxPushNull();
1666
      fxNewProgramInstance(the);
1667
      /* mxHosts */
1668
      mxPushUndefined();
1669
      /* mxModuleQueue */
1670
      fxNewInstance(the);
1671
      /* mxUnhandledPromises */
1672
      fxNewInstance(the);
1673
      /* mxDuringJobs */
1674
      fxNewInstance(the);
1675
      /* mxFinalizationRegistries */
1676
      fxNewInstance(the);
1677
      /* mxPendingJobs */
1678
      fxNewInstance(the);
1679
      /* mxRunningJobs */
1680
      fxNewInstance(the);
1681
      /* mxBreakpoints */
1682
      mxPushList();
1683
      /* mxHostInspectors */
1684
      mxPushList();
1685
      /* mxInstanceInspectors */
1686
      mxPushList();
1687
1688
      the->stackIntrinsics = theMachine->stackTop;
1689
      the->stackPrototypes = theMachine->stackTop - XS_INTRINSICS_COUNT;
1690
1691
      mxPushUndefined();
1692
      mxPush(theMachine->stackTop[-1 - mxGlobalStackIndex]);
1693
      slot = fxLastProperty(the, fxNewObjectInstance(the));
1694
      slot = fxNextSlotProperty(the, slot, the->stack, mxID(_global), XS_DONT_ENUM_FLAG);
1695
      slot = fxNextSlotProperty(the, slot, the->stack, mxID(_globalThis), XS_DONT_ENUM_FLAG);
1696
      mxGlobal.value = the->stack->value;
1697
      mxGlobal.kind = the->stack->kind;
1698
      
1699
      fxNewInstance(the);
1700
      mxPush(theMachine->stackTop[-1 - mxProgramStackIndex]); //@@
1701
      fxNewHostInstance(the);
1702
      
1703
      mxPushUndefined();
1704
      slot = fxLastProperty(the, fxNewEnvironmentInstance(the, C_NULL));
1705
      sharedSlot = theMachine->stackTop[-1 - mxExceptionStackIndex].value.reference->next->next; //@@
1706
      while (sharedSlot) {
1707
        slot = slot->next = fxDuplicateSlot(the, sharedSlot);
1708
        sharedSlot = sharedSlot->next;
1709
      }
1710
      
1711
      
1712
      mxPushUndefined();
1713
      mxPushUndefined();
1714
      mxPushUndefined();
1715
      mxPushUndefined();
1716
      mxPushUndefined();
1717
      mxModuleInstanceInternal(mxProgram.value.reference)->value.module.realm = fxNewRealmInstance(the);
1718
      mxPop();
1719
      
1720
      the->collectFlag = XS_COLLECTING_FLAG;
1721
1722
    #ifdef mxDebug
1723
      fxLogin(the);
1724
    #endif
1725
1726
      the->firstJump = C_NULL;
1727
1728
    }
1729
    else {
1730
      fxFree(the);
1731
      c_free(the);
1732
      the = NULL;
1733
    }
1734
  }
1735
  return the;
1736
}
1737
1738
txMachine* fxPrepareMachine(txCreation* creation, txPreparation* preparation, txString name, void* context, void* archive)
1739
{
1740
  txMachine _root;
1741
  txMachine* root = &_root;
1742
  if ((preparation->version[0] != XS_MAJOR_VERSION) || (preparation->version[1] != XS_MINOR_VERSION))
1743
    return C_NULL;
1744
  c_memset(root, 0, sizeof(txMachine));
1745
  root->preparation = preparation;
1746
  root->keyArray = preparation->keys;
1747
  root->colors = preparation->colors;
1748
  root->keyCount = (txID)preparation->keyCount + (txID)preparation->creation.initialKeyCount;
1749
  root->keyIndex = (txID)preparation->keyCount;
1750
  root->nameModulo = preparation->nameModulo;
1751
  root->nameTable = preparation->names;
1752
  root->symbolModulo = preparation->symbolModulo;
1753
  root->symbolTable = preparation->symbols;
1754
1755
  root->stack = &preparation->stack[0];
1756
  root->stackBottom = &preparation->stack[0];
1757
  root->stackTop = &preparation->stack[preparation->stackCount];
1758
1759
  root->firstHeap = &preparation->heap[0];
1760
  root->freeHeap = &preparation->heap[preparation->heapCount - 1];
1761
  root->aliasCount = (txID)preparation->aliasCount;
1762
  
1763
  root->profileID = (txID)preparation->profileID;
1764
  
1765
  if (!creation)
1766
    creation = &preparation->creation;
1767
  return fxCloneMachine(creation, root, name, context);
1768
}
1769
1770
void fxShareMachine(txMachine* the)
1771
{
1772
  if (!(the->shared)) {
1773
  #ifdef mxDebug
1774
    fxLogout(the);
1775
  #endif
1776
    {
1777
      txSlot* realm = mxModuleInstanceInternal(mxProgram.value.reference)->value.module.realm;
1778
      txSlot* modules = mxOwnModules(realm)->value.reference;
1779
      txSlot* module = modules->next;
1780
      while (module) {
1781
        mxModuleInstanceInternal(module->value.reference)->value.module.realm = NULL;
1782
        module = module->next;
1783
      }
1784
      mxModuleInstanceInternal(mxProgram.value.reference)->value.module.realm = NULL;
1785
      mxException.kind = XS_REFERENCE_KIND;
1786
      mxException.value.reference = mxRealmClosures(realm)->value.reference;
1787
      mxProgram.value.reference = modules; //@@
1788
      
1789
      {
1790
        txSlot* target = fxNewInstance(the);
1791
        txSlot* modules = mxOwnModules(realm)->value.reference;
1792
        txSlot* module = modules->next;
1793
        while (module) {
1794
          target = target->next = fxNewSlot(the);
1795
          target->value.symbol = mxModuleInstanceInternal(module->value.reference)->value.module.id;
1796
          target->kind = XS_SYMBOL_KIND;
1797
          target->ID = mxModuleInstanceInternal(module->value.reference)->value.module.id;
1798
          module = module->next;
1799
        }
1800
        mxPull(mxHosts); //@@
1801
      }
1802
      mxModuleQueue = mxUndefined;
1803
      mxDuringJobs = mxUndefined;
1804
      mxFinalizationRegistries = mxUndefined;
1805
      mxPendingJobs = mxUndefined;
1806
      mxRunningJobs = mxUndefined;
1807
      mxBreakpoints = mxUndefined;
1808
      mxHostInspectors = mxUndefined;
1809
      mxInstanceInspectors = mxUndefined;
1810
    }
1811
    fxCollectGarbage(the);
1812
    fxShare(the);
1813
    the->shared = 1;
1814
  }
1815
}
1816
#endif
1817
1818
/* Garbage Collector */
1819
1820
void fxCollectGarbage(txMachine* the)
1821
13.7k
{
1822
13.7k
  fxCollect(the, XS_COMPACT_FLAG | XS_COLLECT_KEYS_FLAG);
1823
13.7k
}
1824
1825
void fxEnableGarbageCollection(txMachine* the, txBoolean enableIt)
1826
0
{
1827
0
  if (enableIt)
1828
0
    the->collectFlag |= XS_COLLECTING_FLAG;
1829
0
  else
1830
0
    the->collectFlag &= ~XS_COLLECTING_FLAG;
1831
0
}
1832
1833
void fxRemember(txMachine* the, txSlot* theSlot)
1834
1
{
1835
1
  txSlot* aHeap;
1836
1
  txSlot* aLimit;
1837
1
  if ((the->stack <= theSlot) && (theSlot < the->stackTop)) {
1838
0
    return;
1839
0
  }
1840
1
  aHeap = the->firstHeap;
1841
2
  while (aHeap) {
1842
1
    aLimit = aHeap->value.reference;
1843
1
    if ((aHeap < theSlot) && (theSlot < aLimit)) {
1844
0
      return;
1845
0
    }
1846
1
    aHeap = aHeap->next;
1847
1
  }
1848
1
  fxForget(the, theSlot);
1849
1
  theSlot->next = the->cRoot;
1850
1
  the->cRoot = theSlot;
1851
1
}
1852
1853
void fxForget(txMachine* the, txSlot* theSlot)
1854
1
{
1855
1
  if (!(theSlot->flag & XS_MARK_FLAG)) {
1856
1
    txSlot* aSlot = the->cRoot;
1857
1
    txSlot** aSlotAddr = &(the->cRoot);
1858
1
    while ((aSlot = *aSlotAddr)) {
1859
0
      if (aSlot == theSlot) {
1860
0
        *aSlotAddr = aSlot->next;
1861
0
        return;
1862
0
      }
1863
0
      aSlotAddr = &(aSlot->next);
1864
0
    }
1865
1
  }
1866
1
}
1867
1868
void fxAccess(txMachine* the, txSlot* theSlot)
1869
0
{
1870
0
  if (theSlot)
1871
0
    the->scratch = *theSlot;
1872
0
  else
1873
0
    the->scratch.kind = XS_UNDEFINED_KIND;
1874
0
  the->scratch.next = NULL;
1875
0
  the->scratch.flag = XS_NO_FLAG;
1876
0
  the->scratch.ID = XS_NO_ID;
1877
0
}
1878
1879
/* Host */
1880
1881
txMachine* fxBeginHost(txMachine* the)
1882
74.1M
{
1883
74.1M
#if defined(mxInstrument) || defined(mxProfile)
1884
74.1M
  if (the->frame == C_NULL)
1885
24.5k
    fxCheckProfiler(the, C_NULL);
1886
74.1M
#endif
1887
74.1M
  mxOverflow(-5);
1888
  /* THIS */
1889
74.1M
  (--the->stack)->next = C_NULL;
1890
74.1M
  mxInitSlotKind(the->stack, XS_UNDEFINED_KIND);
1891
  /* FUNCTION */
1892
74.1M
  (--the->stack)->next = C_NULL;
1893
74.1M
  mxInitSlotKind(the->stack, XS_UNDEFINED_KIND);
1894
  /* RESULT */
1895
74.1M
  (--the->stack)->next = C_NULL;
1896
74.1M
  mxInitSlotKind(the->stack, XS_UNDEFINED_KIND);
1897
  /* FRAME */
1898
74.1M
  (--the->stack)->next = the->frame;
1899
74.1M
  the->stack->ID = 0;
1900
74.1M
  the->stack->flag = XS_C_FLAG;
1901
74.1M
#ifdef mxDebug
1902
74.1M
  if (the->breakOnStartFlag) {
1903
0
    the->breakOnStartFlag = 0;
1904
0
    the->stack->flag |= XS_STEP_INTO_FLAG | XS_STEP_OVER_FLAG;
1905
0
  }
1906
74.1M
  if (the->frame && (the->frame->flag & XS_STEP_INTO_FLAG))
1907
0
    the->stack->flag |= XS_STEP_INTO_FLAG | XS_STEP_OVER_FLAG;
1908
74.1M
#endif
1909
74.1M
  the->stack->kind = XS_FRAME_KIND;
1910
74.1M
  the->stack->value.frame.code = the->code;
1911
74.1M
  the->stack->value.frame.scope = the->scope;
1912
74.1M
  the->frame = the->stack;
1913
  /* VARC */
1914
74.1M
  (--the->stack)->next = C_NULL;
1915
74.1M
  the->stack->ID = XS_NO_ID;
1916
74.1M
  the->stack->flag = XS_NO_FLAG;
1917
74.1M
  the->stack->kind = XS_VAR_KIND;
1918
74.1M
  the->stack->value.environment.variable.count = 0;
1919
74.1M
  the->stack->value.environment.line = 0;
1920
74.1M
  the->scope = the->stack;
1921
74.1M
  the->code = C_NULL;
1922
74.1M
  return the;
1923
74.1M
}
1924
1925
void fxEndHost(txMachine* the)
1926
74.0M
{
1927
74.0M
    if (the->frame->next == C_NULL) {
1928
23.6k
        fxEndJob(the);
1929
23.6k
    }
1930
74.0M
  the->stack = the->frame + 4;
1931
74.0M
  the->scope = the->frame->value.frame.scope;
1932
74.0M
  the->code = the->frame->value.frame.code;
1933
74.0M
  the->frame = the->frame->next;
1934
74.0M
}
1935
1936
void fxEndJob(txMachine* the)
1937
37.1k
{
1938
37.1k
  if (gxDefaults.cleanupFinalizationRegistries)
1939
37.1k
    gxDefaults.cleanupFinalizationRegistries(the);
1940
37.1k
  if (mxDuringJobs.kind == XS_REFERENCE_KIND)
1941
37.1k
    mxDuringJobs.value.reference->next = C_NULL;
1942
37.1k
  fxCheckUnhandledRejections(the, 0);
1943
37.1k
}
1944
1945
void fxExitToHost(txMachine* the)
1946
950
{
1947
950
  txJump* jump = the->firstJump;
1948
175k
  while (jump->nextJump) {
1949
174k
    txJump* nextJump = jump->nextJump;
1950
174k
    if (jump->flag)
1951
13.0k
      c_free(jump);
1952
174k
    jump = nextJump;
1953
174k
  }
1954
950
  c_longjmp(jump->buffer, 1);
1955
950
}
1956
1957
typedef struct {
1958
  txMachine* machine;
1959
  txU1* archive;
1960
  txArchiveRead read;
1961
  txArchiveWrite write;
1962
  txU1* buffer;
1963
  txU1* scratch;
1964
  size_t offset;
1965
  size_t size;
1966
  size_t bufferCode;
1967
  size_t bufferLoop;
1968
  size_t bufferOffset;
1969
  size_t bufferSize;
1970
  size_t scratchSize;
1971
  txID* ids;
1972
  txID* map;
1973
  txID* maps;
1974
  c_jmp_buf jmp_buf;
1975
  txBoolean dirty;
1976
} txMapper;
1977
1978
static void fxMapperMapID(txMapper* self, txID id);
1979
static void fxMapperMapIDs(txMapper* self);
1980
static txU1 fxMapperRead1(txMapper* self);
1981
static txU2 fxMapperRead2(txMapper* self);
1982
static txU4 fxMapperRead4(txMapper* self);
1983
static void fxMapperReadAtom(txMapper* self, Atom* atom);
1984
static void fxMapperSkip(txMapper* self, size_t size);
1985
static void fxMapperStep(txMapper* self);
1986
1987
#define mxMapAtom(POINTER) \
1988
0
  atom.atomSize = c_read32be(POINTER); \
1989
0
  POINTER += 4; \
1990
0
  atom.atomType = c_read32be(POINTER); \
1991
0
  POINTER += 4
1992
  
1993
1994
#define mxElseStatus(_ASSERTION,_STATUS) \
1995
0
  ((void)((_ASSERTION) || ((self->buffer[8] = (_STATUS)), c_longjmp(self->jmp_buf, 1), 0)))
1996
0
#define mxElseFatalCheck(_ASSERTION) mxElseStatus(_ASSERTION, XS_FATAL_CHECK_EXIT)
1997
0
#define mxElseNoMoreKeys(_ASSERTION) mxElseStatus(_ASSERTION, XS_NO_MORE_KEYS_EXIT)
1998
0
#define mxElseNotEnoughMemory(_ASSERTION) mxElseStatus(_ASSERTION, XS_NOT_ENOUGH_MEMORY_EXIT)
1999
#define mxElseInstall(_ASSERTION) if (!(_ASSERTION)) goto install
2000
2001
0
#define mxArchiveHeaderSize (sizeof(Atom) + sizeof(Atom) + XS_VERSION_SIZE + sizeof(Atom) + XS_DIGEST_SIZE)
2002
2003
static txU1 *fxGetArchiveModules(txMachine *the, void* archive, txU4 *size)
2004
0
{
2005
0
  txPreparation* preparation = the->preparation;
2006
0
  txU1* p = archive;
2007
0
  if (!preparation || !p) {
2008
0
    *size = 0;
2009
0
    return NULL;
2010
0
  }
2011
0
  p += mxArchiveHeaderSize;
2012
  // NAME
2013
0
  p += c_read32be(p);
2014
  // SYMB
2015
0
  p += c_read32be(p);
2016
  // IDEN
2017
0
  p += c_read32be(p);
2018
  // MAPS
2019
0
  p += c_read32be(p);
2020
  // MODS
2021
0
  *size = c_read32be(p) - sizeof(Atom);
2022
0
  return p + sizeof(Atom);
2023
0
}
2024
2025
void* fxGetArchiveCode(txMachine* the, void* archive, txString path, size_t* size)
2026
0
{
2027
0
  txU4 atomSize;
2028
0
  txU1 *p = fxGetArchiveModules(the, archive, &atomSize), *q;
2029
0
  if (!p)
2030
0
    return NULL; 
2031
0
  q = p + atomSize;
2032
0
  while (p < q) {
2033
    // PATH
2034
0
    atomSize = c_read32be(p);
2035
0
    if (!c_strcmp(path, (txString)(p + sizeof(Atom)))) {
2036
0
      p += atomSize;
2037
0
      atomSize = c_read32be(p);
2038
0
      *size = atomSize - sizeof(Atom);
2039
0
      return p + sizeof(Atom);
2040
0
    }
2041
0
    p += atomSize;
2042
    // CODE
2043
0
    atomSize = c_read32be(p);
2044
0
    p += atomSize;
2045
0
  }
2046
0
  return C_NULL;
2047
0
}
2048
2049
txInteger fxGetArchiveCodeCount(txMachine* the, void* archive)
2050
0
{
2051
0
  txInteger count = 0;
2052
0
  txU4 size;
2053
0
  txU1 *p = fxGetArchiveModules(the, archive, &size);
2054
0
  if (p) {
2055
0
    txU1 *q = p + size;
2056
0
    while (p < q) {
2057
      // PATH
2058
0
      p += c_read32be(p);
2059
      // CODE
2060
0
      p += c_read32be(p);
2061
0
      count += 1;
2062
0
    }
2063
0
  }
2064
0
  return count;
2065
0
}
2066
2067
void* fxGetArchiveCodeName(txMachine* the, void* archive, txInteger index)
2068
0
{
2069
0
  txU4 atomSize;
2070
0
  txU1 *p = fxGetArchiveModules(the, archive, &atomSize), *q;
2071
0
  if (!p)
2072
0
    return NULL;
2073
0
  q = p + atomSize;
2074
0
  while (p < q) {
2075
    // PATH
2076
0
    if (!index--)
2077
0
      return (txString)(p + sizeof(Atom));
2078
0
    p += c_read32be(p);
2079
    // CODE
2080
0
    p += c_read32be(p);
2081
0
  }
2082
0
  return C_NULL;
2083
0
}
2084
2085
static txU1 *fxGetArchiveResources(txMachine *the, void* archive, txU4 *size)
2086
0
{
2087
0
  txPreparation* preparation = the->preparation;
2088
0
  txU1* p = archive;
2089
0
  if (!preparation || !p) {
2090
0
    *size = 0;
2091
0
    return NULL;
2092
0
  }
2093
0
  p += mxArchiveHeaderSize;
2094
  // NAME
2095
0
  p += c_read32be(p);
2096
  // SYMB
2097
0
  p += c_read32be(p);
2098
  // IDEN
2099
0
  p += c_read32be(p);
2100
  // MAPS
2101
0
  p += c_read32be(p);
2102
  // MODS
2103
0
  p += c_read32be(p);
2104
  // RSRC
2105
0
  *size = c_read32be(p) - sizeof(Atom);
2106
0
  return p + sizeof(Atom);
2107
0
}
2108
2109
void* fxGetArchiveData(txMachine* the, void* archive, txString path, size_t* size)
2110
0
{
2111
0
  txU4 atomSize;
2112
0
  txU1 *p = fxGetArchiveResources(the, archive, &atomSize), *q;
2113
0
  if (!p)
2114
0
    return NULL; 
2115
0
  q = p + atomSize;
2116
0
  while (p < q) {
2117
    // PATH
2118
0
    atomSize = c_read32be(p);
2119
0
    if (!c_strcmp(path, (txString)(p + sizeof(Atom)))) {
2120
0
      p += atomSize;
2121
0
      atomSize = c_read32be(p);
2122
0
      *size = atomSize - sizeof(Atom);
2123
0
      return p + sizeof(Atom);
2124
0
    }
2125
0
    p += atomSize;
2126
    // DATA
2127
0
    atomSize = c_read32be(p);
2128
0
    p += atomSize;
2129
0
  }
2130
0
  return C_NULL;
2131
0
}
2132
2133
txInteger fxGetArchiveDataCount(txMachine* the, void* archive)
2134
0
{
2135
0
  txInteger count = 0;
2136
0
  txU4 size;
2137
0
  txU1 *p = fxGetArchiveResources(the, archive, &size);
2138
0
  if (p) {
2139
0
    txU1 *q = p + size;
2140
0
    while (p < q) {
2141
      // PATH
2142
0
      p += c_read32be(p);
2143
      // DATA
2144
0
      p += c_read32be(p);
2145
0
      count += 1;
2146
0
    }
2147
0
  }
2148
0
  return count;
2149
0
}
2150
2151
void* fxGetArchiveDataName(txMachine* the, void* archive, txInteger index)
2152
0
{
2153
0
  txU4 atomSize;
2154
0
  txU1 *p = fxGetArchiveResources(the, archive, &atomSize), *q;
2155
0
  if (!p)
2156
0
    return NULL;
2157
0
  q = p + atomSize;
2158
0
  while (p < q) {
2159
    // PATH
2160
0
    if (!index--)
2161
0
      return (txString)(p + sizeof(Atom));
2162
0
    p += c_read32be(p);
2163
    // DATA
2164
0
    p += c_read32be(p);
2165
0
  }
2166
0
  return C_NULL;
2167
0
}
2168
2169
void* fxGetArchiveName(txMachine* the, void* archive)
2170
0
{
2171
0
  txU1* p = archive;
2172
0
  if (!p)
2173
0
    return NULL;
2174
0
  p += mxArchiveHeaderSize;
2175
  // NAME
2176
0
  return p + sizeof(Atom);
2177
0
}
2178
2179
void* fxMapArchive(txMachine* the, txPreparation* preparation, void* archive, size_t bufferSize, txArchiveRead read, txArchiveWrite write)
2180
0
{
2181
0
  txMapper mapper;
2182
0
  txMapper* self = &mapper;
2183
0
  Atom atom;
2184
0
  txU1* p;
2185
0
  txU1* q;
2186
0
  txID id;
2187
0
  txID c, i;
2188
0
  txFlag clean;
2189
2190
0
  c_memset(self, 0, sizeof(txMapper));
2191
0
  if (c_setjmp(self->jmp_buf) == 0) {
2192
0
    self->machine = the;
2193
0
    self->archive = archive;
2194
0
    self->read = read;
2195
0
    self->write = write;
2196
    
2197
0
    self->scratchSize = 1024;
2198
0
    self->scratch = c_malloc(self->scratchSize + bufferSize);
2199
0
    mxElseNotEnoughMemory(self->scratch != C_NULL);
2200
0
    self->bufferSize = bufferSize;
2201
0
    self->buffer = self->scratch + self->scratchSize;
2202
    
2203
0
    mxElseFatalCheck(self->read(self->archive, 0, self->buffer, mxArchiveHeaderSize));
2204
  
2205
0
    p = self->buffer;
2206
0
    mxMapAtom(p);
2207
0
    if (atom.atomType != XS_ATOM_ARCHIVE) {
2208
0
      self->archive = NULL;
2209
0
      goto bail;
2210
0
    }
2211
0
    self->size = atom.atomSize;
2212
0
    mxMapAtom(p);
2213
0
    mxElseFatalCheck(atom.atomType == XS_ATOM_VERSION);
2214
0
    mxElseFatalCheck(atom.atomSize == sizeof(Atom) + 4);
2215
0
    mxElseFatalCheck(*p++ == XS_MAJOR_VERSION);
2216
0
    mxElseFatalCheck(*p++ == XS_MINOR_VERSION);
2217
0
    p++;
2218
0
    p++;
2219
0
    mxMapAtom(p);
2220
0
    mxElseFatalCheck(atom.atomType == XS_ATOM_SIGNATURE);
2221
0
    mxElseFatalCheck(atom.atomSize == sizeof(Atom) + XS_DIGEST_SIZE);
2222
0
    p += XS_DIGEST_SIZE;
2223
    
2224
0
    self->bufferOffset = mxArchiveHeaderSize;
2225
0
    if (self->bufferSize > self->size)
2226
0
      self->bufferSize = self->size;
2227
0
    mxElseFatalCheck(self->read(self->archive, mxArchiveHeaderSize, p, self->bufferSize - mxArchiveHeaderSize));
2228
  
2229
0
    fxMapperReadAtom(self, &atom);
2230
0
    mxElseFatalCheck(atom.atomType == XS_ATOM_NAME);
2231
0
    fxMapperSkip(self, atom.atomSize - sizeof(Atom));
2232
  
2233
0
    fxMapperReadAtom(self, &atom);
2234
0
    mxElseFatalCheck(atom.atomType == XS_ATOM_SYMBOLS);
2235
0
    c = fxMapperRead2(self);
2236
0
    self->ids = c_malloc(c * sizeof(txID));
2237
0
    mxElseFatalCheck(self->ids != C_NULL);
2238
0
    id = (txID)preparation->keyCount;
2239
0
    for (i = 0; i < c; i++) {
2240
0
      txU1 byte;
2241
0
      p = self->scratch;
2242
0
      q = p + self->scratchSize;
2243
0
      while ((byte = fxMapperRead1(self))) {
2244
0
        mxElseFatalCheck(p < q);
2245
0
        *p++ = byte;
2246
0
      }
2247
0
      mxElseFatalCheck(p < q);
2248
0
      *p = 0;
2249
0
      if (i == 0)
2250
0
        self->ids[i] = XS_NO_ID;
2251
0
      else
2252
0
        self->ids[i] = fxID(the, (txString)self->scratch);
2253
0
    }
2254
    
2255
0
    fxMapperReadAtom(self, &atom);
2256
0
    mxElseFatalCheck(atom.atomType == XS_ATOM_IDENTIFIERS);
2257
0
    self->bufferLoop = self->bufferOffset - sizeof(Atom) + atom.atomSize;
2258
0
    i = 0;
2259
0
    clean = 1;
2260
0
    while (self->bufferOffset < self->bufferLoop) {
2261
0
      txID id = self->ids[i];
2262
0
      txU1 low = (txU1)(id & 0x00FF);
2263
0
      txU1 high =  (txU1)(id >> 8);
2264
0
      if (self->bufferOffset == self->bufferSize)
2265
0
        fxMapperStep(self);
2266
0
      if (*(self->buffer + self->bufferOffset) != low) {
2267
0
        *(self->buffer + self->bufferOffset) = low;
2268
0
        self->dirty = 1;
2269
0
        clean = 0;
2270
0
      }
2271
0
      self->bufferOffset++;
2272
0
      if (self->bufferOffset == self->bufferSize)
2273
0
        fxMapperStep(self);
2274
0
      if (*(self->buffer + self->bufferOffset) != high) {
2275
0
        *(self->buffer + self->bufferOffset) = high;
2276
0
        self->dirty = 1;
2277
0
        clean = 0;
2278
0
      }
2279
0
      self->bufferOffset++;
2280
0
      i++;
2281
0
    }
2282
0
    if (clean)
2283
0
      goto bail;
2284
    
2285
0
    fxMapperReadAtom(self, &atom);
2286
0
    mxElseFatalCheck(atom.atomType == XS_ATOM_MAPS);
2287
0
    self->bufferLoop = self->bufferOffset - sizeof(Atom) + atom.atomSize;
2288
0
    self->maps = self->map = c_malloc((self->bufferLoop - self->bufferOffset));
2289
0
    mxElseFatalCheck(self->maps != C_NULL);
2290
0
    while (self->bufferOffset < self->bufferLoop)
2291
0
      *self->map++ = fxMapperRead2(self);
2292
0
    self->map = self->maps;
2293
    
2294
0
    fxMapperReadAtom(self, &atom);
2295
0
    mxElseFatalCheck(atom.atomType == XS_ATOM_MODULES);
2296
0
    self->bufferLoop = self->bufferOffset - sizeof(Atom) + atom.atomSize;
2297
0
    while (self->bufferOffset < self->bufferLoop) {
2298
0
      id += 2;
2299
0
      fxMapperReadAtom(self, &atom);
2300
0
      mxElseFatalCheck(atom.atomType == XS_ATOM_PATH);
2301
0
      fxMapperSkip(self, atom.atomSize - sizeof(Atom));
2302
0
      fxMapperReadAtom(self, &atom);
2303
0
      mxElseFatalCheck(atom.atomType == XS_ATOM_CODE);
2304
0
      self->bufferCode = self->bufferOffset - sizeof(Atom) + atom.atomSize;
2305
0
      fxMapperMapIDs(self);
2306
0
    }
2307
    
2308
0
    if (preparation->creation.incrementalKeyCount == 0)
2309
0
      mxElseNoMoreKeys((id - (txID)preparation->keyCount) < (txID)preparation->creation.initialKeyCount);
2310
  
2311
0
    fxMapperReadAtom(self, &atom);
2312
0
    mxElseFatalCheck(atom.atomType == XS_ATOM_RESOURCES);
2313
0
    self->bufferLoop = self->bufferOffset - sizeof(Atom) + atom.atomSize;
2314
0
    while (self->bufferOffset < self->bufferLoop) {
2315
0
      fxMapperReadAtom(self, &atom);
2316
0
      mxElseFatalCheck(atom.atomType == XS_ATOM_PATH);
2317
0
      fxMapperSkip(self, atom.atomSize - sizeof(Atom));
2318
0
      fxMapperReadAtom(self, &atom);
2319
0
      mxElseFatalCheck(atom.atomType == XS_ATOM_DATA);
2320
0
      fxMapperSkip(self, atom.atomSize - sizeof(Atom));
2321
0
    }
2322
  
2323
0
    if (self->bufferOffset) {
2324
0
      if (self->dirty) {
2325
0
        mxElseFatalCheck(self->write(self->archive, self->offset, self->buffer, self->bufferOffset));
2326
0
        self->dirty = 0;
2327
0
      }
2328
0
    }
2329
0
  }
2330
0
  else {
2331
0
    self->buffer[0] = 0;
2332
0
    self->buffer[1] = 0;
2333
0
    self->buffer[2] = 0;
2334
0
    self->buffer[3] = 9;
2335
0
    self->buffer[4] = 'X';
2336
0
    self->buffer[5] = 'S';
2337
0
    self->buffer[6] = '_';
2338
0
    self->buffer[7] = 'E';
2339
0
    self->write(self->archive, 0, self->buffer, 9);
2340
0
    self->archive = C_NULL;
2341
0
  }
2342
0
bail:
2343
0
  if (self->ids)
2344
0
    c_free(self->ids);
2345
0
  if (self->maps)
2346
0
    c_free(self->maps);
2347
0
  if (self->scratch)
2348
0
    c_free(self->scratch);
2349
0
  return self->archive;
2350
0
}
2351
2352
void fxMapperMapID(txMapper* self, txID id)
2353
0
{
2354
0
  if (self->bufferOffset == self->bufferSize)
2355
0
    fxMapperStep(self);
2356
0
  *(self->buffer + self->bufferOffset) = (txU1)(id & 0x00FF);
2357
0
  self->bufferOffset++;
2358
0
  self->dirty = 1;
2359
0
  if (self->bufferOffset == self->bufferSize)
2360
0
    fxMapperStep(self);
2361
0
  *(self->buffer + self->bufferOffset) = (txU1)(id >> 8);
2362
0
  self->bufferOffset++;
2363
0
  self->dirty = 1;
2364
0
}
2365
2366
void fxMapperMapIDs(txMapper* self)
2367
0
{
2368
0
  register const txS1* bytes = gxCodeSizes;
2369
0
  txU1 code;
2370
0
  txS1 offset;
2371
0
  txU4 index;
2372
0
  while (self->bufferOffset < self->bufferCode) {
2373
    //fprintf(stderr, "%s", gxCodeNames[*((txU1*)p)]);
2374
0
    code = fxMapperRead1(self);
2375
0
    offset = (txS1)c_read8(bytes + code);
2376
0
    if (0 < offset) {
2377
0
      if (XS_CODE_PROFILE == code)
2378
0
        fxMapperMapID(self, fxGenerateProfileID(self->machine));
2379
0
      else
2380
0
        fxMapperSkip(self, offset - 1);
2381
0
    }
2382
0
    else if (0 == offset)
2383
0
      fxMapperMapID(self, self->ids[*(self->map++)]);
2384
0
    else if (-1 == offset) {
2385
0
      index = fxMapperRead1(self);
2386
0
      fxMapperSkip(self, index);
2387
0
    }
2388
0
    else if (-2 == offset) {
2389
0
      index = fxMapperRead2(self); 
2390
0
      fxMapperSkip(self, index);
2391
0
    }
2392
    //fprintf(stderr, "\n");
2393
0
  }
2394
0
}
2395
2396
txU1 fxMapperRead1(txMapper* self)
2397
0
{
2398
0
  txU1 result;
2399
0
  if (self->bufferOffset == self->bufferSize)
2400
0
    fxMapperStep(self);
2401
0
  result = *(self->buffer + self->bufferOffset);
2402
0
  self->bufferOffset++;
2403
0
  return result;
2404
0
}
2405
2406
txU2 fxMapperRead2(txMapper* self)
2407
0
{
2408
0
  txU2 result;
2409
0
  result = fxMapperRead1(self);
2410
0
  result |= fxMapperRead1(self) << 8;
2411
0
  return result;
2412
0
}
2413
2414
txU4 fxMapperRead4(txMapper* self)
2415
0
{
2416
0
  txU4 result;
2417
0
  result = fxMapperRead1(self) << 24;
2418
0
  result |= fxMapperRead1(self) << 16;
2419
0
  result |= fxMapperRead1(self) << 8;
2420
0
  result |= fxMapperRead1(self);
2421
0
  return result;
2422
0
}
2423
2424
void fxMapperReadAtom(txMapper* self, Atom* atom)
2425
0
{
2426
0
  atom->atomSize = fxMapperRead4(self);
2427
0
  atom->atomType = fxMapperRead4(self);
2428
0
}
2429
2430
void fxMapperSkip(txMapper* self, size_t size)
2431
0
{
2432
0
  size_t offset = self->bufferOffset + size;
2433
0
  while ((offset >= self->bufferSize) && (self->bufferSize > 0)) {
2434
0
    offset -= self->bufferSize;
2435
0
    fxMapperStep(self);
2436
0
  }
2437
0
  self->bufferOffset = offset;
2438
0
}
2439
2440
void fxMapperStep(txMapper* self)
2441
0
{
2442
0
  if (self->dirty) {
2443
0
    mxElseFatalCheck(self->write(self->archive, self->offset, self->buffer, self->bufferSize));
2444
0
    self->dirty = 0;
2445
0
  }
2446
0
  self->offset += self->bufferSize;
2447
0
  self->size -= self->bufferSize;
2448
0
  self->bufferCode -= self->bufferSize;
2449
0
  self->bufferLoop -= self->bufferSize;
2450
0
  if (self->bufferSize > self->size)
2451
0
    self->bufferSize = self->size;
2452
0
  if (self->bufferSize > 0)
2453
0
    mxElseFatalCheck(self->read(self->archive, self->offset, self->buffer, self->bufferSize));
2454
0
  self->bufferOffset = 0;
2455
0
}
2456
2457
void fxSetArchive(txMachine* the, void* archive)
2458
0
{
2459
0
  the->archive = archive;
2460
0
  if (archive) {
2461
0
    fxNewHostObject(the, C_NULL);
2462
0
    the->stack->value.reference->next->value.host.data = archive;
2463
0
    mxPush(mxGlobal);
2464
0
    mxDefineID(fxID(the, "archive"), XS_DONT_ENUM_FLAG, XS_GET_ONLY);
2465
0
    mxPop();
2466
0
  }
2467
0
  else {
2468
0
    mxPush(mxGlobal);
2469
0
    mxDeleteID(fxID(the, "archive"));
2470
0
  }
2471
0
}
2472
2473
txBoolean fxIsProfiling(txMachine* the)
2474
0
{
2475
0
#if defined(mxInstrument) || defined(mxProfile)
2476
0
  return (the->profiler) ? 1 : 0;
2477
#else
2478
  return 0;
2479
#endif
2480
0
}
2481
2482
void fxStartProfiling(txMachine* the)
2483
0
{
2484
0
#if defined(mxInstrument) || defined(mxProfile)
2485
0
  if (the->profiler)
2486
0
    return; 
2487
//  if (the->frame)
2488
//    fxAbort(the, XS_FATAL_CHECK_EXIT);
2489
0
  fxCreateProfiler(the);
2490
0
#endif
2491
0
}
2492
2493
void fxStopProfiling(txMachine* the, void* stream)
2494
0
{
2495
0
#if defined(mxInstrument) || defined(mxProfile)
2496
0
  if (!the->profiler)
2497
0
    return; 
2498
//  if (the->frame)
2499
//    fxAbort(the, XS_FATAL_CHECK_EXIT);
2500
0
  fxDeleteProfiler(the, stream);
2501
0
#endif
2502
0
}
2503
2504
#ifdef mxFrequency
2505
2506
typedef struct {
2507
  txNumber exit;
2508
  txNumber frequency;
2509
  txU1 code;
2510
} txFrequency;
2511
2512
static int fxCompareExit(const void* a, const void* b)
2513
{
2514
  return ((txFrequency*)b)->exit - ((txFrequency*)a)->exit;
2515
}
2516
2517
static int fxCompareFrequency(const void* a, const void* b)
2518
{
2519
  return ((txFrequency*)b)->frequency - ((txFrequency*)a)->frequency;
2520
}
2521
2522
void fxReportFrequency(txMachine* the)
2523
{
2524
  txFrequency frequencies[XS_CODE_COUNT];
2525
  txU1 code;
2526
  txNumber exitSum = 0;
2527
  txNumber frequencySum = 0;
2528
  for (code = 0; code < XS_CODE_COUNT; code++) {
2529
    frequencies[code].exit = the->exits[code];
2530
    frequencies[code].frequency = the->frequencies[code];
2531
    frequencies[code].code = code;
2532
    exitSum += the->exits[code];
2533
    frequencySum += the->frequencies[code];
2534
  }
2535
  c_qsort(frequencies, XS_CODE_COUNT, sizeof(txFrequency), fxCompareFrequency);
2536
  fprintf(stderr, "Frequencies %10.0lf\n", frequencySum);
2537
  for (code = 0; code < XS_CODE_COUNT; code++) {
2538
    if (!frequencies[code].frequency)
2539
      break;
2540
    fprintf(stderr, "%24s %10.3lf%%\n", 
2541
      gxCodeNames[frequencies[code].code], 
2542
      ((double)(frequencies[code].frequency) * 100.0) / frequencySum);
2543
  }
2544
  c_qsort(frequencies, XS_CODE_COUNT, sizeof(txFrequency), fxCompareExit);
2545
  fprintf(stderr, "Exits %10.0lf\n", exitSum);
2546
  for (code = 0; code < XS_CODE_COUNT; code++) {
2547
    if (!frequencies[code].exit)
2548
      break;
2549
    fprintf(stderr, "%24s%10.3lf%%\n", 
2550
      gxCodeNames[frequencies[code].code], 
2551
      ((double)(frequencies[code].exit) * 100.0) / exitSum);
2552
  }
2553
}
2554
#endif
2555