Coverage Report

Created: 2026-10-17 07:25

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