x64: function calls; http: download_file()
							parent
							
								
									208f67132d
								
							
						
					
					
						commit
						52d25336db
					
				|  | @ -1,6 +1,11 @@ | |||
| fn main() { | ||||
| 	println('x64 test') | ||||
| 	for _ in 0..5 { | ||||
| 		println('Hello world from V x64 machine code generator!') | ||||
| 	} | ||||
| 	println('Hello again!') | ||||
| } | ||||
| 
 | ||||
| fn test_fn() { | ||||
| 	println('test fn') | ||||
| }	 | ||||
|  |  | |||
|  | @ -44,6 +44,7 @@ mut: | |||
| 	fn_name_token_idx int // used by error reporting
 | ||||
| 	comptime_define string | ||||
| 	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 { | ||||
|  | @ -397,6 +398,9 @@ fn (p mut Parser) fn_decl() { | |||
| 	str_args := f.str_args(p.table) | ||||
| 	// Special case for main() args
 | ||||
| 	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' { | ||||
| 			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('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
 | ||||
| 	if p.mod == 'main' { | ||||
| 		// println(p.cur_fn.scope_level)
 | ||||
|  | @ -541,6 +551,7 @@ fn (p mut Parser) fn_decl() { | |||
| 	p.check_unused_variables() | ||||
| 	p.set_current_fn( EmptyFn ) | ||||
| 	p.returns = false | ||||
| 	 | ||||
| } | ||||
| 
 | ||||
| [inline] | ||||
|  |  | |||
|  | @ -367,7 +367,6 @@ pub fn (v mut V) compile_x64() { | |||
| 		v.parse(f, .main) | ||||
| 	} | ||||
| 	v.x64.generate_elf_footer() | ||||
| 	 | ||||
| }	 | ||||
| 
 | ||||
| fn (v mut V) generate_init() { | ||||
|  |  | |||
|  | @ -167,7 +167,7 @@ fn (p mut Parser) match_statement(is_expr bool) string { | |||
| 		p.gen(')') | ||||
| 
 | ||||
| 		if p.tok == .arrow { | ||||
| 			p.warn(warn_match_arrow) | ||||
| 			p.error(warn_match_arrow) | ||||
| 			p.check(.arrow) | ||||
| 		}	 | ||||
| 
 | ||||
|  |  | |||
|  | @ -69,6 +69,8 @@ pub fn (g mut Gen) generate_elf_header() { | |||
| 	g.write64(0x1000) // p_align
 | ||||
| 	// user code starts here at
 | ||||
| 	// 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() { | ||||
|  | @ -87,6 +89,12 @@ pub fn (g mut Gen) generate_elf_footer() { | |||
| 	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+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
 | ||||
| 	f := os.create(g.out_name) or { panic(err) } | ||||
| 	os.chmod(g.out_name, 0775) | ||||
|  |  | |||
|  | @ -12,8 +12,9 @@ mut: | |||
| 	offset i64 | ||||
| 	str_pos []i64 | ||||
| 	strings []string // TODO use a map and don't duplicate strings
 | ||||
| 	//str string
 | ||||
| 	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
 | ||||
| }	 | ||||
| 
 | ||||
|  | @ -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 (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 | ||||
| 	g.write8(0x7e) | ||||
| 	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) { | ||||
| 	match reg { | ||||
| 		.rsi { | ||||
|  | @ -137,7 +156,9 @@ fn (g mut Gen) mov64(reg Register, val i64) { | |||
| } | ||||
| 
 | ||||
| fn (g mut Gen) call(val int) { | ||||
| 	//println('call val=$val')
 | ||||
| 	g.write8(0xe8) | ||||
| 	g.write32(val) | ||||
| } | ||||
| 
 | ||||
| fn (g mut Gen) syscall() { | ||||
|  | @ -146,7 +167,7 @@ fn (g mut Gen) syscall() { | |||
| 	g.write8(0x05) | ||||
| } | ||||
| 
 | ||||
| fn (g mut Gen) ret() { | ||||
| pub fn (g mut Gen) ret() { | ||||
| 	g.write8(0xc3) | ||||
| } | ||||
| 
 | ||||
|  | @ -163,6 +184,10 @@ pub fn (g mut Gen) gen_loop_end(to int, label int) { | |||
| 	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) { | ||||
| 	g.strings << s + '\n' | ||||
| 	//g.string_addr[s] = str_pos
 | ||||
|  | @ -175,6 +200,13 @@ pub fn (g mut Gen) gen_print(s string) { | |||
| 	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) { | ||||
| 	match reg { | ||||
| 		.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 | ||||
| 
 | ||||
| type downloadfn fn (written int) | ||||
| type download_finished_fn fn ()  | ||||
| type download_finished_fn fn () | ||||
| 
 | ||||
| /*  | ||||
| /* | ||||
| struct DownloadStruct { | ||||
| mut:  | ||||
| mut: | ||||
| 	stream  voidptr | ||||
| 	written int | ||||
| 	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) | ||||
| 	written := C.fwrite(ptr, size, nmemb, data.stream)  | ||||
| 	data.written += written  | ||||
| 	data.cb(data.written)  | ||||
| 	//#data->cb(data->written); // TODO 
 | ||||
| 	return written  | ||||
| */  | ||||
| 	written := C.fwrite(ptr, size, nmemb, data.stream) | ||||
| 	data.written += written | ||||
| 	data.cb(data.written) | ||||
| 	//#data->cb(data->written); // TODO
 | ||||
| 	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() | ||||
| 	if isnil(curl) { | ||||
| 		return | ||||
| 	} | ||||
| 	cout := out.str  | ||||
| 	fp := C.fopen(cout, 'wb')  | ||||
| 	C.curl_easy_setopt(curl, CURLOPT_URL, url.str)  | ||||
| 	cout := out.str | ||||
| 	fp := C.fopen(cout, 'wb') | ||||
| 	C.curl_easy_setopt(curl, CURLOPT_URL, url.str) | ||||
| 	C.curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, download_cb) | ||||
| 	data := &DownloadStruct { | ||||
| 		stream:fp | ||||
| 		cb: cb | ||||
| 	} | ||||
| 	C.curl_easy_setopt(curl, CURLOPT_WRITEDATA, data)  | ||||
| 	mut d := 0.0  | ||||
| 	C.curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d)  | ||||
| 	C.curl_easy_perform(curl)  | ||||
| 	C.curl_easy_cleanup(curl)  | ||||
| 	C.fclose(fp)  | ||||
| 	cb_finished()  | ||||
| */  | ||||
| } | ||||
| 
 | ||||
| fn download_file(url, out string) { | ||||
| 	//download_file_with_progress(url, out, empty, empty) 
 | ||||
| 	C.curl_easy_setopt(curl, CURLOPT_WRITEDATA, data) | ||||
| 	mut d := 0.0 | ||||
| 	C.curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d) | ||||
| 	C.curl_easy_perform(curl) | ||||
| 	C.curl_easy_cleanup(curl) | ||||
| 	C.fclose(fp) | ||||
| 	cb_finished() | ||||
| */ | ||||
| } | ||||
| 
 | ||||
| fn empty() { | ||||
|   | ||||
| }  | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ module http | |||
| fn download_file_with_progress(url, out string, cb, cb_finished voidptr) { | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| pub fn download_file(url, out string) { | ||||
| 	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