objpas.inc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  4. This unit makes Free Pascal as much as possible Delphi compatible
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {****************************************************************************
  12. Internal Routines called from the Compiler
  13. ****************************************************************************}
  14. { the reverse order of the parameters make code generation easier }
  15. function fpc_do_is(aclass : tclass;aobject : tobject) : boolean;[public,alias: 'FPC_DO_IS']; compilerproc;
  16. begin
  17. fpc_do_is:=assigned(aobject) and assigned(aclass) and
  18. aobject.inheritsfrom(aclass);
  19. end;
  20. { the reverse order of the parameters make code generation easier }
  21. function fpc_do_as(aclass : tclass;aobject : tobject): tobject;[public,alias: 'FPC_DO_AS']; compilerproc;
  22. begin
  23. if assigned(aobject) and not(aobject.inheritsfrom(aclass)) then
  24. handleerrorframe(219,get_frame);
  25. result := aobject;
  26. end;
  27. { interface helpers }
  28. procedure fpc_intf_decr_ref(var i: pointer);[public,alias: 'FPC_INTF_DECR_REF']; compilerproc;
  29. begin
  30. if assigned(i) then
  31. IUnknown(i)._Release;
  32. i:=nil;
  33. end;
  34. { local declaration for intf_decr_ref for local access }
  35. procedure intf_decr_ref(var i: pointer); [external name 'FPC_INTF_DECR_REF'];
  36. procedure fpc_intf_incr_ref(i: pointer);[public,alias: 'FPC_INTF_INCR_REF']; compilerproc;
  37. begin
  38. if assigned(i) then
  39. IUnknown(i)._AddRef;
  40. end;
  41. { local declaration of intf_incr_ref for local access }
  42. procedure intf_incr_ref(i: pointer); [external name 'FPC_INTF_INCR_REF'];
  43. procedure fpc_intf_assign(var D: pointer; const S: pointer);[public,alias: 'FPC_INTF_ASSIGN']; compilerproc;
  44. begin
  45. if assigned(S) then
  46. IUnknown(S)._AddRef;
  47. if assigned(D) then
  48. IUnknown(D)._Release;
  49. D:=S;
  50. end;
  51. function fpc_intf_as(const S: pointer; const iid: TGUID): pointer;[public,alias: 'FPC_INTF_AS']; compilerproc;
  52. var
  53. tmpi: pointer; // _AddRef before _Release
  54. begin
  55. if assigned(S) then
  56. begin
  57. if IUnknown(S).QueryInterface(iid,tmpi)<>S_OK then
  58. handleerror(219);
  59. fpc_intf_as:=tmpi;
  60. end
  61. else
  62. fpc_intf_as:=nil;
  63. end;
  64. function fpc_class_as_intf(const S: pointer; const iid: TGUID): pointer;[public,alias: 'FPC_CLASS_AS_INTF']; compilerproc;
  65. var
  66. tmpi: pointer; // _AddRef before _Release
  67. begin
  68. if assigned(S) then
  69. begin
  70. if not TObject(S).GetInterface(iid,tmpi) then
  71. handleerror(219);
  72. fpc_class_as_intf:=tmpi;
  73. end
  74. else
  75. fpc_class_as_intf:=nil;
  76. end;
  77. {****************************************************************************
  78. TOBJECT
  79. ****************************************************************************}
  80. constructor TObject.Create;
  81. begin
  82. end;
  83. destructor TObject.Destroy;
  84. begin
  85. end;
  86. procedure TObject.Free;
  87. begin
  88. // the call via self avoids a warning
  89. if self<>nil then
  90. self.destroy;
  91. end;
  92. class function TObject.InstanceSize : SizeInt;
  93. begin
  94. InstanceSize:=pSizeInt(pointer(self)+vmtInstanceSize)^;
  95. end;
  96. procedure InitInterfacePointers(objclass: tclass;instance : pointer);
  97. var
  98. intftable : pinterfacetable;
  99. i : longint;
  100. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  101. IOffset : longint;
  102. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  103. begin
  104. while assigned(objclass) do
  105. begin
  106. intftable:=pinterfacetable((pointer(objclass)+vmtIntfTable)^);
  107. if assigned(intftable) then
  108. for i:=0 to intftable^.EntryCount-1 do
  109. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  110. begin
  111. move(intftable^.Entries[i].IOffset,IOffset,sizeof(longint));
  112. move(pointer(intftable^.Entries[i].VTable),ppointer(@(PChar(instance)[IOffset]))^,sizeof(pointer));
  113. end;
  114. {$else FPC_REQUIRES_PROPER_ALIGNMENT}
  115. ppointer(@(PChar(instance)[intftable^.Entries[i].IOffset]))^:=
  116. pointer(intftable^.Entries[i].VTable);
  117. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  118. objclass:=pclass(pointer(objclass)+vmtParent)^;
  119. end;
  120. end;
  121. class function TObject.InitInstance(instance : pointer) : tobject;
  122. begin
  123. { the size is saved at offset 0 }
  124. fillchar(instance^, InstanceSize, 0);
  125. { insert VMT pointer into the new created memory area }
  126. { (in class methods self contains the VMT!) }
  127. ppointer(instance)^:=pointer(self);
  128. InitInterfacePointers(self,instance);
  129. InitInstance:=TObject(Instance);
  130. end;
  131. class function TObject.ClassParent : tclass;
  132. begin
  133. { type of self is class of tobject => it points to the vmt }
  134. { the parent vmt is saved at offset vmtParent }
  135. classparent:=pclass(pointer(self)+vmtParent)^;
  136. end;
  137. class function TObject.NewInstance : tobject;
  138. var
  139. p : pointer;
  140. begin
  141. getmem(p, InstanceSize);
  142. if p <> nil then
  143. InitInstance(p);
  144. NewInstance:=TObject(p);
  145. end;
  146. procedure TObject.FreeInstance;
  147. begin
  148. CleanupInstance;
  149. FreeMem(Pointer(Self));
  150. end;
  151. class function TObject.ClassType : TClass;
  152. begin
  153. ClassType:=TClass(Pointer(Self))
  154. end;
  155. type
  156. tmethodnamerec = packed record
  157. name : pshortstring;
  158. addr : pointer;
  159. end;
  160. tmethodnametable = packed record
  161. count : dword;
  162. entries : packed array[0..0] of tmethodnamerec;
  163. end;
  164. pmethodnametable = ^tmethodnametable;
  165. class function TObject.MethodAddress(const name : shortstring) : pointer;
  166. var
  167. UName : ShortString;
  168. methodtable : pmethodnametable;
  169. i : dword;
  170. vmt : tclass;
  171. begin
  172. UName := UpCase(name);
  173. vmt:=self;
  174. while assigned(vmt) do
  175. begin
  176. methodtable:=pmethodnametable((Pointer(vmt)+vmtMethodTable)^);
  177. if assigned(methodtable) then
  178. begin
  179. for i:=0 to methodtable^.count-1 do
  180. if UpCase(methodtable^.entries[i].name^)=UName then
  181. begin
  182. MethodAddress:=methodtable^.entries[i].addr;
  183. exit;
  184. end;
  185. end;
  186. vmt:=pclass(pointer(vmt)+vmtParent)^;
  187. end;
  188. MethodAddress:=nil;
  189. end;
  190. class function TObject.MethodName(address : pointer) : shortstring;
  191. var
  192. methodtable : pmethodnametable;
  193. i : dword;
  194. vmt : tclass;
  195. begin
  196. vmt:=self;
  197. while assigned(vmt) do
  198. begin
  199. methodtable:=pmethodnametable((Pointer(vmt)+vmtMethodTable)^);
  200. if assigned(methodtable) then
  201. begin
  202. for i:=0 to methodtable^.count-1 do
  203. if methodtable^.entries[i].addr=address then
  204. begin
  205. MethodName:=methodtable^.entries[i].name^;
  206. exit;
  207. end;
  208. end;
  209. vmt:=pclass(pointer(vmt)+vmtParent)^;
  210. end;
  211. MethodName:='';
  212. end;
  213. function TObject.FieldAddress(const name : shortstring) : pointer;
  214. type
  215. PFieldInfo = ^TFieldInfo;
  216. TFieldInfo =
  217. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  218. packed
  219. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  220. record
  221. FieldOffset: PtrUInt;
  222. ClassTypeIndex: Word;
  223. Name: ShortString;
  224. end;
  225. PFieldTable = ^TFieldTable;
  226. TFieldTable =
  227. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  228. packed
  229. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  230. record
  231. FieldCount: Word;
  232. ClassTable: Pointer;
  233. { should be array[Word] of TFieldInfo; but
  234. Elements have variant size! force at least proper alignment }
  235. Fields: array[0..0] of TFieldInfo
  236. end;
  237. var
  238. UName: ShortString;
  239. CurClassType: TClass;
  240. FieldTable: PFieldTable;
  241. FieldInfo: PFieldInfo;
  242. i: Integer;
  243. begin
  244. if Length(name) > 0 then
  245. begin
  246. UName := UpCase(name);
  247. CurClassType := ClassType;
  248. while CurClassType <> nil do
  249. begin
  250. FieldTable := PFieldTable((Pointer(CurClassType) + vmtFieldTable)^);
  251. if FieldTable <> nil then
  252. begin
  253. FieldInfo := @FieldTable^.Fields;
  254. for i := 0 to FieldTable^.FieldCount - 1 do
  255. begin
  256. if UpCase(FieldInfo^.Name) = UName then
  257. begin
  258. fieldaddress := Pointer(Self) + FieldInfo^.FieldOffset;
  259. exit;
  260. end;
  261. FieldInfo := @FieldInfo^.Name + 1 + Length(FieldInfo^.Name);
  262. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  263. { align to largest field of TFieldInfo }
  264. FieldInfo := Align(FieldInfo, SizeOf(PtrUInt));
  265. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  266. end;
  267. end;
  268. { Try again with the parent class type }
  269. CurClassType:=pclass(pointer(CurClassType)+vmtParent)^;
  270. end;
  271. end;
  272. fieldaddress:=nil;
  273. end;
  274. function TObject.SafeCallException(exceptobject : tobject;
  275. exceptaddr : pointer) : longint;
  276. begin
  277. safecallexception:=0;
  278. end;
  279. class function TObject.ClassInfo : pointer;
  280. begin
  281. ClassInfo:=ppointer(Pointer(self)+vmtTypeInfo)^;
  282. end;
  283. class function TObject.ClassName : ShortString;
  284. begin
  285. ClassName:=PShortString((Pointer(Self)+vmtClassName)^)^;
  286. end;
  287. class function TObject.ClassNameIs(const name : string) : boolean;
  288. begin
  289. ClassNameIs:=Upcase(ClassName)=Upcase(name);
  290. end;
  291. class function TObject.InheritsFrom(aclass : TClass) : Boolean;
  292. var
  293. vmt : tclass;
  294. begin
  295. vmt:=self;
  296. while assigned(vmt) do
  297. begin
  298. if vmt=aclass then
  299. begin
  300. InheritsFrom:=true;
  301. exit;
  302. end;
  303. vmt:=pclass(pointer(vmt)+vmtParent)^;
  304. end;
  305. InheritsFrom:=false;
  306. end;
  307. class function TObject.stringmessagetable : pstringmessagetable;
  308. type
  309. pdword = ^dword;
  310. begin
  311. stringmessagetable:=pstringmessagetable((pointer(Self)+vmtMsgStrPtr)^);
  312. end;
  313. type
  314. tmessagehandler = procedure(var msg) of object;
  315. tmessagehandlerrec = packed record
  316. proc : pointer;
  317. obj : pointer;
  318. end;
  319. procedure TObject.Dispatch(var message);
  320. type
  321. tmsgtable = packed record
  322. index : dword;
  323. method : pointer;
  324. end;
  325. pmsgtable = ^tmsgtable;
  326. var
  327. index : dword;
  328. count,i : longint;
  329. msgtable : pmsgtable;
  330. p : pointer;
  331. vmt : tclass;
  332. msghandler : tmessagehandler;
  333. begin
  334. index:=dword(message);
  335. vmt:=ClassType;
  336. while assigned(vmt) do
  337. begin
  338. // See if we have messages at all in this class.
  339. p:=pointer(vmt)+vmtDynamicTable;
  340. If assigned(PPointer(p)^) then
  341. begin
  342. msgtable:=pmsgtable(Pointer(p^)+4);
  343. count:=pdword(p^)^;
  344. end
  345. else
  346. Count:=0;
  347. { later, we can implement a binary search here }
  348. for i:=0 to count-1 do
  349. begin
  350. if index=msgtable[i].index then
  351. begin
  352. p:=msgtable[i].method;
  353. tmessagehandlerrec(msghandler).proc:=p;
  354. tmessagehandlerrec(msghandler).obj:=self;
  355. msghandler(message);
  356. exit;
  357. end;
  358. end;
  359. vmt:=pclass(pointer(vmt)+vmtParent)^;
  360. end;
  361. DefaultHandler(message);
  362. end;
  363. procedure TObject.DispatchStr(var message);
  364. type
  365. PSizeUInt = ^SizeUInt;
  366. var
  367. name : shortstring;
  368. count,i : longint;
  369. msgstrtable : pmsgstrtable;
  370. p : pointer;
  371. vmt : tclass;
  372. msghandler : tmessagehandler;
  373. begin
  374. name:=pshortstring(@message)^;
  375. vmt:=ClassType;
  376. while assigned(vmt) do
  377. begin
  378. p:=(pointer(vmt)+vmtMsgStrPtr);
  379. If (P<>Nil) and (PDWord(P)^<>0) then
  380. begin
  381. count:=pdword(PSizeUInt(p)^)^;
  382. msgstrtable:=pmsgstrtable(PSizeUInt(P)^+4);
  383. end
  384. else
  385. Count:=0;
  386. { later, we can implement a binary search here }
  387. for i:=0 to count-1 do
  388. begin
  389. if name=msgstrtable[i].name^ then
  390. begin
  391. p:=msgstrtable[i].method;
  392. tmessagehandlerrec(msghandler).proc:=p;
  393. tmessagehandlerrec(msghandler).obj:=self;
  394. msghandler(message);
  395. exit;
  396. end;
  397. end;
  398. vmt:=pclass(pointer(vmt)+vmtParent)^;
  399. end;
  400. DefaultHandlerStr(message);
  401. end;
  402. procedure TObject.DefaultHandler(var message);
  403. begin
  404. end;
  405. procedure TObject.DefaultHandlerStr(var message);
  406. begin
  407. end;
  408. procedure TObject.CleanupInstance;
  409. Type
  410. TRecElem = packed Record
  411. Info : Pointer;
  412. Offset : Longint;
  413. end;
  414. TRecElemArray = packed array[1..Maxint] of TRecElem;
  415. PRecRec = ^TRecRec;
  416. TRecRec = record
  417. Size,Count : Longint;
  418. Elements : TRecElemArray;
  419. end;
  420. var
  421. vmt : tclass;
  422. temp : pbyte;
  423. count,
  424. i : longint;
  425. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  426. recelem : TRecElem;
  427. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  428. begin
  429. vmt:=ClassType;
  430. while vmt<>nil do
  431. begin
  432. { This need to be included here, because Finalize()
  433. has should support for tkClass }
  434. Temp:=Pointer((Pointer(vmt)+vmtInitTable)^);
  435. if Assigned(Temp) then
  436. begin
  437. inc(Temp);
  438. I:=Temp^;
  439. inc(temp,I+1); // skip name string;
  440. temp:=aligntoptr(temp);
  441. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  442. move(PRecRec(Temp)^.Count,Count,sizeof(Count));
  443. {$else FPC_REQUIRES_PROPER_ALIGNMENT}
  444. Count:=PRecRec(Temp)^.Count; // get element Count
  445. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  446. For I:=1 to count do
  447. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  448. begin
  449. move(PRecRec(Temp)^.elements[I],RecElem,sizeof(RecElem));
  450. With RecElem do
  451. int_Finalize (pointer(self)+Offset,Info);
  452. end;
  453. {$else FPC_REQUIRES_PROPER_ALIGNMENT}
  454. With PRecRec(Temp)^.elements[I] do
  455. int_Finalize (pointer(self)+Offset,Info);
  456. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  457. end;
  458. vmt:=pclass(pointer(vmt)+vmtParent)^;
  459. end;
  460. end;
  461. procedure TObject.AfterConstruction;
  462. begin
  463. end;
  464. procedure TObject.BeforeDestruction;
  465. begin
  466. end;
  467. function IsGUIDEqual(const guid1, guid2: tguid): boolean;
  468. begin
  469. IsGUIDEqual:=
  470. (guid1.D1=guid2.D1) and
  471. (PDWORD(@guid1.D2)^=PDWORD(@guid2.D2)^) and
  472. (PDWORD(@guid1.D4[0])^=PDWORD(@guid2.D4[0])^) and
  473. (PDWORD(@guid1.D4[4])^=PDWORD(@guid2.D4[4])^);
  474. end;
  475. function TObject.getinterface(const iid : tguid;out obj) : boolean;
  476. var
  477. IEntry: pinterfaceentry;
  478. begin
  479. IEntry:=getinterfaceentry(iid);
  480. if Assigned(IEntry) then
  481. begin
  482. Pointer(obj):=Pointer(Self)+IEntry^.IOffset;
  483. if assigned(pointer(obj)) then
  484. iinterface(obj)._AddRef;
  485. getinterface:=True;
  486. end
  487. else
  488. begin
  489. PPointer(@Obj)^:=nil;
  490. getinterface:=False;
  491. end;
  492. end;
  493. function TObject.getinterfacebystr(const iidstr : string;out obj) : boolean;
  494. var
  495. IEntry: pinterfaceentry;
  496. begin
  497. IEntry:=getinterfaceentrybystr(iidstr);
  498. if Assigned(IEntry) then
  499. begin
  500. Pointer(obj):=Pointer(Self)+IEntry^.IOffset;
  501. if assigned(pointer(obj)) then
  502. iinterface(obj)._AddRef;
  503. getinterfacebystr:=True;
  504. end
  505. else
  506. begin
  507. PPointer(@Obj)^:=nil;
  508. getinterfacebystr:=False;
  509. end;
  510. end;
  511. class function TObject.getinterfaceentry(const iid : tguid) : pinterfaceentry;
  512. var
  513. i: integer;
  514. intftable: pinterfacetable;
  515. Res: pinterfaceentry;
  516. begin
  517. getinterfaceentry:=nil;
  518. intftable:=pinterfacetable((pointer(Self)+vmtIntfTable)^);
  519. if assigned(intftable) then begin
  520. i:=intftable^.EntryCount;
  521. Res:=@intftable^.Entries[0];
  522. while (i>0) and
  523. not (assigned(Res^.iid) and IsGUIDEqual(Res^.iid^,iid)) do begin
  524. inc(Res);
  525. dec(i);
  526. end;
  527. if (i>0) then
  528. getinterfaceentry:=Res;
  529. end;
  530. if (getinterfaceentry=nil)and not(classparent=nil) then
  531. getinterfaceentry:=classparent.getinterfaceentry(iid)
  532. end;
  533. class function TObject.getinterfaceentrybystr(const iidstr : string) : pinterfaceentry;
  534. var
  535. i: integer;
  536. intftable: pinterfacetable;
  537. Res: pinterfaceentry;
  538. begin
  539. getinterfaceentrybystr:=nil;
  540. intftable:=getinterfacetable;
  541. if assigned(intftable) then begin
  542. i:=intftable^.EntryCount;
  543. Res:=@intftable^.Entries[0];
  544. while (i>0) and (Res^.iidstr^<>iidstr) do begin
  545. inc(Res);
  546. dec(i);
  547. end;
  548. if (i>0) then
  549. getinterfaceentrybystr:=Res;
  550. end;
  551. if (getinterfaceentrybystr=nil)and not(classparent=nil) then
  552. getinterfaceentrybystr:=classparent.getinterfaceentrybystr(iidstr)
  553. end;
  554. class function TObject.getinterfacetable : pinterfacetable;
  555. begin
  556. getinterfacetable:=pinterfacetable((pointer(Self)+vmtIntfTable)^);
  557. end;
  558. {****************************************************************************
  559. TINTERFACEDOBJECT
  560. ****************************************************************************}
  561. function TInterfacedObject.QueryInterface(
  562. const iid : tguid;out obj) : longint;stdcall;
  563. begin
  564. if getinterface(iid,obj) then
  565. result:=0
  566. else
  567. result:=longint($80004002);
  568. end;
  569. function TInterfacedObject._AddRef : longint;stdcall;
  570. begin
  571. inclocked(frefcount);
  572. _addref:=frefcount;
  573. end;
  574. function TInterfacedObject._Release : longint;stdcall;
  575. begin
  576. if declocked(frefcount) then
  577. begin
  578. self.destroy;
  579. _Release:=0;
  580. end
  581. else
  582. _Release:=frefcount;
  583. end;
  584. procedure TInterfacedObject.AfterConstruction;
  585. begin
  586. { we need to fix the refcount we forced in newinstance }
  587. { further, it must be done in a thread safe way }
  588. declocked(frefcount);
  589. end;
  590. procedure TInterfacedObject.BeforeDestruction;
  591. begin
  592. if frefcount<>0 then
  593. HandleError(204);
  594. end;
  595. class function TInterfacedObject.NewInstance : TObject;
  596. begin
  597. NewInstance:=inherited NewInstance;
  598. TInterfacedObject(NewInstance).frefcount:=1;
  599. end;
  600. {****************************************************************************
  601. Exception Support
  602. ****************************************************************************}
  603. {$i except.inc}
  604. {****************************************************************************
  605. Initialize
  606. ****************************************************************************}