Coverage Report

Created: 2026-08-13 06:36

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
58.3k
{
67
58.3k
  theSlot->kind = XS_UNDEFINED_KIND;
68
58.3k
}
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
28.3k
{
77
28.3k
  theSlot->value.boolean = theValue;
78
28.3k
  theSlot->kind = XS_BOOLEAN_KIND;
79
28.3k
}
80
81
txBoolean fxToBoolean(txMachine* the, txSlot* theSlot)
82
20.0M
{
83
20.0M
  switch (theSlot->kind) {
84
1.15M
  case XS_UNDEFINED_KIND:
85
1.15M
  case XS_NULL_KIND:
86
1.15M
    theSlot->kind = XS_BOOLEAN_KIND;
87
1.15M
    theSlot->value.boolean = 0;
88
1.15M
    break;
89
13.7M
  case XS_BOOLEAN_KIND:
90
13.7M
    break;
91
2.51M
  case XS_INTEGER_KIND:
92
2.51M
    theSlot->kind = XS_BOOLEAN_KIND;
93
2.51M
    theSlot->value.boolean = (theSlot->value.integer == 0) ? 0 : 1;
94
2.51M
    break;
95
1.28M
  case XS_NUMBER_KIND:
96
1.28M
    theSlot->kind = XS_BOOLEAN_KIND;
97
1.28M
    switch (c_fpclassify(theSlot->value.number)) {
98
184k
    case C_FP_NAN:
99
297k
    case C_FP_ZERO:
100
297k
      theSlot->value.boolean = 0;
101
297k
      break;
102
989k
    default:
103
989k
      theSlot->value.boolean = 1;
104
989k
      break;
105
1.28M
    }
106
1.28M
    break;
107
1.28M
  case XS_BIGINT_KIND:
108
423k
  case XS_BIGINT_X_KIND:
109
423k
    if ((theSlot->value.bigint.size == 1) && (theSlot->value.bigint.data[0] == 0))
110
257
      theSlot->value.boolean = 0;
111
422k
    else
112
422k
      theSlot->value.boolean = 1;
113
423k
    theSlot->kind = XS_BOOLEAN_KIND;
114
423k
    break;
115
161k
  case XS_STRING_KIND:
116
161k
  case XS_STRING_X_KIND:
117
161k
    theSlot->kind = XS_BOOLEAN_KIND;
118
161k
    if (c_isEmpty(theSlot->value.string))
119
4.21k
      theSlot->value.boolean = 0;
120
157k
    else
121
157k
      theSlot->value.boolean = 1;
122
161k
    break;
123
#if mxHostFunctionPrimitive
124
  case XS_HOST_FUNCTION_KIND:
125
#endif
126
509
  case XS_SYMBOL_KIND:
127
730k
  case XS_REFERENCE_KIND:
128
730k
    theSlot->kind = XS_BOOLEAN_KIND;
129
730k
    theSlot->value.boolean = 1;
130
730k
    break;
131
6
  default:
132
6
    mxTypeError("cannot coerce to boolean");
133
0
    break;
134
20.0M
  }
135
20.0M
  return theSlot->value.boolean;
136
20.0M
}
137
138
txInteger fxArgc(txMachine* the)
139
1.50M
{
140
1.50M
  return (txInteger)(the->frame->ID);
141
1.50M
}
142
143
void fxInteger(txMachine* the, txSlot* theSlot, txInteger theValue)
144
1.87M
{
145
1.87M
  theSlot->value.integer = theValue;
146
1.87M
  theSlot->kind = XS_INTEGER_KIND;
147
1.87M
}
148
149
txInteger fxToInteger(txMachine* the, txSlot* theSlot)
150
19.4M
{
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
20.7M
again:
157
20.7M
  switch (theSlot->kind) {
158
1.95M
  case XS_UNDEFINED_KIND:
159
2.05M
  case XS_NULL_KIND:
160
2.05M
    theSlot->kind = XS_INTEGER_KIND;
161
2.05M
    theSlot->value.integer = 0;
162
2.05M
    break;
163
3.34M
  case XS_BOOLEAN_KIND:
164
3.34M
    theSlot->kind = XS_INTEGER_KIND;
165
3.34M
    if (theSlot->value.boolean == 0)
166
1.43M
      theSlot->value.integer = 0;
167
1.90M
    else
168
1.90M
      theSlot->value.integer = 1;
169
3.34M
    break;
170
11.1M
  case XS_INTEGER_KIND:
171
11.1M
    break;
172
2.88M
  case XS_NUMBER_KIND:
173
2.88M
    theSlot->kind = XS_INTEGER_KIND;
174
2.88M
    theSlot->value.integer = fxNumberToInteger(theSlot->value.number);
175
2.88M
    mxFloatingPointOp("number to integer");
176
2.88M
    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.02k
  case XS_SYMBOL_KIND:
184
1.02k
    mxTypeError("cannot coerce symbol to integer");
185
0
    break;
186
17.0k
  case XS_REFERENCE_KIND:
187
17.0k
    fxToPrimitive(the, theSlot, XS_NUMBER_HINT);
188
17.0k
    goto again;
189
1
  default:
190
1
    mxTypeError("cannot coerce to integer");
191
0
    break;
192
20.7M
  }
193
19.4M
  return theSlot->value.integer;
194
20.7M
}
195
196
void fxNumber(txMachine* the, txSlot* theSlot, txNumber theValue)
197
2.48k
{
198
2.48k
  theSlot->value.number = theValue;
199
2.48k
  theSlot->kind = XS_NUMBER_KIND;
200
2.48k
}
201
202
txNumber fxToNumber(txMachine* the, txSlot* theSlot)
203
51.6M
{
204
52.7M
again:
205
52.7M
  switch (theSlot->kind) {
206
8.68M
  case XS_UNDEFINED_KIND:
207
8.68M
    theSlot->kind = XS_NUMBER_KIND;
208
8.68M
    theSlot->value.number = C_NAN;
209
8.68M
    break;
210
631k
  case XS_NULL_KIND:
211
631k
    theSlot->kind = XS_NUMBER_KIND;
212
631k
    theSlot->value.number = 0;
213
631k
    break;
214
5.88M
  case XS_BOOLEAN_KIND:
215
5.88M
    theSlot->kind = XS_NUMBER_KIND;
216
5.88M
    if (theSlot->value.boolean == 0)
217
4.34M
      theSlot->value.number = 0;
218
1.54M
    else
219
1.54M
      theSlot->value.number = 1;
220
5.88M
    break;
221
16.2M
  case XS_INTEGER_KIND:
222
16.2M
    theSlot->kind = XS_NUMBER_KIND;
223
16.2M
    theSlot->value.number = theSlot->value.integer;
224
16.2M
    mxFloatingPointOp("integer to number");
225
16.2M
    break;
226
8.67M
  case XS_NUMBER_KIND:
227
8.67M
    break;
228
11.5M
  case XS_STRING_KIND:
229
11.5M
  case XS_STRING_X_KIND:
230
11.5M
    theSlot->kind = XS_NUMBER_KIND;
231
11.5M
    theSlot->value.number = fxStringToNumber(the, theSlot->value.string, 1);
232
11.5M
    mxMeterOne();
233
11.5M
    break;
234
1.68k
  case XS_SYMBOL_KIND:
235
1.68k
    mxTypeError("cannot coerce symbol to number");
236
0
    break;
237
1.07M
  case XS_REFERENCE_KIND:
238
1.07M
    fxToPrimitive(the, theSlot, XS_NUMBER_HINT);
239
1.07M
    goto again;
240
30
  default:
241
30
    mxTypeError("cannot coerce to number");
242
0
    break;
243
52.7M
  }
244
51.6M
  return theSlot->value.number;
245
52.7M
}
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.46M
{
254
2.46M
#ifdef mxSnapshot
255
2.46M
  fxCopyStringC(the, theSlot, theValue);
256
#else
257
  theSlot->value.string = theValue;
258
  theSlot->kind = XS_STRING_X_KIND;
259
#endif
260
2.46M
}
261
262
void fxStringBuffer(txMachine* the, txSlot* theSlot, txString theValue, txSize theSize)
263
31.5k
{
264
31.5k
  theSlot->value.string = (txString)fxNewChunk(the, fxAddChunkSizes(the, theSize, 1));
265
31.5k
  if (theValue)
266
0
    c_memcpy(theSlot->value.string, theValue, theSize);
267
31.5k
  else
268
31.5k
    theSlot->value.string[0] = 0;
269
31.5k
  theSlot->value.string[theSize] = 0;
270
31.5k
  theSlot->kind = XS_STRING_KIND;
271
31.5k
}
272
273
txString fxToString(txMachine* the, txSlot* theSlot)
274
64.3M
{
275
64.3M
  char aBuffer[256];
276
68.9M
again:
277
68.9M
  switch (theSlot->kind) {
278
3.50M
  case XS_UNDEFINED_KIND:
279
3.50M
    *theSlot = mxUndefinedString;
280
3.50M
    break;
281
182k
  case XS_NULL_KIND:
282
182k
    fxStringX(the, theSlot, "null");
283
182k
    break;
284
403k
  case XS_BOOLEAN_KIND:
285
403k
    if (theSlot->value.boolean == 0)
286
86.5k
      fxStringX(the, theSlot, "false");
287
316k
    else
288
316k
      fxStringX(the, theSlot, "true");
289
403k
    break;
290
5.62M
  case XS_INTEGER_KIND:
291
5.62M
    fxCopyStringC(the, theSlot, fxIntegerToString(the, theSlot->value.integer, aBuffer, sizeof(aBuffer)));
292
5.62M
    mxMeterOne();
293
5.62M
    break;
294
5.57M
  case XS_NUMBER_KIND:
295
5.57M
    fxCopyStringC(the, theSlot, fxNumberToString(the, theSlot->value.number, aBuffer, sizeof(aBuffer), 0, 0));
296
5.57M
    mxMeterOne();
297
5.57M
    break;
298
816
  case XS_SYMBOL_KIND:
299
816
    mxTypeError("cannot coerce symbol to string");
300
0
    break;
301
8.12k
  case XS_BIGINT_KIND:
302
8.12k
  case XS_BIGINT_X_KIND:
303
8.12k
    gxTypeBigInt.toString(the, theSlot, 0);
304
8.12k
    break;
305
49.0M
  case XS_STRING_KIND:
306
49.0M
  case XS_STRING_X_KIND:
307
49.0M
    break;
308
4.52M
  case XS_REFERENCE_KIND:
309
4.52M
    fxToPrimitive(the, theSlot, XS_STRING_HINT);
310
4.52M
    goto again;
311
0
  default:
312
0
    mxTypeError("cannot coerce to string");
313
0
    break;
314
68.9M
  }
315
64.3M
  return theSlot->value.string;
316
68.9M
}
317
318
txString fxToStringBuffer(txMachine* the, txSlot* theSlot, txString theBuffer, txSize theSize)
319
41.0k
{
320
41.0k
  char* aString;
321
41.0k
  txSize aSize;
322
323
41.0k
  aString = fxToString(the, theSlot);
324
41.0k
  aSize = mxStringLength(aString) + 1;
325
41.0k
  if (aSize > theSize)
326
0
    mxRangeError("cannot buffer string");
327
41.0k
  c_memcpy(theBuffer, aString, aSize);
328
41.0k
  return theBuffer;
329
41.0k
}
330
331
void fxUnsigned(txMachine* the, txSlot* theSlot, txUnsigned theValue)
332
1.98M
{
333
1.98M
  if (((txInteger)theValue) >= 0) {
334
1.61M
    theSlot->value.integer = theValue;
335
1.61M
    theSlot->kind = XS_INTEGER_KIND;
336
1.61M
  }
337
372k
  else {
338
372k
    theSlot->value.number = theValue;
339
372k
    theSlot->kind = XS_NUMBER_KIND;
340
372k
  }
341
1.98M
}
342
343
txUnsigned fxToUnsigned(txMachine* the, txSlot* theSlot)
344
3.99M
{
345
3.99M
  txUnsigned result;
346
3.99M
again:
347
3.99M
  switch (theSlot->kind) {
348
3.96k
  case XS_UNDEFINED_KIND:
349
4.01k
  case XS_NULL_KIND:
350
4.01k
    theSlot->kind = XS_INTEGER_KIND;
351
4.01k
    result = theSlot->value.integer = 0;
352
4.01k
    break;
353
1.52k
  case XS_BOOLEAN_KIND:
354
1.52k
    theSlot->kind = XS_INTEGER_KIND;
355
1.52k
    if (theSlot->value.boolean == 0)
356
348
      result = theSlot->value.integer = 0;
357
1.17k
    else
358
1.17k
      result = theSlot->value.integer = 1;
359
1.52k
    break;
360
2.31M
  case XS_INTEGER_KIND:
361
2.31M
    if (theSlot->value.integer >= 0)
362
1.66M
      return (txUnsigned)theSlot->value.integer;
363
650k
    theSlot->kind = XS_NUMBER_KIND;
364
650k
    theSlot->value.number = theSlot->value.integer;
365
    // continue
366
650k
    mxFallThrough;
367
2.31M
  case XS_NUMBER_KIND:
368
2.31M
    theSlot->kind = XS_INTEGER_KIND;
369
2.31M
    switch (c_fpclassify(theSlot->value.number)) {
370
180k
    case C_FP_INFINITE:
371
566k
    case C_FP_NAN:
372
1.12M
    case C_FP_ZERO:
373
1.12M
      result = theSlot->value.integer = 0;
374
1.12M
      break;
375
1.19M
    default: {
376
2.21M
      #define MODULO 4294967296.0
377
1.19M
      txNumber aNumber = c_fmod(c_trunc(theSlot->value.number), MODULO);
378
1.19M
      if (aNumber < 0)
379
1.02M
        aNumber += MODULO;
380
1.19M
      result = (txUnsigned)aNumber;
381
1.19M
      if (((txInteger)result) >= 0) {
382
118k
        theSlot->kind = XS_INTEGER_KIND;
383
118k
        theSlot->value.integer = (txInteger)result;
384
118k
      }
385
1.07M
      else {
386
1.07M
        theSlot->kind = XS_NUMBER_KIND;
387
1.07M
        theSlot->value.number = aNumber;
388
1.07M
      }
389
1.19M
      } break;
390
2.31M
    }
391
2.31M
    mxFloatingPointOp("number to unsigned");
392
2.31M
    break;
393
3.51k
  case XS_STRING_KIND:
394
3.51k
  case XS_STRING_X_KIND:
395
3.51k
    theSlot->kind = XS_NUMBER_KIND;
396
3.51k
    theSlot->value.number = fxStringToNumber(the, theSlot->value.string, 1);
397
3.51k
    mxMeterOne();
398
3.51k
    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.81k
  case XS_REFERENCE_KIND:
404
2.81k
    fxToPrimitive(the, theSlot, XS_NUMBER_HINT);
405
2.81k
    goto again;
406
0
  default:
407
0
    result = 0;
408
0
    mxTypeError("cannot coerce to unsigned");
409
0
    break;
410
3.99M
  }
411
2.32M
  return result;
412
3.99M
}
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
6.39M
{
450
6.39M
  txSlot* instance;
451
6.39M
  txSlot* array;
452
6.39M
  mxPush(mxArrayPrototype);
453
6.39M
  instance = fxNewArrayInstance(the);
454
6.39M
  array = instance->next;
455
6.39M
  fxSetIndexSize(the, array, size, XS_CHUNK);
456
6.39M
  fxIndexArray(the, array);
457
6.39M
  return instance;
458
6.39M
}
459
460
txSlot* fxNewObject(txMachine* the)
461
4.14M
{
462
4.14M
  mxPush(mxObjectPrototype);
463
4.14M
  return fxNewObjectInstance(the);
464
4.14M
}
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.66M
{
572
1.66M
  txSlot* aStack;
573
1.66M
  txSlot* instance;
574
1.66M
  txSlot* property;
575
576
1.66M
  fxToInstance(the, the->stack);
577
1.66M
  aStack = the->stack;
578
1.66M
  instance = fxNewHostFunction(the, theCallback, theLength, name, XS_NO_ID);
579
1.66M
  instance->flag |= XS_CAN_CONSTRUCT_FLAG;
580
1.66M
  property = fxLastProperty(the, instance);
581
1.66M
  fxNextSlotProperty(the, property, aStack, mxID(_prototype), XS_GET_ONLY);
582
1.66M
  property = mxBehaviorSetProperty(the, fxGetInstance(the, aStack), mxID(_constructor), 0, XS_OWN);
583
1.66M
  property->flag = XS_DONT_ENUM_FLAG;
584
1.66M
  property->kind = the->stack->kind;
585
1.66M
  property->value = the->stack->value;
586
1.66M
  *aStack = *the->stack;
587
1.66M
  mxPop();
588
1.66M
  return instance;
589
1.66M
}
590
591
txSlot* fxNewHostFunction(txMachine* the, txCallback theCallback, txInteger theLength, txInteger name, txInteger profileID)
592
22.6M
{
593
22.6M
  txSlot* instance;
594
22.6M
  txSlot* property;
595
596
22.6M
  mxPushUndefined();
597
22.6M
  instance = fxNewSlot(the);
598
22.6M
  instance->flag |= XS_CAN_CALL_FLAG;
599
22.6M
  instance->kind = XS_INSTANCE_KIND;
600
22.6M
  instance->value.instance.garbage = C_NULL;
601
22.6M
  instance->value.instance.prototype = mxFunctionPrototype.value.reference;
602
22.6M
  the->stack->value.reference = instance;
603
22.6M
  the->stack->kind = XS_REFERENCE_KIND;
604
605
  /* CALLBACK */
606
22.6M
  property = instance->next = fxNewSlot(the);
607
22.6M
  property->flag = XS_INTERNAL_FLAG;
608
22.6M
  property->kind = XS_CALLBACK_KIND;
609
22.6M
  property->value.callback.address = theCallback;
610
22.6M
  property->value.callback.closures = C_NULL;
611
612
  /* HOME */
613
22.6M
  property = property->next = fxNewSlot(the);
614
22.6M
  if (profileID != XS_NO_ID)
615
3.67M
    property->ID = profileID;
616
18.9M
  else
617
18.9M
    property->ID = fxGenerateProfileID(the);
618
22.6M
  property->flag = XS_INTERNAL_FLAG;
619
22.6M
  property->kind = XS_HOME_KIND;
620
22.6M
  property->value.home.object = C_NULL;
621
22.6M
  if (the->frame && (mxFunction->kind == XS_REFERENCE_KIND) && (mxIsFunction(mxFunction->value.reference))) {
622
3.72M
    txSlot* slot = mxFunctionInstanceHome(mxFunction->value.reference);
623
3.72M
    property->value.home.module = slot->value.home.module;
624
3.72M
  }
625
18.9M
  else
626
18.9M
    property->value.home.module = C_NULL;
627
628
  /* LENGTH */
629
22.6M
  if (gxDefaults.newFunctionLength)
630
22.6M
    gxDefaults.newFunctionLength(the, instance, theLength);
631
632
  /* NAME */
633
22.6M
  fxRenameFunction(the, instance, name, 0, XS_NO_ID, C_NULL);
634
635
22.6M
  return instance;
636
22.6M
}
637
638
txSlot* fxNewHostInstance(txMachine* the)
639
239k
{
640
239k
  txSlot* prototype = fxGetInstance(the, the->stack);
641
239k
  txSlot* instance = fxNewSlot(the);
642
239k
  instance->kind = XS_INSTANCE_KIND;
643
239k
  instance->value.instance.garbage = C_NULL;
644
239k
  instance->value.instance.prototype = prototype;
645
239k
  the->stack->value.reference = instance;
646
239k
  the->stack->kind = XS_REFERENCE_KIND;
647
239k
  if (prototype) {
648
239k
    txSlot* prototypeHost = prototype->next;
649
239k
    if (prototypeHost && (prototypeHost->kind == XS_HOST_KIND) && (prototypeHost->value.host.variant.destructor != fxReleaseSharedChunk)) {
650
31.3k
      txSlot* instanceHost = instance->next = fxNewSlot(the);
651
31.3k
      instanceHost->flag = XS_INTERNAL_FLAG;
652
31.3k
      instanceHost->kind = XS_HOST_KIND;
653
31.3k
      instanceHost->value.host.data = C_NULL;
654
31.3k
      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
31.3k
      else {
659
31.3k
        instanceHost->value.host.variant.destructor = prototypeHost->value.host.variant.destructor;
660
31.3k
      }
661
31.3k
    }
662
239k
  }
663
239k
  return instance;
664
239k
}
665
666
667
txSlot* fxCheckHostObject(txMachine* the, txSlot* it)
668
125k
{
669
125k
  txSlot* result = C_NULL;
670
125k
  if (it->kind == XS_REFERENCE_KIND) {
671
125k
    it = it->value.reference;
672
125k
    if (it->next) {
673
125k
      it = it->next;
674
125k
      if ((it->flag & XS_INTERNAL_FLAG) && (it->kind == XS_HOST_KIND))
675
125k
        result = it;
676
125k
    }
677
125k
  }
678
125k
  return result;
679
125k
}
680
681
txSlot* fxNewHostObject(txMachine* the, txDestructor theDestructor)
682
31.3k
{
683
31.3k
  txSlot* anInstance;
684
31.3k
  txSlot* aProperty;
685
686
31.3k
  mxPushUndefined();
687
688
31.3k
  anInstance = fxNewSlot(the);
689
31.3k
  anInstance->kind = XS_INSTANCE_KIND;
690
31.3k
  anInstance->value.instance.garbage = C_NULL;
691
31.3k
  anInstance->value.instance.prototype = mxObjectPrototype.value.reference;
692
31.3k
  the->stack->value.reference = anInstance;
693
31.3k
  the->stack->kind = XS_REFERENCE_KIND;
694
695
31.3k
  aProperty = anInstance->next = fxNewSlot(the);
696
31.3k
  aProperty->flag = XS_INTERNAL_FLAG;
697
31.3k
  aProperty->kind = XS_HOST_KIND;
698
31.3k
  aProperty->value.host.data = C_NULL;
699
31.3k
  aProperty->value.host.variant.destructor = theDestructor;
700
  
701
31.3k
  return anInstance;
702
31.3k
}
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
62.6k
{
721
62.6k
  txSlot* host = fxCheckHostObject(the, slot);
722
62.6k
  if (host) {
723
62.6k
    if (host->flag & XS_HOST_CHUNK_FLAG)
724
62.6k
      return host->value.host.data;
725
62.6k
    mxSyntaxError("C: xsGetHostChunk: no host data");
726
62.6k
  }
727
62.6k
  mxSyntaxError("C: xsGetHostChunk: not a host object");
728
0
  return NULL;
729
62.6k
}
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
31.3k
{
887
31.3k
  txSlot* host = fxCheckHostObject(the, slot);
888
31.3k
  if (host) {
889
31.3k
    host->flag |= XS_HOST_CHUNK_FLAG;
890
31.3k
    if (theSize) {
891
31.3k
      host->value.host.data = fxNewChunk(the, theSize);
892
31.3k
      if (theValue)
893
31.3k
        c_memcpy(host->value.host.data, theValue, theSize);
894
0
      else
895
0
        c_memset(host->value.host.data, 0, theSize);
896
31.3k
    }
897
0
    else
898
0
      host->value.host.data = NULL;
899
31.3k
    return host->value.host.data;
900
31.3k
  }
901
0
  else
902
0
    mxSyntaxError("C: fxSetHostChunk: not a host object");
903
904
0
  return NULL;
905
31.3k
}
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
31.3k
{
920
31.3k
  txSlot* host = fxCheckHostObject(the, slot);
921
31.3k
  if (host) {
922
31.3k
    host->flag &= ~XS_HOST_HOOKS_FLAG;
923
31.3k
    host->value.host.variant.destructor = theDestructor;
924
31.3k
  }
925
0
  else
926
0
    mxSyntaxError("C: xsSetHostDestructor: not a host object");
927
31.3k
}
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
16.9M
{
944
16.9M
  return fxNewNameC(the, theName);
945
16.9M
}
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
456
{
959
456
  txString string = fxToString(the, theSlot);
960
456
  if (theSlot->kind == XS_STRING_KIND)
961
456
    return fxNewName(the, theSlot);
962
0
  return fxNewNameX(the, string);
963
456
}
964
965
txString fxName(txMachine* the, txID theID)
966
21
{
967
21
  return fxGetKeyName(the, theID);
968
21
}
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
txBoolean fxGetAll(txMachine* the, txSlot* stack, txID id, txIndex index)
980
194M
{
981
194M
  txBoolean flag = mxIsReference(stack) ? 1 : 0;
982
194M
  txSlot* instance = (flag) ? stack->value.reference : fxToInstance(the, stack);
983
194M
  txSlot* property = mxBehaviorGetProperty(the, instance, (txID)id, index, XS_ANY);
984
194M
  if (!property) {
985
27.2M
    the->stack = stack;
986
27.2M
    stack->kind = XS_UNDEFINED_KIND;
987
27.2M
    return 0;
988
27.2M
  }
989
166M
  if (property->kind == XS_ACCESSOR_KIND) {
990
31.0M
    txSlot* function = property->value.accessor.getter;
991
31.0M
    if (mxIsFunction(function)) {
992
31.0M
      txSlot* slot;
993
31.0M
      the->stack = stack;
994
31.0M
      mxOverflow(-3);
995
31.0M
            the->stack -= 3;
996
31.0M
      slot = the->stack;
997
31.0M
      mxInitSlotKind(slot++, XS_UNINITIALIZED_KIND);
998
31.0M
      mxInitSlotKind(slot++, XS_UNDEFINED_KIND);
999
31.0M
      slot->value.reference = function;
1000
31.0M
      mxInitSlotKind(slot++, XS_REFERENCE_KIND);
1001
31.0M
      if (!flag) {
1002
24
        txSlot* primitive = instance->next;
1003
24
        slot->value = primitive->value;
1004
24
        mxInitSlotKind(slot, primitive->kind);
1005
24
      }
1006
31.0M
      mxRunCount(0);
1007
31.0M
    }
1008
22
    else {
1009
22
      the->stack = stack;
1010
22
      stack->kind = XS_UNDEFINED_KIND;
1011
22
    }
1012
31.0M
  }
1013
135M
  else {
1014
135M
    the->stack = stack;
1015
135M
    stack->kind = property->kind;
1016
135M
    stack->value = property->value;
1017
135M
  }
1018
166M
  return 1;
1019
194M
}
1020
1021
txBoolean fxGetAt(txMachine* the)
1022
6.49M
{
1023
6.49M
  txSlot* at = fxAt(the, the->stack);
1024
6.49M
  mxPop();
1025
6.49M
  return mxGetAll(at->value.at.id, at->value.at.index);
1026
6.49M
}
1027
1028
txBoolean fxGetID(txMachine* the, txID id)
1029
109M
{
1030
109M
  return mxGetAll(id, 0);
1031
109M
}
1032
1033
txBoolean fxGetIndex(txMachine* the, txIndex index)
1034
35.6M
{
1035
35.6M
  return mxGetAll(XS_NO_ID, index);
1036
35.6M
}
1037
1038
txBoolean fxHasAll(txMachine* the, txSlot* stack, txID id, txIndex index)
1039
32.8M
{
1040
32.8M
  txSlot* instance = fxToInstance(the, stack);
1041
32.8M
  txBoolean result = mxBehaviorHasProperty(the, instance, id, index);
1042
32.8M
  the->stack = stack;
1043
32.8M
  mxPop();
1044
32.8M
  return result;
1045
32.8M
}
1046
1047
txBoolean fxHasAt(txMachine* the)
1048
12.6M
{
1049
12.6M
  txSlot* at = fxAt(the, the->stack);
1050
12.6M
  return fxHasAll(the, the->stack + 1, at->value.at.id, at->value.at.index);
1051
12.6M
}
1052
1053
txBoolean fxHasID(txMachine* the, txID id)
1054
5.51M
{
1055
5.51M
  return fxHasAll(the, the->stack, id, 0);
1056
5.51M
}
1057
1058
txBoolean fxHasIndex(txMachine* the, txIndex index)
1059
14.6M
{
1060
14.6M
  return fxHasAll(the, the->stack, XS_NO_ID, index);
1061
14.6M
}
1062
1063
void fxSetAll(txMachine* the, txSlot* stack, txID id, txIndex index)
1064
19.8M
{
1065
19.8M
  txSlot* value = stack + 1;
1066
19.8M
  txSlot* instance = fxToInstance(the, stack);
1067
19.8M
  txSlot* property = mxBehaviorSetProperty(the, instance, id, index, XS_ANY);
1068
19.8M
  if (!property)
1069
27
    mxDebugID(XS_TYPE_ERROR, "C: xsSet %s: not extensible", id);
1070
19.8M
  if (property->kind == XS_ACCESSOR_KIND) {
1071
942k
    txSlot* slot;
1072
942k
    txSlot* function = property->value.accessor.setter;
1073
942k
    if (!mxIsFunction(function))
1074
6
      mxDebugID(XS_TYPE_ERROR, "C: xsSet %s: no setter", id);
1075
942k
    the->stack = stack;
1076
942k
    mxOverflow(-3);
1077
942k
    the->stack -= 3;
1078
942k
    slot = the->stack;
1079
942k
    slot->value = value->value;
1080
942k
    mxInitSlotKind(slot++, value->kind);
1081
942k
    mxInitSlotKind(slot++, XS_UNINITIALIZED_KIND);
1082
942k
    slot->value = value->value;
1083
942k
    mxInitSlotKind(slot++, value->kind);
1084
942k
    slot->value.reference = function;
1085
942k
    mxInitSlotKind(slot++, XS_REFERENCE_KIND);
1086
942k
    slot->value.reference = instance;
1087
942k
    mxInitSlotKind(slot, XS_REFERENCE_KIND);
1088
942k
    mxRunCount(1);
1089
942k
  }
1090
18.8M
  else {
1091
18.8M
    if (property->flag & XS_DONT_SET_FLAG)
1092
21
      mxDebugID(XS_TYPE_ERROR, "C: xsSet %s: not writable", id);
1093
18.8M
    property->kind = value->kind;
1094
18.8M
    property->value = value->value;
1095
18.8M
    the->stack = stack;
1096
18.8M
    mxPop();
1097
18.8M
  }
1098
19.8M
}
1099
1100
void fxSetAt(txMachine* the)
1101
1.44M
{
1102
1.44M
  txSlot* at = fxAt(the, the->stack);
1103
1.44M
  fxSetAll(the, the->stack + 1, at->value.at.id, at->value.at.index);
1104
1.44M
}
1105
1106
void fxSetID(txMachine* the, txID id)
1107
17.8M
{
1108
17.8M
  fxSetAll(the, the->stack, id, 0);
1109
17.8M
}
1110
1111
void fxSetIndex(txMachine* the, txIndex index)
1112
495k
{
1113
495k
  fxSetAll(the, the->stack, XS_NO_ID, index);
1114
495k
}
1115
1116
void fxDeleteAll(txMachine* the, txSlot* stack, txID id, txIndex index)
1117
4.94M
{
1118
4.94M
  txSlot* instance = fxToInstance(the, stack);
1119
4.94M
  if (!mxBehaviorDeleteProperty(the, instance, id, index))
1120
5
    mxDebugID(XS_TYPE_ERROR, "delete %s: not configurable", id);
1121
4.94M
  the->stack = stack;
1122
4.94M
}
1123
1124
void fxDeleteAt(txMachine* the)
1125
4.85M
{
1126
4.85M
  txSlot* at = fxAt(the, the->stack);
1127
4.85M
  fxDeleteAll(the, the->stack + 1, at->value.at.id, at->value.at.index);
1128
4.85M
}
1129
1130
void fxDeleteID(txMachine* the, txID id)
1131
0
{
1132
0
  fxDeleteAll(the, the->stack, id, 0);
1133
0
}
1134
1135
void fxDeleteIndex(txMachine* the, txIndex index)
1136
94.6k
{
1137
94.6k
  fxDeleteAll(the, the->stack, XS_NO_ID, index);
1138
94.6k
}
1139
1140
void fxDefineAll(txMachine* the, txSlot* stack, txID id, txIndex index, txFlag flag, txFlag mask)
1141
10.5M
{
1142
10.5M
  txSlot* instance = fxToInstance(the, stack);
1143
10.5M
  txSlot* slot = stack + 1;
1144
10.5M
  if (mask & XS_GETTER_FLAG) {
1145
94.0k
    slot->value.accessor.getter = slot->value.reference;
1146
94.0k
    slot->value.accessor.setter = C_NULL;
1147
94.0k
    slot->kind = XS_ACCESSOR_KIND;
1148
94.0k
  }
1149
10.4M
  else if (mask & XS_SETTER_FLAG) {
1150
0
    slot->value.accessor.setter = slot->value.reference;
1151
0
    slot->value.accessor.getter = C_NULL;
1152
0
    slot->kind = XS_ACCESSOR_KIND;
1153
0
  }
1154
10.5M
  slot->flag = flag & XS_GET_ONLY;
1155
10.5M
  if (!mxBehaviorDefineOwnProperty(the, instance, id, index, slot, mask))
1156
11
    mxTypeError("define %ld: not configurable", id);
1157
10.5M
  the->stack = stack;
1158
10.5M
  mxPop();
1159
10.5M
}
1160
1161
void fxDefineAt(txMachine* the, txFlag flag, txFlag mask)
1162
4.03M
{
1163
4.03M
  txSlot* at = fxAt(the, the->stack);
1164
4.03M
  fxDefineAll(the, the->stack + 1, at->value.at.id, at->value.at.index, flag, mask);
1165
4.03M
}
1166
1167
void fxDefineID(txMachine* the, txID id, txFlag flag, txFlag mask)
1168
355k
{
1169
355k
  fxDefineAll(the, the->stack, id, 0, flag, mask);
1170
355k
}
1171
1172
void fxDefineIndex(txMachine* the, txIndex index, txFlag flag, txFlag mask)
1173
6.15M
{
1174
6.15M
  fxDefineAll(the, the->stack, XS_NO_ID, index, flag, mask);
1175
6.15M
}
1176
1177
void fxCall(txMachine* the)
1178
67.1M
{
1179
  // RESULT
1180
67.1M
  (--the->stack)->next = C_NULL;
1181
67.1M
  mxInitSlotKind(the->stack, XS_UNDEFINED_KIND);
1182
  // FRAME
1183
67.1M
  (--the->stack)->next = C_NULL;
1184
67.1M
  mxInitSlotKind(the->stack, XS_UNINITIALIZED_KIND);
1185
67.1M
}
1186
1187
void fxCallID(txMachine* the, txID theID)
1188
37.8k
{
1189
37.8k
  mxDub();
1190
37.8k
  mxGetID(theID);
1191
37.8k
  fxCall(the);
1192
37.8k
}
1193
1194
void fxCallFrame(txMachine* the)
1195
0
{
1196
0
  mxOverflow(-2);
1197
0
  fxCall(the);
1198
0
}
1199
1200
void fxNew(txMachine* the)
1201
2.04M
{
1202
2.04M
  txSlot* constructor = the->stack;
1203
2.04M
  txSlot* slot = constructor - 4;
1204
2.04M
  the->stack = slot;
1205
  // FRAME
1206
2.04M
  mxInitSlotKind(slot++, XS_UNINITIALIZED_KIND);
1207
  // RESULT
1208
2.04M
  mxInitSlotKind(slot++, XS_UNDEFINED_KIND);
1209
  // FUNCTION (copy of constructor)
1210
2.04M
  slot->value = constructor->value;
1211
2.04M
  mxInitSlotKind(slot++, constructor->kind);
1212
  // THIS (uninitialized marks as constructor)
1213
2.04M
  mxInitSlotKind(slot++, XS_UNINITIALIZED_KIND);
1214
  // TARGET (constructor = new.target, stays in place)
1215
2.04M
}
1216
1217
void fxNewID(txMachine* the, txID theID)
1218
31.3k
{
1219
31.3k
  mxGetID(theID);
1220
31.3k
  fxNew(the);
1221
31.3k
}
1222
1223
void fxNewFrame(txMachine* the)
1224
0
{
1225
0
  mxOverflow(-3);
1226
0
  fxNew(the);
1227
0
}
1228
1229
void fxRunCount(txMachine* the, txInteger count)
1230
1.55M
{
1231
1.55M
  fxRunID(the, C_NULL, count);
1232
1.55M
}
1233
1234
txSlot* fxTarget(txMachine* the)
1235
31.3k
{
1236
31.3k
  static const txSlot undefined = { 0 };
1237
31.3k
  if (the->frame->flag & XS_TARGET_FLAG)
1238
31.3k
    return the->frame + 4;
1239
0
  return (txSlot*)&undefined;
1240
31.3k
}
1241
1242
txBoolean fxRunTest(txMachine* the)
1243
6
{
1244
6
  txBoolean result;
1245
  
1246
6
  switch (the->stack->kind) {
1247
0
  case XS_UNDEFINED_KIND:
1248
0
  case XS_NULL_KIND:
1249
0
    result = 0;
1250
0
    break;
1251
6
  case XS_BOOLEAN_KIND:
1252
6
    result = the->stack->value.boolean;
1253
6
    break;
1254
0
  case XS_INTEGER_KIND:
1255
0
    result = (the->stack->value.integer == 0) ? 0 : 1;
1256
0
    break;
1257
0
  case XS_NUMBER_KIND:
1258
0
    switch (c_fpclassify(the->stack->value.number)) {
1259
0
    case C_FP_NAN:
1260
0
    case C_FP_ZERO:
1261
0
      result = 0;
1262
0
      break;
1263
0
    default:
1264
0
      result = 1;
1265
0
      break;
1266
0
    }
1267
0
    break;
1268
0
  case XS_STRING_KIND:
1269
0
  case XS_STRING_X_KIND:
1270
0
    if (c_isEmpty(the->stack->value.string))
1271
0
      result = 0;
1272
0
    else
1273
0
      result = 1;
1274
0
    break;
1275
0
  default:
1276
0
    result = 1;
1277
0
    break;
1278
6
  }
1279
6
  mxPop();
1280
6
  return result;
1281
6
}
1282
1283
/* Arguments and Variables */
1284
1285
void fxVars(txMachine* the, txInteger theCount)
1286
89.9k
{
1287
89.9k
  if (the->scope != the->stack)
1288
0
    mxSyntaxError("C: xsVars: too late");
1289
89.9k
  mxOverflow(theCount);
1290
89.9k
  the->scope->value.environment.variable.count = theCount;
1291
211k
  while (theCount) {
1292
121k
    mxPushUndefined();
1293
121k
    theCount--;
1294
121k
  }
1295
89.9k
}
1296
1297
txInteger fxCheckArg(txMachine* the, txInteger theIndex)
1298
1.67M
{
1299
1.67M
  if ((theIndex < 0) || (mxArgc <= theIndex))
1300
0
    mxSyntaxError("C: xsArg(%ld): invalid index", theIndex);
1301
1.67M
  return theIndex;
1302
1.67M
}
1303
1304
txInteger fxCheckVar(txMachine* the, txInteger theIndex)
1305
917k
{
1306
917k
  if ((theIndex < 0) || (mxVarc <= theIndex))
1307
0
    mxSyntaxError("C: xsVar(%ld): invalid index", theIndex);
1308
917k
  return theIndex;
1309
917k
}
1310
1311
void fxOverflow(txMachine* the, txInteger theCount, txString thePath, txInteger theLine)
1312
948M
{
1313
948M
  txSlot* aStack = the->stack + theCount;
1314
948M
  if (theCount < 0) {
1315
948M
    if (aStack < the->stackBottom) {
1316
76
      fxReport(the, "stack overflow (%ld)!\n", (the->stack - the->stackBottom) + theCount);
1317
76
      fxAbort(the, XS_JAVASCRIPT_STACK_OVERFLOW_EXIT);
1318
76
    }
1319
948M
  }
1320
121k
  else if (theCount > 0) {
1321
121k
    if (aStack > the->stackTop) {
1322
0
      fxReport(the, "stack overflow (%ld)!\n", theCount - (the->stackTop - the->stack));
1323
0
      fxAbort(the, XS_JAVASCRIPT_STACK_OVERFLOW_EXIT);
1324
0
    }
1325
121k
  }
1326
948M
}
1327
1328
/* Exceptions */
1329
1330
void fxThrow(txMachine* the, txString path, txInteger line)
1331
33
{
1332
33
#ifdef mxDebug
1333
33
  fxDebugThrow(the, path, line, "C: xsThrow");
1334
33
#endif
1335
33
  fxJump(the);
1336
33
}
1337
1338
void fxThrowMessage(txMachine* the, txString path, txInteger line, txError error, txString format, ...)
1339
1.74M
{
1340
1.74M
  char message[128] = "";
1341
1.74M
  txSize length = 0;
1342
1.74M
    va_list arguments;
1343
1.74M
    txSlot* slot;
1344
1.74M
    va_start(arguments, format);
1345
1.74M
    c_vsnprintf(message, sizeof(message), format, arguments);
1346
1.74M
    va_end(arguments);
1347
1348
  //??
1349
1.74M
  length = (txSize)c_strlen(message) - 1;
1350
1.74M
  while (length && (0x80 & message[length]))
1351
128
    message[length--] = 0;
1352
    
1353
1.74M
#ifdef mxDebug
1354
1.74M
  if (!the->debugEval) {
1355
1.74M
    c_strncat(message, " (in ", sizeof(message) - mxStringLength(message) - 1);
1356
1.74M
    length = (txSize)c_strlen(message);
1357
1.74M
    fxBufferFrameName(the, message + length, sizeof(message) - length, the->frame, ")");
1358
1.74M
  }
1359
1.74M
#endif
1360
1361
1.74M
  if ((error <= XS_NO_ERROR) || (XS_ERROR_COUNT <= error))
1362
0
    error = XS_UNKNOWN_ERROR;
1363
1364
1.74M
    slot = fxNewSlot(the);
1365
1.74M
    slot->kind = XS_INSTANCE_KIND;
1366
1.74M
    slot->value.instance.garbage = C_NULL;
1367
1.74M
    slot->value.instance.prototype = mxErrorPrototypes(error).value.reference;
1368
1.74M
  mxException.kind = XS_REFERENCE_KIND;
1369
1.74M
  mxException.value.reference = slot;
1370
1.74M
  slot = slot->next = fxNewSlot(the);
1371
1.74M
  slot->flag = XS_INTERNAL_FLAG;
1372
1.74M
  slot->kind = XS_ERROR_KIND;
1373
1.74M
  slot->value.error.info = C_NULL;
1374
1.74M
  slot->value.error.which = error;
1375
1.74M
  if (gxDefaults.captureErrorStack)
1376
1.74M
    gxDefaults.captureErrorStack(the, slot, the->frame);
1377
1.74M
  slot = fxNextStringProperty(the, slot, message, mxID(_message), XS_DONT_ENUM_FLAG);
1378
1.74M
#ifdef mxDebug
1379
1.74M
  fxDebugThrow(the, path, line, "throw");
1380
1.74M
#endif
1381
1.74M
  fxJump(the);
1382
1.74M
}
1383
1384
/* Debugger */
1385
1386
void fxDebugger(txMachine* the, txString thePath, txInteger theLine)
1387
0
{
1388
0
#ifdef mxDebug
1389
0
  fxDebugLoop(the, thePath, theLine, "C: xsDebugger");
1390
0
#endif
1391
0
}
1392
1393
/* Machine */
1394
1395
const txByte gxNoCode[3] ICACHE_FLASH_ATTR = { XS_CODE_BEGIN_STRICT, 0, XS_CODE_END };
1396
1397
txMachine* fxCreateMachine(txCreation* theCreation, txString theName, void* theContext, txID profileID)
1398
31.3k
{
1399
31.3k
  txMachine* the = (txMachine* )c_calloc(1, sizeof(txMachine));
1400
31.3k
  if (the) {
1401
31.3k
    txJump aJump;
1402
1403
31.3k
    aJump.nextJump = C_NULL;
1404
31.3k
    aJump.stack = C_NULL;
1405
31.3k
    aJump.scope = C_NULL;
1406
31.3k
    aJump.frame = C_NULL;
1407
31.3k
    aJump.code = C_NULL;
1408
31.3k
    aJump.flag = 0;
1409
31.3k
    the->firstJump = &aJump;
1410
31.3k
    if (c_setjmp(aJump.buffer) == 0) {
1411
31.3k
      txInteger id;
1412
31.3k
      txSlot* slot;
1413
1414
31.3k
      if (gxDefaults.initializeSharedCluster)
1415
31.3k
        gxDefaults.initializeSharedCluster(the);
1416
        
1417
31.3k
      the->context = theContext;
1418
31.3k
      fxCreateMachinePlatform(the);
1419
1420
31.3k
    #ifdef mxDebug
1421
31.3k
      the->name = theName;
1422
31.3k
    #endif
1423
31.3k
      the->profileID = (profileID != XS_NO_ID) ? profileID : mxBaseProfileID;
1424
31.3k
      fxAllocate(the, theCreation);
1425
1426
31.3k
            c_memset(the->nameTable, 0, the->nameModulo * sizeof(txSlot *));
1427
31.3k
      c_memset(the->symbolTable, 0, the->symbolModulo * sizeof(txSlot *));
1428
1429
      /* mxGlobal */
1430
31.3k
      mxPushUndefined();
1431
      /* mxException */
1432
31.3k
      mxPushUndefined();
1433
      /* mxProgram */
1434
31.3k
      mxPushNull();
1435
31.3k
      fxNewProgramInstance(the);
1436
      /* mxHosts */
1437
31.3k
      mxPushUndefined();
1438
      /* mxModuleQueue */
1439
31.3k
      fxNewInstance(the);
1440
      /* mxUnhandledPromises */
1441
31.3k
      fxNewInstance(the);
1442
      /* mxDuringJobs */
1443
31.3k
      fxNewInstance(the);
1444
      /* mxFinalizationRegistries */
1445
31.3k
      fxNewInstance(the);
1446
      /* mxPendingJobs */
1447
31.3k
      fxNewInstance(the);
1448
      /* mxRunningJobs */
1449
31.3k
      fxNewInstance(the);
1450
      /* mxBreakpoints */
1451
31.3k
      mxPushList();
1452
      /* mxHostInspectors */
1453
31.3k
      mxPushList();
1454
      /* mxInstanceInspectors */
1455
31.3k
      mxPushList();
1456
1457
4.57M
      for (id = mxInstanceInspectorsStackIndex + 1; id < mxEmptyCodeStackIndex; id++)
1458
4.54M
        mxPushUndefined();
1459
1460
      /* mxEmptyCode */
1461
31.3k
      mxPushUndefined();
1462
31.3k
      the->stack->value.code.address = (txByte*)gxNoCode;
1463
31.3k
      the->stack->value.code.closures = C_NULL;
1464
31.3k
      the->stack->kind = XS_CODE_X_KIND;  
1465
      /* mxEmptyString */
1466
31.3k
      mxPushStringX("");
1467
      /* mxEmptyRegExp */
1468
31.3k
      mxPushStringX("(?:)");
1469
      /* mxBigIntString */
1470
31.3k
      mxPushStringX("bigint");
1471
      /* mxBooleanString */
1472
31.3k
      mxPushStringX("boolean");
1473
      /* mxDefaultString */
1474
31.3k
      mxPushStringX("default");
1475
      /* mxFunctionString */
1476
31.3k
      mxPushStringX("function");
1477
      /* mxNumberString */
1478
31.3k
      mxPushStringX("number");
1479
      /* mxObjectString */
1480
31.3k
      mxPushStringX("object");
1481
      /* mxStringString */
1482
31.3k
      mxPushStringX("string");
1483
      /* mxSymbolString */
1484
31.3k
      mxPushStringX("symbol");
1485
      /* mxUndefinedString */
1486
31.3k
      mxPushStringX("undefined");
1487
1488
31.3k
      fxBuildKeys(the);
1489
31.3k
      fxBuildGlobal(the);
1490
31.3k
      fxBuildObject(the);
1491
31.3k
      fxBuildFunction(the);
1492
31.3k
      fxBuildGenerator(the);
1493
31.3k
      fxBuildArguments(the);
1494
31.3k
      fxBuildArray(the);
1495
31.3k
      fxBuildString(the);
1496
31.3k
      fxBuildBoolean(the);
1497
31.3k
      fxBuildNumber(the);
1498
31.3k
      fxBuildBigInt(the);
1499
31.3k
      fxBuildDate(the);
1500
31.3k
      fxBuildMath(the);
1501
31.3k
      fxBuildRegExp(the);
1502
31.3k
      fxBuildError(the);
1503
31.3k
      fxBuildJSON(the);
1504
31.3k
      fxBuildDataView(the);
1505
31.3k
      fxBuildAtomics(the);
1506
31.3k
      fxBuildPromise(the);
1507
31.3k
      fxBuildSymbol(the);
1508
31.3k
      fxBuildProxy(the);
1509
31.3k
      fxBuildMapSet(the);
1510
31.3k
      fxBuildModule(the);
1511
      
1512
31.3k
      mxPushUndefined();
1513
31.3k
      mxPush(mxObjectPrototype);
1514
  #ifdef mxLink
1515
      slot = fxLastProperty(the, fxNewObjectInstance(the));
1516
  #else
1517
31.3k
      slot = fxLastProperty(the, fxNewGlobalInstance(the));
1518
31.3k
  #endif
1519
1.94M
      for (id = XS_SYMBOL_ID_COUNT; id < _Infinity; id++)
1520
1.91M
        slot = fxNextSlotProperty(the, slot, &the->stackIntrinsics[-1 - id], mxID(id), XS_DONT_ENUM_FLAG);
1521
125k
      for (; id < _Compartment; id++)
1522
94.0k
        slot = fxNextSlotProperty(the, slot, &the->stackIntrinsics[-1 - id], mxID(id), XS_GET_ONLY);
1523
156k
      for (; id < XS_INTRINSICS_COUNT; id++)
1524
125k
        slot = fxNextSlotProperty(the, slot, &the->stackIntrinsics[-1 - id], mxID(id), XS_DONT_ENUM_FLAG);
1525
31.3k
      slot = fxNextSlotProperty(the, slot, the->stack, mxID(_global), XS_DONT_ENUM_FLAG);
1526
31.3k
      slot = fxNextSlotProperty(the, slot, the->stack, mxID(_globalThis), XS_DONT_ENUM_FLAG);
1527
31.3k
      mxGlobal.value = the->stack->value;
1528
31.3k
      mxGlobal.kind = the->stack->kind;
1529
31.3k
      fxNewInstance(the);
1530
31.3k
      fxNewInstance(the);
1531
31.3k
      mxPushUndefined();
1532
31.3k
      fxNewEnvironmentInstance(the, C_NULL);
1533
31.3k
      mxPushUndefined();
1534
31.3k
      mxPushUndefined();
1535
31.3k
      mxPushUndefined();
1536
31.3k
      mxPushUndefined();
1537
31.3k
      mxPushUndefined();
1538
31.3k
      mxModuleInstanceInternal(mxProgram.value.reference)->value.module.realm = fxNewRealmInstance(the);
1539
31.3k
      mxPop();
1540
1541
31.3k
            the->collectFlag = XS_COLLECTING_FLAG;
1542
      
1543
            /*{
1544
        int c = 32;
1545
        while (--c)
1546
          fxCollectGarbage(the);
1547
      }*/
1548
1549
31.3k
    #ifdef mxDebug
1550
31.3k
      fxLogin(the);
1551
31.3k
    #endif
1552
1553
31.3k
      the->firstJump = C_NULL;
1554
31.3k
    }
1555
0
    else {
1556
0
      if (gxDefaults.terminateSharedCluster)
1557
0
        gxDefaults.terminateSharedCluster(the);
1558
0
      fxFree(the);
1559
0
      c_free(the);
1560
0
      the = NULL;
1561
0
    }
1562
31.3k
  }
1563
31.3k
  return the;
1564
31.3k
}
1565
1566
void fxDeleteMachine(txMachine* the)
1567
31.3k
{
1568
31.3k
  txSlot* aSlot;
1569
31.3k
#ifndef mxLink
1570
31.3k
  txSlot* bSlot;
1571
31.3k
  txSlot* cSlot;
1572
31.3k
#endif
1573
1574
31.3k
  if (!(the->shared)) {
1575
  #ifdef mxFrequency
1576
    fxReportFrequency(the);
1577
  #endif
1578
31.3k
  #ifdef mxDebug
1579
31.3k
    fxLogout(the);
1580
31.3k
  #endif
1581
31.3k
  }
1582
31.3k
  the->context = C_NULL;
1583
31.3k
  aSlot = the->cRoot;
1584
31.3k
  while (aSlot) {
1585
1
    aSlot->flag |= XS_MARK_FLAG;
1586
1
    aSlot = aSlot->next;
1587
1
  }
1588
31.3k
#ifndef mxLink
1589
31.3k
  aSlot = the->firstHeap;
1590
65.0k
  while (aSlot) {
1591
33.7k
    bSlot = aSlot + 1;
1592
33.7k
    cSlot = aSlot->value.reference;
1593
1.10G
    while (bSlot < cSlot) {
1594
1.10G
      if ((bSlot->kind == XS_HOST_KIND) && (bSlot->value.host.variant.destructor)) {
1595
12.3k
        if (bSlot->flag & XS_HOST_HOOKS_FLAG) {
1596
0
          if (bSlot->value.host.variant.hooks->destructor)
1597
0
            (*(bSlot->value.host.variant.hooks->destructor))(bSlot->value.host.data);
1598
0
        }
1599
12.3k
        else
1600
12.3k
          (*(bSlot->value.host.variant.destructor))(bSlot->value.host.data);
1601
12.3k
      }
1602
1.10G
      bSlot++;
1603
1.10G
    }
1604
33.7k
    aSlot = aSlot->next;
1605
33.7k
  }
1606
31.3k
#endif
1607
31.3k
  fxDeleteMachinePlatform(the);
1608
31.3k
  if (gxDefaults.terminateSharedCluster)
1609
31.3k
    gxDefaults.terminateSharedCluster(the);
1610
31.3k
  fxFree(the);
1611
31.3k
  c_free(the);
1612
31.3k
}
1613
1614
#if mxAliasInstance
1615
txMachine* fxCloneMachine(txCreation* theCreation, txMachine* theMachine, txString theName, void* theContext)
1616
{
1617
  txMachine* the = (txMachine *)c_calloc(1, sizeof(txMachine));
1618
  if (the) {
1619
    txJump aJump;
1620
1621
    aJump.nextJump = C_NULL;
1622
    aJump.stack = C_NULL;
1623
    aJump.scope = C_NULL;
1624
    aJump.frame = C_NULL;
1625
    aJump.code = C_NULL;
1626
    aJump.flag = 0;
1627
    the->firstJump = &aJump;
1628
    if (c_setjmp(aJump.buffer) == 0) {
1629
      txSlot* sharedSlot;
1630
      txSlot* slot;
1631
1632
      if (gxDefaults.initializeSharedCluster)
1633
        gxDefaults.initializeSharedCluster(the);
1634
1635
      the->preparation = theMachine->preparation;
1636
      the->context = theContext;
1637
      the->sharedMachine = theMachine;
1638
      fxCreateMachinePlatform(the);
1639
1640
    #ifdef mxDebug
1641
      the->name = theName;
1642
    #endif
1643
      the->profileID = theMachine->profileID;
1644
      fxAllocate(the, theCreation);
1645
1646
            c_memcpy(the->nameTable, theMachine->nameTable, the->nameModulo * sizeof(txSlot *));
1647
      c_memcpy(the->symbolTable, theMachine->symbolTable, the->symbolModulo * sizeof(txSlot *));
1648
      the->colors = theMachine->colors;
1649
      the->keyCount = theMachine->keyIndex + (txID)theCreation->initialKeyCount;
1650
      the->keyIndex = theMachine->keyIndex;
1651
      the->keyOffset = the->keyIndex;
1652
      the->keyArrayHost = theMachine->keyArray;
1653
      
1654
      the->aliasCount = theMachine->aliasCount;
1655
      if (the->aliasCount) {
1656
        the->aliasArray = (txSlot **)c_malloc_uint32(the->aliasCount * sizeof(txSlot*));
1657
        if (!the->aliasArray)
1658
          fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT);
1659
        c_memset(the->aliasArray, 0, the->aliasCount * sizeof(txSlot*));
1660
      }
1661
1662
      /* mxGlobal */
1663
      mxPushUndefined();
1664
      /* mxException */
1665
      mxPushUndefined();
1666
      /* mxProgram */
1667
      mxPushNull();
1668
      fxNewProgramInstance(the);
1669
      /* mxHosts */
1670
      mxPushUndefined();
1671
      /* mxModuleQueue */
1672
      fxNewInstance(the);
1673
      /* mxUnhandledPromises */
1674
      fxNewInstance(the);
1675
      /* mxDuringJobs */
1676
      fxNewInstance(the);
1677
      /* mxFinalizationRegistries */
1678
      fxNewInstance(the);
1679
      /* mxPendingJobs */
1680
      fxNewInstance(the);
1681
      /* mxRunningJobs */
1682
      fxNewInstance(the);
1683
      /* mxBreakpoints */
1684
      mxPushList();
1685
      /* mxHostInspectors */
1686
      mxPushList();
1687
      /* mxInstanceInspectors */
1688
      mxPushList();
1689
1690
      the->stackIntrinsics = theMachine->stackTop;
1691
      the->stackPrototypes = theMachine->stackTop - XS_INTRINSICS_COUNT;
1692
1693
      mxPushUndefined();
1694
      mxPush(theMachine->stackTop[-1 - mxGlobalStackIndex]);
1695
      slot = fxLastProperty(the, fxNewObjectInstance(the));
1696
      slot = fxNextSlotProperty(the, slot, the->stack, mxID(_global), XS_DONT_ENUM_FLAG);
1697
      slot = fxNextSlotProperty(the, slot, the->stack, mxID(_globalThis), XS_DONT_ENUM_FLAG);
1698
      mxGlobal.value = the->stack->value;
1699
      mxGlobal.kind = the->stack->kind;
1700
      
1701
      fxNewInstance(the);
1702
      mxPush(theMachine->stackTop[-1 - mxProgramStackIndex]); //@@
1703
      fxNewHostInstance(the);
1704
      
1705
      mxPushUndefined();
1706
      slot = fxLastProperty(the, fxNewEnvironmentInstance(the, C_NULL));
1707
      sharedSlot = theMachine->stackTop[-1 - mxExceptionStackIndex].value.reference->next->next; //@@
1708
      while (sharedSlot) {
1709
        slot = slot->next = fxDuplicateSlot(the, sharedSlot);
1710
        sharedSlot = sharedSlot->next;
1711
      }
1712
      
1713
      
1714
      mxPushUndefined();
1715
      mxPushUndefined();
1716
      mxPushUndefined();
1717
      mxPushUndefined();
1718
      mxPushUndefined();
1719
      mxModuleInstanceInternal(mxProgram.value.reference)->value.module.realm = fxNewRealmInstance(the);
1720
      mxPop();
1721
      
1722
      the->collectFlag = XS_COLLECTING_FLAG;
1723
1724
    #ifdef mxDebug
1725
      fxLogin(the);
1726
    #endif
1727
1728
      the->firstJump = C_NULL;
1729
1730
    }
1731
    else {
1732
      fxFree(the);
1733
      c_free(the);
1734
      the = NULL;
1735
    }
1736
  }
1737
  return the;
1738
}
1739
1740
txMachine* fxPrepareMachine(txCreation* creation, txPreparation* preparation, txString name, void* context, void* archive)
1741
{
1742
  txMachine _root;
1743
  txMachine* root = &_root;
1744
  if ((preparation->version[0] != XS_MAJOR_VERSION) || (preparation->version[1] != XS_MINOR_VERSION))
1745
    return C_NULL;
1746
  c_memset(root, 0, sizeof(txMachine));
1747
  root->preparation = preparation;
1748
  root->keyArray = preparation->keys;
1749
  root->colors = preparation->colors;
1750
  root->keyCount = (txID)preparation->keyCount + (txID)preparation->creation.initialKeyCount;
1751
  root->keyIndex = (txID)preparation->keyCount;
1752
  root->nameModulo = preparation->nameModulo;
1753
  root->nameTable = preparation->names;
1754
  root->symbolModulo = preparation->symbolModulo;
1755
  root->symbolTable = preparation->symbols;
1756
1757
  root->stack = &preparation->stack[0];
1758
  root->stackBottom = &preparation->stack[0];
1759
  root->stackTop = &preparation->stack[preparation->stackCount];
1760
1761
  root->firstHeap = &preparation->heap[0];
1762
  root->freeHeap = &preparation->heap[preparation->heapCount - 1];
1763
  root->aliasCount = (txID)preparation->aliasCount;
1764
  
1765
  root->profileID = (txID)preparation->profileID;
1766
  
1767
  if (!creation)
1768
    creation = &preparation->creation;
1769
  return fxCloneMachine(creation, root, name, context);
1770
}
1771
1772
void fxShareMachine(txMachine* the)
1773
{
1774
  if (!(the->shared)) {
1775
  #ifdef mxDebug
1776
    fxLogout(the);
1777
  #endif
1778
    {
1779
      txSlot* realm = mxModuleInstanceInternal(mxProgram.value.reference)->value.module.realm;
1780
      txSlot* modules = mxOwnModules(realm)->value.reference;
1781
      txSlot* module = modules->next;
1782
      while (module) {
1783
        mxModuleInstanceInternal(module->value.reference)->value.module.realm = NULL;
1784
        module = module->next;
1785
      }
1786
      mxModuleInstanceInternal(mxProgram.value.reference)->value.module.realm = NULL;
1787
      mxException.kind = XS_REFERENCE_KIND;
1788
      mxException.value.reference = mxRealmClosures(realm)->value.reference;
1789
      mxProgram.value.reference = modules; //@@
1790
      
1791
      {
1792
        txSlot* target = fxNewInstance(the);
1793
        txSlot* modules = mxOwnModules(realm)->value.reference;
1794
        txSlot* module = modules->next;
1795
        while (module) {
1796
          target = target->next = fxNewSlot(the);
1797
          target->value.symbol = mxModuleInstanceInternal(module->value.reference)->value.module.id;
1798
          target->kind = XS_SYMBOL_KIND;
1799
          target->ID = mxModuleInstanceInternal(module->value.reference)->value.module.id;
1800
          module = module->next;
1801
        }
1802
        mxPull(mxHosts); //@@
1803
      }
1804
      mxModuleQueue = mxUndefined;
1805
      mxDuringJobs = mxUndefined;
1806
      mxFinalizationRegistries = mxUndefined;
1807
      mxPendingJobs = mxUndefined;
1808
      mxRunningJobs = mxUndefined;
1809
      mxBreakpoints = mxUndefined;
1810
      mxHostInspectors = mxUndefined;
1811
      mxInstanceInspectors = mxUndefined;
1812
    }
1813
    fxCollectGarbage(the);
1814
    fxShare(the);
1815
    the->shared = 1;
1816
  }
1817
}
1818
#endif
1819
1820
/* Garbage Collector */
1821
1822
void fxCollectGarbage(txMachine* the)
1823
10.4k
{
1824
10.4k
  fxCollect(the, XS_COMPACT_FLAG | XS_COLLECT_KEYS_FLAG);
1825
10.4k
}
1826
1827
void fxEnableGarbageCollection(txMachine* the, txBoolean enableIt)
1828
0
{
1829
0
  if (enableIt)
1830
0
    the->collectFlag |= XS_COLLECTING_FLAG;
1831
0
  else
1832
0
    the->collectFlag &= ~XS_COLLECTING_FLAG;
1833
0
}
1834
1835
void fxRemember(txMachine* the, txSlot* theSlot)
1836
2
{
1837
2
  txSlot* aHeap;
1838
2
  txSlot* aLimit;
1839
2
  if ((the->stack <= theSlot) && (theSlot < the->stackTop)) {
1840
0
    return;
1841
0
  }
1842
2
  aHeap = the->firstHeap;
1843
4
  while (aHeap) {
1844
2
    aLimit = aHeap->value.reference;
1845
2
    if ((aHeap < theSlot) && (theSlot < aLimit)) {
1846
0
      return;
1847
0
    }
1848
2
    aHeap = aHeap->next;
1849
2
  }
1850
2
  fxForget(the, theSlot);
1851
2
  theSlot->next = the->cRoot;
1852
2
  the->cRoot = theSlot;
1853
2
}
1854
1855
void fxForget(txMachine* the, txSlot* theSlot)
1856
3
{
1857
3
  if (!(theSlot->flag & XS_MARK_FLAG)) {
1858
3
    txSlot* aSlot = the->cRoot;
1859
3
    txSlot** aSlotAddr = &(the->cRoot);
1860
3
    while ((aSlot = *aSlotAddr)) {
1861
1
      if (aSlot == theSlot) {
1862
1
        *aSlotAddr = aSlot->next;
1863
1
        return;
1864
1
      }
1865
0
      aSlotAddr = &(aSlot->next);
1866
0
    }
1867
3
  }
1868
3
}
1869
1870
void fxAccess(txMachine* the, txSlot* theSlot)
1871
0
{
1872
0
  if (theSlot)
1873
0
    the->scratch = *theSlot;
1874
0
  else
1875
0
    the->scratch.kind = XS_UNDEFINED_KIND;
1876
0
  the->scratch.next = NULL;
1877
0
  the->scratch.flag = XS_NO_FLAG;
1878
0
  the->scratch.ID = XS_NO_ID;
1879
0
}
1880
1881
/* Host */
1882
1883
txMachine* fxBeginHost(txMachine* the)
1884
78.9M
{
1885
78.9M
#if defined(mxInstrument) || defined(mxProfile)
1886
78.9M
  if (the->frame == C_NULL)
1887
31.3k
    fxCheckProfiler(the, C_NULL);
1888
78.9M
#endif
1889
78.9M
  mxOverflow(-5);
1890
  /* THIS */
1891
78.9M
  (--the->stack)->next = C_NULL;
1892
78.9M
  mxInitSlotKind(the->stack, XS_UNDEFINED_KIND);
1893
  /* FUNCTION */
1894
78.9M
  (--the->stack)->next = C_NULL;
1895
78.9M
  mxInitSlotKind(the->stack, XS_UNDEFINED_KIND);
1896
  /* RESULT */
1897
78.9M
  (--the->stack)->next = C_NULL;
1898
78.9M
  mxInitSlotKind(the->stack, XS_UNDEFINED_KIND);
1899
  /* FRAME */
1900
78.9M
  (--the->stack)->next = the->frame;
1901
78.9M
  the->stack->ID = 0;
1902
78.9M
  the->stack->flag = XS_C_FLAG;
1903
78.9M
#ifdef mxDebug
1904
78.9M
  if (the->breakOnStartFlag) {
1905
0
    the->breakOnStartFlag = 0;
1906
0
    the->stack->flag |= XS_STEP_INTO_FLAG | XS_STEP_OVER_FLAG;
1907
0
  }
1908
78.9M
  if (the->frame && (the->frame->flag & XS_STEP_INTO_FLAG))
1909
0
    the->stack->flag |= XS_STEP_INTO_FLAG | XS_STEP_OVER_FLAG;
1910
78.9M
#endif
1911
78.9M
  the->stack->kind = XS_FRAME_KIND;
1912
78.9M
  the->stack->value.frame.code = the->code;
1913
78.9M
  the->stack->value.frame.scope = the->scope;
1914
78.9M
  the->frame = the->stack;
1915
  /* VARC */
1916
78.9M
  (--the->stack)->next = C_NULL;
1917
78.9M
  the->stack->ID = XS_NO_ID;
1918
78.9M
  the->stack->flag = XS_NO_FLAG;
1919
78.9M
  the->stack->kind = XS_VAR_KIND;
1920
78.9M
  the->stack->value.environment.variable.count = 0;
1921
78.9M
  the->stack->value.environment.line = 0;
1922
78.9M
  the->scope = the->stack;
1923
78.9M
  the->code = C_NULL;
1924
78.9M
  return the;
1925
78.9M
}
1926
1927
void fxEndHost(txMachine* the)
1928
78.8M
{
1929
78.8M
    if (the->frame->next == C_NULL) {
1930
30.3k
        fxEndJob(the);
1931
30.3k
    }
1932
78.8M
  the->stack = the->frame + 4;
1933
78.8M
  the->scope = the->frame->value.frame.scope;
1934
78.8M
  the->code = the->frame->value.frame.code;
1935
78.8M
  the->frame = the->frame->next;
1936
78.8M
}
1937
1938
void fxEndJob(txMachine* the)
1939
53.7k
{
1940
53.7k
  if (gxDefaults.cleanupFinalizationRegistries)
1941
53.7k
    gxDefaults.cleanupFinalizationRegistries(the);
1942
53.7k
  if (mxDuringJobs.kind == XS_REFERENCE_KIND)
1943
53.7k
    mxDuringJobs.value.reference->next = C_NULL;
1944
53.7k
  fxCheckUnhandledRejections(the, 0);
1945
53.7k
}
1946
1947
void fxExitToHost(txMachine* the)
1948
979
{
1949
979
  txJump* jump = the->firstJump;
1950
163k
  while (jump->nextJump) {
1951
162k
    txJump* nextJump = jump->nextJump;
1952
162k
    if (jump->flag)
1953
15.5k
      c_free(jump);
1954
162k
    jump = nextJump;
1955
162k
  }
1956
979
  c_longjmp(jump->buffer, 1);
1957
979
}
1958
1959
typedef struct {
1960
  txMachine* machine;
1961
  txU1* archive;
1962
  txArchiveRead read;
1963
  txArchiveWrite write;
1964
  txU1* buffer;
1965
  txU1* scratch;
1966
  size_t offset;
1967
  size_t size;
1968
  size_t bufferCode;
1969
  size_t bufferLoop;
1970
  size_t bufferOffset;
1971
  size_t bufferSize;
1972
  size_t scratchSize;
1973
  txID* ids;
1974
  txID* map;
1975
  txID* maps;
1976
  c_jmp_buf jmp_buf;
1977
  txBoolean dirty;
1978
} txMapper;
1979
1980
static void fxMapperMapID(txMapper* self, txID id);
1981
static void fxMapperMapIDs(txMapper* self);
1982
static txU1 fxMapperRead1(txMapper* self);
1983
static txU2 fxMapperRead2(txMapper* self);
1984
static txU4 fxMapperRead4(txMapper* self);
1985
static void fxMapperReadAtom(txMapper* self, Atom* atom);
1986
static void fxMapperSkip(txMapper* self, size_t size);
1987
static void fxMapperStep(txMapper* self);
1988
1989
#define mxMapAtom(POINTER) \
1990
0
  atom.atomSize = c_read32be(POINTER); \
1991
0
  POINTER += 4; \
1992
0
  atom.atomType = c_read32be(POINTER); \
1993
0
  POINTER += 4
1994
  
1995
1996
#define mxElseStatus(_ASSERTION,_STATUS) \
1997
0
  ((void)((_ASSERTION) || ((self->buffer[8] = (_STATUS)), c_longjmp(self->jmp_buf, 1), 0)))
1998
0
#define mxElseFatalCheck(_ASSERTION) mxElseStatus(_ASSERTION, XS_FATAL_CHECK_EXIT)
1999
0
#define mxElseIncompatibleMod(_ASSERTION) mxElseStatus(_ASSERTION, XS_INCOMPATIBLE_MOD_EXIT)
2000
0
#define mxElseNoMoreKeys(_ASSERTION) mxElseStatus(_ASSERTION, XS_NO_MORE_KEYS_EXIT)
2001
0
#define mxElseNotEnoughMemory(_ASSERTION) mxElseStatus(_ASSERTION, XS_NOT_ENOUGH_MEMORY_EXIT)
2002
#define mxElseInstall(_ASSERTION) if (!(_ASSERTION)) goto install
2003
2004
0
#define mxArchiveHeaderSize (sizeof(Atom) + sizeof(Atom) + XS_VERSION_SIZE + sizeof(Atom) + XS_DIGEST_SIZE)
2005
2006
static txU1 *fxGetArchiveModules(txMachine *the, void* archive, txU4 *size)
2007
0
{
2008
0
  txPreparation* preparation = the->preparation;
2009
0
  txU1* p = archive;
2010
0
  if (!preparation || !p) {
2011
0
    *size = 0;
2012
0
    return NULL;
2013
0
  }
2014
0
  p += mxArchiveHeaderSize;
2015
  // NAME
2016
0
  p += c_read32be(p);
2017
  // SYMB
2018
0
  p += c_read32be(p);
2019
  // IDEN
2020
0
  p += c_read32be(p);
2021
  // MAPS
2022
0
  p += c_read32be(p);
2023
  // MODS
2024
0
  *size = c_read32be(p) - sizeof(Atom);
2025
0
  return p + sizeof(Atom);
2026
0
}
2027
2028
void* fxGetArchiveCode(txMachine* the, void* archive, txString path, size_t* size)
2029
0
{
2030
0
  txU4 atomSize;
2031
0
  txU1 *p = fxGetArchiveModules(the, archive, &atomSize), *q;
2032
0
  if (!p)
2033
0
    return NULL; 
2034
0
  q = p + atomSize;
2035
0
  while (p < q) {
2036
    // PATH
2037
0
    atomSize = c_read32be(p);
2038
0
    if (!c_strcmp(path, (txString)(p + sizeof(Atom)))) {
2039
0
      p += atomSize;
2040
0
      atomSize = c_read32be(p);
2041
0
      *size = atomSize - sizeof(Atom);
2042
0
      return p + sizeof(Atom);
2043
0
    }
2044
0
    p += atomSize;
2045
    // CODE
2046
0
    atomSize = c_read32be(p);
2047
0
    p += atomSize;
2048
0
  }
2049
0
  return C_NULL;
2050
0
}
2051
2052
txInteger fxGetArchiveCodeCount(txMachine* the, void* archive)
2053
0
{
2054
0
  txInteger count = 0;
2055
0
  txU4 size;
2056
0
  txU1 *p = fxGetArchiveModules(the, archive, &size);
2057
0
  if (p) {
2058
0
    txU1 *q = p + size;
2059
0
    while (p < q) {
2060
      // PATH
2061
0
      p += c_read32be(p);
2062
      // CODE
2063
0
      p += c_read32be(p);
2064
0
      count += 1;
2065
0
    }
2066
0
  }
2067
0
  return count;
2068
0
}
2069
2070
void* fxGetArchiveCodeName(txMachine* the, void* archive, txInteger index)
2071
0
{
2072
0
  txU4 atomSize;
2073
0
  txU1 *p = fxGetArchiveModules(the, archive, &atomSize), *q;
2074
0
  if (!p)
2075
0
    return NULL;
2076
0
  q = p + atomSize;
2077
0
  while (p < q) {
2078
    // PATH
2079
0
    if (!index--)
2080
0
      return (txString)(p + sizeof(Atom));
2081
0
    p += c_read32be(p);
2082
    // CODE
2083
0
    p += c_read32be(p);
2084
0
  }
2085
0
  return C_NULL;
2086
0
}
2087
2088
static txU1 *fxGetArchiveResources(txMachine *the, void* archive, txU4 *size)
2089
0
{
2090
0
  txPreparation* preparation = the->preparation;
2091
0
  txU1* p = archive;
2092
0
  if (!preparation || !p) {
2093
0
    *size = 0;
2094
0
    return NULL;
2095
0
  }
2096
0
  p += mxArchiveHeaderSize;
2097
  // NAME
2098
0
  p += c_read32be(p);
2099
  // SYMB
2100
0
  p += c_read32be(p);
2101
  // IDEN
2102
0
  p += c_read32be(p);
2103
  // MAPS
2104
0
  p += c_read32be(p);
2105
  // MODS
2106
0
  p += c_read32be(p);
2107
  // RSRC
2108
0
  *size = c_read32be(p) - sizeof(Atom);
2109
0
  return p + sizeof(Atom);
2110
0
}
2111
2112
void* fxGetArchiveData(txMachine* the, void* archive, txString path, size_t* size)
2113
0
{
2114
0
  txU4 atomSize;
2115
0
  txU1 *p = fxGetArchiveResources(the, archive, &atomSize), *q;
2116
0
  if (!p)
2117
0
    return NULL; 
2118
0
  q = p + atomSize;
2119
0
  while (p < q) {
2120
    // PATH
2121
0
    atomSize = c_read32be(p);
2122
0
    if (!c_strcmp(path, (txString)(p + sizeof(Atom)))) {
2123
0
      p += atomSize;
2124
0
      atomSize = c_read32be(p);
2125
0
      *size = atomSize - sizeof(Atom);
2126
0
      return p + sizeof(Atom);
2127
0
    }
2128
0
    p += atomSize;
2129
    // DATA
2130
0
    atomSize = c_read32be(p);
2131
0
    p += atomSize;
2132
0
  }
2133
0
  return C_NULL;
2134
0
}
2135
2136
txInteger fxGetArchiveDataCount(txMachine* the, void* archive)
2137
0
{
2138
0
  txInteger count = 0;
2139
0
  txU4 size;
2140
0
  txU1 *p = fxGetArchiveResources(the, archive, &size);
2141
0
  if (p) {
2142
0
    txU1 *q = p + size;
2143
0
    while (p < q) {
2144
      // PATH
2145
0
      p += c_read32be(p);
2146
      // DATA
2147
0
      p += c_read32be(p);
2148
0
      count += 1;
2149
0
    }
2150
0
  }
2151
0
  return count;
2152
0
}
2153
2154
void* fxGetArchiveDataName(txMachine* the, void* archive, txInteger index)
2155
0
{
2156
0
  txU4 atomSize;
2157
0
  txU1 *p = fxGetArchiveResources(the, archive, &atomSize), *q;
2158
0
  if (!p)
2159
0
    return NULL;
2160
0
  q = p + atomSize;
2161
0
  while (p < q) {
2162
    // PATH
2163
0
    if (!index--)
2164
0
      return (txString)(p + sizeof(Atom));
2165
0
    p += c_read32be(p);
2166
    // DATA
2167
0
    p += c_read32be(p);
2168
0
  }
2169
0
  return C_NULL;
2170
0
}
2171
2172
void* fxGetArchiveName(txMachine* the, void* archive)
2173
0
{
2174
0
  txU1* p = archive;
2175
0
  if (!p)
2176
0
    return NULL;
2177
0
  p += mxArchiveHeaderSize;
2178
  // NAME
2179
0
  return p + sizeof(Atom);
2180
0
}
2181
2182
void* fxMapArchive(txMachine* the, txPreparation* preparation, void* archive, size_t bufferSize, txArchiveRead read, txArchiveWrite write)
2183
0
{
2184
0
  txMapper mapper;
2185
0
  txMapper* self = &mapper;
2186
0
  Atom atom;
2187
0
  txU1* p;
2188
0
  txU1* q;
2189
0
  txU1 major = 0, minor = 0, patch = 0;
2190
0
  txID id;
2191
0
  txID c, i;
2192
0
  txFlag clean;
2193
2194
0
  c_memset(self, 0, sizeof(txMapper));
2195
0
  if (c_setjmp(self->jmp_buf) == 0) {
2196
0
    self->machine = the;
2197
0
    self->archive = archive;
2198
0
    self->read = read;
2199
0
    self->write = write;
2200
    
2201
0
    self->scratchSize = 1024;
2202
0
    self->scratch = c_malloc(self->scratchSize + bufferSize);
2203
0
    mxElseNotEnoughMemory(self->scratch != C_NULL);
2204
0
    self->bufferSize = bufferSize;
2205
0
    self->buffer = self->scratch + self->scratchSize;
2206
    
2207
0
    mxElseFatalCheck(self->read(self->archive, 0, self->buffer, mxArchiveHeaderSize));
2208
  
2209
0
    p = self->buffer;
2210
0
    mxMapAtom(p);
2211
0
    if (atom.atomType != XS_ATOM_ARCHIVE) {
2212
0
      self->archive = NULL;
2213
0
      goto bail;
2214
0
    }
2215
0
    self->size = atom.atomSize;
2216
0
    mxMapAtom(p);
2217
0
    mxElseFatalCheck(atom.atomType == XS_ATOM_VERSION);
2218
0
    mxElseFatalCheck(atom.atomSize == sizeof(Atom) + 4);
2219
0
    major = *p++;
2220
0
    minor = *p++;
2221
0
    patch = *p++;
2222
0
    txU2 mod = (major << 8) + minor;
2223
0
    txU2 min = (XS_MOD_COMPATIBLE_MAJOR_VERSION << 8) + XS_MOD_COMPATIBLE_MINOR_VERSION;
2224
0
    txU2 max = (XS_MAJOR_VERSION << 8) + XS_MINOR_VERSION;
2225
0
    mxElseIncompatibleMod((min <= mod) && (mod <= max));
2226
0
    p++;
2227
0
    mxMapAtom(p);
2228
0
    mxElseFatalCheck(atom.atomType == XS_ATOM_SIGNATURE);
2229
0
    mxElseFatalCheck(atom.atomSize == sizeof(Atom) + XS_DIGEST_SIZE);
2230
0
    p += XS_DIGEST_SIZE;
2231
    
2232
0
    self->bufferOffset = mxArchiveHeaderSize;
2233
0
    if (self->bufferSize > self->size)
2234
0
      self->bufferSize = self->size;
2235
0
    mxElseFatalCheck(self->read(self->archive, mxArchiveHeaderSize, p, self->bufferSize - mxArchiveHeaderSize));
2236
  
2237
0
    fxMapperReadAtom(self, &atom);
2238
0
    mxElseFatalCheck(atom.atomType == XS_ATOM_NAME);
2239
0
    fxMapperSkip(self, atom.atomSize - sizeof(Atom));
2240
  
2241
0
    fxMapperReadAtom(self, &atom);
2242
0
    mxElseFatalCheck(atom.atomType == XS_ATOM_SYMBOLS);
2243
0
    c = fxMapperRead2(self);
2244
0
    self->ids = c_malloc(c * sizeof(txID));
2245
0
    mxElseFatalCheck(self->ids != C_NULL);
2246
0
    id = (txID)preparation->keyCount;
2247
0
    for (i = 0; i < c; i++) {
2248
0
      txU1 byte;
2249
0
      p = self->scratch;
2250
0
      q = p + self->scratchSize;
2251
0
      while ((byte = fxMapperRead1(self))) {
2252
0
        mxElseFatalCheck(p < q);
2253
0
        *p++ = byte;
2254
0
      }
2255
0
      mxElseFatalCheck(p < q);
2256
0
      *p = 0;
2257
0
      if (i == 0)
2258
0
        self->ids[i] = XS_NO_ID;
2259
0
      else
2260
0
        self->ids[i] = fxID(the, (txString)self->scratch);
2261
0
    }
2262
    
2263
0
    fxMapperReadAtom(self, &atom);
2264
0
    mxElseFatalCheck(atom.atomType == XS_ATOM_IDENTIFIERS);
2265
0
    self->bufferLoop = self->bufferOffset - sizeof(Atom) + atom.atomSize;
2266
0
    i = 0;
2267
0
    clean = 1;
2268
0
    while (self->bufferOffset < self->bufferLoop) {
2269
0
      txID id = self->ids[i];
2270
0
      txU1 low = (txU1)(id & 0x00FF);
2271
0
      txU1 high =  (txU1)(id >> 8);
2272
0
      if (self->bufferOffset == self->bufferSize)
2273
0
        fxMapperStep(self);
2274
0
      if (*(self->buffer + self->bufferOffset) != low) {
2275
0
        *(self->buffer + self->bufferOffset) = low;
2276
0
        self->dirty = 1;
2277
0
        clean = 0;
2278
0
      }
2279
0
      self->bufferOffset++;
2280
0
      if (self->bufferOffset == self->bufferSize)
2281
0
        fxMapperStep(self);
2282
0
      if (*(self->buffer + self->bufferOffset) != high) {
2283
0
        *(self->buffer + self->bufferOffset) = high;
2284
0
        self->dirty = 1;
2285
0
        clean = 0;
2286
0
      }
2287
0
      self->bufferOffset++;
2288
0
      i++;
2289
0
    }
2290
0
    if (clean)
2291
0
      goto bail;
2292
    
2293
0
    fxMapperReadAtom(self, &atom);
2294
0
    mxElseFatalCheck(atom.atomType == XS_ATOM_MAPS);
2295
0
    self->bufferLoop = self->bufferOffset - sizeof(Atom) + atom.atomSize;
2296
0
    self->maps = self->map = c_malloc((self->bufferLoop - self->bufferOffset));
2297
0
    mxElseFatalCheck(self->maps != C_NULL);
2298
0
    while (self->bufferOffset < self->bufferLoop)
2299
0
      *self->map++ = fxMapperRead2(self);
2300
0
    self->map = self->maps;
2301
    
2302
0
    fxMapperReadAtom(self, &atom);
2303
0
    mxElseFatalCheck(atom.atomType == XS_ATOM_MODULES);
2304
0
    self->bufferLoop = self->bufferOffset - sizeof(Atom) + atom.atomSize;
2305
0
    while (self->bufferOffset < self->bufferLoop) {
2306
0
      id += 2;
2307
0
      fxMapperReadAtom(self, &atom);
2308
0
      mxElseFatalCheck(atom.atomType == XS_ATOM_PATH);
2309
0
      fxMapperSkip(self, atom.atomSize - sizeof(Atom));
2310
0
      fxMapperReadAtom(self, &atom);
2311
0
      mxElseFatalCheck(atom.atomType == XS_ATOM_CODE);
2312
0
      self->bufferCode = self->bufferOffset - sizeof(Atom) + atom.atomSize;
2313
0
      fxMapperMapIDs(self);
2314
0
    }
2315
    
2316
0
    if (preparation->creation.incrementalKeyCount == 0)
2317
0
      mxElseNoMoreKeys((id - (txID)preparation->keyCount) < (txID)preparation->creation.initialKeyCount);
2318
  
2319
0
    fxMapperReadAtom(self, &atom);
2320
0
    mxElseFatalCheck(atom.atomType == XS_ATOM_RESOURCES);
2321
0
    self->bufferLoop = self->bufferOffset - sizeof(Atom) + atom.atomSize;
2322
0
    while (self->bufferOffset < self->bufferLoop) {
2323
0
      fxMapperReadAtom(self, &atom);
2324
0
      mxElseFatalCheck(atom.atomType == XS_ATOM_PATH);
2325
0
      fxMapperSkip(self, atom.atomSize - sizeof(Atom));
2326
0
      fxMapperReadAtom(self, &atom);
2327
0
      mxElseFatalCheck(atom.atomType == XS_ATOM_DATA);
2328
0
      fxMapperSkip(self, atom.atomSize - sizeof(Atom));
2329
0
    }
2330
  
2331
0
    if (self->bufferOffset) {
2332
0
      if (self->dirty) {
2333
0
        mxElseFatalCheck(self->write(self->archive, self->offset, self->buffer, self->bufferOffset));
2334
0
        self->dirty = 0;
2335
0
      }
2336
0
    }
2337
0
  }
2338
0
  else {
2339
0
    self->buffer[0] = 0;
2340
0
    self->buffer[1] = 0;
2341
0
    self->buffer[2] = 0;
2342
0
    self->buffer[3] = 12;
2343
0
    self->buffer[4] = 'X';
2344
0
    self->buffer[5] = 'S';
2345
0
    self->buffer[6] = '_';
2346
0
    self->buffer[7] = 'E';
2347
0
    self->buffer[9] = major;
2348
0
    self->buffer[10] = minor;
2349
0
    self->buffer[11] = patch;
2350
0
    self->write(self->archive, 0, self->buffer, 12);
2351
0
    self->archive = C_NULL;
2352
0
  }
2353
0
bail:
2354
0
  if (self->ids)
2355
0
    c_free(self->ids);
2356
0
  if (self->maps)
2357
0
    c_free(self->maps);
2358
0
  if (self->scratch)
2359
0
    c_free(self->scratch);
2360
0
  return self->archive;
2361
0
}
2362
2363
void fxMapperMapID(txMapper* self, txID id)
2364
0
{
2365
0
  if (self->bufferOffset == self->bufferSize)
2366
0
    fxMapperStep(self);
2367
0
  *(self->buffer + self->bufferOffset) = (txU1)(id & 0x00FF);
2368
0
  self->bufferOffset++;
2369
0
  self->dirty = 1;
2370
0
  if (self->bufferOffset == self->bufferSize)
2371
0
    fxMapperStep(self);
2372
0
  *(self->buffer + self->bufferOffset) = (txU1)(id >> 8);
2373
0
  self->bufferOffset++;
2374
0
  self->dirty = 1;
2375
0
}
2376
2377
void fxMapperMapIDs(txMapper* self)
2378
0
{
2379
0
  register const txS1* bytes = gxCodeSizes;
2380
0
  txU1 code;
2381
0
  txS1 offset;
2382
0
  txU4 index;
2383
0
  while (self->bufferOffset < self->bufferCode) {
2384
    //fprintf(stderr, "%s", gxCodeNames[*((txU1*)p)]);
2385
0
    code = fxMapperRead1(self);
2386
0
    offset = (txS1)c_read8(bytes + code);
2387
0
    if (0 < offset) {
2388
0
      if (XS_CODE_PROFILE == code)
2389
0
        fxMapperMapID(self, fxGenerateProfileID(self->machine));
2390
0
      else
2391
0
        fxMapperSkip(self, offset - 1);
2392
0
    }
2393
0
    else if (0 == offset)
2394
0
      fxMapperMapID(self, self->ids[*(self->map++)]);
2395
0
    else if (-1 == offset) {
2396
0
      index = fxMapperRead1(self);
2397
0
      fxMapperSkip(self, index);
2398
0
    }
2399
0
    else if (-2 == offset) {
2400
0
      index = fxMapperRead2(self); 
2401
0
      fxMapperSkip(self, index);
2402
0
    }
2403
    //fprintf(stderr, "\n");
2404
0
  }
2405
0
}
2406
2407
txU1 fxMapperRead1(txMapper* self)
2408
0
{
2409
0
  txU1 result;
2410
0
  if (self->bufferOffset == self->bufferSize)
2411
0
    fxMapperStep(self);
2412
0
  result = *(self->buffer + self->bufferOffset);
2413
0
  self->bufferOffset++;
2414
0
  return result;
2415
0
}
2416
2417
txU2 fxMapperRead2(txMapper* self)
2418
0
{
2419
0
  txU2 result;
2420
0
  result = fxMapperRead1(self);
2421
0
  result |= fxMapperRead1(self) << 8;
2422
0
  return result;
2423
0
}
2424
2425
txU4 fxMapperRead4(txMapper* self)
2426
0
{
2427
0
  txU4 result;
2428
0
  result = fxMapperRead1(self) << 24;
2429
0
  result |= fxMapperRead1(self) << 16;
2430
0
  result |= fxMapperRead1(self) << 8;
2431
0
  result |= fxMapperRead1(self);
2432
0
  return result;
2433
0
}
2434
2435
void fxMapperReadAtom(txMapper* self, Atom* atom)
2436
0
{
2437
0
  atom->atomSize = fxMapperRead4(self);
2438
0
  atom->atomType = fxMapperRead4(self);
2439
0
}
2440
2441
void fxMapperSkip(txMapper* self, size_t size)
2442
0
{
2443
0
  size_t offset = self->bufferOffset + size;
2444
0
  while ((offset >= self->bufferSize) && (self->bufferSize > 0)) {
2445
0
    offset -= self->bufferSize;
2446
0
    fxMapperStep(self);
2447
0
  }
2448
0
  self->bufferOffset = offset;
2449
0
}
2450
2451
void fxMapperStep(txMapper* self)
2452
0
{
2453
0
  if (self->dirty) {
2454
0
    mxElseFatalCheck(self->write(self->archive, self->offset, self->buffer, self->bufferSize));
2455
0
    self->dirty = 0;
2456
0
  }
2457
0
  self->offset += self->bufferSize;
2458
0
  self->size -= self->bufferSize;
2459
0
  self->bufferCode -= self->bufferSize;
2460
0
  self->bufferLoop -= self->bufferSize;
2461
0
  if (self->bufferSize > self->size)
2462
0
    self->bufferSize = self->size;
2463
0
  if (self->bufferSize > 0)
2464
0
    mxElseFatalCheck(self->read(self->archive, self->offset, self->buffer, self->bufferSize));
2465
0
  self->bufferOffset = 0;
2466
0
}
2467
2468
void fxSetArchive(txMachine* the, void* archive)
2469
0
{
2470
0
  the->archive = archive;
2471
0
  if (archive) {
2472
0
    fxNewHostObject(the, C_NULL);
2473
0
    the->stack->value.reference->next->value.host.data = archive;
2474
0
    mxPush(mxGlobal);
2475
0
    mxDefineID(fxID(the, "archive"), XS_DONT_ENUM_FLAG, XS_GET_ONLY);
2476
0
    mxPop();
2477
0
  }
2478
0
  else {
2479
0
    mxPush(mxGlobal);
2480
0
    mxDeleteID(fxID(the, "archive"));
2481
0
  }
2482
0
}
2483
2484
txBoolean fxIsProfiling(txMachine* the)
2485
0
{
2486
0
#if defined(mxInstrument) || defined(mxProfile)
2487
0
  return (the->profiler) ? 1 : 0;
2488
#else
2489
  return 0;
2490
#endif
2491
0
}
2492
2493
void fxStartProfiling(txMachine* the)
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
  fxCreateProfiler(the);
2501
0
#endif
2502
0
}
2503
2504
void fxStopProfiling(txMachine* the, void* stream)
2505
0
{
2506
0
#if defined(mxInstrument) || defined(mxProfile)
2507
0
  if (!the->profiler)
2508
0
    return; 
2509
//  if (the->frame)
2510
//    fxAbort(the, XS_FATAL_CHECK_EXIT);
2511
0
  fxDeleteProfiler(the, stream);
2512
0
#endif
2513
0
}
2514
2515
#ifdef mxFrequency
2516
2517
typedef struct {
2518
  txNumber exit;
2519
  txNumber frequency;
2520
  txU1 code;
2521
} txFrequency;
2522
2523
static int fxCompareExit(const void* a, const void* b)
2524
{
2525
  return ((txFrequency*)b)->exit - ((txFrequency*)a)->exit;
2526
}
2527
2528
static int fxCompareFrequency(const void* a, const void* b)
2529
{
2530
  return ((txFrequency*)b)->frequency - ((txFrequency*)a)->frequency;
2531
}
2532
2533
void fxReportFrequency(txMachine* the)
2534
{
2535
  txFrequency frequencies[XS_CODE_COUNT];
2536
  txU1 code;
2537
  txNumber exitSum = 0;
2538
  txNumber frequencySum = 0;
2539
  for (code = 0; code < XS_CODE_COUNT; code++) {
2540
    frequencies[code].exit = the->exits[code];
2541
    frequencies[code].frequency = the->frequencies[code];
2542
    frequencies[code].code = code;
2543
    exitSum += the->exits[code];
2544
    frequencySum += the->frequencies[code];
2545
  }
2546
  c_qsort(frequencies, XS_CODE_COUNT, sizeof(txFrequency), fxCompareFrequency);
2547
  fprintf(stderr, "Frequencies %10.0lf\n", frequencySum);
2548
  for (code = 0; code < XS_CODE_COUNT; code++) {
2549
    if (!frequencies[code].frequency)
2550
      break;
2551
    fprintf(stderr, "%24s %10.3lf%%\n", 
2552
      gxCodeNames[frequencies[code].code], 
2553
      ((double)(frequencies[code].frequency) * 100.0) / frequencySum);
2554
  }
2555
  c_qsort(frequencies, XS_CODE_COUNT, sizeof(txFrequency), fxCompareExit);
2556
  fprintf(stderr, "Exits %10.0lf\n", exitSum);
2557
  for (code = 0; code < XS_CODE_COUNT; code++) {
2558
    if (!frequencies[code].exit)
2559
      break;
2560
    fprintf(stderr, "%24s%10.3lf%%\n", 
2561
      gxCodeNames[frequencies[code].code], 
2562
      ((double)(frequencies[code].exit) * 100.0) / exitSum);
2563
  }
2564
}
2565
#endif
2566