CacheIRSpewer.cpp (21110B)
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/. */ 6 7 #include "jit/CacheIRSpewer.h" 8 9 #include "mozilla/Sprintf.h" 10 11 #include "jsapi.h" 12 #include "jsmath.h" 13 14 #include "js/ColumnNumber.h" // JS::LimitedColumnNumberOneOrigin 15 #include "js/Printer.h" // js::GenericPrinter 16 #include "js/ScalarType.h" // js::Scalar::Type 17 #include "util/GetPidProvider.h" 18 #include "util/Text.h" 19 #include "vm/JSFunction.h" 20 #include "vm/JSObject.h" 21 #include "vm/JSScript.h" 22 23 #include "vm/JSObject-inl.h" 24 #include "vm/Realm-inl.h" 25 26 using namespace js; 27 using namespace js::jit; 28 29 #ifdef JS_CACHEIR_SPEW 30 31 // Text spewer for CacheIR ops that can be used with JitSpew. 32 // Output looks like this: 33 // 34 // GuardToInt32 inputId 0, resultId 2 35 // GuardToInt32 inputId 1, resultId 3 36 // CompareInt32Result op JSOp::Lt, lhsId 2, rhsId 3 37 // ReturnFromIC 38 class MOZ_RAII CacheIROpsJitSpewer { 39 GenericPrinter& out_; 40 41 // String prepended to each line. Can be used for indentation. 42 const char* prefix_; 43 44 CACHE_IR_SPEWER_GENERATED 45 46 void spewOp(CacheOp op) { 47 const char* opName = CacheIROpNames[size_t(op)]; 48 out_.printf("%s%-30s", prefix_, opName); 49 } 50 void spewOpEnd() { out_.printf("\n"); } 51 52 void spewArgSeparator() { out_.printf(", "); } 53 54 void spewOperandId(const char* name, OperandId id) { 55 spewRawOperandId(name, id.id()); 56 } 57 void spewRawOperandId(const char* name, uint32_t id) { 58 out_.printf("%s %u", name, id); 59 } 60 void spewField(const char* name, uint32_t offset) { 61 out_.printf("%s %u", name, offset); 62 } 63 void spewBoolImm(const char* name, bool b) { 64 out_.printf("%s %s", name, b ? "true" : "false"); 65 } 66 void spewByteImm(const char* name, uint8_t val) { 67 out_.printf("%s %u", name, val); 68 } 69 void spewJSOpImm(const char* name, JSOp op) { 70 out_.printf("%s JSOp::%s", name, CodeName(op)); 71 } 72 void spewTypeofEqOperandImm(const char* name, TypeofEqOperand operand) { 73 out_.printf("%s %s %s", name, JSTypeToString(operand.type()), 74 CodeName(operand.compareOp())); 75 } 76 void spewStaticStringImm(const char* name, const char* str) { 77 out_.printf("%s \"%s\"", name, str); 78 } 79 void spewInt32Imm(const char* name, int32_t val) { 80 out_.printf("%s %d", name, val); 81 } 82 void spewUInt32Imm(const char* name, uint32_t val) { 83 out_.printf("%s %u", name, val); 84 } 85 void spewCallFlagsImm(const char* name, CallFlags flags) { 86 out_.printf( 87 "%s (format %u%s%s%s)", name, flags.getArgFormat(), 88 flags.isConstructing() ? ", isConstructing" : "", 89 flags.isSameRealm() ? ", isSameRealm" : "", 90 flags.needsUninitializedThis() ? ", needsUninitializedThis" : ""); 91 } 92 void spewJSWhyMagicImm(const char* name, JSWhyMagic magic) { 93 out_.printf("%s JSWhyMagic(%u)", name, unsigned(magic)); 94 } 95 void spewScalarTypeImm(const char* name, Scalar::Type type) { 96 out_.printf("%s Scalar::Type(%u)", name, unsigned(type)); 97 } 98 void spewUnaryMathFunctionImm(const char* name, UnaryMathFunction fun) { 99 const char* funName = GetUnaryMathFunctionName(fun); 100 out_.printf("%s UnaryMathFunction::%s", name, funName); 101 } 102 void spewValueTypeImm(const char* name, ValueType type) { 103 out_.printf("%s ValueType(%u)", name, unsigned(type)); 104 } 105 void spewJSNativeImm(const char* name, JSNative native) { 106 out_.printf("%s %p", name, native); 107 } 108 void spewGuardClassKindImm(const char* name, GuardClassKind kind) { 109 out_.printf("%s GuardClassKind(%u)", name, unsigned(kind)); 110 } 111 void spewArrayBufferViewKindImm(const char* name, ArrayBufferViewKind kind) { 112 out_.printf("%s ArrayBufferViewKind(%u)", name, unsigned(kind)); 113 } 114 void spewWasmValTypeImm(const char* name, wasm::ValType::Kind kind) { 115 out_.printf("%s WasmValTypeKind(%u)", name, unsigned(kind)); 116 } 117 void spewAllocKindImm(const char* name, gc::AllocKind kind) { 118 out_.printf("%s AllocKind(%u)", name, unsigned(kind)); 119 } 120 void spewCompletionKindImm(const char* name, CompletionKind kind) { 121 out_.printf("%s CompletionKind(%u)", name, unsigned(kind)); 122 } 123 void spewRealmFuseIndexImm(const char* name, RealmFuses::FuseIndex index) { 124 out_.printf("%s RealmFuseIndex(%u=%s)", name, unsigned(index), 125 RealmFuses::getFuseName(index)); 126 } 127 void spewRuntimeFuseIndexImm(const char* name, 128 RuntimeFuses::FuseIndex index) { 129 out_.printf("%s RuntimeFuseIndex(%u=%s)", name, unsigned(index), 130 RuntimeFuses::getFuseName(index)); 131 } 132 133 public: 134 CacheIROpsJitSpewer(GenericPrinter& out, const char* prefix) 135 : out_(out), prefix_(prefix) {} 136 137 void spew(CacheIRReader& reader) { 138 do { 139 switch (reader.readOp()) { 140 # define SPEW_OP(op, ...) \ 141 case CacheOp::op: \ 142 spew##op(reader); \ 143 break; 144 CACHE_IR_OPS(SPEW_OP) 145 # undef SPEW_OP 146 147 default: 148 MOZ_CRASH("Invalid op"); 149 } 150 } while (reader.more()); 151 } 152 }; 153 154 void js::jit::SpewCacheIROps(GenericPrinter& out, const char* prefix, 155 CacheIRReader& reader) { 156 CacheIROpsJitSpewer spewer(out, prefix); 157 spewer.spew(reader); 158 } 159 160 void js::jit::SpewCacheIROps(GenericPrinter& out, const char* prefix, 161 const CacheIRStubInfo* info) { 162 CacheIRReader reader(info); 163 SpewCacheIROps(out, prefix, reader); 164 } 165 166 // JSON spewer for CacheIR ops. Output looks like this: 167 // 168 // ... 169 // { 170 // "op":"GuardToInt32", 171 // "args":[ 172 // { 173 // "name":"inputId", 174 // "type":"Id", 175 // "value":0 176 // }, 177 // { 178 // "name":"resultId", 179 // "type":"Id", 180 // "value":1 181 // } 182 // ] 183 // }, 184 // { 185 // "op":"Int32IncResult", 186 // "args":[ 187 // { 188 // "name":"inputId", 189 // "type":"Id", 190 // "value":1 191 // } 192 // ] 193 // } 194 // ... 195 class MOZ_RAII CacheIROpsJSONSpewer { 196 JSONPrinter& j_; 197 198 CACHE_IR_SPEWER_GENERATED 199 200 void spewOp(CacheOp op) { 201 const char* opName = CacheIROpNames[size_t(op)]; 202 j_.beginObject(); 203 j_.property("op", opName); 204 j_.beginListProperty("args"); 205 } 206 void spewOpEnd() { 207 j_.endList(); 208 j_.endObject(); 209 } 210 211 void spewArgSeparator() {} 212 213 template <typename T> 214 void spewArgImpl(const char* name, const char* type, T value) { 215 j_.beginObject(); 216 j_.property("name", name); 217 j_.property("type", type); 218 j_.property("value", value); 219 j_.endObject(); 220 } 221 222 void spewOperandId(const char* name, OperandId id) { 223 spewRawOperandId(name, id.id()); 224 } 225 void spewRawOperandId(const char* name, uint32_t id) { 226 spewArgImpl(name, "Id", id); 227 } 228 void spewField(const char* name, uint32_t offset) { 229 spewArgImpl(name, "Field", offset); 230 } 231 void spewBoolImm(const char* name, bool b) { spewArgImpl(name, "Imm", b); } 232 void spewByteImm(const char* name, uint8_t val) { 233 spewArgImpl(name, "Imm", val); 234 } 235 void spewJSOpImm(const char* name, JSOp op) { 236 spewArgImpl(name, "JSOp", CodeName(op)); 237 } 238 void spewTypeofEqOperandImm(const char* name, TypeofEqOperand operand) { 239 spewArgImpl(name, "TypeofEqOperand", uint8_t(operand.rawValue())); 240 } 241 void spewStaticStringImm(const char* name, const char* str) { 242 spewArgImpl(name, "String", str); 243 } 244 void spewInt32Imm(const char* name, int32_t val) { 245 spewArgImpl(name, "Imm", val); 246 } 247 void spewUInt32Imm(const char* name, uint32_t val) { 248 spewArgImpl(name, "Imm", val); 249 } 250 void spewCallFlagsImm(const char* name, CallFlags flags) { 251 spewArgImpl(name, "Imm", flags.toByte()); 252 } 253 void spewJSWhyMagicImm(const char* name, JSWhyMagic magic) { 254 spewArgImpl(name, "Imm", unsigned(magic)); 255 } 256 void spewScalarTypeImm(const char* name, Scalar::Type type) { 257 spewArgImpl(name, "Imm", unsigned(type)); 258 } 259 void spewUnaryMathFunctionImm(const char* name, UnaryMathFunction fun) { 260 const char* funName = GetUnaryMathFunctionName(fun); 261 spewArgImpl(name, "MathFunction", funName); 262 } 263 void spewValueTypeImm(const char* name, ValueType type) { 264 spewArgImpl(name, "Imm", unsigned(type)); 265 } 266 void spewJSNativeImm(const char* name, JSNative native) { 267 spewArgImpl(name, "Word", uintptr_t(native)); 268 } 269 void spewGuardClassKindImm(const char* name, GuardClassKind kind) { 270 spewArgImpl(name, "Imm", unsigned(kind)); 271 } 272 void spewArrayBufferViewKindImm(const char* name, ArrayBufferViewKind kind) { 273 spewArgImpl(name, "Imm", unsigned(kind)); 274 } 275 void spewRealmFuseIndexImm(const char* name, RealmFuses::FuseIndex kind) { 276 spewArgImpl(name, "Imm", unsigned(kind)); 277 } 278 void spewRuntimeFuseIndexImm(const char* name, RuntimeFuses::FuseIndex kind) { 279 spewArgImpl(name, "Imm", unsigned(kind)); 280 } 281 void spewWasmValTypeImm(const char* name, wasm::ValType::Kind kind) { 282 spewArgImpl(name, "Imm", unsigned(kind)); 283 } 284 void spewAllocKindImm(const char* name, gc::AllocKind kind) { 285 spewArgImpl(name, "Imm", unsigned(kind)); 286 } 287 void spewCompletionKindImm(const char* name, CompletionKind kind) { 288 spewArgImpl(name, "Imm", unsigned(kind)); 289 } 290 291 public: 292 explicit CacheIROpsJSONSpewer(JSONPrinter& j) : j_(j) {} 293 294 void spew(CacheIRReader& reader) { 295 do { 296 switch (reader.readOp()) { 297 # define SPEW_OP(op, ...) \ 298 case CacheOp::op: \ 299 spew##op(reader); \ 300 break; 301 CACHE_IR_OPS(SPEW_OP) 302 # undef SPEW_OP 303 304 default: 305 MOZ_CRASH("Invalid op"); 306 } 307 } while (reader.more()); 308 } 309 }; 310 311 MOZ_RUNINIT CacheIRSpewer CacheIRSpewer::cacheIRspewer; 312 313 CacheIRSpewer::CacheIRSpewer() 314 : outputLock_(mutexid::CacheIRSpewer), guardCount_(0) { 315 spewInterval_ = 316 getenv("CACHEIR_LOG_FLUSH") ? atoi(getenv("CACHEIR_LOG_FLUSH")) : 10000; 317 318 if (spewInterval_ < 1) { 319 spewInterval_ = 1; 320 } 321 } 322 323 CacheIRSpewer::~CacheIRSpewer() { 324 if (!enabled()) { 325 return; 326 } 327 328 json_.ref().endList(); 329 output_.flush(); 330 output_.finish(); 331 } 332 333 # ifndef JIT_SPEW_DIR 334 # if defined(_WIN32) 335 # define JIT_SPEW_DIR "." 336 # elif defined(__ANDROID__) 337 # define JIT_SPEW_DIR "/data/local/tmp" 338 # else 339 # define JIT_SPEW_DIR "/tmp" 340 # endif 341 # endif 342 343 bool CacheIRSpewer::init(const char* filename) { 344 if (enabled()) { 345 return true; 346 } 347 348 char name[256]; 349 uint32_t pid = getpid(); 350 // Default to JIT_SPEW_DIR/cacheir${pid}.json 351 if (filename[0] == '1') { 352 SprintfLiteral(name, JIT_SPEW_DIR "/cacheir%" PRIu32 ".json", pid); 353 } else { 354 SprintfLiteral(name, "%s%" PRIu32 ".json", filename, pid); 355 } 356 357 if (!output_.init(name)) { 358 return false; 359 } 360 361 json_.emplace(output_); 362 json_->beginList(); 363 return true; 364 } 365 366 void CacheIRSpewer::beginCache(const IRGenerator& gen) { 367 MOZ_ASSERT(enabled()); 368 JSONPrinter& j = json_.ref(); 369 const char* filename = gen.script_->filename(); 370 j.beginObject(); 371 j.property("name", CacheKindNames[uint8_t(gen.cacheKind_)]); 372 j.property("file", filename ? filename : "null"); 373 j.property("mode", int(gen.mode_)); 374 if (jsbytecode* pc = gen.pc_) { 375 JS::LimitedColumnNumberOneOrigin column; 376 j.property("line", PCToLineNumber(gen.script_, pc, &column)); 377 j.property("column", column.oneOriginValue()); 378 j.formatProperty("pc", "%p", pc); 379 } 380 } 381 382 void CacheIRSpewer::valueProperty(const char* name, const Value& v) { 383 MOZ_ASSERT(enabled()); 384 JSONPrinter& j = json_.ref(); 385 386 j.beginObjectProperty(name); 387 388 const char* type = InformalValueTypeName(v); 389 if (v.isInt32()) { 390 type = "int32"; 391 } 392 j.property("type", type); 393 394 if (v.isInt32()) { 395 j.property("value", v.toInt32()); 396 } else if (v.isDouble()) { 397 j.floatProperty("value", v.toDouble(), 3); 398 } else if (v.isString() || v.isSymbol()) { 399 JSString* str = v.isString() ? v.toString() : v.toSymbol()->description(); 400 if (str && str->isLinear()) { 401 j.property("value", &str->asLinear()); 402 } 403 } else if (v.isObject()) { 404 JSObject& object = v.toObject(); 405 j.formatProperty("value", "%p (shape: %p)", &object, object.shape()); 406 407 if (object.is<JSFunction>()) { 408 if (JSAtom* name = object.as<JSFunction>().maybePartialDisplayAtom()) { 409 j.property("funName", name); 410 } 411 } 412 413 if (NativeObject* nobj = 414 object.is<NativeObject>() ? &object.as<NativeObject>() : nullptr) { 415 j.beginListProperty("flags"); 416 { 417 if (nobj->isIndexed()) { 418 j.value("indexed"); 419 } 420 if (nobj->inDictionaryMode()) { 421 j.value("dictionaryMode"); 422 } 423 } 424 j.endList(); 425 if (nobj->isIndexed()) { 426 j.beginObjectProperty("indexed"); 427 { 428 j.property("denseInitializedLength", 429 nobj->getDenseInitializedLength()); 430 j.property("denseCapacity", nobj->getDenseCapacity()); 431 j.property("denseElementsAreSealed", nobj->denseElementsAreSealed()); 432 j.property("denseElementsAreFrozen", nobj->denseElementsAreFrozen()); 433 } 434 j.endObject(); 435 } 436 } 437 } 438 439 j.endObject(); 440 } 441 442 void CacheIRSpewer::opcodeProperty(const char* name, const JSOp op) { 443 MOZ_ASSERT(enabled()); 444 JSONPrinter& j = json_.ref(); 445 446 j.beginStringProperty(name); 447 output_.put(CodeName(op)); 448 j.endStringProperty(); 449 } 450 451 void CacheIRSpewer::jstypeProperty(const char* name, const JSType type) { 452 MOZ_ASSERT(enabled()); 453 JSONPrinter& j = json_.ref(); 454 455 j.beginStringProperty(name); 456 output_.put(JSTypeToString(type)); 457 j.endStringProperty(); 458 } 459 460 void CacheIRSpewer::cacheIRSequence(CacheIRReader& reader) { 461 MOZ_ASSERT(enabled()); 462 JSONPrinter& j = json_.ref(); 463 464 j.beginListProperty("cacheIR"); 465 466 CacheIROpsJSONSpewer spewer(j); 467 spewer.spew(reader); 468 469 j.endList(); 470 } 471 472 void CacheIRSpewer::attached(const char* name) { 473 MOZ_ASSERT(enabled()); 474 json_.ref().property("attached", name); 475 } 476 477 void CacheIRSpewer::endCache() { 478 MOZ_ASSERT(enabled()); 479 json_.ref().endObject(); 480 } 481 482 #endif /* JS_CACHEIR_SPEW */ 483 484 #ifdef ENABLE_JS_AOT_ICS 485 486 // Note: for several of the functions below that return string 487 // representations of enums, it's important to keep the strings below 488 // *exactly* in sync with the names of the defined constants. The string 489 // that this function returns is used to generate the checked-in corpus 490 // source code. 491 492 static const char* JSValueTypeToString(JSValueType type) { 493 switch (type) { 494 case JSVAL_TYPE_DOUBLE: 495 return "JSVAL_TYPE_DOUBLE"; 496 case JSVAL_TYPE_INT32: 497 return "JSVAL_TYPE_INT32"; 498 case JSVAL_TYPE_BOOLEAN: 499 return "JSVAL_TYPE_BOOLEAN"; 500 case JSVAL_TYPE_UNDEFINED: 501 return "JSVAL_TYPE_UNDEFINED"; 502 case JSVAL_TYPE_NULL: 503 return "JSVAL_TYPE_NULL"; 504 case JSVAL_TYPE_MAGIC: 505 return "JSVAL_TYPE_MAGIC"; 506 case JSVAL_TYPE_STRING: 507 return "JSVAL_TYPE_STRING"; 508 case JSVAL_TYPE_SYMBOL: 509 return "JSVAL_TYPE_SYMBOL"; 510 case JSVAL_TYPE_PRIVATE_GCTHING: 511 return "JSVAL_TYPE_PRIVATE_GCTHING"; 512 case JSVAL_TYPE_BIGINT: 513 return "JSVAL_TYPE_BIGINT"; 514 case JSVAL_TYPE_OBJECT: 515 return "JSVAL_TYPE_OBJECT"; 516 case JSVAL_TYPE_UNKNOWN: 517 return "JSVAL_TYPE_UNKNOWN"; 518 } 519 MOZ_CRASH("Unknown JSValueType"); 520 } 521 522 static const char* ArrayBufferViewKindName(ArrayBufferViewKind kind) { 523 switch (kind) { 524 case ArrayBufferViewKind::FixedLength: 525 return "FixedLength"; 526 case ArrayBufferViewKind::Resizable: 527 return "Resizable"; 528 } 529 MOZ_CRASH("Unknown ArrayBufferViewKind"); 530 } 531 532 // Text spewer for CacheIR ops that produces output that can be included 533 // in the AOT IC corpus. 534 // 535 // Output looks like this: 536 // 537 // OP(GuardToInt32) ID(0) ID(2) 538 // OP(GuardToInt32) ID(1) ID(3) 539 // OP(CompareInt32Result) JSOP(Lt) ID(2) ID(3) 540 // OP(ReturnFromIC) 541 // 542 // The output is meant to be interpreted in the context of defined 543 // preprocessor macros to reproduce the CacheIR bytecode. 544 class MOZ_RAII CacheIROpsAotSpewer { 545 GenericPrinter& out_; 546 547 CACHE_IR_SPEWER_GENERATED 548 549 void spewOp(CacheOp op) { 550 const char* opName = CacheIROpNames[size_t(op)]; 551 out_.printf("OP(%s) ", opName); 552 } 553 void spewOpEnd() { out_.printf(" "); } 554 555 void spewArgSeparator() { out_.printf(" "); } 556 557 void spewOperandId(const char* name, OperandId id) { 558 spewRawOperandId(name, id.id()); 559 } 560 void spewRawOperandId(const char* name, uint32_t id) { 561 (void)name; 562 out_.printf("ID(%u)", id); 563 } 564 void spewField(const char* name, uint32_t offset) { 565 (void)name; 566 out_.printf("OFFSET(%d)", int(offset / sizeof(uintptr_t))); 567 } 568 void spewBoolImm(const char* name, bool b) { 569 (void)name; 570 out_.printf("BOOL(%d)", b ? 1 : 0); 571 } 572 void spewByteImm(const char* name, uint8_t val) { 573 (void)name; 574 out_.printf("BYTE(%u)", val); 575 } 576 void spewJSOpImm(const char* name, JSOp op) { 577 (void)name; 578 out_.printf("JSOP(%s)", CodeName(op)); 579 } 580 void spewTypeofEqOperandImm(const char* name, TypeofEqOperand operand) { 581 (void)name; 582 out_.printf(name, "TYPEOFEQOPERAND(%u)", operand.rawValue()); 583 } 584 void spewStaticStringImm(const char* name, const char* str) { 585 (void)name; 586 out_.printf("STATICSTRING(\"%s\")", str); 587 } 588 void spewInt32Imm(const char* name, int32_t val) { 589 (void)name; 590 out_.printf("INT32(%d)", val); 591 } 592 void spewUInt32Imm(const char* name, uint32_t val) { 593 (void)name; 594 out_.printf("UINT32(%u)", val); 595 } 596 void spewCallFlagsImm(const char* name, CallFlags flags) { 597 (void)name; 598 out_.printf("CALLFLAGS(%u)", flags.toByte()); 599 } 600 void spewJSWhyMagicImm(const char* name, JSWhyMagic magic) { 601 (void)name; 602 out_.printf("WHYMAGIC(%u)", unsigned(magic)); 603 } 604 void spewScalarTypeImm(const char* name, Scalar::Type type) { 605 (void)name; 606 out_.printf("SCALARTYPE(%s)", Scalar::name(type)); 607 } 608 void spewUnaryMathFunctionImm(const char* name, UnaryMathFunction fun) { 609 (void)name; 610 const char* funName = GetUnaryMathFunctionName(fun, true); 611 out_.printf("UNARYMATHFUNC(%s)", funName); 612 } 613 void spewValueTypeImm(const char* name, ValueType type) { 614 (void)name; 615 out_.printf("VALUETYPE(%s)", 616 JSValueTypeToString(static_cast<JSValueType>(type))); 617 } 618 void spewJSNativeImm(const char* name, JSNative native) { 619 (void)name; 620 out_.printf("NATIVEIMM(%p)", native); 621 } 622 void spewGuardClassKindImm(const char* name, GuardClassKind kind) { 623 (void)name; 624 out_.printf("GUARDCLASSKIND(%s)", GuardClassKindEnumName(kind)); 625 } 626 void spewArrayBufferViewKindImm(const char* name, ArrayBufferViewKind kind) { 627 (void)name; 628 out_.printf("ARRAYBUFFERVIEWKIND(%s)", ArrayBufferViewKindName(kind)); 629 } 630 void spewWasmValTypeImm(const char* name, wasm::ValType::Kind kind) { 631 (void)name; 632 out_.printf("WASMVALTYPE(%s)", wasm::ValTypeTraits::KindEnumName(kind)); 633 } 634 void spewAllocKindImm(const char* name, gc::AllocKind kind) { 635 (void)name; 636 out_.printf("ALLOCKIND(%s)", js::gc::AllocKindName(kind)); 637 } 638 void spewCompletionKindImm(const char* name, CompletionKind kind) { 639 (void)name; 640 out_.printf("COMPLETIONKIND(%s)", CompletionKindName(kind)); 641 } 642 void spewRealmFuseIndexImm(const char* name, RealmFuses::FuseIndex index) { 643 (void)name; 644 out_.printf("REALMFUSE(%u)", unsigned(index)); 645 } 646 void spewRuntimeFuseIndexImm(const char* name, 647 RuntimeFuses::FuseIndex index) { 648 (void)name; 649 out_.printf("RUNTIMEFUSE(%u)", unsigned(index)); 650 } 651 652 public: 653 CacheIROpsAotSpewer(GenericPrinter& out) : out_(out) {} 654 655 void spew(CacheIRReader& reader) { 656 do { 657 switch (reader.readOp()) { 658 # define SPEW_OP(op, ...) \ 659 case CacheOp::op: \ 660 spew##op(reader); \ 661 break; 662 CACHE_IR_OPS(SPEW_OP) 663 # undef SPEW_OP 664 665 default: 666 MOZ_CRASH("Invalid op"); 667 } 668 } while (reader.more()); 669 } 670 }; 671 672 void js::jit::SpewCacheIROpsAsAOT(GenericPrinter& out, CacheKind kind, 673 const CacheIRWriter& writer) { 674 // Fields, comma-separated: 675 // - kind 676 // - numOperandIds (u32) 677 // - numInputOperands (u32) 678 // - numInstructions (u32) 679 // - typeData (TypeData aka JSValueType) 680 // - stubDataSize (u32) 681 // - stubFields (list of (StubField::Type, u64)) 682 // - operandLastUsed (list of u32) 683 out.printf("%s, %u, %u, %u, %s, %u, ", CacheKindNames[size_t(kind)], 684 writer.numInputOperands(), writer.numOperandIds(), 685 writer.numInstructions(), 686 JSValueTypeToString(writer.typeData().type()), 687 uint32_t(writer.stubDataSize())); 688 689 for (uint32_t i = 0; i < writer.numStubFields(); i++) { 690 auto field = writer.stubField(i); 691 out.printf("STUBFIELD(%s) ", StubFieldTypeName(field.type())); 692 } 693 out.printf(", "); 694 695 for (uint32_t i = 0; i < writer.numOperandIds(); i++) { 696 out.printf("LASTUSED(%u) ", writer.operandLastUsed(i)); 697 } 698 out.printf(", "); 699 700 CacheIRReader reader(writer.codeStart(), writer.codeEnd()); 701 CacheIROpsAotSpewer spewer(out); 702 spewer.spew(reader); 703 out.printf("\n"); 704 } 705 706 #endif /* ENABLE_JS_AOT_ICS */