[Vm-dev] Making a Slower VM

Eliot Miranda eliot.miranda at gmail.com
Tue Feb 11 19:16:02 UTC 2014


On Tue, Feb 11, 2014 at 11:05 AM, David T. Lewis <lewis at mail.msen.com>wrote:

>
> OK thank you, I am aware of that trick so not a problem.
>
> (But you should not blame Eliot, I think I started abusing slang that way
> in OSProcessPlugin many years ago, so you can blame me just as well)
>

Personally I fin it far less of an abuse than the horrible cCode:
'aString...' idiom.  With "self malloc: n" I can look for senders etc, but
more importantly I can actually implement it in the simulator.  You'll see
in the Cog branch working implementations of str:n:cmp: mem:mo:ve: etc
which are actually required by the simulator.  Let me plead for those of
you writing VM code to avoid cCode: as much as possible.  Use it to include
code that only the simulator should use by all means, but please try and
generate your C calls from Smalltalk code.

Here's the kind of thing I mean.  This coerces an address into a
simulator's CogMethod:

printCogMethod: cogMethod
<api>
<var: #cogMethod type: #'CogMethod *'>
| address primitive |
self cCode: ''
inSmalltalk:
[self transcript ensureCr.
 cogMethod isInteger ifTrue:
[^self printCogMethod: (self cCoerceSimple: cogMethod to: #'CogMethod *')]].
address := cogMethod asInteger.
self printHex: address;
print: ' <-> ';
printHex: address + cogMethod blockSize.
cogMethod cmType = CMMethod ifTrue:
...

Here's the kind of thing to be avoided:

interpreterProxy success:
((interpreterProxy isBytes: oop)
 and: [(interpreterProxy slotSizeOf: oop) = (self cCode:
'sizeof(AsyncFile)')]).

It could be written as (and if so, simulated!!)

interpreterProxy success:
((interpreterProxy isBytes: oop)
 and: [(interpreterProxy slotSizeOf: oop) = (self sizeof: #AsyncFile)]).

cheers!


Thanks a lot,
> Dave
>
> >  Hi David,
> > I wanted to say that COG depends on (self malloc: n) to be translated
> > malloc(n); and not setMalloc(n); for example (you can have many others by
> > browsing unimplemented calls), but maybe foo was not a generic ID in your
> > case?
> >
> >
> > 2014-02-11 15:05 GMT+01:00 David T. Lewis <lewis at mail.msen.com>:
> >
> >>
> >> On Mon, Feb 10, 2014 at 10:12:32PM +0100, Nicolas Cellier wrote:
> >> >
> >> > Hi David,
> >> > do you realize that Eliot is (ab)using this in COG in order to
> >> eliminate
> >> > some direct cCode: '...' inclusion?
> >> > So setFoo: is not an option (or i misunderstood something)
> >> >
> >>
> >> Hi Nicolas,
> >>
> >> Actually I am not sure what you are referring to here, so probably I am
> >> missing something. Can you explain why setFoo: would be a problem in
> >> Cog?
> >> I cannot check it myself right now but I am interested to know if I am
> >> missing something important.
> >>
> >> Thanks,
> >> Dave
> >>
> >>
> >> >
> >> > 2014-02-10 21:51 GMT+01:00 David T. Lewis <lewis at mail.msen.com>:
> >> >
> >> > >
> >> > > I was looking at the trunk VMM yesterday and found that most of the
> >> issues
> >> > > were just caused by accessor methods, where #foo and #foo: generate
> >> > > conflicting foo(void) and foo(aParameter). In most cases, a
> >> convention
> >> of
> >> > > #setFoo: rather than #foo: takes care of the problem. There were a
> >> few
> >> > > other miscellaneous issues as well, but nothing that looked serious.
> >> > >
> >> > > The variable 'memory' is a challenge because it is used extensively
> >> both
> >> > > directly and through #memory and #memory:. I was considering
> >> changing
> >> the
> >> > > variable name to something like memoryBase, and leaving the
> >> accessors
> >> > > alone though I'm not sure that would be a very good idea.
> >> > >
> >> > > I ran out of time yesterday and did not pursue it beyond this.
> >> > >
> >> > > Dave
> >> > >
> >> > > >
> >> > > >
> >> > > > On 10-02-2014, at 11:53 AM, Eliot Miranda
> >> <eliot.miranda at gmail.com>
> >> > > wrote:
> >> > > >>
> >> > > >> I *think* the issue is the internal/external split brought abut
> >> by
> >> the
> >> > > >> introduction of the localFoo variables, such as localSP and
> >> localIP.
> >> > > >
> >> > > > It's really hard to be sure but I suspect that this isn't the
> >> (only)
> >> > > > issue. IIRC we used to be able to make non-inlined VMs at one
> >> point
> >> and
> >> > > > that was well after the internalFoo code was added.
> >> > > >
> >> > > > OK, some quick email searching reveals some work done in '03 by
> >> johnMcI,
> >> > > > Craig & me.
> >> > > > Craig found the following code helped -
> >> > > >
> >> > > > !'From Squeak3.6alpha of ''17 March 2003'' [latest update: #5325]
> >> on
> >> 21
> >> > > > July 2003 at 1:11:25 pm'!
> >> > > >
> >> > > > !Interpreter methodsFor: 'contexts' stamp: 'crl 7/19/2003 15:59'!
> >> > > > primitiveFindNextUnwindContext
> >> > > >       "Primitive. Search up the context stack for the next method
> >> context
> >> > > > marked for unwind handling from the receiver up to but not
> >> including
> >> the
> >> > > > argument. Return nil if none found."
> >> > > >       | thisCntx nilOop aContext isUnwindMarked header meth pIndex
> >> |
> >> > > >       aContext _ self popStack.
> >> > > >       thisCntx _ self fetchPointer: SenderIndex ofObject: self
> >> popStack.
> >> > > >       nilOop _ nilObj.
> >> > > >
> >> > > >       [(thisCntx = aContext) or: [thisCntx = nilOop]] whileFalse:
> >> [
> >> > > >
> >> > > >       header _ self baseHeader: aContext.
> >> > > >
> >> > > >       (self isMethodContextHeader: header)
> >> > > >               ifTrue: [
> >> > > >                       meth _ self fetchPointer: MethodIndex
> >> ofObject:
> >> > > aContext.
> >> > > >                       pIndex _ self primitiveIndexOf: meth.
> >> > > >                       isUnwindMarked _ pIndex == 198]
> >> > > >               ifFalse: [isUnwindMarked _ false].
> >> > > >               isUnwindMarked ifTrue:[
> >> > > >                       self push: thisCntx.
> >> > > >                       ^nil].
> >> > > >               thisCntx _ self fetchPointer: SenderIndex ofObject:
> >> > > thisCntx].
> >> > > >
> >> > > >       ^self push: nilOop! !
> >> > > >
> >> > > > !Interpreter methodsFor: 'interpreter shell' stamp: 'crl 7/19/2003
> >> > > 15:33'!
> >> > > > interpret
> >> > > >       "This is the main interpreter loop. It normally loops
> >> forever,
> >> > > fetching
> >> > > > and executing bytecodes. When running in the context of a browser
> >> plugin
> >> > > > VM, however, it must return control to the browser periodically.
> >> This
> >> > > > should done only when the state of the currently running Squeak
> >> thread is
> >> > > > safely stored in the object heap. Since this is the case at the
> >> moment
> >> > > > that a check for interrupts is performed, that is when we return
> >> to
> >> the
> >> > > > browser if it is time to do so. Interrupt checks happen quite
> >> > > > frequently."
> >> > > >
> >> > > >       "record entry time when running as a browser plug-in"
> >> > > >       "self browserPluginInitialiseIfNeeded"
> >> > > >       self internalizeIPandSP.
> >> > > >       self fetchNextBytecode.
> >> > > >       [true] whileTrue: [self dispatchOn: currentBytecode in:
> >> > > BytecodeTable].
> >> > > >       localIP _ localIP - 1.  "undo the pre-increment of IP before
> >> > > returning"
> >> > > >       self externalizeIPandSP.
> >> > > > ! !
> >> > > >
> >> > > > !Interpreter methodsFor: 'return bytecodes' stamp: 'crl 7/19/2003
> >> 16:05'!
> >> > > > returnValueTo
> >> > > >       "Note: Assumed to be inlined into the dispatch loop."
> >> > > >
> >> > > >       | nilOop thisCntx contextOfCaller localCntx localVal
> >> isUnwindMarked
> >> > > > header meth pIndex |
> >> > > >       self inline: true.
> >> > > >       self sharedCodeNamed: 'commonReturn' inCase: 120.
> >> > > >
> >> > > >       nilOop _ nilObj. "keep in a register"
> >> > > >       thisCntx _ activeContext.
> >> > > >       localCntx _ cntx.
> >> > > >       localVal _ val.
> >> > > >
> >> > > >       "make sure we can return to the given context"
> >> > > >       ((localCntx = nilOop) or:
> >> > > >        [(self fetchPointer: InstructionPointerIndex ofObject:
> >> localCntx)
> >> > > =
> >> > > > nilOop]) ifTrue: [
> >> > > >               "error: sender's instruction pointer or context is
> >> nil;
> >> > > cannot return"
> >> > > >               ^self internalCannotReturn: localVal].
> >> > > >
> >> > > >       "If this return is not to our immediate predecessor (i.e.
> >> from
> >> a
> >> > > method
> >> > > > to its sender, or from a block to its caller), scan the stack for
> >> the
> >> > > > first unwind marked context and inform this context and let it
> >> deal
> >> with
> >> > > > it. This provides a chance for ensure unwinding to occur."
> >> > > >       thisCntx _ self fetchPointer: SenderIndex ofObject:
> >> activeContext.
> >> > > >
> >> > > >       "Just possibly a faster test would be to compare the
> >> homeContext
> >> > > and
> >> > > > activeContext - they are of course different for blocks. Thus we
> >> might be
> >> > > > able to optimise a touch by having a different returnTo for the
> >> > > > blockreteurn (since we know that must return to caller) and then
> >> if
> >> > > > active ~= home we must be doing a non-local return. I think.
> >> Maybe."
> >> > > >       [thisCntx = localCntx] whileFalse: [
> >> > > >               thisCntx = nilObj ifTrue:[
> >> > > >                       "error: sender's instruction pointer or
> >> context is
> >> > > nil; cannot return"
> >> > > >                       ^self internalCannotReturn: localVal].
> >> > > >               "Climb up stack towards localCntx. Break out to a
> >> send
> >> of
> >> > > > #aboutToReturn:through: if an unwind marked context is found"
> >> > > >       header _ self baseHeader: thisCntx.
> >> > > >
> >> > > >       (self isMethodContextHeader: header)
> >> > > >               ifTrue: [
> >> > > >                       meth _ self fetchPointer: MethodIndex
> >> ofObject:
> >> > > thisCntx.
> >> > > >                       pIndex _ self primitiveIndexOf: meth.
> >> > > >                       isUnwindMarked _ pIndex == 198]
> >> > > >               ifFalse: [isUnwindMarked _ false].
> >> > > >
> >> > > >               isUnwindMarked ifTrue:[
> >> > > >                       "context is marked; break out"
> >> > > >                       ^self internalAboutToReturn: localVal
> >> through:
> >> > > thisCntx].
> >> > > >               thisCntx _ self fetchPointer: SenderIndex ofObject:
> >> > > thisCntx.
> >> > > > ].
> >> > > >
> >> > > >       "If we get here there is no unwind to worry about. Simply
> >> > > terminate the
> >> > > > stack up to the localCntx - often just the sender of the method"
> >> > > >       thisCntx _ activeContext.
> >> > > >       [thisCntx = localCntx]
> >> > > >               whileFalse:
> >> > > >               ["climb up stack to localCntx"
> >> > > >               contextOfCaller _ self fetchPointer: SenderIndex
> >> ofObject:
> >> > > thisCntx.
> >> > > >
> >> > > >               "zap exited contexts so any future attempted use
> >> will
> >> be
> >> > > caught"
> >> > > >               self storePointerUnchecked: SenderIndex ofObject:
> >> thisCntx
> >> > > withValue:
> >> > > > nilOop.
> >> > > >               self storePointerUnchecked: InstructionPointerIndex
> >> > > ofObject: thisCntx
> >> > > > withValue: nilOop.
> >> > > >               reclaimableContextCount > 0 ifTrue:
> >> > > >                       ["try to recycle this context"
> >> > > >                       reclaimableContextCount _
> >> reclaimableContextCount
> >> > > - 1.
> >> > > >                       self recycleContextIfPossible: thisCntx].
> >> > > >               thisCntx _ contextOfCaller].
> >> > > >
> >> > > >       activeContext _ thisCntx.
> >> > > >       (thisCntx < youngStart) ifTrue: [ self beRootIfOld: thisCntx
> >> ].
> >> > > >
> >> > > >       self internalFetchContextRegisters: thisCntx.  "updates
> >> local
> >> IP
> >> > > and SP"
> >> > > >       self fetchNextBytecode.
> >> > > >       self internalPush: localVal.
> >> > > > ! !
> >> > > >
> >> > > > Shortly after that I released the VMMaker3.6 with a note that it
> >> couldn't
> >> > > > produce a completely non-inlined VM because of a problem in
> >> fetchByte if
> >> > > > globalstruct was enabled, and some odd problems in B2DPlugin. When
> >> > > > VMMaker3.7 was released a year late (march 04) I apparently
> >> thought
> >> it
> >> > > > could make the core vm non-inlined. Since this is all a bazillion
> >> years
> >> > > > ago I can't remember any context to help extend the history.
> >> > > >
> >> > > > tim
> >> > > > --
> >> > > > tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim
> >> > > > Science is imagination equipped with grappling hooks.
> >> > > >
> >> > >
> >> > >
> >> > >
> >>
> >>
> >
>
>
>


-- 
best,
Eliot
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20140211/efbf0f1b/attachment-0001.htm


More information about the Vm-dev mailing list