/[dotgnu-pnet]/pnet/engine/layout.c
ViewVC logotype

Contents of /pnet/engine/layout.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.36 - (show annotations) (download)
Mon Nov 21 07:01:30 2005 UTC (18 years, 5 months ago) by t3rmin4t0r
Branch: MAIN
Changes since 1.35: +42 -32 lines
File MIME type: text/plain
fix up IMT to check for collisions with interfaces implemented by parent classes

1 /*
2 * layout.c - Type and object layout algorithms.
3 *
4 * Copyright (C) 2001 Southern Storm Software, Pty Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "engine_private.h"
22 #include "il_opcodes.h"
23 #if defined(HAVE_LIBFFI)
24 #include "ffi.h"
25 #else
26 #include "il_align.h"
27 #endif
28
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32
33 /*
34 * Information that results from laying out a type.
35 */
36 typedef struct
37 {
38 ILUInt32 size;
39 ILUInt32 alignment;
40 ILUInt32 nativeSize;
41 ILUInt32 nativeAlignment;
42 ILUInt32 vtableSize;
43 ILMethod **vtable;
44 ILUInt32 staticSize;
45 int hasFinalizer;
46 int managedInstance;
47 int managedStatic;
48
49 } LayoutInfo;
50
51 /*
52 * Forward declaration.
53 */
54 static int LayoutClass(ILExecProcess *process, ILClass *info, LayoutInfo *layout);
55
56 /*
57 * Get the layout information for a type. Returns zero
58 * if there is something wrong with the type.
59 */
60 static int LayoutType(ILExecProcess *process, ILType *type, LayoutInfo *layout)
61 {
62 type = ILTypeStripPrefixes(type);
63 if(ILType_IsPrimitive(type))
64 {
65 /* Lay out a primitive type */
66 layout->managedInstance = 0;
67 switch(ILType_ToElement(type))
68 {
69 case IL_META_ELEMTYPE_BOOLEAN:
70 case IL_META_ELEMTYPE_I1:
71 case IL_META_ELEMTYPE_U1:
72 {
73 layout->size = 1;
74 layout->alignment = 1;
75 }
76 break;
77
78 case IL_META_ELEMTYPE_CHAR:
79 case IL_META_ELEMTYPE_I2:
80 case IL_META_ELEMTYPE_U2:
81 {
82 layout->size = 2;
83 layout->alignment = 2;
84 }
85 break;
86
87 case IL_META_ELEMTYPE_I4:
88 case IL_META_ELEMTYPE_U4:
89 #ifdef IL_NATIVE_INT32
90 case IL_META_ELEMTYPE_I:
91 case IL_META_ELEMTYPE_U:
92 #endif
93 {
94 layout->size = 4;
95 layout->alignment = 4;
96 }
97 break;
98
99 case IL_META_ELEMTYPE_I8:
100 case IL_META_ELEMTYPE_U8:
101 #ifdef IL_NATIVE_INT64
102 case IL_META_ELEMTYPE_I:
103 case IL_META_ELEMTYPE_U:
104 #endif
105 {
106 #if defined(HAVE_LIBFFI)
107 layout->size = ffi_type_uint64.size;
108 layout->alignment = ffi_type_uint64.alignment;
109 #else
110 layout->size = sizeof(ILInt64);
111 layout->alignment = _IL_ALIGN_FOR_TYPE(long);
112 #endif
113 }
114 break;
115
116 case IL_META_ELEMTYPE_R4:
117 {
118 #if defined(HAVE_LIBFFI)
119 layout->size = ffi_type_float.size;
120 layout->alignment = ffi_type_float.alignment;
121 #else
122 layout->size = sizeof(ILFloat);
123 layout->alignment = _IL_ALIGN_FOR_TYPE(float);
124 #endif
125 }
126 break;
127
128 case IL_META_ELEMTYPE_R8:
129 {
130 #if defined(HAVE_LIBFFI)
131 layout->size = ffi_type_double.size;
132 layout->alignment = ffi_type_double.alignment;
133 #else
134 layout->size = sizeof(ILDouble);
135 layout->alignment = _IL_ALIGN_FOR_TYPE(double);
136 #endif
137 }
138 break;
139
140 case IL_META_ELEMTYPE_R:
141 {
142 #if defined(HAVE_LIBFFI)
143 #ifdef IL_NATIVE_FLOAT
144 layout->size = ffi_type_longdouble.size;
145 layout->alignment = ffi_type_longdouble.alignment;
146 #else
147 layout->size = ffi_type_double.size;
148 layout->alignment = ffi_type_double.alignment;
149 #endif
150 #else
151 layout->size = sizeof(ILNativeFloat);
152 layout->alignment = _IL_ALIGN_FOR_TYPE(long_double);
153 #endif
154 }
155 break;
156
157 case IL_META_ELEMTYPE_TYPEDBYREF:
158 {
159 #if defined(HAVE_LIBFFI)
160 layout->size = sizeof(ILTypedRef);
161 layout->alignment = ffi_type_pointer.alignment;
162 #else
163 layout->size = sizeof(ILTypedRef);
164 layout->alignment = _IL_ALIGN_FOR_TYPE(void_p);
165 #endif
166 layout->managedInstance = 1;
167 }
168 break;
169
170 default: return 0;
171 }
172 layout->nativeSize = layout->size;
173 layout->nativeAlignment = layout->alignment;
174 layout->vtableSize = 0;
175 layout->vtable = 0;
176 layout->staticSize = 0;
177 layout->hasFinalizer = 0;
178 layout->managedStatic = 0;
179 return 1;
180 }
181 else if(ILType_IsValueType(type))
182 {
183 /* Lay out a value type by getting the full size and alignment
184 of the class that underlies the value type */
185 ILClass *classInfo = ILClassResolve(ILType_ToValueType(type));
186 ILType *synType = ILClassGetSynType(classInfo);
187 if(synType == 0)
188 {
189 return LayoutClass(process, classInfo, layout);
190 }
191 else
192 {
193 return LayoutType(process, ILTypeStripPrefixes(synType), layout);
194 }
195 }
196 else
197 {
198 /* Everything else is laid out as a pointer */
199 #if defined(HAVE_LIBFFI)
200 layout->size = ffi_type_pointer.size;
201 layout->alignment = ffi_type_pointer.alignment;
202 #else
203 layout->size = sizeof(void *);
204 layout->alignment = _IL_ALIGN_FOR_TYPE(void_p);
205 #endif
206 layout->nativeSize = layout->size;
207 layout->nativeAlignment = layout->alignment;
208 layout->vtableSize = 0;
209 layout->vtable = 0;
210 layout->staticSize = 0;
211 layout->hasFinalizer = 0;
212 layout->managedInstance = ILTypeIsReference(ILTypeStripPrefixes(type));
213 layout->managedStatic = 0;
214 return 1;
215 }
216 }
217
218 /*
219 * Find the virtual ancestor for a method.
220 * Returns NULL if no ancestor found.
221 */
222 static ILMethod *FindVirtualAncestor(ILClass *scope, ILClass *info,
223 ILMethod *testMethod)
224 {
225 ILMethod *method;
226 while(info != 0)
227 {
228 method = 0;
229 while((method = (ILMethod *)ILClassNextMemberByKind
230 (info, (ILMember *)method, IL_META_MEMBERKIND_METHOD)) != 0)
231 {
232 if((method->member.attributes & IL_META_METHODDEF_VIRTUAL) != 0 &&
233 !strcmp(method->member.name, testMethod->member.name) &&
234 ILTypeIdentical(method->member.signature,
235 testMethod->member.signature))
236 {
237 /* If the ancestor is not accessible from the original class,
238 then allocate a new vtable slot for the method */
239 if(ILMemberAccessible(&(method->member), scope))
240 {
241 return method;
242 }
243 else
244 {
245 return 0;
246 }
247 }
248 }
249 info = ILClassGetParent(info);
250 }
251 return 0;
252 }
253
254 /*
255 * Compute the method table for a class's interface.
256 */
257 static int ComputeInterfaceTable(ILClass *info, ILClass *interface)
258 {
259 ILClass *parent;
260 ILImplPrivate *impl;
261 ILImplPrivate *impl2;
262 ILUInt32 size;
263 ILUInt16 *table;
264 ILUInt32 slot;
265 ILMethod *method;
266 ILMethod *method2;
267 ILOverride *over;
268 ILImplements *implBlock;
269
270 /* Determine if we already have an implementation of this interface.
271 This may happen if we reach the same interface via two different
272 paths in the interface inheritance tree */
273 impl = ((ILClassPrivate *)(info->userData))->implements;
274 while(impl != 0)
275 {
276 if(impl->interface == interface)
277 {
278 return 1;
279 }
280 impl = impl->next;
281 }
282
283 /* Create a new interface method table for the class */
284 size = ((ILClassPrivate *)(interface->userData))->vtableSize;
285 impl = (ILImplPrivate *)ILMemStackAllocItem
286 (&(info->programItem.image->memStack),
287 sizeof(ILImplPrivate) + size * sizeof(ILUInt16));
288 if(!impl)
289 {
290 return 0;
291 }
292 table = ILImplPrivate_Table(impl);
293 impl->interface = interface;
294 impl->next = ((ILClassPrivate *)(info->userData))->implements;
295 ((ILClassPrivate *)(info->userData))->implements = impl;
296
297 /* Determine if the parent class implements the interface */
298 parent = info;
299 impl2 = 0;
300 while(impl2 == 0 && (parent = ILClassGetParent(parent)) != 0)
301 {
302 impl2 = ((ILClassPrivate *)(parent->userData))->implements;
303 while(impl2 != 0)
304 {
305 if(impl2->interface == interface)
306 {
307 break;
308 }
309 impl2 = impl2->next;
310 }
311 }
312
313 /* Copy the parent's interface method table, or mark all slots abstract */
314 if(impl2)
315 {
316 ILMemCpy(table, ILImplPrivate_Table(impl2), size * sizeof(ILUInt16));
317 }
318 else
319 {
320 ILMemSet(table, 0xFF, size * sizeof(ILUInt16));
321 }
322
323 /* Fill the interface table slots */
324 for(slot = 0; slot < size; ++slot)
325 {
326 /* Get the method for this slot */
327 method = ((ILClassPrivate *)(interface->userData))->vtable[slot];
328 if(!method)
329 {
330 continue;
331 }
332
333 /* Search for a method in the current class with a matching name */
334 method2 = 0;
335 while((method2 = (ILMethod *)ILClassNextMemberByKind
336 (info, (ILMember *)method2,
337 IL_META_MEMBERKIND_METHOD)) != 0)
338 {
339 if((method2->member.attributes &
340 (IL_META_METHODDEF_MEMBER_ACCESS_MASK |
341 IL_META_METHODDEF_VIRTUAL |
342 IL_META_METHODDEF_NEW_SLOT)) ==
343 (IL_META_METHODDEF_PUBLIC |
344 IL_META_METHODDEF_VIRTUAL |
345 IL_META_METHODDEF_NEW_SLOT))
346 {
347 if(strcmp(method2->member.name, method->member.name) != 0 ||
348 !ILTypeIdentical(method2->member.signature,
349 method->member.signature))
350 {
351 continue;
352 }
353 table[slot] = (ILUInt16)(method2->index);
354 break;
355 }
356 }
357
358 /* If the slot is still empty, then search the class
359 hierarchy for a virtual method match */
360 if(table[slot] == (ILUInt16)0xFFFF)
361 {
362 parent = info;
363 while(parent != 0)
364 {
365 method2 = 0;
366 while((method2 = (ILMethod *)ILClassNextMemberByKind
367 (parent, (ILMember *)method2,
368 IL_META_MEMBERKIND_METHOD)) != 0)
369 {
370 if((method2->member.attributes &
371 (IL_META_METHODDEF_MEMBER_ACCESS_MASK |
372 IL_META_METHODDEF_VIRTUAL)) ==
373 (IL_META_METHODDEF_PUBLIC |
374 IL_META_METHODDEF_VIRTUAL))
375 {
376 if(strcmp(method2->member.name,
377 method->member.name) != 0 ||
378 !ILTypeIdentical(method2->member.signature,
379 method->member.signature))
380 {
381 continue;
382 }
383 table[slot] = (ILUInt16)(method2->index);
384 break;
385 }
386 }
387 if(table[slot] != (ILUInt16)0xFFFF)
388 {
389 break;
390 }
391 parent = ILClassGetParent(parent);
392 }
393 }
394
395 /* Look for an override for the interface method */
396 over = 0;
397 while((over = (ILOverride *)ILClassNextMemberByKind
398 (info, (ILMember *)over, IL_META_MEMBERKIND_OVERRIDE)) != 0)
399 {
400 if(ILMemberResolve((ILMember *)(ILOverrideGetDecl(over)))
401 == (ILMember *)method)
402 {
403 table[slot] = (ILOverrideGetBody(over))->index;
404 break;
405 }
406 }
407 if(table[slot] == (ILUInt16)0xFFFF)
408 {
409 /* There is no implementation of this method, which is an error */
410 return 0;
411 }
412 }
413
414 /* Recursively compute all interfaces that the interface inherits from */
415 implBlock = interface->implements;
416 while(implBlock != 0)
417 {
418 if(!ComputeInterfaceTable(info, ILClassResolve(implBlock->interface)))
419 {
420 return 0;
421 }
422 implBlock = implBlock->nextInterface;
423 }
424
425 /* Done */
426 return 1;
427 }
428
429 #ifdef IL_USE_IMTS
430
431 /*
432 * Build an "Interface Method Table" (IMT) for a particular class, from
433 * the interface information in that class. The mechanism is described
434 * in the following paper by IBM:
435 *
436 * "Efficient Implementation of Java Interfaces: Invokeinterface Considered
437 * Harmless", Bowen Alpern, Anthony Cocchi, Stephen Fink, David Grove,
438 * and Derek Lieber. ACM Conference on Object-Oriented Programming, Systems,
439 * Languages, and Applications (OOPSLA), Tampa, FL, USA, Oct 14-18, 2001.
440 *
441 * http://www.research.ibm.com/people/d/dgrove/papers/oopsla01.pdf
442 *
443 * Each interface method in the system is assigned a unique identifier.
444 * The identifier is used to hash into a fixed-sized table of method entry
445 * points, similar to a vtable. In most cases, the hashed position will
446 * be the right position.
447 *
448 * We modify the IMT conflict resolution mechanism slightly. IBM's RVM
449 * system generates special conflict resolution stubs for interface methods
450 * that hash to the same IMT position. We store NULL at any position where
451 * there is a conflict and bail out to the traditional lookup algorithm.
452 * This is necessary because we convert methods one at a time, instead of
453 * class at a time like RVM does.
454 */
455 static void BuildIMT(ILExecProcess *process, ILClass *info,
456 ILClassPrivate *classPrivate)
457 {
458 ILImplPrivate *impl;
459 ILClassPrivate *implPrivate;
460 ILClassPrivate *parentPrivate;
461 ILUInt32 posn, size;
462 ILUInt32 vtableIndex;
463 ILUInt32 imtIndex;
464
465 /* Is this class itself an interface? */
466 if(ILClass_IsInterface(info))
467 {
468 /* Allocate the base identifier for the interface. We must do
469 this here in case an interface is referenced by a "callvirt"
470 instruction before any of the classes that implement it are
471 laid out */
472 if(!(classPrivate->imtBase))
473 {
474 size = (ILUInt32)(classPrivate->vtableSize);
475 classPrivate->imtBase = process->imtBase;
476 process->imtBase += size;
477 }
478 return;
479 }
480
481 parentPrivate = classPrivate;
482 while(parentPrivate != NULL)
483 {
484 /* Process the implementation records that are attached to this class */
485 impl = parentPrivate->implements;
486 while(impl != 0)
487 {
488 implPrivate = (ILClassPrivate *)(impl->interface->userData);
489 if(implPrivate)
490 {
491 /* Allocate a base identifer for the interface if necessary.
492 This will probably never be used because interfaces are
493 typically laid out before their implementing classes, and
494 the allocation above will catch us. But let's be paranoid
495 and allocate the base identifier here anyway, just in case */
496 size = (ILUInt32)(implPrivate->vtableSize);
497 if(!(implPrivate->imtBase))
498 {
499 implPrivate->imtBase = process->imtBase;
500 process->imtBase += size;
501 }
502
503 /* Process the members of this interface */
504 for(posn = 0; posn < size; ++posn)
505 {
506 imtIndex = (implPrivate->imtBase + posn) % IL_IMT_SIZE;
507 vtableIndex = (ILImplPrivate_Table(impl))[posn];
508 if(vtableIndex != (ILUInt32)(ILUInt16)0xFFFF)
509 {
510 if(!(classPrivate->imt[imtIndex]))
511 {
512 /* No conflict at this table position */
513 classPrivate->imt[imtIndex] =
514 classPrivate->vtable[vtableIndex];
515 }
516 else
517 {
518 /* We have encountered a conflict in the table */
519 classPrivate->imt[imtIndex] =
520 (ILMethod *)(ILNativeInt)(-1);
521 }
522 }
523 }
524 }
525 impl = impl->next;
526 }
527 if(!parentPrivate->classInfo->parent)
528 {
529 break;
530 }
531 parentPrivate = (ILClassPrivate*) (parentPrivate->classInfo->parent->userData);
532 }
533
534 /* Clear positions in the table that indicate conflicts */
535 for(posn = 0; posn < IL_IMT_SIZE; ++posn)
536 {
537 if(classPrivate->imt[posn] == (ILMethod *)(ILNativeInt)(-1))
538 {
539 classPrivate->imt[posn] = 0;
540 }
541 }
542 }
543
544 #endif /* IL_USE_IMTS */
545
546 /*
547 * Lay out a particular class. Returns zero if there
548 * is something wrong with the class definition.
549 */
550 static int LayoutClass(ILExecProcess *process, ILClass *info, LayoutInfo *layout)
551 {
552 ILClassLayout *classLayout;
553 ILFieldLayout *fieldLayout;
554 ILFieldRVA *fieldRVA;
555 LayoutInfo typeLayout;
556 ILUInt32 maxAlignment;
557 ILUInt32 maxNativeAlignment;
558 ILUInt32 packingSize;
559 ILUInt32 explicitSize;
560 int allowFieldLayout;
561 int allowRVALayout;
562 ILClassPrivate *volatile classPrivate;
563 ILField *field;
564 ILMethod *method;
565 ILMethod *ancestor;
566 ILMethod **vtable;
567 ILClass *parent;
568 ILImplements *implements;
569 ILMethodCode code;
570
571 /* Determine if we have already tried to lay out this class */
572 if(info->userData)
573 {
574 /* We have layout data, so return it */
575 classPrivate = (ILClassPrivate *)(info->userData);
576 if(classPrivate->inLayout)
577 {
578 /* We have detected a layout loop. This can occur if a
579 class attempts to include itself in a value type field */
580 return 0;
581 }
582 else
583 {
584 layout->size = classPrivate->size;
585 layout->alignment = classPrivate->alignment;
586 layout->nativeSize = classPrivate->nativeSize;
587 layout->nativeAlignment = classPrivate->nativeAlignment;
588 layout->vtableSize = classPrivate->vtableSize;
589 layout->vtable = classPrivate->vtable;
590 layout->staticSize = classPrivate->staticSize;
591 layout->hasFinalizer = classPrivate->hasFinalizer;
592 layout->managedInstance = classPrivate->managedInstance;
593 layout->managedStatic = classPrivate->managedStatic;
594 return 1;
595 }
596 }
597 else
598 {
599 /* Create a new layout record and attach it to the class.
600 We must allocate this in memory accessible by the
601 garbage collector so that the object pointers that
602 it contains will be visible to the collector */
603 classPrivate = (ILClassPrivate *)
604 (ILGCAlloc(sizeof(ILClassPrivate)));
605 if(!classPrivate)
606 {
607 return 0;
608 }
609 classPrivate->classInfo = info;
610 info->userData = (void *)classPrivate;
611 classPrivate->inLayout = 1;
612 classPrivate->gcTypeDescriptor = IL_MAX_NATIVE_UINT;
613 classPrivate->process = process;
614 }
615
616 /* Lay out the parent class first */
617 if(info->parent)
618 {
619 /* Use "ILClassGetParent" to resolve cross-image links */
620 parent = ILClassGetParent(info);
621 if(!LayoutClass(process, parent, layout))
622 {
623 info->userData = 0;
624 return 0;
625 }
626 }
627 else
628 {
629 /* This is a top-level class (normally "System.Object") */
630 parent = 0;
631 layout->size = 0;
632 layout->alignment = 1;
633 layout->nativeSize = 0;
634 layout->nativeAlignment = 1;
635 layout->vtableSize = 0;
636 layout->hasFinalizer = 0;
637 layout->managedInstance = 0;
638 layout->managedStatic = 0;
639 }
640
641 /* Zero the static size, which must be recomputed for each class */
642 layout->staticSize = 0;
643
644 /* Lay out the interfaces that this class implements */
645 implements = info->implements;
646 while(implements != 0)
647 {
648 if(!LayoutClass(process, ILClassResolve(implements->interface), &typeLayout))
649 {
650 info->userData = 0;
651 return 0;
652 }
653 implements = implements->nextInterface;
654 }
655
656 /* Should we use the explicit layout algorithm? */
657 packingSize = 0;
658 explicitSize = 0;
659 allowFieldLayout = 0;
660 allowRVALayout = ILImageIsSecure(ILProgramItem_Image(info));
661 if((info->attributes & IL_META_TYPEDEF_LAYOUT_MASK) ==
662 IL_META_TYPEDEF_EXPLICIT_LAYOUT)
663 {
664 /* Check that security permissions allow explicit layout */
665 if(allowRVALayout)
666 {
667 /* Look for class layout information to specify the size */
668 classLayout = ILClassLayoutGetFromOwner(info);
669 if(classLayout)
670 {
671 /* Validate the class packing size */
672 if(classLayout->packingSize != 0 &&
673 classLayout->packingSize != 1 &&
674 classLayout->packingSize != 2 &&
675 classLayout->packingSize != 4 &&
676 classLayout->packingSize != 8)
677 {
678 info->userData = 0;
679 return 0;
680 }
681 packingSize = classLayout->packingSize;
682
683 /* Record the explicit size to be used later */
684 explicitSize = classLayout->classSize;
685 }
686
687 /* Field layout is permitted */
688 allowFieldLayout = 1;
689 }
690 }
691
692 /* Use straight-forward field allocation, which will usually
693 match the algorithm used by the platform C compiler */
694 field = 0;
695 maxAlignment = 1;
696 maxNativeAlignment = 1;
697 while((field = (ILField *)ILClassNextMemberByKind
698 (info, (ILMember *)field, IL_META_MEMBERKIND_FIELD)) != 0)
699 {
700 if((field->member.attributes & IL_META_FIELDDEF_STATIC) == 0)
701 {
702 /* Get the layout information for this field's type */
703 if(!LayoutType(process, field->member.signature, &typeLayout))
704 {
705 info->userData = 0;
706 return 0;
707 }
708
709 /* Decrease the alignment if we have an explicit packing size */
710 if(packingSize != 0 && packingSize < typeLayout.alignment)
711 {
712 typeLayout.alignment = packingSize;
713 }
714 if(packingSize != 0 && packingSize < typeLayout.nativeAlignment)
715 {
716 typeLayout.nativeAlignment = packingSize;
717 }
718
719 /* Use an explicit field offset if necessary */
720 if(allowFieldLayout &&
721 (fieldLayout = ILFieldLayoutGetFromOwner(field)) != 0)
722 {
723 /* Record the explicit field offset */
724 field->offset = fieldLayout->offset;
725 field->nativeOffset = fieldLayout->offset;
726
727 /* Extend the default class size to include the field */
728 if((field->offset + typeLayout.size) > layout->size)
729 {
730 layout->size = field->offset + typeLayout.size;
731 }
732 if((field->offset + typeLayout.nativeSize) > layout->nativeSize)
733 {
734 layout->nativeSize = field->offset + typeLayout.nativeSize;
735 }
736 }
737 else
738 {
739 /* Align the field on an appropriate boundary */
740 if((layout->size % typeLayout.alignment) != 0)
741 {
742 layout->size += typeLayout.alignment -
743 (layout->size % typeLayout.alignment);
744 }
745 if((layout->nativeSize % typeLayout.nativeAlignment) != 0)
746 {
747 layout->nativeSize += typeLayout.nativeAlignment -
748 (layout->nativeSize % typeLayout.nativeAlignment);
749 }
750
751 /* Record the field's offset and advance past it */
752 field->offset = layout->size;
753 field->nativeOffset = layout->nativeSize;
754 layout->size += typeLayout.size;
755 layout->nativeSize += typeLayout.nativeSize;
756 }
757
758 /* Update the maximum alignment */
759 if(typeLayout.alignment > maxAlignment)
760 {
761 maxAlignment = typeLayout.alignment;
762 }
763 if(typeLayout.nativeAlignment > maxNativeAlignment)
764 {
765 maxNativeAlignment = typeLayout.nativeAlignment;
766 }
767
768 /* Set the "managedInstance" flag if the type is managed */
769 if(typeLayout.managedInstance)
770 {
771 layout->managedInstance = 1;
772 }
773 }
774 }
775
776 /* Compute the final class size based on explicit sizes and alignment */
777 if(maxAlignment > layout->alignment)
778 {
779 layout->alignment = maxAlignment;
780 }
781 if(explicitSize > layout->size)
782 {
783 layout->size = explicitSize;
784 }
785 else if((layout->size % layout->alignment) != 0)
786 {
787 layout->size += layout->alignment -
788 (layout->size % layout->alignment);
789 }
790 if(maxNativeAlignment > layout->nativeAlignment)
791 {
792 layout->nativeAlignment = maxNativeAlignment;
793 }
794 if(explicitSize > layout->nativeSize)
795 {
796 layout->nativeSize = explicitSize;
797 }
798 else if((layout->nativeSize % layout->nativeAlignment) != 0)
799 {
800 layout->nativeSize += layout->nativeAlignment -
801 (layout->nativeSize % layout->nativeAlignment);
802 }
803
804 /* Record the object size information for this class */
805 classPrivate->size = layout->size;
806 classPrivate->alignment = layout->alignment;
807 classPrivate->nativeSize = layout->nativeSize;
808 classPrivate->nativeAlignment = layout->nativeAlignment;
809 classPrivate->inLayout = 0;
810
811 /* Allocate the static fields. We must do this after the
812 regular fields because some of the statics may be instances
813 of the class that we are trying to lay out, especially
814 in value type definitions */
815 field = 0;
816 while((field = (ILField *)ILClassNextMemberByKind
817 (info, (ILMember *)field, IL_META_MEMBERKIND_FIELD)) != 0)
818 {
819 if((field->member.attributes & IL_META_FIELDDEF_STATIC) != 0 &&
820 (field->member.attributes & IL_META_FIELDDEF_LITERAL) == 0)
821 {
822 /* Lay out a static field */
823 fieldRVA = ILFieldRVAGetFromOwner(field);
824 if(fieldRVA && !allowRVALayout)
825 {
826 /* RVA fields are not permitted, so remove the attribute */
827 field->member.attributes &= ~IL_META_FIELDDEF_HAS_FIELD_RVA;
828 }
829 if(!fieldRVA || !allowRVALayout)
830 {
831 /* Get the layout information for this field's type */
832 if(!LayoutType(process, field->member.signature, &typeLayout))
833 {
834 info->userData = 0;
835 return 0;
836 }
837
838 /* Thread-static variables are allocated slots from the
839 ILExecProcess record. We assume that some higher level
840 function has acquired the metadata lock on the process */
841 if(ILFieldIsThreadStatic(field))
842 {
843 /* Store the slot number in the "offset" field and
844 the field size in the "nativeOffset" field */
845 field->offset = (process->numThreadStaticSlots)++;
846 field->nativeOffset = typeLayout.size;
847 continue;
848 }
849
850 /* Align the field on an appropriate boundary */
851 if((layout->staticSize % typeLayout.alignment) != 0)
852 {
853 layout->staticSize += typeLayout.alignment -
854 (layout->staticSize % typeLayout.alignment);
855 }
856
857 /* Record the field's offset and advance past it */
858 field->offset = layout->staticSize;
859 field->nativeOffset = layout->staticSize;
860 layout->staticSize += typeLayout.size;
861
862 /* Set the "managedStatic" flag if the type is managed */
863 if(typeLayout.managedInstance)
864 {
865 layout->managedStatic = 1;
866 }
867 }
868 }
869 }
870
871 /* Allocate vtable slots to the virtual methods in this class */
872 method = 0;
873 explicitSize = layout->vtableSize;
874 while((method = (ILMethod *)ILClassNextMemberByKind
875 (info, (ILMember *)method, IL_META_MEMBERKIND_METHOD)) != 0)
876 {
877 /* Skip this method if it isn't virtual */
878 if((method->member.attributes & IL_META_METHODDEF_VIRTUAL) == 0)
879 {
880 continue;
881 }
882
883 /* Is this the finalize method? */
884 if(method->member.name[0] == 'F' &&
885 !strcmp(method->member.name + 1, "inalize") &&
886 method->member.signature->un.method__.retType__ == ILType_Void &&
887 method->member.signature->num__ == 0)
888 {
889 /* Determine if the finalizer is non-trivial */
890 if(!ILMethodGetCode(method, &code) ||
891 code.codeLen != 1 ||
892 ((unsigned char *)(code.code))[0] != IL_OP_RET)
893 {
894 layout->hasFinalizer = 1;
895 }
896 }
897
898 /* Do we need a new slot for this method? */
899 if((method->member.attributes & IL_META_METHODDEF_NEW_SLOT) != 0)
900 {
901 /* Allocate a vtable slot */
902 method->index = layout->vtableSize;
903 ++(layout->vtableSize);
904 }
905 else
906 {
907 /* Find the method in an ancestor class that this one overrides */
908 ancestor = FindVirtualAncestor(info, parent, method);
909 if(ancestor)
910 {
911 /* Use the same index as the ancestor */
912 method->index = ancestor->index;
913 }
914 else
915 {
916 /* No ancestor, so allocate a new slot. This case is
917 quite rare and will typically only happen with code
918 that has been loaded from a Java .class file, or
919 where the ancestor method is not accessible due to
920 permission issues */
921 method->member.attributes |= IL_META_METHODDEF_NEW_SLOT;
922 method->index = layout->vtableSize;
923 ++(layout->vtableSize);
924 }
925 }
926 }
927
928 /* If the vtable has grown too big, then bail out */
929 if(layout->vtableSize > (ILUInt32)65535)
930 {
931 info->userData = 0;
932 return 0;
933 }
934
935 /* Allocate the vtable and copy the parent's vtable into it */
936 if((vtable = (ILMethod **)
937 ILMemStackAllocItem(&(info->programItem.image->memStack),
938 layout->vtableSize * sizeof(ILMethod *))) == 0)
939 {
940 info->userData = 0;
941 return 0;
942 }
943 if(explicitSize > 0)
944 {
945 ILMemCpy(vtable, layout->vtable, explicitSize * sizeof(ILMethod *));
946 }
947
948 /* Override the vtable slots with this class's method implementations */
949 method = 0;
950 while((method = (ILMethod *)ILClassNextMemberByKind
951 (info, (ILMember *)method, IL_META_MEMBERKIND_METHOD)) != 0)
952 {
953 if((method->member.attributes & IL_META_METHODDEF_VIRTUAL) != 0)
954 {
955 vtable[method->index] = method;
956 }
957 }
958
959 /* Compute the interface tables for this class */
960 if((info->attributes & IL_META_TYPEDEF_CLASS_SEMANTICS_MASK) !=
961 IL_META_TYPEDEF_INTERFACE)
962 {
963 implements = info->implements;
964 while(implements != 0)
965 {
966 parent = ILClassResolve(implements->interface);
967 if(parent->userData)
968 {
969 if(!ComputeInterfaceTable(info, parent))
970 {
971 info->userData = 0;
972 return 0;
973 }
974 }
975 implements = implements->nextInterface;
976 }
977 }
978
979 /* Record the rest of the layout information for this class */
980 classPrivate->staticSize = layout->staticSize;
981 classPrivate->vtableSize = layout->vtableSize;
982 classPrivate->vtable = vtable;
983 classPrivate->hasFinalizer = layout->hasFinalizer;
984 classPrivate->managedInstance = layout->managedInstance;
985 classPrivate->managedStatic = layout->managedStatic;
986 layout->vtable = vtable;
987
988 #ifdef IL_USE_IMTS
989 /* Build the interface method table for this class */
990 BuildIMT(process, info, classPrivate);
991 #endif
992
993 /* Done */
994 /* add the classprivate data to the liked list */
995 classPrivate->nextClassPrivate = process->firstClassPrivate;
996 process->firstClassPrivate = classPrivate;
997
998 return 1;
999 }
1000
1001 int _ILLayoutClass(ILExecProcess *process, ILClass *info)
1002 {
1003 LayoutInfo layout;
1004 return LayoutClass(process, info, &layout);
1005 }
1006
1007 ILUInt32 _ILLayoutClassReturn(ILExecProcess *process, ILClass *info, ILUInt32 *alignment)
1008 {
1009 LayoutInfo layout;
1010 if(LayoutClass(process, info, &layout))
1011 {
1012 *alignment = layout.alignment;
1013 return layout.size;
1014 }
1015 else
1016 {
1017 *alignment = 0;
1018 return 0;
1019 }
1020 }
1021
1022 int _ILLayoutAlreadyDone(ILClass *info)
1023 {
1024 if(info->userData)
1025 {
1026 ILClassPrivate *classPrivate = (ILClassPrivate *)(info->userData);
1027 return !(classPrivate->inLayout);
1028 }
1029 else
1030 {
1031 return 0;
1032 }
1033 }
1034
1035 ILUInt32 _ILSizeOfTypeLocked(ILExecProcess *process, ILType *type)
1036 {
1037 LayoutInfo layout;
1038 if(!LayoutType(process, type, &layout))
1039 {
1040 return 0;
1041 }
1042 else
1043 {
1044 return layout.size;
1045 }
1046 }
1047
1048 ILUInt32 ILSizeOfType(ILExecThread *thread, ILType *type)
1049 {
1050 if(!ILType_IsValueType(type))
1051 {
1052 /* We can take a shortcut because the type is not a value type */
1053 return _ILSizeOfTypeLocked(_ILExecThreadProcess(thread), type);
1054 }
1055 else
1056 {
1057 /* We have to lock down the metadata first */
1058 ILUInt32 size;
1059 IL_METADATA_WRLOCK(_ILExecThreadProcess(thread));
1060 size = _ILSizeOfTypeLocked(_ILExecThreadProcess(thread), type);
1061 IL_METADATA_UNLOCK(_ILExecThreadProcess(thread));
1062 return size;
1063 }
1064 }
1065
1066 #ifdef __cplusplus
1067 };
1068 #endif

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26