tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 */