Coverage Report

Created: 2026-01-09 07:26

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