Smalltalk and ruby - 2012-12-08
-
Upload
koan-sin-tan -
Category
Technology
-
view
107 -
download
0
description
Transcript of Smalltalk and ruby - 2012-12-08
An Amateur Smalltalk User’s Observations on Ruby Object Model and Bytecode
“freedom” Koan-Sin Tanfreedom_at_computer.org
RubyConf Taiwan, Dec 8th, 2012
1
Friday, March 22, 13
Or say, learning Ruby, a stupid way
2
Friday, March 22, 13
Outline
• General introduction
• Smalltalk-80 and Ruby object models
• Smalltalk-80 and Ruby bytecode
3
Friday, March 22, 13
Who am I• Learnt to write program on MPF-II
• Used to be a programming language junkie
• Learnt a bit Smalltalk during early '90s, use it on and off
• Recent interest in ST-80 because of Scratch and BYOB/SNAP
• Working on dealing with big.LITTLE system
• Knew little about Ruby
4
Friday, March 22, 13
MPF-II• Multi-tech Micro-Professor
II, MPF-II
• A not so compatible Apple-][ clone
• 6502
• Basic similar to Apple SOFT
• Different monitor
• I got one of this in 1983
5
Friday, March 22, 13
the first smalltalk-80 I used is on Sun’s SunView, image from Wikipedia
6
Friday, March 22, 13
Smalltalk/V 286, from http://www.drdobbs.com/architecture-and-design/making-smalltalk-with-widgets/
1844085507
Friday, March 22, 13
Scratch and BYOB/SNAP visual programming
8
Friday, March 22, 13
ARM big.LITTLE9
Friday, March 22, 13
10
Friday, March 22, 13
What I knew about Ruby
• freebsd: portupgrade is written in ruby, http://wiki.freebsd.org/portupgrade
• RoR
• message passing
• temporary variable, block, block arguments
• However, a block in ruby is not an object!!
• And of course, ruby is more than smalltalk-80
11
Friday, March 22, 13
• Object-Oriented Programming
• OO GUI environment, IDE
• VM, bytecode
• Lambda, functional language, block
• Message passing
• Design Pattern:
• if you read GoF book, you ran into lots Smalltalk patterns before
• Learning/educational
• Logo and the dream of Dynabook
Smalltalk-80
12
Friday, March 22, 13
some smalltalk-80 systems
• Squeak: originally from Alan Kay and other veteran Smalltalk guys
• Pharo: a Squeak fork focusing on providing a clean and ready-‐to-‐use smalltalk environment
• VisualWorks: the ParcPlace system
• GNU Smalltalk
13
Friday, March 22, 13
Object Model
• Object Model can be used to refer to different things
• We just touch what a common language user is aware of, not something like the details of how objects are represented in VMs
• I believe you can get more about VM implementations from Sasada-San’s talk
14
Friday, March 22, 13
Smalltalk Object Model• From "purple book", Chap 16
1. Every class is ultimately a subclass of class Object, except for Object itself, which has no superclass. In particular, Class is a subclass of ClassDescription, which is a subclass of Behavior which is a subclass of Object
2. Every object is an instance of a class
3. Every class is an instance of a metaclass
4. All metaclasses are subclasses of Class
5. Every metaclass is an instance of Metaclass
6. The method of Class and it superclasses support the behavior common to all objects that are classes
7. The methods of instances of Metaclass add the behavior specific to particular classes
15
Friday, March 22, 13
Smalltalk Object Model
•10 factorial --> 3628800•10 factorial class --> SmallInteger•SmallInteger superclass --> Integer•Integer superclass --> Number•Number superclass --> Magnitude•Magnitude superclass --> Object•Object superclass -‐-‐> ProtoObject•ProtoObject superclass -‐-‐> nil
16Friday, March 22, 13
• 10 factorial class allSuperClasses --> an OrderedCollection(Integer Number Magnitude Object ProtoObject)
17
Friday, March 22, 13
• SmallInteger class --> SmallInteger class• Integer class --> Integer class• Number class --> Number class• Magnitude class --> Magnitude class• Object class --> Object class• ProtoObject class --> ProtoObject class
18Friday, March 22, 13
Object
Magnitude
Number
Object class
Magnitude class
Number class
Keyinstance-of
Integer class
SmallInteger SmallInteger class
10
Integer
ProtoObject ProtoObject class
figures modified from “Pharo by Example”
19Friday, March 22, 13
4. All metaclasses are subclasses of Class
5. Every metaclass is an instance of Metaclass
20
Friday, March 22, 13
SmallInteger class superclass --> Integer classInteger class superclass --> Number classumber class superclass --> Magnitude classMagnitude class superclass --> Object classObject class superclass --> ProtoObject classProtoObject class superclass --> Class
Class class class --> Metaclass
21Friday, March 22, 13
Object
Magnitude
Number
Object class
Magnitude class
Number class
Keyinstance-of
Integer class
SmallInteger SmallInteger class
10
Integer
ProtoObject ProtoObject class
Class
Class class
Metaclass
Metaclass class
22Friday, March 22, 13
6. The method of Class and it superclasses support the behavior common to all objects that are classes
7. The methods of instances of Metaclass add the behavior specific to particular classes
23
Friday, March 22, 13
Class class class --> MetaclassMetaclass superclass --> ClassDescription.ClassDescription superclass --> BehaviorBehavior superclass --> Object
Class class superclass --> ClassDescription classClassDescription class --> superclass Behavior classBehavior class superclass --> Object class
24Friday, March 22, 13
Object
Magnitude
Number
Object class
Magnitude class
Number class
Keyinstance-of
Integer classSmallInteger
SmallInteger class10
Integer
ProtoObject
ProtoObject class
Class
Class class
Metaclass
Metaclass class
ClassDescription
BehaviorClassDescription class
Behavior class
25Friday, March 22, 13
from “PBE”26
Friday, March 22, 13
• since I cannot find good Ruby tutorial/book similar to blue/purple book, let see check if we can use similar way to explore ruby
27
Friday, March 22, 13
Ruby Metaclass
• Singleton class, eigenclass
28
Friday, March 22, 13
from ‘ri Class’ of ruby 1.8 +------------------+
| |
Object---->(Object) |
^ ^ ^ ^ |
| | | | |
| | +-----+ +---------+ |
| | | | |
| +-----------+ | |
| | | | |
+------+ | Module--->(Module) |
| | ^ ^ |
OtherClass-->(OtherClass) | | |
| | |
Class---->(Class) |
^ |
| |
+----------------+29
Friday, March 22, 13
from ‘ri Class’ of ruby 1.9• All metaclasses are instances of the class `Class'.
+---------+ +-... | | |
BasicObject-----|-->(BasicObject)-------|-...
^ | ^ |
| | | |
Object---------|----->(Object)---------|-...
^ | ^ |
| | | |
+-------+ | +--------+ |
| | | | | |
| Module-|---------|--->(Module)-|-...
| ^ | | ^ |
| | | | | |
| Class-|---------|---->(Class)-|-...
| ^ | | ^ |
| +---+ | +----+
| |
obj--->OtherClass---------->(OtherClass)-----------...30
Friday, March 22, 13
Ruby Eigenclass hierarchynoway:work freedom$ ruby -v
ruby 1.8.7 (2012-02-08 patchlevel 358) [universal-darwin12.0]
noway:work freedom$ irb -v
irb 0.9.5(05/04/13)
noway:work freedom$ irb
>> 1.class
=> Fixnum
>> 1.class.class
=> Class
>> 1.class.class.superclass
=> Module
>> 1.class.class.superclass.superclass
=> Object
>> 1.class.class.superclass.superclass.superclass
=> nil
>>
freedom@freedom-desktop:~$ ruby -vruby 1.9.3p0 (2011-10-30 revision 33570) [arm-linux-eabi]
freedom@freedom-desktop:~$ irb -virb 0.9.6(09/06/30)freedom@freedom-desktop:~$ irbirb(main):001:0> 1.class=> Fixnumirb(main):002:0> 1.class.class=> Classirb(main):003:0> 1.class.class.superclass=> Moduleirb(main):004:0> 1.class.class.superclass.superclass=> Objectirb(main):005:0> 1.class.class.superclass.superclass.superclass
=> BasicObjectirb(main):006:0> 1.class.class.superclass.superclass.superclass.superclass
=> nilirb(main):007:0>
31
Friday, March 22, 13
>> 1.class.ancestors
=> [Fixnum, Integer, Precision, Numeric, Comparable, Object, Kernel]
32
Friday, March 22, 13
$ rbenv exec irb meta.rb
rb(main):001:0> 1.class.class
=> Class
irb(main):002:0> 1.class.class.ancestors
=> [Class, Module, Object, Kernel, BasicObject]
$rbenv exec irb meta.rb
meta.rb(main):001:0> class Object
meta.rb(main):002:1> def metaclass
meta.rb(main):003:2> class << self; self; end
meta.rb(main):004:2> end
meta.rb(main):005:1> end
=> nil
meta.rb(main):006:0>
meta.rb(main):007:0* 1.class.metaclass
=> #<Class:Fixnum>
eta.rb(main):008:0> 1.class.metaclass.superclass
=> #<Class:Integer>
meta.rb(main):009:0> 1.class.metaclass.ancestors
=> [Class, Module, Object, Kernel, BasicObject]
33
Friday, March 22, 13
meta.rb(main):009:0> 1.class.metaclass.ancestors
=> [Class, Module, Object, Kernel, BasicObject]
• hmm..., back to superclass
meta.rb(main):010:0> 1.class.metaclass.superclass.superclass
=> #<Class:Numeric>
meta.rb(main):011:0> 1.class.metaclass.superclass.superclass.superclass
=> #<Class:Object>
meta.rb(main):012:0> 1.class.metaclass.superclass.superclass.superclass.superclass
=> #<Class:BasicObject>
meta.rb(main):013:0> 1.class.metaclass.superclass.superclass.superclass.superclass.superclass
=> Class
34
Friday, March 22, 13
Object
BasicObject
super class
eigenclass #<Class:Object>
eigenclass
#<Class:BasicObject>
super class
Class
super class
instancemethods
methods
super class
BasicObject
super class
super class
String
super class
eigenclass #<Class:String>
super class
! != == __id__ __send__ equal? instance_eval instance_exec
!~ <=> === =~ class clone define_singleton_method display dup eigen_class
eigen_methods enum_for eql? extend freeze frozen? hash initialize_clone initialize_dup inspect
instance_of? instance_variable_defined? instance_variable_get instance_variable_set instance_variables is_a? kind_of? method methods nil? object_id private_methods
protected_methods public_method public_methods public_send respond_to?
respond_to_missing? send singleton_class singleton_methods taint tainted? tap to_enum to_s
trust untaint untrust untrusted?
instancemethods
instancemethods
< <= > >= ancestors autoload autoload? class_eval class_exec class_variable_defined?
class_variable_get class_variable_set class_variables const_defined? const_get
const_missing const_set constants include? included_modules instance_method
instance_methods method_defined? module_eval module_exec name private_class_method
private_constant private_instance_methods private_method_defined?
protected_instance_methods protected_method_defined? public_class_method
public_constant public_instance_method public_instance_methods public_method_defined?
remove_class_variable
instancemethods
allocate new superclass
instancemethods
instancemethods
methods
instancemethods
methods
try_convert
Ruby's Object Hierarchy 2
Thomas Schank © 2011 (CC BY-ND)
Module
ObjectKernel includedmodules
•So Ruby’s object hierarchy should be similar to this•http://drtom.schank.ch/posts/2011/12/11/Rubys_Object_Model_and_Eigenclasses/
35
Friday, March 22, 13
Bytecode
• Bytecode is not new at all
• Smalltalk is one of early bytecode users
• Smalltalk bytecode
• end of Chapter 26, http://www.mirandabanda.org/bluebook/bluebook_chapter26.html#TheBytecodes26
• Chap. 28, http://www.mirandabanda.org/bluebook/bluebook_chapter28.html
36
Friday, March 22, 13
Smalltalk bytecode categories• pushes
• indicates the source of an object to be added to the top of the interpreter's stack
• stores• indicates the variable whose value should be changed
• sends• specifies the selector of a message to be sent and how many
arguments it should have.• returns
• a value is returned for the message that invoked that CompiledMethod
• and jumps• you know what these are 37
Friday, March 22, 13
Smalltalk bytecodesRange Bits FuncQon0-‐15 0000iiii Push Receiver Variable #iiii16-‐31 0001iiii Push Temporary LocaQon #iiii32-‐63 001iiiii Push Literal Constant #iiiii64-‐95 010iiiii Push Literal Variable #iiiii96-‐103 01100iii Pop and Store Receiver Variable #iii104-‐111 01101iii Pop and Store Temporary LocaQon #iii112-‐119 01110iii Push (receiver, true, false, nil, -‐1, 0, 1, 2) [iii]120-‐123 011110ii Return (receiver, true, false, nil) [ii] From Message124-‐125 0111110i Return Stack Top From (Message, Block) [i]126-‐127 0111111i unused128 10000000 jjkkkkkk Push (Receiver Variable, Temporary LocaQon, Literal Constant, Literal Variable) [jj] #kkkkkk129 10000001 jjkkkkkk Store (Receiver Variable, Temporary LocaQon, Illegal, Literal Variable) [jj] #kkkkkk130 10000010 jjkkkkkk Pop and Store (Receiver Variable, Temporary LocaQon, Illegal, Literal Variable) [jj] #kkkkkk131 10000011 jjjkkkkk Send Literal Selector #kkkkk With jjj Arguments132 10000100 jjjjjjjj kkkkkkkk Send Literal Selector #kkkkkkkk With jjjjjjjj Arguments133 10000101 jjjkkkkk Send Literal Selector #kkkkk To Superclass With jjj Arguments134 10000110 jjjjjjjj kkkkkkkk Send Literal Selector #kkkkkkkk To Superclass With jjjjjjjj Arguments135 10000111 Pop Stack Top136 10001000 Duplicate Stack Top137 10001001 Push AcQve Context138-‐143 unused144-‐151 10010iii Jump iii + 1 (i.e., 1 through 8)152-‐159 10011iii Pop and Jump 0n False iii +1 (i.e., 1 through 8)160-‐167 10100iii jjjjjjjj Jump(iii -‐ 4) *256+jjjjjjjj168-‐171 101010ii jjjjjjjj Pop and Jump On True ii *256+jjjjjjjj172-‐175 101011ii jjjjjjjj Pop and Jump On False ii *256+jjjjjjjj176-‐191 1011iiii Send ArithmeQc Message #iiii192-‐207 1100iiii Send Special Message #iiii208-‐223 1101iiii Send Literal Selector #iiii With No Arguments224-‐239 1110iiii Send Literal Selector #iiii With 1 Argument240-‐255 1111iiii Send Literal Selector #iiii With 2 Arguments 38
Friday, March 22, 13
• An example method,forCompiledMethod "to show how CompiledMethod works" | foo | foo := 'test'. ^ 1 + 2
• Bytecode: in System Browser of Squeak/Pharo, we can see byteCode easily–17 <20> pushConstant: 'test'–18 <68> popIntoTemp: 0–19 <76> pushConstant: 1–20 <77> pushConstant: 2–21 <B0> send: +–22 <7C> returnTop
39Friday, March 22, 13
displaying smalltalk bytecode
• CompiledMethod
• Class>>compiledMethodAt
• (Integer compiledMethodAt: #factorial) symbolic
• (RubyConfTW compiledMethodAt: #forCompiledMethd) symbolic
• code here
40
Friday, March 22, 13
compiler
• Behavior>>compile
• compile:
compile: code
^self compile: code notifying: nil
• compile:notifying:
• compile:classified: notifying: requestor trailer: ifFail:
41
Friday, March 22, 13
a Simple Behavior>>compile example• RubyConfTW compile: 'foo^42'
• RubyConfTW will have a new method called foo and the code is to return the ultimate answer
• (RubyConfTW compiledMethodAt: #foo) symbolic
'17 <20> pushConstant: 42
18 <7C> returnTop’
42
Friday, March 22, 13
add a method
| myClass myInstance |
myClass := Behavior new. "create anon behavior"
myClass compile: 'theAnswer ^42'. "add a method for instances"
myInstance := myClass new. "create an instance"
Transcript show: myInstance theAnswer; cr. "shows 42"
43
Friday, March 22, 13
Ruby bytecode
• ruby 1.8o cannot find easy way to do this
• ruby 1.9 and 2.0o ruby.c:proc_opQons()
§ -‐-‐dump=insnso YARV InstrucQon tableo hmp://www.atdot.net/yarv/insnstbl.html, o source code, oro you can ask Sasada-‐san :-‐)
44Friday, March 22, 13
For a simple hello world> rbenv exec ruby --dump=insns ~/work/ruby/test.rb == disasm: <RubyVM::InstructionSequence:<main>@/Users/freedom/work/ruby/test.rb>0000 trace 1 ( 1)0002 putself 0003 putstring "hello, world\n"0005 send <callinfo!mid:print, argc:1, FCALL|ARGS_SKIP>0007 leave
45Friday, March 22, 13
Ruby KERNEL Module
• it took me some Qme to figure out what puts() and other kernel methods are
• puts == KERNEL.puts == $stdout.puts()?, == disasm: <RubyVM::InstructionSequence:<main>@test.rb>=================0000 trace 1 ( 1)0002 putself 0003 putstring "hello, world\n"0005 send <callinfo!mid:puts, argc:1, FCALL|ARGS_SKIP>0007 pop 0008 trace 1 ( 2)0010 getinlinecache 17, <ic:0>0013 getconstant :Kernel0015 setinlinecache <ic:0>0017 putstring "hello, world\n"0019 opt_send_simple <callinfo!mid:puts, argc:1, ARGS_SKIP>0021 pop 0022 trace 1 ( 3)0024 getglobal $stdout0026 putstring "hello, world"0028 opt_send_simple <callinfo!mid:puts, argc:1, ARGS_SKIP>0030 leave
46Friday, March 22, 13
CompiledMethod in Ruby
• RubyVM::InstructionSequence
• = Class methods:
• compile, compile_file, compile_option, compile_option=, disasm, disassemble, load, new
• = Instance methods:
• disasm, disassemble, eval, inspect, to_a
47
Friday, March 22, 13
CompiledMethod in Ruby
filename = ARGV[0]
code = RubyVM::InstructionSequence.compile_file filename
File.open "bytecode.dump", "w" do |file|
file << Marshal.dump(code.to_a)
end
print code.disasm
48
Friday, March 22, 13
Load saved instruction sequence
• there is no RubyVM::InstrucQonSequence.load, but there is iseq_s_load() in iseq.c
#if 0 /* TBD */ rb_define_method(rb_cISeq, "marshal_dump", iseq_marshal_dump, 0); rb_define_method(rb_cISeq, "marshal_load", iseq_marshal_load, 1);#endif
/* disable this feature because there is no verifier. */ /* rb_define_singleton_method(rb_cISeq, "load", iseq_s_load, -1); */ (void)iseq_s_load;
• So, my first reacQon is /* disable this feature because there is no verifier. */ rb_define_singleton_method(rb_cISeq, "load", iseq_s_load, -1); // (void)iseq_s_load;
• And I googled a bit, found that, it seems we can define an InstrucQonSequence.load method to use iseq_s_load()• hmp://bb10.com/ruby-‐core/2012-‐07/msg00303.html
49Friday, March 22, 13
Store and load• test.rb
puts “hello, world\n”
puts 1+2
• store-and-load.rb
filename = ARGV[0]
code = RubyVM::InstructionSequence.compile_file filename
File.open "bytecode.dump", "w" do |file|
file << Marshal.dump(code.to_a)
end
code = nil
File.open "bytecode.dump", "r" do |file|
code = RubyVM::InstructionSequence.load Marshal.restore(file.read)
end
print code.disasm
50
Friday, March 22, 13
test.rb./ruby --disable-gems ~/work/ruby/load.rb
== disasm: <RubyVM::InstructionSequence:<main>@/Users/freedom/work/ruby/test.rb>
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1] s1)
0000 trace 1
0002 putself
0003 putstring "hello, world\n"
0005 send <callinfo!mid:puts, argc:1, FCALL|ARGS_SKIP>
0007 pop
0008 trace 1
0010 putself
0011 putobject 1
0013 putobject 2
0015 opt_plus <callinfo!mid:+, argc:1, ARGS_SKIP>
0017 send <callinfo!mid:puts, argc:1, FCALL|ARGS_SKIP>
0019 leave
51
Friday, March 22, 13
With some tweaks and modification to bytecode.dump
./ruby --disable-gems ~/work/ruby/load.rb
== disasm: <RubyVM::InstructionSequence:<main>@/Users/freedom/work/ruby/test.rb>
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1] s1)
0000 trace 1
0002 putself
0003 putstring "hello, world\n"
0005 send <callinfo!mid:puts, argc:1, FCALL|ARGS_SKIP>
0007 pop
0008 trace 1
0010 putself
0011 putobject 1
0013 putobject 2
0015 opt_plus <callinfo!mid:+, argc:1, ARGS_SKIP>
0017 send <callinfo!mid:puts, argc:1, FCALL|ARGS_SKIP>
0019 answe
52
Friday, March 22, 13
in case you didn’t get it
• There is a YARV instruction called “answer”
• And, the answer instruction will return “The Answer to Life, the Universe, and Everything”, which you know is 42
• http://en.wikipedia.org/wiki/Answer_to_The_Ultimate_Question_of_Life,_the_Universe,_and_Everything#Answer_to_the_Ultimate_Question_of_Life.2C_the_Universe.2C_and_Everything_.2842.29
53
Friday, March 22, 13
Comparing bytecodes17 <20> pushConstant: 'test’18 <68> popIntoTemp: 019 <76> pushConstant: 120 <77> pushConstant: 221 <B0> send: +22 <7C> returnTop
0000 trace 1
0002 putself
0003 putstring "hello, world\n"
0005 send <callinfo!mid:puts, argc:1, FCALL|ARGS_SKIP>
0007 pop
0008 trace 1
0010 putself
0011 putobject 1
0013 putobject 2
0015 opt_plus <callinfo!mid:+, argc:1, ARGS_SKIP>
0017 send <callinfo!mid:puts, argc:1, FCALL|ARGS_SKIP>
0019 leave
54Friday, March 22, 13
• An example method,forCOmpiledMethod2: a and: b "to show how CompiledMethod works" | foo | foo := 'test'. ^ a + b
• Bytecode: in System Browser of Squeak/Pharo, we can see byteCode easily–17 <20> pushConstant: 'test'–18 <68> popIntoTemp: 2–19 <76> pushTemp: 0–20 <77> pushTemp: 1–21 <B0> send: +–22 <7C> returnTop
55Friday, March 22, 13
Some obvious differences
• Smalltalk bytecodes are quite low-level, but more consistent?
• String is not special
• no special optimizations such as ‘op_plus’
• but Smalltalk-80 does have some primitive methods
• no joke bytecode :-)
56
Friday, March 22, 13
Smalltalk primitive methodInteger>>+
+ aNumber "Refer to the comment in Number + " aNumber isInteger ifTrue: [self negative == aNumber negative ifTrue: [^ (self digitAdd: aNumber) normalize] ifFalse: [^ self digitSubtract: aNumber]]. ^ aNumber adaptToInteger: self andSend: #+
SmallInteger>>+
+ aNumber "Primitive. Add the receiver to the argument and answer with the result if it is a SmallInteger. Fail if the argument or the result is not a SmallInteger Essential No Lookup. See Object documentation whatIsAPrimitive."
<primitive: 1> ^ super + aNumber
57Friday, March 22, 13
??
58
Friday, March 22, 13
Thanks!!
59
Friday, March 22, 13