嘗試寫一個jvm吧
為啥要嘗試寫一個呢,自從工作后,感覺就很少接觸github了,也沒精力去玩啥開源了,但自己還是喜歡學習其他東西,可能多動癥???
嘗試寫一個jvm吧,本次選用語言是rust。
其實我個人也是rust初學者,到現(xiàn)在,仍然只是會一些簡單語法,對于其宏、多線程仍然是跨不過去的門檻,所以本次 只會用一些基礎語法來進行,目前應該java coder和go coder比較多,我本人也是一個java coder,所以這篇文章,仍然是以java coder能夠看懂的情況下來開發(fā)。
目前準備分為這么幾個部分:
- command line processing
- find class file
- parse class file
- implements runtime_data
- instruction set and interpreter
- heap and object
- method invoke
- array and string
- native
- exception
- ...
大概這么幾個步驟,可能沒有看到GC,我這兒想說的是,選rust的原因就在于它是一門無GC語言,當然如果想模仿一下也是可以,無非就是自己實現(xiàn)一套buffer的申請和回收,這個可以考慮,簡單實現(xiàn)難度不大,如果加入動態(tài)GC、安全點啥的就挺有難度了,后面再說趴~
最后要說的就是我估計進度會很慢,畢竟公司是真滴挺卷的,基本只有周末時間來開發(fā)一點點~
命令行處理
預期效果 我可以通過類似java -v 或者 xxx -help的方式看到一些命令, 我的二進制包叫azh, 所以命令如下
./target/debug/azh -h

./target/debug/azh -v

一、環(huán)境準備
主要是一些必備的tracing日志包、env環(huán)境等包的引入
[package]
name?=?"azh"?#?放你自己想要的名字,build時二進制包的名字
version?=?"0.1.0"
edition?=?"2021"
[dependencies]
getopts?=?"0.2.21"
tracing?=?"0.1.37"
tracing-subscriber?=?"0.3.16"
二、主要開發(fā)
2.1 定義Command命令行結(jié)構(gòu)體
#[derive(Debug)]
pub?struct?Command?{
????pub?help_flag:?bool,??
????pub?version_flag:?bool,
????pub?info_flag:?bool,
}
其中三個屬性分別對應命令的help、version、info。
2.2 實現(xiàn)command解析: parse_command()方法
- 獲取命令行參數(shù)
let?args:?Vec<String>?=?env::args().collect();
let?program?=?args[0].clone();
let?mut?opts?=?Options::new();
- 定義參數(shù)的解析方式
let?opts?=?opts
????????.parsing_style(ParsingStyle::StopAtFirstFree)
????????.long_only(true);
opts.optflag("h",?"help",?"Print?help?message");
opts.optflag("v",?"version",?"Print?version?and?exit");
opts.optflag("",?"info",?"Print?info?about?azh-jvm");
rust是標準的函數(shù)式編程,可以在學習過程中慢慢發(fā)現(xiàn)它的美。 上面代碼中有兩個點得注意下:
ParsingStyle::StopAtFirstFree: 解析時剩余參數(shù)不作為標記參數(shù)的一部分
long_only: 為true時允許使用 -xxx
- 對參數(shù)進行匹配
let?matches?=?match?opts.parse(&args[1..])?{
????????Ok(m)?=>?m,
????????Err(err)?=>?{
????????????print_introduction_message(&program,?opts);
????????????panic!("{}",?err.to_string());
????????}
????};
????//?匹配help
????if?matches.opt_present("help")?{
????????command.help_flag?=?true;
????}
????if?matches.opt_present("version")?{
????????command.version_flag?=?true;
????}
????if?matches.opt_present("info")?{
????????command.info_flag?=?true;
????}
rust是門很嚴格的語言,上面的match代碼段就是做一個判斷,如果parse錯誤我們要選擇什么處理方式,rust的特點就是任何代碼,要么success,要么就err,所以當我們考慮了所有的場景后,如果你的代碼build成功,基本就不會出現(xiàn)線上問題。相信java coder很容易遇到npe問題(NullPointerException, 我在公司線上遇到過,一個npe 1塊錢,我們并發(fā)很高,記得那天還是沒有直播帶貨的場景,1s就出現(xiàn)了300來個npe... 當時就請各位同事周會喝奶茶...)
- print_introduction_message() 方法
fn?print_introduction_message(program:?&str,?opts:?&mut?Options)?{
????let?brief?=?format!("Usage:?{}?[-options]?class?[args...]",?program);
????info!("{}",?opts.usage(&brief));
}
impl?Command?{
????pub?fn?print_introduction_message(&self)?{
????????let?args:?Vec<String>?=?env::args().collect();
????????info!(
????????????"------?Usage:?{}?[-options]?class?[args...]?------",
????????????args[0]
????????);
????}
}
上面就基本完成了,最后你只需要
cargo build + cargo fmt 后如果沒有error就構(gòu)建二進制包成功了,最好也不要有waring、一個好的開發(fā)者不應該有任何一個waring出現(xiàn)在屏幕上。
然后通過你的二進制包,輸入./xxx -h的方式就可以復現(xiàn)我們剛才的命令了~
