diff --git a/xsnap/makefiles/lin/xsnap-ava.mk b/xsnap/makefiles/lin/xsnap-ava.mk new file mode 100644 index 0000000..3893de5 --- /dev/null +++ b/xsnap/makefiles/lin/xsnap-ava.mk @@ -0,0 +1,130 @@ +% : %.c +%.o : %.c + +GOAL ?= debug +NAME = xsnap +ifneq ($(VERBOSE),1) +MAKEFLAGS += --silent +endif + +MODDABLE = $(CURDIR)/../../moddable +XS_DIR = $(MODDABLE)/xs +BUILD_DIR = $(CURDIR)/../../build + +BIN_DIR = $(BUILD_DIR)/bin/lin/$(GOAL) +INC_DIR = $(XS_DIR)/includes +PLT_DIR = $(XS_DIR)/platforms +SRC_DIR = $(XS_DIR)/sources +TLS_DIR = ../../src +TMP_DIR = $(BUILD_DIR)/tmp/lin/$(GOAL)/$(NAME) + +MACOS_ARCH ?= -arch i386 +MACOS_VERSION_MIN ?= -mmacosx-version-min=10.7 + +C_OPTIONS = \ + -fno-common \ + -DINCLUDE_XSPLATFORM \ + -DXSPLATFORM=\"xsnapPlatform.h\" \ + -DXSNAP_VERSION=\"$(XSNAP_VERSION)\" \ + -DmxParse=1 \ + -DmxRun=1 \ + -DmxSloppy=1 \ + -DmxSnapshot=1 \ + -DmxMetering=1 \ + -DmxRegExpUnicodePropertyEscapes=1 \ + -I$(INC_DIR) \ + -I$(PLT_DIR) \ + -I$(SRC_DIR) \ + -I$(TLS_DIR) \ + -I$(TMP_DIR) +C_OPTIONS += \ + -Wno-misleading-indentation \ + -Wno-implicit-fallthrough +ifeq ($(GOAL),debug) + C_OPTIONS += -DmxDebug=1 -g -O0 -Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter +else + C_OPTIONS += -DmxBoundsCheck=1 -O3 +endif + +LIBRARIES = -ldl -lm -lpthread + +LINK_OPTIONS = -rdynamic + +OBJECTS = \ + $(TMP_DIR)/xsAll.o \ + $(TMP_DIR)/xsAPI.o \ + $(TMP_DIR)/xsArguments.o \ + $(TMP_DIR)/xsArray.o \ + $(TMP_DIR)/xsAtomics.o \ + $(TMP_DIR)/xsBigInt.o \ + $(TMP_DIR)/xsBoolean.o \ + $(TMP_DIR)/xsCode.o \ + $(TMP_DIR)/xsCommon.o \ + $(TMP_DIR)/xsDataView.o \ + $(TMP_DIR)/xsDate.o \ + $(TMP_DIR)/xsDebug.o \ + $(TMP_DIR)/xsDefaults.o \ + $(TMP_DIR)/xsError.o \ + $(TMP_DIR)/xsFunction.o \ + $(TMP_DIR)/xsGenerator.o \ + $(TMP_DIR)/xsGlobal.o \ + $(TMP_DIR)/xsJSON.o \ + $(TMP_DIR)/xsLexical.o \ + $(TMP_DIR)/xsMapSet.o \ + $(TMP_DIR)/xsMarshall.o \ + $(TMP_DIR)/xsMath.o \ + $(TMP_DIR)/xsMemory.o \ + $(TMP_DIR)/xsModule.o \ + $(TMP_DIR)/xsNumber.o \ + $(TMP_DIR)/xsObject.o \ + $(TMP_DIR)/xsPlatforms.o \ + $(TMP_DIR)/xsProfile.o \ + $(TMP_DIR)/xsPromise.o \ + $(TMP_DIR)/xsProperty.o \ + $(TMP_DIR)/xsProxy.o \ + $(TMP_DIR)/xsRegExp.o \ + $(TMP_DIR)/xsRun.o \ + $(TMP_DIR)/xsScope.o \ + $(TMP_DIR)/xsScript.o \ + $(TMP_DIR)/xsSnapshot.o \ + $(TMP_DIR)/xsSourceMap.o \ + $(TMP_DIR)/xsString.o \ + $(TMP_DIR)/xsSymbol.o \ + $(TMP_DIR)/xsSyntaxical.o \ + $(TMP_DIR)/xsTree.o \ + $(TMP_DIR)/xsType.o \ + $(TMP_DIR)/xsdtoa.o \ + $(TMP_DIR)/xsre.o \ + $(TMP_DIR)/xsnapPlatform.o \ + $(TMP_DIR)/$(NAME).o + +VPATH += $(SRC_DIR) $(TLS_DIR) + +build: $(TMP_DIR) $(BIN_DIR) $(BIN_DIR)/$(NAME) + +$(TMP_DIR): + mkdir -p $(TMP_DIR) + +$(BIN_DIR): + mkdir -p $(BIN_DIR) + +$(BIN_DIR)/$(NAME): $(OBJECTS) + @echo "#" $(NAME) $(GOAL) ": cc" $(@F) + $(CC) $(LINK_OPTIONS) $(OBJECTS) $(LIBRARIES) -o $@ + +$(OBJECTS): $(TLS_DIR)/xsnap.h +$(OBJECTS): $(TLS_DIR)/xsnapPlatform.h +$(OBJECTS): $(PLT_DIR)/xsPlatform.h +$(OBJECTS): $(SRC_DIR)/xsCommon.h +$(OBJECTS): $(SRC_DIR)/xsAll.h +$(OBJECTS): $(SRC_DIR)/xsScript.h +$(OBJECTS): $(SRC_DIR)/xsSnapshot.h +$(TMP_DIR)/%.o: %.c + @echo "#" $(NAME) $(GOAL) ": cc" $( 0 && index > gxCurrentMeter) { + // Just throw right out of the main loop and exit. + return 0; + } + // fprintf(stderr, "metering up to %d\n", index); + return 1; +} +static xsBooleanValue gxMeteringPrint = 0; + +static FILE *fromParent; +static FILE *toParent; + +int main(int argc, char* argv[]) +{ + int argi; + int argr = 0; + int error = 0; + int interval = 0; + int freeze = 0; + int parserBufferSize = 8192 * 1024; + + xsSnapshot snapshot = { + SNAPSHOT_SIGNATURE, + sizeof(SNAPSHOT_SIGNATURE) - 1, + gxSnapshotCallbacks, + mxSnapshotCallbackCount, + xsSnapshotRead, + xsSnapshotWrite, + NULL, + 0, + NULL, + NULL, + NULL, + }; + + xsMachine* machine; + char *path; + char* dot; + +#if XSNAP_TEST_RECORD + fxTestRecordArgs(argc, argv); +#endif + + for (argi = 1; argi < argc; argi++) { + if (argv[argi][0] != '-') + continue; + if (!strcmp(argv[argi], "-f")) { + freeze = 1; + } + else if (!strcmp(argv[argi], "-h")) { + xsPrintUsage(); + return 0; + } else if (!strcmp(argv[argi], "-i")) { + argi++; + if (argi < argc) + interval = atoi(argv[argi]); + else { + xsPrintUsage(); + return 1; + } + } + else if (!strcmp(argv[argi], "-l")) { +#if mxMetering + argi++; + if (argi < argc) + gxCrankMeteringLimit = atoi(argv[argi]); + else { + xsPrintUsage(); + return 1; + } +#else + fprintf(stderr, "%s flag not implemented; mxMetering is not enabled\n", argv[argi]); + return 1; +#endif + } + else if (!strcmp(argv[argi], "-p")) + gxMeteringPrint = 1; + else if (!strcmp(argv[argi], "-r")) { + argi++; + if (argi < argc) + argr = argi; + else { + xsPrintUsage(); + return 1; + } + } + else if (!strcmp(argv[argi], "-s")) { + argi++; + if (argi < argc) + parserBufferSize = 1024 * atoi(argv[argi]); + else { + xsPrintUsage(); + return 1; + } + } + else if (!strcmp(argv[argi], "-v")) { + char buffer[16]; + xsVersion(buffer, sizeof(buffer)); + printf("xsnap %s (XS %s)\n", XSNAP_VERSION, buffer); + return 0; + } else { + xsPrintUsage(); + return 1; + } + } + xsCreation _creation = { + 16 * 1024 * 1024, /* initialChunkSize */ + 16 * 1024 * 1024, /* incrementalChunkSize */ + 1 * 1024 * 1024, /* initialHeapCount */ + 1 * 1024 * 1024, /* incrementalHeapCount */ + 4096, /* stackCount */ + 32000, /* keyCount */ + 1993, /* nameModulo */ + 127, /* symbolModulo */ + parserBufferSize, /* parserBufferSize */ + 1993, /* parserTableModulo */ + }; + xsCreation* creation = &_creation; + + if (gxCrankMeteringLimit) { + if (interval == 0) + interval = 1; + } + xsInitializeSharedCluster(); + if (argr) { + snapshot.stream = fopen(argv[argr], "rb"); + if (snapshot.stream) { + machine = fxReadSnapshot(&snapshot, "xsnap", NULL); + fclose(snapshot.stream); + } + else + snapshot.error = errno; + if (snapshot.error) { + fprintf(stderr, "cannot read snapshot %s: %s\n", argv[argr], strerror(snapshot.error)); + return 1; + } + } + else { + machine = xsCreateMachine(creation, "xsnap", NULL); + xsBuildAgent(machine); + } + if (freeze) { + xsFreezeBuiltIns(machine); + xsFreezeAgent(machine); + xsShareMachine(machine); + xsCheckAliases(machine); + machine = xsCloneMachine(creation, machine, "xsnap", NULL); + } + if (!(fromParent = fdopen(3, "rb"))) { + fprintf(stderr, "fdopen(3) from parent failed\n"); + c_exit(1); + } + if (!(toParent = fdopen(4, "wb"))) { + fprintf(stderr, "fdopen(4) to parent failed\n"); + c_exit(1); + } + xsBeginMetering(machine, xsMeteringCallback, interval); + { + char done = 0; + while (!done) { + // By default, use the infinite meter. + gxCurrentMeter = 0; + + xsUnsignedValue meterIndex = 0; + char* nsbuf; + size_t nslen; + int readError = fxReadNetString(fromParent, &nsbuf, &nslen); + int writeError = 0; + + if (readError != 0) { + if (feof(fromParent)) { + break; + } else { + fprintf(stderr, "%s\n", fxReadNetStringError(readError)); + c_exit(1); + } + } + char command = *nsbuf; +// fprintf(stderr, "command: len %d %c arg: %s\n", nslen, command, nsbuf + 1); + switch(command) { + case '?': + case 'e': + xsBeginCrank(machine, gxCrankMeteringLimit); + error = 0; + xsBeginHost(machine); + { + xsVars(3); + xsTry { + if (command == '?') { + #if XSNAP_TEST_RECORD + fxTestRecord(mxTestRecordJSON | mxTestRecordParam, nsbuf + 1, nslen - 1); + #endif + xsVar(0) = xsArrayBuffer(nsbuf + 1, nslen - 1); + xsVar(1) = xsCall1(xsGlobal, xsID("handleCommand"), xsVar(0)); + } else { + #if XSNAP_TEST_RECORD + fxTestRecord(mxTestRecordJS | mxTestRecordParam, nsbuf + 1, nslen - 1); + #endif + xsVar(0) = xsStringBuffer(nsbuf + 1, nslen - 1); + xsVar(1) = xsCall1(xsGlobal, xsID("eval"), xsVar(0)); + } + } + xsCatch { + if (xsTypeOf(xsException) != xsUndefinedType) { + // fprintf(stderr, "%c: %s\n", command, xsToString(xsException)); + error = 1; + xsVar(1) = xsException; + xsException = xsUndefined; + } + } + } + fxRunLoop(machine); + meterIndex = xsEndCrank(machine); + { + if (error) { + xsStringValue message = xsToString(xsVar(1)); + writeError = fxWriteNetString(toParent, "!", message, strlen(message)); + // fprintf(stderr, "error: %d, writeError: %d %s\n", error, writeError, message); + } else { + char* response = NULL; + xsIntegerValue responseLength = 0; + // fprintf(stderr, "report: %d %s\n", xsTypeOf(report), xsToString(report)); + xsTry { + if (xsTypeOf(xsVar(1)) == xsReferenceType && xsHas(xsVar(1), xsID("result"))) { + xsVar(2) = xsGet(xsVar(1), xsID("result")); + } else { + xsVar(2) = xsVar(1); + } + // fprintf(stderr, "result: %d %s\n", xsTypeOf(result), xsToString(result)); + if (xsIsInstanceOf(xsVar(2), xsArrayBufferPrototype)) { + responseLength = xsGetArrayBufferLength(xsVar(2)); + response = xsToArrayBuffer(xsVar(2)); + } + } + xsCatch { + if (xsTypeOf(xsException) != xsUndefinedType) { + fprintf(stderr, "%c computing response %d %d: %s: %s\n", command, + xsTypeOf(xsVar(1)), xsTypeOf(xsVar(2)), + xsToString(xsVar(2)), + xsToString(xsException)); + xsException = xsUndefined; + } + } + // fprintf(stderr, "response of %d bytes\n", responseLength); + writeError = fxWriteOkay(toParent, meterIndex, response, responseLength); + } + } + xsEndHost(machine); + if (writeError != 0) { + fprintf(stderr, "%s\n", fxWriteNetStringError(writeError)); + c_exit(1); + } + break; + case 's': + case 'm': + xsBeginCrank(machine, gxCrankMeteringLimit); + path = nsbuf + 1; + xsBeginHost(machine); + { + xsVars(1); + xsTry { + // ISSUE: realpath necessary? realpath(x, x) doesn't seem to work. + dot = strrchr(path, '.'); + if (command == 'm') + fxRunModuleFile(the, path); + else + fxRunProgramFile(the, path); + } + xsCatch { + if (xsTypeOf(xsException) != xsUndefinedType) { + fprintf(stderr, "%s\n", xsToString(xsException)); + error = 1; + xsException = xsUndefined; + } + } + } + xsEndHost(machine); + fxRunLoop(machine); + meterIndex = xsEndCrank(machine); + if (error == 0) { + int writeError = fxWriteOkay(toParent, meterIndex, "", 0); + if (writeError != 0) { + fprintf(stderr, "%s\n", fxWriteNetStringError(writeError)); + c_exit(1); + } + } else { + // TODO: dynamically build error message including Exception message. + int writeError = fxWriteNetString(toParent, "!", "", 0); + if (writeError != 0) { + fprintf(stderr, "%s\n", fxWriteNetStringError(writeError)); + c_exit(1); + } + } + break; + + case 'w': + path = nsbuf + 1; + snapshot.stream = fopen(path, "wb"); + if (snapshot.stream) { + fxWriteSnapshot(machine, &snapshot); + fclose(snapshot.stream); + } + else + snapshot.error = errno; + if (snapshot.error) { + fprintf(stderr, "cannot write snapshot %s: %s\n", + path, strerror(snapshot.error)); + } + if (snapshot.error == 0) { + int writeError = fxWriteOkay(toParent, meterIndex, "", 0); + if (writeError != 0) { + fprintf(stderr, "%s\n", fxWriteNetStringError(writeError)); + c_exit(1); + } + } else { + // TODO: dynamically build error message including Exception message. + int writeError = fxWriteNetString(toParent, "!", "", 0); + if (writeError != 0) { + fprintf(stderr, "%s\n", fxWriteNetStringError(writeError)); + c_exit(1); + } + } + break; + case -1: + default: + done = 1; + break; + } + free(nsbuf); + } + xsBeginHost(machine); + { + if (xsTypeOf(xsException) != xsUndefinedType) { + fprintf(stderr, "%s\n", xsToString(xsException)); + error = 1; + } + } + xsEndHost(machine); + } + xsEndMetering(machine); + if (machine->abortStatus) + error = machine->abortStatus; + xsDeleteMachine(machine); + xsTerminateSharedCluster(); + return error; +} + +void xsBuildAgent(xsMachine* machine) +{ + xsBeginHost(machine); + + xsResult = xsNewHostFunction(xs_clearTimer, 1); + xsDefine(xsGlobal, xsID("clearImmediate"), xsResult, xsDontEnum); + xsResult = xsNewHostFunction(xs_setImmediate, 1); + xsDefine(xsGlobal, xsID("setImmediate"), xsResult, xsDontEnum); + +// xsResult = xsNewHostFunction(xs_clearTimer, 1); +// xsDefine(xsGlobal, xsID("clearInterval"), xsResult, xsDontEnum); +// xsResult = xsNewHostFunction(xs_setInterval, 1); +// xsDefine(xsGlobal, xsID("setInterval"), xsResult, xsDontEnum); +// +// xsResult = xsNewHostFunction(xs_clearTimer, 1); +// xsDefine(xsGlobal, xsID("clearTimeout"), xsResult, xsDontEnum); +// xsResult = xsNewHostFunction(xs_setTimeout, 1); +// xsDefine(xsGlobal, xsID("setTimeout"), xsResult, xsDontEnum); + + xsResult = xsNewHostFunction(xs_gc, 1); + xsDefine(xsGlobal, xsID("gc"), xsResult, xsDontEnum); + xsResult = xsNewHostFunction(xs_print, 1); + xsDefine(xsGlobal, xsID("print"), xsResult, xsDontEnum); + + xsResult = xsNewHostFunction(xs_issueCommand, 1); + xsDefine(xsGlobal, xsID("issueCommand"), xsResult, xsDontEnum); + + xsEndHost(machine); +} + +void xsFreezeAgent(xsMachine* machine) +{ + xsBeginHost(machine); + xsVars(2); + xsVar(0) = xsGet(xsGlobal, xsID("Object")); + + xsVar(1) = xsGet(xsGlobal, xsID("clearImmediate")); + xsCall2(xsVar(0), xsID("freeze"), xsVar(1), xsTrue); + xsVar(1) = xsGet(xsGlobal, xsID("setImmediate")); + xsCall2(xsVar(0), xsID("freeze"), xsVar(1), xsTrue); + +// xsVar(1) = xsGet(xsGlobal, xsID("clearInterval")); +// xsCall2(xsVar(0), xsID("freeze"), xsVar(1), xsTrue); +// xsVar(1) = xsGet(xsGlobal, xsID("setInterval")); +// xsCall2(xsVar(0), xsID("freeze"), xsVar(1), xsTrue); +// +// xsVar(1) = xsGet(xsGlobal, xsID("clearTimeout")); +// xsCall2(xsVar(0), xsID("freeze"), xsVar(1), xsTrue); +// xsVar(1) = xsGet(xsGlobal, xsID("setTimeout")); +// xsCall2(xsVar(0), xsID("freeze"), xsVar(1), xsTrue); + + xsVar(1) = xsGet(xsGlobal, xsID("gc")); + xsCall2(xsVar(0), xsID("freeze"), xsVar(1), xsTrue); + xsVar(1) = xsGet(xsGlobal, xsID("print")); + xsCall2(xsVar(0), xsID("freeze"), xsVar(1), xsTrue); + + xsVar(1) = xsGet(xsGlobal, xsID("issueCommand")); + xsCall2(xsVar(0), xsID("freeze"), xsVar(1), xsTrue); + + xsEndHost(machine); +} + +void xsPrintUsage() +{ + printf("xsnap [-h] [-f] [-i ] [-l ] [-s ] [-m] [-r ] [-s] [-v]\n"); + printf("\t-f: freeze the XS machine\n"); + printf("\t-h: print this help message\n"); + printf("\t-i : metering interval (default to 1)\n"); + printf("\t-l : metering limit (default to none)\n"); + printf("\t-s : parser buffer size, in kB (default to 8192)\n"); + printf("\t-r : read snapshot to create the XS machine\n"); + printf("\t-v: print XS version\n"); +} + +void xs_gc(xsMachine* the) +{ + xsCollectGarbage(); +} + +void xs_print(xsMachine* the) +{ + xsIntegerValue c = xsToInteger(xsArgc), i; +#if mxMetering + if (gxMeteringPrint) + fprintf(stdout, "[%u] ", xsGetCurrentMeter(the)); +#endif + for (i = 0; i < c; i++) { + if (i) + fprintf(stdout, " "); + fprintf(stdout, "%s", xsToString(xsArg(i))); + } + fprintf(stdout, "\n"); + fflush(stdout); +} + +// void xs_setInterval(xsMachine* the) +// { +// xsSetTimer(xsToNumber(xsArg(1)), 1); +// } +// +// void xs_setTimeout(xsMachine* the) +// { +// xsSetTimer(xsToNumber(xsArg(1)), 0); +// } + +void xs_setImmediate(xsMachine* the) +{ + xsSetTimer(0, 0); +} + +void xs_clearTimer(xsMachine* the) +{ + xsClearTimer(); +} + +static int fxReadNetString(FILE *inStream, char** dest, size_t* len) +{ + int code = 0; + char* buf = NULL; + + if (fscanf(inStream, "%9lu", len) < 1) { + /* >999999999 bytes is bad */ + code = 1; + } else if (fgetc(inStream) != ':') { + code = 2; + } else { + buf = malloc(*len + 1); /* malloc(0) is not portable */ + if (!buf) { + code = 3; + } else if (fread(buf, 1, *len, inStream) < *len) { + code = 4; + } else if (fgetc(inStream) != ',') { + code = 5; + } else { + *(buf + *len) = 0; + } + if (code != 0) { + free(buf); + } + *dest = buf; + } + return code; +} + +static char* fxReadNetStringError(int code) +{ + switch (code) { + case 0: return "OK"; + case 1: return "Cannot read netstring, reading length prefix, fscanf"; + case 2: return "Cannot read netstring, invalid delimiter or end of file, fgetc"; + case 3: return "Cannot read netstring, cannot allocate message buffer, malloc"; + case 4: return "Cannot read netstring, cannot read message body, fread"; + case 5: return "Cannot read netstring, cannot read trailer, fgetc"; + default: return "Cannot read netstring"; + } +} + +static int fxWriteOkay(FILE* outStream, xsUnsignedValue meterIndex, char* buf, size_t length) { + char prefix[32]; + // Prepend the meter usage to the reply. + snprintf(prefix, sizeof(prefix) - 1, ".%u\1", meterIndex); + return fxWriteNetString(outStream, prefix, buf, length); +} + +static int fxWriteNetString(FILE* outStream, char* prefix, char* buf, size_t length) +{ + if (fprintf(outStream, "%lu:%s", length + strlen(prefix), prefix) < 1) { + return 1; + } else if (fwrite(buf, 1, length, outStream) < length) { + return 2; + } else if (fputc(',', outStream) == EOF) { + return 3; + } else if (fflush(outStream) < 0) { + return 4; + } + + return 0; +} + +static char* fxWriteNetStringError(int code) +{ + switch (code) { + case 0: return "OK"; + case 1: return "Cannot write netstring, error writing length prefix"; + case 2: return "Cannot write netstring, error writing message body"; + case 3: return "Cannot write netstring, error writing terminator"; + case 4: return "Cannot write netstring, error flushing stream, fflush"; + default: return "Cannot write netstring"; + } +} + +static void xs_issueCommand(xsMachine *the) +{ + int argc = xsToInteger(xsArgc); + if (argc < 1) { + xsTypeError("expected ArrayBuffer"); + } + + size_t len = xsGetArrayBufferLength(xsArg(0)); + char* buf = xsToArrayBuffer(xsArg(0)); + int writeError = fxWriteNetString(toParent, "?", buf, len); + if (writeError != 0) { + xsUnknownError(fxWriteNetStringError(writeError)); + } + + // read netstring + int readError = fxReadNetString(fromParent, &buf, &len); + if (readError != 0) { + xsUnknownError(fxReadNetStringError(readError)); + } +#if XSNAP_TEST_RECORD + fxTestRecord(mxTestRecordJSON | mxTestRecordReply, buf, len); +#endif + xsResult = xsArrayBuffer(buf, len); + free(buf); +} + +#if XSNAP_TEST_RECORD + +static char directory[PATH_MAX]; +void fxTestRecordArgs(int argc, char* argv[]) +{ + struct timeval tv; + struct tm* tm_info; + gettimeofday(&tv, NULL); + char path[PATH_MAX]; + FILE* file; + mkdir("xsnap-tests", 0755); + tm_info = localtime(&tv.tv_sec); + strftime(path, sizeof(path), "%Y-%m-%d-%H-%M-%S", tm_info); + sprintf(directory, "xsnap-tests/%s-%3.3d", path, tv.tv_usec / 1000); + mkdir(directory, 0755); + sprintf(path, "%s/args.sh", directory); + file = fopen(path, "w"); + if (file) { + int argi; + for (argi = 0; argi < argc; argi++) + fprintf(file, " %s", argv[argi]); + fprintf(file, "\n"); + fclose(file); + } +} + +void fxTestRecord(int flags, void* buffer, size_t length) +{ + char path[PATH_MAX]; + FILE* file; + if (flags & mxTestRecordParam) { + sprintf(path, "%s/param-%d", directory, gxTestRecordReplyIndex); + gxTestRecordReplyIndex++; + } + else { + sprintf(path, "%s/reply-%d", directory, gxTestRecordParamIndex); + gxTestRecordParamIndex++; + } + if (flags & mxTestRecordJSON) + strcat(path, ".json"); + else + strcat(path, ".js"); + file = fopen(path, "wb"); + if (file) { + fwrite(buffer, 1, length, file); + fclose(file); + } +} + +#endif + +// Local Variables: +// tab-width: 4 +// c-basic-offset: 4 +// indent-tabs-mode: t +// End: +// vim: noet ts=4 sw=4 diff --git a/xsnap/sources/xsnap.c b/xsnap/sources/xsnap.c index f98339d..b134894 100644 --- a/xsnap/sources/xsnap.c +++ b/xsnap/sources/xsnap.c @@ -1,160 +1,45 @@ -#include "xsAll.h" -#include "xsScript.h" -#include "xsSnapshot.h" -#include "xs.h" - -extern txScript* fxLoadScript(txMachine* the, txString path, txUnsigned flags); - -typedef struct sxAliasIDLink txAliasIDLink; -typedef struct sxAliasIDList txAliasIDList; -typedef struct sxJob txJob; -typedef void (*txJobCallback)(txJob*); - -struct sxAliasIDLink { - txAliasIDLink* previous; - txAliasIDLink* next; - txInteger id; - txInteger flag; -}; - -struct sxAliasIDList { - txAliasIDLink* first; - txAliasIDLink* last; - txFlag* aliases; - txInteger errorCount; +#include "xsnap.h" + +#define SNAPSHOT_SIGNATURE "xsnap 1" + +static void xsBuildAgent(xsMachine* the); +static void xsFreezeAgent(xsMachine* machine); +static void xsPlayTest(xsMachine* the); +static void xsPrintUsage(); + +extern void xs_clearTimer(xsMachine* the); +static void xs_gc(xsMachine* the); +static void xs_issueCommand(xsMachine* the); +static void xs_print(xsMachine* the); +static void xs_setImmediate(xsMachine* the); +static void xs_setInterval(xsMachine* the); +static void xs_setTimeout(xsMachine* the); + +#define mxSnapshotCallbackCount 7 +xsCallback gxSnapshotCallbacks[mxSnapshotCallbackCount] = { + xs_issueCommand, + xs_clearTimer, + xs_print, + xs_setImmediate, + xs_gc, + xs_setInterval, + xs_setTimeout, }; -struct sxJob { - txJob* next; - txMachine* the; - txNumber when; - txJobCallback callback; - txSlot self; - txSlot function; - txSlot argument; - txNumber interval; -}; - -static void fxBuildAgent(xsMachine* the); -static txInteger fxCheckAliases(txMachine* the); -static void fxCheckAliasesError(txMachine* the, txAliasIDList* list, txFlag flag); -static void fxCheckEnvironmentAliases(txMachine* the, txSlot* environment, txAliasIDList* list); -static void fxCheckInstanceAliases(txMachine* the, txSlot* instance, txAliasIDList* list); -static void fxFreezeBuiltIns(txMachine* the); -static void fxPatchBuiltIns(txMachine* the); -static void fxPrintUsage(); -static void fxTestPlay(txMachine* the); - -static void fx_Array_prototype_meter(xsMachine* the); - -extern void fx_clearTimer(txMachine* the); -static void fx_destroyTimer(void* data); -static void fx_evalScript(xsMachine* the); -static void fx_gc(xsMachine* the); -static void fx_isPromiseJobQueueEmpty(xsMachine* the); -static void fx_issueCommand(xsMachine* the); -static void fx_markTimer(txMachine* the, void* it, txMarkRoot markRoot); -static void fx_print(xsMachine* the); -static void fx_setImmediate(txMachine* the); -static void fx_setInterval(txMachine* the); -static void fx_setTimeout(txMachine* the); -static void fx_setTimer(txMachine* the, txNumber interval, txBoolean repeat); -static void fx_setTimerCallback(txJob* job); - -static void fxFulfillModuleFile(txMachine* the); -static void fxRejectModuleFile(txMachine* the); -static void fxRunModuleFile(txMachine* the, txString path); -static void fxRunProgramFile(txMachine* the, txString path, txUnsigned flags); -static void fxRunLoop(txMachine* the); - -#define mxSnapshotCallbackCount 10 -txCallback gxSnapshotCallbacks[mxSnapshotCallbackCount] = { - fx_clearTimer, - fx_evalScript, - fx_gc, - fx_isPromiseJobQueueEmpty, - fx_issueCommand, - fx_print, - fx_setImmediate, - fx_setInterval, - fx_setTimeout, - fx_Array_prototype_meter, -}; - -enum { - XSL_MODULE_FLAG, - XSL_EXPORT_FLAG, - XSL_ENVIRONMENT_FLAG, - XSL_PROPERTY_FLAG, - XSL_ITEM_FLAG, - XSL_GETTER_FLAG, - XSL_SETTER_FLAG, - XSL_PROXY_HANDLER_FLAG, - XSL_PROXY_TARGET_FLAG, - XSL_GLOBAL_FLAG, -}; - -#define mxPushLink(name,ID,FLAG) \ - txAliasIDLink name = { C_NULL, C_NULL, ID, FLAG }; \ - name.previous = list->last; \ - if (list->last) \ - list->last->next = &name; \ - else \ - list->first = &name; \ - list->last = &name - -#define mxPopLink(name) \ - if (name.previous) \ - name.previous->next = C_NULL; \ - else \ - list->first = C_NULL; \ - list->last = name.previous - -static int fxSnapshopRead(void* stream, void* address, size_t size) +static int xsSnapshopRead(void* stream, void* address, size_t size) { return (fread(address, size, 1, stream) == 1) ? 0 : errno; } -static int fxSnapshopWrite(void* stream, void* address, size_t size) +static int xsSnapshopWrite(void* stream, void* address, size_t size) { return (fwrite(address, size, 1, stream) == 1) ? 0 : errno; } - -#define xsBeginMetering(_THE, _CALLBACK, _STEP) \ - do { \ - xsJump __HOST_JUMP__; \ - __HOST_JUMP__.nextJump = (_THE)->firstJump; \ - __HOST_JUMP__.stack = (_THE)->stack; \ - __HOST_JUMP__.scope = (_THE)->scope; \ - __HOST_JUMP__.frame = (_THE)->frame; \ - __HOST_JUMP__.environment = NULL; \ - __HOST_JUMP__.code = (_THE)->code; \ - __HOST_JUMP__.flag = 0; \ - (_THE)->firstJump = &__HOST_JUMP__; \ - if (setjmp(__HOST_JUMP__.buffer) == 0) { \ - fxBeginMetering(_THE, _CALLBACK, _STEP) - -#define xsEndMetering(_THE) \ - fxEndMetering(_THE); \ - } \ - (_THE)->stack = __HOST_JUMP__.stack, \ - (_THE)->scope = __HOST_JUMP__.scope, \ - (_THE)->frame = __HOST_JUMP__.frame, \ - (_THE)->code = __HOST_JUMP__.code, \ - (_THE)->firstJump = __HOST_JUMP__.nextJump; \ - break; \ - } while(1) - -#define xsPatchHostFunction(_FUNCTION,_PATCH) \ - (xsOverflow(-1), \ - fxPush(_FUNCTION), \ - fxPatchHostFunction(the, _PATCH), \ - fxPop()) -#define xsMeterHostFunction(_COUNT) \ - fxMeterHostFunction(the, _COUNT) +static xsBooleanValue gxMeteringPrint = 0; static xsUnsignedValue gxMeteringLimit = 0; -static xsBooleanValue fxMeteringCallback(xsMachine* the, xsUnsignedValue index) +#ifdef mxMetering +static xsBooleanValue xsMeteringCallback(xsMachine* the, xsUnsignedValue index) { if (index > gxMeteringLimit) { // fprintf(stderr, "too much computation\n"); @@ -163,7 +48,7 @@ static xsBooleanValue fxMeteringCallback(xsMachine* the, xsUnsignedValue index) // fprintf(stderr, "%d\n", index); return 1; } -static xsBooleanValue gxMeteringPrint = 0; +#endif int main(int argc, char* argv[]) { @@ -187,13 +72,13 @@ int main(int argc, char* argv[]) 1993, /* parserTableModulo */ }; xsCreation* creation = &_creation; - txSnapshot snapshot = { - "xsnap 1.0.2", - 11, + xsSnapshot snapshot = { + SNAPSHOT_SIGNATURE, + sizeof(SNAPSHOT_SIGNATURE) - 1, gxSnapshotCallbacks, mxSnapshotCallbackCount, - fxSnapshopRead, - fxSnapshopWrite, + xsSnapshopRead, + xsSnapshopWrite, NULL, 0, NULL, @@ -205,7 +90,7 @@ int main(int argc, char* argv[]) char* dot; if (argc == 1) { - fxPrintUsage(); + xsPrintUsage(); return 0; } for (argi = 1; argi < argc; argi++) { @@ -215,19 +100,19 @@ int main(int argc, char* argv[]) option = 1; else if (!strcmp(argv[argi], "-f")) { if (argw) { - fxPrintUsage(); + xsPrintUsage(); return 1; } freeze = 1; } else if (!strcmp(argv[argi], "-h")) - fxPrintUsage(); + xsPrintUsage(); else if (!strcmp(argv[argi], "-i")) { argi++; if (argi < argc) interval = atoi(argv[argi]); else { - fxPrintUsage(); + xsPrintUsage(); return 1; } } @@ -236,7 +121,7 @@ int main(int argc, char* argv[]) if (argi < argc) gxMeteringLimit = atoi(argv[argi]); else { - fxPrintUsage(); + xsPrintUsage(); return 1; } } @@ -249,7 +134,7 @@ int main(int argc, char* argv[]) if (argi < argc) argr = argi; else { - fxPrintUsage(); + xsPrintUsage(); return 1; } } @@ -257,23 +142,25 @@ int main(int argc, char* argv[]) option = 3; else if (!strcmp(argv[argi], "-t")) option = 4; - else if (!strcmp(argv[argi], "-v")) - printf("XS %d.%d.%d\n", XS_MAJOR_VERSION, XS_MINOR_VERSION, XS_PATCH_VERSION); + else if (!strcmp(argv[argi], "-v")) { + xsVersion(path, sizeof(path)); + printf("XS %s\n", path); + } else if (!strcmp(argv[argi], "-w")) { if (freeze) { - fxPrintUsage(); + xsPrintUsage(); return 1; } argi++; if (argi < argc) argw = argi; else { - fxPrintUsage(); + xsPrintUsage(); return 1; } } else { - fxPrintUsage(); + xsPrintUsage(); return 1; } } @@ -281,11 +168,11 @@ int main(int argc, char* argv[]) if (interval == 0) interval = 1; } - fxInitializeSharedCluster(); + xsInitializeSharedCluster(); if (argr) { snapshot.stream = fopen(argv[argr], "rb"); if (snapshot.stream) { - machine = fxReadSnapshot(&snapshot, "xsnap", NULL); + machine = xsReadSnapshot(&snapshot, "xsnap", NULL); fclose(snapshot.stream); } else @@ -297,22 +184,22 @@ int main(int argc, char* argv[]) } else { machine = xsCreateMachine(creation, "xsnap", NULL); - fxBuildAgent(machine); - fxPatchBuiltIns(machine); + xsBuildAgent(machine); } if (freeze) { - fxFreezeBuiltIns(machine); - fxShareMachine(machine); - fxCheckAliases(machine); + xsFreezeBuiltIns(machine); + xsFreezeAgent(machine); + xsShareMachine(machine); + xsCheckAliases(machine); machine = xsCloneMachine(creation, machine, "xsnap", NULL); } - xsBeginMetering(machine, fxMeteringCallback, interval); + xsBeginMetering(machine, xsMeteringCallback, interval); { xsBeginHost(machine); { xsVars(1); if (option == 4) { - fxTestPlay(the); + xsPlayTest(the); } else { for (argi = 1; argi < argc; argi++) { @@ -339,19 +226,19 @@ int main(int argc, char* argv[]) xsURIError("file not found: %s", argv[argi]); dot = strrchr(path, '.'); if (((option == 0) && dot && !c_strcmp(dot, ".mjs")) || (option == 2)) - fxRunModuleFile(the, path); + xsRunModuleFile(path); else - fxRunProgramFile(the, path, mxProgramFlag | mxDebugFlag); + xsRunProgramFile(path); } } } } xsEndHost(machine); - fxRunLoop(machine); + xsRunLoop(machine); if (argw) { snapshot.stream = fopen(argv[argw], "wb"); if (snapshot.stream) { - fxWriteSnapshot(machine, &snapshot); + xsWriteSnapshot(machine, &snapshot); fclose(snapshot.stream); } else @@ -362,366 +249,76 @@ int main(int argc, char* argv[]) } } xsEndMetering(machine); + if (machine->abortStatus) + error = machine->abortStatus; xsDeleteMachine(machine); - fxTerminateSharedCluster(); + xsTerminateSharedCluster(); return error; } -void fxBuildAgent(xsMachine* the) -{ - txSlot* slot; - mxPush(mxGlobal); - slot = fxLastProperty(the, fxToInstance(the, the->stack)); - slot = fxNextHostFunctionProperty(the, slot, fx_clearTimer, 1, xsID("clearImmediate"), XS_DONT_ENUM_FLAG); - slot = fxNextHostFunctionProperty(the, slot, fx_clearTimer, 1, xsID("clearInterval"), XS_DONT_ENUM_FLAG); - slot = fxNextHostFunctionProperty(the, slot, fx_clearTimer, 1, xsID("clearTimeout"), XS_DONT_ENUM_FLAG); - slot = fxNextHostFunctionProperty(the, slot, fx_evalScript, 1, xsID("evalScript"), XS_DONT_ENUM_FLAG); - slot = fxNextHostFunctionProperty(the, slot, fx_gc, 1, xsID("gc"), XS_DONT_ENUM_FLAG); - slot = fxNextHostFunctionProperty(the, slot, fx_isPromiseJobQueueEmpty, 1, xsID("isPromiseJobQueueEmpty"), XS_DONT_ENUM_FLAG); - slot = fxNextHostFunctionProperty(the, slot, fx_issueCommand, 1, xsID("issueCommand"), XS_DONT_ENUM_FLAG); - slot = fxNextHostFunctionProperty(the, slot, fx_print, 1, xsID("print"), XS_DONT_ENUM_FLAG); - slot = fxNextHostFunctionProperty(the, slot, fx_setImmediate, 1, xsID("setImmediate"), XS_DONT_ENUM_FLAG); - slot = fxNextHostFunctionProperty(the, slot, fx_setInterval, 1, xsID("setInterval"), XS_DONT_ENUM_FLAG); - slot = fxNextHostFunctionProperty(the, slot, fx_setTimeout, 1, xsID("setTimeout"), XS_DONT_ENUM_FLAG); - - mxPush(mxObjectPrototype); - fxNextHostFunctionProperty(the, fxLastProperty(the, fxNewObjectInstance(the)), fx_print, 1, xsID("log"), XS_DONT_ENUM_FLAG); - slot = fxNextSlotProperty(the, slot, the->stack, xsID("console"), XS_DONT_ENUM_FLAG); - mxPop(); - - mxPop(); -} - -txInteger fxCheckAliases(txMachine* the) -{ - txAliasIDList _list = { C_NULL, C_NULL }, *list = &_list; - txSlot* module = mxProgram.value.reference->next; //@@ - list->aliases = c_calloc(the->aliasCount, sizeof(txFlag)); - while (module) { - txSlot* export = mxModuleExports(module)->value.reference->next; - if (export) { - mxPushLink(moduleLink, module->ID, XSL_MODULE_FLAG); - while (export) { - txSlot* closure = export->value.export.closure; - if (closure) { - mxPushLink(exportLink, export->ID, XSL_EXPORT_FLAG); - if (closure->ID != XS_NO_ID) { - if (list->aliases[closure->ID] == 0) { - list->aliases[closure->ID] = 1; - fxCheckAliasesError(the, list, 0); - } - } - if (closure->kind == XS_REFERENCE_KIND) { - fxCheckInstanceAliases(the, closure->value.reference, list); - } - mxPopLink(exportLink); - } - export = export->next; - } - mxPopLink(moduleLink); - } - module = module->next; - } - { - txSlot* global = mxGlobal.value.reference->next->next; - while (global) { - if ((global->ID != mxID(_global)) && (global->ID != mxID(_globalThis))) { - mxPushLink(globalLink, global->ID, XSL_GLOBAL_FLAG); - if (global->kind == XS_REFERENCE_KIND) { - fxCheckInstanceAliases(the, global->value.reference, list); - } - mxPopLink(globalLink); - } - global = global->next; - } - } - { - fxCheckEnvironmentAliases(the, mxException.value.reference, list); - } - return list->errorCount; -} - -void fxCheckAliasesError(txMachine* the, txAliasIDList* list, txFlag flag) -{ - txAliasIDLink* link = list->first; - if (flag > 1) - fprintf(stderr, "### error"); - else - fprintf(stderr, "### warning"); - while (link) { - switch (link->flag) { - case XSL_PROPERTY_FLAG: fprintf(stderr, "."); break; - case XSL_ITEM_FLAG: fprintf(stderr, "["); break; - case XSL_GETTER_FLAG: fprintf(stderr, ".get "); break; - case XSL_SETTER_FLAG: fprintf(stderr, ".set "); break; - case XSL_ENVIRONMENT_FLAG: fprintf(stderr, "() "); break; - case XSL_PROXY_HANDLER_FLAG: fprintf(stderr, ".(handler)"); break; - case XSL_PROXY_TARGET_FLAG: fprintf(stderr, ".(target)"); break; - default: fprintf(stderr, ": "); break; - } - if (link->id < 0) { - if (link->id != XS_NO_ID) { - char* string = fxGetKeyName(the, link->id); - if (string) { - if (link->flag == XSL_MODULE_FLAG) { - char* dot = c_strrchr(string, '.'); - if (dot) { - *dot = 0; - fprintf(stderr, "\"%s\"", string); - *dot = '.'; - } - else - fprintf(stderr, "%s", string); - } - else if (link->flag == XSL_GLOBAL_FLAG) { - fprintf(stderr, "globalThis."); - fprintf(stderr, "%s", string); - } - else - fprintf(stderr, "%s", string); - } - else - fprintf(stderr, "%d", link->id); - } - } - else - fprintf(stderr, "%d", link->id); - if (link->flag == XSL_ITEM_FLAG) - fprintf(stderr, "]"); - link = link->next; - } - if (flag == 3) { - fprintf(stderr, ": generator\n"); - list->errorCount++; - } - else if (flag == 2) { - fprintf(stderr, ": regexp\n"); - list->errorCount++; - } - else if (flag) - fprintf(stderr, ": not frozen\n"); - else - fprintf(stderr, ": no const\n"); -} - -void fxCheckEnvironmentAliases(txMachine* the, txSlot* environment, txAliasIDList* list) -{ - txSlot* closure = environment->next; - if (environment->flag & XS_LEVEL_FLAG) - return; - environment->flag |= XS_LEVEL_FLAG; - if (environment->value.instance.prototype) - fxCheckEnvironmentAliases(the, environment->value.instance.prototype, list); - while (closure) { - if (closure->kind == XS_CLOSURE_KIND) { - txSlot* slot = closure->value.closure; - mxPushLink(closureLink, closure->ID, XSL_ENVIRONMENT_FLAG); - if (slot->ID != XS_NO_ID) { - if (list->aliases[slot->ID] == 0) { - list->aliases[slot->ID] = 1; - fxCheckAliasesError(the, list, 0); - } - } - if (slot->kind == XS_REFERENCE_KIND) { - fxCheckInstanceAliases(the, slot->value.reference, list); - } - mxPopLink(closureLink); - } - closure = closure->next; - } - //environment->flag &= ~XS_LEVEL_FLAG; -} - -void fxCheckInstanceAliases(txMachine* the, txSlot* instance, txAliasIDList* list) +void xsBuildAgent(xsMachine* machine) { - txSlot* property = instance->next; - if (instance->flag & XS_LEVEL_FLAG) - return; - instance->flag |= XS_LEVEL_FLAG; - if (instance->value.instance.prototype) { - mxPushLink(propertyLink, mxID(___proto__), XSL_PROPERTY_FLAG); - fxCheckInstanceAliases(the, instance->value.instance.prototype, list); - mxPopLink(propertyLink); - } - if (instance->ID != XS_NO_ID) { - if (list->aliases[instance->ID] == 0) { - list->aliases[instance->ID] = 1; - fxCheckAliasesError(the, list, 1); - } - } - while (property) { - if (property->kind == XS_ACCESSOR_KIND) { - if (property->value.accessor.getter) { - mxPushLink(propertyLink, property->ID, XSL_GETTER_FLAG); - fxCheckInstanceAliases(the, property->value.accessor.getter, list); - mxPopLink(propertyLink); - } - if (property->value.accessor.setter) { - mxPushLink(propertyLink, property->ID, XSL_SETTER_FLAG); - fxCheckInstanceAliases(the, property->value.accessor.setter, list); - mxPopLink(propertyLink); - } - } - else if (property->kind == XS_ARRAY_KIND) { - txSlot* item = property->value.array.address; - txInteger length = (txInteger)fxGetIndexSize(the, property); - while (length > 0) { - if (item->kind == XS_REFERENCE_KIND) { - mxPushLink(propertyLink, (txInteger)(item->next), XSL_ITEM_FLAG); - fxCheckInstanceAliases(the, item->value.reference, list); - mxPopLink(propertyLink); - } - item++; - length--; - } - } - else if ((property->kind == XS_CODE_KIND) || (property->kind == XS_CODE_X_KIND)) { - if (property->value.code.closures) - fxCheckEnvironmentAliases(the, property->value.code.closures, list); - } - else if (property->kind == XS_PROXY_KIND) { - if (property->value.proxy.handler) { - mxPushLink(propertyLink, XS_NO_ID, XSL_PROXY_HANDLER_FLAG); - fxCheckInstanceAliases(the, property->value.proxy.handler, list); - mxPopLink(propertyLink); - } - if (property->value.proxy.target) { - mxPushLink(propertyLink, XS_NO_ID, XSL_PROXY_TARGET_FLAG); - fxCheckInstanceAliases(the, property->value.proxy.target, list); - mxPopLink(propertyLink); - } - } - else if (property->kind == XS_REFERENCE_KIND) { - mxPushLink(propertyLink, property->ID, XSL_PROPERTY_FLAG); - fxCheckInstanceAliases(the, property->value.reference, list); - mxPopLink(propertyLink); - } - property = property->next; - } -// instance->flag &= ~XS_LEVEL_FLAG; -} - -void fxFreezeBuiltIns(txMachine* the) -{ -#define mxFreezeBuiltInCall \ - mxPush(mxObjectConstructor); \ - mxPushSlot(freeze); \ - mxCall() -#define mxFreezeBuiltInRun \ - mxPushBoolean(1); \ - mxRunCount(2); \ - mxPop() - - txSlot* freeze; - txInteger id; - - mxTemporary(freeze); - mxPush(mxObjectConstructor); - fxGetID(the, mxID(_freeze)); - mxPullSlot(freeze); + xsBeginHost(machine); - for (id = XS_SYMBOL_ID_COUNT; id < _Infinity; id++) { - mxFreezeBuiltInCall; mxPush(the->stackPrototypes[-1 - id]); mxFreezeBuiltInRun; - } - for (id = _Compartment; id < XS_INTRINSICS_COUNT; id++) { - mxFreezeBuiltInCall; mxPush(the->stackPrototypes[-1 - id]); mxFreezeBuiltInRun; - } - mxFreezeBuiltInCall; mxPush(mxGlobal); fxGetID(the, xsID("gc")); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxGlobal); fxGetID(the, xsID("evalScript")); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxGlobal); fxGetID(the, xsID("print")); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxGlobal); fxGetID(the, xsID("clearInterval")); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxGlobal); fxGetID(the, xsID("clearTimeout")); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxGlobal); fxGetID(the, xsID("setInterval")); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxGlobal); fxGetID(the, xsID("setTimeout")); mxFreezeBuiltInRun; + xsResult = xsNewHostFunction(xs_clearTimer, 1); + xsDefine(xsGlobal, xsID("clearImmediate"), xsResult, xsDontEnum); + xsResult = xsNewHostFunction(xs_setImmediate, 1); + xsDefine(xsGlobal, xsID("setImmediate"), xsResult, xsDontEnum); - mxFreezeBuiltInCall; mxPush(mxArgumentsSloppyPrototype); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxArgumentsStrictPrototype); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxArrayIteratorPrototype); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxAsyncFromSyncIteratorPrototype); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxAsyncFunctionPrototype); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxAsyncGeneratorFunctionPrototype); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxAsyncGeneratorPrototype); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxAsyncIteratorPrototype); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxGeneratorFunctionPrototype); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxGeneratorPrototype); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxHostPrototype); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxIteratorPrototype); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxMapEntriesIteratorPrototype); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxMapKeysIteratorPrototype); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxMapValuesIteratorPrototype); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxModulePrototype); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxRegExpStringIteratorPrototype); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxSetEntriesIteratorPrototype); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxSetKeysIteratorPrototype); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxSetValuesIteratorPrototype); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxStringIteratorPrototype); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxTransferPrototype); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxTypedArrayPrototype); mxFreezeBuiltInRun; - - mxFreezeBuiltInCall; mxPush(mxAssignObjectFunction); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxCopyObjectFunction); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxEnumeratorFunction); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxInitializeRegExpFunction); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxOnRejectedPromiseFunction); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxOnResolvedPromiseFunction); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPush(mxOnThenableFunction); mxFreezeBuiltInRun; + xsResult = xsNewHostFunction(xs_clearTimer, 1); + xsDefine(xsGlobal, xsID("clearInterval"), xsResult, xsDontEnum); + xsResult = xsNewHostFunction(xs_setInterval, 1); + xsDefine(xsGlobal, xsID("setInterval"), xsResult, xsDontEnum); - mxFreezeBuiltInCall; mxPushReference(mxArrayLengthAccessor.value.accessor.getter); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPushReference(mxArrayLengthAccessor.value.accessor.setter); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPushReference(mxStringAccessor.value.accessor.getter); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPushReference(mxStringAccessor.value.accessor.setter); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPushReference(mxProxyAccessor.value.accessor.getter); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPushReference(mxProxyAccessor.value.accessor.setter); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPushReference(mxTypedArrayAccessor.value.accessor.getter); mxFreezeBuiltInRun; - mxFreezeBuiltInCall; mxPushReference(mxTypedArrayAccessor.value.accessor.setter); mxFreezeBuiltInRun; + xsResult = xsNewHostFunction(xs_clearTimer, 1); + xsDefine(xsGlobal, xsID("clearTimeout"), xsResult, xsDontEnum); + xsResult = xsNewHostFunction(xs_setTimeout, 1); + xsDefine(xsGlobal, xsID("setTimeout"), xsResult, xsDontEnum); - mxFreezeBuiltInCall; mxPush(mxArrayPrototype); fxGetID(the, mxID(_Symbol_unscopables)); mxFreezeBuiltInRun; + xsResult = xsNewHostFunction(xs_gc, 1); + xsDefine(xsGlobal, xsID("gc"), xsResult, xsDontEnum); + xsResult = xsNewHostFunction(xs_print, 1); + xsDefine(xsGlobal, xsID("print"), xsResult, xsDontEnum); - mxFreezeBuiltInCall; mxPush(mxProgram); mxFreezeBuiltInRun; //@@ - mxFreezeBuiltInCall; mxPush(mxHosts); mxFreezeBuiltInRun; //@@ + xsResult = xsNewHostFunction(xs_issueCommand, 1); + xsDefine(xsGlobal, xsID("issueCommand"), xsResult, xsDontEnum); - mxPop(); -} - -void fx_Array_prototype_meter(xsMachine* the) -{ - xsIntegerValue length = xsToInteger(xsGet(xsThis, xsID("length"))); - xsMeterHostFunction(length); + xsEndHost(machine); } -void fxPatchBuiltIns(txMachine* machine) +void xsFreezeAgent(xsMachine* machine) { xsBeginHost(machine); xsVars(2); - xsVar(0) = xsGet(xsGlobal, xsID("Array")); - xsVar(0) = xsGet(xsVar(0), xsID("prototype")); - xsVar(1) = xsGet(xsVar(0), xsID("reverse")); - xsPatchHostFunction(xsVar(1), fx_Array_prototype_meter); - xsVar(1) = xsGet(xsVar(0), xsID("sort")); - xsPatchHostFunction(xsVar(1), fx_Array_prototype_meter); - xsEndHost(machine); -} + xsVar(0) = xsGet(xsGlobal, xsID("Object")); -void fxPrintUsage() -{ - printf("xsnap [-h] [-e] [-f] [i ] [-s] [-v] [-w ] strings...\n"); - printf("\t-e: eval strings\n"); - printf("\t-f: freeze the XS machine\n"); - printf("\t-h: print this help message\n"); - printf("\t-i : metering interval (default to 1)\n"); - printf("\t-l : metering limit (default to none)\n"); - printf("\t-m: strings are paths to modules\n"); - printf("\t-r : read snapshot to create the XS machine\n"); - printf("\t-s: strings are paths to scripts\n"); - printf("\t-v: print XS version\n"); - printf("\t-w : write snapshot of the XS machine at exit\n"); - printf("without -e, -m, -s:\n"); - printf("\tif the extension is .mjs, strings are paths to modules\n"); - printf("\telse strings are paths to scripts\n"); - printf("-f and -w are incompatible\n"); + xsVar(1) = xsGet(xsGlobal, xsID("clearImmediate")); + xsCall2(xsVar(0), xsID("freeze"), xsVar(1), xsTrue); + xsVar(1) = xsGet(xsGlobal, xsID("setImmediate")); + xsCall2(xsVar(0), xsID("freeze"), xsVar(1), xsTrue); + + xsVar(1) = xsGet(xsGlobal, xsID("clearInterval")); + xsCall2(xsVar(0), xsID("freeze"), xsVar(1), xsTrue); + xsVar(1) = xsGet(xsGlobal, xsID("setInterval")); + xsCall2(xsVar(0), xsID("freeze"), xsVar(1), xsTrue); + + xsVar(1) = xsGet(xsGlobal, xsID("clearTimeout")); + xsCall2(xsVar(0), xsID("freeze"), xsVar(1), xsTrue); + xsVar(1) = xsGet(xsGlobal, xsID("setTimeout")); + xsCall2(xsVar(0), xsID("freeze"), xsVar(1), xsTrue); + + xsVar(1) = xsGet(xsGlobal, xsID("gc")); + xsCall2(xsVar(0), xsID("freeze"), xsVar(1), xsTrue); + xsVar(1) = xsGet(xsGlobal, xsID("print")); + xsCall2(xsVar(0), xsID("freeze"), xsVar(1), xsTrue); + + xsVar(1) = xsGet(xsGlobal, xsID("issueCommand")); + xsCall2(xsVar(0), xsID("freeze"), xsVar(1), xsTrue); + + xsEndHost(machine); } -void fxTestPlay(xsMachine* the) +void xsPlayTest(xsMachine* the) { int index = 0; char* extensions[2] = { ".js", ".json" }; @@ -766,34 +363,37 @@ void fxTestPlay(xsMachine* the) } } -void fx_evalScript(xsMachine* the) +void xsPrintUsage() { - txSlot* realm = mxProgram.value.reference->next->value.module.realm; - txStringStream aStream; - aStream.slot = mxArgv(0); - aStream.offset = 0; - aStream.size = c_strlen(fxToString(the, mxArgv(0))); - fxRunScript(the, fxParseScript(the, &aStream, fxStringGetter, mxProgramFlag | mxDebugFlag), mxRealmGlobal(realm), C_NULL, mxRealmClosures(realm)->value.reference, C_NULL, mxProgram.value.reference); - mxPullSlot(mxResult); + printf("xsnap [-h] [-e] [-f] [i ] [-s] [-v] [-w ] strings...\n"); + printf("\t-e: eval strings\n"); + printf("\t-f: freeze the XS machine\n"); + printf("\t-h: print this help message\n"); + printf("\t-i : metering interval (default to 1)\n"); + printf("\t-l : metering limit (default to none)\n"); + printf("\t-m: strings are paths to modules\n"); + printf("\t-r : read snapshot to create the XS machine\n"); + printf("\t-s: strings are paths to scripts\n"); + printf("\t-v: print XS version\n"); + printf("\t-w : write snapshot of the XS machine at exit\n"); + printf("without -e, -m, -s:\n"); + printf("\tif the extension is .mjs, strings are paths to modules\n"); + printf("\telse strings are paths to scripts\n"); + printf("-f and -w are incompatible\n"); } -void fx_gc(xsMachine* the) +void xs_gc(xsMachine* the) { xsCollectGarbage(); } -void fx_isPromiseJobQueueEmpty(txMachine* the) -{ - xsResult = (the->promiseJobs) ? xsFalse : xsTrue; -} - -void fx_issueCommand(txMachine* the) +void xs_issueCommand(xsMachine* the) { static int index = 0; char path[PATH_MAX]; FILE* file; size_t length; - sprintf(path, "reply-%d.js", index); + sprintf(path, "reply-%d.json", index); fprintf(stderr, "### %s\n", path); file = fopen(path, "rb"); if (file) { @@ -807,11 +407,13 @@ void fx_issueCommand(txMachine* the) index++; } -void fx_print(xsMachine* the) +void xs_print(xsMachine* the) { xsIntegerValue c = xsToInteger(xsArgc), i; +#ifdef mxMetering if (gxMeteringPrint) - fprintf(stdout, "[%u] ", the->meterIndex); + fprintf(stdout, "[%u] ", xsGetCurrentMeter(the)); +#endif for (i = 0; i < c; i++) { if (i) fprintf(stdout, " "); @@ -820,413 +422,26 @@ void fx_print(xsMachine* the) fprintf(stdout, "\n"); } -void fx_setImmediate(txMachine* the) +void xs_setImmediate(xsMachine* the) { - fx_setTimer(the, 0, 0); + xsSetTimer(0, 0); } -void fx_setInterval(txMachine* the) +void xs_setInterval(xsMachine* the) { - fx_setTimer(the, fxToNumber(the, mxArgv(1)), 1); + xsSetTimer(xsToNumber(xsArg(1)), 1); } -void fx_setTimeout(txMachine* the) +void xs_setTimeout(xsMachine* the) { - fx_setTimer(the, fxToNumber(the, mxArgv(1)), 0); + xsSetTimer(xsToNumber(xsArg(1)), 0); } -static txHostHooks gxTimerHooks = { - fx_destroyTimer, - fx_markTimer -}; - -void fx_clearTimer(xsMachine* the) -{ - txJob* job = xsGetHostData(xsArg(0)); - if (job) { - xsForget(job->self); - xsSetHostData(xsArg(0), NULL); - job->the = NULL; - } -} - -void fx_destroyTimer(void* data) -{ -} - -void fx_markTimer(txMachine* the, void* it, txMarkRoot markRoot) -{ - txJob* job = it; - if (job) { - (*markRoot)(the, &job->function); - (*markRoot)(the, &job->argument); - } -} - -void fx_setTimer(txMachine* the, txNumber interval, txBoolean repeat) -{ - c_timeval tv; - txJob* job; - txJob** address = (txJob**)&(the->timerJobs); - while ((job = *address)) - address = &(job->next); - job = *address = malloc(sizeof(txJob)); - c_memset(job, 0, sizeof(txJob)); - job->the = the; - job->callback = fx_setTimerCallback; - c_gettimeofday(&tv, NULL); - if (repeat) - job->interval = interval; - job->when = ((txNumber)(tv.tv_sec) * 1000.0) + ((txNumber)(tv.tv_usec) / 1000.0) + interval; - job->self = xsNewHostObject(NULL); - job->function = xsArg(0); - if (xsToInteger(xsArgc) > 2) - job->argument = xsArg(2); - else - job->argument = xsUndefined; - xsSetHostData(job->self, job); - xsSetHostHooks(job->self, &gxTimerHooks); - xsRemember(job->self); - xsResult = xsAccess(job->self); -} - -void fx_setTimerCallback(txJob* job) -{ - xsMachine* machine = job->the; - xsBeginHost(machine); - { - xsCallFunction1(job->function, xsUndefined, job->argument); - } - xsEndHost(machine); -} - -/* PLATFORM */ - -void fxAbort(txMachine* the, int status) +void xs_clearTimer(xsMachine* the) { - switch (status) { - case XS_STACK_OVERFLOW_EXIT: - xsLog("stack overflow\n"); -#ifdef mxDebug - fxDebugger(the, (char *)__FILE__, __LINE__); -#endif - fxExitToHost(the); - break; - case XS_NOT_ENOUGH_MEMORY_EXIT: - xsLog("memory full\n"); -#ifdef mxDebug - fxDebugger(the, (char *)__FILE__, __LINE__); -#endif - fxExitToHost(the); - break; - case XS_NO_MORE_KEYS_EXIT: - xsLog("not enough keys\n"); -#ifdef mxDebug - fxDebugger(the, (char *)__FILE__, __LINE__); -#endif - fxExitToHost(the); - break; - case XS_TOO_MUCH_COMPUTATION_EXIT: - xsLog("too much computation\n"); -#ifdef mxDebug - fxDebugger(the, (char *)__FILE__, __LINE__); -#endif - fxExitToHost(the); - break; - case XS_UNHANDLED_EXCEPTION_EXIT: - case XS_UNHANDLED_REJECTION_EXIT: - xsLog("%s\n", xsToString(xsException)); - xsException = xsUndefined; - break; - default: - c_exit(status); - break; - } -} - -void fxCreateMachinePlatform(txMachine* the) -{ -#ifdef mxDebug - the->connection = mxNoSocket; -#endif - the->promiseJobs = 0; - the->timerJobs = NULL; -} - -void fxDeleteMachinePlatform(txMachine* the) -{ -} - -void fxQueuePromiseJobs(txMachine* the) -{ - the->promiseJobs = 1; -} - -void fxRunLoop(txMachine* the) -{ - c_timeval tv; - txNumber when; - txJob* job; - txJob** address; - for (;;) { - while (the->promiseJobs) { - while (the->promiseJobs) { - the->promiseJobs = 0; - fxRunPromiseJobs(the); - } - fxEndJob(the); - } - c_gettimeofday(&tv, NULL); - when = ((txNumber)(tv.tv_sec) * 1000.0) + ((txNumber)(tv.tv_usec) / 1000.0); - address = (txJob**)&(the->timerJobs); - if (!*address) - break; - while ((job = *address)) { - if (job->the) { - if (job->when <= when) { - (*job->callback)(job); - if (job->the) { - if (job->interval) { - job->when += job->interval; - } - else { - xsBeginHost(job->the); - xsResult = xsAccess(job->self); - xsForget(job->self); - xsSetHostData(xsResult, NULL); - xsEndHost(job->the); - job->the = NULL; - } - } - break; // to run promise jobs queued by the timer in the same "tick" - } - address = &(job->next); - } - else { - *address = job->next; - c_free(job); - } - } - } + xsClearTimer(); } -void fxFulfillModuleFile(txMachine* the) -{ - xsException = xsUndefined; -} - -void fxRejectModuleFile(txMachine* the) -{ - xsException = xsArg(0); -} - -void fxRunModuleFile(txMachine* the, txString path) -{ - txSlot* realm = mxProgram.value.reference->next->value.module.realm; - mxPushStringC(path); - fxRunImport(the, realm, XS_NO_ID); - mxDub(); - fxGetID(the, mxID(_then)); - mxCall(); - fxNewHostFunction(the, fxFulfillModuleFile, 1, XS_NO_ID); - fxNewHostFunction(the, fxRejectModuleFile, 1, XS_NO_ID); - mxRunCount(2); - mxPop(); -} - -void fxRunProgramFile(txMachine* the, txString path, txUnsigned flags) -{ - txSlot* realm = mxProgram.value.reference->next->value.module.realm; - txScript* script = fxLoadScript(the, path, flags); - mxModuleInstanceInternal(mxProgram.value.reference)->value.module.id = fxID(the, path); - fxRunScript(the, script, mxRealmGlobal(realm), C_NULL, mxRealmClosures(realm)->value.reference, C_NULL, mxProgram.value.reference); - mxPullSlot(mxResult); -} - -/* DEBUG */ - -#ifdef mxDebug - -void fxConnect(txMachine* the) -{ - char name[256]; - char* colon; - int port; - struct sockaddr_in address; -#if mxWindows - if (GetEnvironmentVariable("XSBUG_HOST", name, sizeof(name))) { -#else - colon = getenv("XSBUG_HOST"); - if ((colon) && (c_strlen(colon) + 1 < sizeof(name))) { - c_strcpy(name, colon); -#endif - colon = strchr(name, ':'); - if (colon == NULL) - port = 5002; - else { - *colon = 0; - colon++; - port = strtol(colon, NULL, 10); - } - } - else { - strcpy(name, "localhost"); - port = 5002; - } - memset(&address, 0, sizeof(address)); - address.sin_family = AF_INET; - address.sin_addr.s_addr = inet_addr(name); - if (address.sin_addr.s_addr == INADDR_NONE) { - struct hostent *host = gethostbyname(name); - if (!host) - return; - memcpy(&(address.sin_addr), host->h_addr, host->h_length); - } - address.sin_port = htons(port); -#if mxWindows -{ - WSADATA wsaData; - unsigned long flag; - if (WSAStartup(0x202, &wsaData) == SOCKET_ERROR) - return; - the->connection = socket(AF_INET, SOCK_STREAM, 0); - if (the->connection == INVALID_SOCKET) - return; - flag = 1; - ioctlsocket(the->connection, FIONBIO, &flag); - if (connect(the->connection, (struct sockaddr*)&address, sizeof(address)) == SOCKET_ERROR) { - if (WSAEWOULDBLOCK == WSAGetLastError()) { - fd_set fds; - struct timeval timeout = { 2, 0 }; // 2 seconds, 0 micro-seconds - FD_ZERO(&fds); - FD_SET(the->connection, &fds); - if (select(0, NULL, &fds, NULL, &timeout) == 0) - goto bail; - if (!FD_ISSET(the->connection, &fds)) - goto bail; - } - else - goto bail; - } - flag = 0; - ioctlsocket(the->connection, FIONBIO, &flag); -} -#else -{ - int flag; - the->connection = socket(AF_INET, SOCK_STREAM, 0); - if (the->connection <= 0) - goto bail; - c_signal(SIGPIPE, SIG_IGN); -#if mxMacOSX - { - int set = 1; - setsockopt(the->connection, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)); - } -#endif - flag = fcntl(the->connection, F_GETFL, 0); - fcntl(the->connection, F_SETFL, flag | O_NONBLOCK); - if (connect(the->connection, (struct sockaddr*)&address, sizeof(address)) < 0) { - if (errno == EINPROGRESS) { - fd_set fds; - struct timeval timeout = { 2, 0 }; // 2 seconds, 0 micro-seconds - int error = 0; - unsigned int length = sizeof(error); - FD_ZERO(&fds); - FD_SET(the->connection, &fds); - if (select(the->connection + 1, NULL, &fds, NULL, &timeout) == 0) - goto bail; - if (!FD_ISSET(the->connection, &fds)) - goto bail; - if (getsockopt(the->connection, SOL_SOCKET, SO_ERROR, &error, &length) < 0) - goto bail; - if (error) - goto bail; - } - else - goto bail; - } - fcntl(the->connection, F_SETFL, flag); - c_signal(SIGPIPE, SIG_DFL); -} -#endif - return; -bail: - fxDisconnect(the); -} - -void fxDisconnect(txMachine* the) -{ -#if mxWindows - if (the->connection != INVALID_SOCKET) { - closesocket(the->connection); - the->connection = INVALID_SOCKET; - } - WSACleanup(); -#else - if (the->connection >= 0) { - close(the->connection); - the->connection = -1; - } -#endif -} - -txBoolean fxIsConnected(txMachine* the) -{ - return (the->connection != mxNoSocket) ? 1 : 0; -} - -txBoolean fxIsReadable(txMachine* the) -{ - return 0; -} - -void fxReceive(txMachine* the) -{ - int count; - if (the->connection != mxNoSocket) { -#if mxWindows - count = recv(the->connection, the->debugBuffer, sizeof(the->debugBuffer) - 1, 0); - if (count < 0) - fxDisconnect(the); - else - the->debugOffset = count; -#else - again: - count = read(the->connection, the->debugBuffer, sizeof(the->debugBuffer) - 1); - if (count < 0) { - if (errno == EINTR) - goto again; - else - fxDisconnect(the); - } - else - the->debugOffset = count; -#endif - } - the->debugBuffer[the->debugOffset] = 0; -} - -void fxSend(txMachine* the, txBoolean more) -{ - if (the->connection != mxNoSocket) { -#if mxWindows - if (send(the->connection, the->echoBuffer, the->echoOffset, 0) <= 0) - fxDisconnect(the); -#else - again: - if (write(the->connection, the->echoBuffer, the->echoOffset) <= 0) { - if (errno == EINTR) - goto again; - else - fxDisconnect(the); - } -#endif - } -} - -#endif /* mxDebug */ - diff --git a/xsnap/sources/xsnap.h b/xsnap/sources/xsnap.h index f3c2ddd..7bbaf34 100644 --- a/xsnap/sources/xsnap.h +++ b/xsnap/sources/xsnap.h @@ -1,84 +1,136 @@ #ifndef __XSNAP__ #define __XSNAP__ -#if defined(_MSC_VER) - #if defined(_M_IX86) || defined(_M_X64) - #undef mxLittleEndian - #define mxLittleEndian 1 - #undef mxWindows - #define mxWindows 1 - #define mxExport extern - #define mxImport extern - #define XS_FUNCTION_NORETURN - #else - #error unknown Microsoft compiler - #endif -#elif defined(__GNUC__) - #if defined(__i386__) || defined(i386) || defined(intel) || defined(arm) || defined(__arm__) || defined(__k8__) || defined(__x86_64__) || defined(__aarch64__) - #undef mxLittleEndian - #define mxLittleEndian 1 - #if defined(__linux__) || defined(linux) - #undef mxLinux - #define mxLinux 1 - #else - #undef mxMacOSX - #define mxMacOSX 1 - #endif - #define mxExport extern - #define mxImport extern - #define XS_FUNCTION_NORETURN __attribute__((noreturn)) - #else - #error unknown GNU compiler - #endif -#else - #error unknown compiler +#include "xs.h" + +typedef struct xsSnapshotRecord xsSnapshot; + +struct xsSnapshotRecord { + char* signature; + int signatureLength; + xsCallback* callbacks; + int callbacksLength; + int (*read)(void* stream, void* address, size_t size); + int (*write)(void* stream, void* address, size_t size); + void* stream; + int error; + void* firstChunk; + void* firstProjection; + void* firstSlot; +}; + +#define xsInitializeSharedCluster() \ + fxInitializeSharedCluster() +#define xsTerminateSharedCluster() \ + fxTerminateSharedCluster() + +#ifdef mxMetering + +#define xsBeginMetering(_THE, _CALLBACK, _STEP) \ + do { \ + xsJump __HOST_JUMP__; \ + __HOST_JUMP__.nextJump = (_THE)->firstJump; \ + __HOST_JUMP__.stack = (_THE)->stack; \ + __HOST_JUMP__.scope = (_THE)->scope; \ + __HOST_JUMP__.frame = (_THE)->frame; \ + __HOST_JUMP__.environment = NULL; \ + __HOST_JUMP__.code = (_THE)->code; \ + __HOST_JUMP__.flag = 0; \ + (_THE)->firstJump = &__HOST_JUMP__; \ + if (setjmp(__HOST_JUMP__.buffer) == 0) { \ + fxBeginMetering(_THE, _CALLBACK, _STEP) + +#define xsEndMetering(_THE) \ + fxEndMetering(_THE); \ + } \ + (_THE)->stack = __HOST_JUMP__.stack, \ + (_THE)->scope = __HOST_JUMP__.scope, \ + (_THE)->frame = __HOST_JUMP__.frame, \ + (_THE)->code = __HOST_JUMP__.code, \ + (_THE)->firstJump = __HOST_JUMP__.nextJump; \ + break; \ + } while(1) + +#define xsPatchHostFunction(_FUNCTION,_PATCH) \ + (xsOverflow(-1), \ + fxPush(_FUNCTION), \ + fxPatchHostFunction(the, _PATCH), \ + fxPop()) +#define xsMeterHostFunction(_COUNT) \ + fxMeterHostFunction(the, _COUNT) + +#define xsGetCurrentMeter(_THE) \ + fxGetCurrentMeter(_THE) +#define xsSetCurrentMeter(_THE, _VALUE) \ + fxSetCurrentMeter(_THE, _VALUE) + +#else + #define xsBeginMetering(_THE, _CALLBACK, _STEP) + #define xsEndMetering(_THE) + #define xsPatchHostFunction(_FUNCTION,_PATCH) + #define xsMeterHostFunction(_COUNT) (void)(_COUNT) + #define xsGetCurrentMeter(_THE) 0 + #define xsSetCurrentMeter(_THE, _VALUE) #endif -#if mxWindows - #define _USE_MATH_DEFINES - #define WIN32_LEAN_AND_MEAN - #define _WINSOCK_DEPRECATED_NO_WARNINGS +#define xsReadSnapshot(_SNAPSHOT, _NAME, _CONTEXT) \ + fxReadSnapshot(_SNAPSHOT, _NAME, _CONTEXT) +#define xsWriteSnapshot(_THE, _SNAPSHOT) \ + fxWriteSnapshot(_THE, _SNAPSHOT) + +#define xsCheckAliases(_THE) \ + fxCheckAliases(_THE) +#define xsFreezeBuiltIns(_THE) \ + fxFreezeBuiltIns(_THE) + +#define xsRunModuleFile(_PATH) \ + fxRunModuleFile(the, _PATH) +#define xsRunProgramFile(_PATH) \ + fxRunProgramFile(the, _PATH) +#define xsRunLoop(_THE) \ + fxRunLoop(_THE) + +#define xsClearTimer() \ + fxClearTimer(the) +#define xsSetTimer(_INTERVAL, _REPEAT) \ + fxSetTimer(the, _INTERVAL, _REPEAT) + +#define xsVersion(_BUFFER, _SIZE) \ + fxVersion(_BUFFER, _SIZE) + +#ifdef __cplusplus +extern "C" { #endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if mxWindows - #include - typedef SOCKET txSocket; - #define mxNoSocket INVALID_SOCKET -#else - #include - #include - #include - #include - #include - #include - typedef int txSocket; - #define mxNoSocket -1 - #define mxUseGCCAtomics 1 - #define mxUsePOSIXThreads 1 + +extern void fxInitializeSharedCluster(); +extern void fxTerminateSharedCluster(); + +#ifdef mxMetering +mxImport void fxBeginMetering(xsMachine* the, xsBooleanValue (*callback)(xsMachine*, xsUnsignedValue), xsUnsignedValue interval); +mxImport void fxEndMetering(xsMachine* the); +mxImport void fxMeterHostFunction(xsMachine* the, xsUnsignedValue count); +mxImport void fxPatchHostFunction(xsMachine* the, xsCallback patch); +mxImport xsUnsignedValue fxGetCurrentMeter(xsMachine* the); +mxImport void fxSetCurrentMeter(xsMachine* the, xsUnsignedValue value); +#endif + +mxImport xsMachine* fxReadSnapshot(xsSnapshot* snapshot, xsStringValue theName, void* theContext); +mxImport int fxWriteSnapshot(xsMachine* the, xsSnapshot* snapshot); + +mxImport xsIntegerValue fxCheckAliases(xsMachine* the); +mxImport void fxFreezeBuiltIns(xsMachine* the); + +mxImport void fxRunModuleFile(xsMachine* the, xsStringValue path); +mxImport void fxRunProgramFile(xsMachine* the, xsStringValue path); +mxImport void fxRunLoop(xsMachine* the); + +mxImport void fxClearTimer(xsMachine* the); +mxImport void fxSetTimer(xsMachine* the, xsNumberValue interval, xsBooleanValue repeat); + +mxImport void fxVersion(xsStringValue theBuffer, xsUnsignedValue theSize); + +#ifdef __cplusplus +} #endif -#define mxMachinePlatform \ - txSocket connection; \ - int promiseJobs; \ - void* timerJobs; \ - void* waiterCondition; \ - void* waiterData; \ - txMachine* waiterLink; - -#define mxUseDefaultBuildKeys 1 -#define mxUseDefaultChunkAllocation 1 -#define mxUseDefaultSlotAllocation 1 -#define mxUseDefaultFindModule 1 -#define mxUseDefaultLoadModule 1 -#define mxUseDefaultParseScript 1 -#define mxUseDefaultSharedChunks 1 #endif /* __XSNAP__ */ diff --git a/xsnap/sources/xsnapPlatform.c b/xsnap/sources/xsnapPlatform.c new file mode 100644 index 0000000..b974084 --- /dev/null +++ b/xsnap/sources/xsnapPlatform.c @@ -0,0 +1,793 @@ +#include "xsAll.h" +#include "xsScript.h" +#include "xsSnapshot.h" + +extern txScript* fxLoadScript(txMachine* the, txString path, txUnsigned flags); + +mxExport txInteger fxCheckAliases(txMachine* the); +mxExport void fxFreezeBuiltIns(txMachine* the); + +mxExport void fxRunModuleFile(txMachine* the, txString path); +mxExport void fxRunProgramFile(txMachine* the, txString path); +mxExport void fxRunLoop(txMachine* the); + +mxExport void fxClearTimer(txMachine* the); +mxExport void fxSetTimer(txMachine* the, txNumber interval, txBoolean repeat); + +mxExport void fxVersion(txString theBuffer, txSize theSize); +#ifdef mxMetering +mxExport txUnsigned fxGetCurrentMeter(txMachine* the); +mxExport void fxSetCurrentMeter(txMachine* the, txUnsigned value); +#endif + +typedef struct sxJob txJob; + +struct sxJob { + txJob* next; + txMachine* the; + txNumber when; + txSlot self; + txSlot function; + txSlot argument; + txNumber interval; +}; + +static void fxFulfillModuleFile(txMachine* the); +static void fxRejectModuleFile(txMachine* the); + +static void fxDestroyTimer(void* data); +static void fxMarkTimer(txMachine* the, void* it, txMarkRoot markRoot); + +static txHostHooks gxTimerHooks = { + fxDestroyTimer, + fxMarkTimer +}; + +void fxClearTimer(txMachine* the) +{ + txJob* job = fxGetHostData(the, mxArgv(0)); + if (job) { + fxForget(the, &job->self); + fxSetHostData(the, mxArgv(0), NULL); + job->the = NULL; + } +} + +void fxDestroyTimer(void* data) +{ +} + +void fxMarkTimer(txMachine* the, void* it, txMarkRoot markRoot) +{ + txJob* job = it; + if (job) { + (*markRoot)(the, &job->function); + (*markRoot)(the, &job->argument); + } +} + +void fxSetTimer(txMachine* the, txNumber interval, txBoolean repeat) +{ + c_timeval tv; + txJob* job; + txJob** address = (txJob**)&(the->timerJobs); + while ((job = *address)) + address = &(job->next); + job = *address = malloc(sizeof(txJob)); + c_memset(job, 0, sizeof(txJob)); + job->the = the; + c_gettimeofday(&tv, NULL); + if (repeat) + job->interval = interval; + job->when = ((txNumber)(tv.tv_sec) * 1000.0) + ((txNumber)(tv.tv_usec) / 1000.0) + interval; + fxNewHostObject(the, NULL); + mxPull(job->self); + job->function = *mxArgv(0); + if (mxArgc > 2) + job->argument = *mxArgv(2); + else + job->argument = mxUndefined; + fxSetHostData(the, &job->self, job); + fxSetHostHooks(the, &job->self, &gxTimerHooks); + fxRemember(the, &job->self); + fxAccess(the, &job->self); + *mxResult = the->scratch; +} + +/* PLATFORM */ + +void fxAbort(txMachine* the, int status) +{ + switch (status) { + case XS_STACK_OVERFLOW_EXIT: + fxReport(the, "stack overflow\n"); +#ifdef mxDebug + fxDebugger(the, (char *)__FILE__, __LINE__); +#endif + the->abortStatus = status; + fxExitToHost(the); + break; + case XS_NOT_ENOUGH_MEMORY_EXIT: + fxReport(the, "memory full\n"); +#ifdef mxDebug + fxDebugger(the, (char *)__FILE__, __LINE__); +#endif + the->abortStatus = status; + fxExitToHost(the); + break; + case XS_NO_MORE_KEYS_EXIT: + fxReport(the, "not enough keys\n"); +#ifdef mxDebug + fxDebugger(the, (char *)__FILE__, __LINE__); +#endif + the->abortStatus = status; + fxExitToHost(the); + break; + case XS_TOO_MUCH_COMPUTATION_EXIT: + fxReport(the, "too much computation\n"); +#ifdef mxDebug + fxDebugger(the, (char *)__FILE__, __LINE__); +#endif + the->abortStatus = status; + fxExitToHost(the); + break; + case XS_UNHANDLED_EXCEPTION_EXIT: + fxReport(the, "unhandled exception: %s\n", fxToString(the, &mxException)); + mxException = mxUndefined; + break; + case XS_UNHANDLED_REJECTION_EXIT: + fxReport(the, "unhandled rejection: %s\n", fxToString(the, &mxException)); + mxException = mxUndefined; + break; + default: + c_exit(status); + break; + } +} + +void fxCreateMachinePlatform(txMachine* the) +{ +#ifdef mxDebug + the->connection = mxNoSocket; +#endif + the->abortStatus = 0; + the->promiseJobs = 0; + the->timerJobs = NULL; +} + +void fxDeleteMachinePlatform(txMachine* the) +{ +} + +void fxQueuePromiseJobs(txMachine* the) +{ + the->promiseJobs = 1; +} + +void fxRunLoop(txMachine* the) +{ + c_timeval tv; + txNumber when; + txJob* job; + txJob** address; + for (;;) { + while (the->promiseJobs) { + while (the->promiseJobs) { + the->promiseJobs = 0; + fxRunPromiseJobs(the); + } + fxEndJob(the); + } + c_gettimeofday(&tv, NULL); + when = ((txNumber)(tv.tv_sec) * 1000.0) + ((txNumber)(tv.tv_usec) / 1000.0); + address = (txJob**)&(the->timerJobs); + if (!*address) + break; + while ((job = *address)) { + txMachine* the = job->the; + if (the) { + if (job->when <= when) { + fxBeginHost(the); + mxTry(the) { + mxPushUndefined(); + mxPush(job->function); + mxCall(); + mxPush(job->argument); + mxRunCount(1); + mxPop(); + if (job->the) { + if (job->interval) { + job->when += job->interval; + } + else { + fxAccess(the, &job->self); + *mxResult = the->scratch; + fxForget(the, &job->self); + fxSetHostData(the, mxResult, NULL); + job->the = NULL; + } + } + } + mxCatch(the) { + fxAbort(the, XS_UNHANDLED_EXCEPTION_EXIT); + } + fxEndHost(the); + break; // to run promise jobs queued by the timer in the same "tick" + } + address = &(job->next); + } + else { + *address = job->next; + c_free(job); + } + } + } +} + +void fxFulfillModuleFile(txMachine* the) +{ + mxException = mxUndefined; +} + +void fxRejectModuleFile(txMachine* the) +{ + mxException = *mxArgv(0); +} + +void fxRunModuleFile(txMachine* the, txString path) +{ + txSlot* realm = mxProgram.value.reference->next->value.module.realm; + mxPushStringC(path); + fxRunImport(the, realm, XS_NO_ID); + mxDub(); + fxGetID(the, mxID(_then)); + mxCall(); + fxNewHostFunction(the, fxFulfillModuleFile, 1, XS_NO_ID); + fxNewHostFunction(the, fxRejectModuleFile, 1, XS_NO_ID); + mxRunCount(2); + mxPop(); +} + +void fxRunProgramFile(txMachine* the, txString path) +{ + txSlot* realm = mxProgram.value.reference->next->value.module.realm; + txScript* script = fxLoadScript(the, path, mxProgramFlag | mxDebugFlag); + mxModuleInstanceInternal(mxProgram.value.reference)->value.module.id = fxID(the, path); + fxRunScript(the, script, mxRealmGlobal(realm), C_NULL, mxRealmClosures(realm)->value.reference, C_NULL, mxProgram.value.reference); + mxPullSlot(mxResult); +} + +/* DEBUG */ + +#ifdef mxDebug + +void fxConnect(txMachine* the) +{ + char name[256]; + char* colon; + int port; + struct sockaddr_in address; +#if mxWindows + if (GetEnvironmentVariable("XSBUG_HOST", name, sizeof(name))) { +#else + colon = getenv("XSBUG_HOST"); + if ((colon) && (c_strlen(colon) + 1 < sizeof(name))) { + c_strcpy(name, colon); +#endif + colon = strchr(name, ':'); + if (colon == NULL) + port = 5002; + else { + *colon = 0; + colon++; + port = strtol(colon, NULL, 10); + } + } + else { + strcpy(name, "localhost"); + port = 5002; + } + memset(&address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_addr.s_addr = inet_addr(name); + if (address.sin_addr.s_addr == INADDR_NONE) { + struct hostent *host = gethostbyname(name); + if (!host) + return; + memcpy(&(address.sin_addr), host->h_addr, host->h_length); + } + address.sin_port = htons(port); +#if mxWindows +{ + WSADATA wsaData; + unsigned long flag; + if (WSAStartup(0x202, &wsaData) == SOCKET_ERROR) + return; + the->connection = socket(AF_INET, SOCK_STREAM, 0); + if (the->connection == INVALID_SOCKET) + return; + flag = 1; + ioctlsocket(the->connection, FIONBIO, &flag); + if (connect(the->connection, (struct sockaddr*)&address, sizeof(address)) == SOCKET_ERROR) { + if (WSAEWOULDBLOCK == WSAGetLastError()) { + fd_set fds; + struct timeval timeout = { 2, 0 }; // 2 seconds, 0 micro-seconds + FD_ZERO(&fds); + FD_SET(the->connection, &fds); + if (select(0, NULL, &fds, NULL, &timeout) == 0) + goto bail; + if (!FD_ISSET(the->connection, &fds)) + goto bail; + } + else + goto bail; + } + flag = 0; + ioctlsocket(the->connection, FIONBIO, &flag); +} +#else +{ + int flag; + the->connection = socket(AF_INET, SOCK_STREAM, 0); + if (the->connection <= 0) + goto bail; + c_signal(SIGPIPE, SIG_IGN); +#if mxMacOSX + { + int set = 1; + setsockopt(the->connection, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)); + } +#endif + flag = fcntl(the->connection, F_GETFL, 0); + fcntl(the->connection, F_SETFL, flag | O_NONBLOCK); + if (connect(the->connection, (struct sockaddr*)&address, sizeof(address)) < 0) { + if (errno == EINPROGRESS) { + fd_set fds; + struct timeval timeout = { 2, 0 }; // 2 seconds, 0 micro-seconds + int error = 0; + unsigned int length = sizeof(error); + FD_ZERO(&fds); + FD_SET(the->connection, &fds); + if (select(the->connection + 1, NULL, &fds, NULL, &timeout) == 0) + goto bail; + if (!FD_ISSET(the->connection, &fds)) + goto bail; + if (getsockopt(the->connection, SOL_SOCKET, SO_ERROR, &error, &length) < 0) + goto bail; + if (error) + goto bail; + } + else + goto bail; + } + fcntl(the->connection, F_SETFL, flag); + c_signal(SIGPIPE, SIG_DFL); +} +#endif + return; +bail: + fxDisconnect(the); +} + +void fxDisconnect(txMachine* the) +{ +#if mxWindows + if (the->connection != INVALID_SOCKET) { + closesocket(the->connection); + the->connection = INVALID_SOCKET; + } + WSACleanup(); +#else + if (the->connection >= 0) { + close(the->connection); + the->connection = -1; + } +#endif +} + +txBoolean fxIsConnected(txMachine* the) +{ + return (the->connection != mxNoSocket) ? 1 : 0; +} + +txBoolean fxIsReadable(txMachine* the) +{ + return 0; +} + +void fxReceive(txMachine* the) +{ + int count; + if (the->connection != mxNoSocket) { +#if mxWindows + count = recv(the->connection, the->debugBuffer, sizeof(the->debugBuffer) - 1, 0); + if (count < 0) + fxDisconnect(the); + else + the->debugOffset = count; +#else + again: + count = read(the->connection, the->debugBuffer, sizeof(the->debugBuffer) - 1); + if (count < 0) { + if (errno == EINTR) + goto again; + else + fxDisconnect(the); + } + else + the->debugOffset = count; +#endif + } + the->debugBuffer[the->debugOffset] = 0; +} + +void fxSend(txMachine* the, txBoolean more) +{ + if (the->connection != mxNoSocket) { +#if mxWindows + if (send(the->connection, the->echoBuffer, the->echoOffset, 0) <= 0) + fxDisconnect(the); +#else + again: + if (write(the->connection, the->echoBuffer, the->echoOffset) <= 0) { + if (errno == EINTR) + goto again; + else + fxDisconnect(the); + } +#endif + } +} + +#endif /* mxDebug */ + +typedef struct sxAliasIDLink txAliasIDLink; +typedef struct sxAliasIDList txAliasIDList; + +struct sxAliasIDLink { + txAliasIDLink* previous; + txAliasIDLink* next; + txInteger id; + txInteger flag; +}; + +struct sxAliasIDList { + txAliasIDLink* first; + txAliasIDLink* last; + txFlag* aliases; + txInteger errorCount; +}; + +static void fxCheckAliasesError(txMachine* the, txAliasIDList* list, txFlag flag); +static void fxCheckEnvironmentAliases(txMachine* the, txSlot* environment, txAliasIDList* list); +static void fxCheckInstanceAliases(txMachine* the, txSlot* instance, txAliasIDList* list); + +#define mxPushLink(name,ID,FLAG) \ + txAliasIDLink name = { C_NULL, C_NULL, ID, FLAG }; \ + name.previous = list->last; \ + if (list->last) \ + list->last->next = &name; \ + else \ + list->first = &name; \ + list->last = &name + +#define mxPopLink(name) \ + if (name.previous) \ + name.previous->next = C_NULL; \ + else \ + list->first = C_NULL; \ + list->last = name.previous + +enum { + XSL_MODULE_FLAG, + XSL_EXPORT_FLAG, + XSL_ENVIRONMENT_FLAG, + XSL_PROPERTY_FLAG, + XSL_ITEM_FLAG, + XSL_GETTER_FLAG, + XSL_SETTER_FLAG, + XSL_PROXY_HANDLER_FLAG, + XSL_PROXY_TARGET_FLAG, + XSL_GLOBAL_FLAG, +}; + +txInteger fxCheckAliases(txMachine* the) +{ + txAliasIDList _list = { C_NULL, C_NULL }, *list = &_list; + txSlot* module = mxProgram.value.reference->next; //@@ + list->aliases = c_calloc(the->aliasCount, sizeof(txFlag)); + while (module) { + txSlot* export = mxModuleExports(module)->value.reference->next; + if (export) { + mxPushLink(moduleLink, module->ID, XSL_MODULE_FLAG); + while (export) { + txSlot* closure = export->value.export.closure; + if (closure) { + mxPushLink(exportLink, export->ID, XSL_EXPORT_FLAG); + if (closure->ID != XS_NO_ID) { + if (list->aliases[closure->ID] == 0) { + list->aliases[closure->ID] = 1; + fxCheckAliasesError(the, list, 0); + } + } + if (closure->kind == XS_REFERENCE_KIND) { + fxCheckInstanceAliases(the, closure->value.reference, list); + } + mxPopLink(exportLink); + } + export = export->next; + } + mxPopLink(moduleLink); + } + module = module->next; + } + { + txSlot* global = mxGlobal.value.reference->next->next; + while (global) { + if ((global->ID != mxID(_global)) && (global->ID != mxID(_globalThis))) { + mxPushLink(globalLink, global->ID, XSL_GLOBAL_FLAG); + if (global->kind == XS_REFERENCE_KIND) { + fxCheckInstanceAliases(the, global->value.reference, list); + } + mxPopLink(globalLink); + } + global = global->next; + } + } + { + fxCheckEnvironmentAliases(the, mxException.value.reference, list); + } + return list->errorCount; +} + +void fxCheckAliasesError(txMachine* the, txAliasIDList* list, txFlag flag) +{ + txAliasIDLink* link = list->first; + if (flag > 1) + fprintf(stderr, "### error"); + else + fprintf(stderr, "### warning"); + while (link) { + switch (link->flag) { + case XSL_PROPERTY_FLAG: fprintf(stderr, "."); break; + case XSL_ITEM_FLAG: fprintf(stderr, "["); break; + case XSL_GETTER_FLAG: fprintf(stderr, ".get "); break; + case XSL_SETTER_FLAG: fprintf(stderr, ".set "); break; + case XSL_ENVIRONMENT_FLAG: fprintf(stderr, "() "); break; + case XSL_PROXY_HANDLER_FLAG: fprintf(stderr, ".(handler)"); break; + case XSL_PROXY_TARGET_FLAG: fprintf(stderr, ".(target)"); break; + default: fprintf(stderr, ": "); break; + } + if (link->id < 0) { + if (link->id != XS_NO_ID) { + char* string = fxGetKeyName(the, link->id); + if (string) { + if (link->flag == XSL_MODULE_FLAG) { + char* dot = c_strrchr(string, '.'); + if (dot) { + *dot = 0; + fprintf(stderr, "\"%s\"", string); + *dot = '.'; + } + else + fprintf(stderr, "%s", string); + } + else if (link->flag == XSL_GLOBAL_FLAG) { + fprintf(stderr, "globalThis."); + fprintf(stderr, "%s", string); + } + else + fprintf(stderr, "%s", string); + } + else + fprintf(stderr, "%d", link->id); + } + } + else + fprintf(stderr, "%d", link->id); + if (link->flag == XSL_ITEM_FLAG) + fprintf(stderr, "]"); + link = link->next; + } + if (flag == 3) { + fprintf(stderr, ": generator\n"); + list->errorCount++; + } + else if (flag == 2) { + fprintf(stderr, ": regexp\n"); + list->errorCount++; + } + else if (flag) + fprintf(stderr, ": not frozen\n"); + else + fprintf(stderr, ": no const\n"); +} + +void fxCheckEnvironmentAliases(txMachine* the, txSlot* environment, txAliasIDList* list) +{ + txSlot* closure = environment->next; + if (environment->flag & XS_LEVEL_FLAG) + return; + environment->flag |= XS_LEVEL_FLAG; + if (environment->value.instance.prototype) + fxCheckEnvironmentAliases(the, environment->value.instance.prototype, list); + while (closure) { + if (closure->kind == XS_CLOSURE_KIND) { + txSlot* slot = closure->value.closure; + mxPushLink(closureLink, closure->ID, XSL_ENVIRONMENT_FLAG); + if (slot->ID != XS_NO_ID) { + if (list->aliases[slot->ID] == 0) { + list->aliases[slot->ID] = 1; + fxCheckAliasesError(the, list, 0); + } + } + if (slot->kind == XS_REFERENCE_KIND) { + fxCheckInstanceAliases(the, slot->value.reference, list); + } + mxPopLink(closureLink); + } + closure = closure->next; + } + //environment->flag &= ~XS_LEVEL_FLAG; +} + +void fxCheckInstanceAliases(txMachine* the, txSlot* instance, txAliasIDList* list) +{ + txSlot* property = instance->next; + if (instance->flag & XS_LEVEL_FLAG) + return; + instance->flag |= XS_LEVEL_FLAG; + if (instance->value.instance.prototype) { + mxPushLink(propertyLink, mxID(___proto__), XSL_PROPERTY_FLAG); + fxCheckInstanceAliases(the, instance->value.instance.prototype, list); + mxPopLink(propertyLink); + } + if (instance->ID != XS_NO_ID) { + if (list->aliases[instance->ID] == 0) { + list->aliases[instance->ID] = 1; + fxCheckAliasesError(the, list, 1); + } + } + while (property) { + if (property->kind == XS_ACCESSOR_KIND) { + if (property->value.accessor.getter) { + mxPushLink(propertyLink, property->ID, XSL_GETTER_FLAG); + fxCheckInstanceAliases(the, property->value.accessor.getter, list); + mxPopLink(propertyLink); + } + if (property->value.accessor.setter) { + mxPushLink(propertyLink, property->ID, XSL_SETTER_FLAG); + fxCheckInstanceAliases(the, property->value.accessor.setter, list); + mxPopLink(propertyLink); + } + } + else if (property->kind == XS_ARRAY_KIND) { + txSlot* item = property->value.array.address; + txInteger length = (txInteger)fxGetIndexSize(the, property); + while (length > 0) { + if (item->kind == XS_REFERENCE_KIND) { + mxPushLink(propertyLink, *((txInteger*)item), XSL_ITEM_FLAG); + fxCheckInstanceAliases(the, item->value.reference, list); + mxPopLink(propertyLink); + } + item++; + length--; + } + } + else if ((property->kind == XS_CODE_KIND) || (property->kind == XS_CODE_X_KIND)) { + if (property->value.code.closures) + fxCheckEnvironmentAliases(the, property->value.code.closures, list); + } + else if (property->kind == XS_PROXY_KIND) { + if (property->value.proxy.handler) { + mxPushLink(propertyLink, XS_NO_ID, XSL_PROXY_HANDLER_FLAG); + fxCheckInstanceAliases(the, property->value.proxy.handler, list); + mxPopLink(propertyLink); + } + if (property->value.proxy.target) { + mxPushLink(propertyLink, XS_NO_ID, XSL_PROXY_TARGET_FLAG); + fxCheckInstanceAliases(the, property->value.proxy.target, list); + mxPopLink(propertyLink); + } + } + else if (property->kind == XS_REFERENCE_KIND) { + mxPushLink(propertyLink, property->ID, XSL_PROPERTY_FLAG); + fxCheckInstanceAliases(the, property->value.reference, list); + mxPopLink(propertyLink); + } + property = property->next; + } +// instance->flag &= ~XS_LEVEL_FLAG; +} + +void fxFreezeBuiltIns(txMachine* the) +{ +#define mxFreezeBuiltInCall \ + mxPush(mxObjectConstructor); \ + mxPushSlot(freeze); \ + mxCall() +#define mxFreezeBuiltInRun \ + mxPushBoolean(1); \ + mxRunCount(2); \ + mxPop() + + txSlot* freeze; + txInteger id; + + mxTemporary(freeze); + mxPush(mxObjectConstructor); + fxGetID(the, mxID(_freeze)); + mxPullSlot(freeze); + + for (id = XS_SYMBOL_ID_COUNT; id < _Infinity; id++) { + mxFreezeBuiltInCall; mxPush(the->stackPrototypes[-1 - id]); mxFreezeBuiltInRun; + } + for (id = _Compartment; id < XS_INTRINSICS_COUNT; id++) { + mxFreezeBuiltInCall; mxPush(the->stackPrototypes[-1 - id]); mxFreezeBuiltInRun; + } + + mxFreezeBuiltInCall; mxPush(mxArgumentsSloppyPrototype); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxArgumentsStrictPrototype); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxArrayIteratorPrototype); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxAsyncFromSyncIteratorPrototype); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxAsyncFunctionPrototype); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxAsyncGeneratorFunctionPrototype); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxAsyncGeneratorPrototype); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxAsyncIteratorPrototype); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxGeneratorFunctionPrototype); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxGeneratorPrototype); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxHostPrototype); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxIteratorPrototype); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxMapEntriesIteratorPrototype); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxMapKeysIteratorPrototype); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxMapValuesIteratorPrototype); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxModulePrototype); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxRegExpStringIteratorPrototype); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxSetEntriesIteratorPrototype); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxSetKeysIteratorPrototype); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxSetValuesIteratorPrototype); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxStringIteratorPrototype); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxTransferPrototype); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxTypedArrayPrototype); mxFreezeBuiltInRun; + + mxFreezeBuiltInCall; mxPush(mxAssignObjectFunction); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxCopyObjectFunction); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxEnumeratorFunction); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxInitializeRegExpFunction); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxOnRejectedPromiseFunction); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxOnResolvedPromiseFunction); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPush(mxOnThenableFunction); mxFreezeBuiltInRun; + + mxFreezeBuiltInCall; mxPushReference(mxArrayLengthAccessor.value.accessor.getter); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPushReference(mxArrayLengthAccessor.value.accessor.setter); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPushReference(mxStringAccessor.value.accessor.getter); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPushReference(mxStringAccessor.value.accessor.setter); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPushReference(mxProxyAccessor.value.accessor.getter); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPushReference(mxProxyAccessor.value.accessor.setter); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPushReference(mxTypedArrayAccessor.value.accessor.getter); mxFreezeBuiltInRun; + mxFreezeBuiltInCall; mxPushReference(mxTypedArrayAccessor.value.accessor.setter); mxFreezeBuiltInRun; + + mxFreezeBuiltInCall; mxPush(mxArrayPrototype); fxGetID(the, mxID(_Symbol_unscopables)); mxFreezeBuiltInRun; + + mxFreezeBuiltInCall; mxPush(mxProgram); mxFreezeBuiltInRun; //@@ + mxFreezeBuiltInCall; mxPush(mxHosts); mxFreezeBuiltInRun; //@@ + + mxPop(); +} + +void fxVersion(txString theBuffer, txSize theSize) +{ + c_snprintf(theBuffer, theSize, "%d.%d.%d", XS_MAJOR_VERSION, XS_MINOR_VERSION, XS_PATCH_VERSION); +} + +#ifdef mxMetering +txUnsigned fxGetCurrentMeter(txMachine* the) +{ + return the->meterIndex; +} + +void fxSetCurrentMeter(txMachine* the, txUnsigned value) +{ + the->meterIndex = value; +} +#endif diff --git a/xsnap/sources/xsnapPlatform.h b/xsnap/sources/xsnapPlatform.h new file mode 100644 index 0000000..6b6c57f --- /dev/null +++ b/xsnap/sources/xsnapPlatform.h @@ -0,0 +1,85 @@ +#ifndef __XSNAP_PLATFORM__ +#define __XSNAP_PLATFORM__ + +#if defined(_MSC_VER) + #if defined(_M_IX86) || defined(_M_X64) + #undef mxLittleEndian + #define mxLittleEndian 1 + #undef mxWindows + #define mxWindows 1 + #define mxExport extern + #define mxImport extern + #define XS_FUNCTION_NORETURN + #else + #error unknown Microsoft compiler + #endif +#elif defined(__GNUC__) + #if defined(__i386__) || defined(i386) || defined(intel) || defined(arm) || defined(__arm__) || defined(__k8__) || defined(__x86_64__) || defined(__aarch64__) + #undef mxLittleEndian + #define mxLittleEndian 1 + #if defined(__linux__) || defined(linux) + #undef mxLinux + #define mxLinux 1 + #else + #undef mxMacOSX + #define mxMacOSX 1 + #endif + #define mxExport extern + #define mxImport extern + #define XS_FUNCTION_NORETURN __attribute__((noreturn)) + #else + #error unknown GNU compiler + #endif +#else + #error unknown compiler +#endif + +#if mxWindows + #define _USE_MATH_DEFINES + #define WIN32_LEAN_AND_MEAN + #define _WINSOCK_DEPRECATED_NO_WARNINGS +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if mxWindows + #include + typedef SOCKET txSocket; + #define mxNoSocket INVALID_SOCKET +#else + #include + #include + #include + #include + #include + #include + typedef int txSocket; + #define mxNoSocket -1 + #define mxUseGCCAtomics 1 + #define mxUsePOSIXThreads 1 +#endif +#define mxMachinePlatform \ + txSocket connection; \ + int abortStatus; \ + int promiseJobs; \ + void* timerJobs; \ + void* waiterCondition; \ + void* waiterData; \ + void* waiterLink; + +#define mxUseDefaultBuildKeys 1 +#define mxUseDefaultChunkAllocation 1 +#define mxUseDefaultSlotAllocation 1 +#define mxUseDefaultFindModule 1 +#define mxUseDefaultLoadModule 1 +#define mxUseDefaultParseScript 1 +#define mxUseDefaultSharedChunks 1 + +#endif /* __XSNAP_PLATFORM__ */