x64: function calls; http: download_file()
							parent
							
								
									208f67132d
								
							
						
					
					
						commit
						52d25336db
					
				|  | @ -1,6 +1,11 @@ | ||||||
| fn main() { | fn main() { | ||||||
|  | 	println('x64 test') | ||||||
| 	for _ in 0..5 { | 	for _ in 0..5 { | ||||||
| 		println('Hello world from V x64 machine code generator!') | 		println('Hello world from V x64 machine code generator!') | ||||||
| 	} | 	} | ||||||
| 	println('Hello again!') | 	println('Hello again!') | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | fn test_fn() { | ||||||
|  | 	println('test fn') | ||||||
|  | }	 | ||||||
|  |  | ||||||
|  | @ -44,6 +44,7 @@ mut: | ||||||
| 	fn_name_token_idx int // used by error reporting
 | 	fn_name_token_idx int // used by error reporting
 | ||||||
| 	comptime_define string | 	comptime_define string | ||||||
| 	is_used bool // so that we can skip unused fns in resulting C code
 | 	is_used bool // so that we can skip unused fns in resulting C code
 | ||||||
|  | 	//x64_addr i64 // address in the generated x64 binary
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct TypeInst { | struct TypeInst { | ||||||
|  | @ -397,6 +398,9 @@ fn (p mut Parser) fn_decl() { | ||||||
| 	str_args := f.str_args(p.table) | 	str_args := f.str_args(p.table) | ||||||
| 	// Special case for main() args
 | 	// Special case for main() args
 | ||||||
| 	if f.name == 'main__main' && !has_receiver { | 	if f.name == 'main__main' && !has_receiver { | ||||||
|  | 		if p.pref.x64 && !p.first_pass() { | ||||||
|  | 			p.x64.save_main_fn_addr() | ||||||
|  | 		}	 | ||||||
| 		if str_args != '' || typ != 'void' { | 		if str_args != '' || typ != 'void' { | ||||||
| 			p.error_with_token_index('fn main must have no arguments and no return values', f.fn_name_token_idx) | 			p.error_with_token_index('fn main must have no arguments and no return values', f.fn_name_token_idx) | ||||||
| 		} | 		} | ||||||
|  | @ -525,6 +529,12 @@ fn (p mut Parser) fn_decl() { | ||||||
| 		//p.genln('// live_function body end')
 | 		//p.genln('// live_function body end')
 | ||||||
| 		p.genln('pthread_mutex_unlock(&live_fn_mutex);') | 		p.genln('pthread_mutex_unlock(&live_fn_mutex);') | ||||||
| 	} | 	} | ||||||
|  | 	if p.pref.x64 && f.name == 'main__main' && !p.first_pass() { | ||||||
|  | 		p.x64.gen_exit() | ||||||
|  | 	}	 | ||||||
|  | 	if p.pref.x64 && !p.first_pass() { | ||||||
|  | 		p.x64.ret() | ||||||
|  | 	} | ||||||
| 	// {} closed correctly? scope_level should be 0
 | 	// {} closed correctly? scope_level should be 0
 | ||||||
| 	if p.mod == 'main' { | 	if p.mod == 'main' { | ||||||
| 		// println(p.cur_fn.scope_level)
 | 		// println(p.cur_fn.scope_level)
 | ||||||
|  | @ -541,6 +551,7 @@ fn (p mut Parser) fn_decl() { | ||||||
| 	p.check_unused_variables() | 	p.check_unused_variables() | ||||||
| 	p.set_current_fn( EmptyFn ) | 	p.set_current_fn( EmptyFn ) | ||||||
| 	p.returns = false | 	p.returns = false | ||||||
|  | 	 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| [inline] | [inline] | ||||||
|  |  | ||||||
|  | @ -367,7 +367,6 @@ pub fn (v mut V) compile_x64() { | ||||||
| 		v.parse(f, .main) | 		v.parse(f, .main) | ||||||
| 	} | 	} | ||||||
| 	v.x64.generate_elf_footer() | 	v.x64.generate_elf_footer() | ||||||
| 	 |  | ||||||
| }	 | }	 | ||||||
| 
 | 
 | ||||||
| fn (v mut V) generate_init() { | fn (v mut V) generate_init() { | ||||||
|  |  | ||||||
|  | @ -167,7 +167,7 @@ fn (p mut Parser) match_statement(is_expr bool) string { | ||||||
| 		p.gen(')') | 		p.gen(')') | ||||||
| 
 | 
 | ||||||
| 		if p.tok == .arrow { | 		if p.tok == .arrow { | ||||||
| 			p.warn(warn_match_arrow) | 			p.error(warn_match_arrow) | ||||||
| 			p.check(.arrow) | 			p.check(.arrow) | ||||||
| 		}	 | 		}	 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -69,6 +69,8 @@ pub fn (g mut Gen) generate_elf_header() { | ||||||
| 	g.write64(0x1000) // p_align
 | 	g.write64(0x1000) // p_align
 | ||||||
| 	// user code starts here at
 | 	// user code starts here at
 | ||||||
| 	// address: 00070 and a half
 | 	// address: 00070 and a half
 | ||||||
|  | 	g.code_start_pos = g.buf.len | ||||||
|  | 	g.call(0)// call main function, it's not guaranteed to be the first
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn (g mut Gen) generate_elf_footer() { | pub fn (g mut Gen) generate_elf_footer() { | ||||||
|  | @ -87,6 +89,12 @@ pub fn (g mut Gen) generate_elf_footer() { | ||||||
| 	file_size := g.buf.len | 	file_size := g.buf.len | ||||||
| 	g.write64_at(file_size, g.file_size_pos) // set file size 64 bit value
 | 	g.write64_at(file_size, g.file_size_pos) // set file size 64 bit value
 | ||||||
| 	g.write64_at(file_size, g.file_size_pos+8) | 	g.write64_at(file_size, g.file_size_pos+8) | ||||||
|  | 	// call main function, it's not guaranteed to be the first
 | ||||||
|  | 	// we generated call(0) ("e8 0")
 | ||||||
|  | 	// no need to replace "0" with a relative address of the main function
 | ||||||
|  | 	// +1 is for "e8"
 | ||||||
|  | 	// -5 is for "e8 00 00 00 00"
 | ||||||
|  | 	g.write64_at(int(g.main_fn_addr - g.code_start_pos) - 5, g.code_start_pos+1) | ||||||
| 	// Create the binary
 | 	// Create the binary
 | ||||||
| 	f := os.create(g.out_name) or { panic(err) } | 	f := os.create(g.out_name) or { panic(err) } | ||||||
| 	os.chmod(g.out_name, 0775) | 	os.chmod(g.out_name, 0775) | ||||||
|  |  | ||||||
|  | @ -12,8 +12,9 @@ mut: | ||||||
| 	offset i64 | 	offset i64 | ||||||
| 	str_pos []i64 | 	str_pos []i64 | ||||||
| 	strings []string // TODO use a map and don't duplicate strings
 | 	strings []string // TODO use a map and don't duplicate strings
 | ||||||
| 	//str string
 |  | ||||||
| 	file_size_pos i64 | 	file_size_pos i64 | ||||||
|  | 	main_fn_addr i64 | ||||||
|  | 	code_start_pos i64 // location of the start of the assembly instructions
 | ||||||
| 	//string_addr map[string]i64
 | 	//string_addr map[string]i64
 | ||||||
| }	 | }	 | ||||||
| 
 | 
 | ||||||
|  | @ -120,11 +121,29 @@ fn (g mut Gen) cmp(reg Register, size Size, val i64) { | ||||||
| fn abs(a i64) i64 { return if a < 0 { -a } else { a } } | fn abs(a i64) i64 { return if a < 0 { -a } else { a } } | ||||||
| 
 | 
 | ||||||
| fn (g mut Gen) jle(addr i64) { | fn (g mut Gen) jle(addr i64) { | ||||||
|  | 	// Calculate the relative offset to jump to
 | ||||||
|  | 	// (`addr` is absolute address)
 | ||||||
| 	offset := 0xff - int(abs(addr - g.buf.len))-1 | 	offset := 0xff - int(abs(addr - g.buf.len))-1 | ||||||
| 	g.write8(0x7e) | 	g.write8(0x7e) | ||||||
| 	g.write8(offset) | 	g.write8(offset) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | fn (g mut Gen) jl(addr i64) { | ||||||
|  | 	offset := 0xff - int(abs(addr - g.buf.len))-1 | ||||||
|  | 	g.write8(0x7c) | ||||||
|  | 	g.write8(offset) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn (g &Gen) abs_to_rel_addr(addr i64) int { | ||||||
|  | 	return int(abs(addr - g.buf.len))-1 | ||||||
|  | }	 | ||||||
|  | 
 | ||||||
|  | fn (g mut Gen) jmp (addr i64) { | ||||||
|  | 	offset := 0xff - g.abs_to_rel_addr(addr) | ||||||
|  | 	g.write8(0xe9) | ||||||
|  | 	g.write8(offset) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| fn (g mut Gen) mov64(reg Register, val i64) { | fn (g mut Gen) mov64(reg Register, val i64) { | ||||||
| 	match reg { | 	match reg { | ||||||
| 		.rsi { | 		.rsi { | ||||||
|  | @ -137,7 +156,9 @@ fn (g mut Gen) mov64(reg Register, val i64) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn (g mut Gen) call(val int) { | fn (g mut Gen) call(val int) { | ||||||
|  | 	//println('call val=$val')
 | ||||||
| 	g.write8(0xe8) | 	g.write8(0xe8) | ||||||
|  | 	g.write32(val) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn (g mut Gen) syscall() { | fn (g mut Gen) syscall() { | ||||||
|  | @ -146,7 +167,7 @@ fn (g mut Gen) syscall() { | ||||||
| 	g.write8(0x05) | 	g.write8(0x05) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn (g mut Gen) ret() { | pub fn (g mut Gen) ret() { | ||||||
| 	g.write8(0xc3) | 	g.write8(0xc3) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -163,6 +184,10 @@ pub fn (g mut Gen) gen_loop_end(to int, label int) { | ||||||
| 	g.jle(label) | 	g.jle(label) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | pub fn (g mut Gen) save_main_fn_addr() { | ||||||
|  | 	g.main_fn_addr = g.buf.len | ||||||
|  | } | ||||||
|  | 
 | ||||||
| pub fn (g mut Gen) gen_print(s string) { | pub fn (g mut Gen) gen_print(s string) { | ||||||
| 	g.strings << s + '\n' | 	g.strings << s + '\n' | ||||||
| 	//g.string_addr[s] = str_pos
 | 	//g.string_addr[s] = str_pos
 | ||||||
|  | @ -175,6 +200,13 @@ pub fn (g mut Gen) gen_print(s string) { | ||||||
| 	g.syscall() | 	g.syscall() | ||||||
| }	 | }	 | ||||||
| 
 | 
 | ||||||
|  | pub fn (g mut Gen) gen_exit() { | ||||||
|  | 	// Return 0
 | ||||||
|  | 	g.mov(.edi, 0) // ret value
 | ||||||
|  | 	g.mov(.eax, 60) | ||||||
|  | 	g.syscall() | ||||||
|  | } | ||||||
|  | 
 | ||||||
| fn (g mut Gen) mov(reg Register, val int) { | fn (g mut Gen) mov(reg Register, val int) { | ||||||
| 	match reg { | 	match reg { | ||||||
| 		.eax { g.write8(0xb8) } | 		.eax { g.write8(0xb8) } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,14 @@ | ||||||
|  | // Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
 | ||||||
|  | // Use of this source code is governed by an MIT license
 | ||||||
|  | // that can be found in the LICENSE file.
 | ||||||
|  | 
 | ||||||
|  | module http | ||||||
|  | 
 | ||||||
|  | import os | ||||||
|  | 
 | ||||||
|  | fn download_file(url, out string) bool { | ||||||
|  | 	s := http.get(url) or { return false } | ||||||
|  | 	os.write_file(out, s.text) | ||||||
|  | 	return true | ||||||
|  | 	//download_file_with_progress(url, out, empty, empty)
 | ||||||
|  | } | ||||||
|  | @ -5,57 +5,53 @@ | ||||||
| module http | module http | ||||||
| 
 | 
 | ||||||
| type downloadfn fn (written int) | type downloadfn fn (written int) | ||||||
| type download_finished_fn fn ()  | type download_finished_fn fn () | ||||||
| 
 | 
 | ||||||
| /*  | /* | ||||||
| struct DownloadStruct { | struct DownloadStruct { | ||||||
| mut:  | mut: | ||||||
| 	stream  voidptr | 	stream  voidptr | ||||||
| 	written int | 	written int | ||||||
| 	cb      downloadfn | 	cb      downloadfn | ||||||
| } | } | ||||||
| */  | */ | ||||||
| 
 | 
 | ||||||
| fn download_cb(ptr voidptr, size, nmemb size_t, userp voidptr)  {  | fn download_cb(ptr voidptr, size, nmemb size_t, userp voidptr)  { | ||||||
| /*  | /* | ||||||
| 	mut data := &DownloadStruct(userp) | 	mut data := &DownloadStruct(userp) | ||||||
| 	written := C.fwrite(ptr, size, nmemb, data.stream)  | 	written := C.fwrite(ptr, size, nmemb, data.stream) | ||||||
| 	data.written += written  | 	data.written += written | ||||||
| 	data.cb(data.written)  | 	data.cb(data.written) | ||||||
| 	//#data->cb(data->written); // TODO 
 | 	//#data->cb(data->written); // TODO
 | ||||||
| 	return written  | 	return written | ||||||
| */  | */ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn download_file_with_progress(url, out string, cb downloadfn, cb_finished fn()) {    | fn download_file_with_progress(url, out string, cb downloadfn, cb_finished fn()) { | ||||||
| /*  | /* | ||||||
| 	curl := C.curl_easy_init() | 	curl := C.curl_easy_init() | ||||||
| 	if isnil(curl) { | 	if isnil(curl) { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	cout := out.str  | 	cout := out.str | ||||||
| 	fp := C.fopen(cout, 'wb')  | 	fp := C.fopen(cout, 'wb') | ||||||
| 	C.curl_easy_setopt(curl, CURLOPT_URL, url.str)  | 	C.curl_easy_setopt(curl, CURLOPT_URL, url.str) | ||||||
| 	C.curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, download_cb) | 	C.curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, download_cb) | ||||||
| 	data := &DownloadStruct { | 	data := &DownloadStruct { | ||||||
| 		stream:fp | 		stream:fp | ||||||
| 		cb: cb | 		cb: cb | ||||||
| 	} | 	} | ||||||
| 	C.curl_easy_setopt(curl, CURLOPT_WRITEDATA, data)  | 	C.curl_easy_setopt(curl, CURLOPT_WRITEDATA, data) | ||||||
| 	mut d := 0.0  | 	mut d := 0.0 | ||||||
| 	C.curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d)  | 	C.curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d) | ||||||
| 	C.curl_easy_perform(curl)  | 	C.curl_easy_perform(curl) | ||||||
| 	C.curl_easy_cleanup(curl)  | 	C.curl_easy_cleanup(curl) | ||||||
| 	C.fclose(fp)  | 	C.fclose(fp) | ||||||
| 	cb_finished()  | 	cb_finished() | ||||||
| */  | */ | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn download_file(url, out string) { |  | ||||||
| 	//download_file_with_progress(url, out, empty, empty) 
 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn empty() { | fn empty() { | ||||||
|   | 
 | ||||||
| }  | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ module http | ||||||
| fn download_file_with_progress(url, out string, cb, cb_finished voidptr) { | fn download_file_with_progress(url, out string, cb, cb_finished voidptr) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /* | ||||||
| pub fn download_file(url, out string) { | pub fn download_file(url, out string) { | ||||||
| 	C.URLDownloadToFile(0, url.to_wide(), out.to_wide(), 0, 0) | 	C.URLDownloadToFile(0, url.to_wide(), out.to_wide(), 0, 0) | ||||||
| 	/* | 	/* | ||||||
|  | @ -25,3 +26,4 @@ pub fn download_file(url, out string) { | ||||||
| 	# } | 	# } | ||||||
| 	*/ | 	*/ | ||||||
| } | } | ||||||
|  | */ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue