[ADP開発日誌-公開1周年記念特集 Part4] プログラミング言語の制御構造のいろいろ(2)

前回からちょっと間が空いてしまいましたが、ADPの1周年記念記事のPart4です。

関数呼び出しのスタックの使われ方


前回の記事の終わりにスタックという言葉が出てきましたが、スタックとはプロセス(正確にはスレッド)毎に用意されているメモリエリアで、関数呼び出しやローカル変数の保持に使われます。

以下のC言語での関数呼び出し時のスタックの使われ方の例を図1に示します。
func( arg1, arg2, arg3); /* ------- ※1 */

         図1


スタックは伝統的にアドレスの上位(数字が大きい)から下位に向かって領域が確保されます。
※1の関数が呼び出されるとき、先ず引数がスタックに積まれ、次いでリターンアドレス、そしてローカル変数の領域が確保されます。関数というのはどこから呼び出されても元の場所に戻ることが出来ますが、それが実現できるのは、呼び出し後に実行すべき命令のアドレス(リターンアドレス)をスタックに保持しているからです。
また、同時にどこから呼び出されてもローカル変数が『関数内で一時的に有効な変数』として機能できるのもスタックに変数のエリアを確保しているからになります。

ちなみに、数年前に流行したセキュリティリスクでバッファオーバーランというものがありますが、これはローカル変数の領域を溢れさせアドレスの上位にある戻りアドレスを書き換えてウイルスのプログラムを実行しようというC言語の関数呼び出しの仕組みを悪用したものになります。現在ではCPUレベルでの対策(NXビットとかXDビットとか呼ばれものでデータ領域の実行の禁止)が行われ、バッファオーバーランの脆弱性が起こりにくくなっています。

スタックには引数が積まれていますが、引数が積まれる順番には2通りのやり方があります。図1ではリターンアドレスに次いで arg1,arg2,arg3 と積まれていますが、反対に arg3,arg2,arg1 というやり方もあります。arg3,arg2,arg1の順番ですが、一見すると反対に見えますが、スタックに積む順番はarg1,arg2,arg3となります。ややこしいですが、※1の擬似アセンブラコードを示すと意味が良く分かるかと思います。

	※2 ※1の擬似アセンブラコード(cdecl呼び出し)

	PUSH arg3
	PUSH arg2
	PUSH arg1
	CALL func

PUSH命令の発行順とスタック上のリターンアドレスから見た順番が反対になります。
関数の呼び出し方法(つまりどのように機械語に翻訳するか)を呼び出し規約(主にx86のCPUで用いられている表現)といい、※2のような呼び出し方法をcdeclと呼びます。呼び出し規約はその他にPASCAL(文字通りPASCALで採用されている)とかstdcall(Windows-APIで採用)とかthiscall(C++のメンバ関数呼び出し)等があります。

メンバ関数の呼び出しでのスタックの使われ方


続いて、C++のメンバ関数呼び出しでのスタックの使われ方について説明します。
以下のC++でのメンバ関数の呼び出し時のスタックの使われ方の例を図2に示します。
object.method( arg1, arg2, arg3); // ------- ※3

            図2



※3の擬似アセンブラコードを以下に示します。

	※4 ※3の擬似アセンブラコード(thiscall呼び出し)

	PUSH arg3
	PUSH arg2
	PUSH arg1
	PUSH object
	CALL method

違いは、object(正確にはobjectのアドレス)がthisポインタとして引数の一つとしてスタックに積まれていることです。その他の違いはありません。こうしてみるとオブジェクト指向というのは単純に

method( &object, arg1, arg2, arg3)

というコードを、

object.method( arg1, arg2, arg3)

という風に記述できる構文上の違いであるに過ぎないということに気づくかと思います。
ADPでは、この考え方を推し進めて、メソッド形式(メンバ関数呼び出しとほぼ同じ意味)として通常の述語形式での呼び出しとメソッドの呼び出しを混ぜて使うことができるようにしています。

ちなみに、私も含めて、多くのC言語の上級エンジニアがこのような見方をしてC言語からC++(オブジェクト指向)に移行していたかと思います。

もっとも、この話は、『仮想関数はどのように機械語に翻訳されるのか?』の話をしなければ終わりになりません。
次いで、仮想関数の呼び出しの話をします。

仮想関数の呼び出しでのスタックの使われ方

前節で説明したメンバ関数の呼び出しは従来の関数呼び出しの延長線上のものですが、ここでは、仮想関数と呼ばれるオブジェクト指向独特の呼び出し方法について説明します。ちなみに仮想関数の説明自体は省略します(コメント欄でリクエストを頂ければ記事を追加するかもしれません)。 仮想関数の説明は次の記事で行います。

以下の仮想関数の呼び出しについて考えます。ちなみにスタックの構成は図2で仮想関数・通常のメンバ関数(非仮想関数)での違いはありません。
object.virtual_method( arg1, arg2, arg3); // ------- ※5
※5の擬似C++コードを以下に示します。

	※6 ※5の擬似アセンブラコード(thiscall呼び出し)

	PUSH arg3
	PUSH arg2
	PUSH arg1
	PUSH object
	MOV	 EAX, [object + vptr] ; ------------------- A
	MOV	 EDX, [EAX + virtual_method_offset] ; ----- B
	CALL EDX ; ------------------------------------ C

object + vptrなどや、EAX + virtual_method_number の部分がかなり曖昧ですが、エッセンスとして読んでいただければと思います。
※6のアセンブラコードではよく分からないかと思いますので、まずはオブジェクトのメモリレイアウトを図3に示します。

            図3



vtableと呼ばれるテーブルに呼び出すべき仮想関数の場所(アドレス)が格納されています。
また各objectはvtableの場所(アドレス)を保持する変数(ポインタ)を持っています。
さらに、機械語の特徴のとして関数呼び出し(CALL命令)は、常に同じ場所(アドレス)の関数を呼び出すだけでなく、変数(レジスタ)を通して間接的に呼び出すこともできるようになっています。

以上を踏まえて再度、擬似アセンブラコードを説明しますと、

Aでは、vtableを参照しています。EAXとはレジスタというCPUが持っている変数になりますがそこへvtableのアドレス(vptr)を代入しています。[] というのはアセンブラでのポインタ参照(間接演算子 *)になります。

Bでは、virtual_methodの呼び出すべきアドレスを、EDXに代入します。このvirtual_method_offsetですが配列のインデックスのようなもので、図3では0ということになります。

最後のCのCALL命令が、A,Bを通して取得した呼び出すべき仮想関数の呼び出しを行っていることになります。

このように擬似アセンブラコードを通してみますと、説明は難しいですが、たったの2命令の追加で仮想関数呼び出しを実現しており、C++での仮想関数呼び出しというのはかなり効率的であることが分かります。

もともと、私はアセンブラが大好き(ハードウェアを直接制御できるので)だったのですが、時代に押されてC言語を使うようになりましたが、その理由の一つとしてC言語が高級アセンブラとして設計された(つまりこのように簡単にアセンブラに置き換えられる)から動作がよく理解しやすい面があったからで、その設計思想はC++にも引き継がれていることが分かります。

続いては、公開1周年記念特集記事として『プログラミング言語の制御構造のいろいろ(3)』を書いてみます。
2011-08-04 | コメント:0件



[ADP開発日誌-公開1周年記念特集 Part3] プログラミング言語の制御構造のいろいろ(1)

ADPの1周年記念特集のPart3です。『プログラミング言語の制御構造のいろいろ』ということで数回にわたって記事をアップします。ちなみに本日でちょうどADPの初回リリースから1年になります。
「なぜ、制御構造?」と思われるかもしれませんが、それはADP(Prolog)が持っている制御構造(バックトラック)が独特のものということと、JavaScriptやRubyにありますクロージャが本格的に普及してきて私自身が持っている制御構造に対する考え方(というか感覚)を変える必要があるので記事にしてみます。

制御構造とは

制御構造とはプログラムの流れ、広くはその命令(for文とかif文)を指します。制御構造を有名なものにしたのは、かのダイクストラ氏が提唱した構造化プログラミングがあります。今となっては『構造化プログラミング』という言葉を始めて聞いた人もいらっしゃるかと思いますが、『構造化プログラミング』が提唱された後に、今ではおなじみの制御構造文
・選択(if)
・反復(for,while等のループ)
が明確になりました。それまでの言語ではif文やfor文もありましたが充分でなく、本格的なプログラムの記述にはgoto文を使う必要がありました。そのれに加えてgoto文では様々なプログラムの流れを作ることが出来、流れの追いにくいいわゆるスパゲティプログラムというものもありました。私が駆け出しの頃(20年程前)にはよく可読性の悪いプログラムに対して『このスパゲティプログラムが~』という表現を聞いていました。

機械語ではどうしているのか?

なぜ、「機械語の話が出てくるのか?」と思われるかもしれませんが、制御構造の発展の歴史のルーツを探ることと、コンパイラ言語では制御構造が機械語に変換されるのでその仕組みを探るという意味で、続いて機械語の話をします。
機械語では初期のプログラミング言語のように比較文(if文)とgoto文のみで制御を行います。今となっては逆に難しいかもしれませんが、for文やwhile文がなくてもif文とgoto文の組み合わせでループを記述することが出来ます。
意外に思われるかもしれませんが、もう一つの制御構造文である関数呼び出し(サブルーチン呼び出し)も機械語にCALL命令という形で存在します。初期のCPUにはCALL命令がないものもあったらしいですが、今われわれが主に使っているパソコンのx86と呼ばれるCPUにもCALL命令があります。さらにx86の先祖をたどりますと、8080というパソコン用の8ビットCPUがありますが、そのCPUにもCALL命令があります(それから先は8008、4004とたどれますがこれらにCALL命令があるかどうかは不明です・・・)。
もちろんCALL命令が関数呼び出しとイコールではありません。CALL命令と関数呼び出しの違いは引数の受け渡しになります。CALL命令には引数の概念がありません。引数の受け渡しはレジスタまたはスタックまたはグローバル変数ということになります。C言語の関数呼び出しが機械語に翻訳されるるとCALL命令に翻訳されますが、その引数はスタックで渡されます。

続いては、公開1周年記念特集記事として『プログラミング言語の制御構造のいろいろ(2)』を書いてみます。
2011-07-30 | コメント:0件



[ADP開発日誌-公開1周年記念特集 Part2] ADPの次の1年の目標

ADPの1周年記念特集のPart2です。プロジェクトを公開して1年が経ち少しは慣れてきましたので、次の1年間の目標でも立ててみます。

Ver 0.9 ベータ版のリリース

 現在は開発版(アルファ版)ということでリリースを重ねていますが、次の1年ではベータ版のリリースにまで行えればよいかと思っております。
まぁ、ゆる~い目標かもしれませんが、プロジェクト開始当初はゴールがみえていませんでしたので見えただけでもよろしいかと思います。
もっとも実装する機能が機能だけにかなりの大改造になるかと思いますので、実はゆるくはないかもしれません。
いずれにしても次の1年は開発に専念したいと思ってます。

Ver1.0に向けての機能の実装

 ADPのロードマップには以下のようにVer1.0に向けての機能を掲げています。
・マルチスレッド(マルチコア)対応
・ADPサーバー
・C言語インタフェース
・リソースの開放機能
ベータ版では機能的にはVer1.0相当の機能を実装します。つまり上記の機能は次の1年で実装しようとしています。
 このうちマルチスレッド(マルチコア)対応が一つの山場でして、現在マルチスレッドの機能の一部を実装しています。
ADPではマルチスレッドに関する4つの機能を実装する予定です。2つはProlog由来の述語評価に関する並列処理(AND並列/OR並列)で、残りの2つがオリジナルということになりますが、そのうちの1つは目下開発作業をしているパイプライン処理になります(LL PlanetsのLTで発表するネタの一つです)。もう一つは組み込み述語・C言語インタフェースに関わる部分になります。
次の山場がリソースの開放機能(コンテクスト)になります。現在DBのコネクションの管理やファイルのクローズ管理ですが曖昧に実装しています。この辺りについてもう少し洗練された機能を追加しようと考えております。この機能ですがイメージだけで具体的な実装方法や文法も明確ではないので、かなりの検討・試行錯誤が入るのでそれはそれで難産が予想されます。
次のADPサーバーやC言語インタフェースは、技術的には難しいものではないのですが、マルチスレッド機能やリソースの開放機能が実装されないとこの辺りの機能が実装できないので後回しとなっています。

マニュアル

 英語版マニュアルが欲しいところです。もっともこちらは協力者を募ってやろうかと思っています。ただ、このような小プロジェクトに協力者は来てもらえそうにないので英語の勉強がてら自分で書いてみようかとも思っています。
英語版のマニュアルの必要性に関してですが、私もこの業界が長いので良く分かっているのですが、日本でプログラミング言語を流行らそうと思ったら、先ずは海外で流行らす必要があります。日本人は自国の技術より海外(主に欧米)からの技術を取り入れようとする傾向があります。実は私もそういう傾向があったりしますので、『日本人は~』と自国の否定をする気はさらさらありませんが、まぁこの特性は頭に入れないと痛い目にあうかと思います。
IT業界に関していうと日本が流行の最先端にならない(なれない)理由の1つにこのマインドの弱さにあるかと思います。例えば今でしたら、AndoroidやiPad,iPhoneが流行っていますが、これらはどちらも海外からのものです。一方で日本の携帯は良く出来ていると思いますが、それを『ガラケー』と言って切り捨ててしまうところもどうかと思いますし、なぜ海外ではやらせないのか? 流行らなかったのか? とも思わなくもないのですが、まぁ浮かばれないのは一生懸命開発した技術者でしょうか。
技術者自体は優秀な人がそろっているのになぜトヨタみたいな世界に通用する企業(技術を発信できる企業)が出ないのか改めて考えると不思議に思います。
話が脱線しましたが、日本語版のマニュアルの完成と共に英語版に着手できればと思います。

その他

 最初の1年は広報活動も色々しましたが、少し状況が分かりましたので、次の1年は開発に専念し特に広報活動はやめようかと思っています。もっとも今まで出来たつながりはそのまま維持していこうとも思っております。

続いては、公開1周年記念特集記事として『プログラミング言語の制御構造のいろいろ(1)』を書いてみます。
2011-07-29 | コメント:0件



[ADP開発日誌-公開1周年記念特集 Part1] ADPの1年間を振り返る

この7/30で、ADPをSourceforge.jpさんで公開して1周年になります。本来なら大々的なパーティでもするところですが、残念ながらそこまで流行っていませんが、それでも感慨深いものがありますので、このブログで1周年記念特集でもやってみます。
(もっともこういうふうに、こそっとやっている時が一番楽しいところかもしれません。)
先ずは、この1年間の活動を総括してみます。

ダウンロード件数250件

残念ながらあまり多くないです(他の自作のソフトの方がもっとダウンロードされてたりします)。もっとも最近では、固定客がついたのか、リリースの度に数十件のダウンロードがあり、4月以降のダウンロード件数が150件となっています。
ADPですがまだ開発版なので、ガチであまり使って欲しく無い面もあり、とはいっても流行らせたい思いもあり、といったジレンマを感じるわけですが、Ver 1.0までは開発優先で行こうということでこのまましばらく様子をみます。

バージョン:0.5 → 0.73

この1年でバージョンが0.23増えましたので、このペースで行けば来年の年末にはVer 1.0が出そうです。もっとも途中でスキップ(0.5 → 0.55、0.62 → 0.69)していますので単純には比較できませんが。
この1年で、内部のアーキテクチャーにも手を入れました。特にインタプリタ本体の構造が変わりました。
Ver0.5ではグローバル変数に実行環境のスタックを持っていましたが、途中のバージョン(忘れた・・・Ver0.6付近)からは、スタックを、実行状態を保持するオブジェクトで持つように変更しました。
また、Ver0.69でライブラリを整理し大分洗練されてきたかと思います。

キャッシュ機能の実装、DB関係の充実

機能の実装ですが、大きなところではキャッシュ機能の実装があります。細かなところではDB関係の機能の充実、JSONの対応などがあります。最近では他社からの請負仕事以外はなるべくADPで作成するようにしており、他のプロジェクトのモックアップをADPで作成したりして、この1年で少しは鍛えられたかと思います。

マニュアルがそこそこ充実してきました

マニュアルが大分充実してきました。リファレンスマニュアルで一部抜けているところがありますが、そこはまだ仕様が変わる可能性があるのでそのままにしています(またはサボっている)。
マニュアルは英語版が欲しいところですが、現在のところ日本語版のみです。

Sourceforgeさんについて

当初はダウンロードのみということで使っていましたが、最近ではチケットシステムやSVNのリポジトリもSourceforgeさんのものをメインで使うようになりました。
ちなみに、2011年上半期までの活発なプロジェクトにADPがランクインしました!

その他

LL Eventさんの方で実行委員を募集していましたので、応募してみましたところみごとにとおりました。
今年は、8/20に行われますが、Lightning Talkにも発表者として参加いたします。
80%の出来のADPを発表するのもどうかと思ったのですが、LL Eventに出るというのは目標だったので、早くも達成できたのでよかったです。

ということで次の記事は『次の1年間の目標』を書いてみます。
2011-07-28 | コメント:0件



イージースマートパッド ESP01

久々のブログの更新ですが、先日の連休で、パチンコをしたら結構出たので『デジカメでも換えようか~』と景品を見ていたら、格安のAndoroidタブレットのこれを見つけ、円パチの玉10000発と交換をしました。

 
いかにもな箱で、『硬派なエンジニはやっぱりiPadだろ~』とも思わなくもなかったのですが、とりあえずAndoroidを試そうということで。。。以下スペックです。

重量395g
メモリ256MB
OSAndoroid 1.6(バージョンアップ不可)
画面・解像度7インチ・800×480
Wifi802.11 b/g
内部ストレージ2GB
外部ストレージMicroSD スロット(最大8GB)

CPUのスペックが不明ですが、使ってみた感じはGUIの操作はもたつきませんが、Wifiのネットのスピードは結構遅いです。
また、電池ですが動画再生時は連続2時間もつとのことですが、WifiがONの場合かなり早く電池が消耗します。
とまぁ不満が多いタブレットですが、何よりいいのが寝転がってネットをするという自堕落なことが出来るので私の中では必須のアイテムとなりつつあります。

2011-07-22 | コメント:0件
Previous Page | Next Page