Coverage Report

Created: 2025-10-10 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/moddable/xs/sources/xsPlatforms.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
#include "xsScript.h"
40
41
/* old programming interface defaults to 0 */
42
43
#ifndef mxUseDefaultMachinePlatform
44
  #define mxUseDefaultMachinePlatform 0
45
#endif
46
#ifndef mxUseDefaultBuildKeys
47
  #define mxUseDefaultBuildKeys 0
48
#endif
49
#ifndef mxUseDefaultChunkAllocation
50
  #define mxUseDefaultChunkAllocation 0
51
#endif
52
#ifndef mxUseDefaultSlotAllocation
53
  #define mxUseDefaultSlotAllocation 0
54
#endif
55
#ifndef mxUseDefaultFindModule
56
  #define mxUseDefaultFindModule 0
57
#endif
58
#ifndef mxUseDefaultLoadModule
59
  #define mxUseDefaultLoadModule 0
60
#endif
61
#ifndef mxUseDefaultParseScript
62
  #define mxUseDefaultParseScript 0
63
#endif
64
#ifndef mxUseDefaultQueuePromiseJobs
65
  #define mxUseDefaultQueuePromiseJobs 0
66
#endif
67
#ifndef mxUseDefaultAbort
68
  #define mxUseDefaultAbort 0
69
#endif
70
#ifndef mxUseDefaultDebug
71
  #define mxUseDefaultDebug 0
72
#endif
73
74
#if mxUseDefaultMachinePlatform
75
76
void fxCreateMachinePlatform(txMachine* the)
77
{
78
}
79
80
void fxDeleteMachinePlatform(txMachine* the)
81
{
82
}
83
84
#endif /* mxUseDefaultMachinePlatform */
85
86
#if mxUseDefaultBuildKeys
87
88
void fxBuildKeys(txMachine* the)
89
21.8k
{
90
21.8k
  int i = 0;
91
21.8k
  {
92
21.8k
    txSlot* key = fxFindKey(the);
93
21.8k
    key->flag = XS_INTERNAL_FLAG | XS_DONT_DELETE_FLAG;
94
21.8k
    i++;
95
21.8k
  }
96
348k
  for (; i < XS_SYMBOL_ID_COUNT; i++) {
97
327k
    txSlot* key = fxFindKey(the);
98
327k
    txSlot* instance = fxNewInstance(the);
99
327k
    txSlot* property = fxNextSymbolProperty(the, instance, i, XS_NO_ID, XS_INTERNAL_FLAG);
100
327k
    fxNextStringXProperty(the, property, gxIDStrings[i], XS_NO_ID, XS_INTERNAL_FLAG);
101
327k
    key->flag = XS_INTERNAL_FLAG | XS_DONT_DELETE_FLAG;
102
327k
    key->kind = XS_REFERENCE_KIND;
103
327k
    key->value.reference = instance;
104
327k
    mxPop();
105
327k
  }
106
11.1M
  for (; i < XS_ID_COUNT; i++) {
107
11.1M
    fxID(the, gxIDStrings[i]);
108
11.1M
  }
109
21.8k
}
110
111
#endif  /* mxUseDefaultBuildKeys */ 
112
113
114
#if mxUseDefaultChunkAllocation
115
116
void* fxAllocateChunks(txMachine* the, txSize theSize)
117
24.6k
{
118
24.6k
  return c_malloc(theSize);
119
24.6k
}
120
121
void fxFreeChunks(txMachine* the, void* theChunks)
122
24.6k
{
123
24.6k
  c_free(theChunks);
124
24.6k
}
125
126
#endif /* mxUseDefaultChunkAllocation */ 
127
128
129
#if mxUseDefaultSlotAllocation
130
131
txSlot* fxAllocateSlots(txMachine* the, txSize theCount)
132
45.4k
{
133
45.4k
  return(txSlot*)c_malloc(theCount * sizeof(txSlot));
134
45.4k
}
135
136
void fxFreeSlots(txMachine* the, void* theSlots)
137
45.4k
{
138
45.4k
  c_free(theSlots);
139
45.4k
}
140
141
#endif /* mxUseDefaultSlotAllocation */ 
142
143
#if mxUseDefaultFindModule
144
145
txID fxFindModule(txMachine* the, txSlot* realm, txID moduleID, txSlot* slot)
146
{
147
  txPreparation* preparation = the->preparation;
148
  char name[C_PATH_MAX];
149
#if MODDEF_XS_TEST
150
  char extension[5] = "";
151
#endif
152
  char buffer[C_PATH_MAX];
153
  txInteger dot = 0;
154
  txInteger i = 0;
155
  txInteger hash = 0;
156
  txString slash;
157
  txString path;
158
  fxToStringBuffer(the, slot, name, sizeof(name));
159
  if (name[0] == '.') {
160
    if (name[1] == '/') {
161
      dot = 1;
162
      i = 1;
163
    }
164
    else if ((name[1] == '.') && (name[2] == '/')) {
165
      dot = 2;
166
      i = 2;
167
      while ((name[i + 1] == '.') && (name[i + 2] == '.') && (name[i + 3] == '/')) {
168
        dot++;
169
        i += 3;
170
      }
171
    }
172
  }
173
  else if (name[0] == '#') {
174
    hash = 1;
175
  }
176
  else if (c_strncmp(name, "moddable:", 9) == 0)
177
    c_memmove(name, name + 9, c_strlen(name) - 8);
178
  
179
#if mxWindows
180
  {
181
    char c;
182
    slash = name;
183
    if (!c_strncmp(name, "xsbug://", 8))
184
      slash += 8;
185
    while ((c = *slash)) {
186
      if (c == '/')
187
        *slash = '\\';
188
      slash++;
189
    }
190
  }
191
#endif
192
  slash = c_strrchr(name, mxSeparator);
193
  if (!slash)
194
    slash = name;
195
  slash = c_strrchr(slash, '.');
196
  if (slash && (!c_strcmp(slash, ".js") || !c_strcmp(slash, ".mjs"))) {
197
#if MODDEF_XS_TEST
198
    c_strcpy(extension, slash);
199
#endif
200
    *slash = 0;
201
  }
202
  if (dot > 0) {
203
    if (moduleID == XS_NO_ID)
204
      return XS_NO_ID;
205
    buffer[0] = mxSeparator;
206
    path = buffer + 1;
207
    c_strcpy(path, fxGetKeyName(the, moduleID));
208
    slash = c_strrchr(buffer, mxSeparator);
209
    if (!slash)
210
      return XS_NO_ID;
211
    *slash = 0;
212
    dot--;
213
    while (dot > 0) {
214
      slash = c_strrchr(buffer, mxSeparator);
215
      if (!slash)
216
        return XS_NO_ID;
217
      *slash = 0;
218
      dot--;
219
    }
220
    if ((c_strlen(buffer) + c_strlen(name + i)) >= sizeof(buffer))
221
      mxRangeError("path too long");
222
    c_strcat(buffer, name + i);
223
  }
224
  else if (hash) {
225
    if (moduleID == XS_NO_ID)
226
      return XS_NO_ID;
227
    path = buffer;
228
    c_strcpy(path, fxGetKeyName(the, moduleID));
229
    slash = c_strchr(buffer, mxSeparator);
230
    if (!slash)
231
      return XS_NO_ID;
232
    if (path[0] == '@') {
233
      slash = c_strchr(slash + 1, mxSeparator);
234
      if (!slash)
235
        return XS_NO_ID;
236
    }
237
    *(slash + 1) = 0;
238
    if ((c_strlen(buffer) + c_strlen(name)) >= sizeof(buffer))
239
      mxRangeError("path too long");
240
    c_strcat(buffer, name);
241
  }
242
  else
243
    path = name;
244
  if (preparation) {
245
    txInteger c = preparation->scriptCount;
246
    txScript* script = preparation->scripts;
247
    size_t size;
248
    if (fxGetArchiveCode(the, the->archive, path, &size))
249
      return fxNewNameC(the, path);
250
    while (c > 0) {
251
      if (!c_strcmp(path, script->path))
252
        return fxNewNameC(the, path);
253
      c--;
254
      script++;
255
    }
256
  }
257
#if MODDEF_XS_TEST
258
  if (!c_strncmp(path, "xsbug://", 8)) {
259
    c_strcat(path, extension);
260
    return fxNewNameC(the, path);
261
  }
262
#endif
263
  return XS_NO_ID;
264
}
265
266
#endif /* mxUseDefaultFindModule */
267
268
#if mxUseDefaultLoadModule
269
270
#if MODDEF_XS_TEST
271
extern void fxDebugImport(txMachine* the, txSlot* module, txString path);
272
#endif
273
274
void fxLoadModule(txMachine* the, txSlot* module, txID moduleID)
275
{
276
  txString path = fxGetKeyName(the, moduleID);
277
  txByte* code;
278
  size_t size;
279
  code = fxGetArchiveCode(the, the->archive, path, &size);
280
  if (code) {
281
    txScript script;
282
    script.callback = NULL;
283
    script.symbolsBuffer = NULL;
284
    script.symbolsSize = 0;
285
    script.codeBuffer = code;
286
    script.codeSize = (txSize)size;
287
    script.hostsBuffer = NULL;
288
    script.hostsSize = 0;
289
    script.path = path;
290
    script.version[0] = XS_MAJOR_VERSION;
291
    script.version[1] = XS_MINOR_VERSION;
292
    script.version[2] = XS_PATCH_VERSION;
293
    script.version[3] = 0;
294
    fxResolveModule(the, module, moduleID, &script, C_NULL, C_NULL);
295
  }
296
  else {
297
    txPreparation* preparation = the->preparation;
298
    if (preparation) {
299
      txInteger c = preparation->scriptCount;
300
      txScript* script = preparation->scripts;
301
      while (c > 0) {
302
        if (!c_strcmp(path, script->path)) {
303
          fxResolveModule(the, module, moduleID, script, C_NULL, C_NULL);
304
          return;
305
        }
306
        c--;
307
        script++;
308
      }
309
    }
310
  }
311
#if MODDEF_XS_TEST
312
  if (!c_strncmp(path, "xsbug://", 8)) {
313
    fxDebugImport(the, module, path);
314
    return;
315
  }
316
#endif
317
}
318
319
#endif  /* mxUseDefaultLoadModule */
320
321
#if mxUseDefaultParseScript
322
323
txScript* fxParseScript(txMachine* the, void* stream, txGetter getter, txUnsigned flags)
324
405k
{
325
405k
  txParser _parser;
326
405k
  txParser* parser = &_parser;
327
405k
  txParserJump jump;
328
405k
  txScript* script = NULL;
329
405k
  fxInitializeParser(parser, the, the->parserBufferSize, the->parserTableModulo);
330
405k
  parser->firstJump = &jump;
331
405k
  if (c_setjmp(jump.jmp_buf) == 0) {
332
405k
    fxParserTree(parser, stream, getter, flags, NULL);
333
405k
#ifdef mxDebug
334
405k
    parser->flags |= mxDebugFlag;
335
405k
    if (!the->debugEval) {
336
405k
      if (!parser->source) {
337
405k
        char tag[16];
338
405k
        parser->flags |= mxDebugFlag;
339
405k
        fxGenerateTag(the, tag, sizeof(tag), C_NULL);
340
405k
        parser->source = fxNewParserSymbol(parser, tag);
341
405k
      }
342
405k
      if (fxIsConnected(the)) {
343
0
        if (getter == fxStringGetter)
344
0
          fxFileEvalString(the, ((txStringStream*)stream)->slot->value.string, parser->source->string);
345
0
        else if (getter == fxStringCGetter)
346
0
          fxFileEvalString(the, ((txStringCStream*)stream)->buffer, parser->source->string);
347
0
      }
348
405k
    }
349
405k
#endif
350
405k
    fxParserHoist(parser);
351
405k
    fxParserBind(parser);
352
405k
    script = fxParserCode(parser);
353
405k
  }
354
#ifdef mxInstrument
355
  if (the->peakParserSize < parser->total)
356
    the->peakParserSize = parser->total;
357
#endif
358
405k
  fxTerminateParser(parser);
359
405k
  return script;
360
405k
}
361
362
#endif  /* mxUseDefaultParseScript */
363
364
#if mxUseDefaultQueuePromiseJobs
365
366
void fxQueuePromiseJobs(txMachine* the)
367
{
368
  mxUnknownError("promise: no queue");
369
}
370
371
#endif  /* mxUseDefaultQueuePromiseJobs */
372
373
#if mxUseDefaultAbort
374
375
void fxAbort(txMachine* the, int status)
376
{
377
  txString fxAbortString(int status);
378
  txString why = fxAbortString(status);
379
#ifdef mxDebug
380
    if (status == XS_DEAD_STRIP_EXIT)  {
381
      if (the->debugEval)
382
        mxUnknownError(why);
383
    }
384
#endif
385
  fprintf(stderr, "Error: %s\n", why);
386
  c_exit(status);
387
}
388
389
#endif  /* mxUseDefaultAbort */
390
391
#ifdef mxDebug
392
393
#if mxUseDefaultDebug
394
395
void fxConnect(txMachine* the)
396
{
397
}
398
399
void fxDisconnect(txMachine* the)
400
{
401
}
402
403
txBoolean fxIsConnected(txMachine* the)
404
{
405
  return 0;
406
}
407
408
txBoolean fxIsReadable(txMachine* the)
409
{
410
  return 0;
411
}
412
413
void fxReceive(txMachine* the)
414
{
415
}
416
417
void fxSend(txMachine* the, txBoolean more)
418
{
419
}
420
421
#endif /* mxUseDefaultDebug */
422
423
#endif
424
425
#if mxWindows || mxMacOSX || mxLinux || mxWasm
426
uint32_t modMilliseconds()
427
0
{
428
0
  c_timeval tv;
429
0
  c_gettimeofday(&tv, NULL);
430
// #if (mxWasm || mxWindows || mxMacOSX)
431
0
  return (uint32_t)(uint64_t)(((double)(tv.tv_sec) * 1000.0) + ((double)(tv.tv_usec) / 1000.0));
432
// #else
433
//  return (uint32_t)(((double)(tv.tv_sec) * 1000.0) + ((double)(tv.tv_usec) / 1000.0));
434
// #endif
435
0
}
436
#endif
437
438
#if mxWindows
439
440
#if _MSC_VER < 1800
441
442
unsigned long c_nan[2]={0xffffffff, 0x7fffffff};
443
unsigned long c_infinity[2]={0x00000000, 0x7ff00000};
444
445
int c_fpclassify(double x)
446
{
447
  int result = FP_NORMAL;
448
  switch (_fpclass(x)) {
449
  case _FPCLASS_SNAN:
450
  case _FPCLASS_QNAN:
451
    result = FP_NAN;
452
    break;
453
  case _FPCLASS_NINF:
454
  case _FPCLASS_PINF:
455
    result = FP_INFINITE;
456
    break;
457
  case _FPCLASS_NZ:
458
  case _FPCLASS_PZ:
459
    result = FP_ZERO;
460
    break;
461
  case _FPCLASS_ND:
462
  case _FPCLASS_PD:
463
    result = FP_SUBNORMAL;
464
    break;
465
  }
466
  return result;
467
}
468
469
#endif /* _MSC_VER < 1800 */
470
471
int c_gettimeofday(c_timeval *tp, struct c_timezone *tzp)
472
{
473
  struct _timeb tb;
474
475
  _ftime(&tb);
476
  if (tp != 0) {
477
    tp->tv_sec = (long)tb.time;
478
    tp->tv_usec = tb.millitm * 1000;
479
  }
480
  if (tzp != 0) {
481
    tzp->tz_minuteswest = tb.timezone;
482
    tzp->tz_dsttime = tb.dstflag;
483
  }
484
  return (0);
485
}
486
487
char *c_realpath(const char *path, char *real)
488
{
489
  if (_fullpath(real, path, C_PATH_MAX) != NULL) {
490
    DWORD attributes = GetFileAttributes(real);
491
    if (attributes != 0xFFFFFFFF) {
492
      return real;
493
    }
494
  }
495
  return C_NULL;
496
}
497
498
#endif