Squeak|VisualWorksでバイトコードをディスアセンブル


SmalltalkSqueakVisualWorks)の場合、メソッドオブジェクトに symbolic というメッセージを送ることで得られます。

(Integer compiledMethodAt: #factorial) symbolic
25 <70> self
26 <75> pushConstant: 0
27 <B6> send: =
28 <99> jumpFalse: 31
29 <76> pushConstant: 1
30 <7C> returnTop
31 <70> self
32 <75> pushConstant: 0
33 <B3> send: >
34 <9E> jumpFalse: 42
35 <70> self
36 <70> self
37 <76> pushConstant: 1
38 <B1> send: -
39 <D0> send: factorial
40 <B8> send: *
41 <7C> returnTop
42 <70> self
43 <22> pushConstant: 'Not valid for negative integers'
44 <E1> send: error:
45 <87> pop
46 <78> returnSelf


ちなみにメソッドオブジェクトに getSource を送るとソースコードが得られます。

(Integer compiledMethodAt: #factorial) getSource asString
factorial
   "Answer the factorial of the receiver."

   self = 0 ifTrue: [^ 1].
   self > 0 ifTrue: [^ self * (self - 1) factorial].
   self error: 'Not valid for negative integers'


getSource では、メソッド定義時のログ(.changes)があればそこからソースを引っ張って来ていますが、バイトコードデコンパイルでソースを得ることも可能です。

Smalltalk では、メソッドもオブジェクトで、なおかつ Squeak では Python と違ってメソッドオブジェクトがイミュータブルでないことからソースをコンパイルして生成された時点でのメソッドと、現状のそれとが必ずしも一致しない場合もときとしてありえます。そんなときは、ログから引っ張ってきたソースと、デコンパイルしたソースを見比べる必要があります。

(Integer compiledMethodAt: #factorial) decompileString
factorial
   self = 0
      ifTrue: [^ 1].
   self > 0
      ifTrue: [^ self * (self - 1) factorial].
   self error: 'Not valid for negative integers'


メソッドオブジェクトに関して Squeak Smalltalk では #valueWithReceiver:arguments: のコールを介し、静的なコールも可能です。

| method |
method := Integer compiledMethodAt: #factorial.
method valueWithReceiver: 10 arguments: #().   "=> 3628800 "
method valueWithReceiver: -1.0 arguments: #().   "=> Error: Not valid for negative integers"


後者のエラーは Integer>>#factorial によって出されている(上のソースの self error: '...' 部分)ところがポイントです。念のため、エラー時のコールスタックはこんな感じ。

Float(Object)>>error:
Float(Integer)>>factorial
CompiledMethod>>valueWithReceiver:arguments:
UndefinedObject>>DoIt
Compiler>>evaluate:in:to:notifying:ifFail:logged:
[] in SmalltalkEditor(TextEditor)>>evaluateSelection
BlockClosure>>on:do:
SmalltalkEditor(TextEditor)>>evaluateSelection
SmalltalkEditor(TextEditor)>>printIt
...


-1.0 factorial、つまり動的コールであればこうなります。

Float(Object)>>doesNotUnderstand: #factorial
UndefinedObject>>DoIt
Compiler>>evaluate:in:to:notifying:ifFail:logged:
[] in SmalltalkEditor(TextEditor)>>evaluateSelection
BlockClosure>>on:do:
SmalltalkEditor(TextEditor)>>evaluateSelection
SmalltalkEditor(TextEditor)>>printIt
...