Bug 1874684 - Part 31: Correctly reject invalid durations in some RoundDuration calls...
[gecko.git] / js / src / jit / CacheIRSpewer.cpp
blob613e0f7d85f471c2564c56d1f8516ba6b158b988
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
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/. */
7 #ifdef JS_CACHEIR_SPEW
9 # include "jit/CacheIRSpewer.h"
11 # include "mozilla/Sprintf.h"
13 # include <algorithm>
14 # include <stdarg.h>
16 # include "jsapi.h"
17 # include "jsmath.h"
19 # include "js/ColumnNumber.h" // JS::LimitedColumnNumberOneOrigin
20 # include "js/ScalarType.h" // js::Scalar::Type
21 # include "util/GetPidProvider.h"
22 # include "util/Text.h"
23 # include "vm/JSFunction.h"
24 # include "vm/JSObject.h"
25 # include "vm/JSScript.h"
27 # include "vm/JSObject-inl.h"
28 # include "vm/Realm-inl.h"
30 using namespace js;
31 using namespace js::jit;
33 // Text spewer for CacheIR ops that can be used with JitSpew.
34 // Output looks like this:
36 // GuardToInt32 inputId 0, resultId 2
37 // GuardToInt32 inputId 1, resultId 3
38 // CompareInt32Result op JSOp::Lt, lhsId 2, rhsId 3
39 // ReturnFromIC
40 class MOZ_RAII CacheIROpsJitSpewer {
41 GenericPrinter& out_;
43 // String prepended to each line. Can be used for indentation.
44 const char* prefix_;
46 CACHE_IR_SPEWER_GENERATED
48 void spewOp(CacheOp op) {
49 const char* opName = CacheIROpNames[size_t(op)];
50 out_.printf("%s%-30s", prefix_, opName);
52 void spewOpEnd() { out_.printf("\n"); }
54 void spewArgSeparator() { out_.printf(", "); }
56 void spewOperandId(const char* name, OperandId id) {
57 spewRawOperandId(name, id.id());
59 void spewRawOperandId(const char* name, uint32_t id) {
60 out_.printf("%s %u", name, id);
62 void spewField(const char* name, uint32_t offset) {
63 out_.printf("%s %u", name, offset);
65 void spewBoolImm(const char* name, bool b) {
66 out_.printf("%s %s", name, b ? "true" : "false");
68 void spewByteImm(const char* name, uint8_t val) {
69 out_.printf("%s %u", name, val);
71 void spewJSOpImm(const char* name, JSOp op) {
72 out_.printf("%s JSOp::%s", name, CodeName(op));
74 void spewStaticStringImm(const char* name, const char* str) {
75 out_.printf("%s \"%s\"", name, str);
77 void spewInt32Imm(const char* name, int32_t val) {
78 out_.printf("%s %d", name, val);
80 void spewUInt32Imm(const char* name, uint32_t val) {
81 out_.printf("%s %u", name, val);
83 void spewCallFlagsImm(const char* name, CallFlags flags) {
84 out_.printf(
85 "%s (format %u%s%s%s)", name, flags.getArgFormat(),
86 flags.isConstructing() ? ", isConstructing" : "",
87 flags.isSameRealm() ? ", isSameRealm" : "",
88 flags.needsUninitializedThis() ? ", needsUninitializedThis" : "");
90 void spewJSWhyMagicImm(const char* name, JSWhyMagic magic) {
91 out_.printf("%s JSWhyMagic(%u)", name, unsigned(magic));
93 void spewScalarTypeImm(const char* name, Scalar::Type type) {
94 out_.printf("%s Scalar::Type(%u)", name, unsigned(type));
96 void spewUnaryMathFunctionImm(const char* name, UnaryMathFunction fun) {
97 const char* funName = GetUnaryMathFunctionName(fun);
98 out_.printf("%s UnaryMathFunction::%s", name, funName);
100 void spewValueTypeImm(const char* name, ValueType type) {
101 out_.printf("%s ValueType(%u)", name, unsigned(type));
103 void spewJSNativeImm(const char* name, JSNative native) {
104 out_.printf("%s %p", name, native);
106 void spewGuardClassKindImm(const char* name, GuardClassKind kind) {
107 out_.printf("%s GuardClassKind(%u)", name, unsigned(kind));
109 void spewArrayBufferViewKindImm(const char* name, ArrayBufferViewKind kind) {
110 out_.printf("%s ArrayBufferViewKind(%u)", name, unsigned(kind));
112 void spewWasmValTypeImm(const char* name, wasm::ValType::Kind kind) {
113 out_.printf("%s WasmValTypeKind(%u)", name, unsigned(kind));
115 void spewAllocKindImm(const char* name, gc::AllocKind kind) {
116 out_.printf("%s AllocKind(%u)", name, unsigned(kind));
118 void spewCompletionKindImm(const char* name, CompletionKind kind) {
119 out_.printf("%s CompletionKind(%u)", name, unsigned(kind));
121 void spewRealmFuseIndexImm(const char* name, RealmFuses::FuseIndex index) {
122 out_.printf("%s RealmFuseIndex(%u=%s)", name, unsigned(index),
123 RealmFuses::getFuseName(index));
126 public:
127 CacheIROpsJitSpewer(GenericPrinter& out, const char* prefix)
128 : out_(out), prefix_(prefix) {}
130 void spew(CacheIRReader& reader) {
131 do {
132 switch (reader.readOp()) {
133 # define SPEW_OP(op, ...) \
134 case CacheOp::op: \
135 spew##op(reader); \
136 break;
137 CACHE_IR_OPS(SPEW_OP)
138 # undef SPEW_OP
140 default:
141 MOZ_CRASH("Invalid op");
143 } while (reader.more());
147 void js::jit::SpewCacheIROps(GenericPrinter& out, const char* prefix,
148 const CacheIRStubInfo* info) {
149 CacheIRReader reader(info);
150 CacheIROpsJitSpewer spewer(out, prefix);
151 spewer.spew(reader);
154 // JSON spewer for CacheIR ops. Output looks like this:
156 // ...
157 // {
158 // "op":"GuardToInt32",
159 // "args":[
160 // {
161 // "name":"inputId",
162 // "type":"Id",
163 // "value":0
164 // },
165 // {
166 // "name":"resultId",
167 // "type":"Id",
168 // "value":1
169 // }
170 // ]
171 // },
172 // {
173 // "op":"Int32IncResult",
174 // "args":[
175 // {
176 // "name":"inputId",
177 // "type":"Id",
178 // "value":1
179 // }
180 // ]
181 // }
182 // ...
183 class MOZ_RAII CacheIROpsJSONSpewer {
184 JSONPrinter& j_;
186 CACHE_IR_SPEWER_GENERATED
188 void spewOp(CacheOp op) {
189 const char* opName = CacheIROpNames[size_t(op)];
190 j_.beginObject();
191 j_.property("op", opName);
192 j_.beginListProperty("args");
194 void spewOpEnd() {
195 j_.endList();
196 j_.endObject();
199 void spewArgSeparator() {}
201 template <typename T>
202 void spewArgImpl(const char* name, const char* type, T value) {
203 j_.beginObject();
204 j_.property("name", name);
205 j_.property("type", type);
206 j_.property("value", value);
207 j_.endObject();
210 void spewOperandId(const char* name, OperandId id) {
211 spewRawOperandId(name, id.id());
213 void spewRawOperandId(const char* name, uint32_t id) {
214 spewArgImpl(name, "Id", id);
216 void spewField(const char* name, uint32_t offset) {
217 spewArgImpl(name, "Field", offset);
219 void spewBoolImm(const char* name, bool b) { spewArgImpl(name, "Imm", b); }
220 void spewByteImm(const char* name, uint8_t val) {
221 spewArgImpl(name, "Imm", val);
223 void spewJSOpImm(const char* name, JSOp op) {
224 spewArgImpl(name, "JSOp", CodeName(op));
226 void spewStaticStringImm(const char* name, const char* str) {
227 spewArgImpl(name, "String", str);
229 void spewInt32Imm(const char* name, int32_t val) {
230 spewArgImpl(name, "Imm", val);
232 void spewUInt32Imm(const char* name, uint32_t val) {
233 spewArgImpl(name, "Imm", val);
235 void spewCallFlagsImm(const char* name, CallFlags flags) {
236 spewArgImpl(name, "Imm", flags.toByte());
238 void spewJSWhyMagicImm(const char* name, JSWhyMagic magic) {
239 spewArgImpl(name, "Imm", unsigned(magic));
241 void spewScalarTypeImm(const char* name, Scalar::Type type) {
242 spewArgImpl(name, "Imm", unsigned(type));
244 void spewUnaryMathFunctionImm(const char* name, UnaryMathFunction fun) {
245 const char* funName = GetUnaryMathFunctionName(fun);
246 spewArgImpl(name, "MathFunction", funName);
248 void spewValueTypeImm(const char* name, ValueType type) {
249 spewArgImpl(name, "Imm", unsigned(type));
251 void spewJSNativeImm(const char* name, JSNative native) {
252 spewArgImpl(name, "Word", uintptr_t(native));
254 void spewGuardClassKindImm(const char* name, GuardClassKind kind) {
255 spewArgImpl(name, "Imm", unsigned(kind));
257 void spewArrayBufferViewKindImm(const char* name, ArrayBufferViewKind kind) {
258 spewArgImpl(name, "Imm", unsigned(kind));
260 void spewRealmFuseIndexImm(const char* name, RealmFuses::FuseIndex kind) {
261 spewArgImpl(name, "Imm", unsigned(kind));
263 void spewWasmValTypeImm(const char* name, wasm::ValType::Kind kind) {
264 spewArgImpl(name, "Imm", unsigned(kind));
266 void spewAllocKindImm(const char* name, gc::AllocKind kind) {
267 spewArgImpl(name, "Imm", unsigned(kind));
269 void spewCompletionKindImm(const char* name, CompletionKind kind) {
270 spewArgImpl(name, "Imm", unsigned(kind));
273 public:
274 explicit CacheIROpsJSONSpewer(JSONPrinter& j) : j_(j) {}
276 void spew(CacheIRReader& reader) {
277 do {
278 switch (reader.readOp()) {
279 # define SPEW_OP(op, ...) \
280 case CacheOp::op: \
281 spew##op(reader); \
282 break;
283 CACHE_IR_OPS(SPEW_OP)
284 # undef SPEW_OP
286 default:
287 MOZ_CRASH("Invalid op");
289 } while (reader.more());
293 CacheIRSpewer CacheIRSpewer::cacheIRspewer;
295 CacheIRSpewer::CacheIRSpewer()
296 : outputLock_(mutexid::CacheIRSpewer), guardCount_(0) {
297 spewInterval_ =
298 getenv("CACHEIR_LOG_FLUSH") ? atoi(getenv("CACHEIR_LOG_FLUSH")) : 10000;
300 if (spewInterval_ < 1) {
301 spewInterval_ = 1;
305 CacheIRSpewer::~CacheIRSpewer() {
306 if (!enabled()) {
307 return;
310 json_.ref().endList();
311 output_.flush();
312 output_.finish();
315 # ifndef JIT_SPEW_DIR
316 # if defined(_WIN32)
317 # define JIT_SPEW_DIR "."
318 # elif defined(__ANDROID__)
319 # define JIT_SPEW_DIR "/data/local/tmp"
320 # else
321 # define JIT_SPEW_DIR "/tmp"
322 # endif
323 # endif
325 bool CacheIRSpewer::init(const char* filename) {
326 if (enabled()) {
327 return true;
330 char name[256];
331 uint32_t pid = getpid();
332 // Default to JIT_SPEW_DIR/cacheir${pid}.json
333 if (filename[0] == '1') {
334 SprintfLiteral(name, JIT_SPEW_DIR "/cacheir%" PRIu32 ".json", pid);
335 } else {
336 SprintfLiteral(name, "%s%" PRIu32 ".json", filename, pid);
339 if (!output_.init(name)) {
340 return false;
343 json_.emplace(output_);
344 json_->beginList();
345 return true;
348 void CacheIRSpewer::beginCache(const IRGenerator& gen) {
349 MOZ_ASSERT(enabled());
350 JSONPrinter& j = json_.ref();
351 const char* filename = gen.script_->filename();
352 j.beginObject();
353 j.property("name", CacheKindNames[uint8_t(gen.cacheKind_)]);
354 j.property("file", filename ? filename : "null");
355 j.property("mode", int(gen.mode_));
356 if (jsbytecode* pc = gen.pc_) {
357 JS::LimitedColumnNumberOneOrigin column;
358 j.property("line", PCToLineNumber(gen.script_, pc, &column));
359 j.property("column", column.oneOriginValue());
360 j.formatProperty("pc", "%p", pc);
364 void CacheIRSpewer::valueProperty(const char* name, const Value& v) {
365 MOZ_ASSERT(enabled());
366 JSONPrinter& j = json_.ref();
368 j.beginObjectProperty(name);
370 const char* type = InformalValueTypeName(v);
371 if (v.isInt32()) {
372 type = "int32";
374 j.property("type", type);
376 if (v.isInt32()) {
377 j.property("value", v.toInt32());
378 } else if (v.isDouble()) {
379 j.floatProperty("value", v.toDouble(), 3);
380 } else if (v.isString() || v.isSymbol()) {
381 JSString* str = v.isString() ? v.toString() : v.toSymbol()->description();
382 if (str && str->isLinear()) {
383 j.property("value", &str->asLinear());
385 } else if (v.isObject()) {
386 JSObject& object = v.toObject();
387 j.formatProperty("value", "%p (shape: %p)", &object, object.shape());
389 if (object.is<JSFunction>()) {
390 if (JSAtom* name = object.as<JSFunction>().maybePartialDisplayAtom()) {
391 j.property("funName", name);
395 if (NativeObject* nobj =
396 object.is<NativeObject>() ? &object.as<NativeObject>() : nullptr) {
397 j.beginListProperty("flags");
399 if (nobj->isIndexed()) {
400 j.value("indexed");
402 if (nobj->inDictionaryMode()) {
403 j.value("dictionaryMode");
406 j.endList();
407 if (nobj->isIndexed()) {
408 j.beginObjectProperty("indexed");
410 j.property("denseInitializedLength",
411 nobj->getDenseInitializedLength());
412 j.property("denseCapacity", nobj->getDenseCapacity());
413 j.property("denseElementsAreSealed", nobj->denseElementsAreSealed());
414 j.property("denseElementsAreFrozen", nobj->denseElementsAreFrozen());
416 j.endObject();
421 j.endObject();
424 void CacheIRSpewer::opcodeProperty(const char* name, const JSOp op) {
425 MOZ_ASSERT(enabled());
426 JSONPrinter& j = json_.ref();
428 j.beginStringProperty(name);
429 output_.put(CodeName(op));
430 j.endStringProperty();
433 void CacheIRSpewer::cacheIRSequence(CacheIRReader& reader) {
434 MOZ_ASSERT(enabled());
435 JSONPrinter& j = json_.ref();
437 j.beginListProperty("cacheIR");
439 CacheIROpsJSONSpewer spewer(j);
440 spewer.spew(reader);
442 j.endList();
445 void CacheIRSpewer::attached(const char* name) {
446 MOZ_ASSERT(enabled());
447 json_.ref().property("attached", name);
450 void CacheIRSpewer::endCache() {
451 MOZ_ASSERT(enabled());
452 json_.ref().endObject();
455 #endif /* JS_CACHEIR_SPEW */