------------------------------------------------------------------------------
--                                                                          --
--                         GNAT RUN-TIME COMPONENTS                         --
--                                                                          --
--                             A D A . T A G S                              --
--                                                                          --
--                                 B o d y                                  --
--                                                                          --
--          Copyright (C) 1992-2006, Free Software Foundation, Inc.         --
--                                                                          --
-- GNAT is free software;  you can  redistribute it  and/or modify it under --
-- terms of the  GNU General Public License as published  by the Free Soft- --
-- ware  Foundation;  either version 2,  or (at your option) any later ver- --
-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
-- for  more details.  You should have  received  a copy of the GNU General --
-- Public License  distributed with GNAT;  see file COPYING.  If not, write --
-- to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, --
-- Boston, MA 02110-1301, USA.                                              --
--                                                                          --
-- As a special exception,  if other files  instantiate  generics from this --
-- unit, or you link  this unit with other files  to produce an executable, --
-- this  unit  does not  by itself cause  the resulting  executable  to  be --
-- covered  by the  GNU  General  Public  License.  This exception does not --
-- however invalidate  any other reasons why  the executable file  might be --
-- covered by the  GNU Public License.                                      --
--                                                                          --
-- GNAT was originally developed  by the GNAT team at  New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc.      --
--                                                                          --
------------------------------------------------------------------------------

with Ada.Exceptions;
with System.HTable;
with System.Storage_Elements; use System.Storage_Elements;
with System.WCh_Con;          use System.WCh_Con;
with System.WCh_StW;          use System.WCh_StW;

pragma Elaborate_All (System.HTable);

package body Ada.Tags is

   --  Object specific data types (see description in a-tags.ads)

   type Object_Specific_Data_Array is array (Positive range <>) of Positive;

   type Object_Specific_Data (Nb_Prim : Positive) is record
      OSD_Table : Object_Specific_Data_Array (1 .. Nb_Prim);
      --  Table used in secondary DT to reference their counterpart in the
      --  select specific data (in the TSD of the primary DT). This construct
      --  is used in the handling of dispatching triggers in select statements.
      --  Nb_Prim is the number of non-predefined primitive operations.
   end record;

   --  Select specific data types

   type Select_Specific_Data_Element is record
      Index : Positive;
      Kind  : Prim_Op_Kind;
   end record;

   type Select_Specific_Data_Array is
     array (Positive range <>) of Select_Specific_Data_Element;

   type Select_Specific_Data (Nb_Prim : Positive) is record
      SSD_Table : Select_Specific_Data_Array (1 .. Nb_Prim);
      --  NOTE: Nb_Prim is the number of non-predefined primitive operations
   end record;

   ---------------------------------------------
   -- Unchecked Conversions for String Fields --
   ---------------------------------------------

   function To_Address is
     new Unchecked_Conversion (Cstring_Ptr, System.Address);

   function To_Cstring_Ptr is
     new Unchecked_Conversion (System.Address, Cstring_Ptr);

   ------------------------------------------------
   -- Unchecked Conversions for other components --
   ------------------------------------------------

   type Acc_Size
     is access function (A : System.Address) return Long_Long_Integer;

   function To_Acc_Size is new Unchecked_Conversion (System.Address, Acc_Size);
   --  The profile of the implicitly defined _size primitive

   type Offset_To_Top_Function_Ptr is
      access function (This : System.Address)
               return System.Storage_Elements.Storage_Offset;
   --  Type definition used to call the function that is generated by the
   --  expander in case of tagged types with discriminants that have secondary
   --  dispatch tables. This function provides the Offset_To_Top value in this
   --  specific case.

   function To_Offset_To_Top_Function_Ptr is
      new Unchecked_Conversion (System.Address, Offset_To_Top_Function_Ptr);

   type Storage_Offset_Ptr is access System.Storage_Elements.Storage_Offset;

   function To_Storage_Offset_Ptr is
     new Unchecked_Conversion (System.Address, Storage_Offset_Ptr);

   -----------------------
   -- Local Subprograms --
   -----------------------

   function Is_Primary_DT (T : Tag) return Boolean;
   pragma Inline_Always (Is_Primary_DT);
   --  Given a tag returns True if it has the signature of a primary dispatch
   --  table.  This is Inline_Always since it is called from other Inline_
   --  Always subprograms where we want no out of line code to be generated.

   function Length (Str : Cstring_Ptr) return Natural;
   --  Length of string represented by the given pointer (treating the string
   --  as a C-style string, which is Nul terminated).

   function Predefined_DT (T : Tag) return Tag;
   pragma Inline_Always (Predefined_DT);
   --  Displace the Tag to reference the dispatch table containing the
   --  predefined primitives.

   function Typeinfo_Ptr (T : Tag) return System.Address;
   --  Returns the current value of the typeinfo_ptr component available in
   --  the prologue of the dispatch table.

   pragma Unreferenced (Typeinfo_Ptr);
   --  These functions will be used for full compatibility with the C++ ABI

   -------------------------
   -- External_Tag_HTable --
   -------------------------

   type HTable_Headers is range 1 .. 64;

   --  The following internal package defines the routines used for the
   --  instantiation of a new System.HTable.Static_HTable (see below). See
   --  spec in g-htable.ads for details of usage.

   package HTable_Subprograms is
      procedure Set_HT_Link (T : Tag; Next : Tag);
      function  Get_HT_Link (T : Tag) return Tag;
      function Hash (F : System.Address) return HTable_Headers;
      function Equal (A, B : System.Address) return Boolean;
   end HTable_Subprograms;

   package External_Tag_HTable is new System.HTable.Static_HTable (
     Header_Num => HTable_Headers,
     Element    => Dispatch_Table,
     Elmt_Ptr   => Tag,
     Null_Ptr   => null,
     Set_Next   => HTable_Subprograms.Set_HT_Link,
     Next       => HTable_Subprograms.Get_HT_Link,
     Key        => System.Address,
     Get_Key    => Get_External_Tag,
     Hash       => HTable_Subprograms.Hash,
     Equal      => HTable_Subprograms.Equal);

   ------------------------
   -- HTable_Subprograms --
   ------------------------

   --  Bodies of routines for hash table instantiation

   package body HTable_Subprograms is

      -----------
      -- Equal --
      -----------

      function Equal (A, B : System.Address) return Boolean is
         Str1 : constant Cstring_Ptr := To_Cstring_Ptr (A);
         Str2 : constant Cstring_Ptr := To_Cstring_Ptr (B);
         J    : Integer := 1;
      begin
         loop
            if Str1 (J) /= Str2 (J) then
               return False;
            elsif Str1 (J) = ASCII.NUL then
               return True;
            else
               J := J + 1;
            end if;
         end loop;
      end Equal;

      -----------------
      -- Get_HT_Link --
      -----------------

      function Get_HT_Link (T : Tag) return Tag is
      begin
         return TSD (T).HT_Link;
      end Get_HT_Link;

      ----------
      -- Hash --
      ----------

      function Hash (F : System.Address) return HTable_Headers is
         function H is new System.HTable.Hash (HTable_Headers);
         Str : constant Cstring_Ptr    := To_Cstring_Ptr (F);
         Res : constant HTable_Headers := H (Str (1 .. Length (Str)));
      begin
         return Res;
      end Hash;

      -----------------
      -- Set_HT_Link --
      -----------------

      procedure Set_HT_Link (T : Tag; Next : Tag) is
      begin
         TSD (T).HT_Link := Next;
      end Set_HT_Link;

   end HTable_Subprograms;

   -------------------
   -- CW_Membership --
   -------------------

   --  Canonical implementation of Classwide Membership corresponding to:

   --     Obj in Typ'Class

   --  Each dispatch table contains a reference to a table of ancestors (stored
   --  in the first part of the Tags_Table) and a count of the level of
   --  inheritance "Idepth".

   --  Obj is in Typ'Class if Typ'Tag is in the table of ancestors that are
   --  contained in the dispatch table referenced by Obj'Tag . Knowing the
   --  level of inheritance of both types, this can be computed in constant
   --  time by the formula:

   --   TSD (Obj'tag).Tags_Table (TSD (Obj'tag).Idepth - TSD (Typ'tag).Idepth)
   --     = Typ'tag

   function CW_Membership (Obj_Tag : Tag; Typ_Tag : Tag) return Boolean is
      Pos : Integer;
   begin
      Pos := TSD (Obj_Tag).Idepth - TSD (Typ_Tag).Idepth;
      return Pos >= 0 and then TSD (Obj_Tag).Tags_Table (Pos) = Typ_Tag;
   end CW_Membership;

   ------------------
   -- Base_Address --
   ------------------

   function Base_Address (This : System.Address) return System.Address is
   begin
      return This - Offset_To_Top (This);
   end Base_Address;

   --------------
   -- Displace --
   --------------

   function Displace
     (This : System.Address;
      T    : Tag) return System.Address
   is
      Iface_Table : Interface_Data_Ptr;
      Obj_Base    : System.Address;
      Obj_DT      : Tag;
      Obj_TSD     : Type_Specific_Data_Ptr;

   begin
      Obj_Base    := This - Offset_To_Top (This);
      Obj_DT      := To_Tag_Ptr (Obj_Base).all;
      Obj_TSD     := TSD (Obj_DT);
      Iface_Table := To_Interface_Data_Ptr (Obj_TSD.Ifaces_Table_Ptr);

      if Iface_Table /= null then
         for Id in 1 .. Iface_Table.Nb_Ifaces loop
            if Iface_Table.Ifaces_Table (Id).Iface_Tag = T then

               --  Case of Static value of Offset_To_Top

               if Iface_Table.Ifaces_Table (Id).Static_Offset_To_Top then
                  Obj_Base := Obj_Base +
                    Iface_Table.Ifaces_Table (Id).Offset_To_Top_Value;

               --  Otherwise we call the function generated by the expander
               --  to provide us with this value

               else
                  Obj_Base :=
                    Obj_Base +
                      To_Offset_To_Top_Function_Ptr
                        (Iface_Table.Ifaces_Table (Id).Offset_To_Top_Func).all
                          (Obj_Base);
               end if;

               Obj_DT := To_Tag_Ptr (Obj_Base).all;
               return Obj_Base;
            end if;
         end loop;
      end if;

      --  Check if T is an immediate ancestor. This is required to handle
      --  conversion of class-wide interfaces to tagged types.

      if CW_Membership (Obj_DT, T) then
         return Obj_Base;
      end if;

      --  If the object does not implement the interface we must raise CE

      raise Constraint_Error;
   end Displace;

   -------------------
   -- IW_Membership --
   -------------------

   --  Canonical implementation of Classwide Membership corresponding to:

   --     Obj in Iface'Class

   --  Each dispatch table contains a table with the tags of all the
   --  implemented interfaces.

   --  Obj is in Iface'Class if Iface'Tag is found in the table of interfaces
   --  that are contained in the dispatch table referenced by Obj'Tag.

   function IW_Membership (This : System.Address; T : Tag) return Boolean is
      Iface_Table : Interface_Data_Ptr;
      Last_Id     : Natural;
      Obj_Base    : System.Address;
      Obj_DT      : Tag;
      Obj_TSD     : Type_Specific_Data_Ptr;

   begin
      Obj_Base := This - Offset_To_Top (This);
      Obj_DT   := To_Tag_Ptr (Obj_Base).all;
      Obj_TSD  := TSD (Obj_DT);
      Last_Id  := Obj_TSD.Idepth;

      --  Look for the tag in the table of interfaces

      Iface_Table := To_Interface_Data_Ptr (Obj_TSD.Ifaces_Table_Ptr);

      if Iface_Table /= null then
         for Id in 1 .. Iface_Table.Nb_Ifaces loop
            if Iface_Table.Ifaces_Table (Id).Iface_Tag = T then
               return True;
            end if;
         end loop;
      end if;

      --  Look for the tag in the ancestor tags table. This is required for:
      --     Iface_CW in Typ'Class

      for Id in 0 .. Last_Id loop
         if Obj_TSD.Tags_Table (Id) = T then
            return True;
         end if;
      end loop;

      return False;
   end IW_Membership;

   --------------------
   -- Descendant_Tag --
   --------------------

   function Descendant_Tag (External : String; Ancestor : Tag) return Tag is
      Int_Tag : constant Tag := Internal_Tag (External);

   begin
      if not Is_Descendant_At_Same_Level (Int_Tag, Ancestor) then
         raise Tag_Error;
      end if;

      return Int_Tag;
   end Descendant_Tag;

   -------------------
   -- Expanded_Name --
   -------------------

   function Expanded_Name (T : Tag) return String is
      Result : Cstring_Ptr;

   begin
      if T = No_Tag then
         raise Tag_Error;
      end if;

      Result := TSD (T).Expanded_Name;
      return Result (1 .. Length (Result));
   end Expanded_Name;

   ------------------
   -- External_Tag --
   ------------------

   function External_Tag (T : Tag) return String is
      Result : Cstring_Ptr;

   begin
      if T = No_Tag then
         raise Tag_Error;
      end if;

      Result := TSD (T).External_Tag;
      return Result (1 .. Length (Result));
   end External_Tag;

   ---------------------
   -- Get_Entry_Index --
   ---------------------

   function Get_Entry_Index (T : Tag; Position : Positive) return Positive is
   begin
      return SSD (T).SSD_Table (Position).Index;
   end Get_Entry_Index;

   ----------------------
   -- Get_External_Tag --
   ----------------------

   function Get_External_Tag (T : Tag) return System.Address is
   begin
      return To_Address (TSD (T).External_Tag);
   end Get_External_Tag;

   ----------------------
   -- Get_Prim_Op_Kind --
   ----------------------

   function Get_Prim_Op_Kind
     (T        : Tag;
      Position : Positive) return Prim_Op_Kind
   is
   begin
      return SSD (T).SSD_Table (Position).Kind;
   end Get_Prim_Op_Kind;

   ----------------------
   -- Get_Offset_Index --
   ----------------------

   function Get_Offset_Index
     (T        : Tag;
      Position : Positive) return Positive
   is
   begin
      if Is_Primary_DT (T) then
         return Position;
      else
         return OSD (T).OSD_Table (Position);
      end if;
   end Get_Offset_Index;

   -------------------
   -- Get_RC_Offset --
   -------------------

   function Get_RC_Offset (T : Tag) return SSE.Storage_Offset is
   begin
      return TSD (T).RC_Offset;
   end Get_RC_Offset;

   ---------------------
   -- Get_Tagged_Kind --
   ---------------------

   function Get_Tagged_Kind (T : Tag) return Tagged_Kind is
      Tagged_Kind_Ptr : constant System.Address :=
                          To_Address (T) - K_Tagged_Kind;
   begin
      return To_Tagged_Kind_Ptr (Tagged_Kind_Ptr).all;
   end Get_Tagged_Kind;

   -----------------------------
   -- Interface_Ancestor_Tags --
   -----------------------------

   function Interface_Ancestor_Tags (T : Tag) return Tag_Array is
      Iface_Table : Interface_Data_Ptr;

   begin
      Iface_Table := To_Interface_Data_Ptr (TSD (T).Ifaces_Table_Ptr);

      if Iface_Table = null then
         declare
            Table : Tag_Array (1 .. 0);
         begin
            return Table;
         end;
      else
         declare
            Table : Tag_Array (1 .. Iface_Table.Nb_Ifaces);
         begin
            for J in 1 .. Iface_Table.Nb_Ifaces loop
               Table (J) := Iface_Table.Ifaces_Table (J).Iface_Tag;
            end loop;

            return Table;
         end;
      end if;
   end Interface_Ancestor_Tags;

   ------------------
   -- Internal_Tag --
   ------------------

   function Internal_Tag (External : String) return Tag is
      Ext_Copy : aliased String (External'First .. External'Last + 1);
      Res      : Tag;

   begin
      --  Make a copy of the string representing the external tag with
      --  a null at the end.

      Ext_Copy (External'Range) := External;
      Ext_Copy (Ext_Copy'Last) := ASCII.NUL;
      Res := External_Tag_HTable.Get (Ext_Copy'Address);

      if Res = null then
         declare
            Msg1 : constant String := "unknown tagged type: ";
            Msg2 : String (1 .. Msg1'Length + External'Length);

         begin
            Msg2 (1 .. Msg1'Length) := Msg1;
            Msg2 (Msg1'Length + 1 .. Msg1'Length + External'Length) :=
              External;
            Ada.Exceptions.Raise_Exception (Tag_Error'Identity, Msg2);
         end;
      end if;

      return Res;
   end Internal_Tag;

   ---------------------------------
   -- Is_Descendant_At_Same_Level --
   ---------------------------------

   function Is_Descendant_At_Same_Level
     (Descendant : Tag;
      Ancestor   : Tag) return Boolean
   is
   begin
      return CW_Membership (Descendant, Ancestor)
        and then TSD (Descendant).Access_Level = TSD (Ancestor).Access_Level;
   end Is_Descendant_At_Same_Level;

   -------------------
   -- Is_Primary_DT --
   -------------------

   function Is_Primary_DT (T : Tag) return Boolean is
      Signature  : constant Storage_Offset_Ptr :=
                     To_Storage_Offset_Ptr (To_Address (T) - K_Signature);
      Sig_Values : constant Signature_Values :=
                     To_Signature_Values (Signature.all);
   begin
      return Sig_Values (2) = Primary_DT;
   end Is_Primary_DT;

   ------------
   -- Length --
   ------------

   function Length (Str : Cstring_Ptr) return Natural is
      Len : Integer := 1;

   begin
      while Str (Len) /= ASCII.Nul loop
         Len := Len + 1;
      end loop;

      return Len - 1;
   end Length;

   -------------------
   -- Offset_To_Top --
   -------------------

   function Offset_To_Top
     (This : System.Address) return System.Storage_Elements.Storage_Offset
   is
      Curr_DT       : constant Tag := To_Tag_Ptr (This).all;
      Offset_To_Top : Storage_Offset_Ptr;
   begin
      Offset_To_Top := To_Storage_Offset_Ptr
                         (To_Address (Curr_DT) - K_Offset_To_Top);

      if Offset_To_Top.all = SSE.Storage_Offset'Last then
         Offset_To_Top := To_Storage_Offset_Ptr (This + Tag_Size);
      end if;

      return Offset_To_Top.all;
   end Offset_To_Top;

   ---------
   -- OSD --
   ---------

   function OSD (T : Tag) return Object_Specific_Data_Ptr is
      OSD_Ptr : constant Addr_Ptr :=
                  To_Addr_Ptr (To_Address (T) - K_Typeinfo);
   begin
      return To_Object_Specific_Data_Ptr (OSD_Ptr.all);
   end OSD;

   -----------------
   -- Parent_Size --
   -----------------

   function Parent_Size
     (Obj : System.Address;
      T   : Tag) return SSE.Storage_Count
   is
      Parent_Slot : constant Positive := 1;
      --  The tag of the parent is always in the first slot of the table of
      --  ancestor tags.

      Size_Slot : constant Positive := 1;
      --  The pointer to the _size primitive is always in the first slot of
      --  the dispatch table.

      Parent_Tag : Tag;
      --  The tag of the parent type through the dispatch table

      F : Acc_Size;
      --  Access to the _size primitive of the parent

   begin
      Parent_Tag := TSD (T).Tags_Table (Parent_Slot);
      F := To_Acc_Size (Predefined_DT (Parent_Tag).Prims_Ptr (Size_Slot));

      --  Here we compute the size of the _parent field of the object

      return SSE.Storage_Count (F.all (Obj));
   end Parent_Size;

   ----------------
   -- Parent_Tag --
   ----------------

   function Parent_Tag (T : Tag) return Tag is
   begin
      if T = No_Tag then
         raise Tag_Error;
      end if;

      --  The Parent_Tag of a root-level tagged type is defined to be No_Tag.
      --  The first entry in the Ancestors_Tags array will be null for such
      --  a type, but it's better to be explicit about returning No_Tag in
      --  this case.

      if TSD (T).Idepth = 0 then
         return No_Tag;
      else
         return TSD (T).Tags_Table (1);
      end if;
   end Parent_Tag;

   -------------------
   -- Predefined_DT --
   -------------------

   function Predefined_DT (T : Tag) return Tag is
   begin
      return To_Tag (To_Address (T) - DT_Prologue_Size);
   end Predefined_DT;

   ----------------------------
   -- Register_Interface_Tag --
   ----------------------------

   procedure Register_Interface_Tag
     (T           : Tag;
      Interface_T : Tag;
      Position    : Positive)
   is
      New_T_TSD   : Type_Specific_Data_Ptr;
      Iface_Table : Interface_Data_Ptr;

   begin
      New_T_TSD   := TSD (T);
      Iface_Table := To_Interface_Data_Ptr (New_T_TSD.Ifaces_Table_Ptr);
      Iface_Table.Ifaces_Table (Position).Iface_Tag := Interface_T;
   end Register_Interface_Tag;

   ------------------
   -- Register_Tag --
   ------------------

   procedure Register_Tag (T : Tag) is
   begin
      External_Tag_HTable.Set (T);
   end Register_Tag;

   ---------------------
   -- Set_Entry_Index --
   ---------------------

   procedure Set_Entry_Index
     (T        : Tag;
      Position : Positive;
      Value    : Positive)
   is
   begin
      SSD (T).SSD_Table (Position).Index := Value;
   end Set_Entry_Index;

   -------------------------
   -- Set_Interface_Table --
   -------------------------

   procedure Set_Interface_Table (T : Tag; Value : System.Address) is
   begin
      TSD (T).Ifaces_Table_Ptr := Value;
   end Set_Interface_Table;

   ----------------------
   -- Set_Offset_Index --
   ----------------------

   procedure Set_Offset_Index
     (T        : Tag;
      Position : Positive;
      Value    : Positive)
   is
   begin
      OSD (T).OSD_Table (Position) := Value;
   end Set_Offset_Index;

   -----------------------
   -- Set_Offset_To_Top --
   -----------------------

   procedure Set_Offset_To_Top
     (This          : System.Address;
      Interface_T   : Tag;
      Is_Static     : Boolean;
      Offset_Value  : System.Storage_Elements.Storage_Offset;
      Offset_Func   : System.Address)
   is
      Prim_DT       : Tag;
      Sec_Base      : System.Address;
      Sec_DT        : Tag;
      Offset_To_Top : Storage_Offset_Ptr;
      Iface_Table   : Interface_Data_Ptr;
      Obj_TSD       : Type_Specific_Data_Ptr;
   begin
      if System."=" (This, System.Null_Address) then
         Offset_To_Top :=
           To_Storage_Offset_Ptr (To_Address (Interface_T) - K_Offset_To_Top);
         Offset_To_Top.all := Offset_Value;
         return;
      end if;

      --  "This" points to the primary DT and we must save Offset_Value in the
      --  Offset_To_Top field of the corresponding secondary dispatch table.

      Prim_DT  := To_Tag_Ptr (This).all;

      --  Save the offset to top field in the secondary dispatch table.

      if Offset_Value /= 0 then
         Sec_Base := This + Offset_Value;
         Sec_DT   := To_Tag_Ptr (Sec_Base).all;
         Offset_To_Top :=
           To_Storage_Offset_Ptr (To_Address (Sec_DT) - K_Offset_To_Top);

         if Is_Static then
            Offset_To_Top.all := Offset_Value;
         else
            Offset_To_Top.all := SSE.Storage_Offset'Last;
         end if;
      end if;

      --  Save Offset_Value in the table of interfaces of the primary DT. This
      --  data will be used by the subprogram "Displace" to give support to
      --  backward abstract interface type conversions.

      Obj_TSD     := TSD (Prim_DT);
      Iface_Table := To_Interface_Data_Ptr (Obj_TSD.Ifaces_Table_Ptr);

      --  Register the offset in the table of interfaces

      if Iface_Table /= null then
         for Id in 1 .. Iface_Table.Nb_Ifaces loop
            if Iface_Table.Ifaces_Table (Id).Iface_Tag = Interface_T then
               Iface_Table.Ifaces_Table (Id).Static_Offset_To_Top := Is_Static;

               if Is_Static then
                  Iface_Table.Ifaces_Table (Id).Offset_To_Top_Value
                    := Offset_Value;
               else
                  Iface_Table.Ifaces_Table (Id).Offset_To_Top_Func
                    := Offset_Func;
               end if;

               return;
            end if;
         end loop;
      end if;

      --  If we arrive here there is some error in the run-time data structure

      raise Program_Error;
   end Set_Offset_To_Top;

   -------------
   -- Set_OSD --
   -------------

   procedure Set_OSD (T : Tag; Value : System.Address) is
      OSD_Ptr : constant Addr_Ptr :=
                  To_Addr_Ptr (To_Address (T) - K_Typeinfo);
   begin
      OSD_Ptr.all := Value;
   end Set_OSD;

   ----------------------
   -- Set_Prim_Op_Kind --
   ----------------------

   procedure Set_Prim_Op_Kind
     (T        : Tag;
      Position : Positive;
      Value    : Prim_Op_Kind)
   is
   begin
      SSD (T).SSD_Table (Position).Kind := Value;
   end Set_Prim_Op_Kind;

   -------------------
   -- Set_Signature --
   -------------------

   procedure Set_Signature (T : Tag; Value : Signature_Kind) is
      Signature : constant System.Address := To_Address (T) - K_Signature;
      Sig_Ptr   : constant Signature_Values_Ptr :=
                    To_Signature_Values_Ptr (Signature);
   begin
      Sig_Ptr.all (1) := Valid_Signature;
      Sig_Ptr.all (2) := Value;
   end Set_Signature;

   -------------
   -- Set_SSD --
   -------------

   procedure Set_SSD (T : Tag; Value : System.Address) is
   begin
      TSD (T).SSD_Ptr := Value;
   end Set_SSD;

   ---------------------
   -- Set_Tagged_Kind --
   ---------------------

   procedure Set_Tagged_Kind (T : Tag; Value : Tagged_Kind) is
      Tagged_Kind_Ptr : constant System.Address :=
                          To_Address (T) - K_Tagged_Kind;
   begin
      To_Tagged_Kind_Ptr (Tagged_Kind_Ptr).all := Value;
   end Set_Tagged_Kind;

   ---------
   -- SSD --
   ---------

   function SSD (T : Tag) return Select_Specific_Data_Ptr is
   begin
      return To_Select_Specific_Data_Ptr (TSD (T).SSD_Ptr);
   end SSD;

   ------------------
   -- Typeinfo_Ptr --
   ------------------

   function Typeinfo_Ptr (T : Tag) return System.Address is
      TSD_Ptr : constant Addr_Ptr :=
                  To_Addr_Ptr (To_Address (T) - K_Typeinfo);
   begin
      return TSD_Ptr.all;
   end Typeinfo_Ptr;

   ---------
   -- TSD --
   ---------

   function TSD (T : Tag) return Type_Specific_Data_Ptr is
      TSD_Ptr : constant Addr_Ptr :=
                  To_Addr_Ptr (To_Address (T) - K_Typeinfo);
   begin
      return To_Type_Specific_Data_Ptr (TSD_Ptr.all);
   end TSD;

   ------------------------
   -- Wide_Expanded_Name --
   ------------------------

   WC_Encoding : Character;
   pragma Import (C, WC_Encoding, "__gl_wc_encoding");
   --  Encoding method for source, as exported by binder

   function Wide_Expanded_Name (T : Tag) return Wide_String is
   begin
      return String_To_Wide_String
        (Expanded_Name (T), Get_WC_Encoding_Method (WC_Encoding));
   end Wide_Expanded_Name;

   -----------------------------
   -- Wide_Wide_Expanded_Name --
   -----------------------------

   function Wide_Wide_Expanded_Name (T : Tag) return Wide_Wide_String is
   begin
      return String_To_Wide_Wide_String
        (Expanded_Name (T), Get_WC_Encoding_Method (WC_Encoding));
   end Wide_Wide_Expanded_Name;

end Ada.Tags;
