.. erm.. why sending #class? Is this for possible overrides of #class method?
VM is rigid thing and its safer to have #class return same oop as if
VM does this primitively, otherwise its hard to imagine the number of
errors, which could be result of such override.
Not a big deal IMO.
A well written code should not use non-local values too often,
otherwise its not well-written code :)
And using a message sends instead of compiler early binding is much
more valuable than performance IMO.
As i heard, an early binding is nothing more than optimization and not
a part of smalltalk's design specs.
Btw, the speed loss could be reduced by implementing a dictionary
lookup with primitive, replacing #scanFor: method and leaving only
send #hash to searched object at language side.
> Another aspect is co-existence with existing Squeak classes and
> methods (=> what we want to accomplish with Moebius): a system which
> uses the above is running in its own namespace and module, and the
> SmallWorld example compiler does *not* emit code which can access a
> (Smalltalk at :#Smalltalk) variable.
>
> Instead things must be declared in a module then they can be used by
> +from entities in the module. A nice example is
>
> myDeclarer "usually a class like Object"
> compiledMethodAt: #Processor
> put: (nil environment associationAt: #Processor)
>
> I use the latter in the running SmallWorld example for avoiding name
> clashes etc. SmallWorld has its own Class, Object, Parser, Collection,
> Magnitude, etc with the same name symbols but other provenance as
> those that exist in Squeak.
>
> --------------
>
> I hope the above has something useful for declaring and accessing non-
> local slots in Moebius and for co-existence with Squeak?
>
Well..
Is it a SmallWorld's design decision to keep pool vars in class dictionaries?
I find sending #bindingOf: is more clean, logical and less
complicated/intrusive (consider browser which expects only methods
returned by #methodDict message).
I really don't like abusing things which was designed for different purpose(s).
> Cheers,
> Klaus
>
> >
>
--
Best regards,
Igor Stasenko AKA sig.
> 2008/8/18 Klaus D. Witzel :
>>
>> For the SmallWorld tranformation from primordial soup (a running
>> example in another email thread) it was to decide where and how to
>> declare and access non-local slots. As is often the case one arrives
>> at a solution which Self has for this case: message sends :)
...
>> In the Squeak VM at method lookup time when it finds that (thing
>> isCompiledMethod not) then the VM does:
>>
>> thing run: originalSelector with: arguments in: originalReceiver
>>
>> and the implementor of #run:with:in: gets the original receiver and
>> variable name (=> originalSelector) and can now do what it's pleased.
>>
>> The simplest case is that #run:with:in: just returns (self) and can be
>> implemented by Squeak's Object class. This is the getter case, for
>> which the SmallWorld compiler emits
>>
>> o push: self
>> o send: #class
>
> .. erm.. why sending #class?
Just did that for illustration, using existing Smalltalk things for
communication. Moebius might change that, NP.
> Is this for possible overrides of #class method?
A-b-s-o-l-u-t-e-l-y not ;)
> VM is rigid thing and its safer to have #class return same oop as if
> VM does this primitively, otherwise its hard to imagine the number of
> errors, which could be result of such override.
This remark makes me a bit concerned that we're not talking about
something similiar. Example
igorMethod
"answer the value of a non-local variable (slot)"
^ self class SlotName
and the above bytecodes equiv this source method representation, Okay?
>> o send: #symbol (variable name) with *no* argument
...
>> It is important to note that in the SqueakVM, slot-name-as-selector
>> sends are *not* subject of method caching (but all the other shown
>> methods are), therefore the above is not soo fast for performance
>> sensitive application with bytecode instruction set.
>>
>
> Not a big deal IMO.
:)
> A well written code should not use non-local values too often,
> otherwise its not well-written code :)
> And using a message sends instead of compiler early binding is much
> more valuable than performance IMO.
And all jitted and/or partly compiled VMs/CREs compare sort of equal at
this level :) Only Smalltalk with its (Association key: slotName value:
slotValue) is an exception here, because of VM's immediate bytecode
support.
> As i heard, an early binding is nothing more than optimization and not
> a part of smalltalk's design specs.
:) anything special you could point me to (a paper or an article so), for
my collection of Things Done Right?
> Btw, the speed loss could be reduced by implementing a dictionary
> lookup with primitive, replacing #scanFor: method and leaving only
> send #hash to searched object at language side.
Good point, thank you.
...
>> --------------
>>
>> I hope the above has something useful for declaring and accessing non-
>> local slots in Moebius and for co-existence with Squeak?
>>
>
> Well..
>
> Is it a SmallWorld's design decision to keep pool vars in class
> dictionaries?
No, not separate class dictionaries (possibly misunderstood?), it's
instead in the method dictionary of the declaring class.
> I find sending #bindingOf: is more clean, logical and less
> complicated/intrusive (consider browser which expects only methods
> returned by #methodDict message).
Especially when does browser send #bindingOf: or access method dictionary
directly? I'd love to know every single occurence, since that would incur
*much* more work for me :(
No; browsers do filter, at their indirect accessing level, the method
dictionary through the class' organization object. And this is good so :)
But furtunately I know of no tools which do any #binding or direct method
access -- all they do is use what's implemented from ClassDecription
protocol downwards to more special subclasses of ClassDecription
(exceptions are stupid things like #traitsComposition: in Behavior etc,
but that are exceptions).
Will still need to check what SystemNavigation helpers want from
CompiledMethods (like messages, senders, etc), some of them like
#whichSelectorsReferTo:* miss the #isCompiledMethod check, but this has no
priority for me at the moment (noticed that #selectorsAndMethodsDo: seems
to the central point where check was forgotten by the VM gods).
Nevertheless, if #isCompiledMethod would not be retrofitted into helpers
then #run:with:in: would be great success for the VM maintainers :) only
hard work for nothing :(
Meanwhile I have collected three dozens of methods for the SmallWorld baby
classes (who themselves do not inherit anything from Behavior and its
subclasses, after #new #new #new ;) Many/most of these methods are related
to me wanting inspection and debugging and recompilation (all is done to
the strange-to-Squeak environment, with existing tools).
So far, Marcus' methods in Behavior are best, easy reusable for things
which don't inherit from big Behavior brother ;)
> I really don't like abusing things which was designed for different
> purpose(s).
-
http://www.google.com/search?q=ObjectsAsMethods+VM+site:lists.squeakfoundation.org
No, #run:with:in: was intentionally designed into the Squeak system and is
fully supported by the various VM's, don't worry ;)
>> Cheers,
>> Klaus
>>
>> >>
>>
>
>
>> I find sending #bindingOf: is more clean, logical and less
>> complicated/intrusive (consider browser which expects only methods
>> returned by #methodDict message).
>
> Especially when does browser send #bindingOf: or access method dictionary
> directly? I'd love to know every single occurence, since that would incur
> *much* more work for me :(
>
I think 'explain' command should show how browser get know if given
identifier is temp/inst/class/pool/global var.
I just can suspect that some usages of #compiledMethodAt: would not
expect having non-compiled method in return. And this is why i against
messing methods with pool vars.
Of course it is completely a design related problem. One could
implement class hierarchy, browser & compiler which aware that classes
using single dictionary for holding both methods and class vars.
In essence this can be seen as generalization, that each class having
own namespace (symbol->object). Or if look from Self's POV it is
nothing more than just a named slots of class object :)
> No; browsers do filter, at their indirect accessing level, the method
> dictionary through the class' organization object. And this is good so :)
>
Maybe so. I'm not very good with protocols which is correct for usage
to work with meta data such as methods & behavior.
Do not blame me for using the methods i find most convenient fro my
purposes in Behavior protocol for metaprogramming. :)
Yes yes. I'm aware of that. I'm just thinking that this is an overkill.
The #run:with:in: is sent with
run: oldSelector with: arguments in: aReceiver
^self perform: oldSelector withArguments: arguments
which means that VM need to allocate an array oop for arguments.
While if you make compiler intrinsic to generate #bindingOf:{put:}
send sequence - you don't have this overhead. And receiver gets all
required arguments in the same way, just with different selector :)
Btw, squeak's #bindingOf: returns an association for given symbol,
while in above - #bindingOf: / #bindingOf:put: - should retrieve or
store value instead.
Maybe its better to use #bindingAt:{put:} to avoid confusion.
------------
Some more thoughts about use of #run:with:in:
Since class vars could be used to hold any value, and Squeak VM
sending a #run:with:in: message to this object, you'll have a problem,
that you need to define #run:with:in: in Object class (or even in
ProtoObject) in SmallWorld's image and should prevent it from
overrides.
Its also makes very problematic to use #run:with:in: anywhere except
for non-local symbol lookup:
for example, you having a class var named CoolVar and put there an
object with overridden #run:with:in: then you may not have what you
expecting:
| obj |
CoolVar := nil. "initially is nil"
self assert: (CoolVar == nil). " do not fail, since
Object>>run:with:in: works well and returns self"
obj := ClassWithOverriddenRunWithIn new.
CoolVar := obj.
self assert: (CoolVar == obj). "will fail, if override does not returns self"
CoolVar := nil. "this one can fail as well, since
ClassWithOverriddenRunWithIn>>run:with:in can simply ignore extra
argument"
This leads to a problem that assignments may not always work as
assignments - a big source of errors and confusion.
That's why "I really don't like abusing things which was designed for
different purpose(s)" :)
P.S.
Btw, maybe i was not attentive reading your post, how you suppose to
deal with class vars use at class side?
It is certain that since class vars seen both at instance side and at
class side, they should have single place holder.
But then compiler should be aware that method compiled for class side,
to generate:
o push: self
o send: #symbol (variable name) with *no* argument
instead of
o push: self
o send #clas
o send: #symbol (variable name) with *no* argument
at instance side.
Or maybe you dealing with it at run-time in #run:with:in: method(s)?
> In the past many people wanted to override #class. E.g. for introducing
> proxies where #class returns
> the class of the proxied object, this can be very useful.
Interesting point. Perhaps some of them complained before it became clear
that regular compilers emits the special selector bytecode (no lookup) for
#class ;)
BTW and a bit OT: when transferring SmallWorld bytecode generation to
Squeak I found early steps of block closures, I first thought that was a
bug 8-)
But I took the idea and based copying of unshareable block temps on the
regular Squeak bytecode set, so no need for a VM patch nor message sends
nor allocation of thing(s) other than GOF BlockContext (and blocks have
again same method as home has). Decompiler must + can recognize this, too.
It looks so easy that I asked myself, why haven't people used that for
decade(s), cross-VM version + platform compatible (no crash with .images
from different un/-supporting VMs).
Could this find use in NewCompiler?
Cheers,
Klaus
> Marcus
>
>
> --
> Marcus Denker -- den...@iam.unibe.ch
> http://www.iam.unibe.ch/~denker
>
> Klaus wrote:
>> Interesting point. Perhaps some of them complained before it became
>> clear that regular compilers emits the special selector bytecode (no
>> lookup) for #class ;)
>>
>
> They complained and then changed the compiler to emit a message send for
> #class.
:)
>> BTW and a bit OT: when transferring SmallWorld bytecode generation to
>> Squeak I found early steps of block closures, I first thought that was
>> a bug 8-)
>>
> ?
The SmallWorld compiler pulls all temps/block args used, at block-scope
end compile-time, out of scope for any other block onwards-in-time. So it
doesn't reuse any slot for any other block again, regardless of level.
[this in contrast to Squeak compiler (since St80?) who make the same name
get the same slot, if level permits. So people attempt to make new
bytecodes for better closure support].
Now what SmallWorld compiler does not do is, to copy unshared values into
declarer scope of a nested block. This was easy to add when I saw that
little "sin".
>> But I took the idea and based copying of unshareable block temps on the
>> regular Squeak bytecode set, so no need for a VM patch nor message
>> sends nor allocation of thing(s) other than GOF BlockContext (and
>> blocks have again same method as home has). Decompiler must + can
>> recognize this, too.
>>
>> It looks so easy that I asked myself, why haven't people used that for
>> decade(s), cross-VM version + platform compatible (no crash with
>> .images from different un/-supporting VMs).
>>
>> Could this find use in NewCompiler?
>>
>
> Maybe, I can not really understand much from this short explanation, I
> have to admit.
Could go down to explainig what bytecodes used and when, but I will save
the subject for the next meeting with you (Camp Smalltalk over the
weekend, perhaps?).
First it must be decided whether a platform-neutral, .image version
neutral, and VM neutral solution is wanted and if there are other people
interested in maintaining things.
Today NewCompiler can generate VM-dependent bytecodes and/or alternatively
encode message sends for BlockClosure handling. My suggestion goes go into
the third direction, to not do both.
Cheers,
Klaus
No! I just saying that smalltalk design is different and intended to
hold only methods in method dictionaries.
Let me elaborate.
Object subclass: #SomeClass classVariableNames: 'CoolVar'.
SomeClass>>method1
CoolVar := nil.
self assert: (CoolVar == nil)
SomeClass>>setCoolVarWithInstanceOf: aClass
| obj |
obj := aClass new.
CoolVar := obj.
self assert: (CoolVar == obj)
---
Now suppose a test case:
myObj := SomeClass new.
myObj method1.
myObj setCoolVarWithInstanceOf: ClassWithOverriddenRunWithIn.
myObj method1.
now look what happens, if you using a #run:with:in: pattern:
- the receiver of #run:with:in: is the object held in value slot of
association (where VM expects a CompiledMethod instance). And behavior
of accessing the CoolVar depends on the current value object!
In contrary, if you using a #bindingOf: , then receiver of
#bindingOf: is a SomeClass - and behavior of accessing CoolVar always
depends only from SomeClass.
Next issue is difference between:
SomeClass>>coolVar
^ CoolVar
and:
SomeClass class>>coolVar
^ CoolVar
at instance-side, everything is OK:
compiler generates:
push self (SomeClass instance)
send class
send #CoolVar (receiver is SomeClass)
and VM will do lookup in SomeClass method dictionary.
but if you apply same operations to a class side, it will go wrong:
push self (SomeClass )
send class
send #CoolVar (SomeClass class -- its metaclass)
here VM will do lookup for #CoolVar method in metaclass methods
dictionary, not in a SomeClass method dictionary.
So, in first case, a receiver of #CoolVar is SomeClass class object,
and in second case , a receiver of #CoolVar is SomeClass metaclass object.
Here the problem - you looking for same symbol in different hierachies
of method dictionaries, unless you make compiler to not send #class in
a class-side methods.
Or you can deal with it at run time. But at run time , i think you
will need to handle DNU in one of the cases, otherwise you need to
have to keep (#CoolVar -> object) associations in both class and
metaclass dictionaries and synchronize them at assignment.
This would force increase in complexity of polymorphic send mechanism.
There must be a balance between the size of native code , inlined to
perform a send, and flexibility.
To avoid inlining too much code at polymorphic send site (causing
native methods become too big)
we need to put most of message send handling code in separate method(s).
Currently compiler calls a method which responsible for binding
message selector to method - and then simply calls returned method.
This means, that compiler assuming that returned value of #bind:
method is always an instance of CompiledMethod.
To handle method-as-arbitrary-object case, the bind method then should
check if result of lookup is not a method oop. And if not - then do
additional lookup and return #run:with:in: method which should be
called.
But it is easy to say than just do. The complication is that
#run:with:in: requiring different arguments than original message, so
before sending a message , it would require to make changes on stack
and move original arguments to array.
It is also interesting, how to determine if given oop is
CompiledMethod instance or not (remember , we can't send
#isCompiledMethod in the code responsible for polymorphic send -
otherwise we end up with a mess that to perform ANY polymorphic send
we need to do another polymorphic send :).
I think that its better to keep things simple - allow only
CompiledMethods (or subclasses) in method dicts, and provide other
means for redirecting/wrapping message sends.
Also, some languages, like Io allow to redefine activation action for a method.
It makes things very flexible, and horribly slow at the same time ,
because to make a simplest polymorphic send you must send #activate to
method oop, again, polymorphically :)
[snipped the rest, since we agreed ]
We can do something similar, i think. Instead of doing direct call of
method oop native code,
we could use the fixedMethodsTable to call #activate method for method oop.
So, a CompiledMethod will override an #activate method - to simply
call its entry point, while by default, for the rest of objects in
system, an #activate will result in sending #run:with:in: or something
similar.
So, a procedure of sending message to object could be changed to:
method := receiver callBind: selector numArgs: ... "does lookup &
returns a method to handle message"
result := method callActivateMethod "activates a method"
a callXXX are special natively inlined methods, which doing following:
receiver vtable fixedMethodsTable someFixedMethod call.
This makes things simple, error proof and w/o "idiotic" run-time
checking #isCompiledMethod - everything is defined through behavior.
One of the reasons why i prefer to work in team - to save me from own
stupidity and to share with knowledge and evaluate approaches before
wasting time implementing crappy stuff :)
> o obtain the method for a selector and things *)
> o jcc away when (your #callBind:) dictated so (mispredicton charged
> here)
> o activate the method by call (e.g. the CPU's %eip% return address)
> ....
> o away: return (pops things so stack is clear)
>
> *) or invoke things like, #primitiveAdd with precisely the same
> calling sequence but jcc just around its method activation when
> integer arithmethic was successful, etc, etc. always a triplet #(call
> jcc call).
>
>> a callXXX are special natively inlined methods, which doing following:
>>
>> receiver vtable fixedMethodsTable someFixedMethod call.
>>
>> This makes things simple, error proof and w/o "idiotic" run-time
>> checking #isCompiledMethod - everything is defined through behavior.
>
> great ! :) sending messages rules :)
yeah, with one exception, that you can't put a non-CompiledMethod oop
in fixedMethodsTable.
But i think we can live with such limitation :)