Return-Path: Delivered-To: apmail-incubator-harmony-dev-archive@www.apache.org Received: (qmail 67771 invoked from network); 17 Oct 2006 09:30:49 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 17 Oct 2006 09:30:49 -0000 Received: (qmail 24360 invoked by uid 500); 17 Oct 2006 09:30:45 -0000 Delivered-To: apmail-incubator-harmony-dev-archive@incubator.apache.org Received: (qmail 24320 invoked by uid 500); 17 Oct 2006 09:30:45 -0000 Mailing-List: contact harmony-dev-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: harmony-dev@incubator.apache.org Delivered-To: mailing list harmony-dev@incubator.apache.org Received: (qmail 24309 invoked by uid 99); 17 Oct 2006 09:30:45 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 17 Oct 2006 02:30:45 -0700 X-ASF-Spam-Status: No, hits=-0.0 required=10.0 tests=SPF_HELO_PASS,SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (asf.osuosl.org: domain of gcjhd-harmony-dev@m.gmane.org designates 80.91.229.2 as permitted sender) Received: from [80.91.229.2] (HELO ciao.gmane.org) (80.91.229.2) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 17 Oct 2006 02:30:43 -0700 Received: from root by ciao.gmane.org with local (Exim 4.43) id 1GZlGs-0007O7-MW for harmony-dev@incubator.apache.org; Tue, 17 Oct 2006 11:30:04 +0200 Received: from iswfwpr01.isw.intel.com ([192.55.37.193]) by main.gmane.org with esmtp (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Tue, 17 Oct 2006 11:30:02 +0200 Received: from Salikh.Zakirov by iswfwpr01.isw.intel.com with local (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Tue, 17 Oct 2006 11:30:02 +0200 X-Injected-Via-Gmane: http://gmane.org/ To: harmony-dev@incubator.apache.org From: Salikh Zakirov Subject: Re: "Hot to Write GC" requires improvement Date: Tue, 17 Oct 2006 13:29:13 +0400 Lines: 1391 Message-ID: References: <32CD23D8C6B1454C9120C1525D521D675BDA80@nnsmsx411.ccr.corp.intel.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------010908000603050505080305" X-Complaints-To: usenet@sea.gmane.org X-Gmane-NNTP-Posting-Host: iswfwpr01.isw.intel.com User-Agent: Thunderbird 1.5.0.7 (Windows/20060909) In-Reply-To: <32CD23D8C6B1454C9120C1525D521D675BDA80@nnsmsx411.ccr.corp.intel.com> Sender: news X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N --------------010908000603050505080305 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Svetlana, I've looked through your changes. Mostly they look okay, and they greatly improve the visual presentation. Originally, GC-howto was created using AsciiDoc[1] toolchain from the source text file and source .cpp file. Modifying .html file directly means that we cannot update the document to keep it in sync with the source code. I guess this is acceptable, since nobody is changing source code inlets in GC-howto now, but be warned: if anyone is to introduce source changes, it would tedious task to synchronize visual and content changes. Have you tried to configure asciidoc to produce the content you want? I will send you the version of gc-howto.txt and gc.cpp that I have, but Nadya may have a later version, so please check with her. Since I am not sure attachment will make it to the list, I'll send it to you directly. (* or to anyone else who might be interested, just ask *) [1] http://www.methods.co.nz/asciidoc/ Konovalova, Svetlana wrote: > Sorry about that! > I've created a new patch, hope it's the right one you need. Please let > me know if you still have any problems. > > [JIRA 1881] http://issues.apache.org/jira/browse/HARMONY-1881 > > Cheers, > Sveta Konovalova > > -----Original Message----- > From: Geir Magnusson Jr. [mailto:geir@pobox.com] > Sent: Tuesday, October 17, 2006 8:50 AM > To: harmony-dev@incubator.apache.org > Subject: Re: "Hot to Write GC" requires improvement > > The problem with the patch is that it's to the rendered output > > site/xdoc/subcomponent/drlvm/gc-howto.html > > when what we need is the patch to the source document > > site/xdoc/subcomponent/drlvm/gc-howto-content.html > > Can you add a new patch with that please? > > geir > > Rana Dasgupta wrote: >> This is a good document, thanks Svetlana. Even if a lot of custom gc's > >> don't >> get written, it helps in understanding the current collecor farmework > and >> how it plugs into DRLVM. >> >> Rana >> >> >> >>> On 10/16/06, Konovalova, Svetlana > wrote: >>>> >>>> Folks, >>>> >>>> I took a close look at "Hot to Write GC" [1] and created a patch > for >>>> this doc [JIRA 1881]. I fixed formatting, brushed up the code, > removed >>>> out-dated tags etc. >>>> It would be great if someone can find a chance to look at the > patch. >>>> Thanks in advance! >>>> >>>> [1] >>>> > http://incubator.apache.org/harmony/subcomponents/drlvm/gc-howto.html >>>> [JIRA 1881] http://issues.apache.org/jira/browse/HARMONY-1881 >>>> >>>> >>>> Cheers, >>>> Sveta Konovalova >>>> >>>> > > --------------------------------------------------------------------- > Terms of use : http://incubator.apache.org/harmony/mailing.html > To unsubscribe, e-mail: harmony-dev-unsubscribe@incubator.apache.org > For additional commands, e-mail: harmony-dev-help@incubator.apache.org > > --------------------------------------------------------------------- > Terms of use : http://incubator.apache.org/harmony/mailing.html > To unsubscribe, e-mail: harmony-dev-unsubscribe@incubator.apache.org > For additional commands, e-mail: harmony-dev-help@incubator.apache.org > > --------------010908000603050505080305 Content-Type: text/plain; name="gc.cpp" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="gc.cpp" /** * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include "open/gc.h" #include "open/vm_gc.h" #include "open/vm.h" #define LOG_DOMAIN "gc" #include "cxxlog.h" typedef unsigned char byte; ////////////////////////////////////////////////// // non-GC utilities // Included to get critical sections #include struct Lock { CRITICAL_SECTION cs; Lock() { InitializeCriticalSection(&cs); } ~Lock() { DeleteCriticalSection(&cs); } void lock() { EnterCriticalSection(&cs); } void unlock() { LeaveCriticalSection(&cs); } }; // convenient converter from sizes in bytes to Megabytes inline int mb (int i) { return (i + 1048576/2) / 1048576; } ////////////////////////////////////////////////// // GC types // This structure is allocated for each user thread. // It contains the thread-local allocation area. struct TLS { byte* current; // the allocation pointer byte* limit; // the end of the allocation area }; struct InteriorPointer { struct Object* base; int offset; struct Object** interior_ref; }; // Encapsulates all GC data. struct GC { unsigned int semisize; // the size of the semispace unsigned int chunk_size; // the chunk size for thread-local chunks byte* space; // the pointer to the heap Lock lock; // the lock to protect global heap access byte* fromspace;// the allocation space byte* current; // the allocation marker byte* limit; // the allocation limit byte* tospace; // the evacuation space byte* scan; // the scan marker byte* copy; // the copy marker byte* toend; // the evacuation space limit // The list of thread-local storage (TLS) // structures allocated for user threads. std::list threads; void init(); // configures and initalizes GC void wrapup(); // destroys the heap // Allocates an object from a thread chunk // reserving space for TLS as needed. byte* alloc(unsigned size, TLS* tls); // Allocates space on the global heap. byte* galloc(unsigned size); byte* move(void*); // moves an object byte* forwarded(void*); // reads the forwarding pointer void root(void**); // handles a root reference void trace(byte*); // traces one object // Collects garbage and allocates the object. byte* collect_alloc(unsigned size, TLS* tls); std::list interior_pointers; void repoint_all_roots_with_interior_points(); }; // Structure OI (from "object information") // is used to cache GC information for each Java class // loaded by the virtual machine. // Each VTable stores the pointer to an OI (Object information) structure. struct OI { char magic[8]; // used for debugging const char *name; // the class name (handy for debugging) bool is_array; // true if this structure describes array bool has_slots; // true if the described object has reference fields // (aka slots) and thus needs to be traced // during collection int size; // the object size or the array element size int* offsets; // zero-terminated list of slot offsets in an object // undefined for array }; ////////////////////////////////////////////////// // Static assumptions about object layout // The VTable structure has 4 bytes reserved // for GC use at the beginning. // The pointer to the OI structure is stored there. struct VTable { OI* oi; // Other VTable fields are not used in GC. }; // Describes the object header format assumed by GC. struct Object { VTable *vt; uint32 lockword; }; // Describes the array header format assumed by GC. struct Array { VTable *vt; uint32 lockword; uint32 length; }; ////////////////////////////////////////////////// // GC utility functions // void init_vt(Managed_Object_Handle p, Allocation_Handle ah) { Object* obj = (Object*)p; obj->vt = (VTable*)ah; } OI* obj_oi(Managed_Object_Handle p) { Object* obj = (Object*)p; return obj->vt->oi; } int array_length(Managed_Object_Handle p) { Array* array = (Array*)p; return array->length; } OI* vt_oi(VTable_Handle p) { VTable* vt = (VTable*)p; return vt->oi; } OI* ah_oi(Allocation_Handle ah) { // Allocation_Handle is a VTable pointer on 32-bit platforms. return vt_oi((VTable_Handle)ah); } int object_size (Managed_Object_Handle obj) { OI* oi = obj_oi(obj); if (oi->is_array) { // 4-byte alignment return ((oi->size * array_length(obj) + 12) + 3) & (~3); } else { return oi->size; } } ///////////////////////////////////////////////////// // Global GC instance GC gc; ///////////////////////////////////////////// // GC functions // void GC::init() { semisize = 500*1024*1024; chunk_size = 64*1024; space = (byte*) malloc(semisize*2); assert(space); assert(((int)space & 3) == 0); fromspace = space; tospace = fromspace + semisize; assert(((int)tospace & 3) == 0); toend = tospace + semisize; INFO("heap size " << mb(2*semisize) << " Mb " << (void*)space << "-" << (void*)(space + 2*semisize)); current = fromspace; limit = fromspace + semisize; LOG("allocation from " << (void*)current << "-" << (void*)limit); memset(current, 0, limit - current); interior_pointers.clear(); } void GC::wrapup() { ::free(space); } byte* GC::galloc(unsigned size) { byte* r = NULL; lock.lock(); if (current + size <= limit) { r = current; current += size; } lock.unlock(); return r; } byte* GC::alloc(unsigned size, TLS* tls) { byte* obj = NULL; assert(NULL == tls->current || fromspace <= tls->current); assert(NULL == tls->limit || tls->limit <= limit); if (tls->current + size <= tls->limit) { // Allocate from the thread-local chunk if possible. obj = tls->current; tls->current += size; return obj; } // Allocate "large" objects directly from the heap // bypassing the thread-local allocation buffer // to prevent inefficient handling of half-filled // thread-local allocation buffers. if (size >= chunk_size/4) { return gc.galloc(size); } // Allocate a new thread-local chunk. obj = gc.galloc(chunk_size); if (obj) { tls->current = obj + size; tls->limit = obj + chunk_size; } return obj; } byte* GC::forwarded (void* obj) { int* p = (int*)obj + 1; int lockword = *p; if (lockword & 1) return (byte*)(lockword & (~1)); else return NULL; } byte* GC::move (void* obj) { int size = object_size(obj); assert(tospace <= copy); assert(copy + size <= toend); byte* nobj = copy; TRACE2("gc.move", "move " << (void*)obj << " -> " << (void*)nobj); assert(((int)nobj & 3) == 0); memcpy(nobj, obj, size); copy += size; assert(((int)copy & 3) == 0); int* plockword = (int*)obj + 1; *plockword = ((int)nobj) | 1; return nobj; } void GC::root(void** root) { byte* obj = (byte*)(*root); byte* nobj = forwarded(obj); if (NULL == nobj) { nobj = move(obj); } TRACE2("gc.root", "root " << root << " repointed from " << (void*)obj << " to " << (void*)nobj); *root = nobj; } void GC::trace (byte* obj) { OI* oi = obj_oi(obj); TRACE2("gc.trace", "trace " << (void*)obj << " (" << (void*)object_size(obj) << ", " << oi->name << ")"); if (!oi->has_slots) return; if (oi->is_array) { int len = array_length(obj); int i; // Trace (len) elements starting from the offset 12. // NB: long[] and double[] start at offset 16 // but never need tracing. byte** elem = (byte**)(obj + 12); for (i = 0; i < len; i++, elem += 1) { if (NULL == *elem) continue; byte* nobj = forwarded(*elem); if (!nobj) nobj = move(*elem); TRACE2("gc.update", "elem " << i << " in array " << (void*)obj << " repointed from " << (void*)(*elem) << " to " << (void*)nobj); *elem = nobj; } } else { int* poff; // Use (offsets) array to get the list of reference // field offsets in an object. for (poff = oi->offsets; *poff; poff++) { byte** field = (byte**) (obj + *poff); if (NULL == *field) continue; byte* nobj = forwarded(*field); if (!nobj) nobj = move(*field); TRACE2("gc.update", "field " << *poff << " in object " << (void*)obj << " repointed from " << (void*)(*field) << " to " << (void*)nobj); *field = nobj; } } } void GC::repoint_all_roots_with_interior_points() { for( std::list::iterator it = interior_pointers.begin(); it != interior_pointers.end(); it++ ){ Object** root_ref = (*it).interior_ref; Object* root_base = (*it).base; const int root_offset = (*it).offset; Object* new_slot_contents = root_base + root_offset; if( new_slot_contents != *root_ref ){ *root_ref = new_slot_contents; } } interior_pointers.clear(); return; } byte* GC::collect_alloc(unsigned size, TLS* tls) { scan = tospace; copy = tospace; toend = tospace + semisize; LOG("allocated " << (current - fromspace) << " bytes"); LOG("collection to " << (void*)tospace << "-" << (void*)toend); vm_enumerate_root_set_all_threads(); LOG("scan"); while (scan < copy) { trace(scan); scan += object_size(scan); } LOG("live " << (copy-tospace) << " bytes"); if( !interior_pointers.empty() ){ repoint_all_roots_with_interior_points(); } byte* swap = tospace; tospace = fromspace; fromspace = swap; current = copy; limit = fromspace + semisize; memset(current, 0, limit - current); LOG("allocation from " << (void*)current << "-" << (void*)limit); std::list::iterator i; int j; for (i = gc.threads.begin(), j = 0; i != gc.threads.end(); i++, j++) { (*i) -> current = NULL; (*i) -> limit = NULL; } LOG2("gc.threads", "reset thread allocation areas in " << j << " user threads"); byte* obj = NULL; if (size > 0) { // Allocate an object before resuming threads to maintain // "fairness" and prevent spurious out-of-memory errors. obj = alloc(size, tls); } vm_resume_threads_after(); return obj; } ////////////////////////////////////////////////// // Interface functions // void gc_init() { gc.init(); } void gc_vm_initialized() { } void gc_wrapup() { gc.wrapup(); } void gc_thread_init(void* tp) { TRACE2("gc.thread", "gc_thread_init " << tp); TLS* tls = (TLS*) tp; std::list::iterator i = std::find(gc.threads.begin(), gc.threads.end(), tls); assert(i == gc.threads.end()); gc.threads.push_back(tls); tls->current = NULL; tls->limit = NULL; } void gc_thread_kill(void* tp) { TRACE2("gc.thread", "gc_thread_kill " << tp); TLS* tls = (TLS*) tp; std::list::iterator i = std::find(gc.threads.begin(), gc.threads.end(), tls); assert(i != gc.threads.end()); gc.threads.erase(i); tls->current = NULL; tls->limit = NULL; } Managed_Object_Handle gc_alloc (unsigned size, Allocation_Handle ah, void *tp) { Managed_Object_Handle obj; TLS* tls = (TLS*) tp; // The next-to-highest bit of the size may be set // when allocating objects requiring finalization. // Ignore hint for now. size = size & 0x3fffffff; assert((size & 3) == 0); assert(ah_oi(ah)->is_array || size == ah_oi(ah)->size); // First, try the allocation obj = gc.alloc(size, tls); if (!obj) { // If the allocation failed, // grab the global GC lock. vm_gc_lock_enum(); // Multiple threads may try to get the GC lock. // Only one gets it and does a collection, and others get // blocked on vm_gc_lock_enum() during collection. // Retry the allocation while holding the GC lock. obj = gc.alloc(size, tls); // The allocation will succeed if another thread // has done collection while this thread was waiting for the GC lock. if (!obj) { // If the allocation failed, start a garbage collection. obj = gc.collect_alloc(size, tls); // NULL return value from collect_alloc() indicates out-of-memory. } vm_gc_unlock_enum(); } if (obj) init_vt(obj, ah); TRACE2("gc.alloc.slow", "gc_alloc(" << (void*)size << ", " << (*(OI**)ah)->name << ") = " << obj); assert(NULL == obj || (gc.fromspace <= obj && obj < gc.limit && ((int)obj & 3) == 0)); return obj; } Managed_Object_Handle gc_alloc_fast (unsigned size, Allocation_Handle ah, void *tp) { Managed_Object_Handle obj; TLS* tls = (TLS*) tp; size = size & 0x3fffffff; assert((size & 3) == 0); assert(ah_oi(ah)->is_array || size == ah_oi(ah)->size); obj = gc.alloc(size, tls); if (obj) init_vt(obj, ah); TRACE2("gc.alloc.fast", "gc_alloc_fast(" << (void*)size << ", " << (*(OI**)ah)->name << ") = " << obj); assert(NULL == obj || (gc.fromspace <= obj && obj < gc.limit && ((int)obj & 3) == 0)); return obj; } Boolean gc_requires_barriers() { return FALSE; } Boolean gc_supports_compressed_references() { return FALSE; } void gc_write_barrier(Managed_Object_Handle p_base_of_object_holding_ref) { assert(!"gc does not support write barriers"); } void *gc_heap_base_address() { return (void *)gc.space; } void *gc_heap_ceiling_address() { return (void *)(gc.space + 2*gc.semisize); } void gc_add_root_set_entry(Managed_Object_Handle *ref, Boolean is_pinned) { assert(!is_pinned); TRACE2("gc.root", "gc_add_root_set_entry " << ref << " -> " << *ref); if (NULL == *ref) return; gc.root(ref); } Boolean gc_is_object_pinned(Managed_Object_Handle obj) { return FALSE; } static int *build_slot_offset_array(Class_Handle ch) { unsigned num_ref_fields = 0; // Get the total number of fields including primitive fields. unsigned num_fields = class_num_instance_fields_recursive(ch); // Compute the number of reference fields. unsigned int i; for (i = 0; i < num_fields; i++) { // For each field, get its handle and check // whether it's a reference type. Field_Handle fh = class_get_instance_field_recursive(ch, i); if (field_is_reference(fh)) { num_ref_fields++; } } if (0 == num_ref_fields) return NULL; // Allocate the offsets array. int* ref_array = (int*) malloc((num_ref_fields+1) * sizeof(int)); // For each reference field, store its offset // into the offsets array. int* p = ref_array; for (i = 0; i < num_fields; i++) { Field_Handle fh = class_get_instance_field_recursive(ch, i); if (field_is_reference(fh)) { *p = field_get_offset(fh); p++; } } // It is 0 delimited. *p = 0; return ref_array; } void gc_class_prepared (Class_Handle ch, VTable_Handle vth) { TRACE2("gc.prepared", "gc_class_prepared(" << class_get_name(ch) << ")"); OI** vt = (OI**) vth; OI* oi = new OI; *vt = oi; memset(oi, 0, sizeof(OI)); strcpy(oi->magic, " OI "); oi->name = class_get_name(ch); if (class_is_array(ch)) { oi->is_array = true; // Store the array element size in the OI structure > size. oi->size = class_element_size(ch); // Reference arrays have slots, non-reference arrays don't. oi->has_slots = !class_is_non_ref_array(ch); assert(NULL == oi->offsets); } else { oi->is_array = false; // Store the object size in the OI structure > size. oi->size = class_get_boxed_data_size(ch); assert((oi->size & 3) == 0); oi->offsets = build_slot_offset_array(ch); oi->has_slots = (oi->offsets != NULL); } } void gc_add_root_set_entry_interior_pointer (void **slot, int offset, Boolean is_pinned) { assert(offset > 0); assert( !is_pinned ); Object* p_obj = (Object *)((Byte*)*slot - offset); assert( p_obj->vt != NULL ); InteriorPointer ip; ip.offset = offset; ip.interior_ref = (Object**)slot; ip.base = (Object*)((*(unsigned char**)slot) - offset); OI* oi = obj_oi(ip.base); TRACE2("gc.ip", "interior_pointer " << (void*)ip.base << " (" << (void*)object_size(ip.base) << ", " << oi->name << ")"); gc.interior_pointers.push_back( ip ); gc_add_root_set_entry( (Managed_Object_Handle*)&(ip.base), is_pinned ); return; } void gc_force_gc () { vm_gc_lock_enum(); gc.collect_alloc(0, NULL); vm_gc_unlock_enum(); } int64 gc_free_memory() { return 0; } void gc_pin_object(Managed_Object_Handle*) { } void gc_unpin_object(Managed_Object_Handle*) { } Managed_Object_Handle gc_get_next_live_object(void*) { assert(!"gc does not support heap iteration"); return NULL; } void gc_finalize_on_exit() { } unsigned gc_time_since_last_gc() { return 0; } int64 gc_total_memory() { return 2*gc.semisize; } int64 gc_max_memory() { return 2*gc.semisize; } --------------010908000603050505080305 Content-Type: text/plain; name="GC-howto.conf" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="GC-howto.conf" # Copyright 2005 The Apache Software Foundation or its licensors, as applicable. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # [miscellaneous] numbered [specialwords] monospacedwords = \w+\(\) \w+(?:\/[\w.]*)+ \w+\.dll \w+\.exe \w+\.h(?!\w) \w+\.cpp \w+\.xml NULL [header] {doctitle} # Article, book header. --------------010908000603050505080305 Content-Type: text/plain; name="GC-howto.txt" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="GC-howto.txt" How to write DRL GC =================== Salikh.Zakirov@Intel.com, Nadezhda.Morozova@intel.com revision 1.0, 2006-04-19 // // Copyright 2005 The Apache Software Foundation or its licensors, as applicable. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // // Generate HTML version of this document from text source // and configuration file GC-howto.conf using the command // // asciidoc -f GC-howto.conf --unsafe GC-howto.txt // // Download Asciidoc generic distribution archive from // // http://www.methods.co.nz/asciidoc/downloads.html // // unpack it somewhere (e.g. /usr/local/opt/asciidoc), and // symlink /usr/local/opt/asciidoc/asciidoc.py to /usr/local/bin/asciidoc // This document provides instructions on creating a custom garbage collector implementation in C++ and configuring the DRL virtual machine to use it. The section describes the major steps of this procedure, namely: - Establishing the build infrastructure - Implementing the GC interface - Implementing the garbage collector algorithm - Running the VM with the custom GC .Note Plugging-in a user-designed garbage collector presupposes an operating DRL virtual machine built according to the instructions of the README.txt file supplied with the VM source package. Establishing the build infrastructure ------------------------------------- At this stage, you create the directory and set up the build infrastructure to build the dynamic library. At the end of this stage, you will be fully set for adding the garbage collector code and building it. DRLVM can load a custom garbage collector from a dynamic library. It is recommended that you build your dynamic library using a DRLVM build infrastructure. Below is an example of creating of a build descriptor on the Windows* / IA-32 architecture. Create a directory for a new GC module, for example: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ----- vm$ mkdir gc_copying vm$ mkdir gc_copying/src vm$ cd gc_copying/src ----- That is where you will put the source code, see Section 3, Implementing the garbage collector algorithm. Create a build descriptor file ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Create the build descriptor file build/make/components/vm/gc_copying.xml with the following content: ----- sys::[sed -n '/