tor-browser

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

Tracer.cpp (8263B)


      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 "gc/Tracer.h"
      8 
      9 #include "mozilla/DebugOnly.h"
     10 
     11 #include "NamespaceImports.h"
     12 
     13 #include "gc/PublicIterators.h"
     14 #include "jit/JitCode.h"
     15 #include "util/Memory.h"
     16 #include "util/Text.h"
     17 #include "vm/BigIntType.h"
     18 #include "vm/JSContext.h"
     19 #include "vm/JSFunction.h"
     20 #include "vm/JSScript.h"
     21 #include "vm/RegExpShared.h"
     22 #include "vm/Scope.h"
     23 #include "vm/Shape.h"
     24 #include "vm/StringType.h"
     25 #include "vm/SymbolType.h"
     26 
     27 #include "gc/TraceMethods-inl.h"
     28 #include "vm/Shape-inl.h"
     29 
     30 using namespace js;
     31 using namespace js::gc;
     32 
     33 template void RuntimeScopeData<LexicalScope::SlotInfo>::trace(JSTracer* trc);
     34 template void RuntimeScopeData<ClassBodyScope::SlotInfo>::trace(JSTracer* trc);
     35 template void RuntimeScopeData<VarScope::SlotInfo>::trace(JSTracer* trc);
     36 template void RuntimeScopeData<GlobalScope::SlotInfo>::trace(JSTracer* trc);
     37 template void RuntimeScopeData<EvalScope::SlotInfo>::trace(JSTracer* trc);
     38 template void RuntimeScopeData<WasmFunctionScope::SlotInfo>::trace(
     39    JSTracer* trc);
     40 
     41 void JS::TracingContext::getEdgeName(const char* name, char* buffer,
     42                                     size_t bufferSize) {
     43  MOZ_ASSERT(bufferSize > 0);
     44  if (functor_) {
     45    (*functor_)(this, name, buffer, bufferSize);
     46    return;
     47  }
     48  if (index_ != InvalidIndex) {
     49    snprintf(buffer, bufferSize, "%s[%zu]", name, index_);
     50    return;
     51  }
     52  snprintf(buffer, bufferSize, "%s", name);
     53 }
     54 
     55 /*** Public Tracing API *****************************************************/
     56 
     57 JS_PUBLIC_API void JS::TraceChildren(JSTracer* trc, GCCellPtr thing) {
     58  ApplyGCThingTyped(thing.asCell(), thing.kind(), [trc](auto t) {
     59    MOZ_ASSERT_IF(t->runtimeFromAnyThread() != trc->runtime(),
     60                  t->isPermanentAndMayBeShared());
     61    t->traceChildren(trc);
     62  });
     63 }
     64 
     65 void js::gc::TraceIncomingCCWs(JSTracer* trc,
     66                               const JS::CompartmentSet& compartments) {
     67  for (CompartmentsIter source(trc->runtime()); !source.done(); source.next()) {
     68    if (compartments.has(source)) {
     69      continue;
     70    }
     71    // Iterate over all compartments that |source| has wrappers for.
     72    for (Compartment::WrappedObjectCompartmentEnum dest(source); !dest.empty();
     73         dest.popFront()) {
     74      if (!compartments.has(dest)) {
     75        continue;
     76      }
     77      // Iterate over all wrappers from |source| to |dest| compartments.
     78      for (Compartment::ObjectWrapperEnum e(source, dest); !e.empty();
     79           e.popFront()) {
     80        JSObject* obj = e.front().key();
     81        MOZ_ASSERT(compartments.has(obj->compartment()));
     82        mozilla::DebugOnly<JSObject*> prior = obj;
     83        TraceManuallyBarrieredEdge(trc, &obj,
     84                                   "cross-compartment wrapper target");
     85        MOZ_ASSERT(obj == prior);
     86      }
     87    }
     88  }
     89 }
     90 
     91 /*** Cycle Collector Helpers ************************************************/
     92 
     93 // This function is used by the Cycle Collector (CC) to trace through -- or in
     94 // CC parlance, traverse -- a Shape. The CC does not care about Shapes,
     95 // BaseShapes or PropMaps themselves, only things held live by them that can
     96 // participate in cycles.
     97 void gc::TraceCycleCollectorChildren(JS::CallbackTracer* trc, Shape* shape) {
     98  shape->base()->traceChildren(trc);
     99 
    100  // TODO: Trace symbols reachable from |shape|. Shapes can entrain symbols via
    101  // their propmaps, and these can now participate in cycles. Not doing this
    102  // means there are some cycles that the CC will not be able to collect.
    103 }
    104 
    105 /*** Traced Edge Printer ****************************************************/
    106 
    107 static size_t CountDecimalDigits(size_t num) {
    108  size_t numDigits = 0;
    109  do {
    110    num /= 10;
    111    numDigits++;
    112  } while (num > 0);
    113 
    114  return numDigits;
    115 }
    116 
    117 static const char* StringKindHeader(JSString* str) {
    118  MOZ_ASSERT(str->isLinear());
    119 
    120  if (str->isAtom()) {
    121    if (str->isPermanentAtom()) {
    122      return "permanent atom: ";
    123    }
    124    return "atom: ";
    125  }
    126 
    127  if (str->isExtensible()) {
    128    return "extensible: ";
    129  }
    130 
    131  if (str->isInline()) {
    132    if (str->isFatInline()) {
    133      return "fat inline: ";
    134    }
    135    return "inline: ";
    136  }
    137 
    138  if (str->isDependent()) {
    139    return "dependent: ";
    140  }
    141 
    142  if (str->isExternal()) {
    143    return "external: ";
    144  }
    145 
    146  return "linear: ";
    147 }
    148 
    149 void js::gc::GetTraceThingInfo(char* buf, size_t bufsize, void* thing,
    150                               JS::TraceKind kind, bool details) {
    151  const char* name = nullptr; /* silence uninitialized warning */
    152  size_t n;
    153 
    154  if (bufsize == 0) {
    155    return;
    156  }
    157 
    158  switch (kind) {
    159    case JS::TraceKind::BaseShape:
    160      name = "base_shape";
    161      break;
    162 
    163    case JS::TraceKind::GetterSetter:
    164      name = "getter_setter";
    165      break;
    166 
    167    case JS::TraceKind::PropMap:
    168      name = "prop_map";
    169      break;
    170 
    171    case JS::TraceKind::JitCode:
    172      name = "jitcode";
    173      break;
    174 
    175    case JS::TraceKind::Null:
    176      name = "null_pointer";
    177      break;
    178 
    179    case JS::TraceKind::Object: {
    180      name = static_cast<JSObject*>(thing)->getClass()->name;
    181      break;
    182    }
    183 
    184    case JS::TraceKind::RegExpShared:
    185      name = "reg_exp_shared";
    186      break;
    187 
    188    case JS::TraceKind::Scope:
    189      name = "scope";
    190      break;
    191 
    192    case JS::TraceKind::Script:
    193      name = "script";
    194      break;
    195 
    196    case JS::TraceKind::Shape:
    197      name = "shape";
    198      break;
    199 
    200    case JS::TraceKind::String:
    201      name = ((JSString*)thing)->isDependent() ? "substring" : "string";
    202      break;
    203 
    204    case JS::TraceKind::Symbol:
    205      name = "symbol";
    206      break;
    207 
    208    case JS::TraceKind::BigInt:
    209      name = "BigInt";
    210      break;
    211 
    212    default:
    213      name = "INVALID";
    214      break;
    215  }
    216 
    217  n = strlen(name);
    218  if (n > bufsize - 1) {
    219    n = bufsize - 1;
    220  }
    221  js_memcpy(buf, name, n + 1);
    222  buf += n;
    223  bufsize -= n;
    224  *buf = '\0';
    225 
    226  if (details && bufsize > 2) {
    227    switch (kind) {
    228      case JS::TraceKind::Object: {
    229        JSObject* obj = (JSObject*)thing;
    230        if (obj->is<JSFunction>()) {
    231          JSFunction* fun = &obj->as<JSFunction>();
    232          if (fun->maybePartialDisplayAtom()) {
    233            *buf++ = ' ';
    234            bufsize--;
    235            PutEscapedString(buf, bufsize, fun->maybePartialDisplayAtom(), 0);
    236          }
    237        } else {
    238          snprintf(buf, bufsize, " <unknown object>");
    239        }
    240        break;
    241      }
    242 
    243      case JS::TraceKind::Script: {
    244        auto* script = static_cast<js::BaseScript*>(thing);
    245        snprintf(buf, bufsize, " %s:%u", script->filename(), script->lineno());
    246        break;
    247      }
    248 
    249      case JS::TraceKind::String: {
    250        *buf++ = ' ';
    251        bufsize--;
    252        JSString* str = (JSString*)thing;
    253 
    254        if (str->isLinear()) {
    255          const char* header = StringKindHeader(str);
    256          bool willFit = str->length() + strlen("<length > ") + strlen(header) +
    257                             CountDecimalDigits(str->length()) <
    258                         bufsize;
    259 
    260          n = snprintf(buf, bufsize, "<%slength %zu%s> ", header, str->length(),
    261                       willFit ? "" : " (truncated)");
    262          buf += n;
    263          bufsize -= n;
    264 
    265          PutEscapedString(buf, bufsize, &str->asLinear(), 0);
    266        } else {
    267          snprintf(buf, bufsize, "<rope: length %zu>", str->length());
    268        }
    269        break;
    270      }
    271 
    272      case JS::TraceKind::Symbol: {
    273        *buf++ = ' ';
    274        bufsize--;
    275        auto* sym = static_cast<JS::Symbol*>(thing);
    276        if (JSAtom* desc = sym->description()) {
    277          PutEscapedString(buf, bufsize, desc, 0);
    278        } else {
    279          snprintf(buf, bufsize, "<null>");
    280        }
    281        break;
    282      }
    283 
    284      case JS::TraceKind::Scope: {
    285        auto* scope = static_cast<js::Scope*>(thing);
    286        snprintf(buf, bufsize, " %s", js::ScopeKindString(scope->kind()));
    287        break;
    288      }
    289 
    290      default:
    291        break;
    292    }
    293  }
    294  buf[bufsize - 1] = '\0';
    295 }
    296 
    297 JS::CallbackTracer::CallbackTracer(JSContext* cx, JS::TracerKind kind,
    298                                   JS::TraceOptions options)
    299    : CallbackTracer(cx->runtime(), kind, options) {}