@agoric/xsnap 0.14.3-upgrade-14-dev-c8f9e7b.0 → 0.14.3-upgrade-16-fi-dev-8879538.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/README.md +3 -3
  2. package/api.js +4 -2
  3. package/moddable/modules/data/base64/base64.js +28 -0
  4. package/moddable/modules/data/base64/manifest.json +11 -0
  5. package/moddable/modules/data/base64/modBase64.c +188 -0
  6. package/moddable/modules/data/binaryMessage/BinaryMessage.js +106 -0
  7. package/moddable/modules/data/crc/crc.c +205 -0
  8. package/moddable/modules/data/crc/crc.js +36 -0
  9. package/moddable/modules/data/crc/manifest.json +8 -0
  10. package/moddable/modules/data/hex/hex.js +28 -0
  11. package/moddable/modules/data/hex/manifest.json +11 -0
  12. package/moddable/modules/data/hex/modHex.c +139 -0
  13. package/moddable/modules/data/logical/logical.js +32 -0
  14. package/moddable/modules/data/logical/modLogical.c +98 -0
  15. package/moddable/modules/data/qrcode/manifest.json +9 -0
  16. package/moddable/modules/data/qrcode/qrcode.c +93 -0
  17. package/moddable/modules/data/qrcode/qrcode.js +23 -0
  18. package/moddable/modules/data/qrcode/qrcodegen.c +1025 -0
  19. package/moddable/modules/data/qrcode/qrcodegen.h +267 -0
  20. package/moddable/modules/data/text/decoder/manifest.json +8 -0
  21. package/moddable/modules/data/text/decoder/textdecoder.c +480 -0
  22. package/moddable/modules/data/text/decoder/textdecoder.js +27 -0
  23. package/moddable/modules/data/text/encoder/manifest.json +8 -0
  24. package/moddable/modules/data/text/encoder/textencoder.c +232 -0
  25. package/moddable/modules/data/text/encoder/textencoder.js +24 -0
  26. package/moddable/modules/data/tinyint/tinyint.c +150 -0
  27. package/moddable/modules/data/tinyint/tinyint.js +53 -0
  28. package/moddable/modules/data/url/manifest.json +17 -0
  29. package/moddable/modules/data/url/url.c +1959 -0
  30. package/moddable/modules/data/url/url.js +210 -0
  31. package/moddable/modules/data/wavreader/manifest.json +8 -0
  32. package/moddable/modules/data/wavreader/wavreader.js +128 -0
  33. package/moddable/modules/data/zlib/deflate.c +161 -0
  34. package/moddable/modules/data/zlib/deflate.js +63 -0
  35. package/moddable/modules/data/zlib/inflate.c +145 -0
  36. package/moddable/modules/data/zlib/inflate.js +66 -0
  37. package/moddable/modules/data/zlib/manifest_deflate.json +9 -0
  38. package/moddable/modules/data/zlib/manifest_inflate.json +9 -0
  39. package/moddable/modules/data/zlib/miniz.c +4924 -0
  40. package/moddable/xs/includes/xs.d.ts +73 -0
  41. package/moddable/xs/includes/xs.h +1533 -0
  42. package/moddable/xs/includes/xsmc.h +206 -0
  43. package/moddable/xs/makefiles/lin/makefile +33 -0
  44. package/moddable/xs/makefiles/lin/xsc.mk +118 -0
  45. package/moddable/xs/makefiles/lin/xsid.mk +90 -0
  46. package/moddable/xs/makefiles/lin/xsl.mk +168 -0
  47. package/moddable/xs/makefiles/lin/xst.mk +201 -0
  48. package/moddable/xs/makefiles/mac/makefile +33 -0
  49. package/moddable/xs/makefiles/mac/xsc.mk +130 -0
  50. package/moddable/xs/makefiles/mac/xsid.mk +102 -0
  51. package/moddable/xs/makefiles/mac/xsl.mk +177 -0
  52. package/moddable/xs/makefiles/mac/xst.mk +203 -0
  53. package/moddable/xs/makefiles/mac/xst_no_asan.txt +52 -0
  54. package/moddable/xs/makefiles/win/build.bat +26 -0
  55. package/moddable/xs/makefiles/win/xsc.mak +142 -0
  56. package/moddable/xs/makefiles/win/xsid.mak +113 -0
  57. package/moddable/xs/makefiles/win/xsl.mak +186 -0
  58. package/moddable/xs/makefiles/win/xst.mak +195 -0
  59. package/moddable/xs/platforms/lin_xs.h +99 -0
  60. package/moddable/xs/platforms/mac_xs.h +97 -0
  61. package/moddable/xs/platforms/wasm_xs.h +79 -0
  62. package/moddable/xs/platforms/win_xs.h +104 -0
  63. package/moddable/xs/platforms/xsHost.h +63 -0
  64. package/moddable/xs/platforms/xsPlatform.h +618 -0
  65. package/moddable/xs/sources/xsAPI.c +2555 -0
  66. package/moddable/xs/sources/xsAll.c +294 -0
  67. package/moddable/xs/sources/xsAll.h +2741 -0
  68. package/moddable/xs/sources/xsArguments.c +222 -0
  69. package/moddable/xs/sources/xsArray.c +2657 -0
  70. package/moddable/xs/sources/xsAtomics.c +844 -0
  71. package/moddable/xs/sources/xsBigInt.c +1859 -0
  72. package/moddable/xs/sources/xsBoolean.c +109 -0
  73. package/moddable/xs/sources/xsCode.c +4493 -0
  74. package/moddable/xs/sources/xsCommon.c +1710 -0
  75. package/moddable/xs/sources/xsCommon.h +1142 -0
  76. package/moddable/xs/sources/xsDataView.c +2890 -0
  77. package/moddable/xs/sources/xsDate.c +1541 -0
  78. package/moddable/xs/sources/xsDebug.c +2710 -0
  79. package/moddable/xs/sources/xsDefaults.c +134 -0
  80. package/moddable/xs/sources/xsError.c +353 -0
  81. package/moddable/xs/sources/xsFunction.c +776 -0
  82. package/moddable/xs/sources/xsGenerator.c +865 -0
  83. package/moddable/xs/sources/xsGlobal.c +839 -0
  84. package/moddable/xs/sources/xsJSON.c +1091 -0
  85. package/moddable/xs/sources/xsLexical.c +1969 -0
  86. package/moddable/xs/sources/xsLockdown.c +933 -0
  87. package/moddable/xs/sources/xsMapSet.c +1649 -0
  88. package/moddable/xs/sources/xsMarshall.c +1020 -0
  89. package/moddable/xs/sources/xsMath.c +624 -0
  90. package/moddable/xs/sources/xsMemory.c +1941 -0
  91. package/moddable/xs/sources/xsModule.c +3101 -0
  92. package/moddable/xs/sources/xsNumber.c +560 -0
  93. package/moddable/xs/sources/xsObject.c +1102 -0
  94. package/moddable/xs/sources/xsPlatforms.c +480 -0
  95. package/moddable/xs/sources/xsProfile.c +577 -0
  96. package/moddable/xs/sources/xsPromise.c +1199 -0
  97. package/moddable/xs/sources/xsProperty.c +636 -0
  98. package/moddable/xs/sources/xsProxy.c +1014 -0
  99. package/moddable/xs/sources/xsRegExp.c +1168 -0
  100. package/moddable/xs/sources/xsRun.c +4889 -0
  101. package/moddable/xs/sources/xsScope.c +1293 -0
  102. package/moddable/xs/sources/xsScript.c +288 -0
  103. package/moddable/xs/sources/xsScript.h +1186 -0
  104. package/moddable/xs/sources/xsSnapshot.c +2161 -0
  105. package/moddable/xs/sources/xsSnapshot.h +51 -0
  106. package/moddable/xs/sources/xsSourceMap.c +218 -0
  107. package/moddable/xs/sources/xsString.c +3332 -0
  108. package/moddable/xs/sources/xsSymbol.c +503 -0
  109. package/moddable/xs/sources/xsSyntaxical.c +4193 -0
  110. package/moddable/xs/sources/xsTree.c +1893 -0
  111. package/moddable/xs/sources/xsType.c +1488 -0
  112. package/moddable/xs/sources/xsdtoa.c +6672 -0
  113. package/moddable/xs/sources/xsmc.c +340 -0
  114. package/moddable/xs/sources/xsre.c +7578 -0
  115. package/package.json +35 -20
  116. package/src/avaAssertXS.js +4 -2
  117. package/src/avaHandler.cjs +2 -5
  118. package/src/avaXS.js +7 -8
  119. package/src/build.js +126 -26
  120. package/src/replay.js +0 -3
  121. package/src/xsnap.js +105 -91
  122. package/src/xsrepl.js +2 -3
  123. package/xsnap-native/xsnap/makefiles/lin/makefile +10 -0
  124. package/xsnap-native/xsnap/makefiles/lin/xsnap-worker.mk +153 -0
  125. package/xsnap-native/xsnap/makefiles/lin/xsnap.mk +144 -0
  126. package/xsnap-native/xsnap/makefiles/mac/makefile +10 -0
  127. package/xsnap-native/xsnap/makefiles/mac/xsnap-worker.mk +162 -0
  128. package/xsnap-native/xsnap/makefiles/mac/xsnap.mk +153 -0
  129. package/xsnap-native/xsnap/sources/xsnap-worker.c +996 -0
  130. package/xsnap-native/xsnap/sources/xsnap.c +716 -0
  131. package/xsnap-native/xsnap/sources/xsnap.h +142 -0
  132. package/xsnap-native/xsnap/sources/xsnapPlatform.c +1496 -0
  133. package/xsnap-native/xsnap/sources/xsnapPlatform.h +105 -0
  134. package/CHANGELOG.md +0 -646
@@ -0,0 +1,996 @@
1
+ #include "xsnap.h"
2
+
3
+ // XS heap-snapshot contents depend upon the availability of
4
+ // __has_builtin (e.g. xsRun.c mxCase(XS_CODE_MULTIPLY) , around line
5
+ // 3419): it creates XS_INTEGER_KIND if available, XS_NUMBER_KIND if
6
+ // not. This is not visible from userspace, but breaks snapshot
7
+ // consensus between nodes compiled with e.g. gcc-9 (no __has_builtin,
8
+ // default compiler in Ubuntu-20.04-LTS) and gcc-11 (has it, default
9
+ // in Ubuntu-22.04-LTS). To prohibit variation which might break
10
+ // consensus, insist upon the newer feature, which will force an
11
+ // upgrade of either distro or compiler.
12
+
13
+ #ifndef __has_builtin
14
+ #error "xsnap requires __has_builtin (gcc>=10, e.g. Ubuntu-22.04), see https://github.com/Agoric/agoric-sdk/issues/7829"
15
+ #endif
16
+
17
+ #define SNAPSHOT_SIGNATURE "xsnap 1"
18
+ #ifndef XSNAP_VERSION
19
+ # error "You must define XSNAP_VERSION in the right Makefile"
20
+ #endif
21
+
22
+ #ifndef XSNAP_TEST_RECORD
23
+ #define XSNAP_TEST_RECORD 1
24
+ #endif
25
+
26
+ #if XSNAP_TEST_RECORD
27
+ enum {
28
+ mxTestRecordJS = 1,
29
+ mxTestRecordJSON = 2,
30
+ mxTestRecordParam = 4,
31
+ mxTestRecordReply = 8,
32
+ };
33
+ int gxTestRecordParamIndex = 0;
34
+ int gxTestRecordReplyIndex = 0;
35
+ static void fxTestRecordArgs(int argc, char* argv[]);
36
+ static void fxTestRecord(int flags, void* buffer, size_t length);
37
+ #endif
38
+
39
+ static void xsBuildAgent(xsMachine* the);
40
+ static void xsPrintUsage();
41
+
42
+ // static void xs_clearTimer(xsMachine* the);
43
+ static void xs_currentMeterLimit(xsMachine* the);
44
+ static void xs_gc(xsMachine* the);
45
+ static void xs_issueCommand(xsMachine* the);
46
+ static void xs_performance_now(xsMachine* the);
47
+ static void xs_print(xsMachine* the);
48
+ static void xs_resetMeter(xsMachine* the);
49
+ static void xs_setImmediate(xsMachine* the);
50
+ // static void xs_setInterval(xsMachine* the);
51
+ // static void xs_setTimeout(xsMachine* the);
52
+
53
+ static int fxReadNetString(FILE *inStream, char** dest, size_t* len);
54
+ static char* fxReadNetStringError(int code);
55
+ static int fxWriteOkay(FILE* outStream, xsUnsignedValue meterIndex, xsMachine *the, char* buf, size_t len);
56
+ static int fxWriteNetString(FILE* outStream, char* prefix, char* buf, size_t len);
57
+ static char* fxWriteNetStringError(int code);
58
+
59
+ extern xsIntegerValue fxGetCurrentHeapCount(xsMachine* the);
60
+
61
+ extern void xs_textdecoder(xsMachine *the);
62
+ extern void xs_textdecoder_decode(xsMachine *the);
63
+ extern void xs_textdecoder_get_encoding(xsMachine *the);
64
+ extern void xs_textdecoder_get_ignoreBOM(xsMachine *the);
65
+ extern void xs_textdecoder_get_fatal(xsMachine *the);
66
+
67
+ extern void xs_textencoder(xsMachine *the);
68
+ extern void xs_textencoder_encode(xsMachine *the);
69
+ extern void xs_textencoder_encodeInto(xsMachine *the);
70
+
71
+ extern void modInstallTextDecoder(xsMachine *the);
72
+ extern void modInstallTextEncoder(xsMachine *the);
73
+
74
+ extern void xs_base64_encode(xsMachine *the);
75
+ extern void xs_base64_decode(xsMachine *the);
76
+ extern void modInstallBase64(xsMachine *the);
77
+
78
+ // The order of the callbacks materially affects how they are introduced to
79
+ // code that runs from a snapshot, so must be consistent in the face of
80
+ // upgrade.
81
+ #define mxSnapshotCallbackCount 18
82
+ xsCallback gxSnapshotCallbacks[mxSnapshotCallbackCount] = {
83
+ xs_issueCommand, // 0
84
+ xs_print, // 1
85
+ xs_setImmediate, // 2
86
+ xs_gc, // 3
87
+ xs_performance_now, // 4
88
+ xs_currentMeterLimit, // 5
89
+ xs_resetMeter, // 6
90
+
91
+ xs_textdecoder, // 7
92
+ xs_textdecoder_decode, // 8
93
+ xs_textdecoder_get_encoding, // 9
94
+ xs_textdecoder_get_ignoreBOM, // 10
95
+ xs_textdecoder_get_fatal, // 11
96
+
97
+ xs_textencoder, // 12
98
+ xs_textencoder_encode, // 13
99
+ xs_textencoder_encodeInto, // 14
100
+
101
+ xs_base64_encode, // 15
102
+ xs_base64_decode, // 16
103
+
104
+ fx_harden, // 17
105
+ // fx_setInterval,
106
+ // fx_setTimeout,
107
+ // fx_clearTimer,
108
+ };
109
+
110
+ typedef struct {
111
+ FILE *file;
112
+ int size;
113
+ } SnapshotStream;
114
+
115
+ static int fxSnapshotRead(void* stream, void* address, size_t size)
116
+ {
117
+ return (fread(address, size, 1, stream) == 1) ? 0 : errno;
118
+ }
119
+
120
+ static int fxSnapshotWrite(void* stream, void* address, size_t size)
121
+ {
122
+ SnapshotStream* snapshotStream = stream;
123
+ size_t written = fwrite(address, size, 1, snapshotStream->file);
124
+ snapshotStream->size += size * written;
125
+ return (written == 1) ? 0 : errno;
126
+ }
127
+
128
+ #if mxInstrument
129
+ #define xsnapInstrumentCount 1
130
+ static xsStringValue xsnapInstrumentNames[xsnapInstrumentCount] = {
131
+ "Metering",
132
+ };
133
+ static xsStringValue xsnapInstrumentUnits[xsnapInstrumentCount] = {
134
+ " times",
135
+ };
136
+ static xsIntegerValue xsnapInstrumentValues[xsnapInstrumentCount] = {
137
+ 0,
138
+ };
139
+ #endif
140
+
141
+ #if mxMetering
142
+ #define xsBeginCrank(_THE, _LIMIT) \
143
+ (xsSetCurrentMeter(_THE, 0), \
144
+ gxCurrentMeter = _LIMIT)
145
+ #define xsEndCrank(_THE) \
146
+ (gxCurrentMeter = 0, \
147
+ fxGetCurrentMeter(_THE))
148
+ #else
149
+ #define xsBeginCrank(_THE, _LIMIT)
150
+ #define xsEndCrank(_THE) 0
151
+ #endif
152
+
153
+ static xsUnsignedValue gxCrankMeteringLimit = 0;
154
+ static xsUnsignedValue gxCurrentMeter = 0;
155
+ xsBooleanValue fxMeteringCallback(xsMachine* the, xsUnsignedValue index)
156
+ {
157
+ if (gxCurrentMeter > 0 && index > gxCurrentMeter) {
158
+ // Just throw right out of the main loop and exit.
159
+ return 0;
160
+ }
161
+ // fprintf(stderr, "metering up to %d\n", index);
162
+ return 1;
163
+ }
164
+ static xsBooleanValue gxMeteringPrint = 0;
165
+
166
+ static FILE *fromParent;
167
+ static FILE *toParent;
168
+
169
+ typedef enum {
170
+ E_UNKNOWN_ERROR = -1,
171
+ E_SUCCESS = 0,
172
+ E_BAD_USAGE,
173
+ E_IO_ERROR,
174
+ // 10 + XS_NOT_ENOUGH_MEMORY_EXIT
175
+ E_NOT_ENOUGH_MEMORY = 11,
176
+ E_STACK_OVERFLOW = 12,
177
+ E_UNHANDLED_EXCEPTION = 15,
178
+ E_NO_MORE_KEYS = 16,
179
+ E_TOO_MUCH_COMPUTATION = 17,
180
+ } ExitCode;
181
+
182
+ // 250 syscalls
183
+ #define MAX_TIMESTAMPS 502
184
+ static struct timeval timestamps[MAX_TIMESTAMPS];
185
+ static unsigned int num_timestamps;
186
+ static unsigned int timestamps_overrun;
187
+ static void resetTimestamps() {
188
+ timestamps_overrun = 0;
189
+ num_timestamps = 0;
190
+ // on 64-bit platforms, 'struct timeval' usually needs 8+8=16 bytes
191
+ //printf("sizeof(time_t): %ld\n", sizeof(time_t));
192
+ //printf("sizeof(time_suseconts_t): %ld\n", sizeof(suseconds_t));
193
+ }
194
+ static void recordTimestamp() {
195
+ if (num_timestamps < MAX_TIMESTAMPS) {
196
+ gettimeofday(&(timestamps[num_timestamps]), NULL);
197
+ num_timestamps += 1;
198
+ } else {
199
+ timestamps_overrun = 1;
200
+ }
201
+ }
202
+
203
+ // 2^64 is 18446744073709551616 , which is 20 characters long
204
+ #define DIGITS_FOR_64 20
205
+ // [AA.AA,BB.BB,CC.CC]\0
206
+ static char timestampBuffer[1 + MAX_TIMESTAMPS * (DIGITS_FOR_64 + 1 + 6 + 1) + 1];
207
+ // over provisioning by considering all "sec" values as the max printed length.
208
+ // While the last timestamps does not have a trailing comma, the payload ends
209
+ // with both a closing square bracket and a null byte.
210
+
211
+ static char *renderTimestamps() {
212
+ // return pointer to static string buffer with '[NN.NN,NN.NN]', or NULL
213
+ unsigned int size, i, wrote;
214
+ char *p = timestampBuffer;
215
+ size = sizeof(timestampBuffer); // holds all numbers, commas, and \0
216
+ *(p++) = '['; size--;
217
+ for (i = 0; i < num_timestamps; i++) {
218
+ // snprintf() returns "the number of characters that would have
219
+ // been printed if the size were unlimited, not including the
220
+ // final \0". It writes at most size-1 characters, then writes
221
+ // the trailing \0.
222
+ wrote = snprintf(p, size, "%lu.%06lu",
223
+ timestamps[i].tv_sec, timestamps[i].tv_usec);
224
+ p += wrote;
225
+ size -= wrote;
226
+ if (size < 2) { // 2 is enough for "]\0", but 1 is not
227
+ return NULL;
228
+ }
229
+ if (i+1 < num_timestamps) {
230
+ // 2 is also enough for a comma
231
+ *(p++) = ','; size--;
232
+ }
233
+ if (size < 2) { // but the comma might reduce size below 2
234
+ return NULL;
235
+ }
236
+ }
237
+ if (size < 2) { // paranoia, also in case loop never loops
238
+ return NULL;
239
+ }
240
+ *(p++) = ']'; size--;
241
+ *(p++) = '\0'; size--;
242
+ return timestampBuffer;
243
+ }
244
+
245
+ int main(int argc, char* argv[])
246
+ {
247
+ int argi;
248
+ int argr = 0;
249
+ int error = 0;
250
+ int interval = 0;
251
+ int parserBufferSize = 8192 * 1024;
252
+
253
+ xsSnapshot snapshot = {
254
+ SNAPSHOT_SIGNATURE,
255
+ sizeof(SNAPSHOT_SIGNATURE) - 1,
256
+ gxSnapshotCallbacks,
257
+ mxSnapshotCallbackCount,
258
+ fxSnapshotRead,
259
+ fxSnapshotWrite,
260
+ NULL,
261
+ 0,
262
+ NULL,
263
+ NULL,
264
+ NULL,
265
+ 0,
266
+ NULL
267
+ };
268
+
269
+ xsMachine* machine;
270
+ char *path;
271
+
272
+ #if XSNAP_TEST_RECORD
273
+ fxTestRecordArgs(argc, argv);
274
+ #endif
275
+
276
+ for (argi = 1; argi < argc; argi++) {
277
+ if (argv[argi][0] != '-')
278
+ continue;
279
+ if (!strcmp(argv[argi], "-h")) {
280
+ xsPrintUsage();
281
+ return 0;
282
+ } else if (!strcmp(argv[argi], "-i")) {
283
+ argi++;
284
+ if (argi < argc)
285
+ interval = atoi(argv[argi]);
286
+ else {
287
+ xsPrintUsage();
288
+ return E_BAD_USAGE;
289
+ }
290
+ }
291
+ else if (!strcmp(argv[argi], "-l")) {
292
+ #if mxMetering
293
+ argi++;
294
+ if (argi < argc)
295
+ gxCrankMeteringLimit = atoi(argv[argi]);
296
+ else {
297
+ xsPrintUsage();
298
+ return E_BAD_USAGE;
299
+ }
300
+ #else
301
+ fprintf(stderr, "%s flag not implemented; mxMetering is not enabled\n", argv[argi]);
302
+ return E_BAD_USAGE;
303
+ #endif
304
+ }
305
+ else if (!strcmp(argv[argi], "-p"))
306
+ gxMeteringPrint = 1;
307
+ else if (!strcmp(argv[argi], "-r")) {
308
+ argi++;
309
+ if (argi < argc)
310
+ argr = argi;
311
+ else {
312
+ xsPrintUsage();
313
+ return E_BAD_USAGE;
314
+ }
315
+ }
316
+ else if (!strcmp(argv[argi], "-s")) {
317
+ argi++;
318
+ if (argi < argc)
319
+ parserBufferSize = 1024 * atoi(argv[argi]);
320
+ else {
321
+ xsPrintUsage();
322
+ return E_BAD_USAGE;
323
+ }
324
+ }
325
+ else if (!strcmp(argv[argi], "-v")) {
326
+ char version[16];
327
+ xsVersion(version, sizeof(version));
328
+ printf("xsnap %s (XS %s)\n", XSNAP_VERSION, version);
329
+ return E_SUCCESS;
330
+ }
331
+ else if (!strcmp(argv[argi], "-n")) {
332
+ printf("agoric-upgrade-10\n");
333
+ return E_SUCCESS;
334
+ } else {
335
+ xsPrintUsage();
336
+ return E_BAD_USAGE;
337
+ }
338
+ }
339
+ xsCreation _creation = {
340
+ 32 * 1024 * 1024, /* initialChunkSize */
341
+ 4 * 1024 * 1024, /* incrementalChunkSize */
342
+ 256 * 1024, /* initialHeapCount */
343
+ 128 * 1024, /* incrementalHeapCount */
344
+ 4096, /* stackCount */
345
+ 32000, /* initialKeyCount */
346
+ 8000, /* incrementalKeyCount */
347
+ 1993, /* nameModulo */
348
+ 127, /* symbolModulo */
349
+ parserBufferSize, /* parserBufferSize */
350
+ 1993, /* parserTableModulo */
351
+ };
352
+ xsCreation* creation = &_creation;
353
+
354
+ if (gxCrankMeteringLimit) {
355
+ if (interval == 0)
356
+ interval = 1;
357
+ }
358
+ xsInitializeSharedCluster();
359
+ if (argr) {
360
+ char *path = argv[argr];
361
+ if (path[0] == '@') {
362
+ int fd = atoi(path + 1);
363
+ int tmpfd = dup(fd);
364
+ if (tmpfd < 0) {
365
+ snapshot.stream = NULL;
366
+ } else {
367
+ snapshot.stream = fdopen(tmpfd, "rb");
368
+ }
369
+ } else {
370
+ snapshot.stream = fopen(path, "rb");
371
+ }
372
+ if (snapshot.stream) {
373
+ machine = xsReadSnapshot(&snapshot, "xsnap", NULL);
374
+ fclose(snapshot.stream);
375
+ }
376
+ else
377
+ snapshot.error = errno;
378
+ if (snapshot.error) {
379
+ fprintf(stderr, "cannot read snapshot %s: %s\n", argv[argr], strerror(snapshot.error));
380
+ return E_IO_ERROR;
381
+ }
382
+ }
383
+ else {
384
+ machine = xsCreateMachine(creation, "xsnap", NULL);
385
+ xsBuildAgent(machine);
386
+ }
387
+ if (!(fromParent = fdopen(3, "rb"))) {
388
+ fprintf(stderr, "fdopen(3) from parent failed\n");
389
+ c_exit(E_IO_ERROR);
390
+ }
391
+ if (!(toParent = fdopen(4, "wb"))) {
392
+ fprintf(stderr, "fdopen(4) to parent failed\n");
393
+ c_exit(E_IO_ERROR);
394
+ }
395
+ #if mxInstrument
396
+ xsDescribeInstrumentation(machine, xsnapInstrumentCount, xsnapInstrumentNames, xsnapInstrumentUnits);
397
+ #endif
398
+ xsBeginMetering(machine, fxMeteringCallback, interval);
399
+ {
400
+ fd_set rfds;
401
+ char done = 0;
402
+ while (!done) {
403
+ #if mxInstrument
404
+ FD_ZERO(&rfds);
405
+ FD_SET(3, &rfds);
406
+ FD_SET(5, &rfds);
407
+ if (select(6, &rfds, NULL, NULL, NULL) >= 0) {
408
+ if (FD_ISSET(5, &rfds))
409
+ xsRunDebugger(machine);
410
+ if (!FD_ISSET(3, &rfds))
411
+ continue;
412
+ }
413
+ else {
414
+ fprintf(stderr, "select failed: %s\n", strerror(errno));
415
+ error = E_IO_ERROR;
416
+ break;
417
+ }
418
+ #endif
419
+ // By default, use the infinite meter.
420
+ gxCurrentMeter = 0;
421
+
422
+ xsUnsignedValue meterIndex = 0;
423
+ char* nsbuf;
424
+ size_t nslen;
425
+ resetTimestamps();
426
+ int readError = fxReadNetString(fromParent, &nsbuf, &nslen);
427
+ recordTimestamp(); // after delivery received from parent
428
+ int writeError = 0;
429
+
430
+ if (readError != 0) {
431
+ if (feof(fromParent)) {
432
+ break;
433
+ } else {
434
+ fprintf(stderr, "%s\n", fxReadNetStringError(readError));
435
+ c_exit(E_IO_ERROR);
436
+ }
437
+ }
438
+ char command = *nsbuf;
439
+ // fprintf(stderr, "command: len %d %c arg: %s\n", nslen, command, nsbuf + 1);
440
+ switch(command) {
441
+ case 'R': // isReady
442
+ fxWriteNetString(toParent, ".", "", 0);
443
+ break;
444
+ case '?':
445
+ case 'e':
446
+ xsBeginCrank(machine, gxCrankMeteringLimit);
447
+ char* response = NULL;
448
+ xsIntegerValue responseLength = 0;
449
+ error = 0;
450
+ xsBeginHost(machine);
451
+ {
452
+ xsVars(3);
453
+ xsTry {
454
+ if (command == '?') {
455
+ #if XSNAP_TEST_RECORD
456
+ fxTestRecord(mxTestRecordJSON | mxTestRecordParam, nsbuf + 1, nslen - 1);
457
+ #endif
458
+ // TODO: can we avoid a copy?
459
+ xsVar(0) = xsArrayBuffer(nsbuf + 1, nslen - 1);
460
+ xsVar(1) = xsCall1(xsGlobal, xsID("handleCommand"), xsVar(0));
461
+ } else {
462
+ #if XSNAP_TEST_RECORD
463
+ fxTestRecord(mxTestRecordJS | mxTestRecordParam, nsbuf + 1, nslen - 1);
464
+ #endif
465
+ xsVar(0) = xsStringBuffer(nsbuf + 1, nslen - 1);
466
+ xsVar(1) = xsCall1(xsGlobal, xsID("eval"), xsVar(0));
467
+ }
468
+ }
469
+ xsCatch {
470
+ if (xsTypeOf(xsException) != xsUndefinedType) {
471
+ // fprintf(stderr, "%c: %s\n", command, xsToString(xsException));
472
+ error = E_UNHANDLED_EXCEPTION;
473
+ xsVar(1) = xsException;
474
+ xsException = xsUndefined;
475
+ }
476
+ }
477
+ }
478
+ fxRunLoop(machine);
479
+ meterIndex = xsEndCrank(machine);
480
+ {
481
+ if (error) {
482
+ response = xsToString(xsVar(1));
483
+ responseLength = strlen(response);
484
+ } else {
485
+ // fprintf(stderr, "report: %d %s\n", xsTypeOf(report), xsToString(report));
486
+ xsTry {
487
+ if (xsTypeOf(xsVar(1)) == xsReferenceType && xsHas(xsVar(1), xsID("result"))) {
488
+ xsVar(2) = xsGet(xsVar(1), xsID("result"));
489
+ } else {
490
+ xsVar(2) = xsVar(1);
491
+ }
492
+ // fprintf(stderr, "result: %d %s\n", xsTypeOf(result), xsToString(result));
493
+ if (xsIsInstanceOf(xsVar(2), xsArrayBufferPrototype)) {
494
+ responseLength = xsGetArrayBufferLength(xsVar(2));
495
+ response = xsToArrayBuffer(xsVar(2));
496
+ }
497
+ }
498
+ xsCatch {
499
+ if (xsTypeOf(xsException) != xsUndefinedType) {
500
+ fprintf(stderr, "%c computing response %d", command, xsTypeOf(xsVar(1)));
501
+ fprintf(stderr, " %d:", xsTypeOf(xsVar(2)));
502
+ fprintf(stderr, " %s:", xsToString(xsVar(2)));
503
+ fprintf(stderr, " %s\n", xsToString(xsException));
504
+ xsException = xsUndefined;
505
+ }
506
+ }
507
+ }
508
+ }
509
+ xsEndHost(machine);
510
+ if (error) {
511
+ writeError = fxWriteNetString(toParent, "!", response, responseLength);
512
+ // fprintf(stderr, "error: %d, writeError: %d %s\n", error, writeError, response);
513
+ } else {
514
+ // fprintf(stderr, "response of %d bytes\n", responseLength);
515
+ writeError = fxWriteOkay(toParent, meterIndex, machine, response, responseLength);
516
+ }
517
+ if (writeError != 0) {
518
+ fprintf(stderr, "%s\n", fxWriteNetStringError(writeError));
519
+ c_exit(E_IO_ERROR);
520
+ }
521
+ break;
522
+ case 's':
523
+ case 'm':
524
+ xsBeginCrank(machine, gxCrankMeteringLimit);
525
+ path = nsbuf + 1;
526
+ xsBeginHost(machine);
527
+ {
528
+ xsVars(1);
529
+ xsTry {
530
+ // ISSUE: realpath necessary? realpath(x, x) doesn't seem to work.
531
+ if (command == 'm')
532
+ xsRunModuleFile(path);
533
+ else
534
+ xsRunProgramFile(path);
535
+ }
536
+ xsCatch {
537
+ if (xsTypeOf(xsException) != xsUndefinedType) {
538
+ fprintf(stderr, "%s\n", xsToString(xsException));
539
+ error = E_UNHANDLED_EXCEPTION;
540
+ xsException = xsUndefined;
541
+ }
542
+ }
543
+ }
544
+ xsEndHost(machine);
545
+ fxRunLoop(machine);
546
+ meterIndex = xsEndCrank(machine);
547
+ if (error == 0) {
548
+ int writeError = fxWriteOkay(toParent, meterIndex, machine, "", 0);
549
+ if (writeError != 0) {
550
+ fprintf(stderr, "%s\n", fxWriteNetStringError(writeError));
551
+ c_exit(E_IO_ERROR);
552
+ }
553
+ } else {
554
+ // TODO: dynamically build error message including Exception message.
555
+ int writeError = fxWriteNetString(toParent, "!", "", 0);
556
+ if (writeError != 0) {
557
+ fprintf(stderr, "%s\n", fxWriteNetStringError(writeError));
558
+ c_exit(E_IO_ERROR);
559
+ }
560
+ }
561
+ break;
562
+
563
+ case 'w':
564
+ #if XSNAP_TEST_RECORD
565
+ fxTestRecord(mxTestRecordParam, nsbuf + 1, nslen - 1);
566
+ #endif
567
+ path = nsbuf + 1;
568
+ SnapshotStream stream;
569
+ if (path[0] == '@') {
570
+ int fd = atoi(path + 1);
571
+ int tmpfd = dup(fd);
572
+ if (tmpfd < 0) {
573
+ stream.file = NULL;
574
+ } else {
575
+ stream.file = fdopen(tmpfd, "ab");
576
+ }
577
+ } else {
578
+ stream.file = fopen(path, "wb");
579
+ }
580
+ stream.size = 0;
581
+ if (stream.file) {
582
+ snapshot.stream = &stream;
583
+ fxWriteSnapshot(machine, &snapshot);
584
+ snapshot.stream = NULL;
585
+ fclose(stream.file);
586
+ }
587
+ else
588
+ snapshot.error = errno;
589
+ if (snapshot.error) {
590
+ fprintf(stderr, "cannot write snapshot %s: %s\n",
591
+ path, strerror(snapshot.error));
592
+ c_exit(E_IO_ERROR);
593
+ }
594
+ if (snapshot.error == 0) {
595
+ // Allows us to format up to 999,999,999,999 bytes (1TiB - 1)
596
+ char fsize[13];
597
+ int fsizeLength = snprintf(fsize, sizeof(fsize), "%d", stream.size);
598
+ int writeError = fxWriteOkay(toParent, meterIndex, machine, fsize, fsizeLength);
599
+ if (writeError != 0) {
600
+ fprintf(stderr, "%s\n", fxWriteNetStringError(writeError));
601
+ c_exit(E_IO_ERROR);
602
+ }
603
+ } else {
604
+ // TODO: dynamically build error message including Exception message.
605
+ int writeError = fxWriteNetString(toParent, "!", "", 0);
606
+ if (writeError != 0) {
607
+ fprintf(stderr, "%s\n", fxWriteNetStringError(writeError));
608
+ c_exit(E_IO_ERROR);
609
+ }
610
+ }
611
+ break;
612
+ case 'q':
613
+ done = 1;
614
+ break;
615
+
616
+ // We reserve some prefix characters to avoid/detect/debug confusion,
617
+ // all of which are explicitly rejected, just like unknown commands. Do not
618
+ // reuse these for new commands.
619
+ case '/': // downstream response to upstream issueCommand()
620
+ case '.': // upstream good response to downstream execute/eval
621
+ case '!': // upstream error response to downstream execute/eval
622
+ default:
623
+ // note: the nsbuf we receive from fxReadNetString is null-terminated
624
+ fprintf(stderr, "Unexpected prefix '%c' in command '%s'\n", command, nsbuf);
625
+ c_exit(E_IO_ERROR);
626
+ break;
627
+ }
628
+ free(nsbuf);
629
+ #if mxInstrument
630
+ xsnapInstrumentValues[0] = (xsIntegerValue)meterIndex;
631
+ xsSampleInstrumentation(machine, xsnapInstrumentCount, xsnapInstrumentValues);
632
+ #endif
633
+ }
634
+ xsBeginHost(machine);
635
+ {
636
+ if (xsTypeOf(xsException) != xsUndefinedType) {
637
+ fprintf(stderr, "%s\n", xsToString(xsException));
638
+ error = E_UNHANDLED_EXCEPTION;
639
+ }
640
+ }
641
+ xsEndHost(machine);
642
+ }
643
+ xsEndMetering(machine);
644
+ if (machine->abortStatus) {
645
+ switch (machine->abortStatus) {
646
+ case xsNotEnoughMemoryExit:
647
+ error = E_NOT_ENOUGH_MEMORY;
648
+ break;
649
+ case xsStackOverflowExit:
650
+ error = E_STACK_OVERFLOW;
651
+ break;
652
+ case xsNoMoreKeysExit:
653
+ error = E_NO_MORE_KEYS;
654
+ break;
655
+ case xsTooMuchComputationExit:
656
+ error = E_TOO_MUCH_COMPUTATION;
657
+ break;
658
+ default:
659
+ error = E_UNKNOWN_ERROR;
660
+ break;
661
+ }
662
+ }
663
+ if (error != E_SUCCESS) {
664
+ c_exit(error);
665
+ }
666
+ xsDeleteMachine(machine);
667
+ fxTerminateSharedCluster();
668
+ return E_SUCCESS;
669
+ }
670
+
671
+ void xsBuildAgent(xsMachine* machine)
672
+ {
673
+ xsBeginHost(machine);
674
+ xsVars(1);
675
+
676
+ // xsResult = xsNewHostFunction(xs_clearTimer, 1);
677
+ // xsDefine(xsGlobal, xsID("clearImmediate"), xsResult, xsDontEnum);
678
+ xsResult = xsNewHostFunction(xs_setImmediate, 1);
679
+ xsDefine(xsGlobal, xsID("setImmediate"), xsResult, xsDontEnum);
680
+
681
+ // xsResult = xsNewHostFunction(xs_clearTimer, 1);
682
+ // xsDefine(xsGlobal, xsID("clearInterval"), xsResult, xsDontEnum);
683
+ // xsResult = xsNewHostFunction(xs_setInterval, 1);
684
+ // xsDefine(xsGlobal, xsID("setInterval"), xsResult, xsDontEnum);
685
+
686
+ // xsResult = xsNewHostFunction(xs_clearTimer, 1);
687
+ // xsDefine(xsGlobal, xsID("clearTimeout"), xsResult, xsDontEnum);
688
+ // xsResult = xsNewHostFunction(xs_setTimeout, 1);
689
+ // xsDefine(xsGlobal, xsID("setTimeout"), xsResult, xsDontEnum);
690
+
691
+ xsResult = xsNewHostFunction(xs_gc, 1);
692
+ xsDefine(xsGlobal, xsID("gc"), xsResult, xsDontEnum);
693
+ xsResult = xsNewHostFunction(xs_print, 1);
694
+ xsDefine(xsGlobal, xsID("print"), xsResult, xsDontEnum);
695
+
696
+ xsResult = xsNewHostFunction(xs_issueCommand, 1);
697
+ xsDefine(xsGlobal, xsID("issueCommand"), xsResult, xsDontEnum);
698
+
699
+ xsResult = xsNewObject();
700
+ xsVar(0) = xsNewHostFunction(xs_performance_now, 0);
701
+ xsDefine(xsResult, xsID("now"), xsVar(0), xsDontEnum);
702
+ xsDefine(xsGlobal, xsID("performance"), xsResult, xsDontEnum);
703
+
704
+ xsResult = xsNewHostFunction(xs_currentMeterLimit, 1);
705
+ xsDefine(xsGlobal, xsID("currentMeterLimit"), xsResult, xsDontEnum);
706
+ xsResult = xsNewHostFunction(xs_resetMeter, 1);
707
+ xsDefine(xsGlobal, xsID("resetMeter"), xsResult, xsDontEnum);
708
+
709
+ modInstallTextDecoder(the);
710
+ modInstallTextEncoder(the);
711
+ modInstallBase64(the);
712
+
713
+ xsResult = xsNewHostFunction(fx_harden, 1);
714
+ xsDefine(xsGlobal, xsID("harden"), xsResult, xsDontEnum);
715
+
716
+ // xsResult = xsNewObject();
717
+ // xsVar(0) = xsNewHostFunction(fx_print, 0);
718
+ // xsDefine(xsResult, xsID("log"), xsVar(0), xsDontEnum);
719
+ // xsDefine(xsGlobal, xsID("console"), xsResult, xsDontEnum);
720
+
721
+ xsEndHost(machine);
722
+ }
723
+
724
+ void xsPrintUsage()
725
+ {
726
+ printf("xsnap [-h] [-i <interval>] [-l <limit>] [-s <size>] [-m] [-r <snapshot>] [-s] [-v]\n");
727
+ printf("\t-h: print this help message\n");
728
+ printf("\t-i <interval>: metering interval (default to 1)\n");
729
+ printf("\t-l <limit>: metering limit (default to none)\n");
730
+ printf("\t-s <size>: parser buffer size, in kB (default to 8192)\n");
731
+ printf("\t-r <snapshot>: read snapshot to create the XS machine\n");
732
+ printf("\t-v: print XS version\n");
733
+ }
734
+
735
+ void xs_clearTimer(xsMachine* the)
736
+ {
737
+ xsClearTimer();
738
+ }
739
+
740
+ void xs_currentMeterLimit(xsMachine* the)
741
+ {
742
+ #if mxMetering
743
+ xsResult = xsInteger(gxCurrentMeter);
744
+ #endif
745
+ }
746
+
747
+ void xs_gc(xsMachine* the)
748
+ {
749
+ xsCollectGarbage();
750
+ }
751
+
752
+ void xs_performance_now(xsMachine *the)
753
+ {
754
+ c_timeval tv;
755
+ c_gettimeofday(&tv, NULL);
756
+ xsResult = xsNumber((double)(tv.tv_sec * 1000.0) + ((double)(tv.tv_usec) / 1000.0));
757
+ }
758
+
759
+ void xs_print(xsMachine* the)
760
+ {
761
+ xsIntegerValue c = xsToInteger(xsArgc), i;
762
+ #if mxMetering
763
+ if (gxMeteringPrint)
764
+ fprintf(stdout, "[%u] ", xsGetCurrentMeter(the));
765
+ #endif
766
+ for (i = 0; i < c; i++) {
767
+ if (i)
768
+ fprintf(stdout, " ");
769
+ fprintf(stdout, "%s", xsToString(xsArg(i)));
770
+ }
771
+ fprintf(stdout, "\n");
772
+ fflush(stdout);
773
+ }
774
+
775
+ void xs_resetMeter(xsMachine* the)
776
+ {
777
+ #if mxMetering
778
+ xsIntegerValue argc = xsToInteger(xsArgc);
779
+ if (argc < 2) {
780
+ xsTypeError("expected newMeterLimit, newMeterIndex");
781
+ }
782
+ xsResult = xsInteger(xsGetCurrentMeter(the));
783
+ gxCurrentMeter = xsToInteger(xsArg(0));
784
+ xsSetCurrentMeter(the, xsToInteger(xsArg(1)));
785
+ #endif
786
+ }
787
+
788
+ void xs_setImmediate(xsMachine* the)
789
+ {
790
+ xsSetTimer(0, 0);
791
+ }
792
+
793
+ void xs_setInterval(xsMachine* the)
794
+ {
795
+ xsSetTimer(xsToNumber(xsArg(1)), 1);
796
+ }
797
+
798
+ void xs_setTimeout(xsMachine* the)
799
+ {
800
+ xsSetTimer(xsToNumber(xsArg(1)), 0);
801
+ }
802
+
803
+
804
+ static int fxReadNetString(FILE *inStream, char** dest, size_t* len)
805
+ {
806
+ int code = 0;
807
+ char* buf = NULL;
808
+
809
+ if (fscanf(inStream, "%9lu", len) < 1) {
810
+ /* >999999999 bytes is bad */
811
+ code = 1;
812
+ } else if (fgetc(inStream) != ':') {
813
+ code = 2;
814
+ } else {
815
+ buf = malloc(*len + 1); /* malloc(0) is not portable */
816
+ if (!buf) {
817
+ code = 3;
818
+ } else if (fread(buf, 1, *len, inStream) < *len) {
819
+ code = 4;
820
+ } else if (fgetc(inStream) != ',') {
821
+ code = 5;
822
+ } else {
823
+ *(buf + *len) = 0;
824
+ }
825
+ if (code == 0) {
826
+ *dest = buf;
827
+ } else {
828
+ *dest = 0;
829
+ free(buf);
830
+ }
831
+ }
832
+ return code;
833
+ }
834
+
835
+ static char* fxReadNetStringError(int code)
836
+ {
837
+ switch (code) {
838
+ case 0: return "OK";
839
+ case 1: return "Cannot read netstring, reading length prefix, fscanf";
840
+ case 2: return "Cannot read netstring, invalid delimiter or end of file, fgetc";
841
+ case 3: return "Cannot read netstring, cannot allocate message buffer, malloc";
842
+ case 4: return "Cannot read netstring, cannot read message body, fread";
843
+ case 5: return "Cannot read netstring, cannot read trailer, fgetc";
844
+ default: return "Cannot read netstring";
845
+ }
846
+ }
847
+
848
+ static int fxWriteOkay(FILE* outStream, xsUnsignedValue meterIndex, xsMachine *the, char* buf, size_t length)
849
+ {
850
+ recordTimestamp(); // before sending delivery-result to parent
851
+ char *tsbuf = renderTimestamps();
852
+ if (!tsbuf) {
853
+ // rendering overrun error, send empty list
854
+ tsbuf = "[]";
855
+ }
856
+ char fmt[] = ("." // OK
857
+ "{"
858
+ "\"currentHeapCount\":%u,"
859
+ "\"compute\":%u,"
860
+ "\"allocate\":%u,"
861
+ "\"timestamps\":%s}"
862
+ "\1" // separate meter info from result
863
+ );
864
+ char numeral64[] = "12345678901234567890"; // big enough for 64bit numeral
865
+ char prefix[8 + sizeof fmt + 8 * sizeof numeral64 + sizeof timestampBuffer];
866
+ // Prepend the meter usage to the reply.
867
+ snprintf(prefix, sizeof(prefix), fmt,
868
+ fxGetCurrentHeapCount(the),
869
+ meterIndex, the->allocatedSpace, tsbuf);
870
+ return fxWriteNetString(outStream, prefix, buf, length);
871
+ }
872
+
873
+ static int fxWriteNetString(FILE* outStream, char* prefix, char* buf, size_t length)
874
+ {
875
+ if (fprintf(outStream, "%lu:%s", length + strlen(prefix), prefix) < 1) {
876
+ return 1;
877
+ } else if (fwrite(buf, 1, length, outStream) < length) {
878
+ return 2;
879
+ } else if (fputc(',', outStream) == EOF) {
880
+ return 3;
881
+ } else if (fflush(outStream) < 0) {
882
+ return 4;
883
+ }
884
+
885
+ return 0;
886
+ }
887
+
888
+ static char* fxWriteNetStringError(int code)
889
+ {
890
+ switch (code) {
891
+ case 0: return "OK";
892
+ case 1: return "Cannot write netstring, error writing length prefix";
893
+ case 2: return "Cannot write netstring, error writing message body";
894
+ case 3: return "Cannot write netstring, error writing terminator";
895
+ case 4: return "Cannot write netstring, error flushing stream, fflush";
896
+ default: return "Cannot write netstring";
897
+ }
898
+ }
899
+
900
+ static void xs_issueCommand(xsMachine *the)
901
+ {
902
+ int argc = xsToInteger(xsArgc);
903
+ if (argc < 1) {
904
+ xsTypeError("expected ArrayBuffer");
905
+ }
906
+
907
+ size_t length = xsGetArrayBufferLength(xsArg(0));
908
+ char* buf = xsToArrayBuffer(xsArg(0));
909
+
910
+ recordTimestamp(); // before sending command to parent
911
+
912
+ int writeError = fxWriteNetString(toParent, "?", buf, length);
913
+
914
+ if (writeError != 0) {
915
+ xsUnknownError(fxWriteNetStringError(writeError));
916
+ }
917
+
918
+ // read netstring
919
+ size_t len;
920
+ int readError = fxReadNetString(fromParent, &buf, &len);
921
+ if (readError != 0) {
922
+ xsUnknownError(fxReadNetStringError(readError));
923
+ }
924
+ recordTimestamp(); // after command-result received from parent
925
+
926
+ #if XSNAP_TEST_RECORD
927
+ fxTestRecord(mxTestRecordJSON | mxTestRecordReply, buf, len);
928
+ #endif
929
+ char command = *buf;
930
+ if (len == 0 || command != '/') {
931
+ xsUnknownError("Received unexpected command reply.");
932
+ }
933
+
934
+ xsResult = xsArrayBuffer(buf + 1, len - 1);
935
+ free(buf);
936
+ }
937
+
938
+ #if XSNAP_TEST_RECORD
939
+
940
+ static char directory[PATH_MAX];
941
+ void fxTestRecordArgs(int argc, char* argv[])
942
+ {
943
+ struct timeval tv;
944
+ struct tm* tm_info;
945
+ gettimeofday(&tv, NULL);
946
+ char path[PATH_MAX];
947
+ FILE* file;
948
+ mkdir("xsnap-tests", 0755);
949
+ tm_info = localtime(&tv.tv_sec);
950
+ strftime(path, sizeof(path), "%Y-%m-%d-%H-%M-%S", tm_info);
951
+ sprintf(directory, "xsnap-tests/%s-%3.3d", path, tv.tv_usec / 1000);
952
+ mkdir(directory, 0755);
953
+ sprintf(path, "%s/args.sh", directory);
954
+ file = fopen(path, "w");
955
+ if (file) {
956
+ int argi;
957
+ for (argi = 0; argi < argc; argi++)
958
+ fprintf(file, " %s", argv[argi]);
959
+ fprintf(file, "\n");
960
+ fclose(file);
961
+ }
962
+ }
963
+
964
+ void fxTestRecord(int flags, void* buffer, size_t length)
965
+ {
966
+ char path[PATH_MAX];
967
+ FILE* file;
968
+ if (flags & mxTestRecordParam) {
969
+ sprintf(path, "%s/param-%d", directory, gxTestRecordReplyIndex);
970
+ gxTestRecordReplyIndex++;
971
+ }
972
+ else {
973
+ sprintf(path, "%s/reply-%d", directory, gxTestRecordParamIndex);
974
+ gxTestRecordParamIndex++;
975
+ }
976
+ if (flags & mxTestRecordJS)
977
+ strcat(path, ".js");
978
+ else if (flags & mxTestRecordJSON)
979
+ strcat(path, ".json");
980
+ else
981
+ strcat(path, ".txt");
982
+ file = fopen(path, "wb");
983
+ if (file) {
984
+ fwrite(buffer, 1, length, file);
985
+ fclose(file);
986
+ }
987
+ }
988
+
989
+ #endif
990
+
991
+ // Local Variables:
992
+ // tab-width: 4
993
+ // c-basic-offset: 4
994
+ // indent-tabs-mode: t
995
+ // End:
996
+ // vim: noet ts=4 sw=4