VM Maker: VMMaker.oscog-eem.731.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

VM Maker: VMMaker.oscog-eem.731.mcz

commits-2
 
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.731.mcz

==================== Summary ====================

Name: VMMaker.oscog-eem.731
Author: eem
Time: 21 May 2014, 3:44:59.389 pm
UUID: e19b7342-8c8a-4ad8-8acd-64a6c1a7544d
Ancestors: VMMaker.oscog-eem.730

Spur:
Implement primitives to get (primitiveIsPinned) and (un)set
(primitivePin) per-object pinning.

=============== Diff against VMMaker.oscog-eem.730 ===============

Item was added:
+ ----- Method: InterpreterPrimitives>>primitiveIsPinned (in category 'memory space primitives') -----
+ primitiveIsPinned
+ "Answer if the receiver is pinned, i.e. immobile."
+ | receiver |
+ receiver := self stackTop.
+ ((objectMemory isImmediate: receiver)
+ or: [objectMemory isForwarded: receiver]) ifTrue:
+ [^self primitiveFailFor: PrimErrBadReceiver].
+ self pop: argumentCount - 1.
+ self stackTopPut:
+ (objectMemory hasSpurMemoryManagerAPI
+ ifTrue: [objectMemory booleanObjectOf: (objectMemory isPinned: receiver)]
+ ifFalse: [objectMemory falseObject])!

Item was added:
+ ----- Method: InterpreterPrimitives>>primitivePin (in category 'memory space primitives') -----
+ primitivePin
+ "Pin or unpin the receiver, i.e. make it immobile or mobile.  Answer whether the object was
+ already pinned. N.B. pinning does *not* prevent an object from being garbage collected."
+ | receiver boolean wasPinned failure |
+ objectMemory hasSpurMemoryManagerAPI ifFalse:
+ [^self primitiveFailFor: PrimErrUnsupported].
+
+ receiver := self stackValue: 1.
+ ((objectMemory isImmediate: receiver)
+ or: [(objectMemory isForwarded: receiver)
+ or: [(objectMemory isContext: receiver)
+ and: [self isStillMarriedContext: receiver]]]) ifTrue:
+ [^self primitiveFailFor: PrimErrBadReceiver].
+ boolean := self stackTop.
+ (boolean = objectMemory falseObject
+ or: [boolean = objectMemory trueObject]) ifFalse:
+ [^self primitiveFailFor: PrimErrBadArgument].
+
+ (objectMemory isPinned: receiver)
+ ifTrue:
+ [wasPinned := objectMemory trueObject.
+ objectMemory setIsPinnedOf: receiver to: false]
+ ifFalse:
+ [wasPinned := objectMemory falseObject.
+ failure := objectMemory pinObject: receiver.
+ failure ~= 0 ifTrue:
+ [^self primitiveFailFor: failure]].
+
+ self pop: argumentCount - 1 thenPush: wasPinned!

Item was added:
+ ----- Method: Spur32BitMemoryManager>>allocateSlotsForPinningInOldSpace:bytes:format:classIndex: (in category 'allocation') -----
+ allocateSlotsForPinningInOldSpace: numSlots bytes: totalBytes format: formatField classIndex: classIndex
+ "Answer the oop of a chunk of space in oldSpace with numSlots slots.  Try and
+ allocate in a segment that already includes pinned objects.  The header of the
+ result will have been filled-in but not the contents."
+ <inline: false>
+ | chunk |
+ chunk := self allocateOldSpaceChunkOfBytes: totalBytes
+   suchThat: [:f| (segmentManager segmentContainingObj: f) containsPinned].
+ chunk ifNil:
+ [chunk := self allocateOldSpaceChunkOfBytes: totalBytes.
+ chunk ifNotNil:
+ [(segmentManager segmentContainingObj: chunk) containsPinned: true]].
+ self checkFreeSpace.
+ chunk ifNil:
+ [^nil].
+ numSlots >= self numSlotsMask ifTrue: "for header parsing we put a saturated slot count in the prepended overflow size word"
+ [self flag: #endianness.
+ self longAt: chunk put: numSlots.
+ self longAt: chunk + 4 put: self numSlotsMask << self numSlotsHalfShift.
+ self long64At: chunk + self baseHeaderSize
+ put: (self headerForSlots: self numSlotsMask format: formatField classIndex: classIndex).
+ ^chunk + self baseHeaderSize].
+ self long64At: chunk put: (self headerForSlots: numSlots format: formatField classIndex: classIndex).
+ ^chunk!

Item was added:
+ ----- Method: Spur64BitMemoryManager>>allocateSlotsForPinningInOldSpace:bytes:format:classIndex: (in category 'allocation') -----
+ allocateSlotsForPinningInOldSpace: numSlots bytes: totalBytes format: formatField classIndex: classIndex
+ "Answer the oop of a chunk of space in oldSpace with numSlots slots.  Try and
+ allocate in a segment that already includes pinned objects.  The header of the
+ result will have been filled-in but not the contents."
+ <inline: false>
+ | chunk |
+ chunk := self allocateOldSpaceChunkOfBytes: totalBytes
+   suchThat: [:f| (segmentManager segmentContainingObj: f) containsPinned].
+ chunk ifNil:
+ [chunk := self allocateOldSpaceChunkOfBytes: totalBytes].
+ self checkFreeSpace.
+ chunk ifNil:
+ [^nil].
+ numSlots >= self numSlotsMask ifTrue: "for header parsing we put a saturated slot count in the prepended overflow size word"
+ [self longAt: chunk
+ put: numSlots + (self numSlotsMask << self numSlotsFullShift).
+ self longAt: chunk + self baseHeaderSize
+ put: (self headerForSlots: self numSlotsMask format: formatField classIndex: classIndex).
+ ^chunk + self baseHeaderSize].
+ self longAt: chunk
+ put: (self headerForSlots: numSlots format: formatField classIndex: classIndex).
+ ^chunk!

Item was added:
+ ----- Method: SpurMemoryManager>>allocateOldSpaceChunkOfBytes:suchThat: (in category 'free space') -----
+ allocateOldSpaceChunkOfBytes: chunkBytes suchThat: acceptanceBlock
+ "Answer a chunk of oldSpace from the free lists that satisfies acceptanceBlock,
+ if available, otherwise answer nil.  Break up a larger chunk if one of the exact
+ size cannot be found.  N.B.  the chunk is simply a pointer, it has no valid header.
+ The caller *must* fill in the header correctly."
+ | initialIndex node next prev index child childBytes acceptedChunk acceptedNode |
+ <inline: true> "must inline for acceptanceBlock"
+ self assert: (lastSubdividedFreeChunk := 0) = 0.
+ "for debugging:" "totalFreeOldSpace := self totalFreeListBytes"
+ totalFreeOldSpace := totalFreeOldSpace - chunkBytes. "be optimistic (& don't wait for the write)"
+ initialIndex := chunkBytes / self allocationUnit.
+ (initialIndex < self numFreeLists and: [1 << initialIndex <= freeListsMask]) ifTrue:
+ [(freeListsMask anyMask: 1 << initialIndex) ifTrue:
+ [(node := freeLists at: initialIndex) = 0
+ ifTrue: [freeListsMask := freeListsMask - (1 << initialIndex)]
+ ifFalse:
+ [prev := 0.
+ [node ~= 0] whileTrue:
+ [self assert: node = (self startOfObject: node).
+ self assert: (self isValidFreeObject: node).
+ next := self fetchPointer: self freeChunkNextIndex ofFreeChunk: node.
+ (acceptanceBlock value: node) ifTrue:
+ [prev = 0
+ ifTrue: [freeLists at: initialIndex put: next]
+ ifFalse: [self storePointer: self freeChunkNextIndex ofFreeChunk: prev withValue: next].
+ ^node].
+ prev := node.
+ node := next]]].
+ "first search for free chunks of a multiple of chunkBytes in size"
+ index := initialIndex.
+ [(index := index + initialIndex) < self numFreeLists
+  and: [1 << index <= freeListsMask]] whileTrue:
+ [(freeListsMask anyMask: 1 << index) ifTrue:
+ [(node := freeLists at: index) = 0
+ ifTrue: [freeListsMask := freeListsMask - (1 << index)]
+ ifFalse:
+ [prev := 0.
+ [node ~= 0] whileTrue:
+ [self assert: node = (self startOfObject: node).
+ self assert: (self isValidFreeObject: node).
+ next := self fetchPointer: self freeChunkNextIndex ofFreeChunk: node.
+ (acceptanceBlock value: node) ifTrue:
+ [prev = 0
+ ifTrue: [freeLists at: index put: next]
+ ifFalse: [self storePointer: self freeChunkNextIndex ofFreeChunk: prev withValue: next].
+ self freeChunkWithBytes: index * self allocationUnit - chunkBytes
+ at: (self startOfObject: node) + chunkBytes.
+ ^node].
+ prev := node.
+ node := next]]]].
+ "now get desperate and use the first that'll fit.
+  Note that because the minimum free size is 16 bytes (2 * allocationUnit), to
+  leave room for the forwarding pointer/next free link, we can only break chunks
+  that are at least 16 bytes larger, hence start at initialIndex + 2."
+ index := initialIndex + 1.
+ [(index := index + 1) < self numFreeLists
+  and: [1 << index <= freeListsMask]] whileTrue:
+ [(freeListsMask anyMask: 1 << index) ifTrue:
+ [(node := freeLists at: index) = 0
+ ifTrue: [freeListsMask := freeListsMask - (1 << index)]
+ ifFalse:
+ [prev := 0.
+ [node ~= 0] whileTrue:
+ [self assert: node = (self startOfObject: node).
+ self assert: (self isValidFreeObject: node).
+ next := self fetchPointer: self freeChunkNextIndex ofFreeChunk: node.
+ (acceptanceBlock value: node) ifTrue:
+ [prev = 0
+ ifTrue: [freeLists at: index put: next]
+ ifFalse: [self storePointer: self freeChunkNextIndex ofFreeChunk: prev withValue: next].
+ self freeChunkWithBytes: index * self allocationUnit - chunkBytes
+ at: (self startOfObject: node) + chunkBytes.
+ ^node].
+ prev := node.
+ node := next]]]]].
+
+ "Large chunk, or no space on small free lists.  Search the large chunk list.
+ Large chunk list organized as a tree, each node of which is a list of chunks
+ of the same size. Beneath the node are smaller and larger blocks.
+ When the search ends parent should hold the smallest chunk at least as
+ large as chunkBytes, or 0 if none.  acceptedChunk and acceptedNode save
+ us from having to back-up when the acceptanceBlock filters-out all nodes
+ of the right size, but there are nodes of the wrong size it does accept."
+ child := freeLists at: 0.
+ node := acceptedChunk := acceptedNode := 0.
+ [child ~= 0] whileTrue:
+ [self assert: (self isValidFreeObject: child).
+ childBytes := self bytesInObject: child.
+ childBytes = chunkBytes ifTrue: "size match; try to remove from list at node."
+ [node := child.
+ [prev := node.
+  node := self fetchPointer: self freeChunkNextIndex ofFreeChunk: node.
+  node ~= 0] whileTrue:
+ [(acceptanceBlock value: node) ifTrue:
+ [self assert: (self isValidFreeObject: node).
+ self storePointer: self freeChunkNextIndex
+ ofFreeChunk: prev
+ withValue: (self fetchPointer: self freeChunkNextIndex ofFreeChunk: node).
+ ^self startOfObject: node]].
+ (acceptanceBlock value: child) ifTrue:
+ [next := self fetchPointer: self freeChunkNextIndex ofFreeChunk: child.
+ next = 0
+ ifTrue: "no list; remove the interior node"
+ [self unlinkSolitaryFreeTreeNode: child]
+ ifFalse: "list; replace node with it"
+ [self inFreeTreeReplace: child with: next].
+ ^self startOfObject: child]].
+ child ~= 0 ifTrue:
+ ["Note that because the minimum free size is 16 bytes (2 * allocationUnit), to
+  leave room for the forwarding pointer/next free link, we can only break chunks
+  that are at least 16 bytes larger, hence reject chunks < 2 * allocationUnit larger."
+ childBytes <= (chunkBytes + self allocationUnit)
+ ifTrue: "node too small; walk down the larger size of the tree"
+ [child := self fetchPointer: self freeChunkLargerIndex ofFreeChunk: child]
+ ifFalse:
+ [self flag: 'we can do better here; preferentially choosing the lowest node. That would be a form of best-fit since we are trying to compact down'.
+ node := child.
+ child := self fetchPointer: self freeChunkSmallerIndex ofFreeChunk: node.
+ acceptedNode = 0 ifTrue:
+ [acceptedChunk := node.
+ "first search the list."
+ [acceptedChunk := self fetchPointer: self freeChunkNextIndex
+ ofFreeChunk: acceptedChunk.
+  (acceptedChunk ~= 0 and: [acceptanceBlock value: acceptedChunk]) ifTrue:
+ [acceptedNode := node].
+  acceptedChunk ~= 0 and: [acceptedNode = 0]] whileTrue.
+ "nothing on the list; will the node do?  This prefers
+  acceptable nodes higher up the tree over acceptable
+  list elements further down, but we haven't got all day..."
+ (acceptedNode = 0
+  and: [acceptanceBlock value: node]) ifTrue:
+ [acceptedNode := node.
+ child := 0 "break out of loop now we have an acceptedNode"]]]]].
+
+ acceptedNode ~= 0 ifTrue:
+ [acceptedChunk ~= 0 ifTrue:
+ [self assert: (self bytesInObject: acceptedChunk) >= (chunkBytes + self allocationUnit).
+ [next := self fetchPointer: self freeChunkNextIndex ofFreeChunk: acceptedNode.
+  next ~= acceptedChunk] whileTrue:
+ [acceptedNode := next].
+ self storePointer: self freeChunkNextIndex
+ ofFreeChunk: acceptedNode
+ withValue: (self fetchPointer: self freeChunkNextIndex ofFreeChunk: acceptedChunk).
+ self freeChunkWithBytes: (self bytesInObject: acceptedChunk) - chunkBytes
+ at: (self startOfObject: acceptedChunk) + chunkBytes.
+ ^self startOfObject: acceptedChunk].
+ next := self fetchPointer: self freeChunkNextIndex ofFreeChunk: acceptedNode.
+ next = 0
+ ifTrue: "no list; remove the interior node"
+ [self unlinkSolitaryFreeTreeNode: acceptedNode]
+ ifFalse: "list; replace node with it"
+ [self inFreeTreeReplace: acceptedNode with: next].
+ self assert: (self bytesInObject: acceptedNode) >= (chunkBytes + self allocationUnit).
+ self freeChunkWithBytes: (self bytesInObject: acceptedNode) - chunkBytes
+ at: (self startOfObject: acceptedNode) + chunkBytes.
+ ^self startOfObject: acceptedNode].
+
+ totalFreeOldSpace := totalFreeOldSpace + chunkBytes. "optimism was unfounded"
+ ^nil!

Item was added:
+ ----- Method: SpurMemoryManager>>cloneInOldSpaceForPinning: (in category 'allocation') -----
+ cloneInOldSpaceForPinning: objOop
+ | numSlots newObj |
+ numSlots := self numSlotsOf: objOop.
+
+ newObj := self allocateSlotsForPinningInOldSpace: numSlots
+ bytes: (self objectBytesForSlots: numSlots)
+ format: (self formatOf: objOop)
+ classIndex: (self classIndexOf: objOop).
+ (self isPointersNonImm: objOop)
+ ifTrue:
+ [| hasYoung |
+ hasYoung := false.
+ 0 to: numSlots - 1 do:
+ [:i| | oop |
+ oop := self fetchPointer: i ofObject: objOop.
+ ((self isNonImmediate: oop)
+ and: [self isForwarded: oop]) ifTrue:
+ [oop := self followForwarded: oop].
+ ((self isNonImmediate: oop)
+ and: [self isYoungObject: oop]) ifTrue:
+ [hasYoung := true].
+ self storePointerUnchecked: i
+ ofObject: newObj
+ withValue: oop].
+ (hasYoung
+ and: [(self isYoungObject: newObj) not]) ifTrue:
+ [scavenger remember: newObj.
+ self setIsRememberedOf: newObj to: true]]
+ ifFalse:
+ [0 to: numSlots - 1 do:
+ [:i|
+ self storePointerUnchecked: i
+ ofObject: newObj
+ withValue: (self fetchPointer: i ofObject: objOop)]].
+ ^newObj!

Item was changed:
  ----- Method: SpurMemoryManager>>pinObject: (in category 'primitive support') -----
  pinObject: objOop
+ | oldClone seg |
+ <var: #seg type: #'SpurSegmentInfo *'>
+ self assert: (self isNonImmediate: objOop).
+ self flag: 'policy decision here. if already old, do we clone in a segment containing pinned objects or merely pin?'.
+ "We choose to clone to keep pinned objects together to reduce fragmentation,
+ assuming that pinning is rare and that fragmentation is a bad thing."
+ (self isOldObject: objOop) ifTrue:
+ [seg := segmentManager segmentContainingObj: objOop.
+ seg containsPinned ifTrue:
+ [self setIsPinnedOf: objOop to: true.
+ ^0].
+ segmentManager someSegmentContainsPinned ifFalse:
+ [self setIsPinnedOf: objOop to: true.
+ seg containsPinned: true.
+ ^0]].
+ oldClone := self cloneInOldSpaceForPinning: objOop.
+ oldClone = 0 ifTrue:
+ [^PrimErrNoMemory].
+ self setIsPinnedOf: oldClone to: true.
+ self forward: objOop to: oldClone.
+ ^0!
- "Pin objOop in memory.  If objOop is in oldSpace merely set its isPinned
- bit.  If objOop is in newSpace then created a pinned copy in oldSpace
- and forward objOop to the pinned copy.  Answer the (possibly changed)
- oop of the pinned object."
- <api>
- self shouldBeImplemented!

Item was added:
+ ----- Method: SpurSegmentManager>>someSegmentContainsPinned (in category 'pinning') -----
+ someSegmentContainsPinned
+ 0 to: numSegments - 1 do:
+ [:i| (segments at: i) containsPinned ifTrue: [^true]].
+ ^false!

Item was changed:
  ----- Method: StackInterpreter class>>initializePrimitiveTable (in category 'initialization') -----
(excessive size, no diff calculated)