Dan Sugalski wrote: > This feels excessively hackish. It's OK if we were welding in COW to > an existing code base, but we're not--if we put it in, we put it in > right. > > Right, in this case, is using the COW flag bit in the Buffer > structure and making the changes to the appropriate string_* > functions to use it, I think.
The COW flag bit in the string header is used by the string functions; however, for GC purposes, I need a flag within the buffer as well, to identify buffers which have already been copied, since multiple string headers could point to the same physical buffer. That is the best I can do, so perhaps we should leave COW for somebody else to implement later. For interest, I am attaching an extract from my version of resources.c (not in diff format, because I have not completed syncing yet - things keep changing!) strstart is a void* field in STRING, pointing to the start of the string of interest in the buffer; this could be omitted if substrings were not COWed The last byte of the allocated buffer is always set to zero by string_make and other string creators When a buffer is copied, the address of the first STRING that referenced it is stored in the (old copy of the) buffer, and the in-buffer flag is set; if the same buffer is encountered later, the second header is simply adjusted to point to the new location. -- Peter Gibbs EmKel Systems /* Run through all the string header pools and copy */ for (cur_string_arena = interpreter->arena_base->last_STRING_Arena; NULL != cur_string_arena; cur_string_arena = cur_string_arena->prev) { UINTVAL i; STRING *string_array = cur_string_arena->start_STRING; for (i = 0; i < cur_string_arena->used; i++) { /* Is the string live, and can we move it? */ if (string_array[i].flags & BUFFER_live_FLAG && !(string_array[i].flags & BUFFER_immobile_FLAG) && string_array[i].bufstart) { UINTVAL offset = (char *)string_array[i].strstart - (char *)string_array[i].bufstart; if (string_array[i].flags & BUFFER_COW_FLAG && ((char*)(string_array[i].bufstart))[string_array[i].buflen]) { /* buffer has already been copied; just change the header */ STRING* hdr = *(STRING **)(string_array[i].bufstart); hdr->flags |= BUFFER_COW_FLAG; string_array[i].bufstart = hdr->bufstart; string_array[i].strstart = (char *)(string_array[i].bufstart) + offse t; } else { memcpy(cur_spot, string_array[i].bufstart, string_array[i].buflen+1); if (string_array[i].flags & BUFFER_COW_FLAG) { /* store new address and set 'buffer already copied' flag */ *(STRING **)(string_array[i].bufstart) = &string_array[i]; string_array[i].flags &= ~BUFFER_COW_FLAG; ((char*)(string_array[i].bufstart))[string_array[i].buflen] = 1; } string_array[i].bufstart = cur_spot; string_array[i].strstart = (char *)(string_array[i].bufstart) + offse t; cur_size = string_array[i].buflen; cur_size += 16; cur_size &= ~0x0f; cur_spot += cur_size; } } } }