Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifdef JS_CACHEIR_SPEW
8 :
9 : #include "jit/CacheIRSpewer.h"
10 :
11 : #include "mozilla/SizePrintfMacros.h"
12 : #include "mozilla/Sprintf.h"
13 :
14 : #ifdef XP_WIN
15 : #include <process.h>
16 : #define getpid _getpid
17 : #else
18 : #include <unistd.h>
19 : #endif
20 :
21 : #include <stdarg.h>
22 :
23 : #include "jsfun.h"
24 : #include "jsobj.h"
25 : #include "jsscript.h"
26 :
27 : #include "jscompartmentinlines.h"
28 : #include "jsobjinlines.h"
29 :
30 : using namespace js;
31 : using namespace js::jit;
32 :
33 3 : CacheIRSpewer CacheIRSpewer::cacheIRspewer;
34 :
35 3 : CacheIRSpewer::CacheIRSpewer()
36 3 : : outputLock(mutexid::CacheIRSpewer)
37 3 : { }
38 :
39 0 : CacheIRSpewer::~CacheIRSpewer()
40 : {
41 0 : if (!enabled())
42 0 : return;
43 :
44 0 : json.ref().endList();
45 0 : output.flush();
46 0 : output.finish();
47 0 : }
48 :
49 : #ifndef JIT_SPEW_DIR
50 : # if defined(_WIN32)
51 : # define JIT_SPEW_DIR "."
52 : # elif defined(__ANDROID__)
53 : # define JIT_SPEW_DIR "/data/local/tmp"
54 : # else
55 : # define JIT_SPEW_DIR "/tmp"
56 : # endif
57 : #endif
58 :
59 : bool
60 0 : CacheIRSpewer::init()
61 : {
62 0 : if (enabled())
63 0 : return true;
64 :
65 : char name[256];
66 0 : uint32_t pid = getpid();
67 0 : SprintfLiteral(name, JIT_SPEW_DIR "/cacheir%" PRIu32 ".json", pid);
68 :
69 0 : if (!output.init(name))
70 0 : return false;
71 0 : output.put("[");
72 :
73 0 : json.emplace(output);
74 0 : return true;
75 : }
76 :
77 : void
78 0 : CacheIRSpewer::beginCache(LockGuard<Mutex>&, const IRGenerator& gen)
79 : {
80 0 : MOZ_ASSERT(enabled());
81 0 : JSONPrinter& j = json.ref();
82 :
83 0 : j.beginObject();
84 0 : j.property("name", CacheKindNames[uint8_t(gen.cacheKind_)]);
85 0 : j.property("file", gen.script_->filename());
86 0 : j.property("mode", int(gen.mode_));
87 0 : if (jsbytecode* pc = gen.pc_) {
88 : unsigned column;
89 0 : j.property("line", PCToLineNumber(gen.script_, pc, &column));
90 0 : j.property("column", column);
91 0 : j.formatProperty("pc", "%p", pc);
92 : }
93 0 : }
94 :
95 : template <typename CharT>
96 : static void
97 0 : QuoteString(GenericPrinter& out, const CharT* s, size_t length)
98 : {
99 0 : const CharT* end = s + length;
100 0 : for (const CharT* t = s; t < end; s = ++t) {
101 : // This quote implementation is probably correct,
102 : // but uses \u even when not strictly necessary.
103 0 : char16_t c = *t;
104 0 : if (c == '"' || c == '\\') {
105 0 : out.printf("\\");
106 0 : out.printf("%c", char(c));
107 0 : } else if (c < ' ' || c >= 127 || !isprint(c)) {
108 0 : out.printf("\\u%04x", c);
109 : } else {
110 0 : out.printf("%c", char(c));
111 : }
112 : }
113 0 : }
114 :
115 : static void
116 0 : QuoteString(GenericPrinter& out, JSLinearString* str)
117 : {
118 0 : JS::AutoCheckCannotGC nogc;
119 0 : if (str->hasLatin1Chars())
120 0 : QuoteString(out, str->latin1Chars(nogc), str->length());
121 : else
122 0 : QuoteString(out, str->twoByteChars(nogc), str->length());
123 0 : }
124 :
125 : void
126 0 : CacheIRSpewer::valueProperty(LockGuard<Mutex>&, const char* name, const Value& v)
127 : {
128 0 : MOZ_ASSERT(enabled());
129 0 : JSONPrinter& j = json.ref();
130 :
131 0 : j.beginObjectProperty(name);
132 :
133 0 : const char* type = InformalValueTypeName(v);
134 0 : if (v.isInt32())
135 0 : type = "int32";
136 0 : j.property("type", type);
137 :
138 0 : if (v.isInt32()) {
139 0 : j.property("value", v.toInt32());
140 0 : } else if (v.isDouble()) {
141 0 : j.floatProperty("value", v.toDouble(), 3);
142 0 : } else if (v.isString() || v.isSymbol()) {
143 0 : JSString* str = v.isString() ? v.toString() : v.toSymbol()->description();
144 0 : if (str && str->isLinear()) {
145 0 : j.beginStringProperty("value");
146 0 : QuoteString(output, &str->asLinear());
147 0 : j.endStringProperty();
148 : }
149 0 : } else if (v.isObject()) {
150 0 : j.formatProperty("value", "%p (shape: %p)", &v.toObject(),
151 0 : v.toObject().maybeShape());
152 : }
153 :
154 0 : j.endObject();
155 0 : }
156 :
157 : void
158 0 : CacheIRSpewer::attached(LockGuard<Mutex>&, const char* name)
159 : {
160 0 : MOZ_ASSERT(enabled());
161 0 : json.ref().property("attached", name);
162 0 : }
163 :
164 : void
165 0 : CacheIRSpewer::endCache(LockGuard<Mutex>&)
166 : {
167 0 : MOZ_ASSERT(enabled());
168 0 : json.ref().endObject();
169 0 : }
170 :
171 : #endif /* JS_CACHEIR_SPEW */
|