コンパイラ 2012年11月12日 酒居敬一@A468(sakai.keiichi@kochi-tech.ac.jp) http://www.info.kochi-tech.ac.jp/k1sakai/Lecture/COMP/2012/index.html.

Slides:



Advertisements
Similar presentations
アルゴリズムとプログラミン グ (Algorithms and Programming) 第6回:クラスとインスタンス クラスの宣言 アクセス修飾子 インスタンスの生成 (new キーワード) this キーワード フィールドとメソッドの実際の定義と使い 方 クラスの宣言 アクセス修飾子 インスタンスの生成.
Advertisements

モバイルエージェントシステムの実装 エージェント移動(状態とコードの一括移送) エージェント移動の特徴 システム構成 エージェントプログラム
コンパイラ 2011年11月14日
自社製ミドルウエアをDalvikと連携させることが可能になる
プログラミング入門2 第10回 動的な領域確保 情報工学科 篠埜 功.
データ構造とアルゴリズム 第10回 mallocとfree
実行時のメモリ構造(1) Jasminの基礎とフレーム内動作
システムプログラミング 第11回 シグナル 情報工学科  篠埜 功.
第2回:Javaの変数と型の宣言 プログラミングII 2007年10月2日.
応用情報処理V 第1回 プログラミングとは何か 2004年9月27日.
App. A アセンブラ、リンカ、 SPIMシミュレータ
アルゴリズムとデータ構造 2011年6月13日
応用情報処理V 第1回 プログラミングとは何か 2003年9月29日.
プログラミング演習Ⅰ 課題2 10進数と2進数 2回目.
システムプログラミング 第11回 シグナル 情報工学科  篠埜 功.
Flyingware : バイトコード変換による 安全なエージェントの実行
コンパイラの解析 (2) GCJのデータ構造 - 1.
型付きアセンブリ言語を用いた安全なカーネル拡張
細かい粒度でコードの再利用を可能とするメソッド内メソッドのJava言語への導入
プログラミング言語入門 手続き型言語としてのJava
プログラミング論 ファイル入出力
細かい粒度で コードの再利用を可能とする メソッド内メソッドと その効率の良い実装方法の提案
暗黙的に型付けされる構造体の Java言語への導入
コンパイラの解析 (3) クラスとインスタンスの初期化.
関数の定義.
プログラミング 4 記憶の割り付け.
プログラミング言語入門.
アルゴリズムとデータ構造 補足資料11-1 「mallocとfree」
メモリの準備 メモリには、その準備の方法で2種類ある。 静的変数: コンパイル時にすでにメモリのサイズがわかっているもの。 普通の変数宣言
コンパイラ 2012年11月15日
プログラミング入門2 第11回 情報工学科 篠埜 功.
プログラミング入門2 第11回 情報工学科 篠埜 功.
第7回 プログラミングⅡ 第7回
プログラミング言語論 第五回 理工学部 情報システム工学科 新田直也.
プログラミング論 ファイル入出力
アルゴリズムとデータ構造1 2005年7月5日
オブジェクト指向プログラミングと開発環境
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
プログラミング言語論 第六回 理工学部 情報システム工学科 新田直也.
プログラミング言語入門 2013 (C言語 初級) 演習期間 担当 参考資料 採点 10/24 - 1/23 (全10回) 松澤,鈴木,児玉
アルゴリズムとプログラミング (Algorithms and Programming)
11: 動的メモリ確保 C プログラミング入門 総機1 (月1) Linux にログインし、以下の講義ページ を開いておくこと
コンパイラ 2012年10月1日
ソフトウェア工学 知能情報学部 新田直也.
アルゴリズムとデータ構造 2012年6月11日
コンピュータアーキテクチャ 第 5 回.
アルゴリズムとデータ構造1 2006年6月23日
アルゴリズムとデータ構造1 2009年6月15日
第5回 プログラミングⅡ 第5回
オブジェクト指向言語論 第五回 知能情報学部 新田直也.
11: 動的メモリ確保 C プログラミング入門 基幹7 (水5) Linux にログインし、以下の講義ページ を開いておくこと
コンピュータアーキテクチャ 第 5 回.
第2回 開発環境とゲーム 05A1030 佐々木 和也.
cp-2. 属性,アクセサ (C++ オブジェクト指向プログラミング入門)
モジュール分割.
コンパイラ 2012年10月11日
コンパイラ 第12回 実行時環境 ― 変数と関数 ― 38号館4階N-411 内線5459
アルゴリズムとデータ構造 2010年6月17日
ソフトウェア工学 知能情報学部 新田直也.
11: 動的メモリ確保 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと
プログラミング言語論 第九回 理工学部 情報システム工学科 新田直也.
Javaとは Javaとはオブジェクト指向言語でJava VM(Java仮想マシン)と呼ばれるプログラム上で動作します。
プログラミング演習I 2003年6月11日(第9回) 木村巌.
システムプログラミング 第11回 シグナル 情報工学科  篠埜 功.
オブジェクト指向言語論 第七回 知能情報学部 新田直也.
プログラミング言語論 第九回 理工学部 情報システム工学科 新田直也.
オブジェクト指向言語論 第七回 知能情報学部 新田直也.
プログラミング演習II 2004年11月 16日(第5回) 理学部数学科・木村巌.
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
プログラミング 2 静的変数.
Presentation transcript:

コンパイラ 2012年11月12日 酒居敬一@A468(sakai.keiichi@kochi-tech.ac.jp) http://www.info.kochi-tech.ac.jp/k1sakai/Lecture/COMP/2012/index.html

コンパイラと実行環境の連携1 OS 実行環境 プロセスやファイルシステムなど仮想化したハードウェアを提供 プログラミング言語に依存しない汎用的なインターフェース 実行環境 プログラミング言語固有のサービス メモリ管理(たとえば、割り付け・自動開放) スレッド管理(生成・消滅・同期・相互排除) 初期化処理 C言語の場合、この初期化処理だけで、限定的に動かすことができる ライブラリ 明示的に利用するもの・暗黙的に利用されるもの コンパイラと同時に開発する必要があるモノ もし、仮想化も汎用性も不要なら、ハードウェアを直接操作すればよく、OSは不要。そうすると、Cでは最低限、コンパイラと初期化処理だけあればいい。

実行環境 ソースコード オブジェクト コード コンパイラ OS リンク ライブラリ 実行環境 システムコール

実行環境とコンパイラ たとえば、lookUpReturnAddressInException() たとえば、キャスト。 例外検査コードを生成するとしても、いちいち表を調べる コードをオブジェクトコードに入れておくことは無駄である。 通常はコンパイラが、そういったサブルーチンを呼ぶ。 たとえば、キャスト。 実行時の型検査、例外生成あるいは型変換、といった一連 の手続きを、いちいちコード生成しててはメモリを消費する。 こういったものも、コンパイラがサブルーチンを呼ぶ。 実行時に呼ばれる、そのような様々なサブルーチンも 実行環境であり、コンパイラとペアで開発する。

Garbage Collection (ごみ集め) メモリ割り付けと開放の自動化・機械化 Lispでは、メモリは自動で割り付けられ自動で開放される 割り付けはオブジェクト生成時に行われる 使われていないオブジェクトのメモリは、ころあいを見て開放される Javaでは、開放だけが機械化されている。 割り付けは new オペレータで、明示的に行う。 Cでは、メモリ割り付け・開放については機械化されていない。 malloc()/free() という、ライブラリ関数があるのみ。 メモリの開放に関する問題 開放忘れ:使用可能なメモリの不足による停止 二重開放:メモリ内容の意図せぬ変更によるプログラムの暴走。 不要メモリを機械的に回収し開放する。→ GC マニュアル化→自動化。人手を介在しないで処理が行われるのは機械化。

javaコマンド(Java VM Emulator) Javac (静的コンパイラ) OS Java 実行環境 ソースコード クラス ファイル その他 is_instance_of()など メモリ管理 newInstance()など スレッド管理 EnterSynchronizedBlock() ExitSynchronizedBlock()など javaコマンド(Java VM Emulator) クラスローダ 動的コンパイラ インタプリタ 例外処理 暗黙のnull検査、スタックバンギング用シグナルハンドラ lookUpReturnAddressInException()など 標準クラスライブラリ java.lang.System クラス java.io.orintStream クラス C言語の極端な例では、 スタックポインタを設定しmain()を呼ぶだけの初期化処理でもいい。 実行環境として、機械語で数命令書けば動くということ。 コンパイラ・アセンブラ・リンケージエディタ、といった コマンドだけでよい例は、 学群実験でやった。 Javaは、C言語より楽だ。 でも実行環境は相応に 大きく複雑になる。

静的コンパイラ プログラムを実行する前にコンパイルするコンパイラ 普通のコンパイラ。 Javaでは、利用者の書いたプログラムをコンパイルして 得た、Java VM向けのバイトコードが出力される。 class ファイルが生成される。 javaコマンド実行により、次の処理が行われる。 Java VM の初期化。 引数の class ファイルを読み、main() を探す。 class loader により、外部参照を解決する。 class ファイルや、jar ファイルを決められた順で探す。

動的コンパイラ Java VM はエミュレーションなので、やはり遅い native code に静的コンパイルしないことで、class ファイル (オブジェクトファイル)を機種非依存にできたことは利点。 そこで、必要に応じて、javac (Java VM emulator) で、 バイトコードを native code に翻訳する。 バイトコードと native code を切り替えながら実行する。 ちなみに、native code 実装したメソッドなどを、 java プログラムから呼び出す手段がある。 混ぜて実行できるくらいなので、当然といえば当然。

標準クラスライブラリ 実行環境が用意する標準的なライブラリ群 GUI bean Java 固有 数学 ネット I/O セキュリティ text 処理 ユーティリティ

Write once, run anywhere にも例外がある ずーっと前の情報工学実験 JavaからWebカメラを使って画像をキャプチャしていた。 もちろん標準クラスライブラリにはキャプチャ用クラスはない。 当然ながら、OS経由でカメラを直接操作するクラスがない。 実はJavaにも、非標準的実装方法ある。 もちろん方法は標準化してある。 JNI (Java Native Interface) 無いものは仕方ないという状況で、どうするか? あきらめてもらう。 Javaは使ってもらえなくなるかもしれない。 プログラマに非標準的実装方法を提供する。 Java VMコードではなく、java VMが動作する環境のコードで「実装」。

public class WebCam { public WebCam() { if(initializeWebCam("/dev/video0", 640, 480)){ throw new java.lang.IllegalArgumentException(); } public WebCam(String device) { if(initializeWebCam(device, 640, 480)){ public WebCam(int width, int height) { if(initializeWebCam("/dev/video0", width, height)){ public WebCam(String device, int width, int height) { if(initializeWebCam(device, width, height)){ private static native boolean initializeWebCam(String device, int width, int height); public static native void finalizeWebCam(); public static native int getWidth(); public static native int getHeight(); public static native int[] grabPixels(int[] array); public static native byte[] grabPixels(byte[] array); static { System.loadLibrary("WebCam");

#include <jni.h> #include "WebCam.h" #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/mman.h> #include <sys/fcntl.h> #include <sys/ioctl.h> #include <time.h> #include <linux/videodev.h> #ifdef USE_MMX #include <mmintrin.h> #endif #define SYNC_TIMEOUT 1 /* device stuff */ static int bt848, gb_grab, gb_sync, even, start; static char *gb_frame; static int *gb_work; static struct video_mbuf gb_buffers; static struct video_mmap gb_even, gb_odd; /* geometry stuff */ static int cols, rows, pxls; /* * Class: WebCam * Method: getWidth * Signature: ()I */ JNIEXPORT jint JNICALL Java_WebCam_getWidth(JNIEnv *env, jclass obj) { return cols; } * Method: getHeight Java_WebCam_getHeight(JNIEnv *env, jclass obj) return rows; static void YUV420PtoYRGB(unsigned char *dest, unsigned char *src) int i, j; unsigned char *yp0, *yp1, *dp0, *dp1; unsigned char *up, *vp; int vu; __m64 gb, yr, yrgb, yyyy0, yyyy1, vuvu; short int vu_gb[4], vu_yr[4]; vu_gb[0] = 454; vu_gb[1] = 0; vu_gb[2] = -88; vu_gb[3] = -183; vu_yr[0] = 0; vu_yr[1] = 359; vu_yr[2] = 0; vu_yr[3] = 0; up = src + pxls; vp = up + pxls/4; yp1 = src; dp1 = dest; for(i = 0; i < rows; i+=2){ yp0 = yp1; yp1 = yp0 + cols; dp0 = dp1; dp1 = dp0 + 4*cols; for(j = 0; j < cols; j+=2){ vu = (*vp++ - 128) << 16; /* v */ vu |= (*up++ - 128) & 0x0000FFFF; /* u */ vuvu = _mm_cvtsi32_si64(vu); vuvu = _mm_unpacklo_pi32(vuvu, vuvu); gb = _mm_srai_pi32(_mm_madd_pi16(vuvu, *((__m64 *)vu_gb)), 8); yr = _mm_srai_pi32(_mm_madd_pi16(vuvu, *((__m64 *)vu_yr)), 8); yrgb = _mm_packs_pi32(gb, yr); yyyy0 = _mm_unpacklo_pi8(*((__m64 *)yp0), _mm_setzero_si64()); yyyy0 = yyyy1 = _mm_unpacklo_pi16(yyyy0, yyyy0); yyyy0 = _mm_add_pi16(_mm_unpacklo_pi32(yyyy0, yyyy0), yrgb); yyyy1 = _mm_add_pi16(_mm_unpackhi_pi32(yyyy1, yyyy1), yrgb); yyyy0 = _mm_packs_pu16(yyyy0, yyyy1); *((__m64 *)dp0) = yyyy0; yp0 += 2; dp0+= 8; yyyy0 = _mm_unpacklo_pi8(*((__m64 *)yp1), _mm_setzero_si64()); *((__m64 *)dp1) = yyyy0; yp1 += 2; dp1+= 8; _mm_empty(); #else int u, v; int r, g, b; yp0 = src; src += cols; dp0 = dest; dest += 4*cols; u = *up++ - 128; v = *vp++ - 128; r = (359*v) >> 8; g = (-88*u - 183*v) >> 8; b = (454*u) >> 8; dp0[0] = ((b + yp0[0]) > 255)? 255: ((b + yp0[0]) < 0)? 0: (b + yp0[0]); dp0[1] = ((g + yp0[0]) > 255)? 255: ((g + yp0[0]) < 0)? 0: (g + yp0[0]); dp0[2] = ((r + yp0[0]) > 255)? 255: ((r + yp0[0]) < 0)? 0: (r + yp0[0]); dp0[3] = yp0[0]; dp0[4] = ((b + yp0[1]) > 255)? 255: ((b + yp0[1]) < 0)? 0: (b + yp0[1]); dp0[5] = ((g + yp0[1]) > 255)? 255: ((g + yp0[1]) < 0)? 0: (g + yp0[1]); dp0[6] = ((r + yp0[1]) > 255)? 255: ((r + yp0[1]) < 0)? 0: (r + yp0[1]); dp0[7] = yp0[1]; dp1[0] = ((b + yp1[0]) > 255)? 255: ((b + yp1[0]) < 0)? 0: (b + yp1[0]); dp1[1] = ((g + yp1[0]) > 255)? 255: ((g + yp1[0]) < 0)? 0: (g + yp1[0]); dp1[2] = ((r + yp1[0]) > 255)? 255: ((r + yp1[0]) < 0)? 0: (r + yp1[0]); dp1[3] = yp1[0]; dp1[4] = ((b + yp1[1]) > 255)? 255: ((b + yp1[1]) < 0)? 0: (b + yp1[1]); dp1[5] = ((g + yp1[1]) > 255)? 255: ((g + yp1[1]) < 0)? 0: (g + yp1[1]); dp1[6] = ((r + yp1[1]) > 255)? 255: ((r + yp1[1]) < 0)? 0: (r + yp1[1]); dp1[7] = yp1[1]; static int grab_queue(struct video_mmap *gb) if (-1 == ioctl(bt848,VIDIOCMCAPTURE,gb)) { perror("ioctl VIDIOCMCAPTURE"); return -1; gb_grab++; return 0; grab_wait(struct video_mmap *gb) int ret = 0; alarm(SYNC_TIMEOUT); if (-1 == ioctl(bt848,VIDIOCSYNC,&(gb->frame))) { perror("ioctl VIDIOCSYNC"); ret = -1; gb_sync++; alarm(0); return ret; * Method: grabPixels * Signature: ([I)[I JNIEXPORT jintArray JNICALL Java_WebCam_grabPixels___3I(JNIEnv *env, jclass obj, jintArray array) if((*env)->GetArrayLength(env, array) < pxls){ return NULL; if (gb_grab == gb_sync){ /* started */ start = clock(); if (-1 == grab_queue(even ? &gb_even : &gb_odd)){ if (-1 == grab_queue(even ? &gb_odd : &gb_even)){ grab_wait(even ? &gb_even : &gb_odd); even = !even; YUV420PtoYRGB((unsigned char *)gb_work, (gb_frame + gb_buffers.offsets[even ? 1 : 0])); (*env)->SetIntArrayRegion(env, array, 0, pxls, gb_work); return array; * Signature: ([B)[B JNIEXPORT jbyteArray JNICALL Java_WebCam_grabPixels___3B(JNIEnv *env, jclass obj, jbyteArray array) if((*env)->GetArrayLength(env, array) < pxls*3/2){ (*env)->SetByteArrayRegion(env, array, 0, pxls*3/2, (gb_frame + gb_buffers.offsets[even ? 1 : 0])); * Method: finalizeWebCam * Signature: ()V JNIEXPORT void JNICALL Java_WebCam_finalizeWebCam(JNIEnv *env, jclass obj) double elapsed; if (gb_grab > gb_sync){ elapsed = (double)(clock() - start)/CLOCKS_PER_SEC; munmap(gb_work, (pxls*4 + 4095) & ~4095); munmap(gb_frame, gb_buffers.size); close(bt848); gb_sync--; fprintf(stderr, "%d frames grabbed in %.1f seconds(%.1f[fps]).\n", gb_sync, elapsed, (double)gb_sync/elapsed); gb_sync = gb_grab = even = 0; initialize(void) struct video_capability vcap; struct video_channel vchan; struct video_picture vpic; /* find video capture card */ if(ioctl(bt848, VIDIOCGCAP, &vcap)){ fprintf(stderr, "Can't get video capability.\n"); return 1; fprintf(stderr, "Video capture card is \"%s\".\n" "Width: %d - %d, Height: %d - %d\n", vcap.name, vcap.minwidth, vcap.maxwidth, vcap.minheight, vcap.maxheight); if((cols & 1) || (rows & 1) || (vcap.minwidth > cols) || (cols > vcap.maxwidth) || (vcap.minheight > rows) || (rows > vcap.maxheight)){ for(vchan.channel = 0; vchan.channel < vcap.channels; vchan.channel++){ if(ioctl(bt848, VIDIOCGCHAN, &vchan)){ fprintf(stderr, "Can't get channel info.\n"); if(vchan.flags & VIDEO_VC_TUNER){ continue; if(vchan.type & VIDEO_TYPE_CAMERA){ vchan.norm = VIDEO_MODE_NTSC; ioctl(bt848, VIDIOCSCHAN, &vchan); fprintf(stderr, "Video source is set to \"%s\".\n", vchan.name); break; if(vchan.channel == vcap.channels){ fprintf(stderr, "Can't find camera.\n"); /* set picture */ vpic.brightness = vpic.hue = vpic.colour = vpic.contrast = vpic.whiteness = 32768; vpic.depth = 12; vpic.palette = VIDEO_PALETTE_YUV420P; if(ioctl(bt848, VIDIOCSPICT, &vpic)){ fprintf(stderr, "Can't set YUV420P.\n"); gb_even.frame = 0; gb_odd.frame = 1; gb_odd.format = gb_even.format = vpic.palette; gb_odd.width = gb_even.width = cols; gb_odd.height = gb_even.height = rows; /* map grab buffer */ if (-1 == ioctl(bt848,VIDIOCGMBUF,&gb_buffers)) { perror("ioctl VIDIOCGMBUF"); gb_frame = mmap(0,gb_buffers.size,PROT_READ|PROT_WRITE,MAP_SHARED,bt848,0); if ((char*)-1 == gb_frame) { perror("mmap"); fprintf(stderr, "%d buffers starting at %p. Frame buffer size is %d.\n", gb_buffers.frames, gb_frame + gb_buffers.offsets[0], (gb_buffers.offsets[1] - gb_buffers.offsets[0])); /* map working area */ gb_work = mmap(0, (pxls*4 + 4095) & ~4095, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); if((int *)-1 == gb_work){ * Method: initializeWebCam * Signature: (Ljava/lang/String;II)Z JNIEXPORT jboolean JNICALL Java_WebCam_initializeWebCam (JNIEnv *env, jclass obj, jstring device, jint width, jint height) const jbyte *str; cols = width; rows = height; pxls = cols*rows; /* open video camera device */ str = (*env)->GetStringUTFChars(env, device, 0); bt848 = open(str, O_RDWR); if (bt848 < 0) { fprintf(stderr, "failed to open device %s\n", str); (*env)->ReleaseStringUTFChars(env, device, str); return JNI_TRUE; if(initialize()){ return JNI_FALSE;

メモリ管理 プログラムの実行に必要なメモリ領域の確保・管理・開放 OSの上で動く場合 OSへのメモリ要求 brk()・sbrk()やvalloc()やmmap()システムコール 獲得したメモリのJavaプログラムへの割り付け・回収 OSへのメモリ返却 メモリ管理 方式 比較項目 手動 自動 実行時スタック ごみ集め 適用範囲 広い 狭い 除去困難なバグを生成する確率 大 なし オーバーヘッド 小

実行時スタック 関数やメソッド内の局所変数領域として使われる スタックポインタだけでメモリ管理機構が実装できる エントリー時に確保、return 時に開放。 スタックポインタだけでメモリ管理機構が実装できる たいていは、プロセッサによるサポートがある。 特定のレジスタがスタックポインタになってる。 スタックフレームを形成・破棄する機械語命令がある。 スタックポインタの操作だけなのでオーバーヘッドが少ない。 コンパイラがスタック操作コードを生成するので 開放ミスはない 原理的に静的な割り付けができない ポインタで参照してても、return 後には必ず消滅する。

※ object変数はスタックフレームに置かれてますが、 object変数が指す本体はヒープに置かれている。 メソッド呼び出し メソッドからの返戻 空き領域 newInstance()の スタックフレーム Example8_methos2()の Example8_method1()の Example8_main()の スタックポインタ (TOS) 変数objectの内容 を保存する場所 ※ object変数はスタックフレームに置かれてますが、 object変数が指す本体はヒープに置かれている。

Heap (ヒープ) 静的データ・実行時スタック以外のメモリ領域 ヒープを使う方法に3とおりある。 静的データの一部をあらかじめ割り付ける方法もある たいていはOSから随時割り当てられた仮想記憶領域 OSからはページングサイズで割り当てられたりして使いにくい ヒープを使う方法に3とおりある。 オブジェクトへの割り付けも開放も手動 C言語のmalloc()/free()が典型例 オブジェクトへの割り付けは手動、開放は自動 Java のnew 開放はGCが安全に機械的に行う 割り付けも開放も自動 LispやSchemeなど

手動によるメモリ管理 うまく書ければ最高の効率でメモリが管理できる? 必要なときに確保し、不要になった時点で即開放すれば、 メモリ領域は効率よく再利用されていいかもしれない。 現実には… 間違いなくfree()することはとても面倒 フローグラフ上で、free() する位置が異なるブロックに現れる malloc()コードと対応するfree()を常に同時に記述・抹消する メモリ割り当てが成功したかどうかの検査も面倒 メモリ割り当て失敗はプログラマの責任じゃないでしょう。 オブジェクトの性質に応じたメモリの割り当ての区別が面倒 スクラッチパッド用の細かなデータ領域 行列演算用領域 フレームバッファ用領域

Garbage Collection の必要性 割り付けはオブジェクトが生成されるとき、という明確な タイミングがある。一方で開放には、そこまで明確な タイミングがない。 free()に関する次の問題をGCが解決する 開放忘れ (短期的には)ヒープを圧迫する OSからメモリを一方的に獲得し続ける結果、システム不安定をきたす 誤開放 使用中のエリアを開放して、再利用されたら暴走しかねない 二重開放 開放済み領域を再び開放したら、ヒープ管理が破綻しかねない