CompiledMethod>>value:withArguments:

Ian Piumarta Ian.Piumarta at inria.fr
Tue Dec 28 18:26:59 UTC 1999


> Method wrappers are an extremely useful technique to gather all
> kinds of run-time information, to implement wrappers, ...
[...]
> It seems to me that Squeak is missing in reflective facilities in message
> handling.

Sounds to me like a challenge.  ;^)

> For that matter, so are most Smalltalk VM's.

Ahh, but the beauty of Smalltalk is the possibility of reifying and
interceding on all execution state: if it's missing then you just go
implement it, whatever "it" might be.  (And if it doesn't run blindingly
fast afterwards then consider it a bug in the VM's runtime. ;-)

> > Don't you think we could solve this by doing something along the lines of:
> > CompiledMethod>>valueWithReceiver: aClass Arguments: argList
> >  | aProcess aContext |
> >  aContext _ MethodContext
> >     sender: thisContext sender
> >     receiver: aClass
> >     method: self
> >     arguments: argList.
> >  aProcess _ Process forContext: aContext priority: Processor activePriority.
> >  aProcess resume

Process?  Isn't this a bit like swatting a fly with a steam roller?

Methinks the problem is a little more subtle.  For starters, a minimum of
verification for compatibility between the CompiledMethod and the given
receiver/arguments is required.  (We've come a long way since "Processor :=
nil" for cruel and unusual ways in which to crash the VM. ;-).  Try the
following instead...

Behavior methodsFor: 'testing method dictionary'

  includesMethod: aCompiledMethod
	"Answer whether aCompiledMethod is in the method dictionary of
	the receiver."

	^self methodDict includes: aCompiledMethod

  canExecute: method 
	"Answer whether the receiver implements a message whose method 
	is the argument. The method can be in the method dictionary of the 
	receiver or any of its superclasses."

	(self includesMethod: method) ifTrue: [^true].
	superclass == nil ifTrue: [^false].
	^superclass canExecute: method

CompiledMethod methodsFor: 'evaluating'

  valueWithReceiver: anObject arguments: argumentArray
	"Answer the result of executing the receiver with anObject as
	receiver and argumentArray as arguments.  Signal an error if the
	receiver is not a method suitable for anObject, or if the
	argumentArray contains the wrong number of arguments for the
	receiver."

	(self numArgs == argumentArray size and: [anObject class canExecute: self])
		ifTrue:
			[thisContext swapSender: (MethodContext
				sender: thisContext sender
				receiver: anObject
				method: self
				arguments: argumentArray)]
		ifFalse:
			[self error: 'receiver and/or arguments not appropriate for this method']

Examples:

	(SmallInteger compiledMethodAt: #+) valueWithReceiver: 3 arguments: #(4).
	(Number compiledMethodAt: #//) valueWithReceiver: 22 arguments: #(7).
	(SmallInteger compiledMethodAt: #+) valueWithReceiver: 3 arguments: #(foo).
	(Number compiledMethodAt: #negated) valueWithReceiver: 22 arguments: #().
	(Number compiledMethodAt: #negated) valueWithReceiver: 22 arguments: #(7).
	(Point compiledMethodAt: #=) valueWithReceiver: 3 at 4 arguments: #(4).
	(Point compiledMethodAt: #=) valueWithReceiver: 3 arguments: (Array with: 3 at 4).


And finally (for the incurably skeptical):

	(CompiledMethod compiledMethodAt: #valueWithReceiver:arguments:)
		valueWithReceiver: (SmallInteger compiledMethodAt: #+)
		arguments: #(3 (4))

FWIW: The only part of the above implementation that isn't blindingly fast
is the inclusion test for the method somewhere in or above anObject class.
(The corresponding primitive [twenty lines of code, tops] could do the test
iteratively, and would be about the same speed as #perform:.  Left as an
exercise for anybody who still has a mains electricity supply after midnight
on the 31st...)

Happy wrapping!

Ian

PS: > In VW this is a primitive
    I suspect that the primitive response in VW is nothing more than a
    "hook" that the runtime uses to recompile the send site into something
    entirely more intelligent that (ab)uses the inline cache and/or method
    prologue for #valWithRcvr:args: to make the response as fast as a normal
    message send.  (Otherwise the [slower] 100%-Smalltalk implementation is
    entirely sufficient.)





More information about the Squeak-dev mailing list