Coverage Report

Created: 2026-08-13 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/moddable/xs/sources/xsFunction.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
static txSlot* fxCheckFunctionInstance(txMachine* the, txSlot* slot);
41
static void fxStepAsync(txMachine* the, txSlot* instance, txFlag status);
42
43
static const txByte gxTailCode[1] = { XS_CODE_RUN_TAIL };
44
45
void fxBuildFunction(txMachine* the)
46
31.3k
{
47
31.3k
  txSlot* slot;
48
31.3k
  txSlot* function;
49
31.3k
  txSlot* constructor;
50
31.3k
  mxPush(mxFunctionPrototype);
51
31.3k
  slot = fxLastProperty(the, the->stack->value.reference);
52
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Function_prototype_apply), 2, mxID(_apply), XS_DONT_ENUM_FLAG);
53
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Function_prototype_bind), 1, mxID(_bind), XS_DONT_ENUM_FLAG);
54
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Function_prototype_call), 1, mxID(_call), XS_DONT_ENUM_FLAG);
55
31.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Function_prototype_toString), 0, mxID(_toString), XS_DONT_ENUM_FLAG);
56
31.3k
    slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Function_prototype_hasInstance), 1, mxID(_Symbol_hasInstance), XS_GET_ONLY);
57
31.3k
  function = mxThrowTypeErrorFunction.value.reference;
58
31.3k
  slot = slot->next = fxNewSlot(the);
59
31.3k
  slot->flag = XS_DONT_ENUM_FLAG;
60
31.3k
  slot->ID = mxID(_arguments);
61
31.3k
  slot->kind = XS_ACCESSOR_KIND;
62
31.3k
  slot->value.accessor.getter = function;
63
31.3k
  slot->value.accessor.setter = function;
64
31.3k
  slot = slot->next = fxNewSlot(the);
65
31.3k
  slot->flag = XS_DONT_ENUM_FLAG;
66
31.3k
  slot->ID = mxID(_caller);
67
31.3k
  slot->kind = XS_ACCESSOR_KIND;
68
31.3k
  slot->value.accessor.getter = function;
69
31.3k
  slot->value.accessor.setter = function;
70
31.3k
  constructor = fxBuildHostConstructor(the, mxCallback(fx_Function), 1, mxID(_Function));
71
31.3k
  mxFunctionConstructor = *the->stack;
72
31.3k
  mxPop();
73
  
74
31.3k
  mxPush(mxFunctionPrototype);
75
31.3k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
76
31.3k
  slot = fxNextStringXProperty(the, slot, "AsyncFunction", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
77
31.3k
  mxAsyncFunctionPrototype = *the->stack;
78
31.3k
  slot = fxBuildHostConstructor(the, mxCallback(fx_AsyncFunction), 1, mxID(_AsyncFunction));
79
31.3k
  slot->value.instance.prototype = constructor;
80
31.3k
  mxPop();
81
31.3k
  slot = mxBehaviorGetProperty(the, mxAsyncFunctionPrototype.value.reference, mxID(_constructor), 0, XS_OWN);
82
31.3k
  slot->flag |= XS_DONT_SET_FLAG;
83
31.3k
}
84
85
void fxCheckCallable(txMachine* the, txSlot* slot)
86
6.49M
{
87
6.49M
  if (fxIsCallable(the, slot))
88
6.49M
    return;
89
6.49M
  mxTypeError("this: not a Function instance");
90
6.49M
}
91
92
txSlot* fxCheckFunctionInstance(txMachine* the, txSlot* slot)
93
2.56M
{
94
2.56M
  if (slot->kind == XS_REFERENCE_KIND) {
95
2.56M
    slot = slot->value.reference;
96
2.56M
    if (fxIsFunction(the, slot))
97
2.56M
      return slot;
98
2.56M
  }
99
2.56M
  mxTypeError("this: not a Function instance");
100
0
  return C_NULL;
101
2.56M
}
102
103
txBoolean fxIsCallable(txMachine* the, txSlot* slot) 
104
32.7M
{
105
32.7M
  if (slot->kind == XS_REFERENCE_KIND)
106
32.7M
    return fxIsFunction(the, slot->value.reference);
107
#if mxHostFunctionPrimitive
108
  if (slot->kind == XS_HOST_FUNCTION_KIND)
109
    return 1;
110
#endif
111
52.2k
  return 0;
112
32.7M
}
113
114
txBoolean fxIsFunction(txMachine* the, txSlot* instance)
115
35.3M
{
116
35.4M
again:
117
35.4M
  if (instance) {
118
35.4M
    txSlot* exotic = instance->next;
119
35.4M
    if (exotic && (exotic->flag & XS_INTERNAL_FLAG)) {
120
35.3M
      if (((exotic->kind == XS_CALLBACK_KIND) || (exotic->kind == XS_CALLBACK_X_KIND) || (exotic->kind == XS_CODE_KIND) || (exotic->kind == XS_CODE_X_KIND)))
121
35.0M
        return 1;
122
246k
      if (exotic->kind == XS_PROXY_KIND) {
123
105k
        instance = exotic->value.proxy.target;
124
105k
        goto again;
125
105k
      }
126
246k
    }
127
35.4M
  }
128
228k
  return 0;
129
35.4M
}
130
131
txSlot* fxNewFunctionInstance(txMachine* the, txID name)
132
5.35M
{
133
5.35M
  txSlot* instance;
134
5.35M
  txSlot* property;
135
136
5.35M
  instance = fxNewObjectInstance(the);
137
5.35M
  instance->flag |= XS_CAN_CALL_FLAG;
138
139
  /* CODE */
140
5.35M
  property = instance->next = fxNewSlot(the);
141
5.35M
  property->flag = XS_INTERNAL_FLAG;
142
5.35M
  property->kind = mxEmptyCode.kind;
143
5.35M
  property->value.code.address = mxEmptyCode.value.code.address;
144
5.35M
  property->value.code.closures = C_NULL;
145
146
  /* HOME */
147
5.35M
  property = property->next = fxNewSlot(the);
148
5.35M
  property->flag = XS_INTERNAL_FLAG;
149
5.35M
  property->kind = XS_HOME_KIND;
150
5.35M
  property->value.home.object = C_NULL;
151
5.35M
  if (the->frame && (mxFunction->kind == XS_REFERENCE_KIND) && (mxIsFunction(mxFunction->value.reference))) {
152
5.29M
    txSlot* slot = mxFunctionInstanceHome(mxFunction->value.reference);
153
5.29M
    property->value.home.module = slot->value.home.module;
154
5.29M
  }
155
56.1k
  else
156
56.1k
    property->value.home.module = C_NULL;
157
    
158
  /* LENGTH */
159
5.35M
  if (gxDefaults.newFunctionLength)
160
5.35M
    gxDefaults.newFunctionLength(the, instance, 0);
161
    
162
  /* NAME */
163
5.35M
  fxRenameFunction(the, instance, name, 0, XS_NO_ID, C_NULL);
164
165
5.35M
  return instance;
166
5.35M
}
167
168
void fxDefaultFunctionPrototype(txMachine* the)
169
1.77M
{
170
1.77M
  txSlot* instance;
171
1.77M
  txSlot* property;
172
1.77M
  instance = the->stack->value.reference;
173
1.77M
  instance->flag |= XS_CAN_CONSTRUCT_FLAG;
174
1.77M
  property = fxLastProperty(the, instance);
175
1.77M
  mxPush(mxObjectPrototype);
176
1.77M
  instance = fxNewObjectInstance(the);
177
1.77M
  fxNextSlotProperty(the, property, the->stack, mxID(_prototype), XS_DONT_DELETE_FLAG | XS_DONT_ENUM_FLAG);
178
1.77M
  mxPop();
179
1.77M
  fxNextSlotProperty(the, instance, the->stack, mxID(_constructor), XS_DONT_ENUM_FLAG);
180
1.77M
}
181
182
txSlot* fxGetPrototypeFromConstructor(txMachine* the, txSlot* defaultPrototype)
183
5.58M
{
184
5.58M
  txSlot* result = the->stack;
185
5.58M
  fxCheckCallable(the, result);
186
5.58M
  mxDub();
187
5.58M
  mxGetID(mxID(_prototype));
188
5.58M
  if (!mxIsReference(the->stack)) {
189
107
    txSlot* instance = result->value.reference;
190
107
    txSlot* proxy = instance->next;
191
107
    if (proxy->kind == XS_PROXY_KIND) {
192
76
      if (!proxy->value.proxy.handler)
193
1
        mxTypeError("(proxy).%s: no handler", fxName(the, mxID(_prototype)));
194
75
      if (!proxy->value.proxy.target)
195
0
        mxTypeError("(proxy).%s: no target", fxName(the, mxID(_prototype)));
196
75
    }
197
106
    the->stack->kind = defaultPrototype->kind;
198
106
    the->stack->value = defaultPrototype->value;
199
106
  }
200
5.58M
  mxPullSlot(result);
201
5.58M
  return result->value.reference;
202
5.58M
}
203
204
#ifndef mxLink
205
txSlot* fxNewFunctionLength(txMachine* the, txSlot* instance, txNumber length)
206
32.7M
{
207
32.7M
  txSlot* property = mxBehaviorGetProperty(the, instance, mxID(_length), 0, XS_OWN);
208
32.7M
  if (!property)
209
27.9M
    property = fxNextIntegerProperty(the, fxLastProperty(the, instance), 0, mxID(_length), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
210
32.7M
  if (length <= 0x7FFFFFFF) {
211
32.7M
    property->kind = XS_INTEGER_KIND;
212
32.7M
    property->value.integer = (txInteger)length;
213
32.7M
  }
214
12
  else {
215
12
    property->kind = XS_NUMBER_KIND;
216
12
    property->value.number = length;
217
12
  }
218
32.7M
  return property;
219
32.7M
}
220
221
txSlot* fxNewFunctionName(txMachine* the, txSlot* instance, txID id, txIndex index, txID former, txString prefix)
222
30.4M
{
223
30.4M
  txSlot* property;
224
30.4M
  property = mxBehaviorGetProperty(the, instance, mxID(_name), 0, XS_OWN);
225
30.4M
  if (property) {
226
2.50M
    if ((property->kind != mxEmptyString.kind) || (property->value.string != mxEmptyString.value.string))
227
499
      return property;
228
2.50M
  }
229
27.9M
  else
230
27.9M
    property = fxNextSlotProperty(the, fxLastProperty(the, instance), &mxEmptyString, mxID(_name), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
231
30.4M
  if (id != XS_NO_ID) {
232
19.6M
    txBoolean adorn;
233
19.6M
    fxPushKeyString(the, id, &adorn);
234
19.6M
    mxPullSlot(property);
235
19.6M
    if (adorn)
236
809k
      fxAdornStringC(the, "[", property, "]");
237
19.6M
  }
238
10.8M
  else if (former) {
239
286k
    char buffer[16];
240
286k
    fxCopyStringC(the, property, fxNumberToString(the, index, buffer, sizeof(buffer), 0, 0)); 
241
286k
  }
242
30.4M
  if (prefix) 
243
2.08M
    fxAdornStringC(the, prefix, property, C_NULL);
244
30.4M
  return property;
245
30.4M
}
246
#endif
247
248
void fxRenameFunction(txMachine* the, txSlot* instance, txID id, txIndex index, txID former, txString prefix)
249
30.4M
{
250
30.4M
  txSlot* property;
251
30.4M
  if (instance->flag & XS_MARK_FLAG)
252
0
    return;
253
30.4M
  property = mxFunctionInstanceCode(instance);
254
30.4M
  if ((property->ID == XS_NO_ID) || (property->ID == former)) {
255
30.4M
    if (id != XS_NO_ID)
256
19.6M
      property->ID = (txID)id;
257
30.4M
  }
258
30.4M
  if (gxDefaults.newFunctionName)
259
30.4M
    property = gxDefaults.newFunctionName(the, instance, id, index, former, prefix);
260
30.4M
}
261
262
void fx_Function(txMachine* the)
263
130k
{ 
264
130k
  txInteger c, i;
265
130k
  txStringStream stream;
266
130k
  txSlot* module = mxFunctionInstanceHome(mxFunction->value.reference)->value.home.module;
267
130k
  if (!module) module = mxProgram.value.reference;
268
  
269
130k
  c = mxArgc;
270
130k
  i = 0;
271
130k
  mxPushStringX("(function anonymous(");
272
156k
  while (c > 1) {
273
25.5k
    fxToString(the, mxArgv(i));
274
25.5k
    fxConcatString(the, the->stack, mxArgv(i));
275
25.5k
    if (c > 2)
276
23.7k
      fxConcatStringC(the, the->stack, ", ");
277
25.5k
    c--;
278
25.5k
    i++;
279
25.5k
  }
280
130k
  fxConcatStringC(the, the->stack, "\n){");
281
130k
  if (c > 0) {
282
121k
    fxToString(the, mxArgv(i));
283
121k
    fxConcatString(the, the->stack, mxArgv(i));
284
121k
  }
285
130k
  fxConcatStringC(the, the->stack, "\n})");
286
130k
  stream.slot = the->stack;
287
130k
  stream.offset = 0;
288
130k
  stream.size = mxStringLength(the->stack->value.string);
289
130k
  fxRunScript(the, fxParseScript(the, &stream, fxStringGetter, mxProgramFlag | mxFunctionFlag), C_NULL, C_NULL, C_NULL, C_NULL, module);
290
130k
  mxPullSlot(mxResult);
291
130k
  if (mxHasTarget && !fxIsSameSlot(the, mxTarget, mxFunction)) {
292
0
    mxPushSlot(mxTarget);
293
0
    fxGetPrototypeFromConstructor(the, &mxFunctionPrototype);
294
0
    mxResult->value.reference->value.instance.prototype = the->stack->value.reference;
295
0
    mxPop();
296
0
  }
297
130k
}
298
299
void fx_Function_prototype_apply(txMachine* the)
300
5.33k
{
301
5.33k
  txIndex c, i;
302
5.33k
  fxCheckCallable(the, mxThis);
303
  /* THIS */
304
5.33k
  if (mxArgc < 1)
305
1
    mxPushUndefined();
306
5.33k
  else
307
5.33k
    mxPushSlot(mxArgv(0));
308
  /* FUNCTION */
309
5.33k
  mxPushSlot(mxThis);
310
5.33k
  mxCall();
311
  /* ARGUMENTS */
312
5.33k
  if ((mxArgc < 2) || (mxArgv(1)->kind == XS_UNDEFINED_KIND) || (mxArgv(1)->kind == XS_NULL_KIND))
313
2.85k
    c = 0;
314
2.47k
  else {
315
2.47k
    if (mxArgv(1)->kind != XS_REFERENCE_KIND)
316
5
      mxTypeError("argArray: not an object");
317
2.47k
    fxToInstance(the, mxArgv(1));
318
2.47k
    mxPushSlot(mxArgv(1));
319
2.47k
    mxGetID(mxID(_length));
320
2.47k
    c = (txIndex)fxToLength(the, the->stack);
321
2.47k
    mxPop();
322
2.51k
    for (i = 0; i < c; i++) {
323
46
      mxPushSlot(mxArgv(1));
324
46
      mxGetIndex(i);
325
46
    }
326
2.47k
  }
327
5.32k
  mxPushInteger(c);
328
5.32k
  the->code = (txByte *)gxTailCode;
329
5.32k
}
330
331
void fx_Function_prototype_bind(txMachine* the)
332
3.94k
{
333
3.94k
  txSlot* function = fxToInstance(the, mxThis);
334
3.94k
  txSlot* instance;
335
3.94k
  txSlot* property;
336
3.94k
  txSlot* arguments;
337
3.94k
  txSlot* argument;
338
3.94k
  txSize c = mxArgc, i;
339
340
3.94k
  fxCheckCallable(the, mxThis);
341
3.94k
  mxPushNull();
342
3.94k
  if (mxBehaviorGetPrototype(the, function, the->stack))
343
345
    instance = fxNewObjectInstance(the);
344
3.60k
  else {
345
3.60k
    mxPop();
346
3.60k
    instance = fxNewInstance(the);
347
3.60k
  }
348
3.94k
  instance->flag |= function->flag & (XS_CAN_CALL_FLAG | XS_CAN_CONSTRUCT_FLAG);
349
3.94k
    mxPullSlot(mxResult);
350
      
351
  /* CODE */
352
3.94k
  property = instance->next = fxNewSlot(the);
353
3.94k
  property->flag = XS_INTERNAL_FLAG;
354
3.94k
  property->kind = XS_CALLBACK_KIND;
355
3.94k
  property->value.callback.address = fx_Function_prototype_bound;
356
3.94k
  property->value.callback.closures = C_NULL;
357
358
  /* HOME */
359
3.94k
  property = property->next = fxNewSlot(the);
360
3.94k
  property->flag = XS_INTERNAL_FLAG;
361
3.94k
  property->kind = XS_HOME_KIND;
362
3.94k
  property->value.home.object = C_NULL;
363
3.94k
  property->value.home.module = C_NULL;
364
365
3.94k
  property = fxNextSlotProperty(the, property, mxThis, mxID(_boundFunction), XS_INTERNAL_FLAG);
366
3.94k
  if (c > 0)
367
300
    property = fxNextSlotProperty(the, property, mxArgv(0), mxID(_boundThis), XS_INTERNAL_FLAG);
368
3.64k
  else
369
3.64k
    property = fxNextUndefinedProperty(the, property, mxID(_boundThis), XS_INTERNAL_FLAG);
370
  
371
3.94k
  if (c > 1) {
372
51
    mxPush(mxArrayPrototype);
373
51
    arguments = fxNewArrayInstance(the);
374
51
    argument = fxLastProperty(the, arguments);
375
128
    for (i = 1; i < c; i++) {
376
77
      argument->next = fxNewSlot(the);
377
77
      argument = argument->next;
378
77
      argument->kind = mxArgv(i)->kind;
379
77
      argument->value = mxArgv(i)->value;
380
77
    }
381
51
    arguments->next->value.array.length = c - 1;
382
51
    fxCacheArray(the, arguments);
383
51
    property = fxNextSlotProperty(the, property, the->stack, mxID(_boundArguments), XS_INTERNAL_FLAG);
384
51
    mxPop();
385
51
  }
386
3.89k
  else {
387
3.89k
    property = fxNextNullProperty(the, property, mxID(_boundArguments), XS_INTERNAL_FLAG);
388
3.89k
  }
389
  
390
3.94k
  if (gxDefaults.newFunctionLength) {
391
345
    txNumber length = 0;
392
345
    mxPushUndefined();
393
345
    if (mxBehaviorGetOwnProperty(the, mxThis->value.reference, mxID(_length), 0, the->stack)) {
394
344
      mxPushSlot(mxThis);
395
344
      mxGetID(mxID(_length));
396
344
      property = the->stack;
397
344
      if (property->kind == XS_INTEGER_KIND) {
398
294
        length = property->value.integer;
399
294
      }
400
50
      else if (property->kind == XS_NUMBER_KIND) {
401
29
        length = property->value.number;
402
29
        if (c_isnan(length))
403
8
          length = 0;
404
21
        else
405
21
          length = c_trunc(length);
406
29
      }
407
344
      if (c > 1)
408
50
        length -= c - 1;
409
344
      if (length < 0)
410
33
        length = 0;
411
344
      mxPop();
412
344
    }
413
345
    mxPop();
414
345
    gxDefaults.newFunctionLength(the, instance, length);
415
345
  }
416
  
417
3.94k
  if (gxDefaults.newFunctionName) {
418
345
    txSize length = 0;
419
345
    txString name;
420
345
    mxPushSlot(mxThis);
421
345
    mxGetID(mxID(_name));
422
345
    if ((the->stack->kind == XS_STRING_KIND) || (the->stack->kind == XS_STRING_X_KIND))
423
344
      length = mxStringLength(the->stack->value.string);
424
345
    property = fxNextSlotProperty(the, fxLastProperty(the, instance), &mxEmptyString, mxID(_name), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
425
345
    name = (txString)fxNewChunk(the, fxAddChunkSizes(the, length, 6 + 1));
426
345
    c_memcpy(name, "bound ", 6);
427
345
    if (length)
428
318
      c_memcpy(name + 6, the->stack->value.string, length);
429
345
    name[6 + length] = 0;
430
345
    property->value.string = name;
431
345
    property->kind = XS_STRING_KIND;
432
345
    mxPop();
433
345
  }
434
3.94k
}
435
436
void fx_Function_prototype_bound(txMachine* the)
437
7.68k
{
438
7.68k
  txSlot* function = fxToInstance(the, mxFunction);
439
7.68k
  txSlot* boundArguments;
440
7.68k
  txInteger c, i;
441
7.68k
  txSlot* argument;
442
  /* TARGET */
443
7.68k
  if (mxHasTarget) {
444
7.52k
    if (fxIsSameSlot(the, mxFunction, mxTarget)) {
445
7.51k
      mxPushSlot(mxFunctionInstanceHome(function)->next);
446
7.51k
    }
447
7
    else
448
7
      mxPushSlot(mxTarget);
449
7.52k
  }
450
  /* THIS */
451
7.68k
  if (!mxHasTarget) {
452
164
    mxPushSlot(mxFunctionInstanceHome(function)->next->next);
453
164
  }
454
7.52k
  else
455
7.52k
    mxPushUninitialized();
456
  /* FUNCTION */
457
7.68k
  mxPushSlot(mxFunctionInstanceHome(function)->next);
458
  /* RESULT */
459
7.68k
  mxPushUndefined();
460
7.68k
  mxPushUninitialized();
461
  /* ARGUMENTS */
462
7.68k
  mxPushSlot(mxFunctionInstanceHome(function)->next->next->next);
463
7.68k
  if (the->stack->kind == XS_REFERENCE_KIND) {
464
14
    boundArguments = fxGetInstance(the, the->stack);
465
14
    mxPop();
466
14
    c = boundArguments->next->value.array.length;
467
14
    argument = boundArguments->next->value.array.address;
468
45
    for (i = 0; i < c; i++) {
469
31
      mxPushSlot(argument);
470
31
      argument++;
471
31
    }
472
14
  }
473
7.67k
  else {
474
7.67k
    mxPop();
475
7.67k
    c = 0;
476
7.67k
  }
477
7.85k
  for (i = 0; i < mxArgc; i++)
478
168
    mxPushSlot(mxArgv(i));
479
7.68k
  if (mxHasTarget) {
480
7.52k
    mxRunCount(c + i);
481
7.52k
    mxPullSlot(mxResult);
482
7.52k
  }
483
164
  else {
484
164
    mxPushInteger(c + i);
485
164
    the->code = (txByte *)gxTailCode;
486
164
  }
487
7.68k
}
488
489
void fx_Function_prototype_call(txMachine* the)
490
906k
{ 
491
906k
  txInteger c, i;
492
906k
  fxCheckCallable(the, mxThis);
493
  /* THIS */
494
906k
  if (mxArgc < 1)
495
46
    mxPushUndefined();
496
906k
  else
497
906k
    mxPushSlot(mxArgv(0));
498
  /* FUNCTION */
499
906k
  mxPushSlot(mxThis);
500
906k
  mxCall();
501
  /* ARGUMENTS */
502
906k
  c = mxArgc;
503
906k
  i = 1;
504
1.48M
  while (i < c) {
505
575k
    mxPushSlot(mxArgv(i));
506
575k
    i++;
507
575k
  }
508
906k
  mxPushInteger(i - 1);
509
906k
  the->code = (txByte *)gxTailCode;
510
906k
}
511
512
void fx_Function_prototype_hasInstance(txMachine* the)
513
167k
{ 
514
167k
  txSlot* function;
515
167k
  txSlot* slot;
516
167k
  txSlot* instance;
517
167k
  txSlot* prototype;
518
167k
  mxResult->kind = XS_BOOLEAN_KIND;
519
167k
  mxResult->value.boolean = 0;
520
167k
  if (!fxIsCallable(the, mxThis))
521
8
    return;
522
167k
  function = fxToInstance(the, mxThis);
523
167k
  if (!function)
524
0
    return;
525
167k
  if (mxIsFunction(function)) {
526
167k
    slot = mxFunctionInstanceHome(function)->next;
527
167k
    if (slot && (slot->flag & XS_INTERNAL_FLAG) && (slot->ID == mxID(_boundFunction))) {
528
1
      if (!fxIsCallable(the, slot))
529
0
        return;
530
1
      function = fxToInstance(the, slot);
531
1
      if (!function)
532
0
        return;
533
1
    }
534
167k
  }
535
167k
  if (mxArgc == 0)
536
2
    return;
537
167k
  instance = fxGetInstance(the, mxArgv(0));
538
167k
  if (!instance)
539
559
    return;
540
166k
  mxPushReference(function);
541
166k
  mxGetID(mxID(_prototype));
542
166k
  prototype = fxGetInstance(the, the->stack);
543
166k
  mxPop();
544
166k
  if (!prototype)
545
17
    mxTypeError("this.prototype: not an object");
546
#if mxAliasInstance
547
  if (prototype->ID) {
548
    txSlot* alias = the->aliasArray[prototype->ID];
549
    if (alias)
550
      prototype = alias;
551
  }
552
#endif
553
166k
  mxPushNull();
554
167k
  while (mxBehaviorGetPrototype(the, instance, the->stack)) {
555
167k
    instance = the->stack->value.reference;
556
167k
    if (instance == prototype) {
557
166k
      mxResult->value.boolean = 1;
558
166k
      break;
559
166k
    }
560
167k
  }
561
166k
  mxPop();
562
166k
}
563
564
void fx_Function_prototype_toString(txMachine* the)
565
2.56M
{ 
566
2.56M
  fxCheckFunctionInstance(the, mxThis);
567
2.56M
  mxPushStringX("function [\"");
568
2.56M
  mxPushSlot(mxThis);
569
2.56M
  mxGetID(mxID(_name));
570
2.56M
  if ((the->stack->kind == XS_STRING_KIND) || (the->stack->kind == XS_STRING_X_KIND))
571
2.56M
    fxConcatString(the, the->stack + 1, the->stack);
572
2.56M
  mxPop();
573
2.56M
  mxPushStringX("\"] (){[native code]}");
574
2.56M
  fxConcatString(the, the->stack + 1, the->stack);
575
2.56M
  mxPop();
576
2.56M
  mxPullSlot(mxResult);
577
2.56M
}
578
579
txSlot* fxNewAsyncInstance(txMachine* the)
580
409k
{
581
409k
  txSlot* instance;
582
409k
  txSlot* property;
583
409k
  txSlot* promise;
584
409k
  txSlot* status;
585
409k
  txSlot* function;
586
409k
  txSlot* home;
587
  
588
409k
  mxPushUndefined();
589
590
409k
  instance = fxNewSlot(the);
591
409k
  instance->kind = XS_INSTANCE_KIND;
592
409k
  instance->value.instance.garbage = C_NULL;
593
409k
  instance->value.instance.prototype = C_NULL;
594
409k
  the->stack->value.reference = instance;
595
409k
  the->stack->kind = XS_REFERENCE_KIND;
596
597
409k
  property = instance->next = fxNewSlot(the);
598
409k
  property->flag = XS_INTERNAL_FLAG;
599
409k
  property->kind = XS_STACK_KIND;
600
409k
  property->ID = XS_NO_ID;
601
409k
  property->value.stack.length = 0;
602
409k
  property->value.stack.address = C_NULL;
603
  
604
409k
    property = fxNextIntegerProperty(the, property, XS_CODE_START_ASYNC, XS_NO_ID, XS_INTERNAL_FLAG);
605
606
409k
  mxPush(mxPromisePrototype);
607
409k
  promise = fxNewPromiseInstance(the);
608
409k
  status = mxPromiseStatus(promise);
609
409k
  status->value.integer = mxPendingStatus;
610
409k
    property = fxNextSlotProperty(the, property, the->stack, XS_NO_ID, XS_INTERNAL_FLAG);
611
409k
  mxPop();
612
  
613
409k
  fxPushPromiseFunctions(the, promise);
614
409k
    property = fxNextSlotProperty(the, property, the->stack + 1, XS_NO_ID, XS_INTERNAL_FLAG);
615
409k
    property = fxNextSlotProperty(the, property, the->stack, XS_NO_ID, XS_INTERNAL_FLAG);
616
409k
  mxPop();
617
409k
  mxPop();
618
  
619
409k
  function = fxNewHostFunction(the, fxResolveAwait, 1, XS_NO_ID, mxResolveAwaitProfileID);
620
409k
  home = mxFunctionInstanceHome(function);
621
409k
  home->value.home.object = instance;
622
409k
    property = fxNextSlotProperty(the, property, the->stack, XS_NO_ID, XS_INTERNAL_FLAG);
623
409k
  mxPop();
624
  
625
409k
  function = fxNewHostFunction(the, fxRejectAwait, 1, XS_NO_ID, mxRejectAwaitProfileID);
626
409k
  home = mxFunctionInstanceHome(function);
627
409k
  home->value.home.object = instance;
628
409k
    property = fxNextSlotProperty(the, property, the->stack, XS_NO_ID, XS_INTERNAL_FLAG);
629
409k
  mxPop();
630
  
631
409k
  return instance;
632
409k
}
633
634
void fxResolveAwait(txMachine* the)
635
88.4k
{
636
88.4k
  txSlot* slot = mxFunctionInstanceHome(mxFunction->value.reference);
637
88.4k
  txSlot* instance = slot->value.home.object;
638
88.4k
  the->scratch.kind = mxArgv(0)->kind;
639
88.4k
  the->scratch.value = mxArgv(0)->value;
640
88.4k
  fxStepAsync(the, instance, XS_NO_STATUS);
641
88.4k
}
642
643
void fxRejectAwait(txMachine* the)
644
3
{
645
3
  txSlot* slot = mxFunctionInstanceHome(mxFunction->value.reference);
646
3
  txSlot* instance = slot->value.home.object;
647
3
  the->scratch.kind = mxArgv(0)->kind;
648
3
  the->scratch.value = mxArgv(0)->value;
649
3
  fxStepAsync(the, instance, XS_THROW_STATUS);
650
3
}
651
652
void fxRunAsync(txMachine* the, txSlot* instance)
653
409k
{
654
409k
  txSlot* promise = instance->next->next->next;
655
409k
  fxBeginHost(the);
656
409k
  the->scratch.kind = XS_UNDEFINED_KIND;
657
409k
  fxStepAsync(the, instance, XS_NO_STATUS);
658
409k
  fxEndHost(the);
659
409k
  mxResult->kind = promise->kind;
660
409k
  mxResult->value = promise->value;
661
409k
}
662
663
void fxStepAsync(txMachine* the, txSlot* instance, txFlag status)
664
497k
{
665
497k
  txSlot* state = instance->next->next;
666
497k
  txSlot* promise = state->next;
667
497k
  txSlot* resolveFunction = promise->next;
668
497k
  txSlot* rejectFunction = resolveFunction->next;
669
497k
  txSlot* resolveAwaitFunction = rejectFunction->next;
670
497k
  txSlot* rejectAwaitFunction = resolveAwaitFunction->next;
671
497k
  txSlot* value;
672
497k
  mxTry(the) {
673
497k
    the->status = status;
674
497k
    state->value.integer = XS_NO_CODE;
675
497k
    fxRunID(the, instance, XS_NO_ID);
676
497k
    value = the->stack;
677
497k
    if (state->value.integer == XS_NO_CODE) {
678
      /* THIS */
679
283k
      mxPushUndefined();
680
      /* FUNCTION */
681
283k
      mxPushSlot(resolveFunction);
682
283k
      mxCall();
683
      /* ARGUMENTS */
684
283k
      mxPushSlot(value);
685
283k
      mxRunCount(1);
686
283k
      mxPop();
687
283k
    }
688
214k
    else {
689
214k
      if (mxIsReference(value) && mxIsPromise(value->value.reference)) {
690
13
        mxDub();
691
13
        mxGetID(mxID(_constructor));
692
13
        if (fxIsSameValue(the, &mxPromiseConstructor, the->stack, 0)) {
693
13
          mxPop();
694
13
          fxPromiseThen(the, value->value.reference, resolveAwaitFunction, rejectAwaitFunction, C_NULL, C_NULL);
695
13
          goto exit;
696
13
        }
697
0
        mxPop();
698
0
      }
699
214k
      mxTemporary(resolveFunction);
700
214k
      mxTemporary(rejectFunction);
701
214k
      mxPush(mxPromiseConstructor);
702
214k
      fxNewPromiseCapability(the, resolveFunction, rejectFunction);
703
#ifdef mxPromisePrint
704
      fprintf(stderr, "fxStepAsync %d\n", the->stack->value.reference->next->ID);
705
#endif
706
214k
      fxPromiseThen(the, the->stack->value.reference, resolveAwaitFunction, rejectAwaitFunction, C_NULL, C_NULL);
707
      /* THIS */
708
214k
      mxPushUndefined();
709
      /* FUNCTION */
710
214k
      mxPushSlot(resolveFunction);
711
214k
      mxCall();
712
      /* ARGUMENTS */
713
214k
      mxPushSlot(value);
714
      /* COUNT */
715
214k
      mxRunCount(1);
716
214k
      mxPop();
717
214k
    }
718
497k
exit:     
719
371k
    mxPop();
720
371k
  }
721
371k
  mxCatch(the) {
722
54.8k
    fxRejectException(the, rejectFunction);
723
54.8k
  }
724
497k
}
725
726
void fx_AsyncFunction(txMachine* the)
727
161
{ 
728
161
  txInteger c, i;
729
161
  txStringStream stream;
730
161
  txSlot* module = mxFunctionInstanceHome(mxFunction->value.reference)->value.home.module;
731
161
  if (!module) module = mxProgram.value.reference;
732
  
733
161
  c = mxArgc;
734
161
  i = 0;
735
161
  mxPushStringX("(async function anonymous(");
736
351
  while (c > 1) {
737
190
    fxToString(the, mxArgv(i));
738
190
    fxConcatString(the, the->stack, mxArgv(i));
739
190
    if (c > 2)
740
35
      fxConcatStringC(the, the->stack, ", ");
741
190
    c--;
742
190
    i++;
743
190
  }
744
161
  fxConcatStringC(the, the->stack, "\n){");
745
161
  if (c > 0) {
746
156
    fxToString(the, mxArgv(i));
747
156
    fxConcatString(the, the->stack, mxArgv(i));
748
156
  }
749
161
  fxConcatStringC(the, the->stack, "\n})");
750
161
  stream.slot = the->stack;
751
161
  stream.offset = 0;
752
161
  stream.size = mxStringLength(the->stack->value.string);
753
161
  fxRunScript(the, fxParseScript(the, &stream, fxStringGetter, mxProgramFlag | mxFunctionFlag), C_NULL, C_NULL, C_NULL, C_NULL, module);
754
161
  mxPullSlot(mxResult);
755
161
  if (mxHasTarget && !fxIsSameSlot(the, mxTarget, mxFunction)) {
756
0
    mxPushSlot(mxTarget);
757
0
    fxGetPrototypeFromConstructor(the, &mxAsyncFunctionPrototype);
758
0
    mxResult->value.reference->value.instance.prototype = the->stack->value.reference;
759
0
    mxPop();
760
0
  }
761
161
}