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

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

#include "mozilla/Assertions.h"  // MOZ_ASSERT, MOZ_CRASH
#include "mozilla/MaybeOneOf.h"  // mozilla::MaybeOneOf

#include <stddef.h>  // size_t
#include <stdint.h>  // uint8_t, uint32_t
#include <stdlib.h>  // getenv

#include "jit/BaselineFrame.h"   // js::jit::BaselineFrame
#include "jit/JitFrames.h"       // js::jit::EnsureUnwoundJitExitFrame
#include "jit/JSJitFrameIter.h"  // js::jit::{FrameType,InlineFrameIterator,JSJitFrameIter,MaybeReadFallback,SnapshotIterator}
#include "js/ColumnNumber.h"  // JS::LimitedColumnNumberOneOrigin, JS::TaggedColumnNumberOneOrigin
#include "js/GCAPI.h"              // JS::AutoSuppressGCAnalysis
#include "js/Principals.h"         // JSSubsumesOp
#include "js/RootingAPI.h"         // JS::Rooted
#include "vm/Activation.h"         // js::Activation{,Iterator}
#include "vm/EnvironmentObject.h"  // js::CallObject
#include "vm/JitActivation.h"      // js::jit::JitActivation
#include "vm/JSContext.h"          // JSContext
#include "vm/JSFunction.h"         // JSFunction
#include "vm/JSScript.h"  // js::PCToLineNumber, JSScript, js::ScriptSource
#include "vm/Runtime.h"   // JSRuntime
#include "vm/Stack.h"  // js::{AbstractFramePtr,InterpreterFrame,MaybeCheckAliasing}
#include "wasm/WasmFrameIter.h"  // js::wasm::WasmFrameIter
#include "wasm/WasmInstance.h"   // js::wasm::Instance

#include "jit/JSJitFrameIter-inl.h"  // js::jit::JSJitFrameIter::baselineFrame{,NumValueSlots}
#include "vm/Stack-inl.h"  // js::AbstractFramePtr::*

namespace JS {
class JS_PUBLIC_API Realm;
}  // namespace JS

namespace js {
class ArgumentsObject;
}  // namespace js

using JS::Realm;
using JS::Rooted;
using JS::Value;

using js::AbstractFramePtr;
using js::ArgumentsObject;
using js::CallObject;
using js::FrameIter;
using js::JitFrameIter;
using js::NonBuiltinFrameIter;
using js::NonBuiltinScriptFrameIter;
using js::OnlyJSJitFrameIter;
using js::ScriptSource;
using js::jit::JSJitFrameIter;

JitFrameIter::JitFrameIter(const JitFrameIter& another) { *this = another; }

JitFrameIter& JitFrameIter::operator=(const JitFrameIter& another) {
  MOZ_ASSERT(this != &another);

  act_ = another.act_;
  mustUnwindActivation_ = another.mustUnwindActivation_;

  if (isSome()) {
    iter_.destroy();
  }
  if (!another.isSome()) {
    return *this;
  }

  if (another.isJSJit()) {
    iter_.construct<jit::JSJitFrameIter>(another.asJSJit());
  } else {
    MOZ_ASSERT(another.isWasm());
    iter_.construct<wasm::WasmFrameIter>(another.asWasm());
  }

  return *this;
}

JitFrameIter::JitFrameIter(jit::JitActivation* act, bool mustUnwindActivation) {
  act_ = act;
  mustUnwindActivation_ = mustUnwindActivation;
  MOZ_ASSERT(act->hasExitFP(),
             "packedExitFP is used to determine if JSJit or wasm");
  if (act->hasJSExitFP()) {
    iter_.construct<jit::JSJitFrameIter>(act);
  } else {
    MOZ_ASSERT(act->hasWasmExitFP());
    iter_.construct<wasm::WasmFrameIter>(act);
  }
  settle();
}

void JitFrameIter::skipNonScriptedJSFrames() {
  if (isJSJit()) {
    // Stop at the first scripted frame.
    jit::JSJitFrameIter& frames = asJSJit();
    while (!frames.isScripted() && !frames.done()) {
      ++frames;
    }
    settle();
  }
}

bool JitFrameIter::isSelfHostedIgnoringInlining() const {
  MOZ_ASSERT(!done());

  if (isWasm()) {
    return false;
  }

  return asJSJit().script()->selfHosted();
}

JS::Realm* JitFrameIter::realm() const {
  MOZ_ASSERT(!done());

  if (isWasm()) {
    return asWasm().instance()->realm();
  }

  if (asJSJit().isScripted()) {
    return asJSJit().script()->realm();
  }

  MOZ_RELEASE_ASSERT(asJSJit().isTrampolineNative());
  return asJSJit().callee()->realm();
}

uint8_t* JitFrameIter::resumePCinCurrentFrame() const {
  if (isWasm()) {
    return asWasm().resumePCinCurrentFrame();
  }
  return asJSJit().resumePCinCurrentFrame();
}

bool JitFrameIter::done() const {
  if (!isSome()) {
    return true;
  }
  if (isJSJit()) {
    return asJSJit().done();
  }
  if (isWasm()) {
    return asWasm().done();
  }
  MOZ_CRASH("unhandled case");
}

void JitFrameIter::settle() {
  if (isJSJit()) {
    const jit::JSJitFrameIter& jitFrame = asJSJit();
    if (jitFrame.type() != jit::FrameType::WasmToJSJit) {
      return;
    }

    // Transition from js jit frames to wasm frames: we're on the
    // wasm-to-jit fast path. The current stack layout is as follows:
    // (stack grows downward)
    //
    // [--------------------]
    // [WASM FUNC           ]
    // [WASM JIT EXIT FRAME ]
    // [JIT WASM ENTRY FRAME] <-- we're here.
    //
    // So prevFP points to the wasm jit exit FP, maintaing the invariant in
    // WasmFrameIter that the first frame is an exit frame and can be
    // popped.

    wasm::Frame* prevFP = (wasm::Frame*)jitFrame.prevFp();

    if (mustUnwindActivation_) {
      act_->setWasmExitFP(prevFP);
    }

    iter_.destroy();
    iter_.construct<wasm::WasmFrameIter>(act_, prevFP);
    MOZ_ASSERT(!asWasm().done());
    return;
  }

  if (isWasm()) {
    const wasm::WasmFrameIter& wasmFrame = asWasm();
    if (!wasmFrame.done() || !wasmFrame.unwoundCallerFPIsJSJit()) {
      return;
    }

    // Transition from wasm frames to jit frames: we're on the
    // jit-to-wasm fast path. The current stack layout is as follows:
    // (stack grows downward)
    //
    // [--------------------]
    // [JIT FRAME           ]
    // [WASM JIT ENTRY FRAME] <-- we're here
    //
    // The wasm iterator has saved the previous jit frame pointer for us.

    uint8_t* prevFP = wasmFrame.unwoundCallerFP();

    if (mustUnwindActivation_) {
      act_->setJSExitFP(prevFP);
    }

    iter_.destroy();
    iter_.construct<jit::JSJitFrameIter>(act_, prevFP, mustUnwindActivation_);
    MOZ_ASSERT(!asJSJit().done());
    return;
  }
}

void JitFrameIter::operator++() {
  MOZ_ASSERT(isSome());
  if (isJSJit()) {
    const jit::JSJitFrameIter& jitFrame = asJSJit();

    jit::JitFrameLayout* prevFrame = nullptr;
    if (mustUnwindActivation_ && jitFrame.isScripted()) {
      prevFrame = jitFrame.jsFrame();
    }

    ++asJSJit();

    if (prevFrame) {
      // Unwind the frame by updating packedExitFP. This is necessary
      // so that (1) debugger exception unwind and leave frame hooks
      // don't see this frame when they use ScriptFrameIter, and (2)
      // ScriptFrameIter does not crash when accessing an IonScript
      // that's destroyed by the ionScript->decref call.
      EnsureUnwoundJitExitFrame(act_, prevFrame);
    }
  } else if (isWasm()) {
    ++asWasm();
  } else {
    MOZ_CRASH("unhandled case");
  }
  settle();
}

OnlyJSJitFrameIter::OnlyJSJitFrameIter(jit::JitActivation* act)
    : JitFrameIter(act) {
  settle();
}

OnlyJSJitFrameIter::OnlyJSJitFrameIter(const ActivationIterator& iter)
    : OnlyJSJitFrameIter(iter->asJit()) {}

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

void FrameIter::popActivation() {
  ++data_.activations_;
  settleOnActivation();
}

bool FrameIter::principalsSubsumeFrame() const {
  // If the caller supplied principals, only show frames which are
  // subsumed (of the same origin or of an origin accessible) by these
  // principals.

  MOZ_ASSERT(!done());

  if (!data_.principals_) {
    return true;
  }

  JSSubsumesOp subsumes = data_.cx_->runtime()->securityCallbacks->subsumes;
  if (!subsumes) {
    return true;
  }

  JS::AutoSuppressGCAnalysis nogc;
  return subsumes(data_.principals_, realm()->principals());
}

void FrameIter::popInterpreterFrame() {
  MOZ_ASSERT(data_.state_ == INTERP);

  ++data_.interpFrames_;

  if (data_.interpFrames_.done()) {
    popActivation();
  } else {
    data_.pc_ = data_.interpFrames_.pc();
  }
}

void FrameIter::settleOnActivation() {
  MOZ_ASSERT(!data_.cx_->inUnsafeCallWithABI);

  while (true) {
    if (data_.activations_.done()) {
      data_.state_ = DONE;
      return;
    }

    Activation* activation = data_.activations_.activation();

    if (activation->isJit()) {
      data_.jitFrames_ = JitFrameIter(activation->asJit());
      data_.jitFrames_.skipNonScriptedJSFrames();
      if (data_.jitFrames_.done()) {
        // It's possible to have an JitActivation with no scripted
        // frames, for instance if we hit an over-recursion during
        // bailout.
        ++data_.activations_;
        continue;
      }
      data_.state_ = JIT;
      nextJitFrame();
      return;
    }

    MOZ_ASSERT(activation->isInterpreter());

    InterpreterActivation* interpAct = activation->asInterpreter();
    data_.interpFrames_ = InterpreterFrameIterator(interpAct);

    // If we OSR'ed into JIT code, skip the interpreter frame so that
    // the same frame is not reported twice.
    if (data_.interpFrames_.frame()->runningInJit()) {
      ++data_.interpFrames_;
      if (data_.interpFrames_.done()) {
        ++data_.activations_;
        continue;
      }
    }

    MOZ_ASSERT(!data_.interpFrames_.frame()->runningInJit());
    data_.pc_ = data_.interpFrames_.pc();
    data_.state_ = INTERP;
    return;
  }
}

FrameIter::Data::Data(JSContext* cx, DebuggerEvalOption debuggerEvalOption,
                      JSPrincipals* principals)
    : cx_(cx),
      debuggerEvalOption_(debuggerEvalOption),
      principals_(principals),
      state_(DONE),
      pc_(nullptr),
      interpFrames_(nullptr),
      activations_(cx),
      ionInlineFrameNo_(0) {}

FrameIter::Data::Data(const FrameIter::Data& other) = default;

FrameIter::FrameIter(JSContext* cx, DebuggerEvalOption debuggerEvalOption)
    : data_(cx, debuggerEvalOption, nullptr),
      ionInlineFrames_(cx, (js::jit::JSJitFrameIter*)nullptr) {
  settleOnActivation();

  // No principals so we can see all frames.
  MOZ_ASSERT_IF(!done(), principalsSubsumeFrame());
}

FrameIter::FrameIter(JSContext* cx, DebuggerEvalOption debuggerEvalOption,
                     JSPrincipals* principals)
    : data_(cx, debuggerEvalOption, principals),
      ionInlineFrames_(cx, (js::jit::JSJitFrameIter*)nullptr) {
  settleOnActivation();

  // If we're not allowed to see this frame, call operator++ to skip this (and
  // other) cross-origin frames.
  if (!done() && !principalsSubsumeFrame()) {
    ++*this;
  }
}

FrameIter::FrameIter(const FrameIter& other)
    : data_(other.data_),
      ionInlineFrames_(other.data_.cx_,
                       isIonScripted() ? &other.ionInlineFrames_ : nullptr) {}

FrameIter::FrameIter(const Data& data)
    : data_(data),
      ionInlineFrames_(data.cx_, isIonScripted() ? &jsJitFrame() : nullptr) {
  MOZ_ASSERT(data.cx_);
  if (isIonScripted()) {
    while (ionInlineFrames_.frameNo() != data.ionInlineFrameNo_) {
      ++ionInlineFrames_;
    }
  }
}

void FrameIter::nextJitFrame() {
  MOZ_ASSERT(data_.jitFrames_.isSome());

  if (isJSJit()) {
    if (jsJitFrame().isIonScripted()) {
      ionInlineFrames_.resetOn(&jsJitFrame());
      data_.pc_ = ionInlineFrames_.pc();
    } else {
      MOZ_ASSERT(jsJitFrame().isBaselineJS());
      jsJitFrame().baselineScriptAndPc(nullptr, &data_.pc_);
    }
    return;
  }

  MOZ_ASSERT(isWasm());
  wasmFrame().enableInlinedFrames();
  data_.pc_ = nullptr;
}

void FrameIter::popJitFrame() {
  MOZ_ASSERT(data_.state_ == JIT);
  MOZ_ASSERT(data_.jitFrames_.isSome());

  if (isJSJit() && jsJitFrame().isIonScripted() && ionInlineFrames_.more()) {
    ++ionInlineFrames_;
    data_.pc_ = ionInlineFrames_.pc();
    return;
  }

  ++data_.jitFrames_;
  data_.jitFrames_.skipNonScriptedJSFrames();

  if (!data_.jitFrames_.done()) {
    nextJitFrame();
  } else {
    data_.jitFrames_.reset();
    popActivation();
  }
}

FrameIter& FrameIter::operator++() {
  while (true) {
    switch (data_.state_) {
      case DONE:
        MOZ_CRASH("Unexpected state");
      case INTERP:
        if (interpFrame()->isDebuggerEvalFrame() &&
            data_.debuggerEvalOption_ == FOLLOW_DEBUGGER_EVAL_PREV_LINK) {
          AbstractFramePtr eifPrev = interpFrame()->evalInFramePrev();

          popInterpreterFrame();

          while (!hasUsableAbstractFramePtr() ||
                 abstractFramePtr() != eifPrev) {
            if (data_.state_ == JIT) {
              popJitFrame();
            } else {
              popInterpreterFrame();
            }
          }

          break;
        }
        popInterpreterFrame();
        break;
      case JIT:
        popJitFrame();
        break;
    }

    if (done() || principalsSubsumeFrame()) {
      break;
    }
  }

  return *this;
}

FrameIter::Data* FrameIter::copyData() const {
  Data* data = data_.cx_->new_<Data>(data_);
  if (!data) {
    return nullptr;
  }

  if (data && isIonScripted()) {
    data->ionInlineFrameNo_ = ionInlineFrames_.frameNo();
  }
  return data;
}

void* FrameIter::rawFramePtr() const {
  switch (data_.state_) {
    case DONE:
      return nullptr;
    case INTERP:
      return interpFrame();
    case JIT:
      if (isJSJit()) {
        return jsJitFrame().fp();
      }
      MOZ_ASSERT(isWasm());
      return nullptr;
  }
  MOZ_CRASH("Unexpected state");
}

JS::Compartment* FrameIter::compartment() const {
  switch (data_.state_) {
    case DONE:
      break;
    case INTERP:
    case JIT:
      return data_.activations_->compartment();
  }
  MOZ_CRASH("Unexpected state");
}

Realm* FrameIter::realm() const {
  MOZ_ASSERT(!done());

  if (hasScript()) {
    return script()->realm();
  }

  return wasmInstance()->realm();
}

bool FrameIter::isEvalFrame() const {
  switch (data_.state_) {
    case DONE:
      break;
    case INTERP:
      return interpFrame()->isEvalFrame();
    case JIT:
      if (isJSJit()) {
        if (jsJitFrame().isBaselineJS()) {
          return jsJitFrame().baselineFrame()->isEvalFrame();
        }
        MOZ_ASSERT(!script()->isForEval());
        return false;
      }
      MOZ_ASSERT(isWasm());
      return false;
  }
  MOZ_CRASH("Unexpected state");
}

bool FrameIter::isModuleFrame() const {
  MOZ_ASSERT(!done());

  if (hasScript()) {
    return script()->isModule();
  }
  MOZ_CRASH("Unexpected state");
}

bool FrameIter::isFunctionFrame() const {
  MOZ_ASSERT(!done());
  switch (data_.state_) {
    case DONE:
      break;
    case INTERP:
      return interpFrame()->isFunctionFrame();
    case JIT:
      if (isJSJit()) {
        if (jsJitFrame().isBaselineJS()) {
          return jsJitFrame().baselineFrame()->isFunctionFrame();
        }
        return script()->isFunction();
      }
      MOZ_ASSERT(isWasm());
      return false;
  }
  MOZ_CRASH("Unexpected state");
}

JSAtom* FrameIter::maybeFunctionDisplayAtom() const {
  switch (data_.state_) {
    case DONE:
      break;
    case INTERP:
    case JIT:
      if (isWasm()) {
        return wasmFrame().functionDisplayAtom();
      }
      if (isFunctionFrame()) {
        return calleeTemplate()->fullDisplayAtom();
      }
      return nullptr;
  }

  MOZ_CRASH("Unexpected state");
}

ScriptSource* FrameIter::scriptSource() const {
  switch (data_.state_) {
    case DONE:
      break;
    case INTERP:
    case JIT:
      return script()->scriptSource();
  }

  MOZ_CRASH("Unexpected state");
}

const char* FrameIter::filename() const {
  switch (data_.state_) {
    case DONE:
      break;
    case INTERP:
    case JIT:
      if (isWasm()) {
        return wasmFrame().filename();
      }
      return script()->filename();
  }

  MOZ_CRASH("Unexpected state");
}

const char16_t* FrameIter::displayURL() const {
  switch (data_.state_) {
    case DONE:
      break;
    case INTERP:
    case JIT:
      if (isWasm()) {
        return wasmFrame().displayURL();
      }
      ScriptSource* ss = script()->scriptSource();
      return ss->hasDisplayURL() ? ss->displayURL() : nullptr;
  }
  MOZ_CRASH("Unexpected state");
}

unsigned FrameIter::computeLine(JS::TaggedColumnNumberOneOrigin* column) const {
  switch (data_.state_) {
    case DONE:
      break;
    case INTERP:
    case JIT:
      if (isWasm()) {
        return wasmFrame().computeLine(column);
      }
      JS::LimitedColumnNumberOneOrigin columnNumber;
      unsigned lineNumber = PCToLineNumber(script(), pc(), &columnNumber);
      if (column) {
        *column = JS::TaggedColumnNumberOneOrigin(columnNumber);
      }
      return lineNumber;
  }

  MOZ_CRASH("Unexpected state");
}

bool FrameIter::mutedErrors() const {
  switch (data_.state_) {
    case DONE:
      break;
    case INTERP:
    case JIT:
      if (isWasm()) {
        return wasmFrame().mutedErrors();
      }
      return script()->mutedErrors();
  }
  MOZ_CRASH("Unexpected state");
}

bool FrameIter::isConstructing() const {
  switch (data_.state_) {
    case DONE:
      break;
    case JIT:
      MOZ_ASSERT(isJSJit());
      if (jsJitFrame().isIonScripted()) {
        return ionInlineFrames_.isConstructing();
      }
      MOZ_ASSERT(jsJitFrame().isBaselineJS());
      return jsJitFrame().isConstructing();
    case INTERP:
      return interpFrame()->isConstructing();
  }

  MOZ_CRASH("Unexpected state");
}

bool FrameIter::ensureHasRematerializedFrame(JSContext* cx) {
  MOZ_ASSERT(isIon());
  return !!activation()->asJit()->getRematerializedFrame(cx, jsJitFrame());
}

bool FrameIter::hasUsableAbstractFramePtr() const {
  switch (data_.state_) {
    case DONE:
      return false;
    case JIT:
      if (isJSJit()) {
        if (jsJitFrame().isBaselineJS()) {
          return true;
        }

        MOZ_ASSERT(jsJitFrame().isIonScripted());
        return !!activation()->asJit()->lookupRematerializedFrame(
            jsJitFrame().fp(), ionInlineFrames_.frameNo());
      }
      MOZ_ASSERT(isWasm());
      return wasmFrame().debugEnabled();
    case INTERP:
      return true;
  }
  MOZ_CRASH("Unexpected state");
}

AbstractFramePtr FrameIter::abstractFramePtr() const {
  MOZ_ASSERT(hasUsableAbstractFramePtr());
  switch (data_.state_) {
    case DONE:
      break;
    case JIT: {
      if (isJSJit()) {
        if (jsJitFrame().isBaselineJS()) {
          return jsJitFrame().baselineFrame();
        }
        MOZ_ASSERT(isIonScripted());
        return activation()->asJit()->lookupRematerializedFrame(
            jsJitFrame().fp(), ionInlineFrames_.frameNo());
      }
      MOZ_ASSERT(isWasm());
      MOZ_ASSERT(wasmFrame().debugEnabled());
      return wasmFrame().debugFrame();
    }
    case INTERP:
      MOZ_ASSERT(interpFrame());
      return AbstractFramePtr(interpFrame());
  }
  MOZ_CRASH("Unexpected state");
}

void FrameIter::updatePcQuadratic() {
  switch (data_.state_) {
    case DONE:
      break;
    case INTERP: {
      InterpreterFrame* frame = interpFrame();
      InterpreterActivation* activation = data_.activations_->asInterpreter();

      // Look for the current frame.
      data_.interpFrames_ = InterpreterFrameIterator(activation);
      while (data_.interpFrames_.frame() != frame) {
        ++data_.interpFrames_;
      }

      // Update the pc.
      MOZ_ASSERT(data_.interpFrames_.frame() == frame);
      data_.pc_ = data_.interpFrames_.pc();
      return;
    }
    case JIT:
      if (jsJitFrame().isBaselineJS()) {
        jit::BaselineFrame* frame = jsJitFrame().baselineFrame();
        jit::JitActivation* activation = data_.activations_->asJit();

        // activation's exitFP may be invalid, so create a new
        // activation iterator.
        data_.activations_ = ActivationIterator(data_.cx_);
        while (data_.activations_.activation() != activation) {
          ++data_.activations_;
        }

        // Look for the current frame.
        data_.jitFrames_ = JitFrameIter(data_.activations_->asJit());
        while (!isJSJit() || !jsJitFrame().isBaselineJS() ||
               jsJitFrame().baselineFrame() != frame) {
          ++data_.jitFrames_;
        }

        // Update the pc.
        MOZ_ASSERT(jsJitFrame().baselineFrame() == frame);
        jsJitFrame().baselineScriptAndPc(nullptr, &data_.pc_);
        return;
      }
      break;
  }
  MOZ_CRASH("Unexpected state");
}

void FrameIter::wasmUpdateBytecodeOffset() {
  MOZ_RELEASE_ASSERT(isWasm(), "Unexpected state");

  wasm::DebugFrame* frame = wasmFrame().debugFrame();

  // Relookup the current frame, updating the bytecode offset in the process.
  data_.jitFrames_ = JitFrameIter(data_.activations_->asJit());
  while (!isWasm() || wasmFrame().debugFrame() != frame) {
    ++data_.jitFrames_;
  }

  MOZ_ASSERT(wasmFrame().debugFrame() == frame);
}

JSFunction* FrameIter::calleeTemplate() const {
  switch (data_.state_) {
    case DONE:
      break;
    case INTERP:
      MOZ_ASSERT(isFunctionFrame());
      return &interpFrame()->callee();
    case JIT:
      if (jsJitFrame().isBaselineJS()) {
        return jsJitFrame().callee();
      }
      MOZ_ASSERT(jsJitFrame().isIonScripted());
      return ionInlineFrames_.calleeTemplate();
  }
  MOZ_CRASH("Unexpected state");
}

JSFunction* FrameIter::callee(JSContext* cx) const {
  switch (data_.state_) {
    case DONE:
      break;
    case INTERP:
      return calleeTemplate();
    case JIT:
      if (isIonScripted()) {
        jit::MaybeReadFallback recover(cx, activation()->asJit(),
                                       &jsJitFrame());
        return ionInlineFrames_.callee(recover);
      }
      MOZ_ASSERT(jsJitFrame().isBaselineJS());
      return calleeTemplate();
  }
  MOZ_CRASH("Unexpected state");
}

bool FrameIter::matchCallee(JSContext* cx, JS::Handle<JSFunction*> fun) const {
  // Use the calleeTemplate to rule out a match without needing to invalidate to
  // find the actual callee. The real callee my be a clone of the template which
  // should *not* be considered a match.
  Rooted<JSFunction*> currentCallee(cx, calleeTemplate());

  if (currentCallee->nargs() != fun->nargs()) {
    return false;
  }

  if (currentCallee->flags().stableAcrossClones() !=
      fun->flags().stableAcrossClones()) {
    return false;
  }

  // The calleeTemplate for a callee will always have the same BaseScript. If
  // the script clones do not use the same script, they also have a different
  // group and Ion will not inline them interchangeably.
  //
  // See: js::jit::InlineFrameIterator::findNextFrame()
  if (currentCallee->hasBaseScript() && fun->hasBaseScript()) {
    if (currentCallee->baseScript() != fun->baseScript()) {
      return false;
    }
  }

  return callee(cx) == fun;
}

unsigned FrameIter::numActualArgs() const {
  switch (data_.state_) {
    case DONE:
      break;
    case INTERP:
      MOZ_ASSERT(isFunctionFrame());
      return interpFrame()->numActualArgs();
    case JIT:
      if (isIonScripted()) {
        return ionInlineFrames_.numActualArgs();
      }
      MOZ_ASSERT(jsJitFrame().isBaselineJS());
      return jsJitFrame().numActualArgs();
  }
  MOZ_CRASH("Unexpected state");
}

unsigned FrameIter::numFormalArgs() const {
  return script()->function()->nargs();
}

Value FrameIter::unaliasedActual(unsigned i,
                                 MaybeCheckAliasing checkAliasing) const {
  return abstractFramePtr().unaliasedActual(i, checkAliasing);
}

JSObject* FrameIter::environmentChain(JSContext* cx) const {
  switch (data_.state_) {
    case DONE:
      break;
    case JIT:
      if (isJSJit()) {
        if (isIonScripted()) {
          jit::MaybeReadFallback recover(cx, activation()->asJit(),
                                         &jsJitFrame());
          return ionInlineFrames_.environmentChain(recover);
        }
        return jsJitFrame().baselineFrame()->environmentChain();
      }
      MOZ_ASSERT(isWasm());
      return wasmFrame().debugFrame()->environmentChain();
    case INTERP:
      return interpFrame()->environmentChain();
  }
  MOZ_CRASH("Unexpected state");
}

bool FrameIter::hasInitialEnvironment(JSContext* cx) const {
  if (hasUsableAbstractFramePtr()) {
    return abstractFramePtr().hasInitialEnvironment();
  }

  if (isWasm()) {
    // See JSFunction::needsFunctionEnvironmentObjects().
    return false;
  }

  MOZ_ASSERT(isJSJit());
  MOZ_ASSERT(isIonScripted());

  bool hasInitialEnv = false;
  jit::MaybeReadFallback recover(cx, activation()->asJit(), &jsJitFrame());
  ionInlineFrames_.environmentChain(recover, &hasInitialEnv);

  return hasInitialEnv;
}

CallObject& FrameIter::callObj(JSContext* cx) const {
  MOZ_ASSERT(calleeTemplate()->needsCallObject());
  MOZ_ASSERT(hasInitialEnvironment(cx));

  JSObject* pobj = environmentChain(cx);
  while (!pobj->is<CallObject>()) {
    pobj = pobj->enclosingEnvironment();
  }
  return pobj->as<CallObject>();
}

bool FrameIter::hasArgsObj() const { return abstractFramePtr().hasArgsObj(); }

ArgumentsObject& FrameIter::argsObj() const {
  MOZ_ASSERT(hasArgsObj());
  return abstractFramePtr().argsObj();
}

Value FrameIter::thisArgument(JSContext* cx) const {
  MOZ_ASSERT(isFunctionFrame());

  switch (data_.state_) {
    case DONE:
      break;
    case JIT:
      if (isIonScripted()) {
        jit::MaybeReadFallback recover(cx, activation()->asJit(),
                                       &jsJitFrame());
        return ionInlineFrames_.thisArgument(recover);
      }
      return jsJitFrame().baselineFrame()->thisArgument();
    case INTERP:
      return interpFrame()->thisArgument();
  }
  MOZ_CRASH("Unexpected state");
}

Value FrameIter::returnValue() const {
  switch (data_.state_) {
    case DONE:
      break;
    case JIT:
      if (jsJitFrame().isBaselineJS()) {
        return jsJitFrame().baselineFrame()->returnValue();
      }
      break;
    case INTERP:
      return interpFrame()->returnValue();
  }
  MOZ_CRASH("Unexpected state");
}

void FrameIter::setReturnValue(const Value& v) {
  switch (data_.state_) {
    case DONE:
      break;
    case JIT:
      if (jsJitFrame().isBaselineJS()) {
        jsJitFrame().baselineFrame()->setReturnValue(v);
        return;
      }
      break;
    case INTERP:
      interpFrame()->setReturnValue(v);
      return;
  }
  MOZ_CRASH("Unexpected state");
}

size_t FrameIter::numFrameSlots() const {
  switch (data_.state_) {
    case DONE:
      break;
    case JIT: {
      if (isIonScripted()) {
        return ionInlineFrames_.snapshotIterator().numAllocations() -
               ionInlineFrames_.script()->nfixed();
      }
      uint32_t numValueSlots = jsJitFrame().baselineFrameNumValueSlots();
      return numValueSlots - jsJitFrame().script()->nfixed();
    }
    case INTERP:
      MOZ_ASSERT(data_.interpFrames_.sp() >= interpFrame()->base());
      return data_.interpFrames_.sp() - interpFrame()->base();
  }
  MOZ_CRASH("Unexpected state");
}

Value FrameIter::frameSlotValue(size_t index) const {
  switch (data_.state_) {
    case DONE:
      break;
    case JIT:
      if (isIonScripted()) {
        jit::SnapshotIterator si(ionInlineFrames_.snapshotIterator());
        index += ionInlineFrames_.script()->nfixed();
        return si.maybeReadAllocByIndex(index);
      }
      index += jsJitFrame().script()->nfixed();
      return *jsJitFrame().baselineFrame()->valueSlot(index);
    case INTERP:
      return interpFrame()->base()[index];
  }
  MOZ_CRASH("Unexpected state");
}

#ifdef DEBUG
bool js::SelfHostedFramesVisible() {
  static bool checked = false;
  static bool visible = false;
  if (!checked) {
    checked = true;
    char* env = getenv("MOZ_SHOW_ALL_JS_FRAMES");
    visible = !!env;
  }
  return visible;
}
#endif

void NonBuiltinFrameIter::settle() {
  if (!SelfHostedFramesVisible()) {
    while (!done() && hasScript() && script()->selfHosted()) {
      FrameIter::operator++();
    }
  }
}

void NonBuiltinScriptFrameIter::settle() {
  if (!SelfHostedFramesVisible()) {
    while (!done() && script()->selfHosted()) {
      ScriptFrameIter::operator++();
    }
  }
}

bool FrameIter::inPrologue() const {
  if (pc() < script()->main()) {
    return true;
  }
  // If we do a VM call before pushing locals in baseline, the stack frame will
  // not include space for those locals.
  if (pc() == script()->code() && isBaseline() &&
      jsJitFrame().baselineFrameNumValueSlots() < script()->nfixed()) {
    return true;
  }

  return false;
}

Messung V0.5
C=89 H=97 G=93

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