%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.cc

// Copyright 2022 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.

#include "src/maglev/maglev-assembler.h"

#include "src/maglev/maglev-assembler-inl.h"
#include "src/maglev/maglev-code-generator.h"

namespace v8 {
namespace internal {
namespace maglev {

#define __ masm->

void MaglevAssembler::AllocateHeapNumber(RegisterSnapshot register_snapshot,
                                         Register result,
                                         DoubleRegister value) {
  // In the case we need to call the runtime, we should spill the value
  // register. Even if it is not live in the next node, otherwise the
  // allocation call might trash it.
  register_snapshot.live_double_registers.set(value);
  Allocate(register_snapshot, result, HeapNumber::kSize);
  SetMapAsRoot(result, RootIndex::kHeapNumberMap);
  StoreFloat64(FieldMemOperand(result, HeapNumber::kValueOffset), value);
}

void MaglevAssembler::AllocateTwoByteString(RegisterSnapshot register_snapshot,
                                            Register result, int length) {
  int size = SeqTwoByteString::SizeFor(length);
  Allocate(register_snapshot, result, size);
  StoreTaggedSignedField(result, size - kObjectAlignment, Smi::zero());
  SetMapAsRoot(result, RootIndex::kSeqTwoByteStringMap);
  StoreInt32Field(result, Name::kRawHashFieldOffset, Name::kEmptyHashField);
  StoreInt32Field(result, String::kLengthOffset, length);
}

Register MaglevAssembler::FromAnyToRegister(const Input& input,
                                            Register scratch) {
  if (input.operand().IsConstant()) {
    input.node()->LoadToRegister(this, scratch);
    return scratch;
  }
  const compiler::AllocatedOperand& operand =
      compiler::AllocatedOperand::cast(input.operand());
  if (operand.IsRegister()) {
    return ToRegister(input);
  } else {
    DCHECK(operand.IsStackSlot());
    Move(scratch, ToMemOperand(input));
    return scratch;
  }
}

void MaglevAssembler::LoadSingleCharacterString(Register result,
                                                int char_code) {
  DCHECK_GE(char_code, 0);
  DCHECK_LT(char_code, String::kMaxOneByteCharCode);
  Register table = result;
  LoadRoot(table, RootIndex::kSingleCharacterStringTable);
  LoadTaggedField(result, table,
                  FixedArray::kHeaderSize + char_code * kTaggedSize);
}

void MaglevAssembler::LoadDataField(const PolymorphicAccessInfo& access_info,
                                    Register result, Register object,
                                    Register scratch) {
  Register load_source = object;
  // Resolve property holder.
  if (access_info.holder().has_value()) {
    load_source = scratch;
    Move(load_source, access_info.holder().value().object());
  }
  FieldIndex field_index = access_info.field_index();
  if (!field_index.is_inobject()) {
    Register load_source_object = load_source;
    if (load_source == object) {
      load_source = scratch;
    }
    // The field is in the property array, first load it from there.
    AssertNotSmi(load_source_object);
    LoadTaggedField(load_source, load_source_object,
                    JSReceiver::kPropertiesOrHashOffset);
  }
  AssertNotSmi(load_source);
  LoadTaggedField(result, load_source, field_index.offset());
}

void MaglevAssembler::JumpIfNotUndetectable(Register object, Register scratch,
                                            CheckType check_type, Label* target,
                                            Label::Distance distance) {
  if (check_type == CheckType::kCheckHeapObject) {
    JumpIfSmi(object, target, distance);
  } else if (v8_flags.debug_code) {
    AssertNotSmi(object);
  }
  // For heap objects, check the map's undetectable bit.
  LoadMap(scratch, object);
  LoadByte(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset));
  TestInt32AndJumpIfAllClear(scratch, Map::Bits1::IsUndetectableBit::kMask,
                             target, distance);
}

void MaglevAssembler::JumpIfUndetectable(Register object, Register scratch,
                                         CheckType check_type, Label* target,
                                         Label::Distance distance) {
  Label detectable;
  if (check_type == CheckType::kCheckHeapObject) {
    JumpIfSmi(object, &detectable, Label::kNear);
  } else if (v8_flags.debug_code) {
    AssertNotSmi(object);
  }
  // For heap objects, check the map's undetectable bit.
  LoadMap(scratch, object);
  LoadByte(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset));
  TestInt32AndJumpIfAnySet(scratch, Map::Bits1::IsUndetectableBit::kMask,
                           target, distance);
  bind(&detectable);
}

void MaglevAssembler::EnsureWritableFastElements(
    RegisterSnapshot register_snapshot, Register elements, Register object,
    Register scratch) {
  ZoneLabelRef done(this);
  CompareMapWithRoot(elements, RootIndex::kFixedArrayMap, scratch);
  JumpToDeferredIf(
      kNotEqual,
      [](MaglevAssembler* masm, ZoneLabelRef done, Register object,
         Register result_reg, RegisterSnapshot snapshot) {
        {
          snapshot.live_registers.clear(result_reg);
          snapshot.live_tagged_registers.clear(result_reg);
          SaveRegisterStateForCall save_register_state(masm, snapshot);
          __ CallBuiltin<Builtin::kCopyFastSmiOrObjectElements>(object);
          save_register_state.DefineSafepoint();
          __ Move(result_reg, kReturnRegister0);
        }
        __ Jump(*done);
      },
      done, object, elements, register_snapshot);
  bind(*done);
}

void MaglevAssembler::ToBoolean(Register value, CheckType check_type,
                                ZoneLabelRef is_true, ZoneLabelRef is_false,
                                bool fallthrough_when_true) {
  ScratchRegisterScope temps(this);
  Register map = temps.GetDefaultScratchRegister();

  if (check_type == CheckType::kCheckHeapObject) {
    // Check if {{value}} is Smi.
    Condition is_smi = CheckSmi(value);
    JumpToDeferredIf(
        is_smi,
        [](MaglevAssembler* masm, Register value, ZoneLabelRef is_true,
           ZoneLabelRef is_false) {
          // Check if {value} is not zero.
          __ CompareSmiAndJumpIf(value, Smi::FromInt(0), kEqual, *is_false);
          __ Jump(*is_true);
        },
        value, is_true, is_false);
  } else if (v8_flags.debug_code) {
    AssertNotSmi(value);
  }
  // Check if {{value}} is false.
  CompareRoot(value, RootIndex::kFalseValue);
  JumpIf(kEqual, *is_false);

  // Check if {{value}} is empty string.
  CompareRoot(value, RootIndex::kempty_string);
  JumpIf(kEqual, *is_false);

  // Check if {{value}} is undetectable.
  LoadMap(map, value);
  TestInt32AndJumpIfAnySet(FieldMemOperand(map, Map::kBitFieldOffset),
                           Map::Bits1::IsUndetectableBit::kMask, *is_false);

  // Check if {{value}} is a HeapNumber.
  CompareRoot(map, RootIndex::kHeapNumberMap);
  JumpToDeferredIf(
      kEqual,
      [](MaglevAssembler* masm, Register value, ZoneLabelRef is_true,
         ZoneLabelRef is_false) {
        __ CompareDoubleAndJumpIfZeroOrNaN(
            FieldMemOperand(value, HeapNumber::kValueOffset), *is_false);
        __ Jump(*is_true);
      },
      value, is_true, is_false);

  // Check if {{value}} is a BigInt.
  CompareRoot(map, RootIndex::kBigIntMap);
  // {{map}} is not needed from this point on.
  temps.Include(map);
  JumpToDeferredIf(
      kEqual,
      [](MaglevAssembler* masm, Register value, Register map,
         ZoneLabelRef is_true, ZoneLabelRef is_false) {
        __ TestInt32AndJumpIfAllClear(
            FieldMemOperand(value, BigInt::kBitfieldOffset),
            BigInt::LengthBits::kMask, *is_false);
        __ Jump(*is_true);
      },
      value, map, is_true, is_false);

  // Otherwise true.
  if (!fallthrough_when_true) {
    Jump(*is_true);
  }
}

void MaglevAssembler::MaterialiseValueNode(Register dst, ValueNode* value) {
  switch (value->opcode()) {
    case Opcode::kInt32Constant: {
      int32_t int_value = value->Cast<Int32Constant>()->value();
      if (Smi::IsValid(int_value)) {
        Move(dst, Smi::FromInt(int_value));
      } else {
        MoveHeapNumber(dst, int_value);
      }
      return;
    }
    case Opcode::kFloat64Constant: {
      double double_value =
          value->Cast<Float64Constant>()->value().get_scalar();
      MoveHeapNumber(dst, double_value);
      return;
    }
    default:
      break;
  }
  DCHECK(!value->allocation().IsConstant());
  DCHECK(value->allocation().IsAnyStackSlot());
  using D = NewHeapNumberDescriptor;
  DoubleRegister builtin_input_value = D::GetDoubleRegisterParameter(D::kValue);
  MemOperand src = ToMemOperand(value->allocation());
  switch (value->properties().value_representation()) {
    case ValueRepresentation::kInt32: {
      Label done;
      ScratchRegisterScope temps(this);
      Register scratch = temps.GetDefaultScratchRegister();
      Move(scratch, src);
      SmiTagInt32AndJumpIfSuccess(dst, scratch, &done, Label::kNear);
      // If smi tagging fails, instead of bailing out (deopting), we change
      // representation to a HeapNumber.
      Int32ToDouble(builtin_input_value, scratch);
      CallBuiltin<Builtin::kNewHeapNumber>(builtin_input_value);
      Move(dst, kReturnRegister0);
      bind(&done);
      break;
    }
    case ValueRepresentation::kUint32: {
      Label done;
      ScratchRegisterScope temps(this);
      Register scratch = temps.GetDefaultScratchRegister();
      Move(scratch, src);
      SmiTagUint32AndJumpIfSuccess(dst, scratch, &done, Label::kNear);
      // If smi tagging fails, instead of bailing out (deopting), we change
      // representation to a HeapNumber.
      Uint32ToDouble(builtin_input_value, scratch);
      CallBuiltin<Builtin::kNewHeapNumber>(builtin_input_value);
      Move(dst, kReturnRegister0);
      bind(&done);
      break;
    }
    case ValueRepresentation::kFloat64:
      LoadFloat64(builtin_input_value, src);
      CallBuiltin<Builtin::kNewHeapNumber>(builtin_input_value);
      Move(dst, kReturnRegister0);
      break;
    case ValueRepresentation::kHoleyFloat64: {
      Label done, box;
      JumpIfNotHoleNan(src, &box, Label::kNear);
      LoadRoot(dst, RootIndex::kUndefinedValue);
      Jump(&done);
      bind(&box);
      LoadFloat64(builtin_input_value, src);
      CallBuiltin<Builtin::kNewHeapNumber>(builtin_input_value);
      Move(dst, kReturnRegister0);
      bind(&done);
      break;
    }
    case ValueRepresentation::kWord64:
    case ValueRepresentation::kTagged:
      UNREACHABLE();
  }
}

void MaglevAssembler::TestTypeOf(
    Register object, interpreter::TestTypeOfFlags::LiteralFlag literal,
    Label* is_true, Label::Distance true_distance, bool fallthrough_when_true,
    Label* is_false, Label::Distance false_distance,
    bool fallthrough_when_false) {
  // If both true and false are fallthroughs, we don't have to do anything.
  if (fallthrough_when_true && fallthrough_when_false) return;

  MaglevAssembler::ScratchRegisterScope temps(this);
  Register scratch = temps.GetDefaultScratchRegister();

  // IMPORTANT: Note that `object` could be a register that aliases registers in
  // the ScratchRegisterScope. Make sure that all reads of `object` are before
  // any writes to scratch registers
  using LiteralFlag = interpreter::TestTypeOfFlags::LiteralFlag;
  switch (literal) {
    case LiteralFlag::kNumber: {
      JumpIfSmi(object, is_true, true_distance);
      CompareMapWithRoot(object, RootIndex::kHeapNumberMap, scratch);
      Branch(kEqual, is_true, true_distance, fallthrough_when_true, is_false,
             false_distance, fallthrough_when_false);
      return;
    }
    case LiteralFlag::kString: {
      JumpIfSmi(object, is_false, false_distance);
      CompareObjectTypeRange(object, scratch, FIRST_STRING_TYPE,
                             LAST_STRING_TYPE);
      Branch(kLessThanEqual, is_true, true_distance, fallthrough_when_true,
             is_false, false_distance, fallthrough_when_false);
      return;
    }
    case LiteralFlag::kSymbol: {
      JumpIfSmi(object, is_false, false_distance);
      CompareObjectTypeAndBranch(object, SYMBOL_TYPE, kEqual, is_true,
                                 true_distance, fallthrough_when_true, is_false,
                                 false_distance, fallthrough_when_false);
      return;
    }
    case LiteralFlag::kBoolean:
      JumpIfRoot(object, RootIndex::kTrueValue, is_true, true_distance);
      CompareRoot(object, RootIndex::kFalseValue);
      Branch(kEqual, is_true, true_distance, fallthrough_when_true, is_false,
             false_distance, fallthrough_when_false);
      return;
    case LiteralFlag::kBigInt: {
      JumpIfSmi(object, is_false, false_distance);
      CompareObjectTypeAndBranch(object, BIGINT_TYPE, kEqual, is_true,
                                 true_distance, fallthrough_when_true, is_false,
                                 false_distance, fallthrough_when_false);
      return;
    }
    case LiteralFlag::kUndefined: {
      // Make sure `object` isn't a valid temp here, since we re-use it.
      DCHECK(!temps.Available().has(object));
      JumpIfSmi(object, is_false, false_distance);
      // Check it has the undetectable bit set and it is not null.
      LoadMap(scratch, object);
      TestInt32AndJumpIfAllClear(FieldMemOperand(scratch, Map::kBitFieldOffset),
                                 Map::Bits1::IsUndetectableBit::kMask, is_false,
                                 false_distance);
      CompareRoot(object, RootIndex::kNullValue);
      Branch(kNotEqual, is_true, true_distance, fallthrough_when_true, is_false,
             false_distance, fallthrough_when_false);
      return;
    }
    case LiteralFlag::kFunction: {
      JumpIfSmi(object, is_false, false_distance);
      // Check if callable bit is set and not undetectable.
      LoadMap(scratch, object);
      Branch(IsCallableAndNotUndetectable(scratch, scratch), is_true,
             true_distance, fallthrough_when_true, is_false, false_distance,
             fallthrough_when_false);
      return;
    }
    case LiteralFlag::kObject: {
      JumpIfSmi(object, is_false, false_distance);
      // If the object is null then return true.
      JumpIfRoot(object, RootIndex::kNullValue, is_true, true_distance);
      // Check if the object is a receiver type,
      LoadMap(scratch, object);
      CompareInstanceType(scratch, FIRST_JS_RECEIVER_TYPE);
      JumpIf(kLessThan, is_false, false_distance);
      // ... and is not undefined (undetectable) nor callable.
      Branch(IsNotCallableNorUndetactable(scratch, scratch), is_true,
             true_distance, fallthrough_when_true, is_false, false_distance,
             fallthrough_when_false);
      return;
    }
    case LiteralFlag::kOther:
      if (!fallthrough_when_false) {
        Jump(is_false, false_distance);
      }
      return;
  }
  UNREACHABLE();
}

template <MaglevAssembler::StoreMode store_mode>
void MaglevAssembler::CheckAndEmitDeferredWriteBarrier(
    Register object, OffsetTypeFor<store_mode> offset, Register value,
    RegisterSnapshot register_snapshot, ValueIsCompressed value_is_compressed,
    ValueCanBeSmi value_can_be_smi) {
  ZoneLabelRef done(this);
  Label* deferred_write_barrier = MakeDeferredCode(
      [](MaglevAssembler* masm, ZoneLabelRef done, Register object,
         OffsetTypeFor<store_mode> offset, Register value,
         RegisterSnapshot register_snapshot, ValueIsCompressed value_type) {
        ASM_CODE_COMMENT_STRING(masm, "Write barrier slow path");
        if (PointerCompressionIsEnabled() && value_type == kValueIsCompressed) {
          __ DecompressTagged(value, value);
        }

        {
          // Use the value as the scratch register if possible, since
          // CheckPageFlag emits slightly better code when value == scratch.
          MaglevAssembler::ScratchRegisterScope temp(masm);
          Register scratch = temp.GetDefaultScratchRegister();
          if (value != object && !register_snapshot.live_registers.has(value)) {
            scratch = value;
          }
          __ CheckPageFlag(value, scratch,
                           MemoryChunk::kPointersToHereAreInterestingMask,
                           kEqual, *done);
        }

        Register stub_object_reg = WriteBarrierDescriptor::ObjectRegister();
        Register slot_reg = WriteBarrierDescriptor::SlotAddressRegister();

        RegList saved;
        if (object != stub_object_reg &&
            register_snapshot.live_registers.has(stub_object_reg)) {
          saved.set(stub_object_reg);
        }
        if (register_snapshot.live_registers.has(slot_reg)) {
          saved.set(slot_reg);
        }

        __ PushAll(saved);

        if (object != stub_object_reg) {
          __ Move(stub_object_reg, object);
          object = stub_object_reg;
        }

        if constexpr (store_mode == kElement) {
          __ SetSlotAddressForFixedArrayElement(slot_reg, object, offset);
        } else {
          static_assert(store_mode == kField);
          __ SetSlotAddressForTaggedField(slot_reg, object, offset);
        }

        SaveFPRegsMode const save_fp_mode =
            !register_snapshot.live_double_registers.is_empty()
                ? SaveFPRegsMode::kSave
                : SaveFPRegsMode::kIgnore;

        __ CallRecordWriteStub(object, slot_reg, save_fp_mode);

        __ PopAll(saved);
        __ Jump(*done);
      },
      done, object, offset, value, register_snapshot, value_is_compressed);

  if (value_can_be_smi) {
    JumpIfSmi(value, *done);
  } else {
    AssertNotSmi(value);
  }

  MaglevAssembler::ScratchRegisterScope temp(this);
  Register scratch = temp.GetDefaultScratchRegister();
  CheckPageFlag(object, scratch,
                MemoryChunk::kPointersFromHereAreInterestingMask, kNotEqual,
                deferred_write_barrier);
  bind(*done);
}

void MaglevAssembler::StoreTaggedFieldWithWriteBarrier(
    Register object, int offset, Register value,
    RegisterSnapshot register_snapshot, ValueIsCompressed value_is_compressed,
    ValueCanBeSmi value_can_be_smi) {
  AssertNotSmi(object);
  StoreTaggedFieldNoWriteBarrier(object, offset, value);
  CheckAndEmitDeferredWriteBarrier<kField>(
      object, offset, value, register_snapshot, value_is_compressed,
      value_can_be_smi);
}

void MaglevAssembler::StoreFixedArrayElementWithWriteBarrier(
    Register array, Register index, Register value,
    RegisterSnapshot register_snapshot) {
  if (v8_flags.debug_code) {
    CompareObjectTypeAndAssert(array, FIXED_ARRAY_TYPE, kEqual,
                               AbortReason::kUnexpectedValue);
    CompareInt32AndAssert(index, 0, kGreaterThanEqual,
                          AbortReason::kUnexpectedNegativeValue);
  }
  StoreFixedArrayElementNoWriteBarrier(array, index, value);
  CheckAndEmitDeferredWriteBarrier<kElement>(
      array, index, value, register_snapshot, kValueIsDecompressed,
      kValueCanBeSmi);
}

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

Zerion Mini Shell 1.0