JitSpewer.cpp (20302B)
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 #ifdef JS_JITSPEW 8 9 # include "jit/JitSpewer.h" 10 11 # include "mozilla/Atomics.h" 12 # include "mozilla/Sprintf.h" 13 14 # include "jit/MIR.h" 15 # include "jit/MIRGenerator.h" 16 # include "jit/MIRGraph.h" 17 # include "threading/LockGuard.h" 18 # include "util/GetPidProvider.h" // getpid() 19 # include "vm/MutexIDs.h" 20 21 # ifndef JIT_SPEW_DIR 22 # if defined(_WIN32) 23 # define JIT_SPEW_DIR "." 24 # elif defined(__ANDROID__) 25 # define JIT_SPEW_DIR "/data/local/tmp" 26 # else 27 # define JIT_SPEW_DIR "/tmp" 28 # endif 29 # endif 30 31 using namespace js; 32 using namespace js::jit; 33 using namespace js::jitspew::detail; 34 35 class JitSpewGraphOutput { 36 private: 37 Mutex outputLock_ MOZ_UNANNOTATED; 38 Fprinter jsonOutput_; 39 GraphSpewer graphSpewer_; 40 bool firstFunction_; 41 bool asyncLogging_; 42 bool inited_; 43 44 void release(); 45 46 public: 47 JitSpewGraphOutput() 48 : outputLock_(mutexid::JitSpewGraphOutput), 49 graphSpewer_(jsonOutput_), 50 firstFunction_(false), 51 asyncLogging_(false), 52 inited_(false) {} 53 54 // File output is terminated safely upon destruction. 55 ~JitSpewGraphOutput(); 56 57 bool init(); 58 bool isEnabled() { return inited_; } 59 void setAsyncLogging(bool incremental) { asyncLogging_ = incremental; } 60 bool getAsyncLogging() { return asyncLogging_; } 61 62 void beginFunction(); 63 void spewPass(JitSpewGraphSpewer* gs); 64 void endFunction(JitSpewGraphSpewer* gs); 65 }; 66 67 // JitSpewGraphOutput singleton. 68 MOZ_RUNINIT static JitSpewGraphOutput jitSpewGraphOutput; 69 70 bool jitspew::detail::LoggingChecked = false; 71 static_assert(JitSpew_Terminator <= 64, 72 "Increase the size of the LoggingBits global."); 73 uint64_t jitspew::detail::LoggingBits = 0; 74 mozilla::Atomic<uint32_t, mozilla::Relaxed> 75 jitspew::detail::filteredOutCompilations(0); 76 77 static const char* const ChannelNames[] = { 78 # define JITSPEW_CHANNEL(name) #name, 79 JITSPEW_CHANNEL_LIST(JITSPEW_CHANNEL) 80 # undef JITSPEW_CHANNEL 81 }; 82 83 static size_t ChannelIndentLevel[] = { 84 # define JITSPEW_CHANNEL(name) 0, 85 JITSPEW_CHANNEL_LIST(JITSPEW_CHANNEL) 86 # undef JITSPEW_CHANNEL 87 }; 88 89 // The IONFILTER environment variable specifies an expression to select only 90 // certain functions for spewing to reduce amount of log data generated. 91 static const char* gSpewFilter = nullptr; 92 93 static bool FilterContainsLocation(JSScript* function) { 94 // If there is no filter we accept all outputs. 95 if (!gSpewFilter || !gSpewFilter[0]) { 96 return true; 97 } 98 99 // Disable wasm output when filter is set. 100 if (!function) { 101 return false; 102 } 103 104 const char* filename = function->filename(); 105 const size_t line = function->lineno(); 106 const size_t filelen = strlen(filename); 107 const char* index = strstr(gSpewFilter, filename); 108 while (index) { 109 if (index == gSpewFilter || index[-1] == ',') { 110 if (index[filelen] == 0 || index[filelen] == ',') { 111 return true; 112 } 113 if (index[filelen] == ':' && line != size_t(-1)) { 114 size_t read_line = strtoul(&index[filelen + 1], nullptr, 10); 115 if (read_line == line) { 116 return true; 117 } 118 } 119 } 120 index = strstr(index + filelen, filename); 121 } 122 return false; 123 } 124 125 void jit::EnableIonDebugSyncLogging() { 126 jitSpewGraphOutput.init(); 127 jitSpewGraphOutput.setAsyncLogging(false); 128 EnableChannel(JitSpew_IonSyncLogs); 129 } 130 131 void jit::EnableIonDebugAsyncLogging() { 132 jitSpewGraphOutput.init(); 133 jitSpewGraphOutput.setAsyncLogging(true); 134 } 135 136 void JitSpewGraphOutput::release() { 137 if (jsonOutput_.isInitialized()) { 138 jsonOutput_.finish(); 139 } 140 inited_ = false; 141 } 142 143 bool JitSpewGraphOutput::init() { 144 if (inited_) { 145 return true; 146 } 147 148 // Filter expression for spewing 149 gSpewFilter = getenv("IONFILTER"); 150 151 const size_t bufferLength = 256; 152 char jsonBuffer[bufferLength]; 153 const char* jsonFilename = JIT_SPEW_DIR "/ion.json"; 154 155 const char* usePid = getenv("ION_SPEW_BY_PID"); 156 if (usePid && *usePid != 0) { 157 uint32_t pid = getpid(); 158 size_t len; 159 len = SprintfLiteral(jsonBuffer, JIT_SPEW_DIR "/ion%" PRIu32 ".json", pid); 160 if (bufferLength <= len) { 161 fprintf(stderr, 162 "Warning: JitSpewGraphOutput::init: Cannot serialize file name."); 163 return false; 164 } 165 jsonFilename = jsonBuffer; 166 } 167 168 if (!jsonOutput_.init(jsonFilename)) { 169 release(); 170 return false; 171 } 172 173 graphSpewer_.begin(); 174 firstFunction_ = true; 175 176 inited_ = true; 177 return true; 178 } 179 180 void JitSpewGraphOutput::beginFunction() { 181 // If we are doing a synchronous logging then we spew everything as we go, 182 // as this is useful in case of failure during the compilation. On the other 183 // hand, it is recommended to disable off thread compilation. 184 if (!getAsyncLogging() && !firstFunction_) { 185 LockGuard<Mutex> guard(outputLock_); 186 jsonOutput_.put(","); // separate functions 187 } 188 } 189 190 void JitSpewGraphOutput::spewPass(JitSpewGraphSpewer* gs) { 191 if (!getAsyncLogging()) { 192 LockGuard<Mutex> guard(outputLock_); 193 gs->dump(jsonOutput_); 194 } 195 } 196 197 void JitSpewGraphOutput::endFunction(JitSpewGraphSpewer* gs) { 198 LockGuard<Mutex> guard(outputLock_); 199 if (getAsyncLogging() && !firstFunction_) { 200 jsonOutput_.put(","); // separate functions 201 } 202 203 gs->dump(jsonOutput_); 204 firstFunction_ = false; 205 } 206 207 JitSpewGraphOutput::~JitSpewGraphOutput() { 208 if (!inited_) { 209 return; 210 } 211 212 graphSpewer_.end(); 213 release(); 214 } 215 216 JitSpewGraphSpewer::JitSpewGraphSpewer(TempAllocator* alloc, 217 const wasm::CodeMetadata* wasmCodeMeta) 218 : graph_(nullptr), 219 jsonPrinter_(alloc->lifoAlloc()), 220 graphSpewer_(jsonPrinter_, wasmCodeMeta) {} 221 222 void JitSpewGraphSpewer::init(MIRGraph* graph, JSScript* function) { 223 MOZ_ASSERT(!isSpewing()); 224 if (!jitSpewGraphOutput.isEnabled()) { 225 return; 226 } 227 228 if (!FilterContainsLocation(function)) { 229 // filter out logs during the compilation. 230 filteredOutCompilations++; 231 MOZ_ASSERT(!isSpewing()); 232 return; 233 } 234 235 graph_ = graph; 236 MOZ_ASSERT(isSpewing()); 237 } 238 239 void JitSpewGraphSpewer::beginFunction(JSScript* function) { 240 if (!isSpewing()) { 241 return; 242 } 243 graphSpewer_.beginFunction(function); 244 jitSpewGraphOutput.beginFunction(); 245 } 246 247 void JitSpewGraphSpewer::beginWasmFunction(unsigned funcIndex) { 248 if (!isSpewing()) { 249 return; 250 } 251 graphSpewer_.beginWasmFunction(funcIndex); 252 jitSpewGraphOutput.beginFunction(); 253 } 254 255 void JitSpewGraphSpewer::spewPass(const char* pass, BacktrackingAllocator* ra) { 256 if (!isSpewing()) { 257 return; 258 } 259 260 graphSpewer_.spewPass(pass, graph_, ra); 261 jitSpewGraphOutput.spewPass(this); 262 263 // As this function is used for debugging, we ignore any of the previous 264 // failures and ensure there is enough ballast space, such that we do not 265 // exhaust the ballast space before running the next phase. 266 AutoEnterOOMUnsafeRegion oomUnsafe; 267 if (!graph_->alloc().ensureBallast()) { 268 oomUnsafe.crash( 269 "Could not ensure enough ballast space after spewing graph " 270 "information."); 271 } 272 } 273 274 void JitSpewGraphSpewer::endFunction() { 275 if (!jitSpewGraphOutput.isEnabled()) { 276 return; 277 } 278 279 if (!isSpewing()) { 280 MOZ_ASSERT(filteredOutCompilations != 0); 281 filteredOutCompilations--; 282 return; 283 } 284 285 graphSpewer_.endFunction(); 286 287 jitSpewGraphOutput.endFunction(this); 288 graph_ = nullptr; 289 } 290 291 void JitSpewGraphSpewer::dump(Fprinter& jsonOut) { 292 if (!jsonPrinter_.hadOutOfMemory()) { 293 jsonPrinter_.exportInto(jsonOut); 294 } else { 295 jsonOut.put("{}"); 296 } 297 jsonOut.flush(); 298 jsonPrinter_.clear(); 299 } 300 301 Fprinter& jit::JitSpewPrinter() { 302 static Fprinter out; 303 return out; 304 } 305 306 static void PrintHelpAndExit(int status = 0) { 307 fflush(nullptr); 308 printf( 309 "\n" 310 "usage: IONFLAGS=option,option,option,... where options can be:\n" 311 "\n" 312 " aborts Compilation abort messages\n" 313 " scripts Compiled scripts\n" 314 " mir MIR information\n" 315 " prune Prune unused branches\n" 316 " escape Escape analysis\n" 317 " alias Alias analysis\n" 318 " alias-sum Alias analysis: shows summaries for every block\n" 319 " gvn Global Value Numbering\n" 320 " licm Loop invariant code motion\n" 321 " flac Fold linear arithmetic constants\n" 322 " eaa Effective address analysis\n" 323 " sink Sink transformation\n" 324 " regalloc Register allocation\n" 325 " inline Inlining\n" 326 " snapshots Snapshot information\n" 327 " codegen Native code generation\n" 328 " bailouts Bailouts\n" 329 " caches Inline caches\n" 330 " osi Invalidation\n" 331 " safepoints Safepoints\n" 332 " pools Literal Pools (ARM only for now)\n" 333 " cacheflush Instruction Cache flushes (ARM only for now)\n" 334 " range Range Analysis\n" 335 " branch-hint Wasm Branch Hinting\n" 336 " wasmbce Wasm Bounds Check Elimination\n" 337 " shapeguards Redundant shape guard elimination\n" 338 " gcbarriers Redundant GC barrier elimination\n" 339 " loadkeys Loads used as property keys\n" 340 " stubfolding CacheIR stub folding\n" 341 " stubfolding-details Same as stubfolding, but with spewing of stub " 342 "content.\n" 343 " logs JSON visualization logging\n" 344 " logs-sync Same as logs, but flushes between each pass (sync. " 345 "compiled functions only).\n" 346 " profiling Profiling-related information\n" 347 " dump-mir-expr Dump the MIR expressions\n" 348 " unroll Wasm loop unrolling and peeling -- summary info\n" 349 " unroll-details Wasm loop unrolling and peeling -- details\n" 350 " warp-snapshots WarpSnapshots created by WarpOracle\n" 351 " warp-transpiler Warp CacheIR transpiler\n" 352 " warp-trial-inlining Trial inlining for Warp\n" 353 " all Everything\n" 354 "\n" 355 " bl-aborts Baseline compiler abort messages\n" 356 " bl-scripts Baseline script-compilation\n" 357 " bl-op Baseline compiler detailed op-specific messages\n" 358 " bl-ic Baseline inline-cache messages\n" 359 " bl-ic-fb Baseline IC fallback stub messages\n" 360 " bl-osr Baseline IC OSR messages\n" 361 " bl-bails Baseline bailouts\n" 362 " bl-dbg-osr Baseline debug mode on stack recompile messages\n" 363 " bl-all All baseline spew\n" 364 "\n" 365 "See also SPEW=help for information on the Structured Spewer." 366 "\n"); 367 exit(status); 368 } 369 370 static bool IsFlag(const char* found, const char* flag) { 371 return strlen(found) == strlen(flag) && strcmp(found, flag) == 0; 372 } 373 374 void jit::CheckLogging() { 375 if (LoggingChecked) { 376 return; 377 } 378 379 LoggingChecked = true; 380 381 char* env = getenv("IONFLAGS"); 382 if (!env) { 383 return; 384 } 385 386 const char* found = strtok(env, ","); 387 while (found) { 388 fprintf(stderr, "found tag: %s\n", found); 389 // We're at the end of a flag; check if the previous substring was a 390 // known flag (i-1 is the last character of the flag we just read). 391 if (IsFlag(found, "help")) { 392 PrintHelpAndExit(); 393 } else if (IsFlag(found, "aborts")) { 394 EnableChannel(JitSpew_IonAbort); 395 } else if (IsFlag(found, "prune")) { 396 EnableChannel(JitSpew_Prune); 397 } else if (IsFlag(found, "escape")) { 398 EnableChannel(JitSpew_Escape); 399 } else if (IsFlag(found, "alias")) { 400 EnableChannel(JitSpew_Alias); 401 } else if (IsFlag(found, "alias-sum")) { 402 EnableChannel(JitSpew_AliasSummaries); 403 } else if (IsFlag(found, "scripts")) { 404 EnableChannel(JitSpew_IonScripts); 405 } else if (IsFlag(found, "mir")) { 406 EnableChannel(JitSpew_IonMIR); 407 } else if (IsFlag(found, "gvn")) { 408 EnableChannel(JitSpew_GVN); 409 } else if (IsFlag(found, "range")) { 410 EnableChannel(JitSpew_Range); 411 } else if (IsFlag(found, "wasmbce")) { 412 EnableChannel(JitSpew_WasmBCE); 413 } else if (IsFlag(found, "branch-hint")) { 414 EnableChannel(JitSpew_BranchHint); 415 } else if (IsFlag(found, "licm")) { 416 EnableChannel(JitSpew_LICM); 417 } else if (IsFlag(found, "flac")) { 418 EnableChannel(JitSpew_FLAC); 419 } else if (IsFlag(found, "eaa")) { 420 EnableChannel(JitSpew_EAA); 421 } else if (IsFlag(found, "sink")) { 422 EnableChannel(JitSpew_Sink); 423 } else if (IsFlag(found, "regalloc")) { 424 EnableChannel(JitSpew_RegAlloc); 425 } else if (IsFlag(found, "inline")) { 426 EnableChannel(JitSpew_Inlining); 427 } else if (IsFlag(found, "snapshots")) { 428 EnableChannel(JitSpew_IonSnapshots); 429 } else if (IsFlag(found, "codegen")) { 430 EnableChannel(JitSpew_Codegen); 431 } else if (IsFlag(found, "bailouts")) { 432 EnableChannel(JitSpew_IonBailouts); 433 } else if (IsFlag(found, "osi")) { 434 EnableChannel(JitSpew_IonInvalidate); 435 } else if (IsFlag(found, "caches")) { 436 EnableChannel(JitSpew_IonIC); 437 } else if (IsFlag(found, "safepoints")) { 438 EnableChannel(JitSpew_Safepoints); 439 } else if (IsFlag(found, "pools")) { 440 EnableChannel(JitSpew_Pools); 441 } else if (IsFlag(found, "cacheflush")) { 442 EnableChannel(JitSpew_CacheFlush); 443 } else if (IsFlag(found, "shapeguards")) { 444 EnableChannel(JitSpew_RedundantShapeGuards); 445 } else if (IsFlag(found, "gcbarriers")) { 446 EnableChannel(JitSpew_RedundantGCBarriers); 447 } else if (IsFlag(found, "loadkeys")) { 448 EnableChannel(JitSpew_MarkLoadsUsedAsPropertyKeys); 449 } else if (IsFlag(found, "stubfolding")) { 450 EnableChannel(JitSpew_StubFolding); 451 } else if (IsFlag(found, "stubfolding-details")) { 452 EnableChannel(JitSpew_StubFolding); 453 EnableChannel(JitSpew_StubFoldingDetails); 454 } else if (IsFlag(found, "logs")) { 455 EnableIonDebugAsyncLogging(); 456 } else if (IsFlag(found, "logs-sync")) { 457 EnableIonDebugSyncLogging(); 458 } else if (IsFlag(found, "profiling")) { 459 EnableChannel(JitSpew_Profiling); 460 } else if (IsFlag(found, "dump-mir-expr")) { 461 EnableChannel(JitSpew_MIRExpressions); 462 } else if (IsFlag(found, "unroll")) { 463 EnableChannel(JitSpew_Unroll); 464 } else if (IsFlag(found, "unroll-details")) { 465 EnableChannel(JitSpew_Unroll); 466 EnableChannel(JitSpew_UnrollDetails); 467 } else if (IsFlag(found, "warp-snapshots")) { 468 EnableChannel(JitSpew_WarpSnapshots); 469 } else if (IsFlag(found, "warp-transpiler")) { 470 EnableChannel(JitSpew_WarpTranspiler); 471 } else if (IsFlag(found, "warp-trial-inlining")) { 472 EnableChannel(JitSpew_WarpTrialInlining); 473 } else if (IsFlag(found, "all")) { 474 LoggingBits = uint64_t(-1); 475 } else if (IsFlag(found, "bl-aborts")) { 476 EnableChannel(JitSpew_BaselineAbort); 477 } else if (IsFlag(found, "bl-scripts")) { 478 EnableChannel(JitSpew_BaselineScripts); 479 } else if (IsFlag(found, "bl-op")) { 480 EnableChannel(JitSpew_BaselineOp); 481 } else if (IsFlag(found, "bl-ic")) { 482 EnableChannel(JitSpew_BaselineIC); 483 } else if (IsFlag(found, "bl-ic-fb")) { 484 EnableChannel(JitSpew_BaselineICFallback); 485 } else if (IsFlag(found, "bl-osr")) { 486 EnableChannel(JitSpew_BaselineOSR); 487 } else if (IsFlag(found, "bl-bails")) { 488 EnableChannel(JitSpew_BaselineBailouts); 489 } else if (IsFlag(found, "bl-dbg-osr")) { 490 EnableChannel(JitSpew_BaselineDebugModeOSR); 491 } else if (IsFlag(found, "bl-all")) { 492 EnableChannel(JitSpew_BaselineAbort); 493 EnableChannel(JitSpew_BaselineScripts); 494 EnableChannel(JitSpew_BaselineOp); 495 EnableChannel(JitSpew_BaselineIC); 496 EnableChannel(JitSpew_BaselineICFallback); 497 EnableChannel(JitSpew_BaselineOSR); 498 EnableChannel(JitSpew_BaselineBailouts); 499 EnableChannel(JitSpew_BaselineDebugModeOSR); 500 } else { 501 fprintf(stderr, "Unknown flag.\n"); 502 PrintHelpAndExit(64); 503 } 504 found = strtok(nullptr, ","); 505 } 506 507 FILE* spewfh = stderr; 508 const char* filename = getenv("ION_SPEW_FILENAME"); 509 if (filename && *filename) { 510 char actual_filename[2048] = {0}; 511 SprintfLiteral(actual_filename, "%s.%d", filename, getpid()); 512 spewfh = fopen(actual_filename, "w"); 513 MOZ_RELEASE_ASSERT(spewfh); 514 setbuf(spewfh, nullptr); // Make unbuffered 515 } 516 JitSpewPrinter().init(spewfh); 517 } 518 519 JitSpewIndent::JitSpewIndent(JitSpewChannel channel) : channel_(channel) { 520 ChannelIndentLevel[channel]++; 521 } 522 523 JitSpewIndent::~JitSpewIndent() { ChannelIndentLevel[channel_]--; } 524 525 void jit::JitSpewStartVA(JitSpewChannel channel, const char* fmt, va_list ap) { 526 if (!JitSpewEnabled(channel)) { 527 return; 528 } 529 530 JitSpewHeader(channel); 531 Fprinter& out = JitSpewPrinter(); 532 out.vprintf(fmt, ap); 533 } 534 535 void jit::JitSpewContVA(JitSpewChannel channel, const char* fmt, va_list ap) { 536 if (!JitSpewEnabled(channel)) { 537 return; 538 } 539 540 Fprinter& out = JitSpewPrinter(); 541 out.vprintf(fmt, ap); 542 } 543 544 void jit::JitSpewFin(JitSpewChannel channel) { 545 if (!JitSpewEnabled(channel)) { 546 return; 547 } 548 549 Fprinter& out = JitSpewPrinter(); 550 out.put("\n"); 551 } 552 553 void jit::JitSpewVA(JitSpewChannel channel, const char* fmt, va_list ap) { 554 JitSpewStartVA(channel, fmt, ap); 555 JitSpewFin(channel); 556 } 557 558 void jit::JitSpew(JitSpewChannel channel, const char* fmt, ...) { 559 va_list ap; 560 va_start(ap, fmt); 561 JitSpewVA(channel, fmt, ap); 562 563 // Suppress hazard analysis on logPrintVA function pointer. 564 JS::AutoSuppressGCAnalysis suppress; 565 566 switch (channel) { 567 # define SpewChannel(x) \ 568 case JitSpew_##x: \ 569 if (x##Module.shouldLog(js::LogLevel::Debug)) { \ 570 x##Module.interface.logPrintVA(x##Module.logger, js::LogLevel::Debug, \ 571 fmt, ap); \ 572 } \ 573 break; 574 575 JITSPEW_CHANNEL_LIST(SpewChannel) 576 577 # undef SpewChannel 578 case JitSpew_Terminator: 579 MOZ_CRASH("Unexpected JitSpew"); 580 } 581 582 va_end(ap); 583 } 584 585 void jit::JitSpewDef(JitSpewChannel channel, const char* str, 586 MDefinition* def) { 587 if (!JitSpewEnabled(channel)) { 588 return; 589 } 590 591 JitSpewHeader(channel); 592 Fprinter& out = JitSpewPrinter(); 593 out.put(str); 594 def->dump(out); 595 def->dumpLocation(out); 596 } 597 598 void jit::JitSpewStart(JitSpewChannel channel, const char* fmt, ...) { 599 va_list ap; 600 va_start(ap, fmt); 601 JitSpewStartVA(channel, fmt, ap); 602 va_end(ap); 603 } 604 void jit::JitSpewCont(JitSpewChannel channel, const char* fmt, ...) { 605 va_list ap; 606 va_start(ap, fmt); 607 JitSpewContVA(channel, fmt, ap); 608 va_end(ap); 609 } 610 611 void jit::JitSpewHeader(JitSpewChannel channel) { 612 if (!JitSpewEnabled(channel)) { 613 return; 614 } 615 616 Fprinter& out = JitSpewPrinter(); 617 out.printf("[%s] ", ChannelNames[channel]); 618 for (size_t i = ChannelIndentLevel[channel]; i != 0; i--) { 619 out.put(" "); 620 } 621 } 622 623 void jit::EnableChannel(JitSpewChannel channel) { 624 MOZ_ASSERT(LoggingChecked); 625 LoggingBits |= uint64_t(1) << uint32_t(channel); 626 } 627 628 void jit::DisableChannel(JitSpewChannel channel) { 629 MOZ_ASSERT(LoggingChecked); 630 LoggingBits &= ~(uint64_t(1) << uint32_t(channel)); 631 } 632 633 #endif /* JS_JITSPEW */ 634 635 #if defined(JS_JITSPEW) || defined(ENABLE_JS_AOT_ICS) 636 637 const char* js::jit::ValTypeToString(JSValueType type) { 638 switch (type) { 639 case JSVAL_TYPE_DOUBLE: 640 return "Double"; 641 case JSVAL_TYPE_INT32: 642 return "Int32"; 643 case JSVAL_TYPE_BOOLEAN: 644 return "Boolean"; 645 case JSVAL_TYPE_UNDEFINED: 646 return "Undefined"; 647 case JSVAL_TYPE_NULL: 648 return "Null"; 649 case JSVAL_TYPE_MAGIC: 650 return "Magic"; 651 case JSVAL_TYPE_STRING: 652 return "String"; 653 case JSVAL_TYPE_SYMBOL: 654 return "Symbol"; 655 case JSVAL_TYPE_PRIVATE_GCTHING: 656 return "PrivateGCThing"; 657 case JSVAL_TYPE_BIGINT: 658 return "BigInt"; 659 case JSVAL_TYPE_OBJECT: 660 return "Object"; 661 case JSVAL_TYPE_UNKNOWN: 662 return "None"; 663 default: 664 MOZ_CRASH("Unknown JSValueType"); 665 } 666 } 667 668 #endif /* defined(JS_JITSPEW) || defined(ENABLE_JS_AOT_ICS) */