Coverage Report

Created: 2025-11-11 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/moddable/xs/sources/xsAPI.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016-2025  Moddable Tech, Inc.
3
 *
4
 *   This file is part of the Moddable SDK Runtime.
5
 * 
6
 *   The Moddable SDK Runtime is free software: you can redistribute it and/or modify
7
 *   it under the terms of the GNU Lesser General Public License as published by
8
 *   the Free Software Foundation, either version 3 of the License, or
9
 *   (at your option) any later version.
10
 * 
11
 *   The Moddable SDK Runtime is distributed in the hope that it will be useful,
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *   GNU Lesser General Public License for more details.
15
 * 
16
 *   You should have received a copy of the GNU Lesser General Public License
17
 *   along with the Moddable SDK Runtime.  If not, see <http://www.gnu.org/licenses/>.
18
 *
19
 * This file incorporates work covered by the following copyright and  
20
 * permission notice:  
21
 *
22
 *       Copyright (C) 2010-2016 Marvell International Ltd.
23
 *       Copyright (C) 2002-2010 Kinoma, Inc.
24
 *
25
 *       Licensed under the Apache License, Version 2.0 (the "License");
26
 *       you may not use this file except in compliance with the License.
27
 *       You may obtain a copy of the License at
28
 *
29
 *        http://www.apache.org/licenses/LICENSE-2.0
30
 *
31
 *       Unless required by applicable law or agreed to in writing, software
32
 *       distributed under the License is distributed on an "AS IS" BASIS,
33
 *       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
34
 *       See the License for the specific language governing permissions and
35
 *       limitations under the License.
36
 */
37
38
#include "xsAll.h"
39
40
#define XS_PROFILE_COUNT (256 * 1024)
41
42
static txSlot* fxCheckHostObject(txMachine* the, txSlot* it);
43
44
#ifdef mxFrequency
45
static void fxReportFrequency(txMachine* the);
46
#endif
47
48
/* Slot */
49
50
txKind fxTypeOf(txMachine* the, txSlot* theSlot)
51
0
{
52
0
  if (theSlot->kind == XS_STRING_X_KIND)
53
0
    return XS_STRING_KIND;
54
0
  if (theSlot->kind == XS_BIGINT_X_KIND)
55
0
    return XS_BIGINT_KIND;
56
#if mxHostFunctionPrimitive
57
  if (theSlot->kind == XS_HOST_FUNCTION_KIND)
58
    return XS_REFERENCE_KIND;
59
#endif
60
0
  return theSlot->kind;
61
0
}
62
63
/* Primitives */
64
65
void fxUndefined(txMachine* the, txSlot* theSlot)
66
347k
{
67
347k
  theSlot->kind = XS_UNDEFINED_KIND;
68
347k
}
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
233k
{
77
233k
  theSlot->value.boolean = theValue;
78
233k
  theSlot->kind = XS_BOOLEAN_KIND;
79
233k
}
80
81
txBoolean fxToBoolean(txMachine* the, txSlot* theSlot)
82
27.1M
{
83
27.1M
  switch (theSlot->kind) {
84
585k
  case XS_UNDEFINED_KIND:
85
586k
  case XS_NULL_KIND:
86
586k
    theSlot->kind = XS_BOOLEAN_KIND;
87
586k
    theSlot->value.boolean = 0;
88
586k
    break;
89
21.0M
  case XS_BOOLEAN_KIND:
90
21.0M
    break;
91
2.90M
  case XS_INTEGER_KIND:
92
2.90M
    theSlot->kind = XS_BOOLEAN_KIND;
93
2.90M
    theSlot->value.boolean = (theSlot->value.integer == 0) ? 0 : 1;
94
2.90M
    break;
95
842k
  case XS_NUMBER_KIND:
96
842k
    theSlot->kind = XS_BOOLEAN_KIND;
97
842k
    switch (c_fpclassify(theSlot->value.number)) {
98
35.0k
    case C_FP_NAN:
99
155k
    case C_FP_ZERO:
100
155k
      theSlot->value.boolean = 0;
101
155k
      break;
102
686k
    default:
103
686k
      theSlot->value.boolean = 1;
104
686k
      break;
105
842k
    }
106
842k
    break;
107
842k
  case XS_BIGINT_KIND:
108
75.3k
  case XS_BIGINT_X_KIND:
109
75.3k
    if ((theSlot->value.bigint.size == 1) && (theSlot->value.bigint.data[0] == 0))
110
686
      theSlot->value.boolean = 0;
111
74.6k
    else
112
74.6k
      theSlot->value.boolean = 1;
113
75.3k
    theSlot->kind = XS_BOOLEAN_KIND;
114
75.3k
    break;
115
201k
  case XS_STRING_KIND:
116
201k
  case XS_STRING_X_KIND:
117
201k
    theSlot->kind = XS_BOOLEAN_KIND;
118
201k
    if (c_isEmpty(theSlot->value.string))
119
3.62k
      theSlot->value.boolean = 0;
120
197k
    else
121
197k
      theSlot->value.boolean = 1;
122
201k
    break;
123
#if mxHostFunctionPrimitive
124
  case XS_HOST_FUNCTION_KIND:
125
#endif
126
276
  case XS_SYMBOL_KIND:
127
1.45M
  case XS_REFERENCE_KIND:
128
1.45M
    theSlot->kind = XS_BOOLEAN_KIND;
129
1.45M
    theSlot->value.boolean = 1;
130
1.45M
    break;
131
6
  default:
132
6
    mxTypeError("cannot coerce to boolean");
133
0
    break;
134
27.1M
  }
135
27.1M
  return theSlot->value.boolean;
136
27.1M
}
137
138
void fxInteger(txMachine* the, txSlot* theSlot, txInteger theValue)
139
206k
{
140
206k
  theSlot->value.integer = theValue;
141
206k
  theSlot->kind = XS_INTEGER_KIND;
142
206k
}
143
144
txInteger fxToInteger(txMachine* the, txSlot* theSlot)
145
27.7M
{
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
29.6M
again:
152
29.6M
  switch (theSlot->kind) {
153
3.61M
  case XS_UNDEFINED_KIND:
154
3.71M
  case XS_NULL_KIND:
155
3.71M
    theSlot->kind = XS_INTEGER_KIND;
156
3.71M
    theSlot->value.integer = 0;
157
3.71M
    break;
158
2.31M
  case XS_BOOLEAN_KIND:
159
2.31M
    theSlot->kind = XS_INTEGER_KIND;
160
2.31M
    if (theSlot->value.boolean == 0)
161
943k
      theSlot->value.integer = 0;
162
1.36M
    else
163
1.36M
      theSlot->value.integer = 1;
164
2.31M
    break;
165
18.0M
  case XS_INTEGER_KIND:
166
18.0M
    break;
167
3.70M
  case XS_NUMBER_KIND:
168
3.70M
    theSlot->kind = XS_INTEGER_KIND;
169
3.70M
    switch (c_fpclassify(theSlot->value.number)) {
170
6.52k
    case C_FP_INFINITE:
171
1.92M
    case C_FP_NAN:
172
1.94M
    case C_FP_ZERO:
173
1.94M
      theSlot->value.integer = 0;
174
1.94M
      break;
175
1.75M
    default: {
176
5.33M
      #define MODULO 4294967296.0
177
1.75M
      txNumber aNumber = c_fmod(c_trunc(theSlot->value.number), MODULO);
178
1.75M
      if (aNumber >= MODULO / 2)
179
520k
        aNumber -= MODULO;
180
1.23M
      else if (aNumber < -MODULO / 2)
181
79.2k
        aNumber += MODULO;
182
1.75M
      theSlot->value.integer = (txInteger)aNumber;
183
1.75M
      } break;
184
3.70M
    }
185
3.70M
    mxFloatingPointOp("number to integer");
186
3.70M
    break;
187
1.85M
  case XS_STRING_KIND:
188
1.85M
  case XS_STRING_X_KIND:
189
1.85M
    theSlot->kind = XS_NUMBER_KIND;
190
1.85M
    theSlot->value.number = fxStringToNumber(the, theSlot->value.string, 1);
191
1.85M
    mxMeterOne();
192
1.85M
    goto again;
193
1.28k
  case XS_SYMBOL_KIND:
194
1.28k
    mxTypeError("cannot coerce symbol to integer");
195
0
    break;
196
15.1k
  case XS_REFERENCE_KIND:
197
15.1k
    fxToPrimitive(the, theSlot, XS_NUMBER_HINT);
198
15.1k
    goto again;
199
1
  default:
200
1
    mxTypeError("cannot coerce to integer");
201
0
    break;
202
29.6M
  }
203
27.7M
  return theSlot->value.integer;
204
29.6M
}
205
206
void fxNumber(txMachine* the, txSlot* theSlot, txNumber theValue)
207
4.37k
{
208
4.37k
  theSlot->value.number = theValue;
209
4.37k
  theSlot->kind = XS_NUMBER_KIND;
210
4.37k
}
211
212
txNumber fxToNumber(txMachine* the, txSlot* theSlot)
213
50.5M
{
214
51.4M
again:
215
51.4M
  switch (theSlot->kind) {
216
9.07M
  case XS_UNDEFINED_KIND:
217
9.07M
    theSlot->kind = XS_NUMBER_KIND;
218
9.07M
    theSlot->value.number = C_NAN;
219
9.07M
    break;
220
717k
  case XS_NULL_KIND:
221
717k
    theSlot->kind = XS_NUMBER_KIND;
222
717k
    theSlot->value.number = 0;
223
717k
    break;
224
6.20M
  case XS_BOOLEAN_KIND:
225
6.20M
    theSlot->kind = XS_NUMBER_KIND;
226
6.20M
    if (theSlot->value.boolean == 0)
227
3.73M
      theSlot->value.number = 0;
228
2.46M
    else
229
2.46M
      theSlot->value.number = 1;
230
6.20M
    break;
231
14.6M
  case XS_INTEGER_KIND:
232
14.6M
    theSlot->kind = XS_NUMBER_KIND;
233
14.6M
    theSlot->value.number = theSlot->value.integer;
234
14.6M
    mxFloatingPointOp("integer to number");
235
14.6M
    break;
236
8.71M
  case XS_NUMBER_KIND:
237
8.71M
    break;
238
11.1M
  case XS_STRING_KIND:
239
11.1M
  case XS_STRING_X_KIND:
240
11.1M
    theSlot->kind = XS_NUMBER_KIND;
241
11.1M
    theSlot->value.number = fxStringToNumber(the, theSlot->value.string, 1);
242
11.1M
    mxMeterOne();
243
11.1M
    break;
244
1.10k
  case XS_SYMBOL_KIND:
245
1.10k
    mxTypeError("cannot coerce symbol to number");
246
0
    break;
247
968k
  case XS_REFERENCE_KIND:
248
968k
    fxToPrimitive(the, theSlot, XS_NUMBER_HINT);
249
968k
    goto again;
250
1.66k
  default:
251
1.66k
    mxTypeError("cannot coerce to number");
252
0
    break;
253
51.4M
  }
254
50.5M
  return theSlot->value.number;
255
51.4M
}
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
2.25M
{
264
2.25M
#ifdef mxSnapshot
265
2.25M
  fxCopyStringC(the, theSlot, theValue);
266
#else
267
  theSlot->value.string = theValue;
268
  theSlot->kind = XS_STRING_X_KIND;
269
#endif
270
2.25M
}
271
272
void fxStringBuffer(txMachine* the, txSlot* theSlot, txString theValue, txSize theSize)
273
34.6k
{
274
34.6k
  theSlot->value.string = (txString)fxNewChunk(the, fxAddChunkSizes(the, theSize, 1));
275
34.6k
  if (theValue)
276
0
    c_memcpy(theSlot->value.string, theValue, theSize);
277
34.6k
  else
278
34.6k
    theSlot->value.string[0] = 0;
279
34.6k
  theSlot->value.string[theSize] = 0;
280
34.6k
  theSlot->kind = XS_STRING_KIND;
281
34.6k
}
282
283
txString fxToString(txMachine* the, txSlot* theSlot)
284
75.7M
{
285
75.7M
  char aBuffer[256];
286
79.5M
again:
287
79.5M
  switch (theSlot->kind) {
288
1.22M
  case XS_UNDEFINED_KIND:
289
1.22M
    *theSlot = mxUndefinedString;
290
1.22M
    break;
291
599k
  case XS_NULL_KIND:
292
599k
    fxStringX(the, theSlot, "null");
293
599k
    break;
294
272k
  case XS_BOOLEAN_KIND:
295
272k
    if (theSlot->value.boolean == 0)
296
206k
      fxStringX(the, theSlot, "false");
297
66.5k
    else
298
66.5k
      fxStringX(the, theSlot, "true");
299
272k
    break;
300
6.11M
  case XS_INTEGER_KIND:
301
6.11M
    fxCopyStringC(the, theSlot, fxIntegerToString(the, theSlot->value.integer, aBuffer, sizeof(aBuffer)));
302
6.11M
    mxMeterOne();
303
6.11M
    break;
304
5.44M
  case XS_NUMBER_KIND:
305
5.44M
    fxCopyStringC(the, theSlot, fxNumberToString(the, theSlot->value.number, aBuffer, sizeof(aBuffer), 0, 0));
306
5.44M
    mxMeterOne();
307
5.44M
    break;
308
2.87k
  case XS_SYMBOL_KIND:
309
2.87k
    mxTypeError("cannot coerce symbol to string");
310
0
    break;
311
45.9k
  case XS_BIGINT_KIND:
312
45.9k
  case XS_BIGINT_X_KIND:
313
45.9k
    gxTypeBigInt.toString(the, theSlot, 0);
314
45.9k
    break;
315
62.0M
  case XS_STRING_KIND:
316
62.0M
  case XS_STRING_X_KIND:
317
62.0M
    break;
318
3.86M
  case XS_REFERENCE_KIND:
319
3.86M
    fxToPrimitive(the, theSlot, XS_STRING_HINT);
320
3.86M
    goto again;
321
0
  default:
322
0
    mxTypeError("cannot coerce to string");
323
0
    break;
324
79.5M
  }
325
75.7M
  return theSlot->value.string;
326
79.5M
}
327
328
txString fxToStringBuffer(txMachine* the, txSlot* theSlot, txString theBuffer, txSize theSize)
329
49.6k
{
330
49.6k
  char* aString;
331
49.6k
  txSize aSize;
332
333
49.6k
  aString = fxToString(the, theSlot);
334
49.6k
  aSize = mxStringLength(aString) + 1;
335
49.6k
  if (aSize > theSize)
336
0
    mxRangeError("cannot buffer string");
337
49.6k
  c_memcpy(theBuffer, aString, aSize);
338
49.6k
  return theBuffer;
339
49.6k
}
340
341
void fxUnsigned(txMachine* the, txSlot* theSlot, txUnsigned theValue)
342
1.68M
{
343
1.68M
  if (((txInteger)theValue) >= 0) {
344
1.38M
    theSlot->value.integer = theValue;
345
1.38M
    theSlot->kind = XS_INTEGER_KIND;
346
1.38M
  }
347
292k
  else {
348
292k
    theSlot->value.number = theValue;
349
292k
    theSlot->kind = XS_NUMBER_KIND;
350
292k
  }
351
1.68M
}
352
353
txUnsigned fxToUnsigned(txMachine* the, txSlot* theSlot)
354
3.33M
{
355
3.33M
  txUnsigned result;
356
3.33M
again:
357
3.33M
  switch (theSlot->kind) {
358
1.59k
  case XS_UNDEFINED_KIND:
359
1.63k
  case XS_NULL_KIND:
360
1.63k
    theSlot->kind = XS_INTEGER_KIND;
361
1.63k
    result = theSlot->value.integer = 0;
362
1.63k
    break;
363
2.53k
  case XS_BOOLEAN_KIND:
364
2.53k
    theSlot->kind = XS_INTEGER_KIND;
365
2.53k
    if (theSlot->value.boolean == 0)
366
343
      result = theSlot->value.integer = 0;
367
2.19k
    else
368
2.19k
      result = theSlot->value.integer = 1;
369
2.53k
    break;
370
2.01M
  case XS_INTEGER_KIND:
371
2.01M
    if (theSlot->value.integer >= 0)
372
1.45M
      return (txUnsigned)theSlot->value.integer;
373
561k
    theSlot->kind = XS_NUMBER_KIND;
374
561k
    theSlot->value.number = theSlot->value.integer;
375
    // continue
376
1.87M
  case XS_NUMBER_KIND:
377
1.87M
    theSlot->kind = XS_INTEGER_KIND;
378
1.87M
    switch (c_fpclassify(theSlot->value.number)) {
379
248
    case C_FP_INFINITE:
380
294k
    case C_FP_NAN:
381
741k
    case C_FP_ZERO:
382
741k
      result = theSlot->value.integer = 0;
383
741k
      break;
384
1.13M
    default: {
385
1.98M
      #define MODULO 4294967296.0
386
1.13M
      txNumber aNumber = c_fmod(c_trunc(theSlot->value.number), MODULO);
387
1.13M
      if (aNumber < 0)
388
854k
        aNumber += MODULO;
389
1.13M
      result = (txUnsigned)aNumber;
390
1.13M
      if (((txInteger)result) >= 0) {
391
277k
        theSlot->kind = XS_INTEGER_KIND;
392
277k
        theSlot->value.integer = (txInteger)result;
393
277k
      }
394
854k
      else {
395
854k
        theSlot->kind = XS_NUMBER_KIND;
396
854k
        theSlot->value.number = aNumber;
397
854k
      }
398
1.13M
      } break;
399
1.87M
    }
400
1.87M
    mxFloatingPointOp("number to unsigned");
401
1.87M
    break;
402
1.98k
  case XS_STRING_KIND:
403
1.98k
  case XS_STRING_X_KIND:
404
1.98k
    theSlot->kind = XS_NUMBER_KIND;
405
1.98k
    theSlot->value.number = fxStringToNumber(the, theSlot->value.string, 1);
406
1.98k
    mxMeterOne();
407
1.98k
    goto again;
408
1
  case XS_SYMBOL_KIND:
409
1
    result = 0;
410
1
    mxTypeError("cannot coerce symbol to unsigned");
411
0
    break;
412
1.24k
  case XS_REFERENCE_KIND:
413
1.24k
    fxToPrimitive(the, theSlot, XS_NUMBER_HINT);
414
1.24k
    goto again;
415
7
  default:
416
7
    result = 0;
417
7
    mxTypeError("cannot coerce to unsigned");
418
0
    break;
419
3.33M
  }
420
1.87M
  return result;
421
3.33M
}
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
6.33M
{
459
6.33M
  txSlot* instance;
460
6.33M
  txSlot* array;
461
6.33M
  mxPush(mxArrayPrototype);
462
6.33M
  instance = fxNewArrayInstance(the);
463
6.33M
  array = instance->next;
464
6.33M
  fxSetIndexSize(the, array, size, XS_CHUNK);
465
6.33M
  fxIndexArray(the, array);
466
6.33M
  return instance;
467
6.33M
}
468
469
txSlot* fxNewObject(txMachine* the)
470
3.50M
{
471
3.50M
  mxPush(mxObjectPrototype);
472
3.50M
  return fxNewObjectInstance(the);
473
3.50M
}
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
1.64M
{
581
1.64M
  txSlot* aStack;
582
1.64M
  txSlot* instance;
583
1.64M
  txSlot* property;
584
585
1.64M
  fxToInstance(the, the->stack);
586
1.64M
  aStack = the->stack;
587
1.64M
  instance = fxNewHostFunction(the, theCallback, theLength, name, XS_NO_ID);
588
1.64M
  instance->flag |= XS_CAN_CONSTRUCT_FLAG;
589
1.64M
  property = fxLastProperty(the, instance);
590
1.64M
  fxNextSlotProperty(the, property, aStack, mxID(_prototype), XS_GET_ONLY);
591
1.64M
  property = mxBehaviorSetProperty(the, fxGetInstance(the, aStack), mxID(_constructor), 0, XS_OWN);
592
1.64M
  property->flag = XS_DONT_ENUM_FLAG;
593
1.64M
  property->kind = the->stack->kind;
594
1.64M
  property->value = the->stack->value;
595
1.64M
  *aStack = *the->stack;
596
1.64M
  mxPop();
597
1.64M
  return instance;
598
1.64M
}
599
600
txSlot* fxNewHostFunction(txMachine* the, txCallback theCallback, txInteger theLength, txInteger name, txInteger profileID)
601
24.0M
{
602
24.0M
  txSlot* instance;
603
24.0M
  txSlot* property;
604
605
24.0M
  mxPushUndefined();
606
24.0M
  instance = fxNewSlot(the);
607
24.0M
  instance->flag |= XS_CAN_CALL_FLAG;
608
24.0M
  instance->kind = XS_INSTANCE_KIND;
609
24.0M
  instance->value.instance.garbage = C_NULL;
610
24.0M
  instance->value.instance.prototype = mxFunctionPrototype.value.reference;
611
24.0M
  the->stack->value.reference = instance;
612
24.0M
  the->stack->kind = XS_REFERENCE_KIND;
613
614
  /* CALLBACK */
615
24.0M
  property = instance->next = fxNewSlot(the);
616
24.0M
  property->flag = XS_INTERNAL_FLAG;
617
24.0M
  property->kind = XS_CALLBACK_KIND;
618
24.0M
  property->value.callback.address = theCallback;
619
24.0M
  property->value.callback.closures = C_NULL;
620
621
  /* HOME */
622
24.0M
  property = property->next = fxNewSlot(the);
623
24.0M
  if (profileID != XS_NO_ID)
624
5.73M
    property->ID = profileID;
625
18.3M
  else
626
18.3M
    property->ID = fxGenerateProfileID(the);
627
24.0M
  property->flag = XS_INTERNAL_FLAG;
628
24.0M
  property->kind = XS_HOME_KIND;
629
24.0M
  property->value.home.object = C_NULL;
630
24.0M
  if (the->frame && (mxFunction->kind == XS_REFERENCE_KIND) && (mxIsFunction(mxFunction->value.reference))) {
631
5.56M
    txSlot* slot = mxFunctionInstanceHome(mxFunction->value.reference);
632
5.56M
    property->value.home.module = slot->value.home.module;
633
5.56M
  }
634
18.5M
  else
635
18.5M
    property->value.home.module = C_NULL;
636
637
  /* LENGTH */
638
24.0M
  if (gxDefaults.newFunctionLength)
639
24.0M
    gxDefaults.newFunctionLength(the, instance, theLength);
640
641
  /* NAME */
642
24.0M
  fxRenameFunction(the, instance, name, 0, XS_NO_ID, C_NULL);
643
644
24.0M
  return instance;
645
24.0M
}
646
647
txSlot* fxNewHostInstance(txMachine* the)
648
243k
{
649
243k
  txSlot* prototype = fxGetInstance(the, the->stack);
650
243k
  txSlot* instance = fxNewSlot(the);
651
243k
  instance->kind = XS_INSTANCE_KIND;
652
243k
  instance->value.instance.garbage = C_NULL;
653
243k
  instance->value.instance.prototype = prototype;
654
243k
  the->stack->value.reference = instance;
655
243k
  the->stack->kind = XS_REFERENCE_KIND;
656
243k
  if (prototype) {
657
243k
    txSlot* prototypeHost = prototype->next;
658
243k
    if (prototypeHost && (prototypeHost->kind == XS_HOST_KIND) && (prototypeHost->value.host.variant.destructor != fxReleaseSharedChunk)) {
659
31.0k
      txSlot* instanceHost = instance->next = fxNewSlot(the);
660
31.0k
      instanceHost->flag = XS_INTERNAL_FLAG;
661
31.0k
      instanceHost->kind = XS_HOST_KIND;
662
31.0k
      instanceHost->value.host.data = C_NULL;
663
31.0k
      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
31.0k
      else {
668
31.0k
        instanceHost->value.host.variant.destructor = prototypeHost->value.host.variant.destructor;
669
31.0k
      }
670
31.0k
    }
671
243k
  }
672
243k
  return instance;
673
243k
}
674
675
676
txSlot* fxCheckHostObject(txMachine* the, txSlot* it)
677
124k
{
678
124k
  txSlot* result = C_NULL;
679
124k
  if (it->kind == XS_REFERENCE_KIND) {
680
124k
    it = it->value.reference;
681
124k
    if (it->next) {
682
124k
      it = it->next;
683
124k
      if ((it->flag & XS_INTERNAL_FLAG) && (it->kind == XS_HOST_KIND))
684
124k
        result = it;
685
124k
    }
686
124k
  }
687
124k
  return result;
688
124k
}
689
690
txSlot* fxNewHostObject(txMachine* the, txDestructor theDestructor)
691
31.0k
{
692
31.0k
  txSlot* anInstance;
693
31.0k
  txSlot* aProperty;
694
695
31.0k
  mxPushUndefined();
696
697
31.0k
  anInstance = fxNewSlot(the);
698
31.0k
  anInstance->kind = XS_INSTANCE_KIND;
699
31.0k
  anInstance->value.instance.garbage = C_NULL;
700
31.0k
  anInstance->value.instance.prototype = mxObjectPrototype.value.reference;
701
31.0k
  the->stack->value.reference = anInstance;
702
31.0k
  the->stack->kind = XS_REFERENCE_KIND;
703
704
31.0k
  aProperty = anInstance->next = fxNewSlot(the);
705
31.0k
  aProperty->flag = XS_INTERNAL_FLAG;
706
31.0k
  aProperty->kind = XS_HOST_KIND;
707
31.0k
  aProperty->value.host.data = C_NULL;
708
31.0k
  aProperty->value.host.variant.destructor = theDestructor;
709
  
710
31.0k
  return anInstance;
711
31.0k
}
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
62.1k
{
730
62.1k
  txSlot* host = fxCheckHostObject(the, slot);
731
62.1k
  if (host) {
732
62.1k
    if (host->flag & XS_HOST_CHUNK_FLAG)
733
62.1k
      return host->value.host.data;
734
62.1k
    mxSyntaxError("C: xsGetHostChunk: no host data");
735
62.1k
  }
736
62.1k
  mxSyntaxError("C: xsGetHostChunk: not a host object");
737
0
  return NULL;
738
62.1k
}
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
31.0k
{
896
31.0k
  txSlot* host = fxCheckHostObject(the, slot);
897
31.0k
  if (host) {
898
31.0k
    host->flag |= XS_HOST_CHUNK_FLAG;
899
31.0k
    if (theSize) {
900
31.0k
      host->value.host.data = fxNewChunk(the, theSize);
901
31.0k
      if (theValue)
902
31.0k
        c_memcpy(host->value.host.data, theValue, theSize);
903
0
      else
904
0
        c_memset(host->value.host.data, 0, theSize);
905
31.0k
    }
906
0
    else
907
0
      host->value.host.data = NULL;
908
31.0k
    return host->value.host.data;
909
31.0k
  }
910
0
  else
911
0
    mxSyntaxError("C: fxSetHostChunk: not a host object");
912
913
0
  return NULL;
914
31.0k
}
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
31.0k
{
929
31.0k
  txSlot* host = fxCheckHostObject(the, slot);
930
31.0k
  if (host) {
931
31.0k
    host->flag &= ~XS_HOST_HOOKS_FLAG;
932
31.0k
    host->value.host.variant.destructor = theDestructor;
933
31.0k
  }
934
0
  else
935
0
    mxSyntaxError("C: xsSetHostDestructor: not a host object");
936
31.0k
}
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
16.5M
{
953
16.5M
  return fxNewNameC(the, theName);
954
16.5M
}
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
491
{
968
491
  txString string = fxToString(the, theSlot);
969
491
  if (theSlot->kind == XS_STRING_KIND)
970
491
    return fxNewName(the, theSlot);
971
0
  return fxNewNameX(the, string);
972
491
}
973
974
txString fxName(txMachine* the, txID theID)
975
18
{
976
18
  return fxGetKeyName(the, theID);
977
18
}
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
261M
{
990
261M
  txBoolean flag = mxIsReference(stack) ? 1 : 0;
991
261M
  txSlot* instance = (flag) ? stack->value.reference : fxToInstance(the, stack);
992
261M
  txSlot* property = mxBehaviorGetProperty(the, instance, (txID)id, index, XS_ANY);
993
261M
  if (!property) {
994
31.0M
    the->stack = stack;
995
31.0M
    stack->kind = XS_UNDEFINED_KIND;
996
31.0M
  }
997
230M
  else if (property->kind == XS_ACCESSOR_KIND) {
998
44.6M
    txSlot* function = property->value.accessor.getter;
999
44.6M
    if (mxIsFunction(function)) {
1000
44.6M
      txSlot* slot;
1001
44.6M
      the->stack = stack;
1002
44.6M
      mxOverflow(-5);
1003
44.6M
            the->stack -= 5;
1004
44.6M
      slot = the->stack;
1005
44.6M
      mxInitSlotKind(slot++, XS_UNINITIALIZED_KIND);
1006
44.6M
      mxInitSlotKind(slot++, XS_UNINITIALIZED_KIND);
1007
44.6M
      mxInitSlotKind(slot++, XS_UNDEFINED_KIND);
1008
44.6M
      mxInitSlotKind(slot++, XS_UNDEFINED_KIND);
1009
44.6M
      slot->value.reference = function;
1010
44.6M
      mxInitSlotKind(slot++, XS_REFERENCE_KIND);
1011
44.6M
      if (!flag) {
1012
5
        txSlot* primitive = instance->next;
1013
5
        slot->value = primitive->value;
1014
5
        mxInitSlotKind(slot, primitive->kind);
1015
5
      }
1016
44.6M
      mxRunCount(0);
1017
44.6M
    }
1018
11
    else {
1019
11
      the->stack = stack;
1020
11
      stack->kind = XS_UNDEFINED_KIND;
1021
11
    }
1022
44.6M
  }
1023
185M
  else {
1024
185M
    the->stack = stack;
1025
185M
    stack->kind = property->kind;
1026
185M
    stack->value = property->value;
1027
185M
  }
1028
261M
}
1029
1030
void fxGetAt(txMachine* the)
1031
6.85M
{
1032
6.85M
  txSlot* at = fxAt(the, the->stack);
1033
6.85M
  mxPop();
1034
6.85M
  mxGetAll(at->value.at.id, at->value.at.index);
1035
6.85M
}
1036
1037
void fxGetID(txMachine* the, txID id)
1038
142M
{
1039
142M
  mxGetAll(id, 0);
1040
142M
}
1041
1042
void fxGetIndex(txMachine* the, txIndex index)
1043
46.4M
{
1044
46.4M
  mxGetAll(XS_NO_ID, index);
1045
46.4M
}
1046
1047
txBoolean fxHasAll(txMachine* the, txSlot* stack, txID id, txIndex index)
1048
28.6M
{
1049
28.6M
  txSlot* instance = fxToInstance(the, stack);
1050
28.6M
  txBoolean result = mxBehaviorHasProperty(the, instance, id, index);
1051
28.6M
  the->stack = stack;
1052
28.6M
  mxPop();
1053
28.6M
  return result;
1054
28.6M
}
1055
1056
txBoolean fxHasAt(txMachine* the)
1057
13.6M
{
1058
13.6M
  txSlot* at = fxAt(the, the->stack);
1059
13.6M
  return fxHasAll(the, the->stack + 1, at->value.at.id, at->value.at.index);
1060
13.6M
}
1061
1062
txBoolean fxHasID(txMachine* the, txID id)
1063
3.02M
{
1064
3.02M
  return fxHasAll(the, the->stack, id, 0);
1065
3.02M
}
1066
1067
txBoolean fxHasIndex(txMachine* the, txIndex index)
1068
12.0M
{
1069
12.0M
  return fxHasAll(the, the->stack, XS_NO_ID, index);
1070
12.0M
}
1071
1072
void fxSetAll(txMachine* the, txSlot* stack, txID id, txIndex index)
1073
27.4M
{
1074
27.4M
  txSlot* value = stack + 1;
1075
27.4M
  txSlot* instance = fxToInstance(the, stack);
1076
27.4M
  txSlot* property = mxBehaviorSetProperty(the, instance, id, index, XS_ANY);
1077
27.4M
  if (!property)
1078
18
    mxDebugID(XS_TYPE_ERROR, "C: xsSet %s: not extensible", id);
1079
27.4M
  if (property->kind == XS_ACCESSOR_KIND) {
1080
990k
    txSlot* slot;
1081
990k
    txSlot* function = property->value.accessor.setter;
1082
990k
    if (!mxIsFunction(function))
1083
4
      mxDebugID(XS_TYPE_ERROR, "C: xsSet %s: no setter", id);
1084
990k
    the->stack = stack;
1085
990k
    mxOverflow(-5);
1086
990k
    the->stack -= 5;
1087
990k
    slot = the->stack;
1088
990k
    slot->value = value->value;
1089
990k
    mxInitSlotKind(slot++, value->kind);
1090
990k
    mxInitSlotKind(slot++, XS_UNINITIALIZED_KIND);
1091
990k
    mxInitSlotKind(slot++, XS_UNINITIALIZED_KIND);
1092
990k
    slot->value = value->value;
1093
990k
    mxInitSlotKind(slot++, value->kind);
1094
990k
    mxInitSlotKind(slot++, XS_UNDEFINED_KIND);
1095
990k
    slot->value.reference = function;
1096
990k
    mxInitSlotKind(slot++, XS_REFERENCE_KIND);
1097
990k
    slot->value.reference = instance;
1098
990k
    mxInitSlotKind(slot, XS_REFERENCE_KIND);
1099
990k
    mxRunCount(1);
1100
990k
  }
1101
26.4M
  else {
1102
26.4M
    if (property->flag & XS_DONT_SET_FLAG)
1103
16
      mxDebugID(XS_TYPE_ERROR, "C: xsSet %s: not writable", id);
1104
26.4M
    property->kind = value->kind;
1105
26.4M
    property->value = value->value;
1106
26.4M
    the->stack = stack;
1107
26.4M
    mxPop();
1108
26.4M
  }
1109
27.4M
}
1110
1111
void fxSetAt(txMachine* the)
1112
1.69M
{
1113
1.69M
  txSlot* at = fxAt(the, the->stack);
1114
1.69M
  fxSetAll(the, the->stack + 1, at->value.at.id, at->value.at.index);
1115
1.69M
}
1116
1117
void fxSetID(txMachine* the, txID id)
1118
25.5M
{
1119
25.5M
  fxSetAll(the, the->stack, id, 0);
1120
25.5M
}
1121
1122
void fxSetIndex(txMachine* the, txIndex index)
1123
261k
{
1124
261k
  fxSetAll(the, the->stack, XS_NO_ID, index);
1125
261k
}
1126
1127
void fxDeleteAll(txMachine* the, txSlot* stack, txID id, txIndex index)
1128
3.03M
{
1129
3.03M
  txSlot* instance = fxToInstance(the, stack);
1130
3.03M
  if (!mxBehaviorDeleteProperty(the, instance, id, index))
1131
5
    mxDebugID(XS_TYPE_ERROR, "delete %s: not configurable", id);
1132
3.03M
  the->stack = stack;
1133
3.03M
}
1134
1135
void fxDeleteAt(txMachine* the)
1136
2.96M
{
1137
2.96M
  txSlot* at = fxAt(the, the->stack);
1138
2.96M
  fxDeleteAll(the, the->stack + 1, at->value.at.id, at->value.at.index);
1139
2.96M
}
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
72.6k
{
1148
72.6k
  fxDeleteAll(the, the->stack, XS_NO_ID, index);
1149
72.6k
}
1150
1151
void fxDefineAll(txMachine* the, txSlot* stack, txID id, txIndex index, txFlag flag, txFlag mask)
1152
14.9M
{
1153
14.9M
  txSlot* instance = fxToInstance(the, stack);
1154
14.9M
  txSlot* slot = stack + 1;
1155
14.9M
  if (mask & XS_GETTER_FLAG) {
1156
93.2k
    slot->value.accessor.getter = slot->value.reference;
1157
93.2k
    slot->value.accessor.setter = C_NULL;
1158
93.2k
    slot->kind = XS_ACCESSOR_KIND;
1159
93.2k
  }
1160
14.8M
  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
14.9M
  slot->flag = flag & XS_GET_ONLY;
1166
14.9M
  if (!mxBehaviorDefineOwnProperty(the, instance, id, index, slot, mask))
1167
12
    mxTypeError("define %ld: not configurable", id);
1168
14.9M
  the->stack = stack;
1169
14.9M
  mxPop();
1170
14.9M
}
1171
1172
void fxDefineAt(txMachine* the, txFlag flag, txFlag mask)
1173
2.23M
{
1174
2.23M
  txSlot* at = fxAt(the, the->stack);
1175
2.23M
  fxDefineAll(the, the->stack + 1, at->value.at.id, at->value.at.index, flag, mask);
1176
2.23M
}
1177
1178
void fxDefineID(txMachine* the, txID id, txFlag flag, txFlag mask)
1179
352k
{
1180
352k
  fxDefineAll(the, the->stack, id, 0, flag, mask);
1181
352k
}
1182
1183
void fxDefineIndex(txMachine* the, txIndex index, txFlag flag, txFlag mask)
1184
12.3M
{
1185
12.3M
  fxDefineAll(the, the->stack, XS_NO_ID, index, flag, mask);
1186
12.3M
}
1187
1188
void fxCall(txMachine* the)
1189
81.0M
{
1190
  // TARGET
1191
81.0M
  (--the->stack)->next = C_NULL;
1192
81.0M
  mxInitSlotKind(the->stack, XS_UNDEFINED_KIND);
1193
  // RESULT
1194
81.0M
  (--the->stack)->next = C_NULL;
1195
81.0M
  mxInitSlotKind(the->stack, XS_UNDEFINED_KIND);
1196
  // FRAME
1197
81.0M
  (--the->stack)->next = C_NULL;
1198
81.0M
  mxInitSlotKind(the->stack, XS_UNINITIALIZED_KIND);
1199
  // COUNT
1200
81.0M
  (--the->stack)->next = C_NULL;
1201
81.0M
  mxInitSlotKind(the->stack, XS_UNINITIALIZED_KIND);
1202
81.0M
}
1203
1204
void fxCallID(txMachine* the, txID theID)
1205
37.6k
{
1206
37.6k
  mxDub();
1207
37.6k
  mxGetID(theID);
1208
37.6k
  fxCall(the);
1209
37.6k
}
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
3.45M
{
1219
3.45M
  txSlot* constructor = the->stack;
1220
3.45M
  txSlot* slot = constructor - 5;
1221
3.45M
  the->stack = slot;
1222
3.45M
  mxInitSlotKind(slot++, XS_UNINITIALIZED_KIND);
1223
3.45M
  mxInitSlotKind(slot++, XS_UNINITIALIZED_KIND);
1224
3.45M
  mxInitSlotKind(slot++, XS_UNDEFINED_KIND);
1225
3.45M
  slot->value = constructor->value;
1226
3.45M
  mxInitSlotKind(slot++, constructor->kind);
1227
3.45M
  slot->value = constructor->value;
1228
3.45M
  mxInitSlotKind(slot++, constructor->kind);
1229
3.45M
  mxInitSlotKind(slot, XS_UNINITIALIZED_KIND);
1230
3.45M
}
1231
1232
void fxNewID(txMachine* the, txID theID)
1233
31.0k
{
1234
31.0k
  mxGetID(theID);
1235
31.0k
  fxNew(the);
1236
31.0k
}
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.10M
{
1246
2.10M
  fxRunID(the, C_NULL, count);
1247
2.10M
}
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
210k
{
1294
210k
  if (the->scope != the->stack)
1295
0
    mxSyntaxError("C: xsVars: too late");
1296
210k
  mxOverflow(theCount);
1297
210k
  the->scope->value.environment.variable.count = theCount;
1298
451k
  while (theCount) {
1299
241k
    mxPushUndefined();
1300
241k
    theCount--;
1301
241k
  }
1302
210k
}
1303
1304
txInteger fxCheckArg(txMachine* the, txInteger theIndex)
1305
2.79M
{
1306
2.79M
  if ((theIndex < 0) || (mxArgc <= theIndex))
1307
0
    mxSyntaxError("C: xsArg(%ld): invalid index", theIndex);
1308
2.79M
  return theIndex;
1309
2.79M
}
1310
1311
txInteger fxCheckVar(txMachine* the, txInteger theIndex)
1312
1.32M
{
1313
1.32M
  if ((theIndex < 0) || (mxVarc <= theIndex))
1314
0
    mxSyntaxError("C: xsVar(%ld): invalid index", theIndex);
1315
1.32M
  return theIndex;
1316
1.32M
}
1317
1318
void fxOverflow(txMachine* the, txInteger theCount, txString thePath, txInteger theLine)
1319
1.10G
{
1320
1.10G
  txSlot* aStack = the->stack + theCount;
1321
1.10G
  if (theCount < 0) {
1322
1.10G
    if (aStack < the->stackBottom) {
1323
91
      fxReport(the, "JavaScript stack overflow (%ld)!\n", (the->stack - the->stackBottom) + theCount);
1324
91
      fxAbort(the, XS_JAVASCRIPT_STACK_OVERFLOW_EXIT);
1325
91
    }
1326
1.10G
  }
1327
241k
  else if (theCount > 0) {
1328
241k
    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
241k
  }
1333
1.10G
}
1334
1335
/* Exceptions */
1336
1337
void fxThrow(txMachine* the, txString path, txInteger line)
1338
16
{
1339
16
#ifdef mxDebug
1340
16
  fxDebugThrow(the, path, line, "C: xsThrow");
1341
16
#endif
1342
16
  fxJump(the);
1343
16
}
1344
1345
void fxThrowMessage(txMachine* the, txString path, txInteger line, txError error, txString format, ...)
1346
2.06M
{
1347
2.06M
  char message[128] = "";
1348
2.06M
  txSize length = 0;
1349
2.06M
    va_list arguments;
1350
2.06M
    txSlot* slot;
1351
2.06M
    va_start(arguments, format);
1352
2.06M
    c_vsnprintf(message, sizeof(message), format, arguments);
1353
2.06M
    va_end(arguments);
1354
1355
  //??
1356
2.06M
  length = (txSize)c_strlen(message) - 1;
1357
2.06M
  while (length && (0x80 & message[length]))
1358
86
    message[length--] = 0;
1359
    
1360
2.06M
#ifdef mxDebug
1361
2.06M
  if (!the->debugEval) {
1362
2.06M
    c_strncat(message, " (in ", sizeof(message) - mxStringLength(message) - 1);
1363
2.06M
    length = (txSize)c_strlen(message);
1364
2.06M
    fxBufferFrameName(the, message + length, sizeof(message) - length, the->frame, ")");
1365
2.06M
  }
1366
2.06M
#endif
1367
1368
2.06M
  if ((error <= XS_NO_ERROR) || (XS_ERROR_COUNT <= error))
1369
0
    error = XS_UNKNOWN_ERROR;
1370
1371
2.06M
    slot = fxNewSlot(the);
1372
2.06M
    slot->kind = XS_INSTANCE_KIND;
1373
2.06M
    slot->value.instance.garbage = C_NULL;
1374
2.06M
    slot->value.instance.prototype = mxErrorPrototypes(error).value.reference;
1375
2.06M
  mxException.kind = XS_REFERENCE_KIND;
1376
2.06M
  mxException.value.reference = slot;
1377
2.06M
  slot = slot->next = fxNewSlot(the);
1378
2.06M
  slot->flag = XS_INTERNAL_FLAG;
1379
2.06M
  slot->kind = XS_ERROR_KIND;
1380
2.06M
  slot->value.error.info = C_NULL;
1381
2.06M
  slot->value.error.which = error;
1382
2.06M
  if (gxDefaults.captureErrorStack)
1383
2.06M
    gxDefaults.captureErrorStack(the, slot, the->frame);
1384
2.06M
  slot = fxNextStringProperty(the, slot, message, mxID(_message), XS_DONT_ENUM_FLAG);
1385
2.06M
#ifdef mxDebug
1386
2.06M
  fxDebugThrow(the, path, line, "throw");
1387
2.06M
#endif
1388
2.06M
  fxJump(the);
1389
2.06M
}
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
31.0k
{
1406
31.0k
  txMachine* the = (txMachine* )c_calloc(sizeof(txMachine), 1);
1407
31.0k
  if (the) {
1408
31.0k
    txJump aJump;
1409
1410
31.0k
    aJump.nextJump = C_NULL;
1411
31.0k
    aJump.stack = C_NULL;
1412
31.0k
    aJump.scope = C_NULL;
1413
31.0k
    aJump.frame = C_NULL;
1414
31.0k
    aJump.code = C_NULL;
1415
31.0k
    aJump.flag = 0;
1416
31.0k
    the->firstJump = &aJump;
1417
31.0k
    if (c_setjmp(aJump.buffer) == 0) {
1418
31.0k
      txInteger id;
1419
31.0k
      txSlot* slot;
1420
1421
31.0k
      if (gxDefaults.initializeSharedCluster)
1422
31.0k
        gxDefaults.initializeSharedCluster(the);
1423
        
1424
31.0k
      the->context = theContext;
1425
31.0k
      fxCreateMachinePlatform(the);
1426
1427
31.0k
    #ifdef mxDebug
1428
31.0k
      the->name = theName;
1429
31.0k
    #endif
1430
31.0k
      the->profileID = (profileID != XS_NO_ID) ? profileID : mxBaseProfileID;
1431
31.0k
      fxAllocate(the, theCreation);
1432
1433
31.0k
            c_memset(the->nameTable, 0, the->nameModulo * sizeof(txSlot *));
1434
31.0k
      c_memset(the->symbolTable, 0, the->symbolModulo * sizeof(txSlot *));
1435
1436
      /* mxGlobal */
1437
31.0k
      mxPushUndefined();
1438
      /* mxException */
1439
31.0k
      mxPushUndefined();
1440
      /* mxProgram */
1441
31.0k
      mxPushNull();
1442
31.0k
      fxNewProgramInstance(the);
1443
      /* mxHosts */
1444
31.0k
      mxPushUndefined();
1445
      /* mxModuleQueue */
1446
31.0k
      fxNewInstance(the);
1447
      /* mxUnhandledPromises */
1448
31.0k
      fxNewInstance(the);
1449
      /* mxDuringJobs */
1450
31.0k
      fxNewInstance(the);
1451
      /* mxFinalizationRegistries */
1452
31.0k
      fxNewInstance(the);
1453
      /* mxPendingJobs */
1454
31.0k
      fxNewInstance(the);
1455
      /* mxRunningJobs */
1456
31.0k
      fxNewInstance(the);
1457
      /* mxBreakpoints */
1458
31.0k
      mxPushList();
1459
      /* mxHostInspectors */
1460
31.0k
      mxPushList();
1461
      /* mxInstanceInspectors */
1462
31.0k
      mxPushList();
1463
1464
4.53M
      for (id = mxInstanceInspectorsStackIndex + 1; id < mxEmptyCodeStackIndex; id++)
1465
4.50M
        mxPushUndefined();
1466
1467
      /* mxEmptyCode */
1468
31.0k
      mxPushUndefined();
1469
31.0k
      the->stack->value.code.address = (txByte*)gxNoCode;
1470
31.0k
      the->stack->value.code.closures = C_NULL;
1471
31.0k
      the->stack->kind = XS_CODE_X_KIND;  
1472
      /* mxEmptyString */
1473
31.0k
      mxPushStringX("");
1474
      /* mxEmptyRegExp */
1475
31.0k
      mxPushStringX("(?:)");
1476
      /* mxBigIntString */
1477
31.0k
      mxPushStringX("bigint");
1478
      /* mxBooleanString */
1479
31.0k
      mxPushStringX("boolean");
1480
      /* mxDefaultString */
1481
31.0k
      mxPushStringX("default");
1482
      /* mxFunctionString */
1483
31.0k
      mxPushStringX("function");
1484
      /* mxNumberString */
1485
31.0k
      mxPushStringX("number");
1486
      /* mxObjectString */
1487
31.0k
      mxPushStringX("object");
1488
      /* mxStringString */
1489
31.0k
      mxPushStringX("string");
1490
      /* mxSymbolString */
1491
31.0k
      mxPushStringX("symbol");
1492
      /* mxUndefinedString */
1493
31.0k
      mxPushStringX("undefined");
1494
1495
31.0k
      fxBuildKeys(the);
1496
31.0k
      fxBuildGlobal(the);
1497
31.0k
      fxBuildObject(the);
1498
31.0k
      fxBuildFunction(the);
1499
31.0k
      fxBuildGenerator(the);
1500
31.0k
      fxBuildArguments(the);
1501
31.0k
      fxBuildArray(the);
1502
31.0k
      fxBuildString(the);
1503
31.0k
      fxBuildBoolean(the);
1504
31.0k
      fxBuildNumber(the);
1505
31.0k
      fxBuildBigInt(the);
1506
31.0k
      fxBuildDate(the);
1507
31.0k
      fxBuildMath(the);
1508
31.0k
      fxBuildRegExp(the);
1509
31.0k
      fxBuildError(the);
1510
31.0k
      fxBuildJSON(the);
1511
31.0k
      fxBuildDataView(the);
1512
31.0k
      fxBuildAtomics(the);
1513
31.0k
      fxBuildPromise(the);
1514
31.0k
      fxBuildSymbol(the);
1515
31.0k
      fxBuildProxy(the);
1516
31.0k
      fxBuildMapSet(the);
1517
31.0k
      fxBuildModule(the);
1518
      
1519
31.0k
      mxPushUndefined();
1520
31.0k
      mxPush(mxObjectPrototype);
1521
  #ifdef mxLink
1522
      slot = fxLastProperty(the, fxNewObjectInstance(the));
1523
  #else
1524
31.0k
      slot = fxLastProperty(the, fxNewGlobalInstance(the));
1525
31.0k
  #endif
1526
1.92M
      for (id = XS_SYMBOL_ID_COUNT; id < _Infinity; id++)
1527
1.89M
        slot = fxNextSlotProperty(the, slot, &the->stackIntrinsics[-1 - id], mxID(id), XS_DONT_ENUM_FLAG);
1528
124k
      for (; id < _Compartment; id++)
1529
93.2k
        slot = fxNextSlotProperty(the, slot, &the->stackIntrinsics[-1 - id], mxID(id), XS_GET_ONLY);
1530
155k
      for (; id < XS_INTRINSICS_COUNT; id++)
1531
124k
        slot = fxNextSlotProperty(the, slot, &the->stackIntrinsics[-1 - id], mxID(id), XS_DONT_ENUM_FLAG);
1532
31.0k
      slot = fxNextSlotProperty(the, slot, the->stack, mxID(_global), XS_DONT_ENUM_FLAG);
1533
31.0k
      slot = fxNextSlotProperty(the, slot, the->stack, mxID(_globalThis), XS_DONT_ENUM_FLAG);
1534
31.0k
      mxGlobal.value = the->stack->value;
1535
31.0k
      mxGlobal.kind = the->stack->kind;
1536
31.0k
      fxNewInstance(the);
1537
31.0k
      fxNewInstance(the);
1538
31.0k
      mxPushUndefined();
1539
31.0k
      fxNewEnvironmentInstance(the, C_NULL);
1540
31.0k
      mxPushUndefined();
1541
31.0k
      mxPushUndefined();
1542
31.0k
      mxPushUndefined();
1543
31.0k
      mxPushUndefined();
1544
31.0k
      mxPushUndefined();
1545
31.0k
      mxModuleInstanceInternal(mxProgram.value.reference)->value.module.realm = fxNewRealmInstance(the);
1546
31.0k
      mxPop();
1547
1548
31.0k
            the->collectFlag = XS_COLLECTING_FLAG;
1549
      
1550
            /*{
1551
        int c = 32;
1552
        while (--c)
1553
          fxCollectGarbage(the);
1554
      }*/
1555
1556
31.0k
    #ifdef mxDebug
1557
31.0k
      fxLogin(the);
1558
31.0k
    #endif
1559
1560
31.0k
      the->firstJump = C_NULL;
1561
31.0k
    }
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
31.0k
  }
1570
31.0k
  return the;
1571
31.0k
}
1572
1573
void fxDeleteMachine(txMachine* the)
1574
31.0k
{
1575
31.0k
  txSlot* aSlot;
1576
31.0k
#ifndef mxLink
1577
31.0k
  txSlot* bSlot;
1578
31.0k
  txSlot* cSlot;
1579
31.0k
#endif
1580
1581
31.0k
  if (!(the->shared)) {
1582
  #ifdef mxFrequency
1583
    fxReportFrequency(the);
1584
  #endif
1585
31.0k
  #ifdef mxDebug
1586
31.0k
    fxLogout(the);
1587
31.0k
  #endif
1588
31.0k
  }
1589
31.0k
  the->context = C_NULL;
1590
31.0k
  aSlot = the->cRoot;
1591
31.0k
  while (aSlot) {
1592
1
    aSlot->flag |= XS_MARK_FLAG;
1593
1
    aSlot = aSlot->next;
1594
1
  }
1595
31.0k
#ifndef mxLink
1596
31.0k
  aSlot = the->firstHeap;
1597
65.1k
  while (aSlot) {
1598
34.0k
    bSlot = aSlot + 1;
1599
34.0k
    cSlot = aSlot->value.reference;
1600
1.11G
    while (bSlot < cSlot) {
1601
1.11G
      if ((bSlot->kind == XS_HOST_KIND) && (bSlot->value.host.variant.destructor)) {
1602
5.68k
        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
5.68k
        else
1607
5.68k
          (*(bSlot->value.host.variant.destructor))(bSlot->value.host.data);
1608
5.68k
      }
1609
1.11G
      bSlot++;
1610
1.11G
    }
1611
34.0k
    aSlot = aSlot->next;
1612
34.0k
  }
1613
31.0k
#endif
1614
31.0k
  fxDeleteMachinePlatform(the);
1615
31.0k
  if (gxDefaults.terminateSharedCluster)
1616
31.0k
    gxDefaults.terminateSharedCluster(the);
1617
31.0k
  fxFree(the);
1618
31.0k
  c_free(the);
1619
31.0k
}
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
9.31k
{
1831
9.31k
  fxCollect(the, XS_COMPACT_FLAG | XS_COLLECT_KEYS_FLAG);
1832
9.31k
}
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
3
{
1844
3
  txSlot* aHeap;
1845
3
  txSlot* aLimit;
1846
3
  if ((the->stack <= theSlot) && (theSlot < the->stackTop)) {
1847
0
    return;
1848
0
  }
1849
3
  aHeap = the->firstHeap;
1850
6
  while (aHeap) {
1851
3
    aLimit = aHeap->value.reference;
1852
3
    if ((aHeap < theSlot) && (theSlot < aLimit)) {
1853
0
      return;
1854
0
    }
1855
3
    aHeap = aHeap->next;
1856
3
  }
1857
3
  fxForget(the, theSlot);
1858
3
  theSlot->next = the->cRoot;
1859
3
  the->cRoot = theSlot;
1860
3
}
1861
1862
void fxForget(txMachine* the, txSlot* theSlot)
1863
5
{
1864
5
  if (!(theSlot->flag & XS_MARK_FLAG)) {
1865
5
    txSlot* aSlot = the->cRoot;
1866
5
    txSlot** aSlotAddr = &(the->cRoot);
1867
5
    while ((aSlot = *aSlotAddr)) {
1868
2
      if (aSlot == theSlot) {
1869
2
        *aSlotAddr = aSlot->next;
1870
2
        return;
1871
2
      }
1872
0
      aSlotAddr = &(aSlot->next);
1873
0
    }
1874
5
  }
1875
5
}
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
70.4M
{
1892
70.4M
#if defined(mxInstrument) || defined(mxProfile)
1893
70.4M
  if (the->frame == C_NULL)
1894
31.0k
    fxCheckProfiler(the, C_NULL);
1895
70.4M
#endif
1896
70.4M
  mxOverflow(-7);
1897
  /* THIS */
1898
70.4M
  (--the->stack)->next = C_NULL;
1899
70.4M
  mxInitSlotKind(the->stack, XS_UNDEFINED_KIND);
1900
  /* FUNCTION */
1901
70.4M
  (--the->stack)->next = C_NULL;
1902
70.4M
  mxInitSlotKind(the->stack, XS_UNDEFINED_KIND);
1903
  /* TARGET */
1904
70.4M
  (--the->stack)->next = C_NULL;
1905
70.4M
  mxInitSlotKind(the->stack, XS_UNDEFINED_KIND);
1906
  /* RESULT */
1907
70.4M
  (--the->stack)->next = C_NULL;
1908
70.4M
  mxInitSlotKind(the->stack, XS_UNDEFINED_KIND);
1909
  /* FRAME */
1910
70.4M
  (--the->stack)->next = the->frame;
1911
70.4M
  the->stack->ID = XS_NO_ID;
1912
70.4M
  the->stack->flag = XS_C_FLAG;
1913
70.4M
#ifdef mxDebug
1914
70.4M
  if (the->breakOnStartFlag) {
1915
0
    the->breakOnStartFlag = 0;
1916
0
    the->stack->flag |= XS_STEP_INTO_FLAG | XS_STEP_OVER_FLAG;
1917
0
  }
1918
70.4M
  if (the->frame && (the->frame->flag & XS_STEP_INTO_FLAG))
1919
0
    the->stack->flag |= XS_STEP_INTO_FLAG | XS_STEP_OVER_FLAG;
1920
70.4M
#endif
1921
70.4M
  the->stack->kind = XS_FRAME_KIND;
1922
70.4M
  the->stack->value.frame.code = the->code;
1923
70.4M
  the->stack->value.frame.scope = the->scope;
1924
70.4M
  the->frame = the->stack;
1925
  /* COUNT */
1926
70.4M
  (--the->stack)->next = C_NULL;
1927
70.4M
  mxInitSlotKind(the->stack, XS_INTEGER_KIND);
1928
70.4M
  the->stack->value.integer = 0;
1929
  /* VARC */
1930
70.4M
  (--the->stack)->next = C_NULL;
1931
70.4M
  the->stack->ID = XS_NO_ID;
1932
70.4M
  the->stack->flag = XS_NO_FLAG;
1933
70.4M
  the->stack->kind = XS_VAR_KIND;
1934
70.4M
  the->stack->value.environment.variable.count = 0;
1935
70.4M
  the->stack->value.environment.line = 0;
1936
70.4M
  the->scope = the->stack;
1937
70.4M
  the->code = C_NULL;
1938
70.4M
  return the;
1939
70.4M
}
1940
1941
void fxEndHost(txMachine* the)
1942
70.3M
{
1943
70.3M
    if (the->frame->next == C_NULL) {
1944
30.0k
        fxEndJob(the);
1945
30.0k
    }
1946
70.3M
  the->stack = the->frame + 5;
1947
70.3M
  the->scope = the->frame->value.frame.scope;
1948
70.3M
  the->code = the->frame->value.frame.code;
1949
70.3M
  the->frame = the->frame->next;
1950
70.3M
}
1951
1952
void fxEndJob(txMachine* the)
1953
270k
{
1954
270k
  if (gxDefaults.cleanupFinalizationRegistries)
1955
270k
    gxDefaults.cleanupFinalizationRegistries(the);
1956
270k
  if (mxDuringJobs.kind == XS_REFERENCE_KIND)
1957
270k
    mxDuringJobs.value.reference->next = C_NULL;
1958
270k
  fxCheckUnhandledRejections(the, 0);
1959
270k
}
1960
1961
void fxExitToHost(txMachine* the)
1962
1.06k
{
1963
1.06k
  txJump* jump = the->firstJump;
1964
181k
  while (jump->nextJump) {
1965
180k
    txJump* nextJump = jump->nextJump;
1966
180k
    if (jump->flag)
1967
13.0k
      c_free(jump);
1968
180k
    jump = nextJump;
1969
180k
  }
1970
1.06k
  c_longjmp(jump->buffer, 1);
1971
1.06k
}
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