diff --git a/.gitignore b/.gitignore index bf6dac92d0c..04c1c49deea 100644 --- a/.gitignore +++ b/.gitignore @@ -61,6 +61,8 @@ perl6-debug-j.bat /perl6-lldb-m perl6-m perl6-m.bat +perl6-mc +perl6-mc.exe perl6-debug-m perl6-debug-m.bat perl6-js diff --git a/tools/build/Makefile-Moar.in b/tools/build/Makefile-Moar.in index c5499151b46..cfa4ea8e875 100644 --- a/tools/build/Makefile-Moar.in +++ b/tools/build/Makefile-Moar.in @@ -19,6 +19,8 @@ M_RUN_PERL6 = $(MOAR) --libpath="blib" --libpath="$(M_LIBPATH)" perl6.moarvm --n M_BAT = @runner_suffix@ M_RUNNER = perl6-m@runner_suffix@ +M_C_RUNNER = perl6-mc@exe@ + # files we create PERL6_MOAR = perl6.moarvm PERL6_ML_MOAR = blib/Perl6/ModuleLoader.moarvm @@ -214,6 +216,14 @@ $(M_VALGRIND_RUNNER): tools/build/create-moar-runner.p6 $(PERL6_MOAR) $(SETTING_ $(M_RUN_PERL6) tools/build/create-moar-runner.p6 "$(MOAR)" perl6.moarvm perl6-valgrind-m . "valgrind" --nqp-lib=blib norelocatable . blib "$(M_LIBPATH)" -$(CHMOD) 755 $(M_VALGRIND_RUNNER) +$(M_C_RUNNER): tools/build/moar-runner.c + $(RM_F) $(M_C_RUNNER) +# Using only the pkgconfig moar includes does not work, because moar.h assumes all the specific includes below. + $(M_CC) @moar::ccshared@ $(M_CFLAGS) $(M_LDFLAGS) -I$(M_INCPATH) -I$(M_INCPATH)/moar \ + -I$(M_INCPATH)/libatomic_ops -I$(M_INCPATH)/dyncall -I$(M_INCPATH)/moar -I$(M_INCPATH)/sha1 -I$(M_INCPATH)/tinymt -I$(M_INCPATH)/libtommath -I$(M_INCPATH)/libuv \ + -L@moar::libdir@ -Wl,-z,origin,-rpath,'$$ORIGIN/../lib' -lmoar @moar::ccout@$@ tools/build/moar-runner.c + + ## testing targets m-test : m-coretest$(HARNESS_TYPE) @@ -288,7 +298,7 @@ m-localtest_loud: m-all spectest_checkout t/localtest.data m-sometests: m-all @$(M_HARNESS6_WITH_FUDGE) $(TESTFILES) -m-install: m-all tools/build/create-moar-runner.p6 tools/build/install-core-dist.p6 $(SETTING_MOAR) +m-install: m-all tools/build/create-moar-runner.p6 tools/build/install-core-dist.p6 $(SETTING_MOAR) $(M_C_RUNNER) $(MKPATH) $(DESTDIR)$(PREFIX)/bin $(MKPATH) $(DESTDIR)$(M_LIBPATH)/Perl6 $(M_RUN_CLEAN_TARGET_FILES) $(M_PERL6_LANG_OUTPUT) $(DESTDIR)/$(M_LIBPATH)/Perl6 @@ -305,15 +315,16 @@ m-install: m-all tools/build/create-moar-runner.p6 tools/build/install-core-dist .@slash@$(M_RUNNER) tools/build/upgrade-repository.p6 $(DESTDIR)$(PERL6_LANG_DIR)/vendor .@slash@$(M_RUNNER) tools/build/upgrade-repository.p6 $(DESTDIR)$(PERL6_LANG_DIR)/site .@slash@$(M_RUNNER) tools/build/install-core-dist.p6 $(DESTDIR)$(PERL6_LANG_DIR) - $(M_RUN_PERL6) tools/build/create-moar-runner.p6 "$(MOAR)" perl6.moarvm $(DESTDIR)$(PREFIX)/bin/perl6-m "$(PERL6_LANG_DIR)/runtime" "" "" relocatable "$(M_LIBPATH)" "$(PERL6_LANG_DIR)/lib" "$(PERL6_LANG_DIR)/runtime" + #$(M_RUN_PERL6) tools/build/create-moar-runner.p6 "$(MOAR)" perl6.moarvm $(DESTDIR)$(PREFIX)/bin/perl6-m "$(PERL6_LANG_DIR)/runtime" "" "" relocatable "$(M_LIBPATH)" "$(PERL6_LANG_DIR)/lib" "$(PERL6_LANG_DIR)/runtime" + $(CP) $(M_C_RUNNER) $(DESTDIR)$(PREFIX)/bin/perl6-m@exe@ $(M_RUN_PERL6) tools/build/create-moar-runner.p6 "$(MOAR)" perl6-debug.moarvm $(DESTDIR)$(PREFIX)/bin/perl6-debug-m "$(PERL6_LANG_DIR)/runtime" "" "" relocatable "$(M_LIBPATH)" "$(PERL6_LANG_DIR)/lib" "$(PERL6_LANG_DIR)/runtime" - $(CHMOD) 755 $(DESTDIR)$(PREFIX)/bin/perl6-m$(M_BAT) + #$(CHMOD) 755 $(DESTDIR)$(PREFIX)/bin/perl6-m@exe@ @m_install@ m-runner-default-install: m-install - $(M_RUN_PERL6) tools/build/create-moar-runner.p6 "$(MOAR)" perl6.moarvm $(DESTDIR)$(PREFIX)/bin/perl6-m "$(PERL6_LANG_DIR)/runtime" "" "" relocatable "$(M_LIBPATH)" "$(PERL6_LANG_DIR)/lib" "$(PERL6_LANG_DIR)/runtime" - $(CP) $(DESTDIR)$(PREFIX)/bin/perl6-m$(M_BAT) $(DESTDIR)$(PREFIX)/bin/perl6$(M_BAT) - $(CHMOD) 755 $(DESTDIR)$(PREFIX)/bin/perl6$(M_BAT) + #$(M_RUN_PERL6) tools/build/create-moar-runner.p6 "$(MOAR)" perl6.moarvm $(DESTDIR)$(PREFIX)/bin/perl6-m "$(PERL6_LANG_DIR)/runtime" "" "" relocatable "$(M_LIBPATH)" "$(PERL6_LANG_DIR)/lib" "$(PERL6_LANG_DIR)/runtime" + $(CP) $(DESTDIR)$(PREFIX)/bin/perl6-m@exe@ $(DESTDIR)$(PREFIX)/bin/perl6@exe@ + #$(CHMOD) 755 $(DESTDIR)$(PREFIX)/bin/perl6@exe manifest: echo MANIFEST >MANIFEST diff --git a/tools/build/moar-runner.c b/tools/build/moar-runner.c new file mode 100644 index 00000000000..a9957b3844e --- /dev/null +++ b/tools/build/moar-runner.c @@ -0,0 +1,317 @@ +#include +#include +#include +#include + +#if MVM_TRACING +# define TRACING_OPT "[--tracing] " +# define TRACING_USAGE "\n --tracing output a line to stderr on every interpreter instr" +#else +# define TRACING_OPT "" +# define TRACING_USAGE "" +#endif + +#ifdef HAVE_TELEMEH +# define TELEMEH_USAGE " MVM_TELEMETRY_LOG Log internal events at high precision to this file\n" +#else +# define TELEMEH_USAGE "" +#endif + +#ifndef _WIN32 +# include "signal.h" +#endif + +#ifndef _WIN32 +# include +#else +# include +#endif + +#ifdef _WIN32 +# define snprintf _snprintf +#endif + +#if defined(_MSC_VER) +#define strtoll _strtoi64 +#endif + +/* flags need to be sorted alphabetically */ + +enum { + NOT_A_FLAG = -2, + UNKNOWN_FLAG = -1, + + FLAG_CRASH, + FLAG_SUSPEND, + FLAG_DUMP, + FLAG_FULL_CLEANUP, + FLAG_HELP, + FLAG_TRACING, + FLAG_VERSION, + + OPT_EXECNAME, + OPT_LIBPATH, + OPT_DEBUGPORT +}; + +static const char *const FLAGS[] = { + "--crash", + "--debug-suspend", + "--dump", + "--full-cleanup", + "--help", + "--tracing", + "--version", +}; + +static const char USAGE[] = "\ +USAGE: moar [--crash] [--libpath=...] " TRACING_OPT "input.moarvm [program args]\n\ + moar --dump input.moarvm\n\ + moar --help\n\ +\n\ + --help display this message\n\ + --dump dump the bytecode to stdout instead of executing\n\ + --full-cleanup try to free all memory and exit cleanly\n\ + --crash abort instead of exiting on unhandled exception\n\ + --libpath specify path loadbytecode should search in\n\ + --version show version information\n\ + --debug-port=1234 listen for incoming debugger connections\n\ + --debug-suspend pause execution at the entry point" + TRACING_USAGE + "\n\ +\n\ +The following environment variables are respected:\n\ +\n\ + MVM_SPESH_DISABLE Disables all dynamic optimization\n\ + MVM_SPESH_INLINE_DISABLE Disables inlining\n\ + MVM_SPESH_OSR_DISABLE Disables on-stack replacement\n\ + MVM_SPESH_BLOCKING Blocks log-sending thread while specializer runs\n\ + MVM_SPESH_LOG Specifies a dynamic optimizer log file\n\ + MVM_SPESH_NODELAY Run dynamic optimization even for cold frames\n\ + MVM_SPESH_LIMIT Limit the maximum number of specializations\n\ + MVM_JIT_DISABLE Disables JITting to machine code\n\ + MVM_JIT_EXPR_DISABLE Disable advanced 'expression' JIT\n\ + MVM_JIT_DEBUG Add JIT debugging information to spesh log\n\ + MVM_JIT_PERF_MAP Create a map file for the 'perf' profiler (linux only)\n\ + MVM_JIT_DUMP_BYTECODE Dump bytecode in temporary directory\n\ + MVM_SPESH_INLINE_LOG Dump details of inlining attempts to stderr\n\ + MVM_CROSS_THREAD_WRITE_LOG Log unprotected cross-thread object writes to stderr\n\ + MVM_COVERAGE_LOG Append (de-duped by default) line-by-line coverage messages to this file\n\ + MVM_COVERAGE_CONTROL If set to 1, non-de-duping coverage started with nqp::coveragecontrol(1),\n\ + if set to 2, non-de-duping coverage started right away\n" + TELEMEH_USAGE; + +static int cmp_flag(const void *key, const void *value) +{ + return strcmp(key, *(char **)value); +} + +static int starts_with(const char *str, const char *want) { + size_t str_len = strlen(str); + size_t want_len = strlen(want); + return str_len < want_len + ? 0 + : strncmp(str, want, want_len) == 0; +} + +static int parse_flag(const char *arg) +{ + const char *const *found; + + if (!arg || arg[0] != '-') + return NOT_A_FLAG; + + found = bsearch(arg, FLAGS, sizeof FLAGS / sizeof *FLAGS, sizeof *FLAGS, cmp_flag); + + if (found) + return (int)(found - FLAGS); + else if (starts_with(arg, "--libpath=")) + return OPT_LIBPATH; + else if (starts_with(arg, "--execname=")) + return OPT_EXECNAME; + else if (starts_with(arg, "--debug-port=")) + return OPT_DEBUGPORT; + else + return UNKNOWN_FLAG; +} + +#ifndef _WIN32 +int main(int argc, char *argv[]) +#else +int wmain(int argc, wchar_t *wargv[]) +#endif +{ + MVMInstance *instance; + const char *input_file; + const char *executable_name = NULL; + const char *lib_path[8]; + +#ifdef _WIN32 + char **argv = MVM_UnicodeToUTF8_argv(argc, wargv); +#endif + + int dump = 0; + int full_cleanup = 0; + int argi = 1; + int lib_path_i = 0; + int flag; + + unsigned int interval_id; + char telemeh_inited = 0; + + MVMuint32 debugserverport = 0; + int start_suspended = 0; + + for (; (flag = parse_flag(argv[argi])) != NOT_A_FLAG; ++argi) { + switch (flag) { + case FLAG_CRASH: + MVM_crash_on_error(); + continue; + + case FLAG_DUMP: + dump = 1; + continue; + + case FLAG_FULL_CLEANUP: + full_cleanup = 1; + continue; + + case FLAG_HELP: + puts(USAGE); + return EXIT_SUCCESS; + +#if MVM_TRACING + case FLAG_TRACING: + MVM_interp_enable_tracing(); + continue; +#endif + + case FLAG_SUSPEND: + start_suspended = 1; + continue; + + case OPT_EXECNAME: + executable_name = argv[argi] + strlen("--execname="); + continue; + + case OPT_LIBPATH: + if (lib_path_i == 7) { /* 0..7 == 8 */ + fprintf(stderr, "ERROR: Only up to eight --libpath options are allowed.\n"); + return EXIT_FAILURE; + } + + lib_path[lib_path_i++] = argv[argi] + strlen("--libpath="); + continue; + + case FLAG_VERSION: { + char *spesh_disable; + char *jit_disable; + + printf("This is MoarVM version %s", MVM_VERSION); + if (MVM_jit_support()) { + printf(" built with JIT support"); + + spesh_disable = getenv("MVM_SPESH_DISABLE"); + jit_disable = getenv("MVM_JIT_DISABLE"); + if (spesh_disable && strlen(spesh_disable) != 0) { + printf(" (disabled via MVM_SPESH_DISABLE)"); + } else if (jit_disable && strlen(jit_disable) != 0) { + printf(" (disabled via MVM_JIT_DISABLE)"); + } + } + printf("\n"); + return EXIT_SUCCESS; + } + + case OPT_DEBUGPORT: { + MVMint64 port; + char *portstr = argv[argi] + strlen("--debugport=") + 1; + char *endptr; + port = strtoll(portstr, &endptr, 10); + if (*endptr != '\0') { + fprintf(stderr, "ERROR: Invalid characters in debug port flag: %s\n", portstr); + return EXIT_FAILURE; + } + if (port <= 1024 || 65535 < port) { + fprintf(stderr, "ERROR: debug server port out of range. We only accept ports above 1024 and below 65535. (got: %"PRIi64")\n", port); + return EXIT_FAILURE; + } + debugserverport = (MVMuint32)port; + break; + } + + default: + fprintf(stderr, "ERROR: Unknown flag %s.\n\n%s\n", argv[argi], USAGE); + return EXIT_FAILURE; + } + } + +#ifdef HAVE_TELEMEH + if (getenv("MVM_TELEMETRY_LOG")) { + char path[256]; + FILE *fp; + snprintf(path, 255, "%s.%d", getenv("MVM_TELEMETRY_LOG"), +#ifdef _WIN32 + _getpid() +#else + getpid() +#endif + ); + fp = fopen(path, "w"); + if (fp) { + MVM_telemetry_init(fp); + telemeh_inited = 1; + interval_id = MVM_telemetry_interval_start(0, "moarvm startup"); + } + } +#endif + + lib_path[lib_path_i] = NULL; + + if (argi >= argc) { + fprintf(stderr, "ERROR: Missing input file.\n\n%s\n", USAGE); + return EXIT_FAILURE; + } + + instance = MVM_vm_create_instance(); + input_file = argv[argi++]; + + /* stash the rest of the raw command line args in the instance */ + MVM_vm_set_clargs(instance, argc - argi, argv + argi); + MVM_vm_set_prog_name(instance, input_file); + MVM_vm_set_exec_name(instance, executable_name); + MVM_vm_set_lib_path(instance, lib_path_i, lib_path); + + /* Ignore SIGPIPE by default, since we error-check reads/writes. This does + * not prevent users from setting up their own signal handler for SIGPIPE, + * which will take precedence over this ignore. */ +#ifndef _WIN32 + signal(SIGPIPE, SIG_IGN); +#endif + + if (debugserverport > 0) { + MVM_debugserver_init(instance->main_thread, debugserverport); + + if (start_suspended) { + instance->main_thread->gc_status = MVMGCStatus_INTERRUPT | MVMSuspendState_SUSPEND_REQUEST; + } + } + + if (dump) MVM_vm_dump_file(instance, input_file); + else MVM_vm_run_file(instance, input_file); + +#ifdef HAVE_TELEMEH + if (getenv("MVM_TELEMETRY_LOG") && telemeh_inited) { + MVM_telemetry_interval_stop(0, interval_id, "moarvm teardown"); + MVM_telemetry_finish(); + } +#endif + + if (full_cleanup) { + MVM_vm_destroy_instance(instance); + return EXIT_SUCCESS; + } + else { + MVM_vm_exit(instance); + } +}