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