michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifdef DEBUG michael@0: michael@0: #include "jit/IonSpewer.h" michael@0: michael@0: #include "jsworkers.h" michael@0: michael@0: #include "jit/Ion.h" michael@0: michael@0: #ifndef ION_SPEW_DIR michael@0: # if defined(_WIN32) michael@0: # define ION_SPEW_DIR "" michael@0: # elif defined(__ANDROID__) michael@0: # define ION_SPEW_DIR "/data/local/tmp/" michael@0: # else michael@0: # define ION_SPEW_DIR "/tmp/" michael@0: # endif michael@0: #endif michael@0: michael@0: using namespace js; michael@0: using namespace js::jit; michael@0: michael@0: // IonSpewer singleton. michael@0: static IonSpewer ionspewer; michael@0: michael@0: static bool LoggingChecked = false; michael@0: static uint32_t LoggingBits = 0; michael@0: static uint32_t filteredOutCompilations = 0; michael@0: michael@0: static const char * const ChannelNames[] = michael@0: { michael@0: #define IONSPEW_CHANNEL(name) #name, michael@0: IONSPEW_CHANNEL_LIST(IONSPEW_CHANNEL) michael@0: #undef IONSPEW_CHANNEL michael@0: }; michael@0: michael@0: static bool michael@0: FilterContainsLocation(HandleScript function) michael@0: { michael@0: static const char *filter = getenv("IONFILTER"); michael@0: michael@0: // If there is no filter we accept all outputs. michael@0: if (!filter || !filter[0]) michael@0: return true; michael@0: michael@0: // Disable asm.js output when filter is set. michael@0: if (!function) michael@0: return false; michael@0: michael@0: const char *filename = function->filename(); michael@0: const size_t line = function->lineno(); michael@0: const size_t filelen = strlen(filename); michael@0: const char *index = strstr(filter, filename); michael@0: while (index) { michael@0: if (index == filter || index[-1] == ',') { michael@0: if (index[filelen] == 0 || index[filelen] == ',') michael@0: return true; michael@0: if (index[filelen] == ':' && line != size_t(-1)) { michael@0: size_t read_line = strtoul(&index[filelen + 1], nullptr, 10); michael@0: if (read_line == line) michael@0: return true; michael@0: } michael@0: } michael@0: index = strstr(index + filelen, filename); michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: void michael@0: jit::EnableIonDebugLogging() michael@0: { michael@0: EnableChannel(IonSpew_Logs); michael@0: ionspewer.init(); michael@0: } michael@0: michael@0: void michael@0: jit::IonSpewNewFunction(MIRGraph *graph, HandleScript func) michael@0: { michael@0: if (GetIonContext()->runtime->onMainThread()) michael@0: ionspewer.beginFunction(graph, func); michael@0: } michael@0: michael@0: void michael@0: jit::IonSpewPass(const char *pass) michael@0: { michael@0: if (GetIonContext()->runtime->onMainThread()) michael@0: ionspewer.spewPass(pass); michael@0: } michael@0: michael@0: void michael@0: jit::IonSpewPass(const char *pass, LinearScanAllocator *ra) michael@0: { michael@0: if (GetIonContext()->runtime->onMainThread()) michael@0: ionspewer.spewPass(pass, ra); michael@0: } michael@0: michael@0: void michael@0: jit::IonSpewEndFunction() michael@0: { michael@0: if (GetIonContext()->runtime->onMainThread()) michael@0: ionspewer.endFunction(); michael@0: } michael@0: michael@0: michael@0: IonSpewer::~IonSpewer() michael@0: { michael@0: if (!inited_) michael@0: return; michael@0: michael@0: c1Spewer.finish(); michael@0: jsonSpewer.finish(); michael@0: } michael@0: michael@0: bool michael@0: IonSpewer::init() michael@0: { michael@0: if (inited_) michael@0: return true; michael@0: michael@0: if (!c1Spewer.init(ION_SPEW_DIR "ion.cfg")) michael@0: return false; michael@0: if (!jsonSpewer.init(ION_SPEW_DIR "ion.json")) michael@0: return false; michael@0: michael@0: inited_ = true; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: IonSpewer::isSpewingFunction() const michael@0: { michael@0: return inited_ && graph; michael@0: } michael@0: michael@0: void michael@0: IonSpewer::beginFunction(MIRGraph *graph, HandleScript function) michael@0: { michael@0: if (!inited_) michael@0: return; michael@0: michael@0: if (!FilterContainsLocation(function)) { michael@0: JS_ASSERT(!this->graph); michael@0: // filter out logs during the compilation. michael@0: filteredOutCompilations++; michael@0: return; michael@0: } michael@0: michael@0: this->graph = graph; michael@0: this->function.repoint(function); michael@0: michael@0: c1Spewer.beginFunction(graph, function); michael@0: jsonSpewer.beginFunction(function); michael@0: } michael@0: michael@0: void michael@0: IonSpewer::spewPass(const char *pass) michael@0: { michael@0: if (!isSpewingFunction()) michael@0: return; michael@0: michael@0: c1Spewer.spewPass(pass); michael@0: jsonSpewer.beginPass(pass); michael@0: jsonSpewer.spewMIR(graph); michael@0: jsonSpewer.spewLIR(graph); michael@0: jsonSpewer.endPass(); michael@0: } michael@0: michael@0: void michael@0: IonSpewer::spewPass(const char *pass, LinearScanAllocator *ra) michael@0: { michael@0: if (!isSpewingFunction()) michael@0: return; michael@0: michael@0: c1Spewer.spewPass(pass); michael@0: c1Spewer.spewIntervals(pass, ra); michael@0: jsonSpewer.beginPass(pass); michael@0: jsonSpewer.spewMIR(graph); michael@0: jsonSpewer.spewLIR(graph); michael@0: jsonSpewer.spewIntervals(ra); michael@0: jsonSpewer.endPass(); michael@0: } michael@0: michael@0: void michael@0: IonSpewer::endFunction() michael@0: { michael@0: if (!isSpewingFunction()) { michael@0: if (inited_) { michael@0: JS_ASSERT(filteredOutCompilations != 0); michael@0: filteredOutCompilations--; michael@0: } michael@0: return; michael@0: } michael@0: michael@0: c1Spewer.endFunction(); michael@0: jsonSpewer.endFunction(); michael@0: michael@0: this->graph = nullptr; michael@0: } michael@0: michael@0: michael@0: FILE *jit::IonSpewFile = nullptr; michael@0: michael@0: static bool michael@0: ContainsFlag(const char *str, const char *flag) michael@0: { michael@0: size_t flaglen = strlen(flag); michael@0: const char *index = strstr(str, flag); michael@0: while (index) { michael@0: if ((index == str || index[-1] == ',') && (index[flaglen] == 0 || index[flaglen] == ',')) michael@0: return true; michael@0: index = strstr(index + flaglen, flag); michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: void michael@0: jit::CheckLogging() michael@0: { michael@0: if (LoggingChecked) michael@0: return; michael@0: LoggingChecked = true; michael@0: const char *env = getenv("IONFLAGS"); michael@0: if (!env) michael@0: return; michael@0: if (strstr(env, "help")) { michael@0: fflush(nullptr); michael@0: printf( michael@0: "\n" michael@0: "usage: IONFLAGS=option,option,option,... where options can be:\n" michael@0: "\n" michael@0: " aborts Compilation abort messages\n" michael@0: " scripts Compiled scripts\n" michael@0: " mir MIR information\n" michael@0: " alias Alias analysis\n" michael@0: " gvn Global Value Numbering\n" michael@0: " licm Loop invariant code motion\n" michael@0: " regalloc Register allocation\n" michael@0: " inline Inlining\n" michael@0: " snapshots Snapshot information\n" michael@0: " codegen Native code generation\n" michael@0: " bailouts Bailouts\n" michael@0: " caches Inline caches\n" michael@0: " osi Invalidation\n" michael@0: " safepoints Safepoints\n" michael@0: " pools Literal Pools (ARM only for now)\n" michael@0: " cacheflush Instruction Cache flushes (ARM only for now)\n" michael@0: " range Range Analysis\n" michael@0: " logs C1 and JSON visualization logging\n" michael@0: " trace Generate calls to js::jit::Trace() for effectful instructions\n" michael@0: " all Everything\n" michael@0: "\n" michael@0: " bl-aborts Baseline compiler abort messages\n" michael@0: " bl-scripts Baseline script-compilation\n" michael@0: " bl-op Baseline compiler detailed op-specific messages\n" michael@0: " bl-ic Baseline inline-cache messages\n" michael@0: " bl-ic-fb Baseline IC fallback stub messages\n" michael@0: " bl-osr Baseline IC OSR messages\n" michael@0: " bl-bails Baseline bailouts\n" michael@0: " bl-dbg-osr Baseline debug mode on stack recompile messages\n" michael@0: " bl-all All baseline spew\n" michael@0: "\n" michael@0: ); michael@0: exit(0); michael@0: /*NOTREACHED*/ michael@0: } michael@0: if (ContainsFlag(env, "aborts")) michael@0: EnableChannel(IonSpew_Abort); michael@0: if (ContainsFlag(env, "alias")) michael@0: EnableChannel(IonSpew_Alias); michael@0: if (ContainsFlag(env, "scripts")) michael@0: EnableChannel(IonSpew_Scripts); michael@0: if (ContainsFlag(env, "mir")) michael@0: EnableChannel(IonSpew_MIR); michael@0: if (ContainsFlag(env, "gvn")) michael@0: EnableChannel(IonSpew_GVN); michael@0: if (ContainsFlag(env, "range")) michael@0: EnableChannel(IonSpew_Range); michael@0: if (ContainsFlag(env, "licm")) michael@0: EnableChannel(IonSpew_LICM); michael@0: if (ContainsFlag(env, "regalloc")) michael@0: EnableChannel(IonSpew_RegAlloc); michael@0: if (ContainsFlag(env, "inline")) michael@0: EnableChannel(IonSpew_Inlining); michael@0: if (ContainsFlag(env, "snapshots")) michael@0: EnableChannel(IonSpew_Snapshots); michael@0: if (ContainsFlag(env, "codegen")) michael@0: EnableChannel(IonSpew_Codegen); michael@0: if (ContainsFlag(env, "bailouts")) michael@0: EnableChannel(IonSpew_Bailouts); michael@0: if (ContainsFlag(env, "osi")) michael@0: EnableChannel(IonSpew_Invalidate); michael@0: if (ContainsFlag(env, "caches")) michael@0: EnableChannel(IonSpew_InlineCaches); michael@0: if (ContainsFlag(env, "safepoints")) michael@0: EnableChannel(IonSpew_Safepoints); michael@0: if (ContainsFlag(env, "pools")) michael@0: EnableChannel(IonSpew_Pools); michael@0: if (ContainsFlag(env, "cacheflush")) michael@0: EnableChannel(IonSpew_CacheFlush); michael@0: if (ContainsFlag(env, "logs")) michael@0: EnableIonDebugLogging(); michael@0: if (ContainsFlag(env, "trace")) michael@0: EnableChannel(IonSpew_Trace); michael@0: if (ContainsFlag(env, "all")) michael@0: LoggingBits = uint32_t(-1); michael@0: michael@0: if (ContainsFlag(env, "bl-aborts")) michael@0: EnableChannel(IonSpew_BaselineAbort); michael@0: if (ContainsFlag(env, "bl-scripts")) michael@0: EnableChannel(IonSpew_BaselineScripts); michael@0: if (ContainsFlag(env, "bl-op")) michael@0: EnableChannel(IonSpew_BaselineOp); michael@0: if (ContainsFlag(env, "bl-ic")) michael@0: EnableChannel(IonSpew_BaselineIC); michael@0: if (ContainsFlag(env, "bl-ic-fb")) michael@0: EnableChannel(IonSpew_BaselineICFallback); michael@0: if (ContainsFlag(env, "bl-osr")) michael@0: EnableChannel(IonSpew_BaselineOSR); michael@0: if (ContainsFlag(env, "bl-bails")) michael@0: EnableChannel(IonSpew_BaselineBailouts); michael@0: if (ContainsFlag(env, "bl-dbg-osr")) michael@0: EnableChannel(IonSpew_BaselineDebugModeOSR); michael@0: if (ContainsFlag(env, "bl-all")) { michael@0: EnableChannel(IonSpew_BaselineAbort); michael@0: EnableChannel(IonSpew_BaselineScripts); michael@0: EnableChannel(IonSpew_BaselineOp); michael@0: EnableChannel(IonSpew_BaselineIC); michael@0: EnableChannel(IonSpew_BaselineICFallback); michael@0: EnableChannel(IonSpew_BaselineOSR); michael@0: EnableChannel(IonSpew_BaselineBailouts); michael@0: EnableChannel(IonSpew_BaselineDebugModeOSR); michael@0: } michael@0: michael@0: IonSpewFile = stderr; michael@0: } michael@0: michael@0: void michael@0: jit::IonSpewStartVA(IonSpewChannel channel, const char *fmt, va_list ap) michael@0: { michael@0: if (!IonSpewEnabled(channel)) michael@0: return; michael@0: michael@0: IonSpewHeader(channel); michael@0: vfprintf(stderr, fmt, ap); michael@0: } michael@0: michael@0: void michael@0: jit::IonSpewContVA(IonSpewChannel channel, const char *fmt, va_list ap) michael@0: { michael@0: if (!IonSpewEnabled(channel)) michael@0: return; michael@0: michael@0: vfprintf(stderr, fmt, ap); michael@0: } michael@0: michael@0: void michael@0: jit::IonSpewFin(IonSpewChannel channel) michael@0: { michael@0: if (!IonSpewEnabled(channel)) michael@0: return; michael@0: michael@0: fprintf(stderr, "\n"); michael@0: } michael@0: michael@0: void michael@0: jit::IonSpewVA(IonSpewChannel channel, const char *fmt, va_list ap) michael@0: { michael@0: IonSpewStartVA(channel, fmt, ap); michael@0: IonSpewFin(channel); michael@0: } michael@0: michael@0: void michael@0: jit::IonSpew(IonSpewChannel channel, const char *fmt, ...) michael@0: { michael@0: va_list ap; michael@0: va_start(ap, fmt); michael@0: IonSpewVA(channel, fmt, ap); michael@0: va_end(ap); michael@0: } michael@0: michael@0: void michael@0: jit::IonSpewStart(IonSpewChannel channel, const char *fmt, ...) michael@0: { michael@0: va_list ap; michael@0: va_start(ap, fmt); michael@0: IonSpewStartVA(channel, fmt, ap); michael@0: va_end(ap); michael@0: } michael@0: void michael@0: jit::IonSpewCont(IonSpewChannel channel, const char *fmt, ...) michael@0: { michael@0: va_list ap; michael@0: va_start(ap, fmt); michael@0: IonSpewContVA(channel, fmt, ap); michael@0: va_end(ap); michael@0: } michael@0: michael@0: void michael@0: jit::IonSpewHeader(IonSpewChannel channel) michael@0: { michael@0: if (!IonSpewEnabled(channel)) michael@0: return; michael@0: michael@0: fprintf(stderr, "[%s] ", ChannelNames[channel]); michael@0: } michael@0: michael@0: bool michael@0: jit::IonSpewEnabled(IonSpewChannel channel) michael@0: { michael@0: JS_ASSERT(LoggingChecked); michael@0: return (LoggingBits & (1 << uint32_t(channel))) && !filteredOutCompilations; michael@0: } michael@0: michael@0: void michael@0: jit::EnableChannel(IonSpewChannel channel) michael@0: { michael@0: JS_ASSERT(LoggingChecked); michael@0: LoggingBits |= (1 << uint32_t(channel)); michael@0: } michael@0: michael@0: void michael@0: jit::DisableChannel(IonSpewChannel channel) michael@0: { michael@0: JS_ASSERT(LoggingChecked); michael@0: LoggingBits &= ~(1 << uint32_t(channel)); michael@0: } michael@0: michael@0: #endif /* DEBUG */ michael@0: