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 24 kB image not shown  

Quelle  Stack.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 "vm/Stack-inl.h"

#include "mozilla/Maybe.h"  // mozilla::Maybe

#include <algorithm>  // std::max
#include <iterator>   // std::size
#include <stddef.h>   // size_t
#include <stdint.h>   // uint8_t, uint32_t

#include "gc/Tracer.h"  // js::TraceRoot
#include "jit/JitcodeMap.h"
#include "jit/JitRuntime.h"
#include "js/friend/ErrorMessages.h"  // JSMSG_*
#include "js/Value.h"                 // JS::Value
#include "vm/FrameIter.h"             // js::FrameIter
#include "vm/JSContext.h"
#include "wasm/WasmProcess.h"

#include "jit/JSJitFrameIter-inl.h"
#include "vm/Probes-inl.h"

using namespace js;

using mozilla::Maybe;

using JS::Value;

/*****************************************************************************/

void InterpreterFrame::initExecuteFrame(JSContext* cx, HandleScript script,
                                        AbstractFramePtr evalInFramePrev,
                                        HandleObject envChain) {
  flags_ = 0;
  script_ = script;

  envChain_ = envChain.get();
  prev_ = nullptr;
  prevpc_ = nullptr;
  prevsp_ = nullptr;

  evalInFramePrev_ = evalInFramePrev;
  MOZ_ASSERT_IF(evalInFramePrev, isDebuggerEvalFrame());

  if (script->isDebuggee()) {
    setIsDebuggee();
  }

#ifdef DEBUG
  Debug_SetValueRangeToCrashOnTouch(&rval_, 1);
#endif
}

ArrayObject* InterpreterFrame::createRestParameter(JSContext* cx) {
  MOZ_ASSERT(script()->hasRest());
  unsigned nformal = callee().nargs() - 1, nactual = numActualArgs();
  unsigned nrest = (nactual > nformal) ? nactual - nformal : 0;
  Value* restvp = argv() + nformal;
  return NewDenseCopiedArray(cx, nrest, restvp);
}

static inline void AssertScopeMatchesEnvironment(Scope* scope,
                                                 JSObject* originalEnv) {
#ifdef DEBUG
  JSObject* env = originalEnv;
  for (ScopeIter si(scope); si; si++) {
    if (si.kind() == ScopeKind::NonSyntactic) {
      while (env->is<WithEnvironmentObject>() ||
             env->is<NonSyntacticVariablesObject>() ||
             (env->is<LexicalEnvironmentObject>() &&
              !env->as<LexicalEnvironmentObject>().isSyntactic())) {
        MOZ_ASSERT(!IsSyntacticEnvironment(env));
        env = &env->as<EnvironmentObject>().enclosingEnvironment();
      }
    } else if (si.hasSyntacticEnvironment()) {
      switch (si.kind()) {
        case ScopeKind::Function:
          MOZ_ASSERT(env->as<CallObject>()
                         .callee()
                         .maybeCanonicalFunction()
                         ->nonLazyScript() ==
                     si.scope()->as<FunctionScope>().script());
          env = &env->as<CallObject>().enclosingEnvironment();
          break;

        case ScopeKind::FunctionBodyVar:
          MOZ_ASSERT(&env->as<VarEnvironmentObject>().scope() == si.scope());
          env = &env->as<VarEnvironmentObject>().enclosingEnvironment();
          break;

        case ScopeKind::Lexical:
        case ScopeKind::SimpleCatch:
        case ScopeKind::Catch:
        case ScopeKind::NamedLambda:
        case ScopeKind::StrictNamedLambda:
        case ScopeKind::FunctionLexical:
        case ScopeKind::ClassBody:
          MOZ_ASSERT(&env->as<ScopedLexicalEnvironmentObject>().scope() ==
                     si.scope());
          env =
              &env->as<ScopedLexicalEnvironmentObject>().enclosingEnvironment();
          break;

        case ScopeKind::With:
          MOZ_ASSERT(&env->as<WithEnvironmentObject>().scope() == si.scope());
          env = &env->as<WithEnvironmentObject>().enclosingEnvironment();
          break;

        case ScopeKind::Eval:
        case ScopeKind::StrictEval:
          env = &env->as<VarEnvironmentObject>().enclosingEnvironment();
          break;

        case ScopeKind::Global:
          env =
              &env->as<GlobalLexicalEnvironmentObject>().enclosingEnvironment();
          MOZ_ASSERT(env->is<GlobalObject>());
          break;

        case ScopeKind::NonSyntactic:
          MOZ_CRASH("NonSyntactic should not have a syntactic environment");
          break;

        case ScopeKind::Module:
          MOZ_ASSERT(&env->as<ModuleEnvironmentObject>().module() ==
                     si.scope()->as<ModuleScope>().module());
          env = &env->as<ModuleEnvironmentObject>().enclosingEnvironment();
          break;

        case ScopeKind::WasmInstance:
          env =
              &env->as<WasmInstanceEnvironmentObject>().enclosingEnvironment();
          break;

        case ScopeKind::WasmFunction:
          env = &env->as<WasmFunctionCallObject>().enclosingEnvironment();
          break;
      }
    }
  }

  // In the case of a non-syntactic env chain, the immediate parent of the
  // outermost non-syntactic env may be the global lexical env, or, if
  // called from Debugger, a DebugEnvironmentProxy.
  //
  // In the case of a syntactic env chain, the outermost env is always a
  // GlobalObject.
  MOZ_ASSERT(env->is<GlobalObject>() ||
             env->is<GlobalLexicalEnvironmentObject>() ||
             env->is<DebugEnvironmentProxy>());
#endif
}

static inline void AssertScopeMatchesEnvironment(InterpreterFrame* fp,
                                                 jsbytecode* pc) {
#ifdef DEBUG
  // If we OOMed before fully initializing the environment chain, the scope
  // and environment will definitely mismatch.
  if (fp->script()->initialEnvironmentShape() && fp->hasInitialEnvironment()) {
    AssertScopeMatchesEnvironment(fp->script()->innermostScope(pc),
                                  fp->environmentChain());
  }
#endif
}

bool InterpreterFrame::initFunctionEnvironmentObjects(JSContext* cx) {
  return js::InitFunctionEnvironmentObjects(cx, this);
}

bool InterpreterFrame::prologue(JSContext* cx) {
  RootedScript script(cx, this->script());

  MOZ_ASSERT(cx->interpreterRegs().pc == script->code());
  MOZ_ASSERT(cx->realm() == script->realm());

  if (!isFunctionFrame()) {
    return probes::EnterScript(cx, script, nullptr, this);
  }

  // At this point, we've yet to push any environments. Check that they
  // match the enclosing scope.
  AssertScopeMatchesEnvironment(script->enclosingScope(), environmentChain());

  if (callee().needsFunctionEnvironmentObjects() &&
      !initFunctionEnvironmentObjects(cx)) {
    return false;
  }

  MOZ_ASSERT_IF(isConstructing(),
                thisArgument().isObject() ||
                    thisArgument().isMagic(JS_UNINITIALIZED_LEXICAL));

  return probes::EnterScript(cx, script, script->function(), this);
}

void InterpreterFrame::epilogue(JSContext* cx, jsbytecode* pc) {
  RootedScript script(cx, this->script());
  MOZ_ASSERT(cx->realm() == script->realm());
  probes::ExitScript(cx, script, script->function(),
                     hasPushedGeckoProfilerFrame());

  // Check that the scope matches the environment at the point of leaving
  // the frame.
  AssertScopeMatchesEnvironment(this, pc);

  EnvironmentIter ei(cx, this, pc);
  UnwindAllEnvironmentsInFrame(cx, ei);

  if (isFunctionFrame()) {
    if (!callee().isGenerator() && !callee().isAsync() && isConstructing() &&
        thisArgument().isObject() && returnValue().isPrimitive()) {
      setReturnValue(thisArgument());
    }

    return;
  }

  MOZ_ASSERT(isEvalFrame() || isGlobalFrame() || isModuleFrame());
}

bool InterpreterFrame::checkReturn(JSContext* cx, HandleValue thisv,
                                   MutableHandleValue result) {
  MOZ_ASSERT(script()->isDerivedClassConstructor());
  MOZ_ASSERT(isFunctionFrame());
  MOZ_ASSERT(callee().isClassConstructor());

  HandleValue retVal = returnValue();
  if (retVal.isObject()) {
    result.set(retVal);
    return true;
  }

  if (!retVal.isUndefined()) {
    ReportValueError(cx, JSMSG_BAD_DERIVED_RETURN, JSDVG_IGNORE_STACK, retVal,
                     nullptr);
    return false;
  }

  if (thisv.isMagic(JS_UNINITIALIZED_LEXICAL)) {
    return ThrowUninitializedThis(cx);
  }

  result.set(thisv);
  return true;
}

bool InterpreterFrame::pushVarEnvironment(JSContext* cx, Handle<Scope*> scope) {
  return js::PushVarEnvironmentObject(cx, scope, this);
}

bool InterpreterFrame::pushLexicalEnvironment(JSContext* cx,
                                              Handle<LexicalScope*> scope) {
  BlockLexicalEnvironmentObject* env =
      BlockLexicalEnvironmentObject::createForFrame(cx, scope, this);
  if (!env) {
    return false;
  }

  pushOnEnvironmentChain(*env);
  return true;
}

bool InterpreterFrame::freshenLexicalEnvironment(JSContext* cx,
                                                 jsbytecode* pc) {
  Rooted<BlockLexicalEnvironmentObject*> env(
      cx, &envChain_->as<BlockLexicalEnvironmentObject>());
  BlockLexicalEnvironmentObject* fresh =
      BlockLexicalEnvironmentObject::clone(cx, env);
  if (!fresh) {
    return false;
  }

  if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
    Rooted<BlockLexicalEnvironmentObject*> freshRoot(cx, fresh);
    DebugEnvironments::onPopLexical(cx, this, pc);
    fresh = freshRoot;
  }

  replaceInnermostEnvironment(*fresh);
  return true;
}

bool InterpreterFrame::recreateLexicalEnvironment(JSContext* cx,
                                                  jsbytecode* pc) {
  Rooted<BlockLexicalEnvironmentObject*> env(
      cx, &envChain_->as<BlockLexicalEnvironmentObject>());
  BlockLexicalEnvironmentObject* fresh =
      BlockLexicalEnvironmentObject::recreate(cx, env);
  if (!fresh) {
    return false;
  }

  if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
    Rooted<BlockLexicalEnvironmentObject*> freshRoot(cx, fresh);
    DebugEnvironments::onPopLexical(cx, this, pc);
    fresh = freshRoot;
  }

  replaceInnermostEnvironment(*fresh);
  return true;
}

bool InterpreterFrame::pushClassBodyEnvironment(JSContext* cx,
                                                Handle<ClassBodyScope*> scope) {
  ClassBodyLexicalEnvironmentObject* env =
      ClassBodyLexicalEnvironmentObject::createForFrame(cx, scope, this);
  if (!env) {
    return false;
  }

  pushOnEnvironmentChain(*env);
  return true;
}

void InterpreterFrame::trace(JSTracer* trc, Value* sp, jsbytecode* pc) {
  TraceRoot(trc, &envChain_, "env chain");
  TraceRoot(trc, &script_, "script");

  if (flags_ & HAS_ARGS_OBJ) {
    TraceRoot(trc, &argsObj_, "arguments");
  }

  if (hasReturnValue()) {
    TraceRoot(trc, &rval_, "rval");
  }

  MOZ_ASSERT(sp >= slots());

  if (hasArgs()) {
    // Trace the callee and |this|. When we're doing a moving GC, we
    // need to fix up the callee pointer before we use it below, under
    // numFormalArgs() and script().
    TraceRootRange(trc, 2, argv_ - 2, "fp callee and this");

    // Trace arguments.
    unsigned argc = std::max(numActualArgs(), numFormalArgs());
    TraceRootRange(trc, argc + isConstructing(), argv_, "fp argv");
  }

  JSScript* script = this->script();
  size_t nfixed = script->nfixed();
  size_t nlivefixed = script->calculateLiveFixed(pc);

  if (nfixed == nlivefixed) {
    // All locals are live.
    traceValues(trc, 0, sp - slots());
  } else {
    // Trace operand stack.
    traceValues(trc, nfixed, sp - slots());

    // Clear dead block-scoped locals.
    while (nfixed > nlivefixed) {
      unaliasedLocal(--nfixed).setUndefined();
    }

    // Trace live locals.
    traceValues(trc, 0, nlivefixed);
  }

  if (auto* debugEnvs = script->realm()->debugEnvs()) {
    debugEnvs->traceLiveFrame(trc, this);
  }
}

void InterpreterFrame::traceValues(JSTracer* trc, unsigned start,
                                   unsigned end) {
  if (start < end) {
    TraceRootRange(trc, end - start, slots() + start, "vm_stack");
  }
}

static void TraceInterpreterActivation(JSTracer* trc,
                                       InterpreterActivation* act) {
  for (InterpreterFrameIterator frames(act); !frames.done(); ++frames) {
    InterpreterFrame* fp = frames.frame();
    fp->trace(trc, frames.sp(), frames.pc());
  }
}

void js::TraceInterpreterActivations(JSContext* cx, JSTracer* trc) {
  for (ActivationIterator iter(cx); !iter.done(); ++iter) {
    Activation* act = iter.activation();
    if (act->isInterpreter()) {
      TraceInterpreterActivation(trc, act->asInterpreter());
    }
  }
}

/*****************************************************************************/

// Unlike the other methods of this class, this method is defined here so that
// we don't have to #include jsautooplen.h in vm/Stack.h.
void InterpreterRegs::setToEndOfScript() { sp = fp()->base(); }

/*****************************************************************************/

InterpreterFrame* InterpreterStack::pushInvokeFrame(
    JSContext* cx, const CallArgs& args, MaybeConstruct constructing) {
  LifoAlloc::Mark mark = allocator_.mark();

  RootedFunction fun(cx, &args.callee().as<JSFunction>());
  RootedScript script(cx, fun->nonLazyScript());

  Value* argv;
  InterpreterFrame* fp = getCallFrame(cx, args, script, constructing, &argv);
  if (!fp) {
    return nullptr;
  }

  fp->mark_ = mark;
  fp->initCallFrame(nullptr, nullptr, nullptr, *fun, script, argv,
                    args.length(), constructing);
  return fp;
}

InterpreterFrame* InterpreterStack::pushExecuteFrame(
    JSContext* cx, HandleScript script, HandleObject envChain,
    AbstractFramePtr evalInFrame) {
  LifoAlloc::Mark mark = allocator_.mark();

  unsigned nvars = script->nslots();
  uint8_t* buffer =
      allocateFrame(cx, sizeof(InterpreterFrame) + nvars * sizeof(Value));
  if (!buffer) {
    return nullptr;
  }

  InterpreterFrame* fp = reinterpret_cast<InterpreterFrame*>(buffer);
  fp->mark_ = mark;
  fp->initExecuteFrame(cx, script, evalInFrame, envChain);
  fp->initLocals();

  return fp;
}

/*****************************************************************************/

InterpreterFrameIterator& InterpreterFrameIterator::operator++() {
  MOZ_ASSERT(!done());
  if (fp_ != activation_->entryFrame_) {
    pc_ = fp_->prevpc();
    sp_ = fp_->prevsp();
    fp_ = fp_->prev();
  } else {
    pc_ = nullptr;
    sp_ = nullptr;
    fp_ = nullptr;
  }
  return *this;
}

JS::ProfilingFrameIterator::ProfilingFrameIterator(
    JSContext* cx, const RegisterState& state,
    const Maybe<uint64_t>& samplePositionInProfilerBuffer)
    : cx_(cx),
      samplePositionInProfilerBuffer_(samplePositionInProfilerBuffer),
      activation_(nullptr) {
  if (!cx->runtime()->geckoProfiler().enabled()) {
    MOZ_CRASH(
        "ProfilingFrameIterator called when geckoProfiler not enabled for "
        "runtime.");
  }

  if (!cx->profilingActivation()) {
    return;
  }

  // If profiler sampling is not enabled, skip.
  if (!cx->isProfilerSamplingEnabled()) {
    return;
  }

  activation_ = cx->profilingActivation();

  MOZ_ASSERT(activation_->isProfiling());

  static_assert(sizeof(wasm::ProfilingFrameIterator) <= StorageSpace &&
                    sizeof(jit::JSJitProfilingFrameIterator) <= StorageSpace,
                "ProfilingFrameIterator::storage_ is too small");
  static_assert(alignof(void*) >= alignof(wasm::ProfilingFrameIterator) &&
                    alignof(void*) >= alignof(jit::JSJitProfilingFrameIterator),
                "ProfilingFrameIterator::storage_ is too weakly aligned");

  iteratorConstruct(state);
  settle();
}

JS::ProfilingFrameIterator::~ProfilingFrameIterator() {
  if (!done()) {
    MOZ_ASSERT(activation_->isProfiling());
    iteratorDestroy();
  }
}

void JS::ProfilingFrameIterator::operator++() {
  MOZ_ASSERT(!done());
  MOZ_ASSERT(activation_->isJit());
  if (isWasm()) {
    ++wasmIter();
  } else {
    ++jsJitIter();
  }
  settle();
}

void JS::ProfilingFrameIterator::settleFrames() {
  // Handle transition frames (see comment in JitFrameIter::operator++).
  if (isJSJit() && jsJitIter().done() && jsJitIter().wasmCallerFP()) {
    wasm::Frame* fp = (wasm::Frame*)jsJitIter().wasmCallerFP();
    iteratorDestroy();
    new (storage()) wasm::ProfilingFrameIterator(fp);
    kind_ = Kind::Wasm;
    MOZ_ASSERT(!wasmIter().done());
    maybeSetEndStackAddress(wasmIter().endStackAddress());
    return;
  }

  if (isWasm() && wasmIter().done() && wasmIter().unwoundJitCallerFP()) {
    uint8_t* fp = wasmIter().unwoundJitCallerFP();
    iteratorDestroy();
    // Using this ctor will skip the first jit->wasm frame, which is
    // needed because the profiling iterator doesn't know how to unwind
    // when the callee has no script.
    new (storage())
        jit::JSJitProfilingFrameIterator((jit::CommonFrameLayout*)fp);
    kind_ = Kind::JSJit;
    maybeSetEndStackAddress(jsJitIter().endStackAddress());
    return;
  }
}

void JS::ProfilingFrameIterator::settle() {
  settleFrames();
  while (iteratorDone()) {
    iteratorDestroy();
    activation_ = activation_->prevProfiling();
    endStackAddress_ = nullptr;
    if (!activation_) {
      return;
    }
    iteratorConstruct();
    settleFrames();
  }
}

void JS::ProfilingFrameIterator::iteratorConstruct(const RegisterState& state) {
  MOZ_ASSERT(!done());
  MOZ_ASSERT(activation_->isJit());

  jit::JitActivation* activation = activation_->asJit();

  // We want to know if we should start with a wasm profiling frame iterator
  // or not. To determine this, there are three possibilities:
  // - we've exited to C++ from wasm, in which case the activation
  //   exitFP low bit is tagged and we can test hasWasmExitFP().
  // - we're in wasm code, so we can do a lookup on PC.
  // - in all the other cases, we're not in wasm or we haven't exited from
  //   wasm.
  if (activation->hasWasmExitFP() || wasm::InCompiledCode(state.pc)) {
    new (storage()) wasm::ProfilingFrameIterator(*activation, state);
    kind_ = Kind::Wasm;
    maybeSetEndStackAddress(wasmIter().endStackAddress());
    return;
  }

  new (storage()) jit::JSJitProfilingFrameIterator(cx_, state.pc, state.sp);
  kind_ = Kind::JSJit;
  maybeSetEndStackAddress(jsJitIter().endStackAddress());
}

void JS::ProfilingFrameIterator::iteratorConstruct() {
  MOZ_ASSERT(!done());
  MOZ_ASSERT(activation_->isJit());

  jit::JitActivation* activation = activation_->asJit();

  // The same reasoning as in the above iteratorConstruct variant applies
  // here, except that it's even simpler: since this activation is higher up
  // on the stack, it can only have exited to C++, through wasm or ion.
  if (activation->hasWasmExitFP()) {
    new (storage()) wasm::ProfilingFrameIterator(*activation);
    kind_ = Kind::Wasm;
    maybeSetEndStackAddress(wasmIter().endStackAddress());
    return;
  }

  auto* fp = (jit::ExitFrameLayout*)activation->jsExitFP();
  new (storage()) jit::JSJitProfilingFrameIterator(fp);
  kind_ = Kind::JSJit;
  maybeSetEndStackAddress(jsJitIter().endStackAddress());
}

void JS::ProfilingFrameIterator::iteratorDestroy() {
  MOZ_ASSERT(!done());
  MOZ_ASSERT(activation_->isJit());

  if (isWasm()) {
    wasmIter().~ProfilingFrameIterator();
    return;
  }

  jsJitIter().~JSJitProfilingFrameIterator();
}

bool JS::ProfilingFrameIterator::iteratorDone() {
  MOZ_ASSERT(!done());
  MOZ_ASSERT(activation_->isJit());

  if (isWasm()) {
    return wasmIter().done();
  }

  return jsJitIter().done();
}

void* JS::ProfilingFrameIterator::stackAddress() const {
  MOZ_ASSERT(!done());
  MOZ_ASSERT(activation_->isJit());

  if (isWasm()) {
    return wasmIter().stackAddress();
  }

  return jsJitIter().stackAddress();
}

Maybe<JS::ProfilingFrameIterator::Frame>
JS::ProfilingFrameIterator::getPhysicalFrameAndEntry(
    const jit::JitcodeGlobalEntry** entry) const {
  *entry = nullptr;

  void* stackAddr = stackAddress();

  MOZ_DIAGNOSTIC_ASSERT(endStackAddress_);
#ifndef ENABLE_WASM_JSPI
  // The stack addresses are monotonically increasing, except when
  // suspendable stacks are present (e.g. when JS PI is enabled).
  MOZ_DIAGNOSTIC_ASSERT(stackAddr >= endStackAddress_);
#endif

  if (isWasm()) {
    Frame frame;
    switch (wasmIter().category()) {
      case wasm::ProfilingFrameIterator::Category::Baseline: {
        frame.kind = FrameKind::Frame_WasmBaseline;
        break;
      }
      case wasm::ProfilingFrameIterator::Category::Ion: {
        frame.kind = FrameKind::Frame_WasmIon;
        break;
      }
      default: {
        frame.kind = FrameKind::Frame_WasmOther;
        break;
      }
    }
    frame.stackAddress = stackAddr;
    frame.returnAddress_ = nullptr;
    frame.activation = activation_;
    frame.label = nullptr;
    frame.endStackAddress = endStackAddress_;
    frame.interpreterScript = nullptr;
    // TODO: get the realm ID of wasm frames. Bug 1596235.
    frame.realmID = 0;
    return mozilla::Some(frame);
  }

  MOZ_ASSERT(isJSJit());

  if (jit::IsPortableBaselineInterpreterEnabled()) {
    return mozilla::Nothing();
  }

  // Look up an entry for the return address.
  void* returnAddr = jsJitIter().resumePCinCurrentFrame();
  jit::JitcodeGlobalTable* table =
      cx_->runtime()->jitRuntime()->getJitcodeGlobalTable();

  // NB:
  // The following lookups should be infallible, but the ad-hoc stackwalking
  // code rots easily and corner cases where frames can't be looked up
  // occur too often (e.g. once every day).
  //
  // The calls to `lookup*` below have been changed from infallible ones to
  // fallible ones.  The proper solution to this problem is to fix all
  // the jitcode to use frame-pointers and reliably walk the stack with those.
  if (samplePositionInProfilerBuffer_) {
    *entry = table->lookupForSampler(returnAddr, cx_->runtime(),
                                     *samplePositionInProfilerBuffer_);
  } else {
    *entry = table->lookup(returnAddr);
  }

  // Failed to look up a jitcode entry for the given address, ignore.
  if (!*entry) {
    return mozilla::Nothing();
  }

  // Dummy frames produce no stack frames.
  if ((*entry)->isDummy()) {
    return mozilla::Nothing();
  }

  Frame frame;
  if ((*entry)->isBaselineInterpreter()) {
    frame.kind = Frame_BaselineInterpreter;
  } else if ((*entry)->isBaseline()) {
    frame.kind = Frame_Baseline;
  } else {
    MOZ_ASSERT((*entry)->isIon() || (*entry)->isIonIC());
    frame.kind = Frame_Ion;
  }
  frame.stackAddress = stackAddr;
  if ((*entry)->isBaselineInterpreter()) {
    frame.label = jsJitIter().baselineInterpreterLabel();
    jsJitIter().baselineInterpreterScriptPC(
        &frame.interpreterScript, &frame.interpreterPC_, &frame.realmID);
    MOZ_ASSERT(frame.interpreterScript);
    MOZ_ASSERT(frame.interpreterPC_);
  } else {
    frame.interpreterScript = nullptr;
    frame.returnAddress_ = returnAddr;
    frame.label = nullptr;
    frame.realmID = 0;
  }
  frame.activation = activation_;
  frame.endStackAddress = endStackAddress_;
  return mozilla::Some(frame);
}

uint32_t JS::ProfilingFrameIterator::extractStack(Frame* frames,
                                                  uint32_t offset,
                                                  uint32_t end) const {
  if (offset >= end) {
    return 0;
  }

  const jit::JitcodeGlobalEntry* entry;
  Maybe<Frame> physicalFrame = getPhysicalFrameAndEntry(&entry);

  // Dummy frames produce no stack frames.
  if (physicalFrame.isNothing()) {
    return 0;
  }

  if (isWasm()) {
    frames[offset] = physicalFrame.value();
    frames[offset].label = wasmIter().label();
    return 1;
  }

  if (physicalFrame->kind == Frame_BaselineInterpreter) {
    frames[offset] = physicalFrame.value();
    return 1;
  }

  // Extract the stack for the entry.  Assume maximum inlining depth is <64
  const char* labels[64];
  uint32_t depth = entry->callStackAtAddr(cx_->runtime(),
                                          jsJitIter().resumePCinCurrentFrame(),
                                          labels, std::size(labels));
  MOZ_ASSERT(depth < std::size(labels));
  for (uint32_t i = 0; i < depth; i++) {
    if (offset + i >= end) {
      return i;
    }
    frames[offset + i] = physicalFrame.value();
    frames[offset + i].label = labels[i];
  }

  return depth;
}

Maybe<JS::ProfilingFrameIterator::Frame>
JS::ProfilingFrameIterator::getPhysicalFrameWithoutLabel() const {
  const jit::JitcodeGlobalEntry* unused;
  return getPhysicalFrameAndEntry(&unused);
}

bool JS::ProfilingFrameIterator::isWasm() const {
  MOZ_ASSERT(!done());
  return kind_ == Kind::Wasm;
}

bool JS::ProfilingFrameIterator::isJSJit() const {
  return kind_ == Kind::JSJit;
}

mozilla::Maybe<JS::ProfilingFrameIterator::RegisterState>
JS::ProfilingFrameIterator::getCppEntryRegisters() const {
  if (!isJSJit()) {
    return mozilla::Nothing{};
  }
  return jit::JitRuntime::getCppEntryRegisters(jsJitIter().framePtr());
}

Messung V0.5
C=88 H=98 G=93

¤ Dauer der Verarbeitung: 0.19 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.