Coverage Report

Created: 2026-05-30 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/moddable/xs/sources/xsPromise.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016-2023  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 mxPromisePrint 1
41
#ifndef mxReportUnhandledRejections
42
#define mxReportUnhandledRejections 0
43
#endif
44
45
static void fxAddUnhandledRejection(txMachine* the, txSlot* promise);
46
static void fxCombinePromises(txMachine* the, txInteger which);
47
static txSlot* fxNewCombinePromisesFunction(txMachine* the, txInteger which, txSlot* already, txSlot* object);
48
49
enum {
50
  XS_PROMISE_COMBINE_NONE = 0,
51
  XS_PROMISE_COMBINE_FULFILLED = 1,
52
  XS_PROMISE_COMBINE_REJECTED = 2,
53
  XS_PROMISE_COMBINE_SETTLED = 4,
54
};
55
56
void fxBuildPromise(txMachine* the)
57
24.5k
{
58
24.5k
  txSlot* slot;
59
24.5k
  mxPush(mxObjectPrototype);
60
24.5k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
61
24.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Promise_prototype_catch), 1, mxID(_catch), XS_DONT_ENUM_FLAG);
62
24.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Promise_prototype_finally), 1, mxID(_finally_), XS_DONT_ENUM_FLAG);
63
24.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Promise_prototype_then), 2, mxID(_then), XS_DONT_ENUM_FLAG);
64
24.5k
  slot = fxNextStringXProperty(the, slot, "Promise", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
65
24.5k
  mxPromisePrototype = *the->stack;
66
24.5k
  slot = fxBuildHostConstructor(the, mxCallback(fx_Promise), 1, mxID(_Promise));
67
24.5k
  mxPromiseConstructor = *the->stack;
68
24.5k
  slot = fxLastProperty(the, slot);
69
24.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Promise_all), 1, mxID(_all), XS_DONT_ENUM_FLAG);
70
24.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Promise_allSettled), 1, mxID(_allSettled), XS_DONT_ENUM_FLAG);
71
24.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Promise_any), 1, mxID(_any), XS_DONT_ENUM_FLAG);
72
24.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Promise_race), 1, mxID(_race), XS_DONT_ENUM_FLAG);
73
24.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Promise_reject), 1, mxID(_reject), XS_DONT_ENUM_FLAG);
74
24.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Promise_resolve), 1, mxID(_resolve), XS_DONT_ENUM_FLAG);
75
24.5k
#if mxECMAScript2025
76
24.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Promise_try), 1, mxID(_try_), XS_DONT_ENUM_FLAG);
77
24.5k
#endif
78
24.5k
#if mxECMAScript2024
79
24.5k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Promise_withResolvers), 0, mxID(_withResolvers), XS_DONT_ENUM_FLAG);
80
24.5k
#endif
81
24.5k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_species_get), C_NULL, mxID(_Symbol_species), XS_DONT_ENUM_FLAG);
82
24.5k
  mxPop();
83
24.5k
  fxNewHostFunction(the, mxCallback(fxOnRejectedPromise), 1, XS_NO_ID, XS_NO_ID);
84
24.5k
  mxOnRejectedPromiseFunction = *the->stack;
85
24.5k
  mxPop();
86
24.5k
  fxNewHostFunction(the, mxCallback(fxOnResolvedPromise), 1, XS_NO_ID, XS_NO_ID);
87
24.5k
  mxOnResolvedPromiseFunction = *the->stack;
88
24.5k
  mxPop();
89
24.5k
  fxNewHostFunction(the, mxCallback(fxOnThenable), 1, XS_NO_ID, XS_NO_ID);
90
24.5k
  mxOnThenableFunction = *the->stack;
91
24.5k
  mxPop();
92
24.5k
}
93
94
txSlot* fxNewPromiseInstance(txMachine* the)
95
814k
{
96
#ifdef mxPromisePrint
97
  static txID gID = 0;
98
#endif
99
814k
  txSlot* promise;
100
814k
  txSlot* slot;
101
814k
  txSlot* instance;
102
814k
  promise = fxNewSlot(the);
103
814k
  promise->kind = XS_INSTANCE_KIND;
104
814k
  promise->value.instance.garbage = C_NULL;
105
814k
  promise->value.instance.prototype = the->stack->value.reference;
106
814k
  the->stack->kind = XS_REFERENCE_KIND;
107
814k
  the->stack->value.reference = promise;
108
  /* STATUS */
109
814k
  slot = promise->next = fxNewSlot(the);
110
814k
  slot->flag = XS_INTERNAL_FLAG;
111
#ifdef mxPromisePrint
112
  slot->ID = gID++;
113
#endif
114
814k
  slot->kind = XS_PROMISE_KIND;
115
814k
  slot->value.integer = mxUndefinedStatus;
116
  /* THENS */
117
814k
  slot = slot->next = fxNewSlot(the);
118
814k
  slot->flag = XS_INTERNAL_FLAG;
119
814k
  slot->value.reference = instance = fxNewSlot(the);
120
814k
    slot->kind = XS_REFERENCE_KIND;
121
814k
  instance->kind = XS_INSTANCE_KIND;
122
814k
  instance->value.instance.garbage = C_NULL;
123
814k
  instance->value.instance.prototype = C_NULL;
124
  /* RESULT */
125
814k
  slot = slot->next = fxNewSlot(the);
126
814k
  slot->flag = XS_INTERNAL_FLAG;
127
#if mxReportUnhandledRejections
128
  /* ENVIRONMENT */
129
  slot = slot->next = fxNewSlot(the);
130
  slot->flag = XS_INTERNAL_FLAG;
131
  instance = the->frame;
132
  while (instance) {
133
    txSlot* environment = mxFrameToEnvironment(instance);
134
    if (environment->ID != XS_NO_ID) {
135
      slot->ID = environment->ID;
136
      slot->value.environment.line = environment->value.environment.line;
137
      break;
138
    }
139
    instance = instance->next;
140
  }
141
#endif
142
814k
  return promise;
143
814k
}
144
145
txSlot* fxNewPromiseCapability(txMachine* the, txSlot* resolveFunction, txSlot* rejectFunction)
146
393k
{
147
393k
  txSlot* capability;
148
393k
  txSlot* slot;
149
393k
  txSlot* function;
150
393k
  mxNew();
151
393k
  resolveFunction->value.reference = fxNewHostFunction(the, fxNewPromiseCapabilityCallback, 2, XS_NO_ID, mxNewPromiseCapabilityCallbackProfileID);
152
393k
  resolveFunction->kind = XS_REFERENCE_KIND;
153
393k
    mxRunCount(1);
154
393k
    capability = resolveFunction->value.reference;
155
393k
  resolveFunction->kind = XS_UNDEFINED_KIND;
156
393k
  slot = mxFunctionInstanceHome(capability)->value.home.object;
157
393k
  if (!slot)
158
4
    mxTypeError("executor not called");
159
393k
  slot = slot->next;
160
393k
  if (!mxIsReference(slot))
161
10
    mxTypeError("resolve: not an object");
162
393k
  function = slot->value.reference; 
163
393k
  if (!mxIsFunction(function))
164
0
    mxTypeError("resolve: not a function");
165
393k
  resolveFunction->kind = XS_REFERENCE_KIND;
166
393k
  resolveFunction->value.reference = function;
167
393k
  slot = slot->next;
168
393k
  if (!mxIsReference(slot))
169
2
    mxTypeError("reject: not an object");
170
393k
  function = slot->value.reference; 
171
393k
  if (!mxIsFunction(function))
172
0
    mxTypeError("reject: not a function");
173
393k
  rejectFunction->kind = XS_REFERENCE_KIND;
174
393k
  rejectFunction->value.reference = function;
175
393k
  return the->stack->value.reference;
176
393k
}
177
178
void fxNewPromiseCapabilityCallback(txMachine* the)
179
393k
{
180
393k
  txSlot* slot = mxFunctionInstanceHome(mxFunction->value.reference);
181
393k
  txSlot* object = slot->value.home.object;
182
393k
  txSlot* resolveFunction;
183
393k
  txSlot* rejectFunction;
184
393k
  if (object) {
185
47
    resolveFunction = object->next;
186
47
    rejectFunction = resolveFunction->next;
187
47
    if (!mxIsUndefined(resolveFunction) || !mxIsUndefined(rejectFunction))
188
21
      mxTypeError("executor already called");
189
47
  }
190
393k
  else {
191
393k
    object = fxNewInstance(the);
192
393k
    resolveFunction = object->next = fxNewSlot(the);
193
393k
    rejectFunction = resolveFunction->next = fxNewSlot(the);
194
393k
    slot->value.home.object = object;
195
393k
        mxPop();
196
393k
  }
197
393k
  if (mxArgc > 0) {
198
393k
    resolveFunction->kind = mxArgv(0)->kind;
199
393k
    resolveFunction->value = mxArgv(0)->value;
200
393k
  }
201
393k
  if (mxArgc > 1) {
202
393k
    rejectFunction->kind = mxArgv(1)->kind;
203
393k
    rejectFunction->value = mxArgv(1)->value;
204
393k
  }
205
393k
}
206
207
void fxAddUnhandledRejection(txMachine* the, txSlot* promise)
208
108k
{
209
108k
  txSlot* reason = mxPromiseResult(promise);
210
108k
  txSlot* list = &mxUnhandledPromises;
211
108k
  txSlot** address = &list->value.reference->next;
212
108k
  txSlot* slot;
213
111M
  while ((slot = *address)) {
214
111M
    if (slot->value.weakRef.target == promise)
215
0
      break;
216
111M
    mxMeterSome(1);
217
111M
    slot = slot->next;
218
111M
    address = &slot->next;
219
111M
  }
220
108k
  if (!slot) {
221
#ifdef mxPromisePrint
222
    fprintf(stderr, "fxAddUnhandledRejection %d\n", promise->next->ID);
223
#endif
224
108k
    slot = *address = fxNewSlot(the);
225
108k
    slot->kind = XS_WEAK_REF_KIND;
226
108k
    slot->value.weakRef.target = promise;
227
108k
    slot = slot->next = fxNewSlot(the);
228
108k
    slot->kind = reason->kind;
229
108k
    slot->value = reason->value;
230
108k
  }
231
108k
}
232
233
void fxCheckUnhandledRejections(txMachine* the, txBoolean atExit)
234
37.1k
{
235
37.1k
  txSlot* list = &mxUnhandledPromises;
236
37.1k
  txSlot** address = &list->value.reference->next;
237
37.1k
  txSlot* slot;
238
37.1k
  if (atExit) {
239
0
    txIndex count = 0;
240
0
    while ((slot = *address)) {
241
    #if mxReportUnhandledRejections
242
      if (slot->value.weakRef.target == C_NULL) {
243
        fprintf(stderr, "# garbage collected promise\n");
244
      }
245
      else {
246
        txSlot* property = mxPromiseEnvironment(slot->value.weakRef.target);
247
        if (property && property->ID) {
248
          fprintf(stderr, "%s:%d\n", fxGetKeyName(the, property->ID), property->value.environment.line);
249
        }
250
      }
251
    #endif
252
0
      slot = slot->next;
253
0
      *address = slot->next;
254
0
      mxException.value = slot->value;
255
0
      mxException.kind = slot->kind;
256
0
      count++;
257
0
    }
258
0
    if (count > 0)
259
0
      fxAbort(the, XS_UNHANDLED_REJECTION_EXIT);
260
0
  }
261
37.1k
  else {
262
173k
    while ((slot = *address)) {
263
136k
      if (slot->value.weakRef.target == C_NULL) {
264
27
        slot = slot->next;
265
27
        *address = slot->next;
266
27
        mxException.value = slot->value;
267
27
        mxException.kind = slot->kind;
268
27
        fxAbort(the, XS_UNHANDLED_REJECTION_EXIT);
269
27
      }
270
136k
      else {
271
136k
        slot = slot->next;
272
136k
        address = &slot->next;
273
136k
      }
274
136k
    }
275
37.1k
  }
276
37.1k
}
277
278
void fxCombinePromises(txMachine* the, txInteger which)
279
34.8k
{
280
34.8k
  txSlot* stack = the->stack;
281
34.8k
  txSlot* resolveFunction;
282
34.8k
  txSlot* rejectFunction;
283
34.8k
  txSlot* promise;
284
34.8k
  txSlot* object;
285
34.8k
  txSlot* property;
286
34.8k
  txSlot* array;
287
34.8k
  txSlot* already;
288
34.8k
  txSlot* iterator;
289
34.8k
  txSlot* next;
290
34.8k
  txSlot* value;
291
34.8k
  txInteger index;
292
  
293
34.8k
  if (!mxIsReference(mxThis))
294
32
    mxTypeError("this: not an object");
295
34.8k
  mxTemporary(resolveFunction);
296
34.8k
  mxTemporary(rejectFunction);
297
34.8k
  mxPushSlot(mxThis);
298
34.8k
  promise = fxNewPromiseCapability(the, resolveFunction, rejectFunction);
299
34.8k
  mxPullSlot(mxResult);
300
34.8k
  {
301
34.8k
    mxTry(the) {
302
34.7k
      txSlot* resolve = C_NULL;
303
34.7k
      if (which) {
304
34.7k
        object = fxNewInstance(the);
305
34.7k
        property = fxNextIntegerProperty(the, object, 0, XS_NO_ID, XS_NO_FLAG);
306
34.7k
        property = fxNextReferenceProperty(the, property, promise, XS_NO_ID, XS_NO_FLAG);
307
34.7k
        if (which == XS_PROMISE_COMBINE_REJECTED)
308
29.4k
          property = fxNextSlotProperty(the, property, rejectFunction, XS_NO_ID, XS_NO_FLAG);
309
5.29k
        else
310
5.29k
          property = fxNextSlotProperty(the, property, resolveFunction, XS_NO_ID, XS_NO_FLAG);
311
34.7k
        mxPush(mxArrayPrototype);
312
34.7k
        array = fxNewArrayInstance(the);
313
34.7k
        already = array->next;
314
34.7k
        property = fxNextReferenceProperty(the, property, array, XS_NO_ID, XS_NO_FLAG);
315
34.7k
        mxPop();
316
34.7k
      }
317
34.7k
      mxPushSlot(mxThis);
318
34.7k
      mxGetID(mxID(_resolve)); 
319
34.7k
      resolve = the->stack;
320
34.7k
      if (!fxIsCallable(the, resolve))
321
1
        mxTypeError("resolve: not a function");
322
34.7k
      mxTemporary(iterator);
323
34.7k
      mxTemporary(next);
324
34.7k
      fxGetIterator(the, mxArgv(0), iterator, next, 0);
325
34.7k
      index = 0;
326
34.7k
      mxTemporary(value);
327
107k
      while (fxIteratorNext(the, iterator, next, value)) {
328
72.7k
        mxTry(the) {
329
72.7k
          mxPushSlot(mxThis);
330
72.7k
          mxPushSlot(resolve);
331
72.7k
          mxCall();
332
72.7k
          mxPushSlot(value);
333
72.7k
          mxRunCount(1);
334
72.7k
          mxDub();
335
72.7k
          mxGetID(mxID(_then));
336
72.7k
          mxCall();
337
72.7k
          if (which) {
338
72.7k
            already = already->next = fxNewSlot(the);
339
72.7k
            already->kind = XS_UNINITIALIZED_KIND;
340
72.7k
            array->next->value.array.length++;
341
72.7k
          }
342
72.7k
          if (which & XS_PROMISE_COMBINE_SETTLED) {
343
102
            fxNewCombinePromisesFunction(the, which | XS_PROMISE_COMBINE_FULFILLED, already, object);
344
102
            fxNewCombinePromisesFunction(the, which | XS_PROMISE_COMBINE_REJECTED, already, object);
345
102
          }
346
72.6k
          else if (which & XS_PROMISE_COMBINE_FULFILLED) {
347
14.5k
            fxNewCombinePromisesFunction(the, which, already, object);
348
14.5k
            mxPushSlot(rejectFunction);
349
14.5k
          }
350
58.1k
          else if (which & XS_PROMISE_COMBINE_REJECTED) {
351
58.0k
            mxPushSlot(resolveFunction);
352
58.0k
            fxNewCombinePromisesFunction(the, which, already, object);
353
58.0k
          }
354
49
          else {
355
49
            mxPushSlot(resolveFunction);
356
49
            mxPushSlot(rejectFunction);
357
49
          }
358
72.7k
          mxRunCount(2);
359
72.7k
          mxPop();
360
72.7k
          index++;
361
72.7k
        }
362
72.7k
        mxCatch(the) {
363
20
          fxIteratorReturn(the, iterator, 1);
364
20
          fxJump(the);
365
20
        }
366
72.7k
      }
367
34.7k
      if (which) {
368
31.2k
        property = object->next;
369
31.2k
        property->value.integer += index;
370
31.2k
        index = property->value.integer;
371
31.2k
      }
372
34.7k
      if ((index == 0) && (which != XS_PROMISE_COMBINE_NONE)) {
373
325
        mxPushUndefined();
374
325
        if (which == XS_PROMISE_COMBINE_REJECTED)
375
314
          mxPushSlot(rejectFunction);
376
11
        else
377
11
          mxPushSlot(resolveFunction);
378
325
        mxCall();
379
325
        if ((which == XS_PROMISE_COMBINE_SETTLED) || (which == XS_PROMISE_COMBINE_FULFILLED)) {
380
11
          fxCacheArray(the, array);
381
11
          mxPushReference(array);
382
11
        }
383
314
        else if (which == XS_PROMISE_COMBINE_REJECTED) {
384
314
          mxPush(mxAggregateErrorConstructor);
385
314
          mxNew();
386
314
          fxCacheArray(the, array);
387
314
          mxPushReference(array);
388
314
          mxRunCount(1);
389
314
        }
390
0
        else {
391
0
          mxPushUndefined();
392
0
        }
393
325
        mxRunCount(1);
394
325
      }
395
34.7k
    }
396
34.7k
    mxCatch(the) {
397
3.51k
      fxRejectException(the, rejectFunction);
398
3.51k
    }
399
34.8k
  }
400
34.7k
  the->stack = stack;
401
34.7k
}
402
403
void fxCombinePromisesCallback(txMachine* the)
404
29.1k
{
405
29.1k
  txSlot* slot = mxFunctionInstanceHome(mxFunction->value.reference)->value.home.object->next;
406
29.1k
  txInteger which = slot->value.integer;
407
29.1k
  txSlot* instance;
408
29.1k
  txSlot* property;
409
29.1k
  slot = slot->next;
410
29.1k
  if (slot->value.closure->kind != XS_UNINITIALIZED_KIND)
411
2
    return;
412
29.1k
  if (which & XS_PROMISE_COMBINE_SETTLED) {
413
93
    mxPush(mxObjectPrototype);
414
93
    instance = fxNewObjectInstance(the);
415
93
  }
416
29.1k
  if (mxArgc > 0)
417
29.1k
    mxPushSlot(mxArgv(0));
418
0
  else
419
0
    mxPushUndefined();
420
29.1k
  if (which & XS_PROMISE_COMBINE_SETTLED) {
421
93
    property = fxLastProperty(the, instance);
422
93
    if (which & XS_PROMISE_COMBINE_FULFILLED) {
423
43
      property = fxNextStringXProperty(the, property, "fulfilled", mxID(_status), XS_NO_FLAG);
424
43
      property = fxNextSlotProperty(the, property, the->stack, mxID(_value), XS_NO_FLAG);
425
43
    }
426
50
    else {
427
50
      property = fxNextStringXProperty(the, property, "rejected", mxID(_status), XS_NO_FLAG);
428
50
      property = fxNextSlotProperty(the, property, the->stack, mxID(_reason), XS_NO_FLAG);
429
50
    }
430
93
    mxPop();
431
93
  }
432
29.1k
  mxPullSlot(slot->value.closure);
433
29.1k
  slot = slot->next->value.reference->next;
434
29.1k
  slot->value.integer--;
435
29.1k
  if (slot->value.integer == 0) {
436
    /* THIS */
437
1.71k
    slot = slot->next;
438
1.71k
    mxPushSlot(slot);
439
    /* FUNCTION */
440
1.71k
    slot = slot->next;
441
1.71k
    mxPushSlot(slot);
442
1.71k
    mxCall();
443
    /* ARGUMENTS */
444
1.71k
    slot = slot->next;
445
1.71k
    if (which == XS_PROMISE_COMBINE_REJECTED) {
446
3
      mxPush(mxAggregateErrorConstructor);
447
3
      mxNew();
448
3
    }
449
1.71k
    fxCacheArray(the, slot->value.reference);
450
1.71k
    mxPushSlot(slot);
451
1.71k
    if (which == XS_PROMISE_COMBINE_REJECTED) {
452
3
      mxRunCount(1);
453
3
    }
454
    /* COUNT */
455
1.71k
    mxRunCount(1);
456
1.71k
    mxPullSlot(mxResult);
457
1.71k
  }
458
29.1k
}
459
460
txSlot* fxNewCombinePromisesFunction(txMachine* the, txInteger which, txSlot* already, txSlot* object)
461
72.8k
{
462
72.8k
  txSlot* result;
463
72.8k
  txSlot* instance;
464
72.8k
  txSlot* property;
465
72.8k
  result = fxNewHostFunction(the, fxCombinePromisesCallback, 1, XS_NO_ID, mxCombinePromisesCallbackProfileID);
466
72.8k
  instance = fxNewInstance(the);
467
72.8k
  property = fxNextIntegerProperty(the, instance, which, XS_NO_ID, XS_NO_FLAG);
468
72.8k
  property = property->next = fxNewSlot(the);
469
72.8k
  property->kind = XS_CLOSURE_KIND;
470
72.8k
  property->value.closure = already;
471
72.8k
  property = fxNextReferenceProperty(the, property, object, XS_NO_ID, XS_NO_FLAG);
472
72.8k
  property = mxFunctionInstanceHome(result);
473
72.8k
  property->value.home.object = instance;
474
72.8k
  mxPop();
475
72.8k
  return result;
476
72.8k
}
477
478
void fxOnRejectedPromise(txMachine* the)
479
15.4k
{
480
15.4k
  txSlot* reaction = mxThis->value.reference;
481
15.4k
  txSlot* resolveFunction = reaction->next;
482
15.4k
  txSlot* rejectFunction = resolveFunction->next;
483
15.4k
  txSlot* resolveHandler = rejectFunction->next;
484
15.4k
  txSlot* rejectHandler = resolveHandler->next;
485
15.4k
  txSlot* argument = mxArgv(0);
486
15.4k
  txSlot* function = rejectFunction;
487
15.4k
  if (rejectHandler->kind == XS_REFERENCE_KIND) {
488
15.4k
    mxTry(the) {
489
      /* THIS */
490
15.4k
      mxPushUndefined();
491
      /* FUNCTION */
492
15.4k
      mxPushSlot(rejectHandler);
493
15.4k
      mxCall();
494
      /* ARGUMENTS */
495
15.4k
      mxPushSlot(argument);
496
15.4k
      mxRunCount(1);
497
15.4k
      mxPullSlot(argument);
498
15.4k
      function = resolveFunction;
499
15.4k
    }
500
15.4k
    mxCatch(the) {
501
22
      *argument = mxException;
502
22
      mxException = mxUndefined;
503
22
      function = rejectFunction;
504
22
    }
505
15.4k
  }
506
15.4k
    if (function->kind == XS_REFERENCE_KIND) {
507
    /* THIS */
508
15.4k
    mxPushUndefined();
509
    /* FUNCTION */
510
15.4k
    mxPushSlot(function);
511
15.4k
    mxCall();
512
    /* ARGUMENTS */
513
15.4k
    mxPushSlot(argument);
514
15.4k
    mxRunCount(1);
515
15.4k
    mxPop();
516
15.4k
  }
517
15.4k
}
518
519
void fxOnResolvedPromise(txMachine* the)
520
234k
{
521
234k
  txSlot* reaction = mxThis->value.reference;
522
234k
  txSlot* resolveFunction = reaction->next;
523
234k
  txSlot* rejectFunction = resolveFunction->next;
524
234k
  txSlot* resolveHandler = rejectFunction->next;
525
234k
  txSlot* argument = mxArgv(0);
526
234k
  txSlot* function = resolveFunction;
527
234k
  if (resolveHandler->kind == XS_REFERENCE_KIND) {
528
234k
    mxTry(the) {
529
      /* THIS */
530
234k
      mxPushUndefined();
531
      /* FUNCTION */
532
234k
      mxPushSlot(resolveHandler);
533
234k
      mxCall();
534
      /* ARGUMENTS */
535
234k
      mxPushSlot(argument);
536
234k
      mxRunCount(1);
537
234k
      mxPullSlot(argument);
538
234k
    }
539
234k
    mxCatch(the) {
540
70
      *argument = mxException;
541
70
      mxException = mxUndefined;
542
70
      function = rejectFunction;
543
70
    }
544
234k
  }
545
234k
    if (function->kind == XS_REFERENCE_KIND) {
546
    /* THIS */
547
80.6k
    mxPushUndefined();
548
    /* FUNCTION */
549
80.6k
    mxPushSlot(function);
550
80.6k
    mxCall();
551
    /* ARGUMENTS */
552
80.6k
    mxPushSlot(argument);
553
80.6k
    mxRunCount(1);
554
80.6k
    mxPop();
555
80.6k
    }
556
234k
}
557
558
void fxOnThenable(txMachine* the)
559
81.3k
{
560
81.3k
  txSlot* resolveFunction = mxArgv(0);
561
81.3k
  txSlot* rejectFunction = mxArgv(1);
562
81.3k
  txSlot* thenFunction = mxArgv(2);
563
81.3k
  mxTry(the) {
564
    /* THIS */
565
81.3k
    mxPushSlot(mxThis);
566
    /* FUNCTION */
567
81.3k
    mxPushSlot(thenFunction);
568
81.3k
    mxCall();
569
    /* ARGUMENTS */
570
81.3k
    mxPushSlot(resolveFunction);
571
81.3k
    mxPushSlot(rejectFunction);
572
81.3k
    mxRunCount(2);
573
81.3k
    mxPop();
574
81.3k
  }
575
81.3k
  mxCatch(the) {
576
43.6k
    fxRejectException(the, rejectFunction);
577
43.6k
  }
578
81.3k
}
579
580
void fxPromiseThen(txMachine* the, txSlot* promise, txSlot* onFullfilled, txSlot* onRejected, txSlot* resolveFunction, txSlot* rejectFunction)
581
280k
{
582
280k
  txSlot* reaction;
583
280k
  txSlot* slot;
584
280k
  txSlot* status;
585
  
586
280k
  reaction = fxNewInstance(the);
587
280k
  slot = reaction->next = fxNewSlot(the);
588
280k
  slot->flag = XS_INTERNAL_FLAG;
589
280k
  if (resolveFunction) {
590
125k
    slot->kind = resolveFunction->kind;
591
125k
    slot->value = resolveFunction->value;
592
125k
  }
593
280k
  slot = slot->next = fxNewSlot(the);
594
280k
  slot->flag = XS_INTERNAL_FLAG;
595
280k
  if (rejectFunction) {
596
125k
    slot->kind = rejectFunction->kind;
597
125k
    slot->value = rejectFunction->value;
598
125k
  }
599
280k
  slot = slot->next = fxNewSlot(the);
600
280k
  slot->ID = mxID(__onFullfilled_);
601
280k
  if (onFullfilled) {
602
280k
    slot->kind = onFullfilled->kind;
603
280k
    slot->value = onFullfilled->value;
604
280k
  }
605
280k
  slot = slot->next = fxNewSlot(the);
606
280k
  slot->ID = mxID(__onRejected_);
607
280k
  if (onRejected) {
608
279k
    slot->kind = onRejected->kind;
609
279k
    slot->value = onRejected->value;
610
279k
  }
611
280k
  if (resolveFunction) {
612
125k
    slot = slot->next = fxNewSlot(the);
613
125k
    slot->ID = mxID(__result_);
614
125k
    slot->kind = mxResult->kind;
615
125k
    slot->value = mxResult->value;
616
125k
  }
617
    
618
280k
  status = mxPromiseStatus(promise);
619
280k
  if (status->value.integer == mxPendingStatus) {
620
241k
    txSlot** address = &(mxPromiseThens(promise)->value.reference->next);
621
241k
    while ((slot = *address)) 
622
15
      address = &(slot->next);
623
241k
    slot = *address = fxNewSlot(the);
624
241k
    slot->kind = XS_REFERENCE_KIND;
625
241k
    slot->value.reference = reaction;
626
241k
  }
627
38.7k
  else {
628
38.7k
    mxPushReference(reaction);
629
38.7k
    if (status->value.integer == mxFulfilledStatus)
630
37.9k
      mxPush(mxOnResolvedPromiseFunction);
631
798
    else
632
798
      mxPush(mxOnRejectedPromiseFunction);
633
38.7k
    mxCall();
634
38.7k
    slot = mxPromiseResult(promise);
635
38.7k
    mxPushSlot(slot);
636
38.7k
    fxQueueJob(the, 1, promise);
637
38.7k
  }
638
280k
  mxPop(); // reaction
639
280k
}
640
641
void fxPushPromiseFunctions(txMachine* the, txSlot* promise)
642
899k
{
643
899k
  txSlot* resolve;
644
899k
  txSlot* reject;
645
899k
  txSlot* object;
646
899k
  txSlot* slot;
647
899k
  resolve = fxNewHostFunction(the, fxResolvePromise, 1, XS_NO_ID, mxResolvePromiseProfileID);
648
899k
  reject = fxNewHostFunction(the, fxRejectPromise, 1, XS_NO_ID, mxRejectPromiseProfileID);
649
899k
  slot = object = fxNewInstance(the);
650
899k
  slot = object->next = fxNewSlot(the);
651
899k
  slot->kind = XS_BOOLEAN_KIND;
652
899k
  slot->value.boolean = 0;
653
899k
  slot = slot->next = fxNewSlot(the);
654
899k
  slot->kind = XS_REFERENCE_KIND;
655
899k
  slot->value.reference = promise;
656
899k
  slot = mxFunctionInstanceHome(resolve);
657
899k
  slot->value.home.object = object;
658
899k
  slot = mxFunctionInstanceHome(reject);
659
899k
  slot->value.home.object = object;
660
899k
  mxPop();
661
899k
}
662
663
void fxRejectException(txMachine* the, txSlot* rejectFunction)
664
117k
{
665
  /* THIS */
666
117k
  mxPushUndefined();
667
  /* FUNCTION */
668
117k
  mxPushSlot(rejectFunction);
669
117k
  mxCall();
670
  /* ARGUMENTS */
671
117k
  mxPush(mxException);
672
117k
  mxException = mxUndefined;
673
117k
  mxRunCount(1);
674
117k
  mxPop();
675
117k
}
676
677
void fxRejectPromise(txMachine* the)
678
165k
{
679
165k
  txSlot* slot;
680
165k
  txSlot* promise;
681
165k
  txSlot* argument;
682
165k
  txSlot* result;
683
165k
  slot = mxFunctionInstanceHome(mxFunction->value.reference)->value.home.object->next;
684
165k
  if (slot->value.boolean)
685
43.0k
    return;
686
122k
  slot->value.boolean = 1;
687
122k
  mxPushSlot(slot->next);
688
122k
  promise = the->stack->value.reference;
689
122k
  slot->next = C_NULL;
690
122k
  if (mxArgc > 0)
691
122k
    mxPushSlot(mxArgv(0));
692
3
  else
693
3
    mxPushUndefined();
694
122k
  argument = the->stack;
695
#ifdef mxPromisePrint
696
  fprintf(stderr, "fxRejectPromise %d\n", promise->next->ID);
697
#endif
698
122k
  result = mxPromiseResult(promise);
699
122k
  result->kind = argument->kind;
700
122k
  result->value = argument->value;
701
122k
  slot = mxPromiseThens(promise)->value.reference->next;
702
122k
  if (slot) {
703
29.6k
    while (slot) {
704
14.8k
      mxPushReference(slot->value.reference);
705
14.8k
      mxPush(mxOnRejectedPromiseFunction);
706
14.8k
      mxCall();
707
14.8k
      mxPushSlot(argument);
708
14.8k
      fxQueueJob(the, 1, promise);
709
14.8k
      slot = slot->next;
710
14.8k
    }
711
14.8k
    mxPromiseThens(promise)->value.reference->next = C_NULL;
712
14.8k
  }
713
108k
  else {
714
108k
    fxAddUnhandledRejection(the, promise);
715
108k
  }
716
122k
  slot = mxPromiseStatus(promise);
717
122k
  slot->value.integer = mxRejectedStatus;
718
122k
}
719
720
void fxResolvePromise(txMachine* the)
721
628k
{
722
628k
  txSlot* slot;
723
628k
  txSlot* promise;
724
628k
  txSlot* argument;
725
628k
  txSlot* result;
726
628k
  slot = mxFunctionInstanceHome(mxFunction->value.reference)->value.home.object->next;
727
628k
  if (slot->value.boolean)
728
14.1k
    return;
729
614k
  slot->value.boolean = 1;
730
614k
  mxPushSlot(slot->next);
731
614k
  promise = the->stack->value.reference;
732
614k
  slot->next = C_NULL;
733
614k
  if (mxArgc > 0)
734
569k
    mxPushSlot(mxArgv(0));
735
44.9k
  else
736
44.9k
    mxPushUndefined();
737
614k
  argument = the->stack;  
738
#ifdef mxPromisePrint
739
  fprintf(stderr, "fxResolvePromise %d\n", promise->next->ID);
740
#endif
741
614k
  mxTry(the) {
742
614k
    if (mxIsReference(argument)) {
743
160k
      if (argument->value.reference == promise)
744
2
        mxTypeError("promise resolves itself");
745
160k
      mxPushSlot(argument);
746
160k
      mxGetID(mxID(_then));
747
160k
      slot = the->stack;
748
160k
      if (fxIsCallable(the, slot)) {
749
#ifdef mxPromisePrint
750
  fprintf(stderr, "fxResolvePromise then %d\n", promise->next->ID);
751
#endif
752
84.1k
        mxPushSlot(argument);
753
84.1k
        mxPush(mxOnThenableFunction);
754
84.1k
        mxCall();
755
84.1k
        fxPushPromiseFunctions(the, promise);
756
84.1k
        mxPushSlot(slot);
757
84.1k
        fxQueueJob(the, 3, promise);
758
84.1k
        goto bail;
759
84.1k
      }
760
76.4k
      mxPop();
761
76.4k
    }
762
529k
    result = mxPromiseResult(promise);
763
529k
    result->kind = argument->kind;
764
529k
    result->value = argument->value;
765
529k
    slot = mxPromiseThens(promise)->value.reference->next;
766
727k
    while (slot) {
767
197k
      mxPushReference(slot->value.reference);
768
197k
      mxPush(mxOnResolvedPromiseFunction);
769
197k
      mxCall();
770
197k
      mxPushSlot(result);
771
197k
      fxQueueJob(the, 1, promise);
772
197k
      slot = slot->next;
773
197k
    }
774
529k
    mxPromiseThens(promise)->value.reference->next = C_NULL;
775
529k
    slot = mxPromiseStatus(promise);
776
529k
    slot->value.integer = mxFulfilledStatus;
777
529k
  }
778
614k
bail:
779
614k
  mxCatch(the) {
780
2
    result = mxPromiseResult(promise);
781
2
    result->kind = mxException.kind;
782
2
    result->value = mxException.value;
783
2
    mxException = mxUndefined;
784
2
    slot = mxPromiseThens(promise)->value.reference->next;
785
2
    if (slot) {
786
2
      while (slot) {
787
1
        mxPushReference(slot->value.reference);
788
1
        mxPush(mxOnRejectedPromiseFunction);
789
1
        mxCall();
790
1
        mxPushSlot(result);
791
1
        fxQueueJob(the, 1, promise);
792
1
        slot = slot->next;
793
1
      }
794
1
      mxPromiseThens(promise)->value.reference->next = C_NULL;
795
1
    }
796
1
    else {
797
1
      fxAddUnhandledRejection(the, promise);
798
1
    }
799
2
    slot = mxPromiseStatus(promise);
800
2
    slot->value.integer = mxRejectedStatus;
801
2
  }
802
614k
}
803
804
void fx_Promise(txMachine* the)
805
433k
{
806
433k
  txSlot* stack = the->stack;
807
433k
  txSlot* promise;
808
433k
  txSlot* argument;
809
433k
  txSlot* status;
810
433k
  txSlot* resolveFunction;
811
433k
  txSlot* rejectFunction;
812
433k
  if (!mxHasTarget)
813
6
    mxTypeError("call: Promise");
814
433k
  if (mxArgc < 1)
815
1
    mxTypeError("no executor");
816
433k
  argument = mxArgv(0);
817
433k
  if (!fxIsCallable(the, argument))
818
10
    mxTypeError("executor: not a function");
819
433k
  mxPushSlot(mxTarget);
820
433k
  fxGetPrototypeFromConstructor(the, &mxPromisePrototype);
821
433k
  promise = fxNewPromiseInstance(the);
822
#ifdef mxPromisePrint
823
  fprintf(stderr, "fx_Promise %d\n", promise->next->ID);
824
#endif
825
433k
  mxPullSlot(mxResult);
826
433k
  status = mxPromiseStatus(promise);
827
433k
  status->value.integer = mxPendingStatus;
828
433k
  fxPushPromiseFunctions(the, promise);
829
433k
  resolveFunction = the->stack + 1;
830
433k
  rejectFunction = the->stack;
831
433k
  {
832
433k
    mxTry(the) {
833
      /* THIS */
834
433k
      mxPushUndefined();
835
      /* FUNCTION */
836
433k
      mxPushSlot(argument);
837
433k
      mxCall();
838
      /* ARGUMENTS */
839
433k
      mxPushSlot(resolveFunction);
840
433k
      mxPushSlot(rejectFunction);
841
433k
      mxRunCount(2);
842
433k
    }
843
433k
    mxCatch(the) {
844
19
      fxRejectException(the, rejectFunction);
845
19
    }
846
433k
  }
847
433k
  the->stack = stack;
848
433k
}
849
850
void fx_Promise_all(txMachine* the)
851
5.28k
{
852
5.28k
  fxCombinePromises(the, XS_PROMISE_COMBINE_FULFILLED);
853
5.28k
}
854
855
void fx_Promise_allSettled(txMachine* the)
856
41
{
857
41
  fxCombinePromises(the, XS_PROMISE_COMBINE_SETTLED);
858
41
}
859
860
void fx_Promise_any(txMachine* the)
861
29.4k
{
862
29.4k
  fxCombinePromises(the, XS_PROMISE_COMBINE_REJECTED);
863
29.4k
}
864
865
void fx_Promise_race(txMachine* the)
866
51
{
867
51
  fxCombinePromises(the, XS_PROMISE_COMBINE_NONE);
868
51
}
869
870
void fx_Promise_reject(txMachine* the)
871
658
{
872
658
  txSlot* resolveFunction;
873
658
  txSlot* rejectFunction;
874
875
658
  if (!mxIsReference(mxThis))
876
12
    mxTypeError("this: not an object");
877
646
  mxTemporary(resolveFunction);
878
646
  mxTemporary(rejectFunction);
879
646
  mxPushSlot(mxThis);
880
646
  fxNewPromiseCapability(the, resolveFunction, rejectFunction);
881
646
  mxPullSlot(mxResult);
882
  /* THIS */
883
646
  mxPushUndefined();
884
  /* FUNCTION */
885
646
  mxPushSlot(rejectFunction);
886
646
  mxCall();
887
  /* ARGUMENTS */
888
646
  if (mxArgc > 0)
889
640
    mxPushSlot(mxArgv(0));
890
6
  else
891
6
    mxPushUndefined();
892
646
  mxRunCount(1);
893
646
  mxPop();
894
646
}
895
896
void fx_Promise_resolve(txMachine* the)
897
74.5k
{
898
74.5k
  if (!mxIsReference(mxThis))
899
9
    mxTypeError("this: not an object");
900
74.4k
  mxPushUndefined();
901
74.4k
  mxPushSlot(mxThis);
902
74.4k
  if (mxArgc > 0)
903
74.4k
    mxPushSlot(mxArgv(0));
904
8
  else
905
8
    mxPushUndefined();
906
74.4k
  fx_Promise_resolveAux(the);   
907
74.4k
  mxPop();
908
74.4k
  mxPop();
909
74.4k
  mxPullSlot(mxResult);
910
74.4k
}
911
912
void fx_Promise_resolveAux(txMachine* the)
913
74.5k
{
914
74.5k
  txSlot* argument = the->stack;
915
74.5k
  txSlot* constructor = the->stack + 1;
916
74.5k
  txSlot* result = the->stack + 2;
917
74.5k
  txSlot* resolveFunction;
918
74.5k
  txSlot* rejectFunction;
919
74.5k
  if (mxIsReference(argument)) {
920
58.3k
    txSlot* promise = argument->value.reference;
921
58.3k
    if (mxIsPromise(promise)) {
922
327
      mxPushReference(promise);
923
327
      mxGetID(mxID(_constructor));
924
327
      if (fxIsSameValue(the, constructor, the->stack, 0)) {
925
319
        *result = *argument;
926
319
          mxPop();
927
319
        return;
928
319
      }
929
8
      mxPop();
930
8
    }
931
58.3k
  }
932
74.2k
  mxTemporary(resolveFunction);
933
74.2k
  mxTemporary(rejectFunction);
934
74.2k
  mxPushSlot(constructor);
935
74.2k
  fxNewPromiseCapability(the, resolveFunction, rejectFunction);
936
74.2k
  *result = *the->stack;
937
74.2k
    mxPop();
938
  /* THIS */
939
74.2k
  mxPushUndefined();
940
  /* FUNCTION */
941
74.2k
  mxPushSlot(resolveFunction);
942
74.2k
  mxCall();
943
  /* ARGUMENTS */
944
74.2k
  mxPushSlot(argument);
945
  /* COUNT */
946
74.2k
  mxRunCount(1);
947
74.2k
  mxPop();
948
74.2k
    mxPop(); // rejectFunction
949
74.2k
    mxPop(); // resolveFunction
950
74.2k
}
951
952
#if mxECMAScript2025
953
void fx_Promise_try(txMachine* the)
954
1.19k
{
955
1.19k
  txSlot* stack = the->stack;
956
1.19k
  txSlot* resolveFunction;
957
1.19k
  txSlot* rejectFunction;
958
1.19k
  if (!mxIsReference(mxThis))
959
12
    mxTypeError("this: not an object");
960
1.18k
  mxTemporary(resolveFunction);
961
1.18k
  mxTemporary(rejectFunction);
962
1.18k
  mxPushSlot(mxThis);
963
1.18k
  fxNewPromiseCapability(the, resolveFunction, rejectFunction);
964
1.18k
  mxPullSlot(mxResult);
965
1.18k
  {
966
1.18k
    mxTry(the) {
967
1.18k
      txInteger c = mxArgc, i;
968
1.18k
      txSlot* value;
969
      /* THIS */
970
1.18k
      mxPushUndefined();
971
      /* FUNCTION */
972
1.18k
      if (c > 0)
973
1.11k
        mxPushSlot(mxArgv(0));
974
65
      else
975
65
        mxPushUndefined();
976
1.18k
      mxCall();
977
      /* ARGUMENTS */
978
1.18k
      for (i = 1; i < c; i++)
979
0
        mxPushSlot(mxArgv(i));
980
1.18k
      if (c > 0)
981
1.11k
        mxRunCount(c - 1);
982
65
      else
983
65
        mxRunCount(0);
984
1.18k
      value = the->stack;
985
      /* THIS */
986
1.18k
      mxPushUndefined();
987
      /* FUNCTION */
988
1.18k
      mxPushSlot(resolveFunction);
989
1.18k
      mxCall();
990
      /* ARGUMENTS */
991
1.18k
      mxPushSlot(value);
992
      /* COUNT */
993
1.18k
      mxRunCount(1);
994
1.18k
    }
995
1.18k
    mxCatch(the) {
996
1.18k
      fxRejectException(the, rejectFunction);
997
1.18k
    }
998
1.18k
  }
999
1.18k
  the->stack = stack;
1000
1.18k
}
1001
#endif
1002
1003
#if mxECMAScript2024
1004
void fx_Promise_withResolvers(txMachine* the)
1005
10
{
1006
10
  txSlot* resolveFunction;
1007
10
  txSlot* rejectFunction;
1008
10
  txSlot* promise;
1009
10
  txSlot* slot;
1010
10
  mxTemporary(resolveFunction);
1011
10
  mxTemporary(rejectFunction);
1012
10
  mxPushSlot(mxThis);
1013
10
  fxNewPromiseCapability(the, resolveFunction, rejectFunction);
1014
10
  promise = the->stack;
1015
10
  mxPush(mxObjectPrototype);
1016
10
  slot = fxNewObjectInstance(the);
1017
10
  mxPullSlot(mxResult);
1018
10
  slot = fxLastProperty(the, slot);
1019
10
  slot = fxNextSlotProperty(the, slot, promise, mxID(_promise), XS_NO_FLAG);
1020
10
  slot = fxNextSlotProperty(the, slot, resolveFunction, mxID(_resolve), XS_NO_FLAG);
1021
10
  slot = fxNextSlotProperty(the, slot, rejectFunction, mxID(_reject), XS_NO_FLAG);
1022
10
  mxPop();
1023
10
  mxPop();
1024
10
  mxPop();
1025
10
}
1026
#endif
1027
1028
void fx_Promise_prototype_catch(txMachine* the)
1029
46
{
1030
46
  mxPushSlot(mxThis);
1031
46
  mxDub();
1032
46
  mxGetID(mxID(_then));
1033
46
  mxCall();
1034
46
  mxPushUndefined();
1035
46
  if (mxArgc > 0) 
1036
29
    mxPushSlot(mxArgv(0));
1037
17
  else
1038
17
    mxPushUndefined();
1039
46
  mxRunCount(2);
1040
46
  mxPullSlot(mxResult);
1041
46
}
1042
1043
#if 0
1044
void fx_Promise_prototype_dumpAux(txMachine* the, txSlot* promise, txInteger c)
1045
{
1046
  txInteger i;
1047
  txSlot* reference;
1048
  for (i = 0; i < c; i++)
1049
    fprintf(stderr, "\t");
1050
  fprintf(stderr, "promise %d\n", promise->next->ID);
1051
  reference = mxPromiseThens(promise)->value.reference->next;
1052
    c++;
1053
  while (reference) {
1054
    fx_Promise_prototype_dumpAux(the, reference->value.reference, c);
1055
    reference = reference->next;
1056
  }
1057
}
1058
#endif
1059
1060
void fx_Promise_prototype_finally(txMachine* the)
1061
29.1k
{
1062
29.1k
  txSlot* constructor;
1063
29.1k
  if (!mxIsReference(mxThis))
1064
3
    mxTypeError("this: not an object");
1065
29.1k
  mxPushSlot(mxThis);
1066
29.1k
  mxGetID(mxID(_constructor));
1067
29.1k
  fxToSpeciesConstructor(the, &mxPromiseConstructor);
1068
29.1k
  constructor = the->stack;
1069
  
1070
29.1k
  mxPushSlot(mxThis);
1071
29.1k
  mxDub();
1072
29.1k
  mxGetID(mxID(_then));
1073
29.1k
  mxCall();
1074
29.1k
  if (mxArgc > 0) {
1075
29.1k
    if (mxIsReference(mxArgv(0)) && mxIsCallable(mxArgv(0)->value.reference)) {
1076
29.1k
      txSlot* function = fxNewHostFunction(the, fx_Promise_prototype_finallyAux, 1, XS_NO_ID, mx_Promise_prototype_finallyAuxProfileID);
1077
29.1k
      txSlot* object = fxNewInstance(the);
1078
29.1k
      txSlot* slot = object->next = fxNewSlot(the);
1079
29.1k
      slot->kind = XS_REFERENCE_KIND;
1080
29.1k
      slot->value.reference = constructor->value.reference;
1081
29.1k
      slot = slot->next = fxNewSlot(the);
1082
29.1k
      slot->kind = XS_REFERENCE_KIND;
1083
29.1k
      slot->value.reference = mxArgv(0)->value.reference;
1084
29.1k
      slot = slot->next = fxNewSlot(the);
1085
29.1k
      slot->kind = XS_BOOLEAN_KIND;
1086
29.1k
      slot->value.boolean = 1;
1087
29.1k
      slot = mxFunctionInstanceHome(function);
1088
29.1k
      slot->value.home.object = object;
1089
29.1k
      mxPop();
1090
      
1091
29.1k
      function = fxNewHostFunction(the, fx_Promise_prototype_finallyAux, 1, XS_NO_ID, mx_Promise_prototype_finallyAuxProfileID);
1092
29.1k
      object = fxNewInstance(the);
1093
29.1k
      slot = object->next = fxNewSlot(the);
1094
29.1k
      slot->kind = XS_REFERENCE_KIND;
1095
29.1k
      slot->value.reference = constructor->value.reference;
1096
29.1k
      slot = slot->next = fxNewSlot(the);
1097
29.1k
      slot->kind = XS_REFERENCE_KIND;
1098
29.1k
      slot->value.reference = mxArgv(0)->value.reference;
1099
29.1k
      slot = slot->next = fxNewSlot(the);
1100
29.1k
      slot->kind = XS_BOOLEAN_KIND;
1101
29.1k
      slot->value.boolean = 0;
1102
29.1k
      slot = mxFunctionInstanceHome(function);
1103
29.1k
      slot->value.home.object = object;
1104
29.1k
      mxPop();
1105
29.1k
    }
1106
2
    else {
1107
2
      mxPushSlot(mxArgv(0));
1108
2
      mxPushSlot(mxArgv(0));
1109
2
    }
1110
29.1k
  }
1111
2
  else {
1112
2
    mxPushUndefined();
1113
2
    mxPushUndefined();
1114
2
  }
1115
29.1k
  mxRunCount(2);
1116
29.1k
  mxPullSlot(mxResult);
1117
29.1k
}
1118
1119
void fx_Promise_prototype_finallyAux(txMachine* the)
1120
53
{
1121
53
  txSlot* object = mxFunctionInstanceHome(mxFunction->value.reference)->value.home.object;
1122
53
  txSlot* constructor = object->next;
1123
53
  txSlot* onFinally = constructor->next;
1124
53
  txSlot* success = onFinally->next;
1125
53
  txSlot* argument;
1126
53
  txSlot* function;
1127
53
  txSlot* slot;
1128
53
  txSlot* home;
1129
  
1130
53
  {
1131
53
    mxTry(the) {
1132
53
      mxPushUndefined();
1133
53
      mxPushSlot(onFinally);
1134
53
      mxCall();
1135
53
      mxRunCount(0);
1136
53
    }
1137
53
    mxCatch(the) {
1138
13
      mxArgv(0)->kind = mxException.kind;
1139
13
      mxArgv(0)->value = mxException.value;
1140
13
      success->value.boolean = 0;
1141
13
      mxPush(mxException);
1142
13
      mxException = mxUndefined;
1143
13
    }
1144
53
  }
1145
53
  argument = the->stack;
1146
  
1147
53
  mxPushUndefined();
1148
53
  mxPushSlot(constructor);
1149
53
  mxPushSlot(argument);
1150
53
  fx_Promise_resolveAux(the);
1151
53
  mxPop();
1152
53
  mxPop();
1153
53
  mxDub();
1154
53
  mxGetID(mxID(_then));
1155
53
  mxCall();
1156
  
1157
53
  if (success->value.boolean)
1158
20
    function = fxNewHostFunction(the, fx_Promise_prototype_finallyReturn, 0, XS_NO_ID, mx_Promise_prototype_finallyReturnProfileID);
1159
33
  else
1160
33
    function = fxNewHostFunction(the, fx_Promise_prototype_finallyThrow, 0, XS_NO_ID, mx_Promise_prototype_finallyThrowProfileID);
1161
53
  object = fxNewInstance(the);
1162
53
  slot = object->next = fxNewSlot(the);
1163
53
  slot->kind = mxArgv(0)->kind;
1164
53
  slot->value = mxArgv(0)->value;
1165
53
  home = mxFunctionInstanceHome(function);
1166
53
  home->value.home.object = object;
1167
53
  mxPop();
1168
53
  mxRunCount(1);
1169
  
1170
53
  mxPullSlot(mxResult);
1171
53
}
1172
1173
void fx_Promise_prototype_finallyReturn(txMachine* the)
1174
20
{
1175
20
  txSlot* object = mxFunctionInstanceHome(mxFunction->value.reference)->value.home.object;
1176
20
  txSlot* slot = object->next;
1177
20
  mxResult->kind = slot->kind;
1178
20
  mxResult->value = slot->value;
1179
20
}
1180
1181
void fx_Promise_prototype_finallyThrow(txMachine* the)
1182
32
{
1183
32
  txSlot* object = mxFunctionInstanceHome(mxFunction->value.reference)->value.home.object;
1184
32
  txSlot* slot = object->next;
1185
32
  mxException.kind = slot->kind;
1186
32
  mxException.value = slot->value;
1187
32
  fxThrow(the, NULL, 0);
1188
32
}
1189
1190
void fx_Promise_prototype_then(txMachine* the)
1191
125k
{
1192
125k
  txSlot* promise;
1193
125k
  txSlot* onFullfilled = C_NULL;
1194
125k
  txSlot* onRejected = C_NULL;
1195
125k
  txSlot* resolveFunction;
1196
125k
  txSlot* rejectFunction;
1197
1198
125k
  if (!mxIsReference(mxThis))
1199
1
    mxTypeError("this: not an object");
1200
125k
  promise = mxThis->value.reference;
1201
125k
  if (!mxIsPromise(promise))
1202
1
    mxTypeError("this: not a Promise instance");
1203
#ifdef mxPromisePrint
1204
  fprintf(stderr, "fx_Promise_prototype_then %d\n", promise->next->ID);
1205
#endif
1206
1207
125k
  if ((mxArgc > 0) && mxIsReference(mxArgv(0))) {
1208
125k
    onFullfilled = mxArgv(0);
1209
125k
  }
1210
125k
  if ((mxArgc > 1) && mxIsReference(mxArgv(1))) {
1211
125k
    onRejected = mxArgv(1);
1212
125k
  }
1213
    
1214
125k
  mxTemporary(resolveFunction);
1215
125k
  mxTemporary(rejectFunction);
1216
125k
  mxPushSlot(mxThis);
1217
125k
  mxGetID(mxID(_constructor));
1218
125k
  fxToSpeciesConstructor(the, &mxPromiseConstructor);
1219
125k
  fxNewPromiseCapability(the, resolveFunction, rejectFunction);
1220
125k
  mxPullSlot(mxResult);
1221
    
1222
125k
  fxPromiseThen(the, promise, onFullfilled, onRejected, resolveFunction, rejectFunction);
1223
125k
}
1224
1225
void fxQueueJob(txMachine* the, txInteger count, txSlot* promise)
1226
334k
{
1227
334k
  txSlot* slot;
1228
334k
  txSlot* job;
1229
334k
  txSlot* item;
1230
334k
  txSlot* stack;
1231
334k
  txSlot** address;
1232
  
1233
334k
  if (promise) {
1234
334k
    txSlot* list = &mxUnhandledPromises;
1235
334k
    txSlot** address = &list->value.reference->next;
1236
45.0M
    while ((slot = *address)) {
1237
44.6M
      if (slot->value.weakRef.target == promise) {
1238
792
        slot = slot->next;
1239
792
        *address = slot->next;
1240
792
        break;
1241
792
      }
1242
44.6M
      slot = slot->next;
1243
44.6M
      address = &slot->next;
1244
44.6M
    }
1245
#ifdef mxPromisePrint
1246
    fprintf(stderr, "fxQueueJob %d\n", promise->next->ID);
1247
#endif
1248
#ifdef mxInstrument 
1249
  the->promisesSettledCount += 1;
1250
#endif
1251
334k
  }
1252
334k
  if (mxPendingJobs.value.reference->next == NULL) {
1253
67.1k
    fxQueuePromiseJobs(the);
1254
67.1k
  }
1255
334k
  count += 4;
1256
334k
  item = stack = the->stack + count;
1257
334k
  slot = job = fxNewInstance(the);
1258
2.17M
  while (count > 0) {
1259
1.84M
    item--;
1260
1.84M
    slot = slot->next = fxNewSlot(the);
1261
1.84M
    slot->kind = item->kind;
1262
1.84M
    slot->value = item->value;
1263
1.84M
    count--;
1264
1.84M
  }
1265
334k
  address = &(mxPendingJobs.value.reference->next);
1266
126M
  while ((slot = *address)) 
1267
126M
    address = &(slot->next);
1268
334k
  slot = *address = fxNewSlot(the); 
1269
334k
  slot->kind = XS_REFERENCE_KIND;
1270
334k
  slot->value.reference = job;
1271
334k
  the->stack = stack;
1272
334k
}
1273
1274
void fxRunPromiseJobs(txMachine* the)
1275
67.0k
{
1276
67.0k
  txSlot* job;
1277
67.0k
  txSlot* slot;
1278
67.0k
  txInteger count;
1279
  
1280
#ifdef mxPromisePrint
1281
  fprintf(stderr, "\n# fxRunPromiseJobs\n");
1282
#endif
1283
67.0k
  job = mxRunningJobs.value.reference->next = mxPendingJobs.value.reference->next;
1284
67.0k
  mxPendingJobs.value.reference->next = C_NULL;
1285
398k
  while (job) {
1286
331k
    mxTry(the) {
1287
331k
      count = 0;
1288
331k
      slot = job->value.reference->next;
1289
2.15M
      while (slot) {
1290
1.82M
        mxPushSlot(slot);
1291
1.82M
        count++;
1292
1.82M
        slot = slot->next;
1293
1.82M
      }
1294
331k
      mxRunCount(count - 4);
1295
331k
      mxPop();
1296
331k
      if (mxDuringJobs.kind == XS_REFERENCE_KIND)
1297
331k
        mxDuringJobs.value.reference->next = C_NULL;
1298
331k
    }
1299
331k
    mxCatch(the) {
1300
1
      fxAbort(the, XS_UNHANDLED_EXCEPTION_EXIT);
1301
1
    }
1302
331k
    job = job->next;
1303
331k
  }
1304
67.0k
  mxRunningJobs.value.reference->next = C_NULL;
1305
67.0k
}
1306
1307
1308
1309
1310