text: /*
   * Copyright (c) [2019] Huawei Technologies Co.,Ltd.All rights reverved.
   *
   * OpenArkCompiler is licensed under the Mulan PSL v1. 
   * You can use this software according to the terms and conditions of the Mulan PSL v1.
   * You may obtain a copy of Mulan PSL v1 at:
   *
   * 	http://license.coscl.org.cn/MulanPSL 
   *
   * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 
   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR
   * FIT FOR A PARTICULAR PURPOSE.  
   * See the Mulan PSL v1 for more details.  
   */
  #ifndef MAPLE_IR_INCLUDE_MIR_SYMBOL_H
  #define MAPLE_IR_INCLUDE_MIR_SYMBOL_H
  #include <sstream>
  #include "mir_const.h"
  #include "mir_preg.h"
  
  constexpr int kScopeLocal = 2;   // the default scope level for function variables
  constexpr int kScopeGlobal = 1;  // the scope level for global variables
  
  namespace maple {
  enum MIRSymKind {
    kStInvalid,
    kStVar,
    kStFunc,
    kStConst,
    kStJavaClass,
    kStJavaInterface,
    kStPreg,
  };
  
  enum MIRStorageClass : std::uint8_t {
    kScInvalid,
    kScAuto,
    kScAliased,
    kScFormal,
    kScExtern,
    kScGlobal,
    kScPstatic,  // PU-static
    kScFstatic,  // file-static
    kScText,
    kScTypeInfo,      // used for eh type st
    kScTypeInfoName,  // used for eh type st name
    kScTypeCxxAbi,    // used for eh inherited from c++ __cxxabiv1
    kScUnused
  };
  
  // to represent a single symbol
  class MIRSymbol {
   public:
    union SymbolType {  // a symbol can either be a const or a function or a preg which currently used for formal
      MIRConst *konst;
      MIRFunction *mirFunc;
      MIRPreg *preg;  // the MIRSymKind must be kStPreg
    };
  
    // Please keep order of the fields, avoid paddings.
   private:
    TyIdx tyIdx;
    TyIdx inferredTyIdx;
    MIRStorageClass storageClass;
    MIRSymKind sKind;
    bool isTmp;
    bool needForwDecl;  // addrof of this symbol used in initialization, NOT serialized
    bool isDeleted;     // tell if it is deleted, NOT serialized
    bool instrumented;  // a local ref pointer instrumented by RC opt, NOT serialized
    bool isImported;
    StIdx stIdx;
    TypeAttrs typeAttrs;
    GStrIdx nameStrIdx;
    SymbolType value;
    static GStrIdx reflectClassNameIdx;
    static GStrIdx reflectMethodNameIdx;
    static GStrIdx reflectFieldNameIdx;
  
   public:
    MIRSymbol()
        : tyIdx(0),
          inferredTyIdx(kInitTyIdx),
          storageClass(kScInvalid),
          sKind(kStInvalid),
          isTmp(false),
          needForwDecl(false),
          isDeleted(false),
          instrumented(false),
          isImported(false),
          stIdx(0, 0),
          nameStrIdx(0),
          value({ nullptr }) {
    }
    MIRSymbol(uint32 idx, uint8 scp)
        : tyIdx(0),
          inferredTyIdx(kInitTyIdx),
          storageClass(kScInvalid),
          sKind(kStInvalid),
          isTmp(false),
          needForwDecl(false),
          isDeleted(false),
          instrumented(false),
          isImported(false),
          stIdx(scp, idx),
          nameStrIdx(0),
          value({ nullptr }) {
    }
    ~MIRSymbol() {}
  
    void SetIsTmp(bool temp) {
      isTmp = temp;
    }
  
    bool GetIsTmp() const {
      return isTmp;
    }
  
    void SetNeedForwDecl() {
      needForwDecl = true;
    }
  
    bool IsNeedForwDecl() const {
      return needForwDecl;
    }
  
    void SetInstrumented() {
      instrumented = true;
    }
  
    bool IsInstrumented() const {
      return instrumented;
    }
  
    void SetIsImported(bool imported) {
      isImported = imported;
    }
  
    bool GetIsImported() {
      return isImported;
    }
  
    void SetTyIdx(TyIdx tyIdx) {
      this->tyIdx = tyIdx;
    }
  
    const TyIdx GetTyIdx() const {
      return tyIdx;
    }
  
    void SetInferredTyIdx(TyIdx i) {
      inferredTyIdx = i;
    }
  
    const TyIdx &GetInferredTyIdx() const {
      return inferredTyIdx;
    }
  
    void SetStIdx(StIdx stIdx) {
      this->stIdx = stIdx;
    }
  
    const StIdx &GetStIdx() const {
      return stIdx;
    }
  
    void SetSKind(MIRSymKind m) {
      sKind = m;
    }
  
    MIRSymKind GetSKind() const {
      return sKind;
    }
  
    uint32 GetScopeIdx() const {
      return stIdx.Scope();
    }
  
    uint32 GetStIndex() const {
      return stIdx.Idx();
    }
  
    bool IsLocal() const {
      return stIdx.Islocal();
    }
  
    bool IsGlobal() const {
      return stIdx.IsGlobal();
    }
  
    const TypeAttrs &GetAttrs() const {
      return typeAttrs;
    }
  
    TypeAttrs &GetAttrs() {
      return typeAttrs;
    }
  
    void SetAttrs(TypeAttrs attr) {
      typeAttrs = attr;
    }
  
    // AddAttrs adds more attributes instead of overrides the current one
    void AddAttrs(TypeAttrs attr) {
      typeAttrs.SetAttrFlag(typeAttrs.GetAttrFlag() | attr.GetAttrFlag());
    }
  
    bool GetAttr(AttrKind x) const {
      return typeAttrs.GetAttr(x);
    }
  
    void SetAttr(AttrKind x) {
      typeAttrs.SetAttr(x);
    }
  
    void ResetAttr(AttrKind x) {
      typeAttrs.ResetAttr(x);
    }
  
    bool IsVolatile() const {
      return typeAttrs.GetAttr(ATTR_volatile);
    }
  
    bool IsStatic() const {
      return typeAttrs.GetAttr(ATTR_static);
    }
  
    bool IsFinal() const {
      return (typeAttrs.GetAttr(ATTR_final) || typeAttrs.GetAttr(ATTR_readonly)) || IsLiteral() || IsLiteralPtr();
    }
  
    bool IsWeak() const {
      return typeAttrs.GetAttr(ATTR_weak);
    }
  
    bool IsPrivate() const {
      return typeAttrs.GetAttr(ATTR_private);
    }
  
    bool IsRefType() const {
      return typeAttrs.GetAttr(ATTR_localrefvar);
    }
  
    void SetNameStrIdx(const GStrIdx &stridx) {
      nameStrIdx = stridx;
    }
  
    void SetNameStrIdx(const std::string &name);
  
    GStrIdx GetNameStrIdx() const {
      return nameStrIdx;
    }
  
    MIRStorageClass GetStorageClass() const {
      return storageClass;
    }
  
    void SetStorageClass(MIRStorageClass cl) {
      storageClass = cl;
    }
  
    bool IsReadOnly() const {
      return (kScFstatic == storageClass && kStConst == sKind);
    }
  
    bool IsConst() const {
      return sKind == kStConst || (sKind == kStVar && value.konst != nullptr);
    }
  
    MIRType *GetType() const;
  
    const std::string &GetName() const;
  
    MIRConst *GetKonst() const {
      ASSERT((sKind == kStConst || sKind == kStVar), "must be const symbol");
      return value.konst;
    }
  
    void SetKonst(MIRConst *mirconst) {
      ASSERT((sKind == kStConst || sKind == kStVar), "must be const symbol");
      value.konst = mirconst;
    }
  
    void SetIsDeleted() {
      isDeleted = true;
    }
  
    void ResetIsDeleted() {
      isDeleted = false;
    }
  
    bool IsDeleted() const {
      return isDeleted;
    }
  
    bool IsPreg() const {
      return sKind == kStPreg;
    }
  
    bool IsJavaClassInterface() const {
      return sKind == kStJavaClass || sKind == kStJavaInterface;
    }
  
    SymbolType GetValue() const {
      return value;
    }
  
    void SetValue(SymbolType value) {
      this->value = value;
    }
  
    MIRPreg *GetPreg() {
      ASSERT(IsPreg(), "must be Preg");
      return value.preg;
    }
  
    const MIRPreg *GetPreg() const {
      CHECK_FATAL(IsPreg(), "must be Preg");
      return value.preg;
    }
  
    void SetPreg(MIRPreg *preg) {
      CHECK_FATAL(IsPreg(), "must be Preg");
      value.preg = preg;
    }
  
    void SetLocalRefVar() {
      SetAttr(ATTR_localrefvar);
    }
  
    void ResetLocalRefVar() {
      ResetAttr(ATTR_localrefvar);
    }
  
    MIRFunction *GetFunction() const {
      ASSERT(sKind == kStFunc, "must be function symbol");
      return value.mirFunc;
    }
  
    void SetFunction(MIRFunction *func) {
      ASSERT(sKind == kStFunc, "must be function symbol");
      value.mirFunc = func;
    }
  
    bool IsEhIndex() const {
      return GetName().compare("__eh_index__") == 0;
    }
  
    bool HasAddrOfValues();
    bool IsLiteral() const;
    bool IsLiteralPtr() const;
    bool PointsToConstString() const;
    bool IsConstString() const;
    bool IsClassInitBridge();
    bool IsReflectionStrTab() const;
    bool IsReflectionHashTabBucket() const;
    bool IsReflectionInfo();
    bool IsReflectionFieldsInfo() const;
    bool IsReflectionFieldsInfoCompact() const;
    bool IsReflectionSuperclassInfo();
    bool IsReflectionClassInfo();
    bool IsReflectionArrayClassInfo() const;
    bool IsReflectionClassInfoPtr() const;
    bool IsReflectionClassInfoRO();
    bool IsITabConflictInfo();
    bool IsVTabInfo();
    bool IsITabInfo();
    bool IsReflectionPrimitiveClassInfo();
    bool IsReflectionMethodsInfo() const;
    bool IsReflectionMethodsInfoCompact() const;
    bool IsRegJNITab() const;
    bool IsRegJNIFuncTab() const;
    bool IsMuidTab() const;
    bool IsCodeLayoutInfo() const;
    std::string GetMuidTabName();
    bool IsMuidFuncDefTab() const;
    bool IsMuidFuncDefOrigTab() const;
    bool IsMuidFuncInfTab() const;
    bool IsMuidFuncUndefTab() const;
    bool IsMuidDataDefTab() const;
    bool IsMuidDataDefOrigTab() const;
    bool IsMuidDataUndefTab() const;
    bool IsMuidFuncDefMuidTab() const;
    bool IsMuidFuncUndefMuidTab() const;
    bool IsMuidDataDefMuidTab() const;
    bool IsMuidDataUndefMuidTab() const;
    bool IsMuidRangeTab() const;
    bool IsGctibSym();
    bool IsPrimordialObject();
    bool IgnoreRC();
    void Dump(bool isLocal, int32 indent, bool suppressinit = false) const;
    void DumpAsLiteralVar(int32 indent);
    bool operator==(const MIRSymbol &msym) const {
      return nameStrIdx == msym.nameStrIdx;
    }
  
    bool operator!=(const MIRSymbol &msym) const {
      return nameStrIdx != msym.nameStrIdx;
    }
  
    bool operator<(const MIRSymbol &msym) const {
      return nameStrIdx < msym.nameStrIdx;
    }
  };
  
  class MIRSymbolTable {
   public:
    explicit MIRSymbolTable(MapleAllocator *allocator)
        : mAllocator(allocator), strIdxToStIdxMap(mAllocator->Adapter()), symbolTable(mAllocator->Adapter()) {
      symbolTable.push_back(static_cast<MIRSymbol*>(nullptr));
    }
  
    ~MIRSymbolTable() {}
  
    bool IsValidIdx(uint32 idx) const {
      return idx < symbolTable.size();
    }
  
    MIRSymbol *GetSymbolFromStIdx(uint32 idx, bool checkFirst = false) const {
      if (checkFirst && idx >= symbolTable.size()) {
        return nullptr;
      }
      CHECK_FATAL(IsValidIdx(idx), "symbol table index out of range");
      return symbolTable[idx];
    }
  
    MIRSymbol *CreateSymbol(uint8 scopeID) {
      MIRSymbol *st = mAllocator->GetMemPool()->New<MIRSymbol>(symbolTable.size(), scopeID);
      symbolTable.push_back(st);
      return st;
    }
  
    // add sym from other symbol table, happens in inline
    bool AddStOutside(MIRSymbol *sym) {
      sym->SetStIdx(StIdx(sym->GetScopeIdx(), symbolTable.size()));
      symbolTable.push_back(sym);
      return AddToStringSymbolMap(sym);
    }
  
    bool AddToStringSymbolMap(const MIRSymbol *st) {
      GStrIdx strIdx = st->GetNameStrIdx();
      if (strIdxToStIdxMap[strIdx].FullIdx() != 0) {
        return false;
      }
      strIdxToStIdxMap[strIdx] = st->GetStIdx();
      return true;
    }
  
    StIdx GetStIdxFromStrIdx(GStrIdx idx) const {
      auto it = strIdxToStIdxMap.find(idx);
      if (it == strIdxToStIdxMap.end()) {
        return StIdx();
      }
      return it->second;
    }
  
    MIRSymbol *GetSymbolFromStrIdx(GStrIdx idx, bool checkFirst = false) const {
      return GetSymbolFromStIdx(GetStIdxFromStrIdx(idx).Idx(), checkFirst);
    }
  
    void Dump(bool isLocal, int32 indent = 0, bool printDeleted = false) const;
    size_t GetSymbolTableSize() const {
      return symbolTable.size();
    }
  
    void Clear() {
      symbolTable.clear();
    }
  
   private:
    MapleAllocator *mAllocator;
    // hash table mapping string index to st index
    MapleMap<GStrIdx, StIdx> strIdxToStIdxMap;
    // map symbol idx to symbol node
    MapleVector<MIRSymbol*> symbolTable;
  };
  
  class MIRLabelTable {
   public:
    explicit MIRLabelTable(MapleAllocator *allocator)
        : mAllocator(allocator),
          strIdxToLabIdxMap(std::less<GStrIdx>(), mAllocator->Adapter()),
          labelTable(mAllocator->Adapter()) {
      labelTable.push_back(GStrIdx(kDummyLabel));  // push dummy label index 0
    }
  
    ~MIRLabelTable() {}
  
    LabelIdx CreateLabel() {
      LabelIdx labelIdx = labelTable.size();
      labelTable.push_back(GStrIdx(0));  // insert dummy global string index for anonymous label
      return labelIdx;
    }
  
    LabelIdx CreateLabelWithPrefix(char c);
  
    LabelIdx AddLabel(GStrIdx nameIdx) {
      LabelIdx labelIdx = labelTable.size();
      labelTable.push_back(nameIdx);
      strIdxToLabIdxMap[nameIdx] = labelIdx;
      return labelIdx;
    }
  
    LabelIdx GetStIdxFromStrIdx(GStrIdx idx) const {
      auto it = strIdxToLabIdxMap.find(idx);
      if (it == strIdxToLabIdxMap.end()) {
        return LabelIdx();
      }
      return it->second;
    }
  
    bool AddToStringLabelMap(LabelIdx lidx);
    size_t GetLabelTableSize() const {
      return labelTable.size();
    }
  
    const std::string &GetName(LabelIdx labelIdx) const;
  
    size_t Size() const {
      return labelTable.size();
    }
  
    static uint32 GetDummyLabel() {
      return kDummyLabel;
    }
  
    GStrIdx GetSymbolFromStIdx(LabelIdx idx) const {
      CHECK_FATAL(idx < labelTable.size(), "label table index out of range");
      return labelTable[idx];
    }
  
    void SetSymbolFromStIdx(LabelIdx idx, GStrIdx strIdx) {
      CHECK_FATAL(idx < labelTable.size(), "label table index out of range");
      labelTable[idx] = strIdx;
    }
  
   private:
    static constexpr uint32 kDummyLabel = 0;
    MapleAllocator *mAllocator;
    MapleMap<GStrIdx, LabelIdx> strIdxToLabIdxMap;
    MapleVector<GStrIdx> labelTable;  // map label idx to label name
  };
  
  }  // namespace maple
  #endif
  