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