Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Smalltalk and ruby - 2012-12-08
1. An Amateur Smalltalk User’s
Observations on Ruby
Object Model and Bytecode
“freedom” Koan-Sin Tan
freedom_at_computer.org
RubyConf Taiwan, Dec 8th, 2012
1
Friday, March 22, 13
3. Outline
• General introduction
• Smalltalk-80 and Ruby object models
• Smalltalk-80 and Ruby bytecode
3
Friday, March 22, 13
4. 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
5. 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
6. the first smalltalk-80 I used is on
Sun’s SunView, image from Wikipedia
6
Friday, March 22, 13
7. Smalltalk/V 286, from http://www.drdobbs.com/
architecture-and-design/making-smalltalk-with-widgets/
184408550
7
Friday, March 22, 13
11. 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
12. Smalltalk-80
• Object-Oriented • Design Pattern:
Programming
• if you read GoF
• OO GUI environment, book, you ran into
IDE lots Smalltalk patterns
before
• VM, bytecode
• Learning/educational
• Lambda, functional
language, block • Logo and the dream
of Dynabook
• Message passing
12
Friday, March 22, 13
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
14. 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
15. 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
17. • 10 factorial class allSuperClasses --> an
OrderedCollection(Integer Number
Magnitude Object ProtoObject)
17
Friday, March 22, 13
18. • SmallInteger class --> SmallInteger class
• Integer
class
--> Integer
class
• Number
class -->
Number
class
• Magnitude
class -->
Magnitude
class
• Object
class -->
Object
class
• ProtoObject
class -->
ProtoObject
class
18
Friday, March 22, 13
19. ProtoObject ProtoObject class
Object Object class
Magnitude Magnitude class
Number Number class
Integer Integer class
SmallInteger SmallInteger class
10
Key
instance-of
figures modified from “Pharo by Example”
19
Friday, March 22, 13
20. 4. All metaclasses are subclasses of Class
5. Every metaclass is an instance of Metaclass
20
Friday, March 22, 13
21. SmallInteger class superclass --> Integer class
Integer class superclass --> Number class
umber class superclass --> Magnitude class
Magnitude class superclass --> Object class
Object class superclass --> ProtoObject class
ProtoObject class superclass --> Class
Class class class --> Metaclass
21
Friday, March 22, 13
22. Class class
Class
ProtoObject ProtoObject class
Metaclass class
Object Object class
Magnitude Magnitude class
Metaclass
Number Number class
Integer Integer class
SmallInteger SmallInteger class
Key
instance-of
10
22
Friday, March 22, 13
23. 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
24. Class class class --> Metaclass
Metaclass superclass --> ClassDescription.
ClassDescription superclass --> Behavior
Behavior superclass --> Object
Class class superclass --> ClassDescription class
ClassDescription class --> superclass Behavior
class
Behavior class superclass --> Object class
24
Friday, March 22, 13
25. Behavior class
Behavior
ClassDescription class
ClassDescription
Class class
Class
ProtoObject
ProtoObject class Metaclass class
Object
Object class
Magnitude Metaclass
Magnitude class
Number
Number class
Integer
Integer class Key
SmallInteger instance-of
SmallInteger class
10
25
Friday, March 22, 13
27. • 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
36. 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
37. 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
38. Smalltalk
bytecodes
Range Bits FuncQon
0-‐15 0000iiii Push
Receiver
Variable
#iiii
16-‐31 0001iiii Push
Temporary
LocaQon
#iiii
32-‐63 001iiiii Push
Literal
Constant
#iiiii
64-‐95 010iiiii Push
Literal
Variable
#iiiii
96-‐103 01100iii Pop
and
Store
Receiver
Variable
#iii
104-‐111 01101iii Pop
and
Store
Temporary
LocaQon
#iii
112-‐119 01110iii Push
(receiver,
true,
false,
nil,
-‐1,
0,
1,
2)
[iii]
120-‐123 011110ii Return
(receiver,
true,
false,
nil)
[ii]
From
Message
124-‐125 0111110i Return
Stack
Top
From
(Message,
Block)
[i]
126-‐127 0111111i unused
128 10000000
jjkkkkkk Push
(Receiver
Variable,
Temporary
LocaQon,
Literal
Constant,
Literal
Variable)
[jj]
#kkkkkk
129 10000001
jjkkkkkk Store
(Receiver
Variable,
Temporary
LocaQon,
Illegal,
Literal
Variable)
[jj]
#kkkkkk
130 10000010
jjkkkkkk Pop
and
Store
(Receiver
Variable,
Temporary
LocaQon,
Illegal,
Literal
Variable)
[jj]
#kkkkkk
131 10000011
jjjkkkkk Send
Literal
Selector
#kkkkk
With
jjj
Arguments
132 10000100
jjjjjjjj
kkkkkkkk Send
Literal
Selector
#kkkkkkkk
With
jjjjjjjj
Arguments
133 10000101
jjjkkkkk Send
Literal
Selector
#kkkkk
To
Superclass
With
jjj
Arguments
134 10000110
jjjjjjjj
kkkkkkkk Send
Literal
Selector
#kkkkkkkk
To
Superclass
With
jjjjjjjj
Arguments
135 10000111 Pop
Stack
Top
136 10001000 Duplicate
Stack
Top
137 10001001 Push
AcQve
Context
138-‐143 unused
144-‐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+jjjjjjjj
168-‐171 101010ii
jjjjjjjj Pop
and
Jump
On
True
ii
*256+jjjjjjjj
172-‐175 101011ii
jjjjjjjj Pop
and
Jump
On
False
ii
*256+jjjjjjjj
176-‐191 1011iiii Send
ArithmeQc
Message
#iiii
192-‐207 1100iiii Send
Special
Message
#iiii
208-‐223 1101iiii Send
Literal
Selector
#iiii
With
No
Arguments
224-‐239 1110iiii Send
Literal
Selector
#iiii
With
1
Argument
240-‐255 1111iiii 38
Send
Literal
Selector
#iiii
With
2
Arguments
Friday, March 22, 13
39. • 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
39
Friday, March 22, 13
42. 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
43. add a method
| myClass myInstance |
myClass := Behavior new. "create anon behavior"
myClass compile: 'theAnswer ^42'. "add a method for insta
nces"
myInstance := myClass new. "create an instance"
Transcript show: myInstance theAnswer; cr. "shows 42"
43
Friday, March 22, 13
44. Ruby bytecode
• ruby
1.8
o cannot
find
easy
way
to
do
this
• ruby
1.9
and
2.0
o ruby.c:proc_opQons()
§ -‐-‐dump=insns
o YARV
InstrucQon
table
o hmp://www.atdot.net/yarv/insnstbl.html,
o source
code,
or
o you
can
ask
Sasada-‐san
:-‐)
44
Friday, March 22, 13
45. 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, worldn"
0005 send <callinfo!mid:print, argc:1, FCALL|ARGS_SKIP>
0007 leave
45
Friday, March 22, 13
46. 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, worldn"
0005 send <callinfo!mid:puts, argc:1, FCALL|ARGS_SKIP>
0007 pop
0008 trace 1 ( 2)
0010 getinlinecache 17, <ic:0>
0013 getconstant :Kernel
0015 setinlinecache <ic:0>
0017 putstring "hello, worldn"
0019 opt_send_simple <callinfo!mid:puts, argc:1, ARGS_SKIP>
0021 pop
0022 trace 1 ( 3)
0024 getglobal $stdout
0026 putstring "hello, world"
0028 opt_send_simple <callinfo!mid:puts, argc:1, ARGS_SKIP>
0030 leave
46
Friday, March 22, 13
47. 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
48. 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
49. 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
49
Friday, March 22, 13
50. Store and load
• test.rb
puts “hello, worldn”
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
53. 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_th
e_Ultimate_Question_of_Life.
2C_the_Universe.2C_and_Everything_.2842.29
53
Friday, March 22, 13
55. • 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
55
Friday, March 22, 13
56. 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
57. Smalltalk primitive method
Integer>>+
+ 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
57
Friday, March 22, 13