Mercurial > projects > ddmd
annotate dmd/InterfaceDeclaration.d @ 22:fd4acc376c45
Implemented object file output and linking on linux.
author | Robert Clipsham <robert@octarineparrot.com> |
---|---|
date | Thu, 08 Apr 2010 04:21:03 +0100 |
parents | 10317f0c89a5 |
children | 460959608115 |
rev | line source |
---|---|
0 | 1 module dmd.InterfaceDeclaration; |
2 | |
3 import dmd.ClassDeclaration; | |
4 import dmd.Loc; | |
5 import dmd.DsymbolTable; | |
6 import dmd.STC; | |
7 import dmd.Type; | |
8 import dmd.TY; | |
9 import dmd.LINK; | |
10 import dmd.Argument; | |
11 import dmd.Util; | |
12 import dmd.TypeTuple; | |
13 import dmd.PROT; | |
14 import dmd.TypeClass; | |
15 import dmd.Identifier; | |
16 import dmd.ArrayTypes; | |
17 import dmd.Dsymbol; | |
18 import dmd.Scope; | |
19 import dmd.Global; | |
22
fd4acc376c45
Implemented object file output and linking on linux.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
20 import dmd.Module; |
0 | 21 import dmd.BaseClass; |
22 import dmd.Id; | |
23 | |
24 import dmd.backend.Symbol; | |
25 import dmd.backend.TYM; | |
26 import dmd.backend.dt_t; | |
27 import dmd.backend.Util; | |
28 import dmd.codegen.Util; | |
29 import dmd.backend.SC; | |
30 import dmd.backend.FL; | |
31 import dmd.backend.LIST; | |
32 import dmd.backend.SFL; | |
33 | |
34 class InterfaceDeclaration : ClassDeclaration | |
35 { | |
36 version (DMDV2) { | |
37 bool cpp; // true if this is a C++ interface | |
38 } | |
39 this(Loc loc, Identifier id, BaseClasses baseclasses) | |
40 { | |
41 super(loc, id, baseclasses); | |
42 | |
43 if (id is Id.IUnknown) // IUnknown is the root of all COM interfaces | |
44 { | |
45 com = true; | |
46 cpp = true; // IUnknown is also a C++ interface | |
47 } | |
48 } | |
49 | |
50 Dsymbol syntaxCopy(Dsymbol s) | |
51 { | |
52 assert(false); | |
53 } | |
54 | |
55 void semantic(Scope sc) | |
56 { | |
57 int i; | |
58 | |
59 //printf("InterfaceDeclaration.semantic(%s), type = %p\n", toChars(), type); | |
60 if (inuse) | |
61 return; | |
62 | |
63 if (!sc) | |
64 sc = scope_; | |
65 if (!parent && sc.parent && !sc.parent.isModule()) | |
66 parent = sc.parent; | |
67 | |
68 type = type.semantic(loc, sc); | |
69 handle = type; | |
70 | |
71 if (!members) // if forward reference | |
72 { | |
73 //printf("\tinterface '%s' is forward referenced\n", toChars()); | |
74 return; | |
75 } | |
76 if (symtab) // if already done | |
77 { | |
78 if (!scope_) | |
79 return; | |
80 } | |
81 else | |
82 symtab = new DsymbolTable(); | |
83 | |
84 Scope scx = null; | |
85 if (scope_) | |
86 { | |
87 sc = scope_; | |
88 scx = scope_; // save so we don't make redundant copies | |
89 scope_ = null; | |
90 } | |
91 | |
92 if (sc.stc & STC.STCdeprecated) | |
93 { | |
94 isdeprecated = true; | |
95 } | |
96 | |
97 // Expand any tuples in baseclasses[] | |
98 for (i = 0; i < baseclasses.dim; ) | |
99 { | |
100 BaseClass b = cast(BaseClass)baseclasses.data[0]; | |
101 b.type = b.type.semantic(loc, sc); | |
102 Type tb = b.type.toBasetype(); | |
103 | |
104 if (tb.ty == TY.Ttuple) | |
105 { TypeTuple tup = cast(TypeTuple)tb; | |
106 PROT protection = b.protection; | |
107 baseclasses.remove(i); | |
108 size_t dim = Argument.dim(tup.arguments); | |
109 for (size_t j = 0; j < dim; j++) | |
110 { Argument arg = Argument.getNth(tup.arguments, j); | |
111 b = new BaseClass(arg.type, protection); | |
112 baseclasses.insert(i + j, cast(void*)b); | |
113 } | |
114 } | |
115 else | |
116 i++; | |
117 } | |
118 | |
119 if (!baseclasses.dim && sc.linkage == LINK.LINKcpp) | |
120 cpp = 1; | |
121 | |
122 // Check for errors, handle forward references | |
123 for (i = 0; i < baseclasses.dim; ) | |
124 { | |
125 TypeClass tc; | |
126 BaseClass b; | |
127 Type tb; | |
128 | |
129 b = cast(BaseClass)baseclasses.data[i]; | |
130 b.type = b.type.semantic(loc, sc); | |
131 tb = b.type.toBasetype(); | |
132 if (tb.ty == TY.Tclass) | |
133 tc = cast(TypeClass)tb; | |
134 else | |
135 tc = null; | |
136 if (!tc || !tc.sym.isInterfaceDeclaration()) | |
137 { | |
138 error("base type must be interface, not %s", b.type.toChars()); | |
139 baseclasses.remove(i); | |
140 continue; | |
141 } | |
142 else | |
143 { | |
144 // Check for duplicate interfaces | |
145 for (size_t j = 0; j < i; j++) | |
146 { | |
147 BaseClass b2 = cast(BaseClass)baseclasses.data[j]; | |
148 if (b2.base is tc.sym) | |
149 error("inherits from duplicate interface %s", b2.base.toChars()); | |
150 } | |
151 | |
152 b.base = tc.sym; | |
153 if (b.base == this || isBaseOf2(b.base)) | |
154 { | |
155 error("circular inheritance of interface"); | |
156 baseclasses.remove(i); | |
157 continue; | |
158 } | |
159 if (!b.base.symtab) | |
160 { | |
161 // Try to resolve forward reference | |
162 if (sc.mustsemantic && b.base.scope_) | |
163 b.base.semantic(null); | |
164 } | |
165 if (!b.base.symtab || b.base.scope_ || b.base.inuse) | |
166 { | |
167 //error("forward reference of base class %s", baseClass.toChars()); | |
168 // Forward reference of base, try again later | |
169 //printf("\ttry later, forward reference of base %s\n", b.base.toChars()); | |
170 scope_ = scx ? scx : new Scope(sc); | |
171 scope_.setNoFree(); | |
172 scope_.module_.addDeferredSemantic(this); | |
173 return; | |
174 } | |
175 } | |
176 static if (false) { | |
177 // Inherit const/invariant from base class | |
178 storage_class |= b.base.storage_class & STC.STC_TYPECTOR; | |
179 } | |
180 i++; | |
181 } | |
182 | |
183 interfaces_dim = baseclasses.dim; | |
184 interfaces = cast(BaseClass*)baseclasses.data; | |
185 | |
186 interfaceSemantic(sc); | |
187 | |
188 if (vtblOffset()) | |
189 vtbl.push(cast(void*)this); // leave room at vtbl[0] for classinfo | |
190 | |
191 // Cat together the vtbl[]'s from base interfaces | |
192 for (i = 0; i < interfaces_dim; i++) | |
193 { | |
194 BaseClass b = interfaces[i]; | |
195 | |
196 // Skip if b has already appeared | |
197 for (int k = 0; k < i; k++) | |
198 { | |
199 if (b == interfaces[i]) | |
200 goto Lcontinue; | |
201 } | |
202 | |
203 // Copy vtbl[] from base class | |
204 if (b.base.vtblOffset()) | |
205 { int d = b.base.vtbl.dim; | |
206 if (d > 1) | |
207 { | |
208 vtbl.reserve(d - 1); | |
209 for (int j = 1; j < d; j++) | |
210 vtbl.push(b.base.vtbl.data[j]); | |
211 } | |
212 } | |
213 else | |
214 { | |
215 vtbl.append(b.base.vtbl); | |
216 } | |
217 | |
218 Lcontinue: | |
219 ; | |
220 } | |
221 | |
222 protection = sc.protection; | |
223 storage_class |= sc.stc & STC.STC_TYPECTOR; | |
224 | |
225 for (i = 0; i < members.dim; i++) | |
226 { | |
227 Dsymbol s = cast(Dsymbol)members.data[i]; | |
228 s.addMember(sc, this, 1); | |
229 } | |
230 | |
231 sc = sc.push(this); | |
232 sc.stc &= ~(STC.STCfinal | STC.STCauto | STC.STCscope | STC.STCstatic | | |
233 STC.STCabstract | STC.STCdeprecated | STC.STC_TYPECTOR | STC.STCtls | STC.STCgshared); | |
234 sc.stc |= storage_class & STC.STC_TYPECTOR; | |
235 sc.parent = this; | |
236 if (isCOMinterface()) | |
237 sc.linkage = LINK.LINKwindows; | |
238 else if (isCPPinterface()) | |
239 sc.linkage = LINK.LINKcpp; | |
240 sc.structalign = 8; | |
241 structalign = sc.structalign; | |
242 sc.offset = PTRSIZE * 2; | |
243 inuse++; | |
244 for (i = 0; i < members.dim; i++) | |
245 { | |
246 Dsymbol s = cast(Dsymbol)members.data[i]; | |
247 s.semantic(sc); | |
248 } | |
249 inuse--; | |
250 //members.print(); | |
251 sc.pop(); | |
252 //printf("-InterfaceDeclaration.semantic(%s), type = %p\n", toChars(), type); | |
253 } | |
254 | |
255 bool isBaseOf(ClassDeclaration cd, int* poffset) | |
256 { | |
257 uint j; | |
258 | |
259 //printf("%s.InterfaceDeclaration.isBaseOf(cd = '%s')\n", toChars(), cd.toChars()); | |
260 assert(!baseClass); | |
261 for (j = 0; j < cd.interfaces_dim; j++) | |
262 { | |
263 BaseClass b = cd.interfaces[j]; | |
264 | |
265 //printf("\tbase %s\n", b.base.toChars()); | |
266 if (this == b.base) | |
267 { | |
268 //printf("\tfound at offset %d\n", b.offset); | |
269 if (poffset) | |
270 { | |
271 *poffset = b.offset; | |
272 if (j && cd.isInterfaceDeclaration()) | |
273 *poffset = OFFSET_RUNTIME; | |
274 } | |
275 return true; | |
276 } | |
277 if (isBaseOf(b, poffset)) | |
278 { | |
279 if (j && poffset && cd.isInterfaceDeclaration()) | |
280 *poffset = OFFSET_RUNTIME; | |
281 return true; | |
282 } | |
283 } | |
284 | |
285 if (cd.baseClass && isBaseOf(cd.baseClass, poffset)) | |
286 return true; | |
287 | |
288 if (poffset) | |
289 *poffset = 0; | |
290 return false; | |
291 } | |
292 | |
293 bool isBaseOf(BaseClass bc, int* poffset) | |
294 { | |
295 assert(false); | |
296 } | |
297 | |
298 string kind() | |
299 { | |
300 assert(false); | |
301 } | |
302 | |
303 /**************************************** | |
304 * Determine if slot 0 of the vtbl[] is reserved for something else. | |
305 * For class objects, yes, this is where the ClassInfo ptr goes. | |
306 * For COM interfaces, no. | |
307 * For non-COM interfaces, yes, this is where the Interface ptr goes. | |
308 */ | |
309 int vtblOffset() | |
310 { | |
311 if (isCOMinterface() || isCPPinterface()) | |
312 return 0; | |
313 return 1; | |
314 } | |
315 | |
316 version (DMDV2) { | |
317 bool isCPPinterface() | |
318 { | |
319 return cpp; | |
320 } | |
321 } | |
322 bool isCOMinterface() | |
323 { | |
324 return com; | |
325 } | |
326 | |
327 void toObjFile(int multiobj) // compile to .obj file | |
328 { | |
329 uint i; | |
330 uint offset; | |
331 Symbol* sinit; | |
332 SC scclass; | |
333 | |
334 //printf("InterfaceDeclaration.toObjFile('%s')\n", toChars()); | |
335 | |
336 if (!members) | |
337 return; | |
338 | |
339 if (global.params.symdebug) | |
340 toDebug(); | |
341 | |
342 scclass = SCglobal; | |
343 if (inTemplateInstance()) | |
344 scclass = SCcomdat; | |
345 | |
346 // Put out the members | |
347 for (i = 0; i < members.dim; i++) | |
348 { | |
349 Dsymbol member; | |
350 | |
351 member = cast(Dsymbol)members.data[i]; | |
352 if (!member.isFuncDeclaration()) | |
353 member.toObjFile(0); | |
354 } | |
355 | |
356 // Generate C symbols | |
357 toSymbol(); | |
358 | |
359 ////////////////////////////////////////////// | |
360 | |
361 // Put out the TypeInfo | |
362 type.getTypeInfo(null); | |
363 type.vtinfo.toObjFile(multiobj); | |
364 | |
365 ////////////////////////////////////////////// | |
366 | |
367 // Put out the ClassInfo | |
368 csym.Sclass = scclass; | |
369 csym.Sfl = FLdata; | |
370 | |
371 /* The layout is: | |
372 { | |
373 void **vptr; | |
374 monitor_t monitor; | |
375 byte[] initializer; // static initialization data | |
376 char[] name; // class name | |
377 void *[] vtbl; | |
378 Interface[] interfaces; | |
379 Object *base; // base class | |
380 void *destructor; | |
381 void *invariant; // class invariant | |
382 uint flags; | |
383 void *deallocator; | |
384 OffsetTypeInfo[] offTi; | |
385 void *defaultConstructor; | |
386 #if DMDV2 | |
387 const(MemberInfo[]) function(string) xgetMembers; // module getMembers() function | |
388 #endif | |
389 TypeInfo typeinfo; | |
390 } | |
391 */ | |
392 dt_t *dt = null; | |
393 | |
394 if (classinfo) | |
395 dtxoff(&dt, classinfo.toVtblSymbol(), 0, TYnptr); // vtbl for ClassInfo | |
396 else | |
397 dtdword(&dt, 0); // BUG: should be an assert() | |
398 dtdword(&dt, 0); // monitor | |
399 | |
400 // initializer[] | |
401 dtdword(&dt, 0); // size | |
402 dtdword(&dt, 0); // initializer | |
403 | |
404 // name[] | |
405 string name = toPrettyChars(); | |
406 size_t namelen = name.length; | |
407 dtdword(&dt, namelen); | |
408 dtabytes(&dt, TYnptr, 0, namelen + 1, toStringz(name)); | |
409 | |
410 // vtbl[] | |
411 dtdword(&dt, 0); | |
412 dtdword(&dt, 0); | |
413 | |
414 // vtblInterfaces.data[] | |
415 dtdword(&dt, vtblInterfaces.dim); | |
416 if (vtblInterfaces.dim) | |
417 { | |
418 if (classinfo) | |
419 assert(classinfo.structsize == CLASSINFO_SIZE); | |
420 offset = CLASSINFO_SIZE; | |
421 dtxoff(&dt, csym, offset, TYnptr); // (*) | |
422 } | |
423 else | |
424 dtdword(&dt, 0); | |
425 | |
426 // base | |
427 assert(!baseClass); | |
428 dtdword(&dt, 0); | |
429 | |
430 // dtor | |
431 dtdword(&dt, 0); | |
432 | |
433 // invariant | |
434 dtdword(&dt, 0); | |
435 | |
436 // flags | |
437 dtdword(&dt, 4 | isCOMinterface() | 32); | |
438 | |
439 // deallocator | |
440 dtdword(&dt, 0); | |
441 | |
442 // offTi[] | |
443 dtdword(&dt, 0); | |
444 dtdword(&dt, 0); // null for now, fix later | |
445 | |
446 // defaultConstructor | |
447 dtdword(&dt, 0); | |
448 | |
449 version (DMDV2) { | |
450 // xgetMembers | |
451 dtdword(&dt, 0); | |
452 } | |
453 | |
454 dtxoff(&dt, type.vtinfo.toSymbol(), 0, TYnptr); // typeinfo | |
455 | |
456 ////////////////////////////////////////////// | |
457 | |
458 // Put out vtblInterfaces.data[]. Must immediately follow csym, because | |
459 // of the fixup (*) | |
460 | |
461 offset += vtblInterfaces.dim * (4 * PTRSIZE); | |
462 for (i = 0; i < vtblInterfaces.dim; i++) | |
463 { | |
464 BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; | |
465 ClassDeclaration id = b.base; | |
466 | |
467 // ClassInfo | |
468 dtxoff(&dt, id.toSymbol(), 0, TYnptr); | |
469 | |
470 // vtbl[] | |
471 dtdword(&dt, 0); | |
472 dtdword(&dt, 0); | |
473 | |
474 // this offset | |
475 dtdword(&dt, b.offset); | |
476 } | |
477 | |
478 csym.Sdt = dt; | |
479 version (ELFOBJ) { | |
22
fd4acc376c45
Implemented object file output and linking on linux.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
480 csym.Sseg = Segment.CDATA; |
0 | 481 } |
482 version (MACHOBJ) { | |
22
fd4acc376c45
Implemented object file output and linking on linux.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
483 csym.Sseg = Segment.DATA; |
0 | 484 } |
485 outdata(csym); | |
486 if (isExport()) | |
487 obj_export(csym,0); | |
488 } | |
489 | |
490 /************************************* | |
491 * Create the "InterfaceInfo" symbol | |
492 */ | |
493 Symbol* toSymbol() | |
494 { | |
495 if (!csym) | |
496 { | |
497 Symbol *s; | |
498 | |
499 if (!scc) | |
500 scc = fake_classsym(Id.ClassInfo); | |
501 | |
502 s = toSymbolX("__Interface", SCextern, scc.Stype, "Z"); | |
503 s.Sfl = FLextern; | |
504 s.Sflags |= SFLnodebug; | |
505 csym = s; | |
506 slist_add(s); | |
507 } | |
508 return csym; | |
509 } | |
510 | |
511 InterfaceDeclaration isInterfaceDeclaration() { return this; } | |
22
fd4acc376c45
Implemented object file output and linking on linux.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
512 } |