Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1843 lines
52 KiB

  1. #ifndef __GCP_H
  2. #define __GCP_H
  3. // Great Circle garbage collector header
  4. /// Copyright Geodesic Systems 1993-95
  5. /// By Charles Fiterman.
  6. // Collector algorithm from an article by Henry G. Baker
  7. /// ACM Sigplan Notices March 1992 pp 66
  8. ///
  9. /// The Baker paper referred to this as a four color algorithm.
  10. /// Free, White (which I call Mixed), Grey (which I call Marked)
  11. /// and Black (which I call Passed).
  12. /// Dealing with C++ adds two new queues, which are really about C++.
  13. /// Locked, which is generally called the root object in collector
  14. /// terminology, and Limbo which is used for objects under construction.
  15. /// I think this is better than the original inconsistent color terminology.
  16. // Meaningful defines
  17. ///
  18. /// #define GC_NO_TEMPLATES to generate non-template code from the macro
  19. /// version of Great Circle. This is set in gc.h for Microsoft C++ and g++.
  20. ///
  21. /// #define GC_NO_EXCEPTIONS to generate a non exception handling version
  22. /// of Great Circle. This is set in gc.h for Microsoft C++. It is slightly
  23. /// more efficient.
  24. ///
  25. /// #define GC_DEBUG to enable extra debug support. GC_DEBUG allows
  26. /// gcCheckAll() to be called at any moment even as a watch variable from a
  27. /// debugger. This is expensive in time but costs little space.
  28. ///
  29. /// #define GC_INCREMENTAL to make the collector incremental.
  30. /// This means write barrier overhead and calls to gcMinWork().
  31. ///
  32. /// #define GC_COLLECTION_TRIGGER some_number
  33. /// When ever this much collectible memory is new()ed a collection cycle
  34. /// is run. In our samples we like values around 40000L but don't know why
  35. /// this is true. A value of zero turns off automatic collection cycles.
  36. /// This is ignored if GC_INCREMENTAL is defined.
  37. ///
  38. /// Great Circle uses the #define _MSC_VER set by Microsoft C++.
  39. ///
  40. /// Great Circle uses the #define __BCPLUSPLUS__ set by Borland C++.
  41. ///
  42. /// Great Circle uses the #define __GNUG__ set by Gnu C++
  43. // #defines used for tuning.
  44. // This is the largest message that can be built in a gcCheck()
  45. /// Zero disables gcCheck() and gcCheckAll(). This must be done in advance
  46. /// since if an error occurs the memory managment system may be dead.
  47. /// Space for address decoration is automatically added. This shouldn't be
  48. /// too large to display easily.
  49. #define GC_ERROR_MESSAGE_SIZE 50
  50. // One object's constructor may new another to a depth of GC_MAX_NEW_RECURSION.
  51. /// For most programs 1 or 2 is enough. The problem with letting this run
  52. /// limitlessly is that a buggy program in which a class x object news another
  53. /// x endlessly will run longer and be harder to debug. At initialization we
  54. /// build a stack of size (GC_MAX_NEW_RECURSION * 6 * sizeof(void *)).
  55. #define GC_MAX_NEW_RECURSION 50
  56. // This is the number of gcHandle's allocated at once
  57. #define GC_FREELUMP 64
  58. #include <stdlib.h>
  59. #include <string.h>
  60. #include <assert.h>
  61. // This section adjusts to various known compilers.
  62. #define GC_NO_EXCEPTIONS 1
  63. #define GC_INLINE_DELETE 1
  64. #ifdef __BCPLUSPLUS__
  65. #define GC_NOT_CFRONT
  66. #if __BCPLUSPLUS__ == 0x310
  67. // Version 3.10 is buggy for fooPtr->~foo(); which calls the destructor.
  68. /// This means the destructors on array items don't get called.
  69. /// We have no workaround. One result is that you can't have a collectible
  70. /// array of non collectible objects which contain collectible objects.
  71. #define GC_NO_INPLACE_DESTRUCTORS 1
  72. // Don't inline delete function under Borland C++ 3.10 it generates buggy code.
  73. #undef GC_INLINE_DELETE
  74. #else
  75. // So far only Borland 4.0 allows exceptions
  76. #undef GC_NO_EXCEPTIONS
  77. #endif
  78. inline void *operator new(size_t, void *p) { return p; }
  79. #endif
  80. #ifdef _MSC_VER
  81. #define GC_NOT_CFRONT
  82. #include <new.h>
  83. #if 800 == _MSC_VER
  84. // No Templates in Visual C++ 1.5
  85. #define GC_NO_TEMPLATES 1
  86. inline void *operator new(size_t, void *p) { return p; }
  87. #endif
  88. #if 900 == _MSC_VER
  89. // Visual C++ 2.0 will not automatically instantiate template statics.
  90. #define GC_NO_TEMPLATE_STATICS 1
  91. #define GC_NO_INPLACE_DESTRUCTORS 1
  92. inline void *operator new(size_t, void *p) { return p; }
  93. #endif
  94. #endif
  95. #ifdef __SUNPRO_CC
  96. #define GC_NOT_CFRONT
  97. // Sparcworks CC will not automatically instantiate template statics.
  98. #define GC_NO_TEMPLATE_STATICS 1
  99. #define GC_SPECIAL_INLINING 1
  100. inline void *operator new(size_t, void *p) { return p; }
  101. #endif
  102. #ifdef __CLCC__
  103. inline void *operator new(size_t, void *p) { return p; }
  104. #endif
  105. #ifdef __GNUG__
  106. #define GC_NOT_CFRONT
  107. #include <new.h>
  108. // g++ 2.6 templates will not automatically instantiate statics.
  109. /// For versions below 2.6 replace this with GC_NO_TEMPLATES
  110. #define GC_NO_TEMPLATE_STATICS 1
  111. #define GC_SPECIAL_INLINING 1
  112. #endif
  113. #ifdef __HIGHC__
  114. #define GC_NOT_CFRONT
  115. #define GC_SPECIAL_INLINING 1
  116. #define GC_TEMPLATE_H template<class T>
  117. inline void *operator new(size_t, void *p) { return p; }
  118. #else
  119. #define GC_TEMPLATE_H template<class T> inline
  120. #endif
  121. #ifdef __OS2__
  122. #define GC_NOT_CFRONT
  123. #define GC_NO_TEMPLATE_STATICS 1
  124. inline void *operator new(size_t, void *p) { return p; }
  125. #endif
  126. #ifndef GC_NOT_CFRONT
  127. // fooPtr->~foo(); produces syntax errors under cfront.
  128. /// This means the destructors on array items don't get called.
  129. /// We have no workaround. One result is that you can't have a collectible
  130. /// array of non collectible objects which contain collectible objects.
  131. #define GC_NO_INPLACE_DESTRUCTORS 1
  132. #endif
  133. #define GC_COLLECTION_TRIGGER 40000L
  134. #include <iostream.h>
  135. // It is usually poor to use the keyword inline directly for non trivial
  136. /// functions. This is because debuggers don't step through inline functions.
  137. /// And you don't want to step through the inline functions of working
  138. /// subsystems while debugging. By using lines like '#define GC_INLINE inline'
  139. /// you gain the ability to turn inlining off and on selectivly by subsystem.
  140. #define GC_INLINE inline
  141. #ifdef NDEBUG
  142. #define GC_ASSERT(cond, message)
  143. #else
  144. #define GC_ASSERT(cond, message) if(!(cond)) gc::gcError(message);
  145. #endif
  146. #ifdef GC_SPECIAL_INLINING
  147. #define GC_TEMPLATE template<class T> inline
  148. #else
  149. #define GC_TEMPLATE template<class T>
  150. #endif
  151. // Forward class definitions.
  152. class gcHandle;
  153. class gcTable;
  154. class gcNewTable;
  155. // Function that takes a string describing a fatal error and responds to it.
  156. typedef void (*gcErrorHandler)(const char *);
  157. // Single object gc::gcStats used to collect and display statistics.
  158. class gcStatistics {
  159. long gcCycles, // Calls to gcSwitchLists
  160. gcCollectCalls, // Calls to gcCollect
  161. gcTotalHandles; // gcHandles allocated
  162. friend class gcHandle;
  163. friend class gc;
  164. friend ostream &operator<<(ostream &, const gcStatistics &);
  165. public:
  166. // Change these flags in gc::gcStats to modify the statistical report.
  167. /// Non zero displays zero supresses.
  168. char showQueue, // Show the counts in each queue.
  169. showCount, // Count the objects of each type before display.
  170. showErrors; // Show the results of gcCheckAll().
  171. gcStatistics() : gcCycles(0), gcCollectCalls(0), gcTotalHandles(0),
  172. showQueue(1), showCount(1), showErrors(1) {}
  173. };
  174. ostream &operator<<(ostream &, const gcStatistics &);
  175. extern char *gcCheckAll(); // Consistency check
  176. // Used on user collectible classes to tell gcIsCollectible
  177. /// if a class is being used as a base class or a member
  178. enum gcPosition {
  179. gcOuter = 0, // Outer level declaration
  180. gcBase = 1, // Base class
  181. gcMember = 3 // Member class
  182. };
  183. // Used to initialize the garbage collector through the
  184. /// idiom described on page 20 of the ARM
  185. class gcInitializeFirst {
  186. public:
  187. static unsigned int firstTime;
  188. gcInitializeFirst(int errorSize,
  189. size_t stackSize,
  190. size_t freeLump,
  191. // If GC_DEBUG is defined for a user module a debug form of gc.cpp is required.
  192. size_t debugSw,
  193. // The incremental | not_incremental mode of all modules in an executable
  194. /// must match.
  195. long incrAmt);
  196. ~gcInitializeFirst();
  197. };
  198. static gcInitializeFirst GC_INITIALIZE_FIRST_OBJECT(
  199. GC_ERROR_MESSAGE_SIZE,
  200. GC_MAX_NEW_RECURSION,
  201. GC_FREELUMP,
  202. #ifdef GC_DEBUG
  203. 1,
  204. #else
  205. 0,
  206. #endif
  207. #ifndef GC_INCREMENTAL
  208. GC_COLLECTION_TRIGGER);
  209. #else
  210. 1);
  211. #endif
  212. // Garbage Collectible object class.
  213. /// Collectible objects must inherit from a single instance of this publicly.
  214. class gc {
  215. public:
  216. gc();
  217. gc(const gc &);
  218. // To create user defined new and delete redefine _new or _delete
  219. static void * _new(size_t s) {
  220. return new char[s];
  221. }
  222. #ifdef GC_INLINE_DELETE
  223. static void _delete(void *x) {
  224. ::delete x;
  225. }
  226. #else
  227. static void _delete(void *);
  228. #endif
  229. static int gcMinWork();
  230. // If not GC_INCREMENTAL this is the number of bytes which are allocated
  231. /// before a collection cycle is triggered.
  232. static long gcSetAllocationLimit(long limit);
  233. // If GC_INCREMENTAL this is the number of calls to gcMinWork()
  234. /// every time a gcHandle is new()ed. It is initialized to 1 which is
  235. /// generally good. But for real time programs 0 is often better.
  236. static unsigned gcSetCollectionRate(unsigned count = 1);
  237. // If GC_INCREMENTAL this causes objects to be deleted as soon
  238. /// as the collector knows they are free. This may cause millesecond pauses
  239. /// it is generally ok with interactive programs but not with real time
  240. /// ones or animation. It reduces the amount of storage required and
  241. /// improves speed about 3%. Your mileage may vary.
  242. static unsigned gcSetQuickDelete(unsigned doQuickDelete = 1);
  243. // This causes all unlocked and completed collectible objects to be
  244. /// deleted at end of job.
  245. static unsigned gcSetDeleteAtEnd(unsigned sw = 1);
  246. // Locate all unreferenced objects and delete them.
  247. static int gcCollect();
  248. // Return compiler used.
  249. static const char *gcCompiler();
  250. // Return Library Id
  251. static const char *gcLibrary();
  252. // Return Great Circle Version Number
  253. static int gcVersion();
  254. // Returns zero for production copies and the expire time()
  255. // for evaluation copies.
  256. static long gcEvaluationCopy();
  257. // Accumulator for statistics, cout << gc::gcStats; prints them.
  258. static gcStatistics gcStats;
  259. // Copyright string
  260. static const char *gcCopyright();
  261. // Table for leaf objects
  262. static gcTable *gcLeafTable;
  263. // This normally points to a function that prints a message and exit()s
  264. /// you may change it say to something that raises an exception. It is
  265. /// called on all fatal errors by the collector.
  266. static gcErrorHandler gcSetFatalError(gcErrorHandler v);
  267. static void gcError(char *msg); // default gc fatal error routine.
  268. // new()s for default objects
  269. static void * operator new(size_t, void *, gcTable **); // Inplace new
  270. static void * operator new(size_t, gcTable **, void *); // whole object new
  271. // new()s for pointer and custom objects
  272. static void * operator new(size_t);
  273. static void * operator new(size_t, void *);
  274. virtual ~gc();
  275. virtual void gcMarkRefs() const;
  276. virtual char *gcCheck() const;
  277. void operator =(const gc &) {} // Copy of gc part does nothing.
  278. int gcLock() const; // Locked objects are never deleted
  279. int gcUnlock() const; // Decrement lock count.
  280. void gcMark() const; // Mark this object as used.
  281. void *gcFindOuterObject() const;
  282. protected:
  283. static void gcInternalMakeCollectible(gc *, gcTable **);
  284. static void gcInternalMakeCollectible(void *, gcTable **);
  285. gc(gcPosition); // Used by custom collectible objects
  286. gc(int); // Used by special collectible objects
  287. virtual void gcAppend() const; // Save object location on a table.
  288. void operator delete(void *x) {
  289. _delete(x);
  290. }
  291. void gcWriteBarrier(void *) const;
  292. void gcInternalArrayMakeCollectible();
  293. void gcInternalPtrCollectible(size_t, gcHandle **);
  294. private:
  295. static gcErrorHandler gcFatalError;
  296. #ifdef _MSC_VER
  297. static int noMoreMemory(size_t);
  298. #else
  299. static void noMoreMemory();
  300. #endif
  301. void gcExceptionTearDown();
  302. gcHandle *gcHandlePtr;
  303. friend class gcInitializeFirst;
  304. friend class gcHandle;
  305. friend class gcList;
  306. friend class gcPointerBase;
  307. friend class gcLocker;
  308. friend class gcNewTable;
  309. friend ostream &operator<<(ostream &, const gc &);
  310. };
  311. ostream &operator<<(ostream &, const gc &); // Usefull for debugging only.
  312. // Custom collectible objects descend from this
  313. class gcCustom : public gc {
  314. public:
  315. gcCustom() : gc(gcBase) {}
  316. gcCustom(const gcCustom &) : gc(gcBase) {}
  317. gcCustom(int) : gc(0) {}
  318. virtual void gcMarkRefs() const = 0;
  319. virtual char *gcCheck() const;
  320. };
  321. class gcSpecial : public gcCustom {
  322. public:
  323. gcSpecial() : gcCustom(0) {}
  324. gcSpecial(const gcSpecial &) : gcCustom(0) {}
  325. static gcPosition gcPos; // creates default of gcOuter
  326. };
  327. #define gcIsCollectible() gcLocker gcLockedObj(this, sizeof(*this), gcPos)
  328. #ifdef GC_DEBUG
  329. // In debug mode gcMark of a deleted object triggers a fatal error.
  330. /// If there are any pointers left to the object gcCollect() will find them.
  331. #define gcDelete(ptr) \
  332. if(!!ptr) { gc *x = ptr; ptr = 0; _delete(x); gc::gcCollect(); }
  333. #else
  334. #define gcDelete(ptr) if(!!ptr) { gc *x = ptr; ptr = 0; _delete(x); }
  335. #endif
  336. #define gcParm gcPosition gcPos = gcOuter
  337. #define gcPtrCollectible() \
  338. gcInternalPtrCollectible(sizeof(*this), &gcPtrHandle)
  339. // Collectible objects are removed from the Limbo queue by the construction
  340. /// of a gcLocker object, but left locked. They are unlocked by the gcLocker
  341. /// destructor if they were independently new()ed.
  342. class gcLocker {
  343. public:
  344. gcLocker(gc *, size_t, gcParm); // custom objects
  345. ~gcLocker();
  346. private:
  347. gcHandle *lockedHandle;
  348. };
  349. // This are short ways to allocate Arrays
  350. #define GC_NEW_ARRAY(S, T) new(S) GC_ARRAY(T)
  351. #define GC_NEW_PRIMITIVE_ARRAY(S, T) new(S) GC_PRIMARRAY(T)
  352. // These are used for default collectible objects. These objects don't declare
  353. /// themselves collectible. They are all allocated by their own new() which
  354. /// saves the objects size and position and the address of its table pointer
  355. /// on a stack. When a pointer is saved to the object its constuction is
  356. /// completed. Default collectible objects are the sum of their non-default
  357. /// parts, so if the object is not independently newed it never needs to be
  358. /// constructed as collectible.
  359. #define GC_STRUCT(T) GC_CLASS(T) class T : GC(T) public:
  360. #define GC_CLASS(T) GC_START_CLASS(T) GC_FINISH_CLASS(T)
  361. #define GC(T) public virtual gc { GC_BODY(T)
  362. #if !defined(GC_NOT_CFRONT) || defined (__GNUG__)
  363. // Some compilers require these apparently as the result of some bug.
  364. #define GC_ODDNEW1 static void *operator new(size_t s) { \
  365. return ::operator new(s); }
  366. #define GC_ODDNEW2 static void *operator new(size_t s) { \
  367. return gc::operator new(s, &gc::gcLeafTable, _new(s)); }
  368. #else
  369. #define GC_ODDNEW1
  370. #define GC_ODDNEW2
  371. #endif
  372. // Define operator new for a default object, define an inaccessable
  373. /// operator delete.
  374. #ifdef GC_NOT_CFRONT
  375. #define GC_BODY(T) public: \
  376. static void * operator new(size_t n) { \
  377. GC_ASSERT(n == sizeof(T), "A subclass of '" # T \
  378. "' was not declared collectible") \
  379. return gc::operator new(n, GC_GENERATE(T)::whereTab(), _new(n)); } \
  380. static void * operator new(size_t n, void *p) { \
  381. GC_ASSERT(n == sizeof(T), "A subclass of '" # T\
  382. "' was not declared collectible") \
  383. return gc::operator new(n, p, GC_GENERATE(T)::whereTab()); } private:
  384. #else
  385. // The full message format in GC_BODY confuses cfront under objectcenter.
  386. #define GC_BODY(T) void operator delete(void *x) { _delete(x); } public: \
  387. static void * operator new(size_t n) { \
  388. GC_ASSERT(n == sizeof(T), \
  389. "A subclass of a default collectible was not declared collectible") \
  390. return gc::operator new(n, GC_GENERATE(T)::whereTab(), _new(n)); } \
  391. static void * operator new(size_t n, void *p) { \
  392. GC_ASSERT(n == sizeof(T), \
  393. "A subclass of a default collectible was not declared collectible") \
  394. return gc::operator new(n, p, GC_GENERATE(T)::whereTab()); } private:
  395. #endif
  396. // Return values for gcInBounds tests
  397. enum gcArrayTest {
  398. gcNotAnArray,
  399. gcPointerOk,
  400. gcPointerTooLow,
  401. gcPointerTooHigh,
  402. gcPointerAtEnd
  403. };
  404. // Parent of all array class templates.
  405. class gcArrayBase : public gc {
  406. public:
  407. static gcTable *ncoTable;
  408. // The maybe functions call gcMarkRefs or gcCheck for gc's but not
  409. /// otherwise they are used in gcArray< T >'s functions.
  410. static void gcMaybeMarkRefs(const gc *);
  411. static void gcMaybeMarkRefs(const void *) {}
  412. static char * gcMaybeCheck(const gc *);
  413. static char * gcMaybeCheck(const void *);
  414. static void * operator new(size_t, size_t, gcTable **);
  415. gcArrayBase() {}
  416. virtual void gcMarkRefs() const {}
  417. void * gcArrayBottom() const;
  418. size_t size() const;
  419. size_t len() const;
  420. void setLen(size_t);
  421. int gcValidReference(const void *);
  422. gcArrayTest gcInBounds(const void *) const;
  423. size_t gcItemLen;
  424. void * gcArrayEnd;
  425. private:
  426. GC_ODDNEW1
  427. };
  428. // All pointer and reference wrappers descend from this class which
  429. /// contains the pointer's handle. This class does the actual write
  430. /// barrier. Since we always choose speed over space it is correct
  431. /// to keep the handle with the pointer. Whenever a pointer is changed
  432. /// the handle is loaded but since we always gcMark() there is no
  433. /// time lost in the case when gcMarkRefs is never called.
  434. class gcPointerBase {
  435. public:
  436. virtual void gcMarkRefs() const;
  437. protected:
  438. gcPointerBase() {}
  439. gcPointerBase(const gcPointerBase &);
  440. gcPointerBase(gcHandle *);
  441. gcPointerBase(int);
  442. #ifdef GC_DEBUG
  443. static char gcBusy;
  444. #endif
  445. void gcMarkPtr() const;
  446. void pointersBusy();
  447. void pointersOk();
  448. char * gcCheck(const gc *) const;
  449. char * gcCheck(const void *) const { return 0; };
  450. void setHandle();
  451. void setHandle(const gc *);
  452. void setHandle(gcHandle *);
  453. void setHandle(const gcPointerBase &p);
  454. void * gcValidReference(void *newP) const;
  455. virtual void gcAppend() const;
  456. gcArrayBase * isArray() const;
  457. gcHandle *gcPtrHandle;
  458. };
  459. // Doubly linked list
  460. class gcDlist {
  461. public:
  462. void l_dconn();
  463. void l_conn(gcDlist *);
  464. int isEmpty() const;
  465. gcDlist *f, *b; // Forward and backward pointers
  466. };
  467. // Color bucket
  468. class gcList : public gcDlist {
  469. public:
  470. gcList() {}
  471. gcList(unsigned char, char *);
  472. void operator << (gcList &);
  473. int gcMinWork();
  474. int gcFreeAll();
  475. void l_dconn(gcHandle *);
  476. void l_conn(gcHandle *);
  477. char * gcCheck() const;
  478. char * gcBuildMsg(char *) const;
  479. void gcAllLive();
  480. int gcPassAll();
  481. unsigned long l_count() const;
  482. char *gcName; // Name for statistics and error reporting
  483. unsigned long gcCount; // items on queue if GC_DEBUG else garbage
  484. unsigned char gcColor; // Queue items match this except for free queue
  485. unsigned char gcBusy; // Semiphore used if GC_DEBUG
  486. };
  487. ostream &operator<<(ostream &, const gcList &);
  488. // gcHandle objects have pointers to the user's objects and are the
  489. /// real basis of collectibility
  490. class gcHandle : public gcDlist {
  491. public:
  492. enum gcMarkValue { // The kind of objects in the system
  493. gcNewlyCreatedObject, // Object newly created
  494. gcTempValue, // Short term transient value for debugging
  495. gcUnlinkedObject, // Object marked for destruction
  496. gcPointerMarkRefs, // Table has only pointers
  497. gcObjectMarkRefs, // Table has only subobjects
  498. gcFullMarkRefs, // Table has pointers and subobjects
  499. gcCustomMarkRefs, // Not a default object
  500. gcPtrMarkRefs, // gcPtr etc is outer object
  501. gcArrayMarkRefs, // gcArray< T > is outer object
  502. gcLeafMarkRefs, // Table is empty
  503. gcArrayLeafMarkRefs, // gcArray< T > is outer object
  504. gcEndOfEnum // No objects of this type
  505. };
  506. gcHandle();
  507. static int gcSwitchLists();
  508. // static class instead of static here stops an objectcenter warning.
  509. static class gcList Free, Mixed, Marked, Passed, Locked, Limbo;
  510. static void * operator new(size_t);
  511. void operator delete(void *) {} // never called
  512. void gcMark();
  513. #ifndef _MSC_VER
  514. void gcMarkWork();
  515. #endif
  516. void gcPass();
  517. void gcAborted();
  518. int gcLock();
  519. int gcUnlock();
  520. void gcUnlink();
  521. void gcAssert(const gcList &);
  522. char * gcCheck(const gcList &) const;
  523. char * gcBuildMsg(char *, const gcList &) const;
  524. char * gcBuildConnectMsg(const gcList &) const;
  525. char * gcBuildColorMsg(const gcList &) const;
  526. char * gcBuildTrampolineMsg(const gcList &) const;
  527. void gcMake(gcList &, gcList &);
  528. void gcInternalMakeCollectible(gc *, void *);
  529. void gcWriteBarrier(const gc *, void *);
  530. int gcIs(const gcList &) const;
  531. int gcIsLeaf() const;
  532. gcArrayBase * isArray() const;
  533. gc *gcUsersObj; // The users actual object
  534. union { // Union descriminated by gcTrampoline
  535. gcHandle **gcPtr; // gcMarkValue::gcPtrMarkrefs
  536. gcTable *gcTablePtr; // gcMarkValue:: Table values
  537. } gcTabs;
  538. unsigned gcLockCount; // Non zero is locked.
  539. gcMarkValue gcTrampoline; // Set what we do
  540. unsigned char gcColor; // Color of this object.
  541. };
  542. // Inline functions for common section.
  543. GC_INLINE void *gc::gcFindOuterObject() const {
  544. return (void *)gcHandlePtr->gcUsersObj;
  545. }
  546. GC_INLINE void gc::gcInternalMakeCollectible(void *, gcTable **t) {
  547. *t = gcArrayBase::ncoTable;
  548. }
  549. GC_INLINE int gc::gcLock() const {
  550. return gcHandlePtr->gcLock();
  551. }
  552. GC_INLINE int gc::gcUnlock() const {
  553. return gcHandlePtr->gcUnlock();
  554. }
  555. #ifdef GC_NO_GLOBAL_FUNCTIONS
  556. GC_INLINE gcErrorHandler gc::gcSetFatalError(gcErrorHandler v) {
  557. gcErrorHandler rv = gcFatalError;
  558. gcFatalError = v;
  559. return rv;
  560. }
  561. #endif
  562. GC_INLINE void gc::gcError(char *msg) {
  563. gcFatalError(msg);
  564. }
  565. GC_INLINE unsigned long
  566. gcNotYetProtected()
  567. {
  568. return gcHandle::Limbo.l_count();
  569. }
  570. // If you intend to improve speed by rewriting something in assembler
  571. /// our profile analysis shows these three functions are the best candidates.
  572. inline void gcDlist::l_dconn() {
  573. (f->b = b)->f = f;
  574. }
  575. inline void gcDlist::l_conn(gcDlist *t) {
  576. t->b = (b = (f = t)->b)->f = this;
  577. }
  578. inline gcDlist::isEmpty() const {
  579. return this == f;
  580. }
  581. inline int gcList::gcMinWork() {
  582. #ifdef GC_INCREMENTAL
  583. if (!isEmpty()) {
  584. ((gcHandle *)b)->gcPass();
  585. return 0;
  586. }
  587. else {
  588. gcHandle::gcSwitchLists();
  589. return 1;
  590. }
  591. #else
  592. return 1;
  593. #endif
  594. }
  595. inline int gc::gcMinWork() {
  596. return gcHandle::Marked.gcMinWork();
  597. }
  598. inline void gcList::l_dconn(gcHandle *p) {
  599. #ifdef GC_DEBUG
  600. gcBusy = 1;
  601. gcCount--;
  602. #endif
  603. p->l_dconn();
  604. #ifdef GC_DEBUG
  605. gcBusy = 0;
  606. #endif
  607. }
  608. inline void gcList::l_conn(gcHandle *p) {
  609. #ifdef GC_DEBUG
  610. gcBusy = 1;
  611. gcCount++;
  612. #endif
  613. p->l_conn(this);
  614. p->gcColor = gcColor;
  615. #ifdef GC_DEBUG
  616. gcBusy = 0;
  617. #endif
  618. }
  619. GC_INLINE gcHandle::gcHandle()
  620. : gcLockCount(1), gcUsersObj(0), gcTrampoline(gcNewlyCreatedObject)
  621. {
  622. gcTabs.gcTablePtr = gc::gcLeafTable;
  623. Limbo.l_conn(this);
  624. }
  625. inline int gcHandle::gcIs(const gcList &c) const {
  626. return c.gcColor == gcColor;
  627. }
  628. inline int gcHandle::gcIsLeaf() const {
  629. return gcLeafMarkRefs <= gcTrampoline;
  630. }
  631. inline void gcHandle::gcMake(gcList &c, gcList &l) {
  632. l.l_dconn(this);
  633. c.l_conn(this);
  634. }
  635. #ifdef GC_DEBUG
  636. // Check the validity of a gcHandle and have a fatal error if bad.
  637. GC_INLINE void
  638. gcHandle::gcAssert(const gcList &c)
  639. {
  640. char *msg = gcCheck(c);
  641. if (msg)
  642. gc::gcError(gcBuildMsg(msg, c));
  643. }
  644. #else
  645. GC_INLINE void
  646. gcHandle::gcAssert(const gcList &) {}
  647. #endif
  648. #ifndef _MSC_VER
  649. GC_INLINE void
  650. gcHandle::gcMark() {
  651. if (gcIs(Mixed))
  652. gcMarkWork();
  653. }
  654. #endif
  655. inline void gc::gcMark() const {
  656. gcHandlePtr->gcMark();
  657. }
  658. GC_INLINE void gcHandle::gcWriteBarrier(const gc *obj, void *ptr) {
  659. if (gcNewlyCreatedObject == gcTrampoline)
  660. gcInternalMakeCollectible((gc *)obj, ptr);
  661. #ifdef GC_INCREMENTAL
  662. else
  663. gcMark();
  664. #endif
  665. }
  666. inline void gc::gcWriteBarrier(void *ptr) const {
  667. gcHandlePtr->gcWriteBarrier(this, ptr);
  668. }
  669. GC_INLINE void gcHandle::gcUnlink() {
  670. #ifdef GC_DEBUG
  671. gcTrampoline = gcTempValue;
  672. #endif
  673. gcUsersObj = 0;
  674. gcLockCount = 0;
  675. gcTrampoline = gcUnlinkedObject;
  676. }
  677. GC_INLINE gcArrayBase * gcHandle::isArray() const {
  678. return (gcTrampoline == gcArrayMarkRefs ||
  679. gcTrampoline == gcArrayLeafMarkRefs) ?
  680. (gcArrayBase *)(void *)gcUsersObj : 0;
  681. }
  682. inline void *gcArrayBase::gcArrayBottom() const {
  683. return (void *)(this + 1);
  684. }
  685. inline size_t gcArrayBase::size() const {
  686. return (size_t)((char *)gcArrayEnd - (char *)gcArrayBottom());
  687. }
  688. inline size_t gcArrayBase::len() const{
  689. return size() / gcItemLen;
  690. }
  691. GC_INLINE void gcArrayBase::setLen(size_t newLen) {
  692. void *x = (char *)gcArrayBottom() + newLen * gcItemLen;
  693. GC_ASSERT(x <= gcArrayEnd, "Attempt to set array length too large");
  694. gcArrayEnd = x;
  695. }
  696. GC_INLINE int gcArrayBase::gcValidReference(const void *p) {
  697. return p < gcArrayEnd && p >= gcArrayBottom();
  698. }
  699. GC_INLINE void gcArrayBase::gcMaybeMarkRefs(const gc *p) {
  700. p->gcMarkRefs();
  701. }
  702. GC_INLINE char * gcArrayBase::gcMaybeCheck(const gc *p) {
  703. return p->gcCheck();
  704. }
  705. GC_INLINE char * gcArrayBase::gcMaybeCheck(const void *) {
  706. return 0;
  707. }
  708. // Some people like the convenience of avoiding gc:: and others
  709. /// want to avoid namespace pollution. We try to satisfy both.
  710. /// Define GC_NO_GLOBAL_FUNCTIONS to avoid namespace pollution.
  711. #ifndef GC_NO_GLOBAL_FUNCTIONS
  712. inline const char *gcCompiler() {
  713. return gc::gcCompiler();
  714. }
  715. inline const char *gcLibrary() {
  716. return gc::gcLibrary();
  717. }
  718. inline int gcVersion() {
  719. return gc::gcVersion();
  720. }
  721. inline const char *gcCopyright() {
  722. return gc::gcCopyright();
  723. }
  724. inline int gcMinWork() {
  725. return gc::gcMinWork();
  726. }
  727. inline long gcSetAllocationLimit(long limit) {
  728. return gc::gcSetAllocationLimit(limit);
  729. }
  730. inline unsigned gcSetCollectionRate(unsigned count = 1) {
  731. return gc::gcSetCollectionRate(count);
  732. }
  733. inline unsigned gcSetQuickDelete(unsigned doQuickDelete = 1) {
  734. return gc::gcSetQuickDelete(doQuickDelete);
  735. }
  736. inline unsigned gcSetDeleteAtEnd(unsigned sw = 1) {
  737. return gc::gcSetDeleteAtEnd(sw);
  738. }
  739. inline int gcCollect() {
  740. return gc::gcCollect();
  741. }
  742. inline gcErrorHandler gcSetFatalError(gcErrorHandler v) {
  743. return gc::gcSetFatalError(v);
  744. }
  745. #endif
  746. #ifdef GC_DEBUG
  747. inline void gcPointerBase::pointersBusy() { gcBusy = 1; }
  748. inline void gcPointerBase::pointersOk() { gcBusy = 0; }
  749. #else
  750. inline void gcPointerBase::pointersBusy() {}
  751. inline void gcPointerBase::pointersOk() {}
  752. #endif
  753. inline void gcPointerBase::gcMarkPtr() const {
  754. gcPtrHandle->gcMark();
  755. }
  756. GC_INLINE void gcPointerBase::gcMarkRefs() const {
  757. if (gcPtrHandle)
  758. gcMarkPtr();
  759. }
  760. GC_INLINE void gcPointerBase::setHandle() {
  761. gcPtrHandle = 0;
  762. pointersOk();
  763. }
  764. GC_INLINE void gcPointerBase::setHandle(const gc *p) {
  765. if (p) {
  766. gcPtrHandle = p->gcHandlePtr;
  767. p->gcWriteBarrier((void *)this);
  768. } else
  769. gcPtrHandle = 0;
  770. pointersOk();
  771. }
  772. GC_INLINE void gcPointerBase::setHandle(gcHandle *h) {
  773. #ifndef GC_INCREMENTAL
  774. gcPtrHandle = h;
  775. #else
  776. if (0 != (gcPtrHandle = h))
  777. gcMarkPtr();
  778. #endif
  779. pointersOk();
  780. }
  781. GC_INLINE void gcPointerBase::setHandle(const gcPointerBase &p) {
  782. setHandle(p.gcPtrHandle);
  783. }
  784. GC_INLINE gcPointerBase::gcPointerBase(int) {
  785. setHandle();
  786. }
  787. GC_INLINE gcPointerBase::gcPointerBase(gcHandle *h) {
  788. setHandle(h);
  789. }
  790. GC_INLINE gcPointerBase::gcPointerBase(const gcPointerBase &p) {
  791. setHandle(p.gcPtrHandle);
  792. }
  793. GC_INLINE gcArrayBase * gcPointerBase::isArray() const {
  794. return gcPtrHandle ? gcPtrHandle->isArray() : 0;
  795. }
  796. GC_INLINE void* gcPointerBase::gcValidReference(void *newP) const {
  797. #ifdef GC_DEBUG
  798. gcArrayBase *a = isArray();
  799. GC_ASSERT(a && a->gcValidReference(newP), "Invalid Pointer Dereference");
  800. #endif
  801. return newP;
  802. }
  803. GC_INLINE gcLocker::~gcLocker() {
  804. if (lockedHandle)
  805. lockedHandle->gcLockCount--;
  806. }
  807. #ifndef GC_NO_TEMPLATES
  808. // gc template wrapper classes.
  809. // Normally it is good style to separate class definitions from function
  810. /// internals as with the above non template classes. However templates are
  811. /// new to C++ and some compilers crash with the normal style.
  812. template<class T> class gcPrimArray;
  813. template<class T>
  814. class gcGenerate {
  815. public:
  816. static gcTable **whereTab() {
  817. return &gcTablePtr;
  818. }
  819. static gcTable* gcTablePtr; // Table of offsets
  820. };
  821. // Parent for wrapped data pointers and references.
  822. template<class T>
  823. class gcWrap : public gcPointerBase {
  824. protected:
  825. gcWrap() : data(0), gcPointerBase(0) {}
  826. gcWrap(T *p) {
  827. setPointer(p);
  828. }
  829. gcWrap(const gcWrap< T > &p) : data(p.data), gcPointerBase(p.gcPtrHandle) {}
  830. void setPointer() {
  831. pointersBusy(); // Prevent gcCheck from testing pointers
  832. data = 0;
  833. setHandle(); // Allow gcCheck to check pointers
  834. }
  835. void setPointer(T* p);
  836. void setPointer(const gcWrap< T > &p) {
  837. pointersBusy();
  838. data = p.data;
  839. setHandle(p);
  840. }
  841. T* data; // The pointer to the actual object
  842. };
  843. // Wrap data pointers only for items that will not have
  844. /// automtacally generated gcMarkRefs()
  845. template<class T>
  846. class gcPointer : public gcWrap< T > {
  847. public:
  848. gcPointer() {}
  849. gcPointer(int) {}
  850. gcPointer(T *x) : gcWrap< T >(x) {}
  851. gcPointer(const gcPointer< T > &x) : gcWrap< T >(x) {}
  852. gcPointer(gcPrimArray< T > *x);
  853. T* operator=(T *x) {
  854. setPointer(x);
  855. return data;
  856. }
  857. T* operator=(const gcPointer< T > &x) {
  858. setPointer(x);
  859. return data;
  860. }
  861. operator T*() const {
  862. return data;
  863. }
  864. T* operator()() const {
  865. return data;
  866. }
  867. T* operator->() const {
  868. return data;
  869. }
  870. int operator!() const {
  871. return data == 0;
  872. }
  873. int operator==(const gcPointer< T > &x) const {
  874. return data == x.data;
  875. }
  876. int operator==(T *x) const {
  877. return data == x;
  878. }
  879. int operator==(int x) const {
  880. return data == (T *) x;
  881. }
  882. int operator!=(const gcPointer< T > &x) const {
  883. return data != x.data;
  884. }
  885. int operator!=(T *x) const {
  886. return data != x;
  887. }
  888. T& operator[](int n) const;
  889. T* operator+(int n) const;
  890. T* operator-(int n) const {
  891. return (*this) + -n;
  892. }
  893. T* operator+=(int n) {
  894. return data = (*this + n);
  895. }
  896. T* operator-=(int n) {
  897. return data = (*this + -n);
  898. }
  899. #ifdef GC_DEBUG
  900. T* operator=(int n) {
  901. GC_ASSERT(!n, "Invalid integer to pointer assignment");
  902. setPointer();
  903. return 0;
  904. }
  905. T& operator*() const {
  906. if (isArray())
  907. return *(T*)gcValidReference((void *)data);
  908. else {
  909. GC_ASSERT(data, "Dereference of null pointer");
  910. return *data;
  911. }
  912. }
  913. #else
  914. T* operator=(int) {
  915. setPointer();
  916. return 0;
  917. }
  918. T& operator*() const {
  919. return *data;
  920. }
  921. #endif
  922. gcArrayTest gcInBounds(int n) const;
  923. };
  924. // Wrap pointers to collectible arrays of uncollectible objects.
  925. /// This will also work on arrays of collectible objects but is less
  926. /// space efficient than gcP< T >
  927. template<class T>
  928. class gcArrayP : public gcPointerBase {
  929. protected:
  930. T* data;
  931. void setPointer() {
  932. pointersBusy();
  933. data = 0;
  934. setHandle();
  935. }
  936. void setPointer(const gcArrayP< T > &p) {
  937. pointersBusy();
  938. data = p.data;
  939. setHandle(p.gcPtrHandle);
  940. }
  941. void setPointer(gcPrimArray< T > *p) {
  942. pointersBusy();
  943. if (p) {
  944. data = (T*)p->gcArrayBottom();
  945. setHandle(p);
  946. } else {
  947. data = 0;
  948. setHandle();
  949. }
  950. }
  951. public:
  952. gcArrayP() : data(0), gcPointerBase(0) {}
  953. gcArrayP(int) : data(0), gcPointerBase(0) {}
  954. gcArrayP(const gcArrayP< T > &p)
  955. : data(p.data), gcPointerBase(p.gcPtrHandle) {}
  956. gcArrayP(gcPrimArray< T > *p) {
  957. setPointer(p);
  958. }
  959. T* operator=(T *x) {
  960. return data = x;
  961. }
  962. T* operator=(const gcArrayP< T > &x) {
  963. setPointer(x);
  964. return data;
  965. }
  966. T* operator=(gcPrimArray< T > *x) {
  967. setPointer(x);
  968. return data;
  969. }
  970. operator T*() const {
  971. return data;
  972. }
  973. T* operator()() const {
  974. return data;
  975. }
  976. operator gcPrimArray< T > *() const {
  977. return (gcPrimArray< T > *)(void *)isArray();
  978. }
  979. int operator!() const {
  980. return data == 0;
  981. }
  982. int operator==(const gcArrayP< T > &x) const {
  983. return data == x.data;
  984. }
  985. int operator==(T *x) const {
  986. return data == x;
  987. }
  988. int operator!=(const gcArrayP< T > &x) const {
  989. return data != x.data;
  990. }
  991. int operator!=(T *x) const {
  992. return data != x;
  993. }
  994. T* operator++() {
  995. return data = (*this + 1);
  996. }
  997. T* operator--() {
  998. return data = (*this - 1);
  999. }
  1000. T* operator++(int) {
  1001. T* tmp = data;
  1002. data = (*this + 1);
  1003. return tmp;
  1004. }
  1005. T* operator--(int) {
  1006. T* tmp = data;
  1007. data = (*this - 1);
  1008. return tmp;
  1009. }
  1010. T* operator+(int n) const;
  1011. T* operator-(int n) const {
  1012. return (*this) + -n;
  1013. }
  1014. T* operator+=(int n) {
  1015. return data = (*this + n);
  1016. }
  1017. T* operator-=(int n) {
  1018. return data = (*this + -n);
  1019. }
  1020. size_t len() const {
  1021. gcArrayBase *a = isArray();
  1022. return a ? a->len() : 0;
  1023. }
  1024. size_t size() const {
  1025. gcArrayBase *a = isArray();
  1026. return a ? a->size() : 0;
  1027. }
  1028. void setLen(size_t l) {
  1029. gcArrayBase *a = isArray();
  1030. if (a)
  1031. a->setLen(l);
  1032. }
  1033. #ifdef GC_DEBUG
  1034. T* operator=(int n) {
  1035. GC_ASSERT(!n, "Invalid integer to pointer assignment");
  1036. setHandle();
  1037. return data = 0;
  1038. }
  1039. T& operator[](int n) const {
  1040. return *(T*)gcValidReference((void *)(*this + n));
  1041. }
  1042. T& operator *() const {
  1043. return *(T*)gcValidReference((void *)data);
  1044. }
  1045. #else
  1046. T* operator=(int) {
  1047. setHandle();
  1048. return data = 0;
  1049. }
  1050. T& operator*() const {
  1051. return *data;
  1052. }
  1053. T& operator[](int n) const {
  1054. return *(*this + n);
  1055. }
  1056. #endif
  1057. gcArrayTest gcInBounds(int n) const;
  1058. };
  1059. // gcR is a reference to a collectible object which, but it is not
  1060. /// itself a collectible object. It is used as a reference through operator()
  1061. template<class T>
  1062. class gcReference : public gcWrap< T > {
  1063. public:
  1064. gcReference() {}
  1065. gcReference(const T &x) : gcWrap< T >((T *)&x) {}
  1066. gcReference(const gcReference< T > &x) : gcWrap< T >(x) {}
  1067. // Only Borland can inline this operator
  1068. #ifdef __BCPLUSPLUS__
  1069. void operator=(T &x) {
  1070. *data = x;
  1071. }
  1072. void operator=(const gcReference< T > &x) {
  1073. *data = x();
  1074. }
  1075. #else
  1076. void operator=(T &x);
  1077. void operator=(const gcReference< T > &x);
  1078. #endif
  1079. T& operator()() const {
  1080. return *data;
  1081. }
  1082. operator T&() const {
  1083. return *data;
  1084. }
  1085. };
  1086. // gcRef is a gcRWrap that is itself a collectible object
  1087. template<class T>
  1088. class gcRef : public gc, public gcReference< T > {
  1089. public:
  1090. gcRef() {
  1091. gcPtrCollectible();
  1092. }
  1093. gcRef(const T &x) : gcReference< T >(x) {
  1094. gcPtrCollectible();
  1095. }
  1096. gcRef(const gcReference< T > &x) : gcReference< T >(x) {
  1097. gcPtrCollectible();
  1098. }
  1099. gcRef(const gcRef< T > &x) : gcReference< T >(x) {
  1100. gcPtrCollectible();
  1101. }
  1102. virtual void gcMarkRefs() const;
  1103. virtual void gcAppend() const;
  1104. char *gcCheck() const;
  1105. };
  1106. // gcPtr is a pointer to a gc object. It is itself a gc object.
  1107. template<class T>
  1108. class gcPtr : public gc, public gcPointer< T > {
  1109. public:
  1110. gcPtr() {
  1111. gcPtrCollectible();
  1112. }
  1113. gcPtr(int) {
  1114. gcPtrCollectible();
  1115. }
  1116. gcPtr(T *x) : gcPointer< T >(x) {
  1117. gcPtrCollectible();
  1118. }
  1119. gcPtr(const gcPointer< T > &x) : gcPointer< T >(x) {
  1120. gcPtrCollectible();
  1121. }
  1122. gcPtr(const gcPtr< T > &x): gcPointer< T >(x) {
  1123. gcPtrCollectible();
  1124. }
  1125. gcPtr(gcPrimArray< T > *x) : gcPointer< T >(x) {
  1126. gcPtrCollectible();
  1127. }
  1128. T* operator=(T *x) {
  1129. setPointer(x);
  1130. return data;
  1131. }
  1132. T* operator=(const gcPointer< T > &x) {
  1133. setPointer(x);
  1134. return data;
  1135. }
  1136. T* operator=(const gcPtr< T > &x) {
  1137. setPointer(x);
  1138. return data;
  1139. }
  1140. T* operator->() const {
  1141. return data;
  1142. }
  1143. virtual void gcMarkRefs() const;
  1144. virtual void gcAppend() const;
  1145. char *gcCheck() const;
  1146. };
  1147. // gcArrayPtr is a pointer to a gc object. It is itself a gc object.
  1148. template<class T>
  1149. class gcArrayPtr : public gc, public gcArrayP< T > {
  1150. public:
  1151. gcArrayPtr() {
  1152. gcPtrCollectible();
  1153. }
  1154. gcArrayPtr(const gcArrayP< T > &x) : gcArrayP< T >(x) {
  1155. gcPtrCollectible();
  1156. }
  1157. gcArrayPtr(const gcArrayPtr< T > &x) : gcArrayP< T >(x) {
  1158. gcPtrCollectible();
  1159. }
  1160. gcArrayPtr(gcPrimArray< T > *x) : gcArrayP< T >(x) {
  1161. gcPtrCollectible();
  1162. }
  1163. T* operator=(gcPrimArray< T > *x) {
  1164. setPointer(x);
  1165. return data;
  1166. }
  1167. #ifdef GC_DEBUG
  1168. T* operator=(int n) {
  1169. GC_ASSERT(!n, "Invalid integer to pointer assignment");
  1170. setPointer();
  1171. return 0;
  1172. }
  1173. #else
  1174. T* operator=(int) {
  1175. setPointer();
  1176. return 0;
  1177. }
  1178. #endif
  1179. virtual void gcMarkRefs() const;
  1180. virtual void gcAppend() const;
  1181. char *gcCheck() const {
  1182. return 0;
  1183. }
  1184. };
  1185. // Arrays of primitive objects like ints
  1186. template<class T>
  1187. class gcPrimArray : public gcArrayBase {
  1188. public:
  1189. gcPrimArray() {
  1190. gcInternalArrayMakeCollectible();
  1191. }
  1192. static void *operator new(size_t, size_t);
  1193. operator T*() const {
  1194. return (T*)gcArrayBottom();
  1195. }
  1196. T& operator[](int n) const;
  1197. T* operator+(int n) const;
  1198. virtual void gcMarkRefs() const {}
  1199. protected:
  1200. GC_ODDNEW2
  1201. gcPrimArray(gcPosition) {
  1202. // used only by children for null effect.
  1203. }
  1204. private:
  1205. gcPrimArray(const gcPrimArray< T > &) {} // prevent use
  1206. };
  1207. // Arrays of collectible objects used like gcPrimArray< T >
  1208. template<class T>
  1209. class gcArray : public gcPrimArray< T > {
  1210. public:
  1211. gcArray();
  1212. #ifndef GC_NO_INPLACE_DESTRUCTORS
  1213. ~gcArray();
  1214. #endif
  1215. static void *operator new(size_t, size_t);
  1216. virtual void gcMarkRefs() const;
  1217. char * gcCheck() const;
  1218. protected:
  1219. GC_ODDNEW2
  1220. private:
  1221. gcArray(const gcArray< T > &) {} // private declaration prevents use
  1222. };
  1223. // These functions may not be inlined. They are kept together
  1224. /// to make the creation of the macro version easier.
  1225. GC_TEMPLATE void gcWrap< T >::setPointer(T* p) {
  1226. pointersBusy();
  1227. setHandle((gc *)(data = p));
  1228. }
  1229. GC_TEMPLATE gcArrayTest gcPointer< T >::gcInBounds(int n) const {
  1230. gcArrayBase *a = isArray();
  1231. return a ? a->gcInBounds((void *)(data + n)) : gcNotAnArray;
  1232. }
  1233. GC_TEMPLATE T& gcPointer< T >::operator[](int n) const {
  1234. return *(T*)gcValidReference((void *)(data + n));
  1235. }
  1236. GC_TEMPLATE T* gcPointer< T >::operator+(int n) const {
  1237. return data + n;
  1238. }
  1239. GC_TEMPLATE T* gcArrayP< T >::operator+(int n) const {
  1240. return data + n;
  1241. }
  1242. GC_TEMPLATE gcPointer< T >::gcPointer(gcPrimArray< T > *x) {
  1243. setPointer((T*)*x);
  1244. }
  1245. GC_TEMPLATE void gcPtr< T >::gcMarkRefs() const {
  1246. gcPointerBase::gcMarkRefs();
  1247. }
  1248. GC_TEMPLATE void gcPtr< T >::gcAppend() const {
  1249. gcPointerBase::gcAppend();
  1250. }
  1251. GC_TEMPLATE char * gcPtr< T >::gcCheck() const {
  1252. #ifdef GC_DEBUG
  1253. if (gcBusy)
  1254. return 0;
  1255. #endif
  1256. return (gcPtrHandle
  1257. ? ((data && gcPtrHandle->isArray()) ||
  1258. (data == gcPtrHandle->gcUsersObj))
  1259. : !data)
  1260. ? 0 : "Invalid Pointer";
  1261. }
  1262. GC_TEMPLATE void gcRef< T >::gcMarkRefs() const {
  1263. gcPointerBase::gcMarkRefs();
  1264. }
  1265. GC_TEMPLATE void gcRef< T >::gcAppend() const {
  1266. gcPointerBase::gcAppend();
  1267. }
  1268. GC_TEMPLATE char * gcRef< T >::gcCheck() const {
  1269. return gcPointerBase::gcCheck(data);
  1270. }
  1271. GC_TEMPLATE gcArrayTest gcArrayP< T >::gcInBounds(int n) const {
  1272. gcArrayBase *a = isArray();
  1273. return a ? a->gcInBounds((void *)(data + n)) : gcNotAnArray;
  1274. }
  1275. GC_TEMPLATE void gcArrayPtr< T >::gcMarkRefs() const {
  1276. gcPointerBase::gcMarkRefs();
  1277. }
  1278. GC_TEMPLATE void gcArrayPtr< T >::gcAppend() const {
  1279. gcPointerBase::gcAppend();
  1280. }
  1281. #ifndef __BCPLUSPLUS__
  1282. GC_TEMPLATE void gcReference< T >::operator=(T &x) {
  1283. *data = x;
  1284. }
  1285. GC_TEMPLATE void gcReference< T >::operator=(const gcReference< T > &x) {
  1286. *data = x();
  1287. }
  1288. #endif
  1289. // Pointer to default table or zero
  1290. #define GC_METHODS(T) GC_ARRAY_METHODS(T)
  1291. #ifdef GC_NO_TEMPLATE_STATICS
  1292. #define GC_ARRAY_METHODS(T) gcTable * gcGenerate< T >::gcTablePtr;
  1293. #else
  1294. #define GC_ARRAY_METHODS(T)
  1295. template<class T> gcTable * gcGenerate< T >::gcTablePtr;
  1296. #endif
  1297. // Array of primitive objects
  1298. GC_TEMPLATE void * gcPrimArray< T >::operator new(size_t s, size_t i) {
  1299. return gcArrayBase::operator new(s+i*sizeof(T),sizeof(T),&gc::gcLeafTable);
  1300. }
  1301. GC_TEMPLATE T& gcPrimArray< T >::operator[](int n) const {
  1302. T* loc = (T *)gcArrayBottom() + n;
  1303. GC_ASSERT(((void*)loc) >= gcArrayBottom() && ((void*)loc) < gcArrayEnd,
  1304. "Array reference out of bounds");
  1305. return *loc;
  1306. }
  1307. GC_TEMPLATE T* gcPrimArray< T >::operator+(int n) const {
  1308. T* loc = (T *)gcArrayBottom() + n;
  1309. GC_ASSERT(((void*)loc) >= gcArrayBottom() && ((void*)loc) <= gcArrayEnd,
  1310. "Array increment out of bounds");
  1311. return loc;
  1312. }
  1313. // For array of collectable objects
  1314. GC_TEMPLATE void * gcArray< T >::operator new(size_t s, size_t i) {
  1315. gcTable **table = gcGenerate< T >::whereTab();
  1316. if (!*table)
  1317. gcInternalMakeCollectible(new T, table);
  1318. return gcArrayBase::operator new(s + (i * sizeof(T)), sizeof(T), table);
  1319. }
  1320. GC_TEMPLATE gcArray< T >::gcArray() : gcPrimArray< T >(gcBase) {
  1321. for (T *x = (T *)*this; ((void*)x) < gcArrayEnd; x++)
  1322. new((void *)x) T;
  1323. gcInternalArrayMakeCollectible();
  1324. }
  1325. #ifndef GC_NO_INPLACE_DESTRUCTORS
  1326. GC_TEMPLATE_H gcArray< T >::~gcArray() {
  1327. for (T *x = (T *)*this; ((void*)x) < gcArrayEnd; x++)
  1328. x->~T();
  1329. }
  1330. #endif
  1331. // This will never be called on non collectible T.
  1332. GC_TEMPLATE void gcArray< T >::gcMarkRefs() const {
  1333. for (T *x = (T *)*this; ((void*)x) < gcArrayEnd; x++)
  1334. gcMaybeMarkRefs(x);
  1335. }
  1336. GC_TEMPLATE char * gcArray< T >::gcCheck() const {
  1337. for (T *x = (T *)*this; ((void*)x) < gcArrayEnd; x++) {
  1338. char *msg;
  1339. if (0 != (msg = gcMaybeCheck(x)))
  1340. return msg;
  1341. }
  1342. return 0;
  1343. }
  1344. #define GC_NEST(a, b, c) a< b< c > >
  1345. #define GC_START_CLASS(T) class T;
  1346. #define GC_FINISH_CLASS(T)
  1347. #define GC_PRIM(T)
  1348. #define GC_PRIM_METHODS(T)
  1349. #define GC_GENERATE(T) gcGenerate< T >
  1350. #define GC_WRAP(T) gcWrap< T >
  1351. #define GC_POINTER(T) gcPointer< T >
  1352. #define GC_REFERENCE(T) gcReference< T >
  1353. #define GC_PTR(T) gcPtr< T >
  1354. #define GC_REF(T) gcRef< T >
  1355. #define GC_ARRAYP(T) gcArrayP< T >
  1356. #define GC_ARRAYPTR(T) gcArrayPtr< T >
  1357. #define GC_PRIMARRAY(T) gcPrimArray< T >
  1358. #define GC_OBJARRAY(T) gcObjArray< T >
  1359. #define GC_ARRAY(T) gcArray< T >
  1360. #else // GC_NO_TEMPLATES
  1361. // These macros allow programs to be freely ported between compilers that
  1362. /// do and do not support templates.
  1363. // If you use cpp to expand this before debugging you will get a
  1364. /// largely unreadable mess. However we provide a program fixer.cpp
  1365. /// which will make it a semi readable mess.
  1366. #define GC_NEST(a, b, c) a ## _ ## b ## _ ## c
  1367. #define GC_GENERATE(T) GC_GENERATE_ ## T
  1368. #define GC_WRAP(T) GC_WRAP_ ## T
  1369. #define GC_POINTER(T) GC_P_ ## T
  1370. #define GC_REFERENCE(T) GC_R_ ## T
  1371. #define GC_PTR(T) GC_PTR_ ## T
  1372. #define GC_REF(T) GC_REF_ ## T
  1373. #define GC_ARRAYP(T) GC_ARRAYP_ ## T
  1374. #define GC_ARRAYPTR(T) GC_ARRAYPTR_ ## T
  1375. #define GC_PRIMARRAY(T) GC_PRIMARRAY_ ## T
  1376. #define GC_OBJARRAY(T) GC_OBJARRAY_ ## T
  1377. #define GC_ARRAY(T) GC_ARRAY_ ## T
  1378. #ifdef __BCPLUSPLUS__
  1379. #define GC_R_DEF(T) void operator=(T &x) { *data = x; } \
  1380. void operator=(const GC_REFERENCE(T) &x) { *data = x(); }
  1381. #define GC_R_MOD(T)
  1382. #else
  1383. #define GC_R_DEF(T) void operator=(T &x); \
  1384. void operator=(const GC_REFERENCE(T) &x);
  1385. #define GC_R_MOD(T) void GC_REFERENCE(T)::operator=(T &x) { *data = x; } \
  1386. void GC_REFERENCE(T)::operator=(const GC_REFERENCE(T) &x) { *data = x(); }
  1387. #endif
  1388. #ifdef GC_NO_INPLACE_DESTRUCTORS
  1389. #define GC_ARRAY_DES(T)
  1390. #define GC_ARRAY_DES_METH(T)
  1391. #else
  1392. #define GC_ARRAY_DES(T) ~GC_ARRAY(T)();
  1393. #define GC_ARRAY_DES_METH(T) GC_ARRAY(T)::~GC_ARRAY(T)() { \
  1394. for (T *x = (T *)*this; ((void*)x) < gcArrayEnd; x++) { x->~T(); } }
  1395. #endif
  1396. #ifdef GC_DEBUG
  1397. #define GC_P_DEF(T) T* operator=(int n) { \
  1398. GC_ASSERT(!n, "Invalid integer to pointer assignment"); \
  1399. setPointer(); return 0; } \
  1400. T& operator *() const { \
  1401. if (isArray()) \
  1402. return *(T*)gcValidReference((void *)data); \
  1403. else { \
  1404. GC_ASSERT(data, "Dereference of null pointer"); \
  1405. return *data; } }
  1406. #define GC_AP_DEF(T) T* operator=(int n) { \
  1407. GC_ASSERT(!n, "Invalid integer to pointer assignment"); \
  1408. setHandle(); return data = 0; } \
  1409. T& operator[](int n) const { \
  1410. return *(T*)gcValidReference((void *)(*this + n)); } \
  1411. T& operator *() const { \
  1412. return *(T*)gcValidReference((void *)data); }
  1413. #define GC_APTR_DEF(T) T* operator=(int n) { \
  1414. GC_ASSERT(!n, "Invalid integer to pointer assignment"); \
  1415. setPointer(); \
  1416. return 0; }
  1417. #define GC_CHECK_BUSY if(gcBusy) return 0;
  1418. #else
  1419. #define GC_P_DEF(T) T* operator=(int) { setPointer(); return 0; } \
  1420. T& operator *() const { return *data; }
  1421. #define GC_AP_DEF(T) T* operator=(int) { \
  1422. setHandle(); return data = 0; } \
  1423. T& operator *() const { return *data; } \
  1424. T& operator[](int n) const { return *(*this + n); }
  1425. #define GC_APTR_DEF(T) T* operator=(int) { \
  1426. setPointer(); \
  1427. return 0; }
  1428. #define GC_CHECK_BUSY
  1429. #endif
  1430. #define GC_INTERNAL(T) \
  1431. class T; \
  1432. class GC_WRAP(T) : public gcPointerBase { protected: \
  1433. T* data; \
  1434. GC_WRAP(T)() : data(0), gcPointerBase(0) {} \
  1435. GC_WRAP(T)(T *p) { setPointer(p); } \
  1436. GC_WRAP(T)(const GC_WRAP(T) &p) : data(p.data), \
  1437. gcPointerBase(p.gcPtrHandle) {} \
  1438. void setPointer() { pointersBusy(); data = 0; setHandle(); } \
  1439. void setPointer(T* p); \
  1440. void setPointer(const GC_WRAP(T) &p) { \
  1441. pointersBusy(); data = p.data; setHandle(p); } };
  1442. // Microsoft Visual C++ has a fixed macro expansion buffer which is
  1443. /// too small for GC_CLASS so you must use GC_START and GC_FINISH.
  1444. #define GC_START_CLASS(T) \
  1445. class GC_GENERATE(T); \
  1446. GC_INTERNAL(T) \
  1447. class GC_PRIMARRAY(T); \
  1448. class GC_POINTER(T) : public GC_WRAP(T) { public: \
  1449. GC_POINTER(T)() {} \
  1450. GC_POINTER(T)(int) {} \
  1451. GC_POINTER(T)(T *x) : GC_WRAP(T)(x) {} \
  1452. GC_POINTER(T)(const GC_POINTER(T) &x) : GC_WRAP(T)(x) {} \
  1453. GC_POINTER(T)(GC_PRIMARRAY(T) *x); \
  1454. T* operator=(T *x) { setPointer(x); return data; } \
  1455. T* operator=(const GC_POINTER(T) &x) { setPointer((T*)x); return data; } \
  1456. operator T*() const { return data; } \
  1457. T* operator()() const { return data; } \
  1458. T* operator->() const { return data; } \
  1459. int operator!() const { return data == 0; } \
  1460. int operator==(const GC_POINTER(T) &x) const { return data == x.data; } \
  1461. int operator==(T *x) const { return data == x; } \
  1462. int operator==(int x) const { return data == (T *) x; } \
  1463. int operator!=(const GC_POINTER(T) &x) const { return data != x.data; } \
  1464. int operator!=(T *x) const { return data != x; } \
  1465. T& operator[](int n) const; \
  1466. T* operator+(int n) const; \
  1467. T* operator-(int n) const { return (*this) + -n; } \
  1468. T* operator+=(int n) { return data = (*this + n); } \
  1469. T* operator-=(int n) { return data = (*this + -n); } \
  1470. GC_P_DEF(T) \
  1471. gcArrayTest gcInBounds(int n) const; }; \
  1472. class GC_REFERENCE(T) : public GC_WRAP(T) { public: \
  1473. GC_REFERENCE(T)() {} \
  1474. GC_REFERENCE(T)(const T &x) : GC_WRAP(T)((T *)&x) {} \
  1475. GC_REFERENCE(T)(const GC_REFERENCE(T) &x) : GC_WRAP(T)(x) {} \
  1476. GC_R_DEF(T) \
  1477. T& operator()() const { return *data; } \
  1478. operator T&() const { return *data; } }; \
  1479. class GC_REF(T) : public gc, public GC_REFERENCE(T) { public: \
  1480. GC_REF(T)() { gcPtrCollectible(); } \
  1481. GC_REF(T)(const T &x) : GC_REFERENCE(T)(x) { gcPtrCollectible(); } \
  1482. GC_REF(T)(const GC_REFERENCE(T) &x) : GC_REFERENCE(T)(x) { gcPtrCollectible(); } \
  1483. GC_REF(T)(const GC_REF(T) &x) : GC_REFERENCE(T)(x) { gcPtrCollectible(); } \
  1484. void gcMarkRefs() const; \
  1485. void gcAppend() const; \
  1486. char *gcCheck() const; }; \
  1487. class GC_PTR(T) : public gc, public GC_POINTER(T) { public: \
  1488. GC_PTR(T)(int i = 0) { gcPtrCollectible(); } \
  1489. GC_PTR(T)(T *x) : GC_POINTER(T)(x) { gcPtrCollectible(); } \
  1490. GC_PTR(T)(const GC_POINTER(T) &x) : GC_POINTER(T)(x) { gcPtrCollectible(); } \
  1491. GC_PTR(T)(const GC_PTR(T) &x) : GC_POINTER(T)(x) { gcPtrCollectible(); } \
  1492. GC_PTR(T)(GC_PRIMARRAY(T) *x) : GC_POINTER(T)(x) { gcPtrCollectible(); } \
  1493. T* operator=(T *x) { setPointer(x); return data; } \
  1494. T* operator=(const GC_POINTER(T) &x) { setPointer((T*)x); return data; } \
  1495. T* operator=(const GC_PTR(T) &x) { setPointer(x); return data; } \
  1496. T* operator->() const { return data; } \
  1497. void gcMarkRefs() const; \
  1498. void gcAppend() const; \
  1499. char *gcCheck() const; };
  1500. #define GC_PRIM(T) \
  1501. class GC_PRIMARRAY(T) : public gcArrayBase { \
  1502. GC_PRIMARRAY(T)(const GC_PRIMARRAY(T) &) {} \
  1503. protected: \
  1504. GC_ODDNEW2 \
  1505. GC_PRIMARRAY(T)(gcPosition) {} \
  1506. public: \
  1507. static void *operator new(size_t, size_t); \
  1508. GC_PRIMARRAY(T)() { gcInternalArrayMakeCollectible(); } \
  1509. operator T*() const { return (T*)gcArrayBottom(); } \
  1510. T& operator[](int n) const; \
  1511. T* operator+(int n) const; \
  1512. void gcMarkRefs() const {} }; \
  1513. class GC_ARRAYP(T) : public gcPointerBase { protected: \
  1514. T* data; \
  1515. void setPointer() { pointersBusy(); data = 0; setHandle(); } \
  1516. void setPointer(const GC_ARRAYP(T) &p) { \
  1517. pointersBusy(); data = p.data; setHandle(p.gcPtrHandle); } \
  1518. void setPointer(GC_PRIMARRAY(T) *p) { \
  1519. pointersBusy(); \
  1520. if (p) { \
  1521. data = (T*)p->gcArrayBottom(); setHandle(p); \
  1522. } else { \
  1523. data = 0; setHandle(); } } \
  1524. public: \
  1525. GC_ARRAYP(T)() : data(0), gcPointerBase(0) {} \
  1526. GC_ARRAYP(T)(int) : data(0), gcPointerBase(0) {} \
  1527. GC_ARRAYP(T)(const GC_ARRAYP(T) &p) : data(p.data), \
  1528. gcPointerBase(p.gcPtrHandle) {} \
  1529. GC_ARRAYP(T)(GC_PRIMARRAY(T) *p) { setPointer(p); } \
  1530. T* operator=(T *x) { return data = x; } \
  1531. T* operator=(const GC_ARRAYP(T) &x) { setPointer(x); return data; } \
  1532. T* operator=(GC_PRIMARRAY(T) *x) { setPointer(x); return data; } \
  1533. operator T*() const { return data; } \
  1534. T* operator()() const { return data; } \
  1535. operator GC_PRIMARRAY(T) *() const { \
  1536. return (GC_PRIMARRAY(T) *)(void *)isArray(); } \
  1537. int operator!() const { return data == 0; } \
  1538. int operator==(const GC_ARRAYP(T) &x) const { return data == x.data; } \
  1539. int operator==(T *x) const { return data == x; } \
  1540. int operator!=(const GC_ARRAYP(T) &x) const { return data != x.data; } \
  1541. int operator!=(T *x) const { return data != x; } \
  1542. T* operator+(int n) const; \
  1543. T* operator-(int n) const { return (*this) + -n; } \
  1544. T* operator+=(int n) { return data = (*this + n); } \
  1545. T* operator-=(int n) { return data = (*this + -n); } \
  1546. size_t len() const { \
  1547. gcArrayBase *a = isArray(); return a ? a->len() : 0; } \
  1548. size_t size() const { \
  1549. gcArrayBase *a = isArray(); return a ? a->size() : 0; } \
  1550. void setLen(size_t l) { \
  1551. gcArrayBase *a = isArray(); if (a) a->setLen(l); } \
  1552. GC_AP_DEF(T) \
  1553. gcArrayTest gcInBounds(int n) const; }; \
  1554. class GC_ARRAYPTR(T) : public gc, public GC_ARRAYP(T) { public: \
  1555. GC_ARRAYPTR(T)() { gcPtrCollectible(); } \
  1556. GC_ARRAYPTR(T)(const GC_ARRAYP(T) &x) : GC_ARRAYP(T)(x) { \
  1557. gcPtrCollectible(); } \
  1558. GC_ARRAYPTR(T)(const GC_ARRAYPTR(T) &x) : GC_ARRAYP(T)(x) { \
  1559. gcPtrCollectible(); } \
  1560. GC_ARRAYPTR(T)(GC_PRIMARRAY(T) *x) : GC_ARRAYP(T)(x) { \
  1561. gcPtrCollectible(); } \
  1562. T* operator=(GC_PRIMARRAY(T) *x) { setPointer(x); return data; } \
  1563. GC_APTR_DEF(T) \
  1564. void gcMarkRefs() const; \
  1565. void gcAppend() const; \
  1566. char *gcCheck() const { return 0; } }; \
  1567. #define GC_FINISH_CLASS(T) \
  1568. class GC_GENERATE(T) { \
  1569. public: \
  1570. static gcTable** whereTab(); \
  1571. static gcTable* gcTablePtr; }; \
  1572. GC_INTERNAL(GC_PARRAY_ ## T) \
  1573. GC_PRIM(T) \
  1574. class GC_ARRAY(T) : public GC_PRIMARRAY(T) { \
  1575. GC_ARRAY(T)(const GC_ARRAY(T) &) {} \
  1576. protected: \
  1577. GC_ODDNEW2 \
  1578. public: \
  1579. static void *operator new(size_t, size_t); \
  1580. GC_ARRAY(T)(); \
  1581. GC_ARRAY_DES(T) \
  1582. void gcMarkRefs() const; \
  1583. char * gcCheck() const; };
  1584. #define GC_INTERNAL_METHODS(T) \
  1585. void GC_WRAP(T)::setPointer(T* p) { \
  1586. pointersBusy(); \
  1587. setHandle((gc *)(data = p)); }
  1588. #define GC_METHODS(T) \
  1589. GC_INTERNAL_METHODS(T) \
  1590. gcArrayTest GC_POINTER(T)::gcInBounds(int n) const { \
  1591. gcArrayBase *a = isArray(); \
  1592. return a ? a->gcInBounds((void *)(data + n)) : gcNotAnArray; } \
  1593. T& GC_POINTER(T)::operator[](int n) const { \
  1594. return *(T*)gcValidReference((void *)(data + n)); } \
  1595. T* GC_POINTER(T)::operator+(int n) const { \
  1596. return data + n; } \
  1597. GC_POINTER(T)::GC_POINTER(T)(GC_PRIMARRAY(T) *x) { setPointer((T*)*x); } \
  1598. void GC_PTR(T)::gcMarkRefs() const { gcPointerBase::gcMarkRefs(); } \
  1599. void GC_PTR(T)::gcAppend() const { gcPointerBase::gcAppend(); } \
  1600. char * GC_PTR(T)::gcCheck() const { \
  1601. GC_CHECK_BUSY \
  1602. return (gcPtrHandle \
  1603. ? ((data && gcPtrHandle->isArray()) || \
  1604. (data == gcPtrHandle->gcUsersObj)) \
  1605. : !data) ? 0 : "Invalid Pointer"; } \
  1606. GC_R_MOD(T) \
  1607. void GC_REF(T)::gcMarkRefs() const { gcPointerBase::gcMarkRefs(); } \
  1608. void GC_REF(T)::gcAppend() const { gcPointerBase::gcAppend(); } \
  1609. char * GC_REF(T)::gcCheck() const { return gcPointerBase::gcCheck(data); } \
  1610. GC_ARRAY_METHODS(T)
  1611. #define GC_PRIM_METHODS(T) \
  1612. T& GC_PRIMARRAY(T)::operator[](int n) const { \
  1613. T* loc = (T *)gcArrayBottom() + n; \
  1614. GC_ASSERT(((void*)loc) >= gcArrayBottom() && ((void*)loc) < gcArrayEnd, \
  1615. "Array reference out of bounds"); \
  1616. return *loc; } \
  1617. T* GC_PRIMARRAY(T)::operator+(int n) const { \
  1618. T* loc = (T *)gcArrayBottom() + n; \
  1619. GC_ASSERT(((void*)loc) >= gcArrayBottom() && ((void*)loc) <= gcArrayEnd, \
  1620. "Array increment out of bounds"); \
  1621. return loc; } \
  1622. T* GC_ARRAYP(T)::operator+(int n) const { \
  1623. return data + n; } \
  1624. void * GC_PRIMARRAY(T)::operator new(size_t s, size_t i) { \
  1625. return gcArrayBase::operator new(s+i*sizeof(T),sizeof(T),&gc::gcLeafTable); }\
  1626. gcArrayTest GC_ARRAYP(T)::gcInBounds(int n) const { \
  1627. gcArrayBase *a = isArray(); \
  1628. return a ? a->gcInBounds((void *)(data + n)) : gcNotAnArray; } \
  1629. void GC_ARRAYPTR(T)::gcMarkRefs() const { gcPointerBase::gcMarkRefs(); } \
  1630. void GC_ARRAYPTR(T)::gcAppend() const { gcPointerBase::gcAppend(); } \
  1631. #define GC_ARRAY_METHODS(T) \
  1632. GC_INTERNAL_METHODS(GC_PARRAY_ ## T) \
  1633. gcTable ** GC_GENERATE(T)::whereTab() { return &gcTablePtr; } \
  1634. gcTable * GC_GENERATE(T)::gcTablePtr; \
  1635. GC_PRIM_METHODS(T) \
  1636. void * GC_ARRAY(T)::operator new(size_t s, size_t i) { \
  1637. gcTable **table = GC_GENERATE(T)::whereTab(); \
  1638. if (!*table) gcInternalMakeCollectible(new T, table); \
  1639. return gcArrayBase::operator new(s + (i * sizeof(T)), sizeof(T), table);} \
  1640. GC_ARRAY(T)::GC_ARRAY(T)() : GC_PRIMARRAY(T)(gcBase) { \
  1641. for (T *x = (T *)*this; ((void*)x) < gcArrayEnd; x++) \
  1642. new((void *)x) T; \
  1643. gcInternalArrayMakeCollectible(); } \
  1644. GC_ARRAY_DES_METH(T) \
  1645. void GC_ARRAY(T)::gcMarkRefs() const { \
  1646. for (T *x = (T *)*this; ((void*)x) < gcArrayEnd; x++) \
  1647. gcMaybeMarkRefs(x); } \
  1648. char * GC_ARRAY(T)::gcCheck() const { \
  1649. for (T *x = (T *)*this; ((void*)x) < gcArrayEnd; x++) { \
  1650. char *msg; \
  1651. if (0 != (msg = gcMaybeCheck(x))) return msg; } \
  1652. return 0; }
  1653. #endif
  1654. #endif