1ヶ月前に、DELLにPC(Studio XPS 16)注文したが、
未だに、届かない。
(1ヶ月たってもオーダー状況が『生産の準備』)
さらに悪いことに
以下のメールが送信されてくる始末
<メール内容の一部>
この度本製品の構成上の問題により、お客様ご選択いただきました
カスタマイズの通りに提供できなくなりました。
そのため製品自体の生産が進まず、お客様には多大な
ご迷惑をおかけしてしまっていることお詫び申し上げます。
そこで、構成を確認してメール返信を行ったが、
また構成を変えるようなメールが
(しかもメールの内容がどうやら間違っているらしい)
再度、送られてきた。
電話でいつぐらいに届くのか聞いても
答えてもらえず、どう考えてもおかしい状況がつづいていた。
(あきらかに電話にでているオペレータが日本人ではなく
こちらの言うことが、はたして理解できているのかが非常に不安であった)
いろいろとネット上には、DELLに対する悪評があったのだが
開発の仕事の作業場所にDELLのPCが
あったりするのでそれなりには信用していた。
Studio XPS 16のスペックと価格に惹かれて今回注文したが、
今後のサポート対応を考えると、非常に不安に感じられるため解約した。
今後、DELLから性能がよい製品がでても、このような応対であるなら購入は難しい。
2009年10月27日火曜日
2009年10月21日水曜日
ベクトル
【サンプルソース】
public class Vector
{
float x;
float y;
float z;
Vector(float x,float y,float z)
{
this.x = x;
this.y = y;
this.z = z;
}
//加算
public Vector add(Vector v){
return
new Vector(
this.x + v.x,
this.y + v.y,
this.z + v.z
);
}
//ベクトルを反転する
public Vector getInvert()
{
return
new Vector(
-x,
-y,
-z
);
}
// 倍
public Vector times(float n){
return
new Vector(
n * this.x,
n * this.y,
n * this.z
);
}
//単位ベクトル化
Vector unit()
{
//単位ベクトルとは長さが1のベクトルのこと。
float len = (float)(1 / len());
return new Vector(
x *= len,
y *= len,
z *= len
);
}
// 長さ
float len()
{
return (float)Math.sqrt(x*x + y*y + z*z);
}
//内積
static float getDot(Vector a,Vector b)
{
//内積を取るとベクトルとベクトルのなす角度が求まる。
return (
a.x * b.x +
a.y * b.y +
a.z * b.z
);
}
//外積
static Vector getCross(Vector a,Vector b)
{
//外積は主に面に垂直な法線ベクトルを求めるために使用する。
return new Vector(
a.y * b.z - a.z * b.y,
a.z * b.x - a.x * b.z,
a.x * b.y - a.y * b.x
);
}
public String toString(){
StringBuffer sbf = new StringBuffer();
// sbf.append("(x,y,z )>>>(" );
sbf.append("(" );
sbf.append(x);
sbf.append(",");
sbf.append(y);
sbf.append(",");
sbf.append(z);
sbf.append(")");
return sbf.toString();
}
}
public class test01 {
public static void main(String[] args) {
Vector a = new Vector(1,-3,2);
Vector b = new Vector(-1,2,3);
Vector c = new Vector(3,-4,1);
Vector d = new Vector(2,-3,1);
Vector v = new Vector(1,1,0);
Vector u = new Vector(1,1,(float)Math.sqrt(2d));
int k = 5;
System.out.printf( "%s + %s - %s = %s \n",a,b,c,a.add(b).add(c.getInvert()));
System.out.printf( "%d%s = %s \n",k,a,a.times(k));
System.out.printf( "%s の長さは、 %s \n",d,d.len());
System.out.printf( "%s と %s の内積は、%s \n",v,u,Vector.getDot(v,u));
System.out.printf( "%s と %s の外積は、%s \n",v,u,Vector.getCross(v,u));
}
}
【実行結果】
2009年10月13日火曜日
2009年10月2日金曜日
複数のテクスチャー画像を貼れるように 機能を追加してみることにした。
簡単な3Dオブジェクト表示のアップレットに
複数のテクスチャー画像を貼れるように
機能を追加してみることにした。
プログラム自身の追加変更は、割と簡単にできた。
まず、ポリゴンクラスを追加して
画像の対応づけを行うようにしてみた。
データ追加(uv座標と3D座標の対応づけ)が
思ったよりうまくいかず時間がかかってしまった。
(なんか計算どおりにいかないので、とりあえず試行錯誤状態ですすめた。)
いくつか課題はまだあるもののとりあえず思っていたものは作成できた。
複数のテクスチャー画像を貼れるように
機能を追加してみることにした。
プログラム自身の追加変更は、割と簡単にできた。
まず、ポリゴンクラスを追加して
画像の対応づけを行うようにしてみた。
データ追加(uv座標と3D座標の対応づけ)が
思ったよりうまくいかず時間がかかってしまった。
(なんか計算どおりにいかないので、とりあえず試行錯誤状態ですすめた。)
いくつか課題はまだあるもののとりあえず思っていたものは作成できた。
2009年9月29日火曜日
テクスチャーマッピング(平行にマッピングしてみた。)
お遊びでJAVAアプレットを作成してみた。
以前、作成したものに少しばかり追加修正してみた。
内容は、簡単な3Dオブジェにテクスチャーマッピングを
施してみた。
以前、作成したものに少しばかり追加修正してみた。
内容は、簡単な3Dオブジェにテクスチャーマッピングを
施してみた。
2009年7月20日月曜日
ブートとプロテクトモード
[boot.asm]
1 [org 0]
2 00000000 EA[0500]C007 jmp 07C0h:start
3
4 start:
5 00000005 8CC8 mov ax, cs
6 00000007 8ED8 mov ds, ax
7 00000009 8EC0 mov es, ax
8
9 0000000B B800B8 mov ax, 0xB800
10 0000000E 8EC0 mov es, ax
11 00000010 BF0000 mov di, 0
12 00000013 A1[4000] mov ax, word [msgBack]
13 00000016 B9FF07 mov cx, 0x7FF
14 paint:
15 00000019 268905 mov word [es:di], ax
16 0000001C 81C70200 add di,2
17 00000020 49 dec cx
18 00000021 75F6 jnz paint
19 read:
20 00000023 B80010 mov ax, 0x1000 ; ES:BX=1000:0000
21 00000026 8EC0 mov es, ax
22 00000028 BB0000 mov bx, 0
23
24 0000002B B402 mov ah, 2 ; ディスクにあるデータをes:bxのアドレスに
25 0000002D B001 mov al, 1 ; 1セクタを読み込む。
26 0000002F B500 mov ch, 0 ; 0番目のCylinder
27 00000031 B102 mov cl, 2 ; 2番目のセクタから読み込み始める。
28 00000033 B600 mov dh, 0 ; Head=0
29 00000035 B200 mov dl, 0 ; Drive=0 A:ドライブ
30 00000037 CD13 int 0x13 ; Read!
31
32 00000039 72E8 jc read ; エラーになれば、やり直し。
33
34 0000003B EA00000010 jmp 0x1000:0000 ; kernel.binが位置するところにジャンプする。
35
36 00000040 2E67 msgBack db '.', 0x67
37
38 00000042 00times 510-($-$$) db 0
39 000001FE 55AA dw 0AA55h
[kernel.asm]
1 [org 0]
2 [bits 16]
3
4 start:
5 00000000 8CC8 mov ax,cs ; CSには0x1000が入っている
6 00000002 8ED8 mov ds,ax
7 00000004 31C0 xor ax,ax
8 00000006 8ED0 mov ss,ax
9
10 00000008 FA cli ;割り込み禁止状態にする
11
12 00000009 0F0116[7E00] lgdt [gdtr] ;GDTR値をロードする
13
14 0000000E 0F20C0 mov eax, cr0 ;CR0のPEビットを
15 00000011 660D01000000 or eax, 0x00000001 ;1にセットし、
16 00000017 0F22C0 mov cr0, eax ;プロテクトモードに移行する
17
18 0000001A EB00 jmp $+2
19 0000001C 90 nop
20 0000001D 90 nop
21
22 0000001E 66 db 0x66 ; operand prefix
23 0000001F 67 db 0x67 ; address prefix
24 00000020 EA db 0xEA ; JMP命令
25 00000021 [27000000] dd PM_Start
26 00000025 0800 dw SysCodeSelector
27
28 ;-------------------------------------------------------;
29 ;*********** ここからProtected Modeです。***************;
30 ;-------------------------------------------------------;
31 [bits 32]
32
33 PM_Start:
34 00000027 66BB1000 mov bx, SysDataSelector
35 0000002B 8EDB mov ds, bx
36 0000002D 8EC3 mov es, bx
37 0000002F 8EE3 mov fs, bx
38 00000031 8EEB mov gs, bx
39 00000033 8ED3 mov ss, bx
40
41 00000035 31C0 xor eax, eax
42 00000037 66B81800 mov ax, VideoSelector
43 0000003B 8EC0 mov es, ax
44 0000003D BF54060000 mov edi, 80*2*10+2*10
45 00000042 3E8D35[65000000] lea esi, [ds:msgPMode]
46 00000049 E802000000 call printf
47
48 0000004E EBFE jmp $
49
50 ;-----------------------------------------;
51 ;*************Sub Routines****************;
52 ;-----------------------------------------;
53 printf:
54 00000050 50 push eax
55
56 printf_loop:
57 00000051 08C0 or al, al
58 00000053 740E jz printf_end
59 00000055 8A06 mov al, byte [esi]
60 00000057 268807 mov byte [es:edi], al
61 0000005A 47 inc edi
62 0000005B 26C60706 mov byte [es:edi], 0x06
63 0000005F 46 inc esi
64 00000060 47 inc edi
65 00000061 EBEE jmp printf_loop
66
67 printf_end:
68 00000063 58 pop eax
69 00000064 C3 ret
70
71 00000065 57652061726520696E- msgPMode db "We are in Protected Mode", 0
72 0000006E 2050726F7465637465-
73 00000077 64204D6F646500
74
75 ;------------------------------------------;
76 ;*********** GDT Table ********************;
77 ;------------------------------------------;
78 gdtr:
79 0000007E 1F00 dw gdt_end - gdt - 1 ; GDTのlimit 0xA4 - 0x84 - 0x01 = 0x1f
80 00000080 [84000100] dd gdt+0x10000 ; GDTのベースアドレス 0x10000 + 0x84 = 0x10084
81
82 gdt:
83 00000084 0000 dw 0 ; limit 0~15ビット
84 00000086 0000 dw 0 ; ベースアドレスの下位2バイト
85 00000088 00 db 0 ; ベースアドレスの16~23ビット
86 00000089 00 db 0 ; Type
87 0000008A 00 db 0 ; limit 16~19 ビット、フラグ
88 0000008B 00 db 0 ; ベースアドレスの31~24ビット
89
90 ; コードセグメント・ディスクリプタ
91 SysCodeSelector equ 0x08
92 0000008C FFFF dw 0xFFFF ; limit:0xFFFF
93 0000008E 0000 dw 0x0000 ; base 0~15ビット
94 00000090 01 db 0x01 ; base 16~23ビット
95 00000091 9A db 0x9A ; P:1, DPL:0, Code, non-conforming, readable
96 00000092 CF db 0xCF ; G:1, D:1, limit 16~19ビット:0xF
97 00000093 00 db 0x00 ; base 24~32ビット
98
99 ; データセグメント・ディスクリプタ
100 SysDataSelector equ 0x10
101 00000094 FFFF dw 0xFFFF ; limit 0xFFFF
102 00000096 0000 dw 0x0000 ; base 0~15ビット
103 00000098 01 db 0x01 ; base 16~23ビット
104 00000099 92 db 0x92 ; P:1, DPL:0, data, expand-up, writable
105 0000009A CF db 0xCF ; G:1, D:1, limit 16~19ビット:0xF
106 0000009B 00 db 0x00 ; base 24~32ビット
107
108 ; ビデオセグメント・ディスクリプタ
109 VideoSelector equ 0x18
110 0000009C FFFF dw 0xFFFF ; limit 0xFFFF
111 0000009E 0080 dw 0x8000 ; base 0~15ビット
112 000000A0 0B db 0x0B ; base 16~23ビット
113 000000A1 92 db 0x92 ; P:1, DPL:0, data, expand-up, writable
114 000000A2 40 db 0x40 ; G:0, D:1, limit 16~19ビット:0
115 000000A3 00 db 0x00 ; base 24~32ビット
116 gdt_end:
117 ;------------------------------------------------------------------------
118 ;------------------------------------------------------------------------
補足説明
1) Pcに電源が入った後、BIOSに記録されているプログラムを実行し、いろいろな処理を行い、最後にはディスクの
最初の512バイト(1セクタ)を読み込みRAMの0x7c00番地にコピーする。
2) 一般的に0x7c00番地は0x07c0:0000、0x0000:7c00、0x0700:0c00など、たくさんの方法で表現できます。ここでの
0x07c00番地を物理アドレス(Physical Address)と呼び、0x07c0:00で表現されたものを論理アドレス(Logical Address)
と呼びます。
<例>リアルモードでのアドレス指定
0x7c0:0000は、以下のように計算される。
0x7c00 + 0x0000 = 0x7c00 = 0x07c00 変換するときにはセグメントにある値に16を掛け算して
(16進数で左側に1桁シフト)、そこにオフセットを加えます。
3) Jmp 0x07C0:start実行後、CSには、0x07c0が入り、IPに0x05が入る状態になる。
4) CS、DS、ESなどのセグメントレジスタに値を入れるときには、必ず、値をax,bxなどの汎用レジスタに1回入れてから
CS、DS、ESに入れなければならない。
5) 0xB800ではじまるアドレスは、一般のRAMとはちょっと違う領域です。
0xB800:0000番地から0xB800:FFFF番地の領域は、カラーテキストモードで、
モニターで横80個、縦25個の文字を表し、文字数は、合計2000字(16進数で0x7D0)。
+---------------------------+
| 拡張メモリ領域 |
| (1MB以上) |
+---------------------------+ FFFF:FFFF
| ROM BIOS 領域 |
| |
+---------------------------+ C000:0000
| カラーテキストモード |
| ビデオメモリ |
+---------------------------+ B800:0000
| 白黒テキストモード |
| ビデオメモリ |
+---------------------------+ B000:0000
| グラフィックモード |
| ビデオメモリ |
+---------------------------+ A000:0000
カラーテキストモードでは、文字を表すのに2バイト使用する。
最初のバイトがASCIIコードとなり、次のバイトが(上位4ビット)背景色、(下位4ビット)文字色となる。
色指定は、
0x0 黒
0x1 青
0x2 緑
0x3 空色
0x4 赤
0x5 紫
0x6 ブラウン
0x7 白
となり、最上位ビットを1にすると文字が点滅するようになる。
6) MBRの1番後ろの1ワードに0xAA55の値があると、MBRなのは確かであるという判断ができる。
7) ディスクからの読み込み、ディスクへの書き込み、セクタのベリファイ、およびシーク
AH = 0x02; (読み込み時)
AH = 0x03; (書き込み時) フロッピーディスクの場合
AH = 0x04; (ベリファイ時) ・シリンダは片面に80本(0番~79番まであります。
AH = 0x0c; (シーク時) ・セクタは各シリンダ内に18個(1番~18番まで)あります。
AL = 処理するセクタ数; (連続したセクタを処理できる) ・ヘッドは2つ(0番~1番)
CH = シリンダ番号 & 0xff; 1枚のディスクには80シリンダあって、ヘッドは合計2つあって、
CL = セクタ番号(bit0-5) | (シリンダ番号 & 0x300) >> 2; さらにそれぞれ18セクタあって、しかも1セクタは、512バイトなので、
DH = ヘッド番号; 80x2x18x512=1,474,560バイト=1,440KB
DL = ドライブ番号;
ES:BX = バッファアドレス; (ベリファイ時、シーク時にはこれは参照しない) バッファアドレスは、メモリのどこへ読む込むか、それを表す番地のこと。
戻り値:
FLAGS.CF == 0 : エラーなし、AH == 0
FLAGS.CF == 1 : エラーあり、AHにエラーコード(リセットファンクションと同じ)
補足:
処理するセクタ数は0x01~0xffの範囲で指定 (0x02以上を指定するときは、連続処理できる条件があるかもしれないので注意 -- FDの場合は、たぶん、複数のトラックにはまたがれないし、64KB境界をこえてもいけない、だと思います)
セクタ番号は0x01~0xffの範囲で指定 (FDの場合は0x01~0x12)
シリンダ番号は0x000~0x3ffの範囲で指定 (FDの場合は0x00~0x4f)
ヘッド番号は0x00~0xffの範囲で指定 (FDの場合は0x00~0x01)
シークしてからアクセスしなければいけないというわけではない
HDDへのアクセスの場合、BIOSはパーティションを理解せず、ハード的に1台のデバイスを1ドライブとして扱う事に注意すること。パーティション処理が必要なら自分でやるのだ。
BIOSのせいだったかどうか忘れましたが、FDDのブートセクタをリードするとなぜか0x03~0x0aの8バイトの内容だけが正しく読み込まれません(変なごみが入っている)。I/Oを自分で制御してFDCをコントロールしたときはこんな変なことは起きません。
8) 保護モードでアドレスを指定するためには、リアルモードから保護モードに切り替える前に前もって
一つのテーブル(GDT:Global Descriptor Table)を用意しねければならない。メモリのエリア内の中の
どこに記述してもよい。
CPUにはGDTRというレジスタがあります。このレジスタは48ビットの大きさを持っています。その中で、最初の16ビットには、
このプログラムで使うGDTの大きさが入り、残り32ビットにはGDTのスタートアドレスが物理アドレスの形で入ります。
GDTRに値をセットするには、LGDT命令文を使います。
<例>
12行目 lgdt [gdtr] ;GDTR値をロードする
78行目 gdtr:
79行目 dw gdt_end - gdt - 1 ; GDTのlimit 0xA4 - 0x84 - 0x01 = 0x1f(24バイト)
80行目 dd gdt+0x10000 ; GDTのベースアドレス 0x10000 + 0x84 = 0x10084
9) リアルモード命令語が残っている状態でプログラムが進行されると、次の命令語からは保護モードで
リアルモードの命令語を実行させることになっていて問題になってしまうので、ユニットに残っている命令を
消すJMP命令を使用する
IA32のA20ゲートについて
A20ゲートについて、ちょっと見てみよう。
適当に、ここでメモして後で、整理してHPにアップするつもり
(ほとんど書籍『作りながら学ぶOSカーネル』の内容だけど
この本、日本語がちょっと変でよみづらいのと
誤植が多いのが欠点だなぁ。内容は良いけど)
■アドレス指定について
・8086時代
CPUのアドレスラインは0番~19番までの20本、レジスタは16ビット
0x0000:0000~0xffff:ffffの範囲で、物理アドレスで
示すと、0x00000~0x10FFEF(0xffff0 + 0xffff)となる。
0x10FFEFは、2進数で、1 0000 1111 1111 1110 1111となる。
アドレスラインが20本なので、最上位ビットを除いた
0000 1111 1111 1110 1111(16進数では、0xffef)となる。
要するに8086では、アドレス指定(セグメントとオフセット)を使用し
1MBを超えた場合、0番地からになってしまう。
・80286時代以降
8086との互換を可能にする為に、A20に、当時のキーボートコントローラチップ
である8042の1つのピンとともにANDゲートで繋いでいる。
1MB目を指定した場合、
A20ゲートがOFFだと
1MB = 1024x1024 = 0x10 0000 = 1 0000 0000 0000 0000 0000[2進数]
常に20番目が0になって次のようになる。
(ここでは最上位ビットの1が0になってしまう)
0 0000 0000 0000 0000 0000[2進数] = 0
A20ゲートがONだと、A20の値がAND演算されて
(ここでは最上位ビットの1と1がAND演算されて1になる)
1 0000 0000 0000 0000 0000[2進数] = 1MB
32ビットで、1Mバイト以上のアドレス指定を正常に
行うには、常にA20ゲートをONにしなければならない。
[参考書籍]
はじめて読む486、OS自作入門、作りながら学ぶOSカーネル、
適当に、ここでメモして後で、整理してHPにアップするつもり
(ほとんど書籍『作りながら学ぶOSカーネル』の内容だけど
この本、日本語がちょっと変でよみづらいのと
誤植が多いのが欠点だなぁ。内容は良いけど)
■アドレス指定について
・8086時代
CPUのアドレスラインは0番~19番までの20本、レジスタは16ビット
0x0000:0000~0xffff:ffffの範囲で、物理アドレスで
示すと、0x00000~0x10FFEF(0xffff0 + 0xffff)となる。
0x10FFEFは、2進数で、1 0000 1111 1111 1110 1111となる。
アドレスラインが20本なので、最上位ビットを除いた
0000 1111 1111 1110 1111(16進数では、0xffef)となる。
要するに8086では、アドレス指定(セグメントとオフセット)を使用し
1MBを超えた場合、0番地からになってしまう。
・80286時代以降
8086との互換を可能にする為に、A20に、当時のキーボートコントローラチップ
である8042の1つのピンとともにANDゲートで繋いでいる。
1MB目を指定した場合、
A20ゲートがOFFだと
1MB = 1024x1024 = 0x10 0000 = 1 0000 0000 0000 0000 0000[2進数]
常に20番目が0になって次のようになる。
(ここでは最上位ビットの1が0になってしまう)
0 0000 0000 0000 0000 0000[2進数] = 0
A20ゲートがONだと、A20の値がAND演算されて
(ここでは最上位ビットの1と1がAND演算されて1になる)
1 0000 0000 0000 0000 0000[2進数] = 1MB
32ビットで、1Mバイト以上のアドレス指定を正常に
行うには、常にA20ゲートをONにしなければならない。
[参考書籍]
はじめて読む486、OS自作入門、作りながら学ぶOSカーネル、
2009年7月19日日曜日
読売新聞に気になる(セカンドライフの)記事が・・・・
記事の内容は、企業や団体の利用を想定した会議サービス(現在開発中)を
行う予定らしい。
セカンドライフは、以前、参加してみたことがあったが、
処理が重く、やたらと異常終了するうえ
何がおもしろいのかがわからなかった為
徐々に、参加しなくなっていた。(今は、改善されているのだろうか?)
いろいろと検索してみると
セカンドライフは、メタバースというカテゴリに、属するらしい。
メタバース (Metaverse)とはインターネット上に存在する
電子三次元空間である。[ウィキペディアより]
自分が知らないうちに、メタバースのネットサービスが
多く行われているようだ。ただどこも成功しているとは
言いがたい状況で、閉鎖してしまったところもあるようだ。
そんな中で、興味深いものがあった。
OpenSimと呼ばれているもので、セカンドライフのクライアントを
使用し、独自のサーバーを構築できるオープンソースの
プロダクトである。ソース自体は、c#で記述されている
らしい。時間に余裕ができたら少しさわってみたいと思う。
[セカンドライフのページ]http://www.sec-life.com/
[THE SECOND TIMES ページ]http://www.secondtimes.net/
[OpenSim]http://opensimulator.org/wiki/Main_Page
行う予定らしい。
セカンドライフは、以前、参加してみたことがあったが、
処理が重く、やたらと異常終了するうえ
何がおもしろいのかがわからなかった為
徐々に、参加しなくなっていた。(今は、改善されているのだろうか?)
いろいろと検索してみると
セカンドライフは、メタバースというカテゴリに、属するらしい。
メタバース (Metaverse)とはインターネット上に存在する
電子三次元空間である。[ウィキペディアより]
自分が知らないうちに、メタバースのネットサービスが
多く行われているようだ。ただどこも成功しているとは
言いがたい状況で、閉鎖してしまったところもあるようだ。
そんな中で、興味深いものがあった。
OpenSimと呼ばれているもので、セカンドライフのクライアントを
使用し、独自のサーバーを構築できるオープンソースの
プロダクトである。ソース自体は、c#で記述されている
らしい。時間に余裕ができたら少しさわってみたいと思う。
[セカンドライフのページ]http://www.sec-life.com/
[THE SECOND TIMES ページ]http://www.secondtimes.net/
[OpenSim]http://opensimulator.org/wiki/Main_Page
2009年6月12日金曜日
2009年2月14日土曜日
JavaVMについて
作成者:Naozary
JavaVMについて1.Javaの処理系と実行系
Javaはオブジェクト指向かつ機種非依存と いう2つの特徴をもったプログラミング言語です。JDK自身は処理系と実行系が分かれているので、その片方のみを使用するといったことも可能です。たとえ ば、オブジェクト指向でない機種非依存な開発を行う、というような組み合わせが考えられます。実行系だけを用意することによって他機種で開発したJava アプリケーションを実行することが可能になります。皆さんが知っているように、クラスファイルに適合したJavaコードを生成する処理系を作成すれば、 Java以外のコードで書かれたプログラムが既存のJava処理系と併用できます。JDKのみで開発を行う場合、Javaのプログラムは以下の2つの フェーズを経て実行されます。 |
<例1>
>type HelloWorld.java public class HelloWorld { public static void main(String[] args){ System.out.println("Hello World"); } } >javac HelloWorld.java (1)ソースファイルを中間言語形式へ変換 >java HelloWorld (2)クラスファイルを専用の実行プログラムで実行 Hello World |
通常のコンパイラは、ある特定のCPUの命令コードを出力するのですが、Javaコンパイラは、Java仮想マシンと呼ばれる仮想的なCPU命令を出力します。 |
2.クラスファイルのフォーマット Javaコンパイラは、クラスファイルを出力します。一般的に、プログラムはコードとデータで成り立っていますので、当然、クラスファイルにはデータも一緒に含まれています。そのほかにデバッグ字に役立つ情報も含まれてる場合があります。Javaバイトコードの規格書によるとクラスファイルのフォーマットは、大きく分けてファイルヘッダ、定数プール、クラスの情報、インタフェースの情報、フィールドの情報、メソッドの情報、ファイル属性情報から成り立っています。JavaVMは、このクラスファイルを読み込んで実行します。(ここでは、JavaVMとは、java.exeのことであると定義しておけばOKです。) |
<HelloWorld.classダンプリスト>
00000000 CA FE BA BE 00 00 00 32-00 1D 0A 00 06 00 0F 09 .......2........ 00000010 00 10 00 11 08 00 12 0A-00 13 00 14 07 00 15 07 ................ 00000020 00 16 01 00 06 3C 69 6E-69 74 3E 01 00 03 28 29 .....<init>...() 00000030 56 01 00 04 43 6F 64 65-01 00 0F 4C 69 6E 65 4E V...Code...LineN 00000040 75 6D 62 65 72 54 61 62-6C 65 01 00 04 6D 61 69 umberTable...mai 00000050 6E 01 00 16 28 5B 4C 6A-61 76 61 2F 6C 61 6E 67 n...([Ljava/lang 00000060 2F 53 74 72 69 6E 67 3B-29 56 01 00 0A 53 6F 75 /String;)V...Sou 00000070 72 63 65 46 69 6C 65 01-00 0F 48 65 6C 6C 6F 57 rceFile...HelloW 00000080 6F 72 6C 64 2E 6A 61 76-61 0C 00 07 00 08 07 00 orld.java....... 00000090 17 0C 00 18 00 19 01 00-0B 48 65 6C 6C 6F 20 57 .........Hello W 000000A0 6F 72 6C 64 07 00 1A 0C-00 1B 00 1C 01 00 0A 48 orld...........H 000000B0 65 6C 6C 6F 57 6F 72 6C-64 01 00 10 6A 61 76 61 elloWorld...java 000000C0 2F 6C 61 6E 67 2F 4F 62-6A 65 63 74 01 00 10 6A /lang/Object...j 000000D0 61 76 61 2F 6C 61 6E 67-2F 53 79 73 74 65 6D 01 ava/lang/System. 000000E0 00 03 6F 75 74 01 00 15-4C 6A 61 76 61 2F 69 6F ..out...Ljava/io 000000F0 2F 50 72 69 6E 74 53 74-72 65 61 6D 3B 01 00 13 /PrintStream;... 00000100 6A 61 76 61 2F 69 6F 2F-50 72 69 6E 74 53 74 72 java/io/PrintStr 00000110 65 61 6D 01 00 07 70 72-69 6E 74 6C 6E 01 00 15 eam...println... 00000120 28 4C 6A 61 76 61 2F 6C-61 6E 67 2F 53 74 72 69 (Ljava/lang/Stri 00000130 6E 67 3B 29 56 00 21 00-05 00 06 00 00 00 00 00 ng;)V.!......... 00000140 02 00 01 00 07 00 08 00-01 00 09 00 00 00 1D 00 ................ 00000150 01 00 01 00 00 00 05 2A-B7 00 01 B1 00 00 00 01 .......*........ 00000160 00 0A 00 00 00 06 00 01-00 00 00 01 00 09 00 0B ................ 00000170 00 0C 00 01 00 09 00 00-00 25 00 02 00 01 00 00 .........%...... 00000180 00 09 B2 00 02 12 03 B6-00 04 B1 00 00 00 01 00 ................ 00000190 0A 00 00 00 0A 00 02 00-00 00 04 00 08 00 05 00 ................ 000001A0 01 00 0D 00 00 00 02 00-0E ......... |
<ダンプリストの解析>
00000000: Magic number '0xcafebabe' confirmed. 00000004: Java version 50.0 | 【ヘッダ】 [00000000] Classファイルは、必ずこの値になる。 [00000004] 50.0の値は、バージョン1.6を表す(45.0の値は、JDK1.02を表す) |
00000008: Below are 29 of Constastant(s) 0000000a: Const(1), Methodref class 6 name-and-type 15 0000000f: Const(2), Fieldref class 16 name-and-type 17 00000014: Const(3), String 18 00000017: Const(4), Methodref class 19 name-and-type 20 0000001c: Const(5), Class name 21 0000001f: Const(6), Class name 22 00000022: Const(7), UTF8 "<init>" 0000002b: Const(8), UTF8 "()V" 00000031: Const(9), UTF8 "Code" 00000038: Const(10), UTF8 "LineNumberTable" 0000004a: Const(11), UTF8 "main" 00000051: Const(12), UTF8 "([Ljava/lang/String;)V" 0000006a: Const(13), UTF8 "SourceFile" 00000077: Const(14), UTF8 "HelloWorld.java" 00000089: Const(15), NameAndType name 7 descriptor 8 0000008e: Const(16), Class name 23 00000091: Const(17), NameAndType name 24 descriptor 25 00000096: Const(18), UTF8 "Hello World" 000000a4: Const(19), Class name 26 000000a7: Const(20), NameAndType name 27 descriptor 28 000000ac: Const(21), UTF8 "HelloWorld" 000000b9: Const(22), UTF8 "java/lang/Object" 000000cc: Const(23), UTF8 "java/lang/System" 000000df: Const(24), UTF8 "out" 000000e5: Const(25), UTF8 "Ljava/io/PrintStream;" 000000fd: Const(26), UTF8 "java/io/PrintStream" 00000113: Const(27), UTF8 "println" 0000011d: Const(28), UTF8 "(Ljava/lang/String;)V" | 【コンスタントプール】 [00000008] コンスタントプールエントリー数。 [0000000a]-[00000134] コンスタントプールエントリ |
Belows are class information 00000135: Access Flags = 0x21 (Public, Syhnchronized) 00000137: This Class #5 00000139: Super Class #6 0000013b: 0 Interface(s) 0000013d: 0 Field(s) 0000013f: 2 Method(s) | 【クラス情報】 [00000135] クラス属性 [00000137] クラスの名前定義 [00000139] 親クラスの名前定義 [0000013b] インターフェース数 [0000013d] フィールド数 [0000013f] メソッド数(mainとコンストラクタで2個) |
Method 0: 00000141: Access Flag = 0x0001(Public) 00000143: name #7 00000145: descriptor #8 00000147: 1 method attribute(s): 00000149: name = #9 0000014b: length = 29 0000014f: max Stack 1 00000151: max Locals 1 00000153: code length = 5 00000157: 00000000 2a aload_0 00000158: 00000001 b7 invokespecial #1 0000015b: 00000004 b1 return 0000015c: 0 Exception entrie(s) 0000015e: 1 Code Attribute(s) 00000160: name = #10 00000162: length = 6 0x00 0x01 0x00 0x00 0x00 0x01 | 【メソッド情報】 [00000141] メソッドの属性 [00000143] メソッドの名前定義 <init>はコンストラクタを表す [00000145] 引数と戻り値 ()Vは、引数なし、戻り値なし [00000147] メソッド属性の個数 [00000149] “Code”で命令コードを示す [0000014b] 属性の大きさ29バイト0000014f~0000016b [0000014f] スタックの大きさ [00000151] ローカル変数の大きさ [00000153] コード本体の大きさ [00000157]-[0000015b] Java仮想コード [0000015c] 例外のエントリー数 [0000015e]-[0000016d] コードに対する付加情報。各javaバイトコードとソースコード上の位置を関連づける情報。最初の2バイトが行数で、コード開始、Javaソース行となる。 |
Method 1: 0000016c: Access Flag = 0x0009(Public, Static) 0000016e: name #11 00000170: descriptor #12 00000172: 1 method attribute(s): 00000174: name = #9 00000176: length = 37 0000017a: max Stack 2 0000017c: max Locals 1 0000017e: code length = 9 00000182: 00000000 b2 getstatic #2 00000185: 00000003 12 ldc #3 00000187: 00000005 b6 invokevirtual #4 0000018a: 00000008 b1 return 0000018b: 0 Exception entrie(s) 0000018d: 1 Code Attribute(s) 0000018f: name = #10 00000191: length = 10 0x00 0x02 0x00 0x00 0x00 0x04 0x00 0x08 0x00 0x05 | 省略 |
0000019f: 1 class file attribute(s) 000001a1: name #13 000001a3: length = 2 000001a7: sourceFile = #14 | 【クラス属性情報】 |
ダンプリストの解析にある太字部分がメソッドのアセンブラを示しているが、この部分のみの解析であれば、javapコマンドでも結果が得られる。 |
<例2>
>javap -c HelloWorld Compiled from "HelloWorld.java" public class HelloWorld extends java.lang.Object{ public HelloWorld(); Code: 0: aload_0 ① 1: invokespecial #1; //Method java/lang/Object."<init>":()V ② 4: return ③ public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; ④ 3: ldc #3; //String Hello World ⑤ 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V ⑥ 8: return ⑦ } |
3.アセンブラプログラムの解読(例2のアセンブラを解説する。) ①0番目のローカル変数からオブジェクト参照を取り出してスタックに積む。0番目の変数には実行中のオブジェクトへのポインタ(this)が格納されており、メソッドの呼び出しではこれを第1引数として使用する。 ②スーパークラスの<init>メソッドを呼び出すコード。JavaVMは、オブジェクト指向CPUなので、マシン語レベルでオブジェクト指向のクラスという概念が出てきます。 ③メソッド呼び出しを終了する。 ④クラスフィールドの値を、オペランドスタックに積む。 ⑤オペランドの定数をオペランドスタックに積む。 ⑥インスタンスメソッドを呼び出す。 ⑦メソッド呼び出しを終了する。 |
・Java言語のコンストラクタは、JavaVMの<init>メソッドになります。
・①~③は、インスタンス初期化メソッドで、インスタンスがヒープに割り当てられた直後に実行されるJavaVMメソッドです。
4.JavaVMメモリ構成
4.1 クラスローダについて
JavaVMは、クラスファイルを読み込んでそれを実行します。JavaVMにクラスファイルをロードする方式は、
大きくわけて2つあります。
・システムクラスローダ
VMに元から組み込まれているクラスのローディング機構を使ってクラスをロードするもので、CLASSPATHで指定さ
れた場所からクラスを読み込みます。JavaVM中に一つだけ存在する。
・ユーザクラスローダ
CLASSPATH以外の場所からクラスを読み込むときに使用する。ネットワーク経由、外部ファイル、メモリ上などから
クラスを読み込むことなども可能。JavaVM中に複数の存在が可能。
(実際にユーザクラスローダはJava.lang.ClassLoaderのインスタンスなのでヒープに存在します。)
4.2 メソッドエリアとヒープ
・メソッドエリア
メモリ中のクラスの置き場所。JavaVMはクラスファイルを読み込むと、クラスをメモリに展開します。
・ヒープ
インスタンスの置き場所。メソッドエリアに置かれたクラスのインスタンス生成時にここに置かれる。
4.3 Javaスタックとフレーム
・Javaスタック
スレッドが1つ生成されると、そのスレッドのJavaスタックが1つ生成されます。スレッドとJavaスタッ
クの関係は、常に1対1です。Javaスタックは、フレームを積み上げたものです。
・フレーム
メソッドの作業用メモリのこと。メソッド実行時に、対応するフレームが1つ作られ、終了時に破棄されます。
<例>あるJavaのスレッド(スレッドT)がrun()というメソッドを実行し、MethodC実行中のJavaスタックの状態
4.4 ローカル変数とオペランドスタック
・ローカル変数(JavaVM)
JAVA言語コンパイラがJAVA言語のメソッドを変換してJavaVMのメソッドを生成するとき、Java
言語のローカル変数とメソッド引数をJavaVMのローカル変数に割り当てます。JavaVMのローカル変数は、
名前ではなく、番号で指定されます。この番号は0から始まる整数です。ローカル変数の個数は、コンパイラの最
適化の余地がない場合に、次のように決定される。
JavaVMローカル変数の個数 = Java言語メソッド引数の個数 + Java言語のローカル変数の個数 + 1
+1されているのは、暗黙的に渡されるthisという引数がある為。(インスタンスメソッドの場合のみ)
<例>次のSampleMethod1メソッドをコンパイルすると、ローカル変数のサイズは3になります。まず暗黙
の引数thisで1つ、引数aで1つ、ローカル変数bで1つの合計3つになります。
javapでアセンブラを出力すると
5.JavaVMのマシン語
5.1 メソッドの実行例
JavaVMの使うメモリについてある程度理解できたところで、どのようにそのメモリを使用して
処理を行うかを前頁のSampleMethod1メソッドの部分で見ていきましょう。
(メソッドに対応するフレームをフレームXとする)
(0)実行前
(1)bipush 10
(2)istore_2
(3)iload_1
(4)iload_2
(5)iadd
(6)ireturn
a)スタックからPOPし、それを呼び出し元のオペランドスタックにPUSHする。
b)このカレントメソッドのフレームXが破棄され、呼び出し元のメソッドのフレームが復元され、実行制御が呼び出し元に戻ります。
[参考書籍]
Javaバーチャルマシン
Java Developer 2002/08
登録:
投稿 (Atom)