Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/js/src/vm/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 15 kB image not shown  

Quelle  UbiNode.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "js/UbiNode.h"

#include "mozilla/Assertions.h"

#include <algorithm>

#include "debugger/Debugger.h"
#include "gc/GC.h"
#include "jit/JitCode.h"
#include "js/Debug.h"
#include "js/TracingAPI.h"
#include "js/TypeDecls.h"
#include "js/UbiNodeUtils.h"
#include "js/Utility.h"
#include "util/Text.h"
#include "vm/BigIntType.h"
#include "vm/Compartment.h"
#include "vm/EnvironmentObject.h"
#include "vm/GetterSetter.h"
#include "vm/GlobalObject.h"
#include "vm/JSContext.h"
#include "vm/JSObject.h"
#include "vm/JSScript.h"
#include "vm/PropMap.h"
#include "vm/Scope.h"
#include "vm/Shape.h"
#include "vm/StringType.h"
#include "vm/SymbolType.h"

#include "debugger/Debugger-inl.h"
#include "gc/StableCellHasher-inl.h"
#include "vm/JSObject-inl.h"

using namespace js;

using JS::ApplyGCThingTyped;
using JS::HandleValue;
using JS::Value;
using JS::ZoneSet;
using JS::ubi::AtomOrTwoByteChars;
using JS::ubi::CoarseType;
using JS::ubi::Concrete;
using JS::ubi::Edge;
using JS::ubi::EdgeRange;
using JS::ubi::EdgeVector;
using JS::ubi::Node;
using JS::ubi::StackFrame;
using JS::ubi::TracerConcrete;
using JS::ubi::TracerConcreteWithRealm;
using mozilla::RangedPtr;

struct CopyToBufferMatcher {
  RangedPtr<char16_t> destination;
  size_t maxLength;

  CopyToBufferMatcher(RangedPtr<char16_t> destination, size_t maxLength)
      : destination(destination), maxLength(maxLength) {}

  template <typename CharT>
  static size_t copyToBufferHelper(const CharT* src, RangedPtr<char16_t> dest,
                                   size_t length) {
    size_t i = 0;
    for (; i < length; i++) {
      dest[i] = src[i];
    }
    return i;
  }

  size_t operator()(JSAtom* atom) {
    if (!atom) {
      return 0;
    }

    size_t length = std::min(atom->length(), maxLength);
    JS::AutoCheckCannotGC noGC;
    return atom->hasTwoByteChars()
               ? copyToBufferHelper(atom->twoByteChars(noGC), destination,
                                    length)
               : copyToBufferHelper(atom->latin1Chars(noGC), destination,
                                    length);
  }

  size_t operator()(const char16_t* chars) {
    if (!chars) {
      return 0;
    }

    size_t length = std::min(js_strlen(chars), maxLength);
    return copyToBufferHelper(chars, destination, length);
  }
};

size_t JS::ubi::AtomOrTwoByteChars::copyToBuffer(
    RangedPtr<char16_t> destination, size_t length) {
  CopyToBufferMatcher m(destination, length);
  return match(m);
}

struct LengthMatcher {
  size_t operator()(JSAtom* atom) { return atom ? atom->length() : 0; }

  size_t operator()(const char16_t* chars) {
    return chars ? js_strlen(chars) : 0;
  }
};

size_t JS::ubi::AtomOrTwoByteChars::length() {
  LengthMatcher m;
  return match(m);
}

size_t StackFrame::source(RangedPtr<char16_t> destination,
                          size_t length) const {
  auto s = source();
  return s.copyToBuffer(destination, length);
}

size_t StackFrame::functionDisplayName(RangedPtr<char16_t> destination,
                                       size_t length) const {
  auto name = functionDisplayName();
  return name.copyToBuffer(destination, length);
}

size_t StackFrame::sourceLength() { return source().length(); }

size_t StackFrame::functionDisplayNameLength() {
  return functionDisplayName().length();
}

// All operations on null ubi::Nodes crash.
CoarseType Concrete<void>::coarseType() const { MOZ_CRASH("null ubi::Node"); }
const char16_t* Concrete<void>::typeName() const {
  MOZ_CRASH("null ubi::Node");
}
JS::Zone* Concrete<void>::zone() const { MOZ_CRASH("null ubi::Node"); }
JS::Compartment* Concrete<void>::compartment() const {
  MOZ_CRASH("null ubi::Node");
}
JS::Realm* Concrete<void>::realm() const { MOZ_CRASH("null ubi::Node"); }

UniquePtr<EdgeRange> Concrete<void>::edges(JSContext*, boolconst {
  MOZ_CRASH("null ubi::Node");
}

Node::Size Concrete<void>::size(mozilla::MallocSizeOf mallocSizeof) const {
  MOZ_CRASH("null ubi::Node");
}

Node::Node(JS::GCCellPtr thing) {
  ApplyGCThingTyped(thing, [this](auto t) { this->construct(t); });
}

Node::Node(HandleValue value) {
  if (!ApplyGCThingTyped(value, [this](auto t) { this->construct(t); })) {
    construct<void>(nullptr);
  }
}

static bool IsSafeToExposeToJS(JSObject* obj) {
  if (obj->is<js::EnvironmentObject>() || obj->is<js::ScriptSourceObject>() ||
      obj->is<js::DebugEnvironmentProxy>()) {
    return false;
  }
  if (obj->is<JSFunction>() && js::IsInternalFunctionObject(*obj)) {
    return false;
  }
  return true;
}

Value Node::exposeToJS() const {
  Value v;

  if (is<JSObject>()) {
    JSObject* obj = as<JSObject>();
    if (IsSafeToExposeToJS(obj)) {
      v.setObject(*obj);
    } else {
      v.setUndefined();
    }
  } else if (is<JSString>()) {
    v.setString(as<JSString>());
  } else if (is<JS::Symbol>()) {
    v.setSymbol(as<JS::Symbol>());
  } else if (is<BigInt>()) {
    v.setBigInt(as<BigInt>());
  } else {
    v.setUndefined();
  }

  ExposeValueToActiveJS(v);

  return v;
}

// A JS::CallbackTracer subclass that adds a Edge to a Vector for each
// edge on which it is invoked.
class EdgeVectorTracer final : public JS::CallbackTracer {
  // The vector to which we add Edges.
  EdgeVector* vec;

  // True if we should populate the edge's names.
  bool wantNames;

  void onChild(JS::GCCellPtr thing, const char* name) override {
    if (!okay) {
      return;
    }

    // Don't trace permanent atoms and well-known symbols that are owned by
    // a parent JSRuntime.
    if (thing.is<JSString>() && thing.as<JSString>().isPermanentAtom()) {
      return;
    }
    if (thing.is<JS::Symbol>() && thing.as<JS::Symbol>().isWellKnownSymbol()) {
      return;
    }

    char16_t* name16 = nullptr;
    if (wantNames) {
      // Ask the tracer to compute an edge name for us.
      char buffer[1024];
      context().getEdgeName(name, buffer, sizeof(buffer));
      name = buffer;

      // Convert the name to char16_t characters.
      name16 = js_pod_malloc<char16_t>(strlen(name) + 1);
      if (!name16) {
        okay = false;
        return;
      }

      size_t i;
      for (i = 0; name[i]; i++) {
        name16[i] = name[i];
      }
      name16[i] = '\0';
    }

    // The simplest code is correct! The temporary Edge takes
    // ownership of name; if the append succeeds, the vector element
    // then takes ownership; if the append fails, then the temporary
    // retains it, and its destructor will free it.
    if (!vec->append(Edge(name16, Node(thing)))) {
      okay = false;
      return;
    }
  }

 public:
  // True if no errors (OOM, say) have yet occurred.
  bool okay;

  EdgeVectorTracer(JSRuntime* rt, EdgeVector* vec, bool wantNames)
      : JS::CallbackTracer(rt), vec(vec), wantNames(wantNames), okay(true) {}
};

template <typename Referent>
JS::Zone* TracerConcrete<Referent>::zone() const {
  return get().zoneFromAnyThread();
}

template JS::Zone* TracerConcrete<js::BaseScript>::zone() const;
template JS::Zone* TracerConcrete<js::Shape>::zone() const;
template JS::Zone* TracerConcrete<js::BaseShape>::zone() const;
template JS::Zone* TracerConcrete<js::GetterSetter>::zone() const;
template JS::Zone* TracerConcrete<js::PropMap>::zone() const;
template JS::Zone* TracerConcrete<js::RegExpShared>::zone() const;
template JS::Zone* TracerConcrete<js::Scope>::zone() const;
template JS::Zone* TracerConcrete<JS::Symbol>::zone() const;
template JS::Zone* TracerConcrete<BigInt>::zone() const;
template JS::Zone* TracerConcrete<JSString>::zone() const;
template JS::Zone* TracerConcrete<js::gc::SmallBuffer>::zone() const;

template <typename Referent>
UniquePtr<EdgeRange> TracerConcrete<Referent>::edges(JSContext* cx,
                                                     bool wantNames) const {
  auto range = js::MakeUnique<SimpleEdgeRange>();
  if (!range) {
    return nullptr;
  }

  if (!range->addTracerEdges(cx->runtime(), ptr,
                             JS::MapTypeToTraceKind<Referent>::kind,
                             wantNames)) {
    return nullptr;
  }

  // Note: Clang 3.8 (or older) require an explicit construction of the
  // target UniquePtr type. When we no longer require to support these Clang
  // versions the return statement can be simplified to |return range;|.
  return UniquePtr<EdgeRange>(range.release());
}

template UniquePtr<EdgeRange> TracerConcrete<js::BaseScript>::edges(
    JSContext* cx, bool wantNames) const;
template UniquePtr<EdgeRange> TracerConcrete<js::Shape>::edges(
    JSContext* cx, bool wantNames) const;
template UniquePtr<EdgeRange> TracerConcrete<js::BaseShape>::edges(
    JSContext* cx, bool wantNames) const;
template UniquePtr<EdgeRange> TracerConcrete<js::GetterSetter>::edges(
    JSContext* cx, bool wantNames) const;
template UniquePtr<EdgeRange> TracerConcrete<js::PropMap>::edges(
    JSContext* cx, bool wantNames) const;
template UniquePtr<EdgeRange> TracerConcrete<js::RegExpShared>::edges(
    JSContext* cx, bool wantNames) const;
template UniquePtr<EdgeRange> TracerConcrete<js::Scope>::edges(
    JSContext* cx, bool wantNames) const;
template UniquePtr<EdgeRange> TracerConcrete<JS::Symbol>::edges(
    JSContext* cx, bool wantNames) const;
template UniquePtr<EdgeRange> TracerConcrete<BigInt>::edges(
    JSContext* cx, bool wantNames) const;
template UniquePtr<EdgeRange> TracerConcrete<JSString>::edges(
    JSContext* cx, bool wantNames) const;
template UniquePtr<EdgeRange> TracerConcrete<js::gc::SmallBuffer>::edges(
    JSContext* cx, bool wantNames) const;

template <typename Referent>
JS::Compartment* TracerConcreteWithRealm<Referent>::compartment() const {
  return TracerBase::get().compartment();
}

template <typename Referent>
Realm* TracerConcreteWithRealm<Referent>::realm() const {
  return TracerBase::get().realm();
}

template Realm* TracerConcreteWithRealm<js::BaseScript>::realm() const;
template JS::Compartment* TracerConcreteWithRealm<js::BaseScript>::compartment()
    const;

bool Concrete<JSObject>::hasAllocationStack() const {
  return !!js::Debugger::getObjectAllocationSite(get());
}

StackFrame Concrete<JSObject>::allocationStack() const {
  MOZ_ASSERT(hasAllocationStack());
  return StackFrame(js::Debugger::getObjectAllocationSite(get()));
}

const char* Concrete<JSObject>::jsObjectClassName() const {
  return Concrete::get().getClass()->name;
}

JS::Compartment* Concrete<JSObject>::compartment() const {
  return Concrete::get().compartment();
}

Realm* Concrete<JSObject>::realm() const {
  // Cross-compartment wrappers are shared by all realms in the compartment,
  // so we return nullptr in that case.
  return JS::GetObjectRealmOrNull(&Concrete::get());
}

const char16_t Concrete<JS::Symbol>::concreteTypeName[] = u"JS::Symbol";
const char16_t Concrete<BigInt>::concreteTypeName[] = u"JS::BigInt";
const char16_t Concrete<js::BaseScript>::concreteTypeName[] = u"js::BaseScript";
const char16_t Concrete<js::jit::JitCode>::concreteTypeName[] =
    u"js::jit::JitCode";
const char16_t Concrete<js::Shape>::concreteTypeName[] = u"js::Shape";
const char16_t Concrete<js::BaseShape>::concreteTypeName[] = u"js::BaseShape";
const char16_t Concrete<js::GetterSetter>::concreteTypeName[] =
    u"js::GetterSetter";
const char16_t Concrete<js::PropMap>::concreteTypeName[] = u"js::PropMap";
const char16_t Concrete<js::Scope>::concreteTypeName[] = u"js::Scope";
const char16_t Concrete<js::RegExpShared>::concreteTypeName[] =
    u"js::RegExpShared";

namespace JS {
namespace ubi {

RootList::RootList(JSContext* cx, bool wantNames /* = false */)
    : cx(cx), wantNames(wantNames), inited(false) {}

std::pair<bool, JS::AutoCheckCannotGC> RootList::init() {
  EdgeVectorTracer tracer(cx->runtime(), &edges, wantNames);
  js::TraceRuntime(&tracer);
  inited = tracer.okay;
  return {tracer.okay, JS::AutoCheckCannotGC(cx)};
}

std::pair<bool, JS::AutoCheckCannotGC> RootList::init(
    CompartmentSet& debuggees) {
  EdgeVector allRootEdges;
  EdgeVectorTracer tracer(cx->runtime(), &allRootEdges, wantNames);

  ZoneSet debuggeeZones;
  for (auto range = debuggees.all(); !range.empty(); range.popFront()) {
    if (!debuggeeZones.put(range.front()->zone())) {
      return {false, JS::AutoCheckCannotGC(cx)};
    }
  }

  js::TraceRuntime(&tracer);
  if (!tracer.okay) {
    return {false, JS::AutoCheckCannotGC(cx)};
  }
  js::gc::TraceIncomingCCWs(&tracer, debuggees);
  if (!tracer.okay) {
    return {false, JS::AutoCheckCannotGC(cx)};
  }

  for (EdgeVector::Range r = allRootEdges.all(); !r.empty(); r.popFront()) {
    Edge& edge = r.front();

    JS::Compartment* compartment = edge.referent.compartment();
    if (compartment && !debuggees.has(compartment)) {
      continue;
    }

    Zone* zone = edge.referent.zone();
    if (zone && !debuggeeZones.has(zone)) {
      continue;
    }

    if (!edges.append(std::move(edge))) {
      return {false, JS::AutoCheckCannotGC(cx)};
    }
  }

  inited = true;
  return {true, JS::AutoCheckCannotGC(cx)};
}

std::pair<bool, JS::AutoCheckCannotGC> RootList::init(HandleObject debuggees) {
  MOZ_ASSERT(debuggees && JS::dbg::IsDebugger(*debuggees));
  js::Debugger* dbg = js::Debugger::fromJSObject(debuggees.get());

  CompartmentSet debuggeeCompartments;

  for (js::WeakGlobalObjectSet::Range r = dbg->allDebuggees(); !r.empty();
       r.popFront()) {
    if (!debuggeeCompartments.put(r.front()->compartment())) {
      return {false, JS::AutoCheckCannotGC(cx)};
    }
  }

  auto [ok, nogc] = init(debuggeeCompartments);
  if (!ok) {
    return {false, nogc};
  }

  // Ensure that each of our debuggee globals are in the root list.
  for (js::WeakGlobalObjectSet::Range r = dbg->allDebuggees(); !r.empty();
       r.popFront()) {
    if (!addRoot(JS::ubi::Node(static_cast<JSObject*>(r.front())),
                 u"debuggee global")) {
      return {false, nogc};
    }
  }

  inited = true;
  return {true, nogc};
}

bool RootList::addRoot(Node node, const char16_t* edgeName) {
  MOZ_ASSERT_IF(wantNames, edgeName);

  UniqueTwoByteChars name;
  if (edgeName) {
    name = js::DuplicateString(edgeName);
    if (!name) {
      return false;
    }
  }

  return edges.append(Edge(name.release(), node));
}

const char16_t Concrete<RootList>::concreteTypeName[] = u"JS::ubi::RootList";

UniquePtr<EdgeRange> Concrete<RootList>::edges(JSContext* cx,
                                               bool wantNames) const {
  MOZ_ASSERT_IF(wantNames, get().wantNames);
  return js::MakeUnique<PreComputedEdgeRange>(get().edges);
}

bool SimpleEdgeRange::addTracerEdges(JSRuntime* rt, void* thing,
                                     JS::TraceKind kind, bool wantNames) {
  EdgeVectorTracer tracer(rt, &edges, wantNames);
  JS::TraceChildren(&tracer, JS::GCCellPtr(thing, kind));
  settle();
  return tracer.okay;
}

void Concrete<JSObject>::construct(void* storage, JSObject* ptr) {
  if (ptr) {
    auto clasp = ptr->getClass();
    auto callback = ptr->compartment()
                        ->runtimeFromMainThread()
                        ->constructUbiNodeForDOMObjectCallback;
    if (clasp->isDOMClass() && callback) {
      AutoSuppressGCAnalysis suppress;
      callback(storage, ptr);
      return;
    }
  }
  new (storage) Concrete(ptr);
}

void SetConstructUbiNodeForDOMObjectCallback(JSContext* cx,
                                             void (*callback)(void*,
                                                              JSObject*)) {
  cx->runtime()->constructUbiNodeForDOMObjectCallback = callback;
}

JS_PUBLIC_API const char* CoarseTypeToString(CoarseType type) {
  switch (type) {
    case CoarseType::Other:
      return "Other";
    case CoarseType::Object:
      return "Object";
    case CoarseType::Script:
      return "Script";
    case CoarseType::String:
      return "String";
    case CoarseType::DOMNode:
      return "DOMNode";
    default:
      return "Unknown";
  }
};

}  // namespace ubi
}  // namespace JS

Messung V0.5
C=91 H=94 G=92

¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.