%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/maglev/
Upload File :
Create Path :
Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/maglev/maglev-assembler-inl.h

// Copyright 2023 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_MAGLEV_MAGLEV_ASSEMBLER_INL_H_
#define V8_MAGLEV_MAGLEV_ASSEMBLER_INL_H_

#include <algorithm>
#include <type_traits>

#include "src/base/iterator.h"
#include "src/base/template-utils.h"
#include "src/codegen/machine-type.h"
#include "src/maglev/maglev-assembler.h"

#ifdef V8_TARGET_ARCH_ARM
#include "src/maglev/arm/maglev-assembler-arm-inl.h"
#elif V8_TARGET_ARCH_ARM64
#include "src/maglev/arm64/maglev-assembler-arm64-inl.h"
#elif V8_TARGET_ARCH_X64
#include "src/maglev/x64/maglev-assembler-x64-inl.h"
#else
#error "Maglev does not supported this architecture."
#endif

namespace v8 {
namespace internal {
namespace maglev {

namespace detail {

// Base case provides an error.
template <typename T, typename Enable = void>
struct CopyForDeferredHelper {
  template <typename U>
  struct No_Copy_Helper_Implemented_For_Type;
  static void Copy(MaglevCompilationInfo* compilation_info,
                   No_Copy_Helper_Implemented_For_Type<T>);
};

// Helper for copies by value.
template <typename T, typename Enable = void>
struct CopyForDeferredByValue {
  static T Copy(MaglevCompilationInfo* compilation_info, T node) {
    return node;
  }
};

// Node pointers are copied by value.
template <typename T>
struct CopyForDeferredHelper<
    T*, typename std::enable_if<std::is_base_of<NodeBase, T>::value>::type>
    : public CopyForDeferredByValue<T*> {};
// Arithmetic values and enums are copied by value.
template <typename T>
struct CopyForDeferredHelper<
    T, typename std::enable_if<std::is_arithmetic<T>::value>::type>
    : public CopyForDeferredByValue<T> {};
template <typename T>
struct CopyForDeferredHelper<
    T, typename std::enable_if<std::is_enum<T>::value>::type>
    : public CopyForDeferredByValue<T> {};
// MaglevCompilationInfos are copied by value.
template <>
struct CopyForDeferredHelper<MaglevCompilationInfo*>
    : public CopyForDeferredByValue<MaglevCompilationInfo*> {};
// Machine registers are copied by value.
template <>
struct CopyForDeferredHelper<Register>
    : public CopyForDeferredByValue<Register> {};
template <>
struct CopyForDeferredHelper<DoubleRegister>
    : public CopyForDeferredByValue<DoubleRegister> {};
// Bytecode offsets are copied by value.
template <>
struct CopyForDeferredHelper<BytecodeOffset>
    : public CopyForDeferredByValue<BytecodeOffset> {};
// EagerDeoptInfo pointers are copied by value.
template <>
struct CopyForDeferredHelper<EagerDeoptInfo*>
    : public CopyForDeferredByValue<EagerDeoptInfo*> {};
// LazyDeoptInfo pointers are copied by value.
template <>
struct CopyForDeferredHelper<LazyDeoptInfo*>
    : public CopyForDeferredByValue<LazyDeoptInfo*> {};
// ZoneLabelRef is copied by value.
template <>
struct CopyForDeferredHelper<ZoneLabelRef>
    : public CopyForDeferredByValue<ZoneLabelRef> {};
// MapCompare is copied by value.
template <>
struct CopyForDeferredHelper<MapCompare>
    : public CopyForDeferredByValue<MapCompare> {};
// RegList are copied by value.
template <>
struct CopyForDeferredHelper<RegList> : public CopyForDeferredByValue<RegList> {
};
// Register snapshots are copied by value.
template <>
struct CopyForDeferredHelper<RegisterSnapshot>
    : public CopyForDeferredByValue<RegisterSnapshot> {};
// Feedback slots are copied by value.
template <>
struct CopyForDeferredHelper<FeedbackSlot>
    : public CopyForDeferredByValue<FeedbackSlot> {};
// Heap Refs are copied by value.
template <typename T>
struct CopyForDeferredHelper<T, typename std::enable_if<std::is_base_of<
                                    compiler::ObjectRef, T>::value>::type>
    : public CopyForDeferredByValue<T> {};

template <typename T>
T CopyForDeferred(MaglevCompilationInfo* compilation_info, T&& value) {
  return CopyForDeferredHelper<T>::Copy(compilation_info,
                                        std::forward<T>(value));
}

template <typename T>
T CopyForDeferred(MaglevCompilationInfo* compilation_info, T& value) {
  return CopyForDeferredHelper<T>::Copy(compilation_info, value);
}

template <typename T>
T CopyForDeferred(MaglevCompilationInfo* compilation_info, const T& value) {
  return CopyForDeferredHelper<T>::Copy(compilation_info, value);
}

template <typename Function>
struct FunctionArgumentsTupleHelper
    : public FunctionArgumentsTupleHelper<decltype(&Function::operator())> {};

template <typename C, typename R, typename... A>
struct FunctionArgumentsTupleHelper<R (C::*)(A...) const> {
  using FunctionPointer = R (*)(A...);
  using Tuple = std::tuple<A...>;
  static constexpr size_t kSize = sizeof...(A);
};

template <typename R, typename... A>
struct FunctionArgumentsTupleHelper<R (&)(A...)> {
  using FunctionPointer = R (*)(A...);
  using Tuple = std::tuple<A...>;
  static constexpr size_t kSize = sizeof...(A);
};

template <typename T>
struct StripFirstTupleArg;

template <typename T1, typename... T>
struct StripFirstTupleArg<std::tuple<T1, T...>> {
  using Stripped = std::tuple<T...>;
};

template <typename Function>
class DeferredCodeInfoImpl final : public DeferredCodeInfo {
 public:
  using FunctionPointer =
      typename FunctionArgumentsTupleHelper<Function>::FunctionPointer;
  using Tuple = typename StripFirstTupleArg<
      typename FunctionArgumentsTupleHelper<Function>::Tuple>::Stripped;

  template <typename... InArgs>
  explicit DeferredCodeInfoImpl(MaglevCompilationInfo* compilation_info,
                                RegList general_temporaries,
                                DoubleRegList double_temporaries,
                                FunctionPointer function, InArgs&&... args)
      : function(function),
        args(CopyForDeferred(compilation_info, std::forward<InArgs>(args))...),
        general_temporaries_(general_temporaries),
        double_temporaries_(double_temporaries) {}

  DeferredCodeInfoImpl(DeferredCodeInfoImpl&&) = delete;
  DeferredCodeInfoImpl(const DeferredCodeInfoImpl&) = delete;

  void Generate(MaglevAssembler* masm) override {
    MaglevAssembler::ScratchRegisterScope scratch_scope(masm);
    scratch_scope.SetAvailable(general_temporaries_);
    scratch_scope.SetAvailableDouble(double_temporaries_);
#ifdef DEBUG
    masm->set_allow_call(allow_call_);
    masm->set_allow_deferred_call(allow_call_);
    masm->set_allow_allocate(allow_allocate_);
#endif  // DEBUG
    std::apply(function,
               std::tuple_cat(std::make_tuple(masm), std::move(args)));
#ifdef DEBUG
    masm->set_allow_call(false);
    masm->set_allow_deferred_call(false);
    masm->set_allow_allocate(false);
#endif  // DEBUG
  }

#ifdef DEBUG
  void set_allow_call(bool value) { allow_call_ = value; }
  void set_allow_allocate(bool value) { allow_allocate_ = value; }
#endif  // DEBUG

 private:
  FunctionPointer function;
  Tuple args;
  RegList general_temporaries_;
  DoubleRegList double_temporaries_;

#ifdef DEBUG
  bool allow_call_ = false;
  bool allow_allocate_ = false;
#endif  // DEBUG
};

}  // namespace detail

template <typename Function, typename... Args>
inline Label* MaglevAssembler::MakeDeferredCode(Function&& deferred_code_gen,
                                                Args&&... args) {
  using FunctionPointer =
      typename detail::FunctionArgumentsTupleHelper<Function>::FunctionPointer;
  static_assert(
      std::is_invocable_v<FunctionPointer, MaglevAssembler*,
                          decltype(detail::CopyForDeferred(
                              std::declval<MaglevCompilationInfo*>(),
                              std::declval<Args>()))...>,
      "Parameters of deferred_code_gen function should match arguments into "
      "MakeDeferredCode");

  ScratchRegisterScope scratch_scope(this);
  using DeferredCodeInfoT = detail::DeferredCodeInfoImpl<Function>;
  DeferredCodeInfoT* deferred_code =
      compilation_info()->zone()->New<DeferredCodeInfoT>(
          compilation_info(), scratch_scope.Available(),
          scratch_scope.AvailableDouble(), deferred_code_gen,
          std::forward<Args>(args)...);

#ifdef DEBUG
  deferred_code->set_allow_call(allow_deferred_call_);
  deferred_code->set_allow_allocate(allow_allocate_);
#endif  // DEBUG

  code_gen_state()->PushDeferredCode(deferred_code);
  return &deferred_code->deferred_code_label;
}

// Note this doesn't take capturing lambdas by design, since state may
// change until `deferred_code_gen` is actually executed. Use either a
// non-capturing lambda, or a plain function pointer.
template <typename Function, typename... Args>
inline void MaglevAssembler::JumpToDeferredIf(Condition cond,
                                              Function&& deferred_code_gen,
                                              Args&&... args) {
  if (v8_flags.code_comments) {
    RecordComment("-- Jump to deferred code");
  }
  JumpIf(cond, MakeDeferredCode<Function, Args...>(
                   std::forward<Function>(deferred_code_gen),
                   std::forward<Args>(args)...));
}

inline void MaglevAssembler::SmiToDouble(DoubleRegister result, Register smi) {
  AssertSmi(smi);
  SmiUntag(smi);
  Int32ToDouble(result, smi);
}

inline void MaglevAssembler::Branch(Condition condition, BasicBlock* if_true,
                                    BasicBlock* if_false,
                                    BasicBlock* next_block) {
  Branch(condition, if_true->label(), Label::kFar, if_true == next_block,
         if_false->label(), Label::kFar, if_false == next_block);
}

inline void MaglevAssembler::Branch(Condition condition, Label* if_true,
                                    Label::Distance true_distance,
                                    bool fallthrough_when_true, Label* if_false,
                                    Label::Distance false_distance,
                                    bool fallthrough_when_false) {
  if (fallthrough_when_false) {
    if (fallthrough_when_true) {
      // If both paths are a fallthrough, do nothing.
      DCHECK_EQ(if_true, if_false);
      return;
    }
    // Jump over the false block if true, otherwise fall through into it.
    JumpIf(condition, if_true, true_distance);
  } else {
    // Jump to the false block if true.
    JumpIf(NegateCondition(condition), if_false, false_distance);
    // Jump to the true block if it's not the next block.
    if (!fallthrough_when_true) {
      Jump(if_true, true_distance);
    }
  }
}

inline void MaglevAssembler::LoadTaggedField(Register result,
                                             MemOperand operand) {
  MacroAssembler::LoadTaggedField(result, operand);
}

inline void MaglevAssembler::LoadTaggedField(Register result, Register object,
                                             int offset) {
  MacroAssembler::LoadTaggedField(result, FieldMemOperand(object, offset));
}

inline void MaglevAssembler::LoadTaggedFieldWithoutDecompressing(
    Register result, Register object, int offset) {
  MacroAssembler::LoadTaggedFieldWithoutDecompressing(
      result, FieldMemOperand(object, offset));
}

inline void MaglevAssembler::LoadTaggedSignedField(Register result,
                                                   MemOperand operand) {
  MacroAssembler::LoadTaggedField(result, operand);
}

inline void MaglevAssembler::LoadTaggedSignedField(Register result,
                                                   Register object,
                                                   int offset) {
  MacroAssembler::LoadTaggedField(result, FieldMemOperand(object, offset));
}

inline void MaglevAssembler::LoadAndUntagTaggedSignedField(Register result,
                                                           Register object,
                                                           int offset) {
  MacroAssembler::SmiUntagField(result, FieldMemOperand(object, offset));
}

namespace detail {

#ifdef DEBUG
inline bool ClobberedBy(RegList written_registers, Register reg) {
  return written_registers.has(reg);
}
inline bool ClobberedBy(RegList written_registers, DoubleRegister reg) {
  return false;
}
inline bool ClobberedBy(RegList written_registers, Handle<Object> handle) {
  return false;
}
inline bool ClobberedBy(RegList written_registers, Tagged<Smi> smi) {
  return false;
}
inline bool ClobberedBy(RegList written_registers, Tagged<TaggedIndex> index) {
  return false;
}
inline bool ClobberedBy(RegList written_registers, int32_t imm) {
  return false;
}
inline bool ClobberedBy(RegList written_registers, RootIndex index) {
  return false;
}
inline bool ClobberedBy(RegList written_registers, const Input& input) {
  if (!input.IsGeneralRegister()) return false;
  return ClobberedBy(written_registers, input.AssignedGeneralRegister());
}

inline bool ClobberedBy(DoubleRegList written_registers, Register reg) {
  return false;
}
inline bool ClobberedBy(DoubleRegList written_registers, DoubleRegister reg) {
  return written_registers.has(reg);
}
inline bool ClobberedBy(DoubleRegList written_registers,
                        Handle<Object> handle) {
  return false;
}
inline bool ClobberedBy(DoubleRegList written_registers, Tagged<Smi> smi) {
  return false;
}
inline bool ClobberedBy(DoubleRegList written_registers,
                        Tagged<TaggedIndex> index) {
  return false;
}
inline bool ClobberedBy(DoubleRegList written_registers, int32_t imm) {
  return false;
}
inline bool ClobberedBy(DoubleRegList written_registers, RootIndex index) {
  return false;
}
inline bool ClobberedBy(DoubleRegList written_registers, const Input& input) {
  if (!input.IsDoubleRegister()) return false;
  return ClobberedBy(written_registers, input.AssignedDoubleRegister());
}

// We don't know what's inside machine registers or operands, so assume they
// match.
inline bool MachineTypeMatches(MachineType type, Register reg) {
  return !IsFloatingPoint(type.representation());
}
inline bool MachineTypeMatches(MachineType type, DoubleRegister reg) {
  return IsFloatingPoint(type.representation());
}
inline bool MachineTypeMatches(MachineType type, MemOperand reg) {
  return true;
}
inline bool MachineTypeMatches(MachineType type, Handle<HeapObject> handle) {
  return type.IsTagged() && !type.IsTaggedSigned();
}
inline bool MachineTypeMatches(MachineType type, Tagged<Smi> smi) {
  return type.IsTagged() && !type.IsTaggedPointer();
}
inline bool MachineTypeMatches(MachineType type, Tagged<TaggedIndex> index) {
  // TaggedIndex doesn't have a separate type, so check for the same type as for
  // Smis.
  return type.IsTagged() && !type.IsTaggedPointer();
}
inline bool MachineTypeMatches(MachineType type, int32_t imm) {
  // 32-bit immediates can be used for 64-bit params -- they'll be
  // zero-extended.
  return type.representation() == MachineRepresentation::kWord32 ||
         type.representation() == MachineRepresentation::kWord64;
}
inline bool MachineTypeMatches(MachineType type, RootIndex index) {
  return type.IsTagged() && !type.IsTaggedSigned();
}
inline bool MachineTypeMatches(MachineType type, const Input& input) {
  if (type.representation() == input.node()->GetMachineRepresentation()) {
    return true;
  }
  if (type.IsTagged()) {
    return input.node()->is_tagged();
  }
  return false;
}

template <typename Descriptor, typename Arg>
void CheckArg(MaglevAssembler* masm, Arg& arg, int& i) {
  if (i >= Descriptor::GetParameterCount()) {
    CHECK(Descriptor::AllowVarArgs());
  }
  CHECK(MachineTypeMatches(Descriptor::GetParameterType(i), arg));
  ++i;
}

template <typename Descriptor, typename Iterator>
void CheckArg(MaglevAssembler* masm,
              const base::iterator_range<Iterator>& range, int& i) {
  for (auto it = range.begin(), end = range.end(); it != end; ++it, ++i) {
    if (i >= Descriptor::GetParameterCount()) {
      CHECK(Descriptor::AllowVarArgs());
    }
    CHECK(MachineTypeMatches(Descriptor::GetParameterType(i), *it));
  }
}

template <typename Descriptor, typename... Args>
void CheckArgs(MaglevAssembler* masm, const std::tuple<Args...>& args) {
  int i = 0;
  base::tuple_for_each(args,
                       [&](auto&& arg) { CheckArg<Descriptor>(masm, arg, i); });
  if (Descriptor::AllowVarArgs()) {
    CHECK_GE(i, Descriptor::GetParameterCount());
  } else {
    CHECK_EQ(i, Descriptor::GetParameterCount());
  }
}

#else  // DEBUG

template <typename Descriptor, typename... Args>
void CheckArgs(Args&&... args) {}

#endif  // DEBUG

template <typename Descriptor, typename... Args>
void PushArgumentsForBuiltin(MaglevAssembler* masm, std::tuple<Args...> args) {
  std::apply(
      [&](auto&&... stack_args) {
        if (Descriptor::kStackArgumentOrder == StackArgumentOrder::kDefault) {
          masm->Push(std::forward<decltype(stack_args)>(stack_args)...);
        } else {
          masm->PushReverse(std::forward<decltype(stack_args)>(stack_args)...);
        }
      },
      args);
}

template <typename Descriptor>
void PushArgumentsForBuiltin(MaglevAssembler* masm, std::tuple<> empty_args) {}

template <Builtin kBuiltin, typename... Args>
void MoveArgumentsForBuiltin(MaglevAssembler* masm, Args&&... args) {
  using Descriptor = typename CallInterfaceDescriptorFor<kBuiltin>::type;

  // Put the args into a tuple for easier manipulation.
  std::tuple<Args&&...> args_tuple{std::forward<Args>(args)...};

  // If there is a context, the first argument is the context parameter. Use
  // the remaining args as the actual arguments. We pass the context first
  // instead of last to avoid ambiguity around dealing with on-stack
  // arguments.
  constexpr size_t context_args = Descriptor::HasContextParameter() ? 1 : 0;
  static_assert(context_args <= std::tuple_size_v<decltype(args_tuple)>,
                "Not enough arguments passed in to builtin (are you missing a "
                "context argument?)");
  auto args_tuple_without_context = base::tuple_drop<context_args>(args_tuple);
  CheckArgs<Descriptor>(masm, args_tuple_without_context);

  // Split args into register and stack args.
  static_assert(Descriptor::GetRegisterParameterCount() <=
                    std::tuple_size_v<decltype(args_tuple_without_context)>,
                "Not enough arguments passed in to builtin (are you missing a "
                "context argument?)");
  auto register_args =
      base::tuple_head<Descriptor::GetRegisterParameterCount()>(
          args_tuple_without_context);
  auto stack_args = base::tuple_drop<Descriptor::GetRegisterParameterCount()>(
      args_tuple_without_context);

  // Split stack args into fixed and variable.
  static_assert(
      Descriptor::GetStackParameterCount() <=
          std::tuple_size_v<decltype(stack_args)>,
      "Not enough stack arguments passed in to builtin (are you missing a "
      "context argument?)");
  auto fixed_stack_args =
      base::tuple_head<Descriptor::GetStackParameterCount()>(stack_args);
  auto vararg_stack_args =
      base::tuple_drop<Descriptor::GetStackParameterCount()>(stack_args);

  if constexpr (!Descriptor::AllowVarArgs()) {
    static_assert(std::tuple_size_v<decltype(vararg_stack_args)> == 0,
                  "Too many arguments passed in to builtin that expects no "
                  "vararg stack arguments");
  }

  // First push stack arguments (if any), since some of these may be in
  // registers and we don't want to clobber them. This supports any thing
  // `masm->Push` supports, including iterator ranges, so the tuple size may be
  // smaller than the number of arguments actually pushed. We push fixed and
  // vararg stack arguments separately, so that there's an appropriate amount
  // of padding between them.
  if (Descriptor::kStackArgumentOrder == StackArgumentOrder::kDefault) {
    PushArgumentsForBuiltin<Descriptor>(
        masm, std::forward<decltype(fixed_stack_args)>(fixed_stack_args));
    PushArgumentsForBuiltin<Descriptor>(
        masm, std::forward<decltype(vararg_stack_args)>(vararg_stack_args));
  } else {
    PushArgumentsForBuiltin<Descriptor>(
        masm, std::forward<decltype(vararg_stack_args)>(vararg_stack_args));
    PushArgumentsForBuiltin<Descriptor>(
        masm, std::forward<decltype(fixed_stack_args)>(fixed_stack_args));
  }

// Then, set register arguments.
// TODO(leszeks): Use the parallel move helper to do register moves, instead
// of detecting clobbering.
#ifdef DEBUG
  RegList written_registers = {};
  DoubleRegList written_double_registers = {};
#endif  // DEBUG

  base::tuple_for_each_with_index(register_args, [&](auto&& arg, auto index) {
    using Arg = decltype(arg);
    static_assert(index < Descriptor::GetRegisterParameterCount());

    // Make sure the argument wasn't clobbered by any previous write.
    DCHECK(!ClobberedBy(written_registers, arg));
    DCHECK(!ClobberedBy(written_double_registers, arg));

    static constexpr bool use_double_register =
        IsFloatingPoint(Descriptor::GetParameterType(index).representation());
    if constexpr (use_double_register) {
      DoubleRegister target = Descriptor::GetDoubleRegisterParameter(index);
      if constexpr (std::is_same_v<Input, std::decay_t<Arg>>) {
        DCHECK_EQ(target, arg.AssignedDoubleRegister());
        USE(target);
      } else {
        masm->Move(target, std::forward<Arg>(arg));
      }
#ifdef DEBUG
      written_double_registers.set(target);
#endif  // DEBUG
    } else {
      Register target = Descriptor::GetRegisterParameter(index);
      if constexpr (std::is_same_v<Input, std::decay_t<Arg>>) {
        DCHECK_EQ(target, arg.AssignedGeneralRegister());
        USE(target);
      } else {
        masm->Move(target, std::forward<Arg>(arg));
      }
#ifdef DEBUG
      written_registers.set(target);
#endif  // DEBUG
    }

    // TODO(leszeks): Support iterator range for register args.
  });

  // Set the context last (to avoid clobbering).
  if constexpr (Descriptor::HasContextParameter()) {
    auto&& context = std::get<0>(args_tuple);
    DCHECK(!ClobberedBy(written_registers, context));
    DCHECK(!ClobberedBy(written_double_registers, context));
    DCHECK(MachineTypeMatches(MachineType::AnyTagged(), context));

    if constexpr (std::is_same_v<Input, std::decay_t<decltype(context)>>) {
      DCHECK_EQ(Descriptor::ContextRegister(),
                context.AssignedGeneralRegister());
    } else {
      // Don't allow raw Register here, force materialisation from a constant.
      // This is because setting parameters could have clobbered the register.
      // TODO(leszeks): Include the context register in the parallel moves
      // described above.
      static_assert(!std::is_same_v<Register, std::decay_t<decltype(context)>>);
      masm->Move(Descriptor::ContextRegister(), context);
    }
  }
}

}  // namespace detail

inline void MaglevAssembler::CallBuiltin(Builtin builtin) {
  // Special case allowing calls to DoubleToI, which takes care to preserve all
  // registers and therefore doesn't require special spill handling.
  DCHECK(allow_call() || builtin == Builtin::kDoubleToI);

  // Temporaries have to be reset before calling CallBuiltin, in case it uses
  // temporaries that alias register parameters.
  ScratchRegisterScope reset_temps(this);
  reset_temps.ResetToDefault();

  // Make sure that none of the register parameters alias the default
  // temporaries.
#ifdef DEBUG
  CallInterfaceDescriptor descriptor =
      Builtins::CallInterfaceDescriptorFor(builtin);
  for (int i = 0; i < descriptor.GetRegisterParameterCount(); ++i) {
    DCHECK(!reset_temps.Available().has(descriptor.GetRegisterParameter(i)));
  }
#endif

  MacroAssembler::CallBuiltin(builtin);
}

template <Builtin kBuiltin, typename... Args>
inline void MaglevAssembler::CallBuiltin(Args&&... args) {
  ASM_CODE_COMMENT(this);
  detail::MoveArgumentsForBuiltin<kBuiltin>(this, std::forward<Args>(args)...);
  CallBuiltin(kBuiltin);
}

inline void MaglevAssembler::CallRuntime(Runtime::FunctionId fid) {
  DCHECK(allow_call());
  // Temporaries have to be reset before calling CallRuntime, in case it uses
  // temporaries that alias register parameters.
  ScratchRegisterScope reset_temps(this);
  reset_temps.ResetToDefault();
  MacroAssembler::CallRuntime(fid);
}

inline void MaglevAssembler::CallRuntime(Runtime::FunctionId fid,
                                         int num_args) {
  DCHECK(allow_call());
  // Temporaries have to be reset before calling CallRuntime, in case it uses
  // temporaries that alias register parameters.
  ScratchRegisterScope reset_temps(this);
  reset_temps.ResetToDefault();
  MacroAssembler::CallRuntime(fid, num_args);
}

inline void MaglevAssembler::SetMapAsRoot(Register object, RootIndex map) {
  ScratchRegisterScope temps(this);
  Register scratch = temps.GetDefaultScratchRegister();
  LoadTaggedRoot(scratch, map);
  StoreTaggedFieldNoWriteBarrier(object, HeapObject::kMapOffset, scratch);
}

inline void MaglevAssembler::SmiTagInt32AndJumpIfFail(
    Register dst, Register src, Label* fail, Label::Distance distance) {
  SmiTagInt32AndSetFlags(dst, src);
  if (!SmiValuesAre32Bits()) {
    JumpIf(kOverflow, fail, distance);
  }
}

inline void MaglevAssembler::SmiTagInt32AndJumpIfFail(
    Register reg, Label* fail, Label::Distance distance) {
  SmiTagInt32AndJumpIfFail(reg, reg, fail, distance);
}

inline void MaglevAssembler::SmiTagInt32AndJumpIfSuccess(
    Register dst, Register src, Label* success, Label::Distance distance) {
  SmiTagInt32AndSetFlags(dst, src);
  if (!SmiValuesAre32Bits()) {
    JumpIf(kNoOverflow, success, distance);
  } else {
    jmp(success);
  }
}

inline void MaglevAssembler::SmiTagInt32AndJumpIfSuccess(
    Register reg, Label* success, Label::Distance distance) {
  SmiTagInt32AndJumpIfSuccess(reg, reg, success, distance);
}

inline void MaglevAssembler::UncheckedSmiTagInt32(Register dst, Register src) {
  SmiTagInt32AndSetFlags(dst, src);
  Assert(kNoOverflow, AbortReason::kInputDoesNotFitSmi);
}

inline void MaglevAssembler::UncheckedSmiTagInt32(Register reg) {
  UncheckedSmiTagInt32(reg, reg);
}

inline void MaglevAssembler::SmiTagUint32AndJumpIfFail(
    Register dst, Register src, Label* fail, Label::Distance distance) {
  // Perform an unsigned comparison against Smi::kMaxValue.
  CompareInt32AndJumpIf(src, Smi::kMaxValue, kUnsignedGreaterThan, fail,
                        distance);
  SmiTagInt32AndSetFlags(dst, src);
  Assert(kNoOverflow, AbortReason::kInputDoesNotFitSmi);
}

inline void MaglevAssembler::SmiTagUint32AndJumpIfFail(
    Register reg, Label* fail, Label::Distance distance) {
  SmiTagUint32AndJumpIfFail(reg, reg, fail, distance);
}

inline void MaglevAssembler::SmiTagUint32AndJumpIfSuccess(
    Register dst, Register src, Label* success, Label::Distance distance) {
  Label fail;
  SmiTagUint32AndJumpIfFail(dst, src, &fail, Label::Distance::kNear);
  Jump(success, distance);
  bind(&fail);
}

inline void MaglevAssembler::SmiTagUint32AndJumpIfSuccess(
    Register reg, Label* success, Label::Distance distance) {
  SmiTagUint32AndJumpIfSuccess(reg, reg, success, distance);
}

inline void MaglevAssembler::UncheckedSmiTagUint32(Register dst, Register src) {
  if (v8_flags.debug_code) {
    // Perform an unsigned comparison against Smi::kMaxValue.
    CompareInt32AndAssert(src, Smi::kMaxValue, kUnsignedLessThanEqual,
                          AbortReason::kInputDoesNotFitSmi);
  }
  SmiTagInt32AndSetFlags(dst, src);
  Assert(kNoOverflow, AbortReason::kInputDoesNotFitSmi);
}

inline void MaglevAssembler::UncheckedSmiTagUint32(Register reg) {
  UncheckedSmiTagUint32(reg, reg);
}

inline void MaglevAssembler::SmiAddConstant(Register reg, int value,
                                            Label* fail,
                                            Label::Distance distance) {
  return SmiAddConstant(reg, reg, value, fail, distance);
}

inline void MaglevAssembler::SmiSubConstant(Register reg, int value,
                                            Label* fail,
                                            Label::Distance distance) {
  return SmiSubConstant(reg, reg, value, fail, distance);
}

inline void MaglevAssembler::StringLength(Register result, Register string) {
  if (v8_flags.debug_code) {
    // Check if {string} is a string.
    ScratchRegisterScope temps(this);
    Register scratch = temps.GetDefaultScratchRegister();
    AssertNotSmi(string);
    LoadMap(scratch, string);
    CompareInstanceTypeRange(scratch, scratch, FIRST_STRING_TYPE,
                             LAST_STRING_TYPE);
    Check(kUnsignedLessThanEqual, AbortReason::kUnexpectedValue);
  }
  LoadSignedField(result, FieldMemOperand(string, String::kLengthOffset),
                  sizeof(int32_t));
}

}  // namespace maglev
}  // namespace internal
}  // namespace v8

#endif  // V8_MAGLEV_MAGLEV_ASSEMBLER_INL_H_

Zerion Mini Shell 1.0