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

Quelle  WarpBuilderShared.h   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/. */


#ifndef jit_WarpBuilderShared_h
#define jit_WarpBuilderShared_h

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

#include "jit/MIRGraph.h"
#include "js/Value.h"

namespace js {

class BytecodeLocation;

namespace jit {

class MBasicBlock;
class MCall;
class MConstant;
class MInstruction;
class MIRGenerator;
class TempAllocator;
class WarpSnapshot;
class WrappedFunction;

// Helper class to manage call state.
class MOZ_STACK_CLASS CallInfo {
  MDefinition* callee_ = nullptr;
  MDefinition* thisArg_ = nullptr;
  MDefinition* newTargetArg_ = nullptr;
  MDefinitionVector args_;

  bool constructing_;

  // True if the caller does not use the return value.
  bool ignoresReturnValue_;

  bool inlined_ = false;
  bool setter_ = false;

 public:
  // For normal calls and FunCall we can shuffle around definitions in
  // the CallInfo and use a normal MCall. For others, we need to use a
  // specialized call.
  enum class ArgFormat {
    Standard,
    Array,
    FunApplyArgsObj,
  };

 private:
  ArgFormat argFormat_ = ArgFormat::Standard;
  mozilla::Maybe<ResumeMode> inliningMode_;

 public:
  CallInfo(TempAllocator& alloc, bool constructing, bool ignoresReturnValue,
           jsbytecode* pc = nullptr)
      : args_(alloc),
        constructing_(constructing),
        ignoresReturnValue_(ignoresReturnValue) {}

  [[nodiscard]] bool init(MBasicBlock* current, uint32_t argc) {
    MOZ_ASSERT(args_.empty());

    // Get the arguments in the right order
    if (!args_.reserve(argc)) {
      return false;
    }

    if (constructing()) {
      setNewTarget(current->pop());
    }

    for (int32_t i = argc; i > 0; i--) {
      args_.infallibleAppend(current->peek(-i));
    }
    current->popn(argc);

    // Get |this| and |callee|
    setThis(current->pop());
    setCallee(current->pop());

    return true;
  }

  void initForSpreadCall(MBasicBlock* current) {
    MOZ_ASSERT(args_.empty());

    if (constructing()) {
      setNewTarget(current->pop());
    }

    // Spread calls have one argument, an Array object containing the args.
    static_assert(decltype(args_)::InlineLength >= 1,
                  "Appending one argument should be infallible");
    MOZ_ALWAYS_TRUE(args_.append(current->pop()));

    // Get |this| and |callee|
    setThis(current->pop());
    setCallee(current->pop());

    argFormat_ = ArgFormat::Array;
  }

  void initForGetterCall(MDefinition* callee, MDefinition* thisVal) {
    MOZ_ASSERT(args_.empty());
    setCallee(callee);
    setThis(thisVal);
  }

  void initForProxyGet(MDefinition* callee, MDefinition* handler,
                       MDefinition* target, MDefinition* id,
                       MDefinition* receiver) {
    MOZ_ASSERT(args_.empty());
    setCallee(callee);
    setThis(handler);
    static_assert(decltype(args_)::InlineLength >= 3,
                  "Appending three arguments should be infallible");
    MOZ_ALWAYS_TRUE(args_.append(target));
    MOZ_ALWAYS_TRUE(args_.append(id));
    MOZ_ALWAYS_TRUE(args_.append(receiver));
  }

  void initForSetterCall(MDefinition* callee, MDefinition* thisVal,
                         MDefinition* rhs) {
    MOZ_ASSERT(args_.empty());
    markAsSetter();
    setCallee(callee);
    setThis(thisVal);
    static_assert(decltype(args_)::InlineLength >= 1,
                  "Appending one argument should be infallible");
    MOZ_ALWAYS_TRUE(args_.append(rhs));
  }

  void initForApplyInlinedArgs(MDefinition* callee, MDefinition* thisVal,
                               uint32_t numActuals) {
    MOZ_ASSERT(args_.empty());
    MOZ_ASSERT(!constructing_);

    setCallee(callee);
    setThis(thisVal);

    MOZ_ASSERT(numActuals <= ArgumentsObject::MaxInlinedArgs);
    static_assert(
        ArgumentsObject::MaxInlinedArgs <= decltype(args_)::InlineLength,
        "Actual arguments can be infallibly stored inline");
    MOZ_ALWAYS_TRUE(args_.reserve(numActuals));
  }

  [[nodiscard]] bool initForApplyArray(MDefinition* callee,
                                       MDefinition* thisVal,
                                       uint32_t numActuals) {
    MOZ_ASSERT(args_.empty());
    MOZ_ASSERT(!constructing_);

    setCallee(callee);
    setThis(thisVal);

    return args_.reserve(numActuals);
  }

  [[nodiscard]] bool initForConstructArray(MDefinition* callee,
                                           MDefinition* thisVal,
                                           MDefinition* newTarget,
                                           uint32_t numActuals) {
    MOZ_ASSERT(args_.empty());
    MOZ_ASSERT(constructing_);

    setCallee(callee);
    setThis(thisVal);
    setNewTarget(newTarget);

    return args_.reserve(numActuals);
  }

  void initForCloseIter(MDefinition* iter, MDefinition* callee) {
    MOZ_ASSERT(args_.empty());
    setCallee(callee);
    setThis(iter);
  }

  void popCallStack(MBasicBlock* current) { current->popn(numFormals()); }

  [[nodiscard]] bool pushCallStack(MBasicBlock* current) {
    current->push(callee());
    current->push(thisArg());

    for (uint32_t i = 0; i < argc(); i++) {
      current->push(getArg(i));
    }

    if (constructing()) {
      current->push(getNewTarget());
    }

    return true;
  }

  uint32_t argc() const { return args_.length(); }
  uint32_t numFormals() const { return argc() + 2 + constructing(); }

  [[nodiscard]] bool setArgs(const MDefinitionVector& args) {
    MOZ_ASSERT(args_.empty());
    return args_.appendAll(args);
  }

  MDefinitionVector& argv() { return args_; }

  const MDefinitionVector& argv() const { return args_; }

  MDefinition* getArg(uint32_t i) const {
    MOZ_ASSERT(i < argc());
    return args_[i];
  }

  void initArg(uint32_t i, MDefinition* def) {
    MOZ_ASSERT(i == argc());
    args_.infallibleAppend(def);
  }

  void setArg(uint32_t i, MDefinition* def) {
    MOZ_ASSERT(i < argc());
    args_[i] = def;
  }

  void removeArg(uint32_t i) { args_.erase(&args_[i]); }

  MDefinition* thisArg() const {
    MOZ_ASSERT(thisArg_);
    return thisArg_;
  }

  void setThis(MDefinition* thisArg) { thisArg_ = thisArg; }

  bool constructing() const { return constructing_; }

  bool ignoresReturnValue() const { return ignoresReturnValue_; }

  void setNewTarget(MDefinition* newTarget) {
    MOZ_ASSERT(constructing());
    newTargetArg_ = newTarget;
  }
  MDefinition* getNewTarget() const {
    MOZ_ASSERT(newTargetArg_);
    return newTargetArg_;
  }

  bool isSetter() const { return setter_; }
  void markAsSetter() { setter_ = true; }

  bool isInlined() const { return inlined_; }
  void markAsInlined() { inlined_ = true; }

  ResumeMode inliningResumeMode() const {
    MOZ_ASSERT(isInlined());
    return *inliningMode_;
  }

  void setInliningResumeMode(ResumeMode mode) {
    MOZ_ASSERT(isInlined());
    MOZ_ASSERT(inliningMode_.isNothing());
    inliningMode_.emplace(mode);
  }

  MDefinition* callee() const {
    MOZ_ASSERT(callee_);
    return callee_;
  }

  void setCallee(MDefinition* callee) { callee_ = callee; }

  template <typename Fun>
  void forEachCallOperand(Fun& f) {
    f(callee_);
    f(thisArg_);
    if (newTargetArg_) {
      f(newTargetArg_);
    }
    for (uint32_t i = 0; i < argc(); i++) {
      f(getArg(i));
    }
  }

  // Prepend `numArgs` arguments. Calls `f(i)` for each new argument.
  template <typename Fun>
  [[nodiscard]] bool prependArgs(size_t numArgs, const Fun& f) {
    size_t numArgsBefore = args_.length();
    if (!args_.growBy(numArgs)) {
      return false;
    }
    for (size_t i = numArgsBefore; i > 0; i--) {
      args_[numArgs + i - 1] = args_[i - 1];
    }
    for (size_t i = 0; i < numArgs; i++) {
      args_[i] = f(i);
    }
    return true;
  }

  void setImplicitlyUsedUnchecked() {
    auto setFlag = [](MDefinition* def) { def->setImplicitlyUsedUnchecked(); };
    forEachCallOperand(setFlag);
  }

  ArgFormat argFormat() const { return argFormat_; }
  void setArgFormat(ArgFormat argFormat) { argFormat_ = argFormat; }

  MDefinition* arrayArg() const {
    MOZ_ASSERT(argFormat_ == ArgFormat::Array);
    // The array argument for a spread call or FunApply is always the last
    // argument.
    return getArg(argc() - 1);
  }
};

template <typename Undef>
MCall* MakeCall(TempAllocator& alloc, Undef addUndefined, CallInfo& callInfo,
                bool needsThisCheck, WrappedFunction* target, bool isDOMCall,
                gc::Heap initialHeap = gc::Heap::Default) {
  MOZ_ASSERT(callInfo.argFormat() == CallInfo::ArgFormat::Standard);
  MOZ_ASSERT_IF(needsThisCheck, !target);
  MOZ_ASSERT_IF(isDOMCall, target->jitInfo()->type() == JSJitInfo::Method);

  mozilla::Maybe<DOMObjectKind> objKind;
  mozilla::Maybe<gc::Heap> heap;
  if (isDOMCall) {
    const Shape* shape = callInfo.thisArg()->toGuardShape()->shape();
    MOZ_ASSERT(shape->getObjectClass()->isDOMClass());
    if (shape->isNative()) {
      objKind.emplace(DOMObjectKind::Native);
    } else {
      MOZ_ASSERT(shape->isProxy());
      objKind.emplace(DOMObjectKind::Proxy);
    }

    heap.emplace(initialHeap);
  }

  uint32_t targetArgs = callInfo.argc();

  // Collect number of missing arguments provided that the target is
  // scripted. Native functions are passed an explicit 'argc' parameter.
  if (target && target->hasJitEntry()) {
    targetArgs = std::max<uint32_t>(target->nargs(), callInfo.argc());
  }

  MCall* call =
      MCall::New(alloc, target, targetArgs + 1 + callInfo.constructing(),
                 callInfo.argc(), callInfo.constructing(),
                 callInfo.ignoresReturnValue(), isDOMCall, objKind, heap);
  if (!call) {
    return nullptr;
  }

  if (callInfo.constructing()) {
    // Note: setThis should have been done by the caller of makeCall.
    if (needsThisCheck) {
      call->setNeedsThisCheck();
    }

    // Pass |new.target|
    call->addArg(targetArgs + 1, callInfo.getNewTarget());
  }

  // Explicitly pad any missing arguments with |undefined|.
  // This permits skipping the argumentsRectifier.
  MOZ_ASSERT_IF(target && targetArgs > callInfo.argc(), target->hasJitEntry());

  MConstant* undef = nullptr;
  for (uint32_t i = targetArgs; i > callInfo.argc(); i--) {
    if (!undef) {
      undef = addUndefined();
    }
    if (!alloc.ensureBallast()) {
      return nullptr;
    }
    call->addArg(i, undef);
  }

  // Add explicit arguments.
  // Skip addArg(0) because it is reserved for |this|.
  for (int32_t i = callInfo.argc() - 1; i >= 0; i--) {
    call->addArg(i + 1, callInfo.getArg(i));
  }

  if (isDOMCall) {
    // Now that we've told it about all the args, compute whether it's movable
    call->computeMovable();
  }

  // Pass |this| and callee.
  call->addArg(0, callInfo.thisArg());
  call->initCallee(callInfo.callee());

  if (target) {
    // The callee must be a JSFunction so we don't need a Class check.
    call->disableClassCheck();
  }

  return call;
}

// Base class for code sharing between WarpBuilder and WarpCacheIRTranspiler.
// Because this code is used by WarpCacheIRTranspiler we should
// generally assume that we only have access to the current basic block.
class WarpBuilderShared {
  WarpSnapshot& snapshot_;
  MIRGenerator& mirGen_;
  TempAllocator& alloc_;

 protected:
  MBasicBlock* current;

  WarpBuilderShared(WarpSnapshot& snapshot, MIRGenerator& mirGen,
                    MBasicBlock* current_);

  [[nodiscard]] bool resumeAfter(MInstruction* ins, BytecodeLocation loc);

  MConstant* constant(const JS::Value& v);
  void pushConstant(const JS::Value& v);

  // Note: unboxObjectInfallible defaults to adding a non-movable MUnbox to
  // ensure we don't hoist the infallible unbox before a branch checking the
  // value type.
  enum class IsMovable : bool { No, Yes };
  MDefinition* unboxObjectInfallible(MDefinition* def,
                                     IsMovable movable = IsMovable::No);

  MCall* makeCall(CallInfo& callInfo, bool needsThisCheck,
                  WrappedFunction* target = nullptr, bool isDOMCall = false,
                  gc::Heap initialHeap = gc::Heap::Default);
  MInstruction* makeSpreadCall(CallInfo& callInfo, bool needsThisCheck,
                               bool isSameRealm = false,
                               WrappedFunction* target = nullptr);

 public:
  MBasicBlock* currentBlock() const { return current; }
  WarpSnapshot& snapshot() const { return snapshot_; }
  MIRGenerator& mirGen() { return mirGen_; }
  TempAllocator& alloc() { return alloc_; }
};

}  // namespace jit
}  // namespace js

#endif

Messung V0.5
C=82 H=95 G=88

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