Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.607.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.607
Author: eem
Time: 4 February 2014, 3:40:08.328 pm
UUID: 9be0d8dc-ed68-4f51-becb-f83ed96185bf
Ancestors: VMMaker.oscog-eem.606
Following forwarders in Spur markAndTrace: requires a store check.
=============== Diff against VMMaker.oscog-eem.606 ===============
Item was changed:
----- Method: SpurMemoryManager>>markAndTrace: (in category 'gc - global') -----
markAndTrace: objOop
"Mark the argument, and all objects reachable from it, and any remaining objects
on the mark stack. Follow forwarding pointers in the scan."
<api>
| objToScan numStrongSlots index field |
(self markAndShouldScan: objOop) ifFalse:
[^self].
"if markAndTrace: is to follow and eliminate forwarding pointers
in its scan it cannot be handed an r-value which is forwarded."
self assert: (self isForwarded: objOop) not.
"Now scan the object, and any remaining objects on the mark stack."
objToScan := objOop.
"To avoid overflowing the mark stack when we encounter large objects, we
push the obj, then its numStrongSlots, and then index the object from the stack."
[((self isImmediate: objToScan)
or: [numStrongSlots := self numStrongSlotsOf: objToScan ephemeronInactiveIf: #inactiveOrFailedToDeferScan:.
numStrongSlots > self traceImmediatelySlotLimit])
ifTrue: "scanning a large object. scan until hitting an unmarked object, then switch to it, if any."
[(self isImmediate: objToScan)
ifTrue:
[index := self integerValueOf: objToScan.
objToScan := self topOfObjStack: markStack]
ifFalse:
[index := numStrongSlots.
self markAndTraceClassOf: objToScan].
[index > 0] whileTrue:
[index := index - 1.
field := self fetchPointer: index ofObject: objToScan.
(self isOopForwarded: field) ifTrue:
[field := self followForwarded: field.
+ self storePointer: index ofObject: objToScan withValue: field].
- self storePointerUnchecked: index ofObject: objToScan withValue: field].
(self markAndShouldScan: field) ifTrue:
[index > 0 ifTrue:
[(self topOfObjStack: markStack) ~= objToScan ifTrue:
[self push: objToScan onObjStack: markStack].
self push: (self integerObjectOf: index) onObjStack: markStack].
objToScan := field.
index := -1]].
index >= 0 ifTrue: "if loop terminated without finding an unmarked referent, switch to top of stack."
[objToScan := self popObjStack: markStack.
objToScan = objOop ifTrue:
[objToScan := self popObjStack: markStack]]]
ifFalse: "scanning a small object. scan, marking, pushing unmarked referents, then switch to the top of the stack."
[index := numStrongSlots.
self markAndTraceClassOf: objToScan.
[index > 0] whileTrue:
[index := index - 1.
field := self fetchPointer: index ofObject: objToScan.
(self isOopForwarded: field) ifTrue:
[field := self followForwarded: field.
+ self storePointer: index ofObject: objToScan withValue: field].
- self storePointerUnchecked: index ofObject: objToScan withValue: field].
(self markAndShouldScan: field) ifTrue:
[self push: field onObjStack: markStack.
numStrongSlots := self numStrongSlotsOf: field ephemeronInactiveIf: #inactiveOrFailedToDeferScan:.
numStrongSlots > self traceImmediatelySlotLimit ifTrue:
[self push: (self integerObjectOf: numStrongSlots) onObjStack: markStack]]].
objToScan := self popObjStack: markStack].
objToScan notNil] whileTrue!
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.605.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.605
Author: eem
Time: 4 February 2014, 10:32:47.2 am
UUID: 8ccb5e9c-1a6e-455f-8a97-1c30cca3ea1a
Ancestors: VMMaker.oscog-eem.604
Confine primitiveTestShortenIndexableSize to a TestingPrimitives ghetto.
=============== Diff against VMMaker.oscog-eem.604 ===============
Item was changed:
----- Method: InterpreterPrimitives>>primitiveTestShortenIndexableSize (in category 'object access primitives') -----
primitiveTestShortenIndexableSize
"Given an object with indexable pointer fields, reduce the size of the indexable fields
to the requested size. Answer the number of bytes freed, or zero if the object cannot
be shortened."
+ <option: #TestingPrimitives>
-
<export: true>
| array newSize bytesFreed |
newSize := self stackIntegerValue: 0.
array := self stackValue: 1.
self pop: argumentCount + 1.
bytesFreed := self shorten: array toIndexableSize: newSize.
self pushInteger: bytesFreed!
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.604.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.604
Author: eem
Time: 4 February 2014, 10:24:54.015 am
UUID: 3dedfc9d-e8c2-47ea-bb78-5dde624ade77
Ancestors: VMMaker.oscog-eem.603
Rewrite allocateLargestFreeChunk to skirt Slang limitation.
=============== Diff against VMMaker.oscog-eem.603 ===============
Item was changed:
----- Method: SpurMemoryManager>>allocateLargestFreeChunk (in category 'free space') -----
allocateLargestFreeChunk
"Answer the largest free chunk in the free lists."
+ | freeChunk next |
+ "would like to use ifNotNil: but the ^next inside the ^blah ifNotNil: confused Slang"
+ freeChunk := self findLargestFreeChunk.
+ freeChunk ifNil: [^nil].
+ "This will be the node, not a list element. Answer a list element in preference."
+ next := self fetchPointer: self freeChunkNextIndex ofFreeChunk: freeChunk.
+ next ~= 0 ifTrue:
+ [self storePointer: self freeChunkNextIndex
+ ofFreeChunk: freeChunk
+ withValue: (self fetchPointer: self freeChunkNextIndex ofFreeChunk: next).
+ ^next].
+ self unlinkSolitaryFreeTreeNode: freeChunk.
+ ^freeChunk!
- ^self findLargestFreeChunk ifNotNil:
- [:freeChunk| | next |
- "This will be the node, not a list element. Answer a list element in preference."
- next := self fetchPointer: self freeChunkNextIndex ofFreeChunk: freeChunk.
- next ~= 0 ifTrue:
- [self storePointer: self freeChunkNextIndex
- ofFreeChunk: freeChunk
- withValue: (self fetchPointer: self freeChunkNextIndex ofFreeChunk: next).
- ^next].
- self unlinkSolitaryFreeTreeNode: freeChunk.
- freeChunk]!
Hi Eliot,
This is the primitiveAllObjects update. I made significant changes in shorten:toIndexableSize:
after having discovered a number of interesting new ways to crash the VM, so you will want
to review those changes. There is also a primitiveTestShortenIndexableSize that exists
solely for the purpose of exercising shorten:toIndexableSize: from the image. This should
probably not be a permanent addition to the VM.
I built a Cog VM with these changes, and it seems to be fine. That said, most of my
testing was done on an interpreter VM and there are some difference in the NewObjectMemory
shorten:toIndexableSize: method, so please do check it.
I used the attached Foo.st for testing, you may find that useful also.
Dave
On Sun, Feb 02, 2014 at 07:51:41PM +0000, commits(a)source.squeak.org wrote:
>
> David T. Lewis uploaded a new version of VMMaker to project VM Maker:
> http://source.squeak.org/VMMaker/VMMaker.oscog-dtl.601.mcz
>
> ==================== Summary ====================
>
> Name: VMMaker.oscog-dtl.601
> Author: dtl
> Time: 2 February 2014, 2:50:58.398 pm
> UUID: 0074410d-1695-4af5-82f4-c74b52a35a9e
> Ancestors: VMMaker.oscog-eem.600
>
> Fix NewObjectMemory>>shorten:toIndexableSize: for large arrays (3 word header) and make it work for variable objects with fixed fields. Change return value to be number of bytes freed, to permit sender to check for success.
>
> Fix method comment in ObjectMemory>>lengthOf:baseHeader:format:
>
> Add primitiveAllObjects.
>
> Add primitiveTestShortenIndexableSize for testing shorten:toIndexableSize: from the image.
>
> Adapted from VMMaker-dtl.339.mcz
>
David T. Lewis uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-dtl.601.mcz
==================== Summary ====================
Name: VMMaker.oscog-dtl.601
Author: dtl
Time: 2 February 2014, 2:50:58.398 pm
UUID: 0074410d-1695-4af5-82f4-c74b52a35a9e
Ancestors: VMMaker.oscog-eem.600
Fix NewObjectMemory>>shorten:toIndexableSize: for large arrays (3 word header) and make it work for variable objects with fixed fields. Change return value to be number of bytes freed, to permit sender to check for success.
Fix method comment in ObjectMemory>>lengthOf:baseHeader:format:
Add primitiveAllObjects.
Add primitiveTestShortenIndexableSize for testing shorten:toIndexableSize: from the image.
Adapted from VMMaker-dtl.339.mcz
=============== Diff against VMMaker.oscog-eem.600 ===============
Item was added:
+ ----- Method: InterpreterPrimitives>>primitiveAllObjects (in category 'object access primitives') -----
+ primitiveAllObjects
+ "Answer an array of all objects that exist when the primitive is called, excluding those
+ that may be garbage collected as a side effect of allocating the result array. The array
+ will contain at least one trailing integer zero that serves as a marker for end of valid
+ object references. Additional trailing zeros represent objects that were garbage
+ collected during execution of this primitive. Sender is responsible for ignoring all
+ trailing zero marker objects in the result array."
+
+ <export: true>
+ | count obj resultArray newCount |
+ self pop: argumentCount+1.
+ "Count the currently accessible objects"
+ count := 0.
+ obj := objectMemory firstAccessibleObject.
+ [obj = nil] whileFalse:
+ [count := count + 1.
+ obj := objectMemory accessibleObjectAfter: obj].
+ "Allocate result array, may cause GC"
+ resultArray := objectMemory instantiateClass: objectMemory classArray indexableSize: count.
+ resultArray = nil ifTrue:
+ [^self primitiveFailFor: PrimErrNoMemory].
+ "Store all objects in result array, excluding any reference to the result array
+ itself, as may happen if garbage collection occurred during allocation of the array."
+ newCount := 0.
+ obj := objectMemory firstAccessibleObject.
+ [obj = nil or: [newCount >= count]] whileFalse:
+ [obj == resultArray
+ ifFalse: [newCount := newCount + 1.
+ self stObject: resultArray at: newCount put: obj ].
+ obj := objectMemory accessibleObjectAfter: obj].
+ "If GC occurred during result array allocation, truncate unused portion of result array"
+ newCount < count
+ ifTrue: [self shorten: resultArray toIndexableSize: newCount].
+ self push: resultArray!
Item was added:
+ ----- Method: InterpreterPrimitives>>primitiveTestShortenIndexableSize (in category 'object access primitives') -----
+ primitiveTestShortenIndexableSize
+ "Given an object with indexable pointer fields, reduce the size of the indexable fields
+ to the requested size. Answer the number of bytes freed, or zero if the object cannot
+ be shortened."
+
+ <export: true>
+ | array newSize bytesFreed |
+ newSize := self stackIntegerValue: 0.
+ array := self stackValue: 1.
+ self pop: argumentCount + 1.
+ bytesFreed := self shorten: array toIndexableSize: newSize.
+ self pushInteger: bytesFreed!
Item was changed:
----- Method: NewObjectMemory>>shorten:toIndexableSize: (in category 'allocation') -----
shorten: obj toIndexableSize: nSlots
+ "Reduce the number if indexable fields in obj, a pointer object, to nSlots. Convert the
+ unused residual to a free chunk. Word and byte indexable objects are not changed.
+ Answer the number of bytes returned to free memory, which may be zero if no change
+ was possible."
+ | deltaBytes desiredLength fixedFields fmt hdr totalLength
+ indexableFields |
+ (self isPointersNonImm: obj) ifFalse: [^0].
+ nSlots > 0
+ ifFalse: [^0]. "no change if nSlots is zero, error if nSlots is negative"
- "Currently this works for pointer objects only, and is almost certainly wrong for 64 bits."
- | deltaBytes desiredLength fixedFields fmt hdr totalLength |
- (self isPointersNonImm: obj) ifFalse:
- [^obj].
hdr := self baseHeader: obj.
fmt := self formatOfHeader: hdr.
totalLength := self lengthOf: obj baseHeader: hdr format: fmt.
fixedFields := self fixedFieldsOf: obj format: fmt length: totalLength.
+ indexableFields := totalLength - fixedFields.
+ nSlots >= indexableFields
+ ifTrue: [^0]. "no change, or error if attempting to increase size into next chunk"
+ desiredLength := fixedFields + nSlots.
- desiredLength := fixedFields + nSlots.
deltaBytes := (totalLength - desiredLength) * BytesPerWord.
obj + BaseHeaderSize + (totalLength * BytesPerWord) = freeStart
ifTrue: "Shortening the last object. Need to reduce freeStart."
[self maybeFillWithAllocationCheckFillerFrom: obj + BaseHeaderSize + (desiredLength * BytesPerWord) to: freeStart.
freeStart := obj + BaseHeaderSize + (desiredLength * BytesPerWord)]
ifFalse: "Shortening some interior object. Need to create a free block."
[self setSizeOfFree: obj + BaseHeaderSize + (desiredLength * BytesPerWord)
to: deltaBytes].
(self headerType: obj) caseOf: {
[HeaderTypeSizeAndClass] ->
+ [self longAt: (obj - (BaseHeaderSize * 2)) put: (self sizeHeader: obj) - deltaBytes].
- [self longAt: obj put: hdr - deltaBytes].
[HeaderTypeClass] ->
[self longAt: obj put: ((hdr bitClear: SizeMask) bitOr: (hdr bitAnd: SizeMask) - deltaBytes)].
[HeaderTypeShort] ->
[self longAt: obj put: ((hdr bitClear: SizeMask) bitOr: (hdr bitAnd: SizeMask) - deltaBytes)] }.
+ ^deltaBytes!
- ^obj!
Item was changed:
----- Method: ObjectMemory>>lengthOf:baseHeader:format: (in category 'indexing primitive support') -----
lengthOf: oop baseHeader: hdr format: fmt
+ "Return the number of fixed and indexable bytes, words, or object pointers in the
+ given object. Assume the given oop is not an integer. For a CompiledMethod, the size
+ of the method header (in bytes) should be subtracted from the result of this method."
- "Return the number of indexable bytes or words in the given object. Assume the given oop is not an integer. For a CompiledMethod, the size of the method header (in bytes) should be subtracted from the result of this method."
| sz |
<inline: true>
<asmLabel: false>
(hdr bitAnd: TypeMask) = HeaderTypeSizeAndClass
ifTrue: [ sz := (self sizeHeader: oop) bitAnd: LongSizeMask ]
ifFalse: [ sz := (hdr bitAnd: SizeMask)].
sz := sz - (hdr bitAnd: Size4Bit).
fmt <= self lastPointerFormat
ifTrue: [ ^ (sz - BaseHeaderSize) >> ShiftForWord "words"].
^fmt < self firstByteFormat
ifTrue: [(sz - BaseHeaderSize) >> 2 "32-bit longs"]
ifFalse: [(sz - BaseHeaderSize) - (fmt bitAnd: 3) "bytes"]!
Item was changed:
----- Method: ObjectMemory>>shorten:toIndexableSize: (in category 'allocation') -----
shorten: obj toIndexableSize: nSlots
+ "Reduce the number if indexable fields in obj, a pointer object, to nSlots. Convert the
+ unused residual to a free chunk. Word and byte indexable objects are not changed.
+ Answer the number of bytes returned to free memory, which may be zero if no change
+ was possible."
+ | deltaBytes desiredLength fixedFields fmt hdr totalLength
+ indexableFields |
+ (self isPointersNonImm: obj) ifFalse: [^0].
+ nSlots > 0
+ ifFalse: [^0]. "no change if nSlots is zero, error if nSlots is negative"
- "Currently this works for pointer objects only, and is almost certainly wrong for 64 bits."
- | deltaBytes desiredLength fixedFields fmt hdr totalLength |
- (self isPointersNonImm: obj) ifFalse:
- [^obj].
hdr := self baseHeader: obj.
fmt := self formatOfHeader: hdr.
totalLength := self lengthOf: obj baseHeader: hdr format: fmt.
fixedFields := self fixedFieldsOf: obj format: fmt length: totalLength.
+ indexableFields := totalLength - fixedFields.
+ nSlots >= indexableFields
+ ifTrue: [^0]. "no change, or error if attempting to increase size into next chunk"
+ desiredLength := fixedFields + nSlots.
- desiredLength := fixedFields + nSlots.
deltaBytes := (totalLength - desiredLength) * BytesPerWord.
self setSizeOfFree: obj + BaseHeaderSize + (desiredLength * BytesPerWord)
to: deltaBytes.
(self headerType: obj) caseOf: {
[HeaderTypeSizeAndClass] ->
+ [self longAt: (obj - (BaseHeaderSize * 2)) put: (self sizeHeader: obj) - deltaBytes].
- [self longAt: obj put: hdr - deltaBytes].
[HeaderTypeClass] ->
[self longAt: obj put: ((hdr bitClear: SizeMask) bitOr: (hdr bitAnd: SizeMask) - deltaBytes)].
[HeaderTypeShort] ->
[self longAt: obj put: ((hdr bitClear: SizeMask) bitOr: (hdr bitAnd: SizeMask) - deltaBytes)] }.
+ ^deltaBytes!
- ^obj!
>> Not necessarily. There should be a SimulatorMorph that holds onto the simulator itself and embeds the image morph. That could present a nice UI, and could either handle events itself, or register event handlers with the image morph. If you need UI ideas I suggest you try my >>SqueakJS morph (which essintially is also a VM simulator): http://lively-web.org/users/bert/squeak.html It's a shame we never bothered to make the simulator this nice ;)
>>
>+1
agreed
>It would be great if someone were to take inspiration from Bert's SqueakJS
>morph and do something similar for the traditional VM simulators.
>Personally, it's inspiring me to want to learn about JS some day soon. That
>lively VM is seriously impressive.
+2
>Dave
Bert's work is inspiring and a very impressive.
After mulling on it yesterday and poking around a bit, I decided Bert's Morphic approach is the way to go for now.
My reasoning is that I saw no easy way of filtering out mouse-move events from other mouse events (most mouse move events happen outside the scope of the simulator)
and mouse coordinate translation is needed with the Semaphore approach.
Please bear in mind that my stated goal is to port the StackInterpreterSimulator /StackInterpreter to native 64 bits and then to 64x64 (native 64 running a 64 bit image).
That exercise is the foundation of upping my programming chops so that I can break out of the UI/Web/DB application programmer rut I am in.
>From there, Eliot needs help porting Cog to 64 native.
I do not want to detour from that goal too much except to correct learning deficiencies and to help with some fixes to plugins.
That said, I do have a free day or two so I will try to stub what Bert has in place visually with the idea of bringing in the functionality as I learn it.
I REALLY like that step functionality, and the view of the MethodContext.
Also, I do not understand how debuggers work, and looking at what Bert has, it looks like a lot of debugger techniques are used; That in itself is a very useful exercise.
>Tim R. wrote:
>A useful UI for the simulator would allow pushing in events that are *not* those going on in the outer world; some way to send in a variety of keyboard/button events would help with making sure that the event handling can cope with variations not provided by your host. For >example, some platforms send a triple of keydown/keystroke/keyup for each keyboard press. Some do it quite differently. Or say one is trying to develop handling for a new event that isn’t actually provided by any VM yet (OS_TeaTime_Alert, for example) and you want to make >sure it can work.
>At the very least it might lead to some decent documentation of WTF goes on down there.
Tim. I have this noted in my working notes. Since events are just CArrayAccessors, the structure is fixed and I do think a pop-up that allows you to set and send an event that is fed to the interpreter is doable.
cordially,
tty.