1 ------------------------------------------------------------------------------
3 -- GNAT RUNTIME 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 ------------------------------------------------------------------------------
37 pragma Elaborate_All (System.HTable);
39 package body Ada.Tags is
41 -- Structure of the GNAT Dispatch Table
43 -- +-----------------------+
45 -- +-----------------------+
46 -- | Typeinfo_Ptr/TSD_Ptr |----> Type Specific Data
47 -- Tag ---> +-----------------------+ +-------------------+
48 -- | table of | | inheritance depth |
49 -- : primitive ops : +-------------------+
50 -- | pointers | | expanded name |
51 -- +-----------------------+ +-------------------+
53 -- +-------------------+
54 -- | Hash table link |
55 -- +-------------------+
56 -- | Remotely Callable |
57 -- +-------------------+
58 -- | Rec Ctrler offset |
59 -- +-------------------+
63 -- +-------------------+
65 subtype Cstring is String (Positive);
66 type Cstring_Ptr is access all Cstring;
68 type Tag_Table is array (Natural range <>) of Tag;
69 pragma Suppress_Initialization (Tag_Table);
70 pragma Suppress (Index_Check, On => Tag_Table);
71 -- We suppress index checks because the declared size in the record below
72 -- is a dummy size of one (see below).
74 type Wide_Boolean is new Boolean;
75 -- This name should probably be changed sometime ??? and indeed probably
76 -- this field could simply be of type Standard.Boolean.
78 type Type_Specific_Data is record
80 Expanded_Name : Cstring_Ptr;
81 External_Tag : Cstring_Ptr;
83 Remotely_Callable : Wide_Boolean;
84 RC_Offset : SSE.Storage_Offset;
85 Ancestor_Tags : Tag_Table (0 .. 1);
87 -- The size of the Ancestor_Tags array actually depends on the tagged type
88 -- to which it applies. We are using the same mechanism as for the
89 -- Prims_Ptr array in the Dispatch_Table record. See comments below for
92 type Dispatch_Table is record
93 -- Offset_To_Top : Integer := 0;
94 -- Typeinfo_Ptr : System.Address; -- Currently TSD is also here???
95 Prims_Ptr : Address_Array (Positive);
98 -- Note on the commented out fields of the Dispatch_Table
99 -- ------------------------------------------------------
100 -- According to the C++ ABI the components Offset_To_Top and Typeinfo_Ptr
101 -- are stored just "before" the dispatch table (that is, the Prims_Ptr
102 -- table), and they are referenced with negative offsets referring to the
103 -- base of the dispatch table. The _Tag (or the VTable_Ptr in C++ termi-
104 -- nology) must point to the base of the virtual table, just after these
105 -- components, to point to the Prims_Ptr table. For this purpose the
106 -- expander generates a Prims_Ptr table that has enough space for these
107 -- additional components, and generates code that displaces the _Tag to
108 -- point after these components.
109 -- -----------------------------------------------------------------------
111 -- The size of the Prims_Ptr array actually depends on the tagged type to
112 -- which it applies. For each tagged type, the expander computes the
113 -- actual array size, allocates the Dispatch_Table record accordingly, and
114 -- generates code that displaces the base of the record after the
115 -- Typeinfo_Ptr component. For this reason the first two components have
116 -- been commented in the previous declaration. The access to these
117 -- components is done by means of local functions.
119 -- To avoid the use of discriminants to define the actual size of the
120 -- dispatch table, we used to declare the tag as a pointer to a record
121 -- that contains an arbitrary array of addresses, using Positive as its
122 -- index. This ensures that there are never range checks when accessing
123 -- the dispatch table, but it prevents GDB from displaying tagged types
124 -- properly. A better approach is to declare this record type as holding a
125 -- small number of addresses, and to explicitly suppress checks on it.
127 -- Note that in both cases, this type is never allocated, and serves only
128 -- to declare the corresponding access type.
130 ---------------------------------------------
131 -- Unchecked Conversions for String Fields --
132 ---------------------------------------------
134 function To_Cstring_Ptr is
135 new Unchecked_Conversion (System.Address, Cstring_Ptr);
137 function To_Address is
138 new Unchecked_Conversion (Cstring_Ptr, System.Address);
140 -----------------------------------------------------------
141 -- Unchecked Conversions for the component offset_to_top --
142 -----------------------------------------------------------
144 type Int_Ptr is access Integer;
146 function To_Int_Ptr is
147 new Unchecked_Conversion (System.Address, Int_Ptr);
149 -----------------------
150 -- Local Subprograms --
151 -----------------------
153 function Length (Str : Cstring_Ptr) return Natural;
154 -- Length of string represented by the given pointer (treating the string
155 -- as a C-style string, which is Nul terminated).
157 function Offset_To_Top (T : Tag) return Integer;
158 -- Returns the current value of the offset_to_top component available in
159 -- the prologue of the dispatch table.
161 function Typeinfo_Ptr (T : Tag) return System.Address;
162 -- Returns the current value of the typeinfo_ptr component available in
163 -- the prologue of the dispatch table.
165 pragma Unreferenced (Offset_To_Top);
166 pragma Unreferenced (Typeinfo_Ptr);
167 -- These functions will be used for full compatibility with the C++ ABI
169 -------------------------
170 -- External_Tag_HTable --
171 -------------------------
173 type HTable_Headers is range 1 .. 64;
175 -- The following internal package defines the routines used for the
176 -- instantiation of a new System.HTable.Static_HTable (see below). See
177 -- spec in g-htable.ads for details of usage.
179 package HTable_Subprograms is
180 procedure Set_HT_Link (T : Tag; Next : Tag);
181 function Get_HT_Link (T : Tag) return Tag;
182 function Hash (F : System.Address) return HTable_Headers;
183 function Equal (A, B : System.Address) return Boolean;
184 end HTable_Subprograms;
186 package External_Tag_HTable is new System.HTable.Static_HTable (
187 Header_Num => HTable_Headers,
188 Element => Dispatch_Table,
191 Set_Next => HTable_Subprograms.Set_HT_Link,
192 Next => HTable_Subprograms.Get_HT_Link,
193 Key => System.Address,
194 Get_Key => Get_External_Tag,
195 Hash => HTable_Subprograms.Hash,
196 Equal => HTable_Subprograms.Equal);
198 ------------------------
199 -- HTable_Subprograms --
200 ------------------------
202 -- Bodies of routines for hash table instantiation
204 package body HTable_Subprograms is
210 function Equal (A, B : System.Address) return Boolean is
211 Str1 : constant Cstring_Ptr := To_Cstring_Ptr (A);
212 Str2 : constant Cstring_Ptr := To_Cstring_Ptr (B);
217 if Str1 (J) /= Str2 (J) then
220 elsif Str1 (J) = ASCII.NUL then
233 function Get_HT_Link (T : Tag) return Tag is
235 return TSD (T).HT_Link;
242 function Hash (F : System.Address) return HTable_Headers is
243 function H is new System.HTable.Hash (HTable_Headers);
244 Str : constant Cstring_Ptr := To_Cstring_Ptr (F);
245 Res : constant HTable_Headers := H (Str (1 .. Length (Str)));
254 procedure Set_HT_Link (T : Tag; Next : Tag) is
256 TSD (T).HT_Link := Next;
259 end HTable_Subprograms;
265 -- Canonical implementation of Classwide Membership corresponding to:
269 -- Each dispatch table contains a reference to a table of ancestors
270 -- (Ancestor_Tags) and a count of the level of inheritance "Idepth" .
272 -- Obj is in Typ'Class if Typ'Tag is in the table of ancestors that are
273 -- contained in the dispatch table referenced by Obj'Tag . Knowing the
274 -- level of inheritance of both types, this can be computed in constant
275 -- time by the formula:
277 -- Obj'tag.TSD.Ancestor_Tags (Obj'tag.TSD.Idepth - Typ'tag.TSD.Idepth)
280 function CW_Membership (Obj_Tag : Tag; Typ_Tag : Tag) return Boolean is
281 Pos : constant Integer := TSD (Obj_Tag).Idepth - TSD (Typ_Tag).Idepth;
283 return Pos >= 0 and then TSD (Obj_Tag).Ancestor_Tags (Pos) = Typ_Tag;
290 function Expanded_Name (T : Tag) return String is
291 Result : constant Cstring_Ptr := TSD (T).Expanded_Name;
293 return Result (1 .. Length (Result));
300 function External_Tag (T : Tag) return String is
301 Result : constant Cstring_Ptr := TSD (T).External_Tag;
303 return Result (1 .. Length (Result));
306 ----------------------
307 -- Get_External_Tag --
308 ----------------------
310 function Get_External_Tag (T : Tag) return System.Address is
312 return To_Address (TSD (T).External_Tag);
313 end Get_External_Tag;
315 -------------------------
316 -- Get_Prim_Op_Address --
317 -------------------------
319 function Get_Prim_Op_Address
321 Position : Positive) return System.Address
324 return T.Prims_Ptr (Position);
325 end Get_Prim_Op_Address;
331 function Get_RC_Offset (T : Tag) return SSE.Storage_Offset is
333 return TSD (T).RC_Offset;
336 ---------------------------
337 -- Get_Remotely_Callable --
338 ---------------------------
340 function Get_Remotely_Callable (T : Tag) return Boolean is
342 return TSD (T).Remotely_Callable = True;
343 end Get_Remotely_Callable;
352 Entry_Count : Natural)
355 if Old_T /= null then
356 New_T.Prims_Ptr (1 .. Entry_Count) :=
357 Old_T.Prims_Ptr (1 .. Entry_Count);
365 procedure Inherit_TSD (Old_Tag : Tag; New_Tag : Tag) is
366 New_TSD_Ptr : constant Type_Specific_Data_Ptr := TSD (New_Tag);
367 Old_TSD_Ptr : Type_Specific_Data_Ptr;
370 if Old_Tag /= null then
371 Old_TSD_Ptr := TSD (Old_Tag);
372 New_TSD_Ptr.Idepth := Old_TSD_Ptr.Idepth + 1;
373 New_TSD_Ptr.Ancestor_Tags (1 .. New_TSD_Ptr.Idepth) :=
374 Old_TSD_Ptr.Ancestor_Tags (0 .. Old_TSD_Ptr.Idepth);
376 New_TSD_Ptr.Idepth := 0;
379 New_TSD_Ptr.Ancestor_Tags (0) := New_Tag;
386 function Internal_Tag (External : String) return Tag is
387 Ext_Copy : aliased String (External'First .. External'Last + 1);
391 -- Make a copy of the string representing the external tag with
394 Ext_Copy (External'Range) := External;
395 Ext_Copy (Ext_Copy'Last) := ASCII.NUL;
396 Res := External_Tag_HTable.Get (Ext_Copy'Address);
400 Msg1 : constant String := "unknown tagged type: ";
401 Msg2 : String (1 .. Msg1'Length + External'Length);
403 Msg2 (1 .. Msg1'Length) := Msg1;
404 Msg2 (Msg1'Length + 1 .. Msg1'Length + External'Length) :=
406 Ada.Exceptions.Raise_Exception (Tag_Error'Identity, Msg2);
417 function Length (Str : Cstring_Ptr) return Natural is
421 while Str (Len) /= ASCII.Nul loop
433 is access function (A : System.Address) return Long_Long_Integer;
435 function To_Acc_Size is new Unchecked_Conversion (System.Address, Acc_Size);
436 -- The profile of the implicitly defined _size primitive
439 (Obj : System.Address;
440 T : Tag) return SSE.Storage_Count
442 Parent_Tag : constant Tag := TSD (T).Ancestor_Tags (1);
443 -- The tag of the parent type through the dispatch table
445 F : constant Acc_Size := To_Acc_Size (Parent_Tag.Prims_Ptr (1));
446 -- Access to the _size primitive of the parent. We assume that
447 -- it is always in the first slot of the distatch table
450 -- Here we compute the size of the _parent field of the object
452 return SSE.Storage_Count (F.all (Obj));
459 function Parent_Tag (T : Tag) return Tag is
461 return TSD (T).Ancestor_Tags (1);
468 procedure Register_Tag (T : Tag) is
470 External_Tag_HTable.Set (T);
473 -----------------------
474 -- Set_Expanded_Name --
475 -----------------------
477 procedure Set_Expanded_Name (T : Tag; Value : System.Address) is
479 TSD (T).Expanded_Name := To_Cstring_Ptr (Value);
480 end Set_Expanded_Name;
482 ----------------------
483 -- Set_External_Tag --
484 ----------------------
486 procedure Set_External_Tag (T : Tag; Value : System.Address) is
488 TSD (T).External_Tag := To_Cstring_Ptr (Value);
489 end Set_External_Tag;
491 -------------------------
492 -- Set_Prim_Op_Address --
493 -------------------------
495 procedure Set_Prim_Op_Address
498 Value : System.Address)
501 T.Prims_Ptr (Position) := Value;
502 end Set_Prim_Op_Address;
508 procedure Set_RC_Offset (T : Tag; Value : SSE.Storage_Offset) is
510 TSD (T).RC_Offset := Value;
513 ---------------------------
514 -- Set_Remotely_Callable --
515 ---------------------------
517 procedure Set_Remotely_Callable (T : Tag; Value : Boolean) is
520 TSD (T).Remotely_Callable := True;
522 TSD (T).Remotely_Callable := False;
524 end Set_Remotely_Callable;
530 procedure Set_TSD (T : Tag; Value : System.Address) is
531 use type System.Storage_Elements.Storage_Offset;
532 TSD_Ptr : constant Addr_Ptr :=
533 To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
535 TSD_Ptr.all := Value;
542 function Offset_To_Top (T : Tag) return Integer is
543 use type System.Storage_Elements.Storage_Offset;
544 TSD_Ptr : constant Int_Ptr :=
545 To_Int_Ptr (To_Address (T) - DT_Prologue_Size);
554 function Typeinfo_Ptr (T : Tag) return System.Address is
555 use type System.Storage_Elements.Storage_Offset;
556 TSD_Ptr : constant Addr_Ptr :=
557 To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
566 function TSD (T : Tag) return Type_Specific_Data_Ptr is
567 use type System.Storage_Elements.Storage_Offset;
568 TSD_Ptr : constant Addr_Ptr :=
569 To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
571 return To_Type_Specific_Data_Ptr (TSD_Ptr.all);