1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME COMPONENTS --
9 -- Copyright (C) 1992-2005 Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 2, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
20 -- MA 02111-1307, USA. --
22 -- As a special exception, if other files instantiate generics from this --
23 -- unit, or you link this unit with other files to produce an executable, --
24 -- this unit does not by itself cause the resulting executable to be --
25 -- covered by the GNU General Public License. This exception does not --
26 -- however invalidate any other reasons why the executable file might be --
27 -- covered by the GNU Public License. --
29 -- GNAT was originally developed by the GNAT team at New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc. --
32 ------------------------------------------------------------------------------
36 with System.Storage_Elements; use System.Storage_Elements;
38 pragma Elaborate_All (System.HTable);
40 package body Ada.Tags is
42 -- Structure of the GNAT Dispatch Table
44 -- +-----------------------+
46 -- +-----------------------+
47 -- | Typeinfo_Ptr/TSD_Ptr |----> Type Specific Data
48 -- Tag ---> +-----------------------+ +-------------------+
49 -- | table of | | inheritance depth |
50 -- : primitive ops : +-------------------+
51 -- | pointers | | expanded name |
52 -- +-----------------------+ +-------------------+
54 -- +-------------------+
55 -- | Hash table link |
56 -- +-------------------+
57 -- | Remotely Callable |
58 -- +-------------------+
59 -- | Rec Ctrler offset |
60 -- +-------------------+
62 -- +-------------------+
66 -- +-------------------+
70 -- +-------------------+
72 subtype Cstring is String (Positive);
73 type Cstring_Ptr is access all Cstring;
75 type Tag_Table is array (Natural range <>) of Tag;
76 pragma Suppress_Initialization (Tag_Table);
77 pragma Suppress (Index_Check, On => Tag_Table);
78 -- We suppress index checks because the declared size in the record below
79 -- is a dummy size of one (see below).
81 type Type_Specific_Data is record
83 Access_Level : Natural;
84 Expanded_Name : Cstring_Ptr;
85 External_Tag : Cstring_Ptr;
87 Remotely_Callable : Boolean;
88 RC_Offset : SSE.Storage_Offset;
89 Num_Interfaces : Natural;
90 Tags_Table : Tag_Table (Natural);
92 -- The size of the Tags_Table array actually depends on the tagged type
93 -- to which it applies. The compiler ensures that has enough space to
94 -- store all the entries of the two tables phisically stored there: the
95 -- "table of ancestor tags" and the "table of interface tags". For this
96 -- purpose we are using the same mechanism as for the Prims_Ptr array in
97 -- the Dispatch_Table record. See comments below for more details.
101 type Dispatch_Table is record
102 -- Offset_To_Top : Natural;
103 -- Typeinfo_Ptr : System.Address; -- Currently TSD is also here???
104 Prims_Ptr : Address_Array (Positive);
107 -- Note on the commented out fields of the Dispatch_Table
109 -- According to the C++ ABI the components Offset_To_Top and Typeinfo_Ptr
110 -- are stored just "before" the dispatch table (that is, the Prims_Ptr
111 -- table), and they are referenced with negative offsets referring to the
112 -- base of the dispatch table. The _Tag (or the VTable_Ptr in C++ termi-
113 -- nology) must point to the base of the virtual table, just after these
114 -- components, to point to the Prims_Ptr table. For this purpose the
115 -- expander generates a Prims_Ptr table that has enough space for these
116 -- additional components, and generates code that displaces the _Tag to
117 -- point after these components.
119 -- The size of the Prims_Ptr array actually depends on the tagged type to
120 -- which it applies. For each tagged type, the expander computes the
121 -- actual array size, allocates the Dispatch_Table record accordingly, and
122 -- generates code that displaces the base of the record after the
123 -- Typeinfo_Ptr component. For this reason the first two components have
124 -- been commented in the previous declaration. The access to these
125 -- components is done by means of local functions.
127 -- To avoid the use of discriminants to define the actual size of the
128 -- dispatch table, we used to declare the tag as a pointer to a record
129 -- that contains an arbitrary array of addresses, using Positive as its
130 -- index. This ensures that there are never range checks when accessing
131 -- the dispatch table, but it prevents GDB from displaying tagged types
132 -- properly. A better approach is to declare this record type as holding a
133 -- small number of addresses, and to explicitly suppress checks on it.
135 -- Note that in both cases, this type is never allocated, and serves only
136 -- to declare the corresponding access type.
138 ---------------------------------------------
139 -- Unchecked Conversions for String Fields --
140 ---------------------------------------------
142 function To_Address is
143 new Unchecked_Conversion (Cstring_Ptr, System.Address);
145 function To_Cstring_Ptr is
146 new Unchecked_Conversion (System.Address, Cstring_Ptr);
148 ------------------------------------------------
149 -- Unchecked Conversions for other components --
150 ------------------------------------------------
152 type Storage_Offset_Ptr is access System.Storage_Elements.Storage_Offset;
154 function To_Storage_Offset_Ptr is
155 new Unchecked_Conversion (System.Address, Storage_Offset_Ptr);
157 -----------------------
158 -- Local Subprograms --
159 -----------------------
161 function Length (Str : Cstring_Ptr) return Natural;
162 -- Length of string represented by the given pointer (treating the string
163 -- as a C-style string, which is Nul terminated).
165 function Offset_To_Top
166 (T : Tag) return System.Storage_Elements.Storage_Offset;
167 -- Returns the current value of the offset_to_top component available in
168 -- the prologue of the dispatch table.
170 function Typeinfo_Ptr (T : Tag) return System.Address;
171 -- Returns the current value of the typeinfo_ptr component available in
172 -- the prologue of the dispatch table.
174 pragma Unreferenced (Typeinfo_Ptr);
175 -- These functions will be used for full compatibility with the C++ ABI
177 -------------------------
178 -- External_Tag_HTable --
179 -------------------------
181 type HTable_Headers is range 1 .. 64;
183 -- The following internal package defines the routines used for the
184 -- instantiation of a new System.HTable.Static_HTable (see below). See
185 -- spec in g-htable.ads for details of usage.
187 package HTable_Subprograms is
188 procedure Set_HT_Link (T : Tag; Next : Tag);
189 function Get_HT_Link (T : Tag) return Tag;
190 function Hash (F : System.Address) return HTable_Headers;
191 function Equal (A, B : System.Address) return Boolean;
192 end HTable_Subprograms;
194 package External_Tag_HTable is new System.HTable.Static_HTable (
195 Header_Num => HTable_Headers,
196 Element => Dispatch_Table,
199 Set_Next => HTable_Subprograms.Set_HT_Link,
200 Next => HTable_Subprograms.Get_HT_Link,
201 Key => System.Address,
202 Get_Key => Get_External_Tag,
203 Hash => HTable_Subprograms.Hash,
204 Equal => HTable_Subprograms.Equal);
206 ------------------------
207 -- HTable_Subprograms --
208 ------------------------
210 -- Bodies of routines for hash table instantiation
212 package body HTable_Subprograms is
218 function Equal (A, B : System.Address) return Boolean is
219 Str1 : constant Cstring_Ptr := To_Cstring_Ptr (A);
220 Str2 : constant Cstring_Ptr := To_Cstring_Ptr (B);
225 if Str1 (J) /= Str2 (J) then
228 elsif Str1 (J) = ASCII.NUL then
241 function Get_HT_Link (T : Tag) return Tag is
243 return TSD (T).HT_Link;
250 function Hash (F : System.Address) return HTable_Headers is
251 function H is new System.HTable.Hash (HTable_Headers);
252 Str : constant Cstring_Ptr := To_Cstring_Ptr (F);
253 Res : constant HTable_Headers := H (Str (1 .. Length (Str)));
262 procedure Set_HT_Link (T : Tag; Next : Tag) is
264 TSD (T).HT_Link := Next;
267 end HTable_Subprograms;
273 -- Canonical implementation of Classwide Membership corresponding to:
277 -- Each dispatch table contains a reference to a table of ancestors (stored
278 -- in the first part of the Tags_Table) and a count of the level of
279 -- inheritance "Idepth".
281 -- Obj is in Typ'Class if Typ'Tag is in the table of ancestors that are
282 -- contained in the dispatch table referenced by Obj'Tag . Knowing the
283 -- level of inheritance of both types, this can be computed in constant
284 -- time by the formula:
286 -- Obj'tag.TSD.Ancestor_Tags (Obj'tag.TSD.Idepth - Typ'tag.TSD.Idepth)
289 function CW_Membership (Obj_Tag : Tag; Typ_Tag : Tag) return Boolean is
290 Pos : constant Integer := TSD (Obj_Tag).Idepth - TSD (Typ_Tag).Idepth;
292 return Pos >= 0 and then TSD (Obj_Tag).Tags_Table (Pos) = Typ_Tag;
299 -- Canonical implementation of Classwide Membership corresponding to:
301 -- Obj in Iface'Class
303 -- Each dispatch table contains a table with the tags of all the
304 -- implemented interfaces.
306 -- Obj is in Iface'Class if Iface'Tag is found in the table of interfaces
307 -- that are contained in the dispatch table referenced by Obj'Tag.
309 function IW_Membership
310 (This : System.Address;
311 Iface_Tag : Tag) return Boolean
313 T : constant Tag := To_Tag_Ptr (This).all;
314 Obj_Base : constant System.Address := This - Offset_To_Top (T);
315 T_Base : constant Tag := To_Tag_Ptr (Obj_Base).all;
317 Obj_TSD : constant Type_Specific_Data_Ptr := TSD (T_Base);
318 Last_Id : constant Natural := Obj_TSD.Idepth + Obj_TSD.Num_Interfaces;
322 if Obj_TSD.Num_Interfaces > 0 then
323 Id := Obj_TSD.Idepth + 1;
325 if Obj_TSD.Tags_Table (Id) = Iface_Tag then
330 exit when Id > Last_Id;
341 function Descendant_Tag (External : String; Ancestor : Tag) return Tag is
342 Int_Tag : constant Tag := Internal_Tag (External);
345 if not Is_Descendant_At_Same_Level (Int_Tag, Ancestor) then
356 function Expanded_Name (T : Tag) return String is
357 Result : Cstring_Ptr;
364 Result := TSD (T).Expanded_Name;
365 return Result (1 .. Length (Result));
372 function External_Tag (T : Tag) return String is
373 Result : Cstring_Ptr;
379 Result := TSD (T).External_Tag;
381 return Result (1 .. Length (Result));
384 ----------------------
385 -- Get_Access_Level --
386 ----------------------
388 function Get_Access_Level (T : Tag) return Natural is
390 return TSD (T).Access_Level;
391 end Get_Access_Level;
393 ----------------------
394 -- Get_External_Tag --
395 ----------------------
397 function Get_External_Tag (T : Tag) return System.Address is
399 return To_Address (TSD (T).External_Tag);
400 end Get_External_Tag;
402 -------------------------
403 -- Get_Prim_Op_Address --
404 -------------------------
406 function Get_Prim_Op_Address
408 Position : Positive) return System.Address is
410 return T.Prims_Ptr (Position);
411 end Get_Prim_Op_Address;
417 function Get_RC_Offset (T : Tag) return SSE.Storage_Offset is
419 return TSD (T).RC_Offset;
422 ---------------------------
423 -- Get_Remotely_Callable --
424 ---------------------------
426 function Get_Remotely_Callable (T : Tag) return Boolean is
428 return TSD (T).Remotely_Callable;
429 end Get_Remotely_Callable;
438 Entry_Count : Natural)
441 if Old_T /= null then
442 New_T.Prims_Ptr (1 .. Entry_Count) :=
443 Old_T.Prims_Ptr (1 .. Entry_Count);
451 procedure Inherit_TSD (Old_Tag : Tag; New_Tag : Tag) is
452 New_TSD_Ptr : constant Type_Specific_Data_Ptr := TSD (New_Tag);
453 Old_TSD_Ptr : Type_Specific_Data_Ptr;
456 if Old_Tag /= null then
457 Old_TSD_Ptr := TSD (Old_Tag);
458 New_TSD_Ptr.Idepth := Old_TSD_Ptr.Idepth + 1;
459 New_TSD_Ptr.Num_Interfaces := Old_TSD_Ptr.Num_Interfaces;
461 -- Copy the "table of ancestor tags" plus the "table of interfaces"
464 New_TSD_Ptr.Tags_Table
465 (1 .. New_TSD_Ptr.Idepth + New_TSD_Ptr.Num_Interfaces)
466 := Old_TSD_Ptr.Tags_Table
467 (0 .. Old_TSD_Ptr.Idepth + Old_TSD_Ptr.Num_Interfaces);
469 New_TSD_Ptr.Idepth := 0;
470 New_TSD_Ptr.Num_Interfaces := 0;
473 New_TSD_Ptr.Tags_Table (0) := New_Tag;
480 function Internal_Tag (External : String) return Tag is
481 Ext_Copy : aliased String (External'First .. External'Last + 1);
485 -- Make a copy of the string representing the external tag with
488 Ext_Copy (External'Range) := External;
489 Ext_Copy (Ext_Copy'Last) := ASCII.NUL;
490 Res := External_Tag_HTable.Get (Ext_Copy'Address);
494 Msg1 : constant String := "unknown tagged type: ";
495 Msg2 : String (1 .. Msg1'Length + External'Length);
497 Msg2 (1 .. Msg1'Length) := Msg1;
498 Msg2 (Msg1'Length + 1 .. Msg1'Length + External'Length) :=
500 Ada.Exceptions.Raise_Exception (Tag_Error'Identity, Msg2);
507 ---------------------------------
508 -- Is_Descendant_At_Same_Level --
509 ---------------------------------
511 function Is_Descendant_At_Same_Level
513 Ancestor : Tag) return Boolean
516 return CW_Membership (Descendant, Ancestor)
517 and then TSD (Descendant).Access_Level = TSD (Ancestor).Access_Level;
518 end Is_Descendant_At_Same_Level;
524 function Length (Str : Cstring_Ptr) return Natural is
528 while Str (Len) /= ASCII.Nul loop
539 function Offset_To_Top
540 (T : Tag) return System.Storage_Elements.Storage_Offset
542 Offset_To_Top_Ptr : constant Storage_Offset_Ptr :=
543 To_Storage_Offset_Ptr (To_Address (T)
544 - DT_Typeinfo_Ptr_Size
545 - DT_Offset_To_Top_Size);
547 return Offset_To_Top_Ptr.all;
555 is access function (A : System.Address) return Long_Long_Integer;
557 function To_Acc_Size is new Unchecked_Conversion (System.Address, Acc_Size);
558 -- The profile of the implicitly defined _size primitive
561 (Obj : System.Address;
562 T : Tag) return SSE.Storage_Count
564 Parent_Tag : constant Tag := TSD (T).Tags_Table (1);
565 -- The tag of the parent type through the dispatch table
567 F : constant Acc_Size := To_Acc_Size (Parent_Tag.Prims_Ptr (1));
568 -- Access to the _size primitive of the parent. We assume that
569 -- it is always in the first slot of the dispatch table
572 -- Here we compute the size of the _parent field of the object
574 return SSE.Storage_Count (F.all (Obj));
581 function Parent_Tag (T : Tag) return Tag is
587 -- The Parent_Tag of a root-level tagged type is defined to be No_Tag.
588 -- The first entry in the Ancestors_Tags array will be null for such
589 -- a type, but it's better to be explicit about returning No_Tag in
592 if TSD (T).Idepth = 0 then
595 return TSD (T).Tags_Table (1);
599 ----------------------------
600 -- Register_Interface_Tag --
601 ----------------------------
603 procedure Register_Interface_Tag
607 New_T_TSD : constant Type_Specific_Data_Ptr := TSD (T);
610 -- Check if the interface is already registered
612 if New_T_TSD.Num_Interfaces > 0 then
614 Id : Natural := New_T_TSD.Idepth + 1;
615 Last_Id : constant Natural := New_T_TSD.Idepth
616 + New_T_TSD.Num_Interfaces;
619 if New_T_TSD.Tags_Table (Id) = Interface_T then
624 exit when Id > Last_Id;
629 New_T_TSD.Num_Interfaces := New_T_TSD.Num_Interfaces + 1;
630 Index := New_T_TSD.Idepth + New_T_TSD.Num_Interfaces;
631 New_T_TSD.Tags_Table (Index) := Interface_T;
632 end Register_Interface_Tag;
638 procedure Register_Tag (T : Tag) is
640 External_Tag_HTable.Set (T);
643 ----------------------
644 -- Set_Access_Level --
645 ----------------------
647 procedure Set_Access_Level (T : Tag; Value : Natural) is
649 TSD (T).Access_Level := Value;
650 end Set_Access_Level;
652 -----------------------
653 -- Set_Expanded_Name --
654 -----------------------
656 procedure Set_Expanded_Name (T : Tag; Value : System.Address) is
658 TSD (T).Expanded_Name := To_Cstring_Ptr (Value);
659 end Set_Expanded_Name;
661 ----------------------
662 -- Set_External_Tag --
663 ----------------------
665 procedure Set_External_Tag (T : Tag; Value : System.Address) is
667 TSD (T).External_Tag := To_Cstring_Ptr (Value);
668 end Set_External_Tag;
670 -----------------------
671 -- Set_Offset_To_Top --
672 -----------------------
674 procedure Set_Offset_To_Top
676 Value : System.Storage_Elements.Storage_Offset)
678 Offset_To_Top_Ptr : constant Storage_Offset_Ptr :=
679 To_Storage_Offset_Ptr (To_Address (T)
680 - DT_Typeinfo_Ptr_Size
681 - DT_Offset_To_Top_Size);
683 Offset_To_Top_Ptr.all := Value;
684 end Set_Offset_To_Top;
686 -------------------------
687 -- Set_Prim_Op_Address --
688 -------------------------
690 procedure Set_Prim_Op_Address
693 Value : System.Address) is
695 T.Prims_Ptr (Position) := Value;
696 end Set_Prim_Op_Address;
702 procedure Set_RC_Offset (T : Tag; Value : SSE.Storage_Offset) is
704 TSD (T).RC_Offset := Value;
707 ---------------------------
708 -- Set_Remotely_Callable --
709 ---------------------------
711 procedure Set_Remotely_Callable (T : Tag; Value : Boolean) is
713 TSD (T).Remotely_Callable := Value;
714 end Set_Remotely_Callable;
720 procedure Set_TSD (T : Tag; Value : System.Address) is
721 TSD_Ptr : constant Addr_Ptr :=
722 To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
724 TSD_Ptr.all := Value;
731 function Typeinfo_Ptr (T : Tag) return System.Address is
732 TSD_Ptr : constant Addr_Ptr :=
733 To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
742 function TSD (T : Tag) return Type_Specific_Data_Ptr is
743 TSD_Ptr : constant Addr_Ptr :=
744 To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
746 return To_Type_Specific_Data_Ptr (TSD_Ptr.all);