111
|
1 ------------------------------------------------------------------------------
|
|
2 -- --
|
|
3 -- GNAT RUN-TIME COMPONENTS --
|
|
4 -- --
|
|
5 -- A D A . T A G S --
|
|
6 -- --
|
|
7 -- B o d y --
|
|
8 -- --
|
|
9 -- Copyright (C) 1992-2017, Free Software Foundation, Inc. --
|
|
10 -- --
|
|
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 3, 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. --
|
|
17 -- --
|
|
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
|
|
19 -- additional permissions described in the GCC Runtime Library Exception, --
|
|
20 -- version 3.1, as published by the Free Software Foundation. --
|
|
21 -- --
|
|
22 -- You should have received a copy of the GNU General Public License and --
|
|
23 -- a copy of the GCC Runtime Library Exception along with this program; --
|
|
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
|
|
25 -- <http://www.gnu.org/licenses/>. --
|
|
26 -- --
|
|
27 -- GNAT was originally developed by the GNAT team at New York University. --
|
|
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
|
|
29 -- --
|
|
30 ------------------------------------------------------------------------------
|
|
31
|
|
32 with Ada.Exceptions;
|
|
33 with Ada.Unchecked_Conversion;
|
|
34
|
|
35 with System.HTable;
|
|
36 with System.Storage_Elements; use System.Storage_Elements;
|
|
37 with System.WCh_Con; use System.WCh_Con;
|
|
38 with System.WCh_StW; use System.WCh_StW;
|
|
39
|
|
40 pragma Elaborate (System.HTable);
|
|
41 -- Elaborate needed instead of Elaborate_All to avoid elaboration cycles
|
|
42 -- when polling is turned on. This is safe because HTable doesn't do anything
|
|
43 -- at elaboration time; it just contains a generic package we want to
|
|
44 -- instantiate.
|
|
45
|
|
46 package body Ada.Tags is
|
|
47
|
|
48 -----------------------
|
|
49 -- Local Subprograms --
|
|
50 -----------------------
|
|
51
|
|
52 function CW_Membership (Obj_Tag : Tag; Typ_Tag : Tag) return Boolean;
|
|
53 -- Given the tag of an object and the tag associated to a type, return
|
|
54 -- true if Obj is in Typ'Class.
|
|
55
|
|
56 function Get_External_Tag (T : Tag) return System.Address;
|
|
57 -- Returns address of a null terminated string containing the external name
|
|
58
|
|
59 function Is_Primary_DT (T : Tag) return Boolean;
|
|
60 -- Given a tag returns True if it has the signature of a primary dispatch
|
|
61 -- table. This is Inline_Always since it is called from other Inline_
|
|
62 -- Always subprograms where we want no out of line code to be generated.
|
|
63
|
|
64 function IW_Membership
|
|
65 (Descendant_TSD : Type_Specific_Data_Ptr;
|
|
66 T : Tag) return Boolean;
|
|
67 -- Subsidiary function of IW_Membership and CW_Membership which factorizes
|
|
68 -- the functionality needed to check if a given descendant implements an
|
|
69 -- interface tag T.
|
|
70
|
|
71 function Length (Str : Cstring_Ptr) return Natural;
|
|
72 -- Length of string represented by the given pointer (treating the string
|
|
73 -- as a C-style string, which is Nul terminated). See comment in body
|
|
74 -- explaining why we cannot use the normal strlen built-in.
|
|
75
|
|
76 function OSD (T : Tag) return Object_Specific_Data_Ptr;
|
|
77 -- Ada 2005 (AI-251): Given a pointer T to a secondary dispatch table,
|
|
78 -- retrieve the address of the record containing the Object Specific
|
|
79 -- Data table.
|
|
80
|
|
81 function SSD (T : Tag) return Select_Specific_Data_Ptr;
|
|
82 -- Ada 2005 (AI-251): Given a pointer T to a dispatch Table, retrieves the
|
|
83 -- address of the record containing the Select Specific Data in T's TSD.
|
|
84
|
|
85 pragma Inline_Always (CW_Membership);
|
|
86 pragma Inline_Always (Get_External_Tag);
|
|
87 pragma Inline_Always (Is_Primary_DT);
|
|
88 pragma Inline_Always (OSD);
|
|
89 pragma Inline_Always (SSD);
|
|
90
|
|
91 -- Unchecked conversions
|
|
92
|
|
93 function To_Address is
|
|
94 new Unchecked_Conversion (Cstring_Ptr, System.Address);
|
|
95
|
|
96 function To_Cstring_Ptr is
|
|
97 new Unchecked_Conversion (System.Address, Cstring_Ptr);
|
|
98
|
|
99 -- Disable warnings on possible aliasing problem
|
|
100
|
|
101 function To_Tag is
|
|
102 new Unchecked_Conversion (Integer_Address, Tag);
|
|
103
|
|
104 function To_Addr_Ptr is
|
|
105 new Ada.Unchecked_Conversion (System.Address, Addr_Ptr);
|
|
106
|
|
107 function To_Address is
|
|
108 new Ada.Unchecked_Conversion (Tag, System.Address);
|
|
109
|
|
110 function To_Dispatch_Table_Ptr is
|
|
111 new Ada.Unchecked_Conversion (Tag, Dispatch_Table_Ptr);
|
|
112
|
|
113 function To_Dispatch_Table_Ptr is
|
|
114 new Ada.Unchecked_Conversion (System.Address, Dispatch_Table_Ptr);
|
|
115
|
|
116 function To_Object_Specific_Data_Ptr is
|
|
117 new Ada.Unchecked_Conversion (System.Address, Object_Specific_Data_Ptr);
|
|
118
|
|
119 function To_Tag_Ptr is
|
|
120 new Ada.Unchecked_Conversion (System.Address, Tag_Ptr);
|
|
121
|
|
122 function To_Type_Specific_Data_Ptr is
|
|
123 new Ada.Unchecked_Conversion (System.Address, Type_Specific_Data_Ptr);
|
|
124
|
|
125 -------------------------------
|
|
126 -- Inline_Always Subprograms --
|
|
127 -------------------------------
|
|
128
|
|
129 -- Inline_always subprograms must be placed before their first call to
|
|
130 -- avoid defeating the frontend inlining mechanism and thus ensure the
|
|
131 -- generation of their correct debug info.
|
|
132
|
|
133 -------------------
|
|
134 -- CW_Membership --
|
|
135 -------------------
|
|
136
|
|
137 -- Canonical implementation of Classwide Membership corresponding to:
|
|
138
|
|
139 -- Obj in Typ'Class
|
|
140
|
|
141 -- Each dispatch table contains a reference to a table of ancestors (stored
|
|
142 -- in the first part of the Tags_Table) and a count of the level of
|
|
143 -- inheritance "Idepth".
|
|
144
|
|
145 -- Obj is in Typ'Class if Typ'Tag is in the table of ancestors that are
|
|
146 -- contained in the dispatch table referenced by Obj'Tag . Knowing the
|
|
147 -- level of inheritance of both types, this can be computed in constant
|
|
148 -- time by the formula:
|
|
149
|
|
150 -- TSD (Obj'tag).Tags_Table (TSD (Obj'tag).Idepth - TSD (Typ'tag).Idepth)
|
|
151 -- = Typ'tag
|
|
152
|
|
153 function CW_Membership (Obj_Tag : Tag; Typ_Tag : Tag) return Boolean is
|
|
154 Obj_TSD_Ptr : constant Addr_Ptr :=
|
|
155 To_Addr_Ptr (To_Address (Obj_Tag) - DT_Typeinfo_Ptr_Size);
|
|
156 Typ_TSD_Ptr : constant Addr_Ptr :=
|
|
157 To_Addr_Ptr (To_Address (Typ_Tag) - DT_Typeinfo_Ptr_Size);
|
|
158 Obj_TSD : constant Type_Specific_Data_Ptr :=
|
|
159 To_Type_Specific_Data_Ptr (Obj_TSD_Ptr.all);
|
|
160 Typ_TSD : constant Type_Specific_Data_Ptr :=
|
|
161 To_Type_Specific_Data_Ptr (Typ_TSD_Ptr.all);
|
|
162 Pos : constant Integer := Obj_TSD.Idepth - Typ_TSD.Idepth;
|
|
163 begin
|
|
164 return Pos >= 0 and then Obj_TSD.Tags_Table (Pos) = Typ_Tag;
|
|
165 end CW_Membership;
|
|
166
|
|
167 ----------------------
|
|
168 -- Get_External_Tag --
|
|
169 ----------------------
|
|
170
|
|
171 function Get_External_Tag (T : Tag) return System.Address is
|
|
172 TSD_Ptr : constant Addr_Ptr :=
|
|
173 To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
|
|
174 TSD : constant Type_Specific_Data_Ptr :=
|
|
175 To_Type_Specific_Data_Ptr (TSD_Ptr.all);
|
|
176 begin
|
|
177 return To_Address (TSD.External_Tag);
|
|
178 end Get_External_Tag;
|
|
179
|
|
180 -----------------
|
|
181 -- Is_Abstract --
|
|
182 -----------------
|
|
183
|
|
184 function Is_Abstract (T : Tag) return Boolean is
|
|
185 TSD_Ptr : Addr_Ptr;
|
|
186 TSD : Type_Specific_Data_Ptr;
|
|
187
|
|
188 begin
|
|
189 if T = No_Tag then
|
|
190 raise Tag_Error;
|
|
191 end if;
|
|
192
|
|
193 TSD_Ptr := To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
|
|
194 TSD := To_Type_Specific_Data_Ptr (TSD_Ptr.all);
|
|
195 return TSD.Is_Abstract;
|
|
196 end Is_Abstract;
|
|
197
|
|
198 -------------------
|
|
199 -- Is_Primary_DT --
|
|
200 -------------------
|
|
201
|
|
202 function Is_Primary_DT (T : Tag) return Boolean is
|
|
203 begin
|
|
204 return DT (T).Signature = Primary_DT;
|
|
205 end Is_Primary_DT;
|
|
206
|
|
207 ---------
|
|
208 -- OSD --
|
|
209 ---------
|
|
210
|
|
211 function OSD (T : Tag) return Object_Specific_Data_Ptr is
|
|
212 OSD_Ptr : constant Addr_Ptr :=
|
|
213 To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
|
|
214 begin
|
|
215 return To_Object_Specific_Data_Ptr (OSD_Ptr.all);
|
|
216 end OSD;
|
|
217
|
|
218 ---------
|
|
219 -- SSD --
|
|
220 ---------
|
|
221
|
|
222 function SSD (T : Tag) return Select_Specific_Data_Ptr is
|
|
223 TSD_Ptr : constant Addr_Ptr :=
|
|
224 To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
|
|
225 TSD : constant Type_Specific_Data_Ptr :=
|
|
226 To_Type_Specific_Data_Ptr (TSD_Ptr.all);
|
|
227 begin
|
|
228 return TSD.SSD;
|
|
229 end SSD;
|
|
230
|
|
231 -------------------------
|
|
232 -- External_Tag_HTable --
|
|
233 -------------------------
|
|
234
|
|
235 type HTable_Headers is range 1 .. 64;
|
|
236
|
|
237 -- The following internal package defines the routines used for the
|
|
238 -- instantiation of a new System.HTable.Static_HTable (see below). See
|
|
239 -- spec in g-htable.ads for details of usage.
|
|
240
|
|
241 package HTable_Subprograms is
|
|
242 procedure Set_HT_Link (T : Tag; Next : Tag);
|
|
243 function Get_HT_Link (T : Tag) return Tag;
|
|
244 function Hash (F : System.Address) return HTable_Headers;
|
|
245 function Equal (A, B : System.Address) return Boolean;
|
|
246 end HTable_Subprograms;
|
|
247
|
|
248 package External_Tag_HTable is new System.HTable.Static_HTable (
|
|
249 Header_Num => HTable_Headers,
|
|
250 Element => Dispatch_Table,
|
|
251 Elmt_Ptr => Tag,
|
|
252 Null_Ptr => null,
|
|
253 Set_Next => HTable_Subprograms.Set_HT_Link,
|
|
254 Next => HTable_Subprograms.Get_HT_Link,
|
|
255 Key => System.Address,
|
|
256 Get_Key => Get_External_Tag,
|
|
257 Hash => HTable_Subprograms.Hash,
|
|
258 Equal => HTable_Subprograms.Equal);
|
|
259
|
|
260 ------------------------
|
|
261 -- HTable_Subprograms --
|
|
262 ------------------------
|
|
263
|
|
264 -- Bodies of routines for hash table instantiation
|
|
265
|
|
266 package body HTable_Subprograms is
|
|
267
|
|
268 -----------
|
|
269 -- Equal --
|
|
270 -----------
|
|
271
|
|
272 function Equal (A, B : System.Address) return Boolean is
|
|
273 Str1 : constant Cstring_Ptr := To_Cstring_Ptr (A);
|
|
274 Str2 : constant Cstring_Ptr := To_Cstring_Ptr (B);
|
|
275 J : Integer;
|
|
276 begin
|
|
277 J := 1;
|
|
278 loop
|
|
279 if Str1 (J) /= Str2 (J) then
|
|
280 return False;
|
|
281 elsif Str1 (J) = ASCII.NUL then
|
|
282 return True;
|
|
283 else
|
|
284 J := J + 1;
|
|
285 end if;
|
|
286 end loop;
|
|
287 end Equal;
|
|
288
|
|
289 -----------------
|
|
290 -- Get_HT_Link --
|
|
291 -----------------
|
|
292
|
|
293 function Get_HT_Link (T : Tag) return Tag is
|
|
294 TSD_Ptr : constant Addr_Ptr :=
|
|
295 To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
|
|
296 TSD : constant Type_Specific_Data_Ptr :=
|
|
297 To_Type_Specific_Data_Ptr (TSD_Ptr.all);
|
|
298 begin
|
|
299 return TSD.HT_Link.all;
|
|
300 end Get_HT_Link;
|
|
301
|
|
302 ----------
|
|
303 -- Hash --
|
|
304 ----------
|
|
305
|
|
306 function Hash (F : System.Address) return HTable_Headers is
|
|
307 function H is new System.HTable.Hash (HTable_Headers);
|
|
308 Str : constant Cstring_Ptr := To_Cstring_Ptr (F);
|
|
309 Res : constant HTable_Headers := H (Str (1 .. Length (Str)));
|
|
310 begin
|
|
311 return Res;
|
|
312 end Hash;
|
|
313
|
|
314 -----------------
|
|
315 -- Set_HT_Link --
|
|
316 -----------------
|
|
317
|
|
318 procedure Set_HT_Link (T : Tag; Next : Tag) is
|
|
319 TSD_Ptr : constant Addr_Ptr :=
|
|
320 To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
|
|
321 TSD : constant Type_Specific_Data_Ptr :=
|
|
322 To_Type_Specific_Data_Ptr (TSD_Ptr.all);
|
|
323 begin
|
|
324 TSD.HT_Link.all := Next;
|
|
325 end Set_HT_Link;
|
|
326
|
|
327 end HTable_Subprograms;
|
|
328
|
|
329 ------------------
|
|
330 -- Base_Address --
|
|
331 ------------------
|
|
332
|
|
333 function Base_Address (This : System.Address) return System.Address is
|
|
334 begin
|
|
335 return This - Offset_To_Top (This);
|
|
336 end Base_Address;
|
|
337
|
|
338 ---------------
|
|
339 -- Check_TSD --
|
|
340 ---------------
|
|
341
|
|
342 procedure Check_TSD (TSD : Type_Specific_Data_Ptr) is
|
|
343 T : Tag;
|
|
344
|
|
345 E_Tag_Len : constant Integer := Length (TSD.External_Tag);
|
|
346 E_Tag : String (1 .. E_Tag_Len);
|
|
347 for E_Tag'Address use TSD.External_Tag.all'Address;
|
|
348 pragma Import (Ada, E_Tag);
|
|
349
|
|
350 Dup_Ext_Tag : constant String := "duplicated external tag """;
|
|
351
|
|
352 begin
|
|
353 -- Verify that the external tag of this TSD is not registered in the
|
|
354 -- runtime hash table.
|
|
355
|
|
356 T := External_Tag_HTable.Get (To_Address (TSD.External_Tag));
|
|
357
|
|
358 if T /= null then
|
|
359
|
|
360 -- Avoid concatenation, as it is not allowed in no run time mode
|
|
361
|
|
362 declare
|
|
363 Msg : String (1 .. Dup_Ext_Tag'Length + E_Tag_Len + 1);
|
|
364 begin
|
|
365 Msg (1 .. Dup_Ext_Tag'Length) := Dup_Ext_Tag;
|
|
366 Msg (Dup_Ext_Tag'Length + 1 .. Dup_Ext_Tag'Length + E_Tag_Len) :=
|
|
367 E_Tag;
|
|
368 Msg (Msg'Last) := '"';
|
|
369 raise Program_Error with Msg;
|
|
370 end;
|
|
371 end if;
|
|
372 end Check_TSD;
|
|
373
|
|
374 --------------------
|
|
375 -- Descendant_Tag --
|
|
376 --------------------
|
|
377
|
|
378 function Descendant_Tag (External : String; Ancestor : Tag) return Tag is
|
|
379 Int_Tag : constant Tag := Internal_Tag (External);
|
|
380 begin
|
|
381 if not Is_Descendant_At_Same_Level (Int_Tag, Ancestor) then
|
|
382 raise Tag_Error;
|
|
383 else
|
|
384 return Int_Tag;
|
|
385 end if;
|
|
386 end Descendant_Tag;
|
|
387
|
|
388 --------------
|
|
389 -- Displace --
|
|
390 --------------
|
|
391
|
|
392 function Displace (This : System.Address; T : Tag) return System.Address is
|
|
393 Iface_Table : Interface_Data_Ptr;
|
|
394 Obj_Base : System.Address;
|
|
395 Obj_DT : Dispatch_Table_Ptr;
|
|
396 Obj_DT_Tag : Tag;
|
|
397
|
|
398 begin
|
|
399 if System."=" (This, System.Null_Address) then
|
|
400 return System.Null_Address;
|
|
401 end if;
|
|
402
|
|
403 Obj_Base := Base_Address (This);
|
|
404 Obj_DT_Tag := To_Tag_Ptr (Obj_Base).all;
|
|
405 Obj_DT := DT (To_Tag_Ptr (Obj_Base).all);
|
|
406 Iface_Table := To_Type_Specific_Data_Ptr (Obj_DT.TSD).Interfaces_Table;
|
|
407
|
|
408 if Iface_Table /= null then
|
|
409 for Id in 1 .. Iface_Table.Nb_Ifaces loop
|
|
410 if Iface_Table.Ifaces_Table (Id).Iface_Tag = T then
|
|
411
|
|
412 -- Case of Static value of Offset_To_Top
|
|
413
|
|
414 if Iface_Table.Ifaces_Table (Id).Static_Offset_To_Top then
|
|
415 Obj_Base := Obj_Base +
|
|
416 Iface_Table.Ifaces_Table (Id).Offset_To_Top_Value;
|
|
417
|
|
418 -- Otherwise call the function generated by the expander to
|
|
419 -- provide the value.
|
|
420
|
|
421 else
|
|
422 Obj_Base := Obj_Base +
|
|
423 Iface_Table.Ifaces_Table (Id).Offset_To_Top_Func.all
|
|
424 (Obj_Base);
|
|
425 end if;
|
|
426
|
|
427 return Obj_Base;
|
|
428 end if;
|
|
429 end loop;
|
|
430 end if;
|
|
431
|
|
432 -- Check if T is an immediate ancestor. This is required to handle
|
|
433 -- conversion of class-wide interfaces to tagged types.
|
|
434
|
|
435 if CW_Membership (Obj_DT_Tag, T) then
|
|
436 return Obj_Base;
|
|
437 end if;
|
|
438
|
|
439 -- If the object does not implement the interface we must raise CE
|
|
440
|
|
441 raise Constraint_Error with "invalid interface conversion";
|
|
442 end Displace;
|
|
443
|
|
444 --------
|
|
445 -- DT --
|
|
446 --------
|
|
447
|
|
448 function DT (T : Tag) return Dispatch_Table_Ptr is
|
|
449 Offset : constant SSE.Storage_Offset :=
|
|
450 To_Dispatch_Table_Ptr (T).Prims_Ptr'Position;
|
|
451 begin
|
|
452 return To_Dispatch_Table_Ptr (To_Address (T) - Offset);
|
|
453 end DT;
|
|
454
|
|
455 -------------------
|
|
456 -- IW_Membership --
|
|
457 -------------------
|
|
458
|
|
459 function IW_Membership
|
|
460 (Descendant_TSD : Type_Specific_Data_Ptr;
|
|
461 T : Tag) return Boolean
|
|
462 is
|
|
463 Iface_Table : Interface_Data_Ptr;
|
|
464
|
|
465 begin
|
|
466 Iface_Table := Descendant_TSD.Interfaces_Table;
|
|
467
|
|
468 if Iface_Table /= null then
|
|
469 for Id in 1 .. Iface_Table.Nb_Ifaces loop
|
|
470 if Iface_Table.Ifaces_Table (Id).Iface_Tag = T then
|
|
471 return True;
|
|
472 end if;
|
|
473 end loop;
|
|
474 end if;
|
|
475
|
|
476 -- Look for the tag in the ancestor tags table. This is required for:
|
|
477 -- Iface_CW in Typ'Class
|
|
478
|
|
479 for Id in 0 .. Descendant_TSD.Idepth loop
|
|
480 if Descendant_TSD.Tags_Table (Id) = T then
|
|
481 return True;
|
|
482 end if;
|
|
483 end loop;
|
|
484
|
|
485 return False;
|
|
486 end IW_Membership;
|
|
487
|
|
488 -------------------
|
|
489 -- IW_Membership --
|
|
490 -------------------
|
|
491
|
|
492 -- Canonical implementation of Classwide Membership corresponding to:
|
|
493
|
|
494 -- Obj in Iface'Class
|
|
495
|
|
496 -- Each dispatch table contains a table with the tags of all the
|
|
497 -- implemented interfaces.
|
|
498
|
|
499 -- Obj is in Iface'Class if Iface'Tag is found in the table of interfaces
|
|
500 -- that are contained in the dispatch table referenced by Obj'Tag.
|
|
501
|
|
502 function IW_Membership (This : System.Address; T : Tag) return Boolean is
|
|
503 Obj_Base : System.Address;
|
|
504 Obj_DT : Dispatch_Table_Ptr;
|
|
505 Obj_TSD : Type_Specific_Data_Ptr;
|
|
506
|
|
507 begin
|
|
508 Obj_Base := Base_Address (This);
|
|
509 Obj_DT := DT (To_Tag_Ptr (Obj_Base).all);
|
|
510 Obj_TSD := To_Type_Specific_Data_Ptr (Obj_DT.TSD);
|
|
511
|
|
512 return IW_Membership (Obj_TSD, T);
|
|
513 end IW_Membership;
|
|
514
|
|
515 -------------------
|
|
516 -- Expanded_Name --
|
|
517 -------------------
|
|
518
|
|
519 function Expanded_Name (T : Tag) return String is
|
|
520 Result : Cstring_Ptr;
|
|
521 TSD_Ptr : Addr_Ptr;
|
|
522 TSD : Type_Specific_Data_Ptr;
|
|
523
|
|
524 begin
|
|
525 if T = No_Tag then
|
|
526 raise Tag_Error;
|
|
527 end if;
|
|
528
|
|
529 TSD_Ptr := To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
|
|
530 TSD := To_Type_Specific_Data_Ptr (TSD_Ptr.all);
|
|
531 Result := TSD.Expanded_Name;
|
|
532 return Result (1 .. Length (Result));
|
|
533 end Expanded_Name;
|
|
534
|
|
535 ------------------
|
|
536 -- External_Tag --
|
|
537 ------------------
|
|
538
|
|
539 function External_Tag (T : Tag) return String is
|
|
540 Result : Cstring_Ptr;
|
|
541 TSD_Ptr : Addr_Ptr;
|
|
542 TSD : Type_Specific_Data_Ptr;
|
|
543
|
|
544 begin
|
|
545 if T = No_Tag then
|
|
546 raise Tag_Error;
|
|
547 end if;
|
|
548
|
|
549 TSD_Ptr := To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
|
|
550 TSD := To_Type_Specific_Data_Ptr (TSD_Ptr.all);
|
|
551 Result := TSD.External_Tag;
|
|
552 return Result (1 .. Length (Result));
|
|
553 end External_Tag;
|
|
554
|
|
555 ---------------------
|
|
556 -- Get_Entry_Index --
|
|
557 ---------------------
|
|
558
|
|
559 function Get_Entry_Index (T : Tag; Position : Positive) return Positive is
|
|
560 begin
|
|
561 return SSD (T).SSD_Table (Position).Index;
|
|
562 end Get_Entry_Index;
|
|
563
|
|
564 ----------------------
|
|
565 -- Get_Prim_Op_Kind --
|
|
566 ----------------------
|
|
567
|
|
568 function Get_Prim_Op_Kind
|
|
569 (T : Tag;
|
|
570 Position : Positive) return Prim_Op_Kind
|
|
571 is
|
|
572 begin
|
|
573 return SSD (T).SSD_Table (Position).Kind;
|
|
574 end Get_Prim_Op_Kind;
|
|
575
|
|
576 ----------------------
|
|
577 -- Get_Offset_Index --
|
|
578 ----------------------
|
|
579
|
|
580 function Get_Offset_Index
|
|
581 (T : Tag;
|
|
582 Position : Positive) return Positive
|
|
583 is
|
|
584 begin
|
|
585 if Is_Primary_DT (T) then
|
|
586 return Position;
|
|
587 else
|
|
588 return OSD (T).OSD_Table (Position);
|
|
589 end if;
|
|
590 end Get_Offset_Index;
|
|
591
|
|
592 ---------------------
|
|
593 -- Get_Tagged_Kind --
|
|
594 ---------------------
|
|
595
|
|
596 function Get_Tagged_Kind (T : Tag) return Tagged_Kind is
|
|
597 begin
|
|
598 return DT (T).Tag_Kind;
|
|
599 end Get_Tagged_Kind;
|
|
600
|
|
601 -----------------------------
|
|
602 -- Interface_Ancestor_Tags --
|
|
603 -----------------------------
|
|
604
|
|
605 function Interface_Ancestor_Tags (T : Tag) return Tag_Array is
|
|
606 TSD_Ptr : constant Addr_Ptr :=
|
|
607 To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
|
|
608 TSD : constant Type_Specific_Data_Ptr :=
|
|
609 To_Type_Specific_Data_Ptr (TSD_Ptr.all);
|
|
610 Iface_Table : constant Interface_Data_Ptr := TSD.Interfaces_Table;
|
|
611
|
|
612 begin
|
|
613 if Iface_Table = null then
|
|
614 declare
|
|
615 Table : Tag_Array (1 .. 0);
|
|
616 begin
|
|
617 return Table;
|
|
618 end;
|
|
619
|
|
620 else
|
|
621 declare
|
|
622 Table : Tag_Array (1 .. Iface_Table.Nb_Ifaces);
|
|
623 begin
|
|
624 for J in 1 .. Iface_Table.Nb_Ifaces loop
|
|
625 Table (J) := Iface_Table.Ifaces_Table (J).Iface_Tag;
|
|
626 end loop;
|
|
627
|
|
628 return Table;
|
|
629 end;
|
|
630 end if;
|
|
631 end Interface_Ancestor_Tags;
|
|
632
|
|
633 ------------------
|
|
634 -- Internal_Tag --
|
|
635 ------------------
|
|
636
|
|
637 -- Internal tags have the following format:
|
|
638 -- "Internal tag at 16#ADDRESS#: <full-name-of-tagged-type>"
|
|
639
|
|
640 Internal_Tag_Header : constant String := "Internal tag at ";
|
|
641 Header_Separator : constant Character := '#';
|
|
642
|
|
643 function Internal_Tag (External : String) return Tag is
|
|
644 pragma Unsuppress (All_Checks);
|
|
645 -- To make T'Class'Input robust in the case of bad data
|
|
646
|
|
647 Res : Tag := null;
|
|
648
|
|
649 begin
|
|
650 -- Raise Tag_Error for empty strings and very long strings. This makes
|
|
651 -- T'Class'Input robust in the case of bad data, for example
|
|
652 --
|
|
653 -- String (123456789..1234)
|
|
654 --
|
|
655 -- The limit of 10,000 characters is arbitrary, but is unlikely to be
|
|
656 -- exceeded by legitimate external tag names.
|
|
657
|
|
658 if External'Length not in 1 .. 10_000 then
|
|
659 raise Tag_Error;
|
|
660 end if;
|
|
661
|
|
662 -- Handle locally defined tagged types
|
|
663
|
|
664 if External'Length > Internal_Tag_Header'Length
|
|
665 and then
|
|
666 External (External'First ..
|
|
667 External'First + Internal_Tag_Header'Length - 1) =
|
|
668 Internal_Tag_Header
|
|
669 then
|
|
670 declare
|
|
671 Addr_First : constant Natural :=
|
|
672 External'First + Internal_Tag_Header'Length;
|
|
673 Addr_Last : Natural;
|
|
674 Addr : Integer_Address;
|
|
675
|
|
676 begin
|
|
677 -- Search the second separator (#) to identify the address
|
|
678
|
|
679 Addr_Last := Addr_First;
|
|
680
|
|
681 for J in 1 .. 2 loop
|
|
682 while Addr_Last <= External'Last
|
|
683 and then External (Addr_Last) /= Header_Separator
|
|
684 loop
|
|
685 Addr_Last := Addr_Last + 1;
|
|
686 end loop;
|
|
687
|
|
688 -- Skip the first separator
|
|
689
|
|
690 if J = 1 then
|
|
691 Addr_Last := Addr_Last + 1;
|
|
692 end if;
|
|
693 end loop;
|
|
694
|
|
695 if Addr_Last <= External'Last then
|
|
696
|
|
697 -- Protect the run-time against wrong internal tags. We
|
|
698 -- cannot use exception handlers here because it would
|
|
699 -- disable the use of this run-time compiling with
|
|
700 -- restriction No_Exception_Handler.
|
|
701
|
|
702 declare
|
|
703 C : Character;
|
|
704 Wrong_Tag : Boolean := False;
|
|
705
|
|
706 begin
|
|
707 if External (Addr_First) /= '1'
|
|
708 or else External (Addr_First + 1) /= '6'
|
|
709 or else External (Addr_First + 2) /= '#'
|
|
710 then
|
|
711 Wrong_Tag := True;
|
|
712
|
|
713 else
|
|
714 for J in Addr_First + 3 .. Addr_Last - 1 loop
|
|
715 C := External (J);
|
|
716
|
|
717 if not (C in '0' .. '9')
|
|
718 and then not (C in 'A' .. 'F')
|
|
719 and then not (C in 'a' .. 'f')
|
|
720 then
|
|
721 Wrong_Tag := True;
|
|
722 exit;
|
|
723 end if;
|
|
724 end loop;
|
|
725 end if;
|
|
726
|
|
727 -- Convert the numeric value into a tag
|
|
728
|
|
729 if not Wrong_Tag then
|
|
730 Addr := Integer_Address'Value
|
|
731 (External (Addr_First .. Addr_Last));
|
|
732
|
|
733 -- Internal tags never have value 0
|
|
734
|
|
735 if Addr /= 0 then
|
|
736 return To_Tag (Addr);
|
|
737 end if;
|
|
738 end if;
|
|
739 end;
|
|
740 end if;
|
|
741 end;
|
|
742
|
|
743 -- Handle library-level tagged types
|
|
744
|
|
745 else
|
|
746 -- Make NUL-terminated copy of external tag string
|
|
747
|
|
748 declare
|
|
749 Ext_Copy : aliased String (External'First .. External'Last + 1);
|
|
750 pragma Assert (Ext_Copy'Length > 1); -- See Length check at top
|
|
751 begin
|
|
752 Ext_Copy (External'Range) := External;
|
|
753 Ext_Copy (Ext_Copy'Last) := ASCII.NUL;
|
|
754 Res := External_Tag_HTable.Get (Ext_Copy'Address);
|
|
755 end;
|
|
756 end if;
|
|
757
|
|
758 if Res = null then
|
|
759 declare
|
|
760 Msg1 : constant String := "unknown tagged type: ";
|
|
761 Msg2 : String (1 .. Msg1'Length + External'Length);
|
|
762
|
|
763 begin
|
|
764 Msg2 (1 .. Msg1'Length) := Msg1;
|
|
765 Msg2 (Msg1'Length + 1 .. Msg1'Length + External'Length) :=
|
|
766 External;
|
|
767 Ada.Exceptions.Raise_Exception (Tag_Error'Identity, Msg2);
|
|
768 end;
|
|
769 end if;
|
|
770
|
|
771 return Res;
|
|
772 end Internal_Tag;
|
|
773
|
|
774 ---------------------------------
|
|
775 -- Is_Descendant_At_Same_Level --
|
|
776 ---------------------------------
|
|
777
|
|
778 function Is_Descendant_At_Same_Level
|
|
779 (Descendant : Tag;
|
|
780 Ancestor : Tag) return Boolean
|
|
781 is
|
|
782 begin
|
|
783 if Descendant = Ancestor then
|
|
784 return True;
|
|
785
|
|
786 else
|
|
787 declare
|
|
788 D_TSD_Ptr : constant Addr_Ptr :=
|
|
789 To_Addr_Ptr (To_Address (Descendant) - DT_Typeinfo_Ptr_Size);
|
|
790 A_TSD_Ptr : constant Addr_Ptr :=
|
|
791 To_Addr_Ptr (To_Address (Ancestor) - DT_Typeinfo_Ptr_Size);
|
|
792 D_TSD : constant Type_Specific_Data_Ptr :=
|
|
793 To_Type_Specific_Data_Ptr (D_TSD_Ptr.all);
|
|
794 A_TSD : constant Type_Specific_Data_Ptr :=
|
|
795 To_Type_Specific_Data_Ptr (A_TSD_Ptr.all);
|
|
796 begin
|
|
797 return
|
|
798 D_TSD.Access_Level = A_TSD.Access_Level
|
|
799 and then (CW_Membership (Descendant, Ancestor)
|
|
800 or else IW_Membership (D_TSD, Ancestor));
|
|
801 end;
|
|
802 end if;
|
|
803 end Is_Descendant_At_Same_Level;
|
|
804
|
|
805 ------------
|
|
806 -- Length --
|
|
807 ------------
|
|
808
|
|
809 -- Note: This unit is used in the Ravenscar runtime library, so it cannot
|
|
810 -- depend on System.CTRL. Furthermore, this happens on CPUs where the GCC
|
|
811 -- intrinsic strlen may not be available, so we need to recode our own Ada
|
|
812 -- version here.
|
|
813
|
|
814 function Length (Str : Cstring_Ptr) return Natural is
|
|
815 Len : Integer;
|
|
816
|
|
817 begin
|
|
818 Len := 1;
|
|
819 while Str (Len) /= ASCII.NUL loop
|
|
820 Len := Len + 1;
|
|
821 end loop;
|
|
822
|
|
823 return Len - 1;
|
|
824 end Length;
|
|
825
|
|
826 -------------------
|
|
827 -- Offset_To_Top --
|
|
828 -------------------
|
|
829
|
|
830 function Offset_To_Top
|
|
831 (This : System.Address) return SSE.Storage_Offset
|
|
832 is
|
|
833 Tag_Size : constant SSE.Storage_Count :=
|
|
834 SSE.Storage_Count (1 * (Standard'Address_Size / System.Storage_Unit));
|
|
835
|
|
836 type Storage_Offset_Ptr is access SSE.Storage_Offset;
|
|
837 function To_Storage_Offset_Ptr is
|
|
838 new Unchecked_Conversion (System.Address, Storage_Offset_Ptr);
|
|
839
|
|
840 Curr_DT : Dispatch_Table_Ptr;
|
|
841
|
|
842 begin
|
|
843 Curr_DT := DT (To_Tag_Ptr (This).all);
|
|
844
|
|
845 -- See the documentation of Dispatch_Table_Wrapper.Offset_To_Top
|
|
846
|
|
847 if Curr_DT.Offset_To_Top = SSE.Storage_Offset'Last then
|
|
848
|
|
849 -- The parent record type has variable-size components, so the
|
|
850 -- instance-specific offset is stored in the tagged record, right
|
|
851 -- after the reference to Curr_DT (which is a secondary dispatch
|
|
852 -- table).
|
|
853
|
|
854 return To_Storage_Offset_Ptr (This + Tag_Size).all;
|
|
855
|
|
856 else
|
|
857 -- The offset is compile-time known, so it is simply stored in the
|
|
858 -- Offset_To_Top field.
|
|
859
|
|
860 return Curr_DT.Offset_To_Top;
|
|
861 end if;
|
|
862 end Offset_To_Top;
|
|
863
|
|
864 ------------------------
|
|
865 -- Needs_Finalization --
|
|
866 ------------------------
|
|
867
|
|
868 function Needs_Finalization (T : Tag) return Boolean is
|
|
869 TSD_Ptr : constant Addr_Ptr :=
|
|
870 To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
|
|
871 TSD : constant Type_Specific_Data_Ptr :=
|
|
872 To_Type_Specific_Data_Ptr (TSD_Ptr.all);
|
|
873 begin
|
|
874 return TSD.Needs_Finalization;
|
|
875 end Needs_Finalization;
|
|
876
|
|
877 -----------------
|
|
878 -- Parent_Size --
|
|
879 -----------------
|
|
880
|
|
881 function Parent_Size
|
|
882 (Obj : System.Address;
|
|
883 T : Tag) return SSE.Storage_Count
|
|
884 is
|
|
885 Parent_Slot : constant Positive := 1;
|
|
886 -- The tag of the parent is always in the first slot of the table of
|
|
887 -- ancestor tags.
|
|
888
|
|
889 TSD_Ptr : constant Addr_Ptr :=
|
|
890 To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
|
|
891 TSD : constant Type_Specific_Data_Ptr :=
|
|
892 To_Type_Specific_Data_Ptr (TSD_Ptr.all);
|
|
893 -- Pointer to the TSD
|
|
894
|
|
895 Parent_Tag : constant Tag := TSD.Tags_Table (Parent_Slot);
|
|
896 Parent_TSD_Ptr : constant Addr_Ptr :=
|
|
897 To_Addr_Ptr (To_Address (Parent_Tag) - DT_Typeinfo_Ptr_Size);
|
|
898 Parent_TSD : constant Type_Specific_Data_Ptr :=
|
|
899 To_Type_Specific_Data_Ptr (Parent_TSD_Ptr.all);
|
|
900
|
|
901 begin
|
|
902 -- Here we compute the size of the _parent field of the object
|
|
903
|
|
904 return SSE.Storage_Count (Parent_TSD.Size_Func.all (Obj));
|
|
905 end Parent_Size;
|
|
906
|
|
907 ----------------
|
|
908 -- Parent_Tag --
|
|
909 ----------------
|
|
910
|
|
911 function Parent_Tag (T : Tag) return Tag is
|
|
912 TSD_Ptr : Addr_Ptr;
|
|
913 TSD : Type_Specific_Data_Ptr;
|
|
914
|
|
915 begin
|
|
916 if T = No_Tag then
|
|
917 raise Tag_Error;
|
|
918 end if;
|
|
919
|
|
920 TSD_Ptr := To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
|
|
921 TSD := To_Type_Specific_Data_Ptr (TSD_Ptr.all);
|
|
922
|
|
923 -- The Parent_Tag of a root-level tagged type is defined to be No_Tag.
|
|
924 -- The first entry in the Ancestors_Tags array will be null for such
|
|
925 -- a type, but it's better to be explicit about returning No_Tag in
|
|
926 -- this case.
|
|
927
|
|
928 if TSD.Idepth = 0 then
|
|
929 return No_Tag;
|
|
930 else
|
|
931 return TSD.Tags_Table (1);
|
|
932 end if;
|
|
933 end Parent_Tag;
|
|
934
|
|
935 -------------------------------
|
|
936 -- Register_Interface_Offset --
|
|
937 -------------------------------
|
|
938
|
|
939 procedure Register_Interface_Offset
|
|
940 (Prim_T : Tag;
|
|
941 Interface_T : Tag;
|
|
942 Is_Static : Boolean;
|
|
943 Offset_Value : SSE.Storage_Offset;
|
|
944 Offset_Func : Offset_To_Top_Function_Ptr)
|
|
945 is
|
|
946 Prim_DT : constant Dispatch_Table_Ptr := DT (Prim_T);
|
|
947 Iface_Table : constant Interface_Data_Ptr :=
|
|
948 To_Type_Specific_Data_Ptr (Prim_DT.TSD).Interfaces_Table;
|
|
949
|
|
950 begin
|
|
951 -- Save Offset_Value in the table of interfaces of the primary DT.
|
|
952 -- This data will be used by the subprogram "Displace" to give support
|
|
953 -- to backward abstract interface type conversions.
|
|
954
|
|
955 -- Register the offset in the table of interfaces
|
|
956
|
|
957 if Iface_Table /= null then
|
|
958 for Id in 1 .. Iface_Table.Nb_Ifaces loop
|
|
959 if Iface_Table.Ifaces_Table (Id).Iface_Tag = Interface_T then
|
|
960 if Is_Static or else Offset_Value = 0 then
|
|
961 Iface_Table.Ifaces_Table (Id).Static_Offset_To_Top := True;
|
|
962 Iface_Table.Ifaces_Table (Id).Offset_To_Top_Value :=
|
|
963 Offset_Value;
|
|
964 else
|
|
965 Iface_Table.Ifaces_Table (Id).Static_Offset_To_Top := False;
|
|
966 Iface_Table.Ifaces_Table (Id).Offset_To_Top_Func :=
|
|
967 Offset_Func;
|
|
968 end if;
|
|
969
|
|
970 return;
|
|
971 end if;
|
|
972 end loop;
|
|
973 end if;
|
|
974
|
|
975 -- If we arrive here there is some error in the run-time data structure
|
|
976
|
|
977 raise Program_Error;
|
|
978 end Register_Interface_Offset;
|
|
979
|
|
980 ------------------
|
|
981 -- Register_Tag --
|
|
982 ------------------
|
|
983
|
|
984 procedure Register_Tag (T : Tag) is
|
|
985 begin
|
|
986 External_Tag_HTable.Set (T);
|
|
987 end Register_Tag;
|
|
988
|
|
989 -------------------
|
|
990 -- Secondary_Tag --
|
|
991 -------------------
|
|
992
|
|
993 function Secondary_Tag (T, Iface : Tag) return Tag is
|
|
994 Iface_Table : Interface_Data_Ptr;
|
|
995 Obj_DT : Dispatch_Table_Ptr;
|
|
996
|
|
997 begin
|
|
998 if not Is_Primary_DT (T) then
|
|
999 raise Program_Error;
|
|
1000 end if;
|
|
1001
|
|
1002 Obj_DT := DT (T);
|
|
1003 Iface_Table := To_Type_Specific_Data_Ptr (Obj_DT.TSD).Interfaces_Table;
|
|
1004
|
|
1005 if Iface_Table /= null then
|
|
1006 for Id in 1 .. Iface_Table.Nb_Ifaces loop
|
|
1007 if Iface_Table.Ifaces_Table (Id).Iface_Tag = Iface then
|
|
1008 return Iface_Table.Ifaces_Table (Id).Secondary_DT;
|
|
1009 end if;
|
|
1010 end loop;
|
|
1011 end if;
|
|
1012
|
|
1013 -- If the object does not implement the interface we must raise CE
|
|
1014
|
|
1015 raise Constraint_Error with "invalid interface conversion";
|
|
1016 end Secondary_Tag;
|
|
1017
|
|
1018 ---------------------
|
|
1019 -- Set_Entry_Index --
|
|
1020 ---------------------
|
|
1021
|
|
1022 procedure Set_Entry_Index
|
|
1023 (T : Tag;
|
|
1024 Position : Positive;
|
|
1025 Value : Positive)
|
|
1026 is
|
|
1027 begin
|
|
1028 SSD (T).SSD_Table (Position).Index := Value;
|
|
1029 end Set_Entry_Index;
|
|
1030
|
|
1031 -----------------------
|
|
1032 -- Set_Offset_To_Top --
|
|
1033 -----------------------
|
|
1034
|
|
1035 procedure Set_Dynamic_Offset_To_Top
|
|
1036 (This : System.Address;
|
|
1037 Prim_T : Tag;
|
|
1038 Interface_T : Tag;
|
|
1039 Offset_Value : SSE.Storage_Offset;
|
|
1040 Offset_Func : Offset_To_Top_Function_Ptr)
|
|
1041 is
|
|
1042 Sec_Base : System.Address;
|
|
1043 Sec_DT : Dispatch_Table_Ptr;
|
|
1044
|
|
1045 begin
|
|
1046 -- Save the offset to top field in the secondary dispatch table
|
|
1047
|
|
1048 if Offset_Value /= 0 then
|
|
1049 Sec_Base := This + Offset_Value;
|
|
1050 Sec_DT := DT (To_Tag_Ptr (Sec_Base).all);
|
|
1051 Sec_DT.Offset_To_Top := SSE.Storage_Offset'Last;
|
|
1052 end if;
|
|
1053
|
|
1054 Register_Interface_Offset
|
|
1055 (Prim_T, Interface_T, False, Offset_Value, Offset_Func);
|
|
1056 end Set_Dynamic_Offset_To_Top;
|
|
1057
|
|
1058 ----------------------
|
|
1059 -- Set_Prim_Op_Kind --
|
|
1060 ----------------------
|
|
1061
|
|
1062 procedure Set_Prim_Op_Kind
|
|
1063 (T : Tag;
|
|
1064 Position : Positive;
|
|
1065 Value : Prim_Op_Kind)
|
|
1066 is
|
|
1067 begin
|
|
1068 SSD (T).SSD_Table (Position).Kind := Value;
|
|
1069 end Set_Prim_Op_Kind;
|
|
1070
|
|
1071 --------------------
|
|
1072 -- Unregister_Tag --
|
|
1073 --------------------
|
|
1074
|
|
1075 procedure Unregister_Tag (T : Tag) is
|
|
1076 begin
|
|
1077 External_Tag_HTable.Remove (Get_External_Tag (T));
|
|
1078 end Unregister_Tag;
|
|
1079
|
|
1080 ------------------------
|
|
1081 -- Wide_Expanded_Name --
|
|
1082 ------------------------
|
|
1083
|
|
1084 WC_Encoding : Character;
|
|
1085 pragma Import (C, WC_Encoding, "__gl_wc_encoding");
|
|
1086 -- Encoding method for source, as exported by binder
|
|
1087
|
|
1088 function Wide_Expanded_Name (T : Tag) return Wide_String is
|
|
1089 S : constant String := Expanded_Name (T);
|
|
1090 W : Wide_String (1 .. S'Length);
|
|
1091 L : Natural;
|
|
1092 begin
|
|
1093 String_To_Wide_String
|
|
1094 (S, W, L, Get_WC_Encoding_Method (WC_Encoding));
|
|
1095 return W (1 .. L);
|
|
1096 end Wide_Expanded_Name;
|
|
1097
|
|
1098 -----------------------------
|
|
1099 -- Wide_Wide_Expanded_Name --
|
|
1100 -----------------------------
|
|
1101
|
|
1102 function Wide_Wide_Expanded_Name (T : Tag) return Wide_Wide_String is
|
|
1103 S : constant String := Expanded_Name (T);
|
|
1104 W : Wide_Wide_String (1 .. S'Length);
|
|
1105 L : Natural;
|
|
1106 begin
|
|
1107 String_To_Wide_Wide_String
|
|
1108 (S, W, L, Get_WC_Encoding_Method (WC_Encoding));
|
|
1109 return W (1 .. L);
|
|
1110 end Wide_Wide_Expanded_Name;
|
|
1111
|
|
1112 end Ada.Tags;
|