'From Squeak 2.3 of January 14, 1999 on 20 April 1999 at 9:35:11 am'! "Change Set: imageSeg-tkKB Date: 20 April 1999 Author: Ted Kaehler For writing External Segments that can be read by other images: Any CompiledMethods that create blocks will be in the outPointers array (and not get written on the file) if the block is held outside of this segment. Puts such methods into the roots list, and creates the segment again."! !ImageSegment commentStamp: 'tk 4/20/1999 09:34' prior: 0! I represent a segment of Squeak address space. I am created from an array of root objects. After storing, my segment contains a binary encoding of every object accessible from my roots but not otherwise accessible from anywhere else in the system. Within my segment are indices into my table of outPointers. I may exist in several states... #activeCopy arrayOfRoots segment outPointers are all as created by the copyFromRoots: initialization message. Nothing else has changed about the Squeak system. #active Each of the original roots has been transmuted into an ImageSegmentRootStub that refers back to this image segment. The original objects in the segment will all be garbageCollected. #onFile The segment has been written out to a file and replaced by a file pointer. Only the array of outPointers remains in the image. (ImageSegment new copyFromRootsForExport: (Array with: Baz with: Baz class)) writeForExport: 'myFile.extSeg'. To read into another image: FileList, more..., fileIn. It will install classes automatically. If you need to see the roots Array, it is temporarily stored in (SmartRefStream scannedObject). #onFileWithSymbols The segment has been written out to a file, along with the text of all the symbols in the outPointers array, and replaced by a file pointer. This reduces the size of the outPointers array, and also allows the system to reclaim any symbols that are not referred to from elsewhere in the image. The specific format used is that of a literal array as follows: #(symbol1 symbol2 # symbol3 symbol4 'symbolWithSpaces' # symbol5). In this case, the original outPointers array was 8 long, but the compacted table of outPointers retains only two entries. These get inserted in place of the #'s in the array of symbols after it is read back in. Symbols with embedded spaces or other strange characters are written as strings, and converted back to symbols when read back in. The symbol # is never written out. NOTE: All IdentitySets or dictionaries must be rehashed when being read back from this format. The symbols are effectively internal. (No, not if read back into same image. If a different image, then use #imported. -tk) #imported The segment is on an external file or just read in from one. The segment and outPointers are meant to be read into a foreign image. (It is in SmartRefStream format.) In this form the segment can be read from a URL, and installed. A copy of the original array of root objects is constructed, with former outPointers bound to existing objects in the host system. (Any Class inside the segment MUST be in the arrayOfRoots. This is so its association can be inserted into Smalltalk. The class's metaclass must be in roots also. Methods that are in outPointers because blocks point at them, are found and added to the roots.) All IdentitySets and dictionaries are rehashed when being read back from exported segments.) #inactive In this state, the rootsArray is set, but the segment is invalid.! !ImageSegment reorganize! ('access' arrayOfRoots outPointers) ('read/write segment' copyFromRoots: copyFromRootsForExport: extract extractThenInstall install readFromFile rootsIncludingBlockMethods segmentCopy writeForExport: writeToFile: writeToFileWithSymbols:) ('primitives' loadSegmentFrom:outPointers: storeSegmentFor:into:outPointers:) ('testing' deepCopyTest: errorWrongState verify:matches:knowing: verifyCopy) ('fileIn/Out' comeFullyUpOnReload: declare: prepareToBeSaved rehashSets storeDataOn:) ('object fileIn' convertasosfs0:asosf0:) ! !ImageSegment methodsFor: 'read/write segment' stamp: 'tk 4/20/1999 09:26'! copyFromRoots: aRootArray | segmentWordArray outPointerArray segSize | aRootArray ifNil: [self errorWrongState]. arrayOfRoots _ aRootArray. segSize _ 50000. ["Guess a reasonable segment size" segmentWordArray _ WordArray new: segSize. outPointerArray _ Array new: segSize // 20. (self storeSegmentFor: arrayOfRoots into: segmentWordArray outPointers: outPointerArray) == nil] whileTrue: ["Double the segment size and try again" segmentWordArray _ outPointerArray _ nil. segSize _ segSize * 2]. segment _ segmentWordArray. outPointers _ outPointerArray. state _ #activeCopy. ! ! !ImageSegment methodsFor: 'read/write segment' stamp: 'tk 4/20/1999 09:25'! copyFromRootsForExport: aRootArray "Add to roots: Any methods pointed to from the outside by blocks." | newRoots | self copyFromRoots: aRootArray. "Include compiledMethods that spawned blocks" (newRoots _ self rootsIncludingBlockMethods) ifNotNil: [ self copyFromRootsForExport: newRoots]. ! ! !ImageSegment methodsFor: 'read/write segment' stamp: 'tk 4/20/1999 08:49'! rootsIncludingBlockMethods "Return a new roots array with more objects. (Caller should store into rootArray.) Any CompiledMethods that create blocks will be in outPointers if the block is held outside of this segment. Put such methods into the roots list. Then ask for the segment again." | extras myClasses gotIt | extras _ OrderedCollection new. myClasses _ OrderedCollection new. arrayOfRoots do: [:aRoot | aRoot class class == Metaclass ifTrue: [ myClasses add: aRoot]]. myClasses isEmpty ifTrue: [^ nil]. "no change" outPointers do: [:anOut | anOut class == CompiledMethod ifTrue: [ "specialized version of who" gotIt _ false. myClasses detect: [:class | class selectorsDo: [:sel | (class compiledMethodAt: sel) == anOut ifTrue: [extras add: anOut. gotIt _ true]]. gotIt] ifNone: [] ]]. extras isEmpty ifTrue: [^ nil]. "no change" ^ arrayOfRoots, extras! !