authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-02-02 00:42:06-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-02-02 00:42:06-07:00
log6f1a7a0d70d53e7402380ce23a7b1e9c55aefa5c
treef568794f5e83b6840afcd37812a6652ed21a93c8
parentfc5ffd32e99bfac6bbf6f5f77804c3c5ebe9ae88

add abort function and "cold" fn attribute


4 files changed, 149 insertions(+), 18 deletions(-)

src/all_types.hpp+1
...@@ -792,6 +792,7 @@ struct FnTypeId {...@@ -792,6 +792,7 @@ struct FnTypeId {
792 int param_count;792 int param_count;
793 bool is_var_args;793 bool is_var_args;
794 bool is_naked;794 bool is_naked;
795 bool is_cold;
795 bool is_extern;796 bool is_extern;
796};797};
797798
src/analyze.cpp+23-5
...@@ -457,7 +457,14 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId fn_type_id) {...@@ -457,7 +457,14 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId fn_type_id) {
457457
458 TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);458 TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
459 fn_type->data.fn.fn_type_id = fn_type_id;459 fn_type->data.fn.fn_type_id = fn_type_id;
460 fn_type->data.fn.calling_convention = fn_type_id.is_extern ? LLVMCCallConv : LLVMFastCallConv;460
461 if (fn_type_id.is_cold) {
462 fn_type->data.fn.calling_convention = LLVMColdCallConv;
463 } else if (fn_type_id.is_extern) {
464 fn_type->data.fn.calling_convention = LLVMCCallConv;
465 } else {
466 fn_type->data.fn.calling_convention = LLVMFastCallConv;
467 }
461468
462 fn_type->size_in_bits = g->pointer_size_bytes * 8;469 fn_type->size_in_bits = g->pointer_size_bytes * 8;
463 fn_type->align_in_bits = g->pointer_size_bytes * 8;470 fn_type->align_in_bits = g->pointer_size_bytes * 8;
...@@ -466,7 +473,8 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId fn_type_id) {...@@ -466,7 +473,8 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId fn_type_id) {
466 buf_resize(&fn_type->name, 0);473 buf_resize(&fn_type->name, 0);
467 const char *extern_str = fn_type_id.is_extern ? "extern " : "";474 const char *extern_str = fn_type_id.is_extern ? "extern " : "";
468 const char *naked_str = fn_type_id.is_naked ? "naked " : "";475 const char *naked_str = fn_type_id.is_naked ? "naked " : "";
469 buf_appendf(&fn_type->name, "%s%sfn(", extern_str, naked_str);476 const char *cold_str = fn_type_id.is_cold ? "cold " : "";
477 buf_appendf(&fn_type->name, "%s%s%sfn(", extern_str, naked_str, cold_str);
470 for (int i = 0; i < fn_type_id.param_count; i += 1) {478 for (int i = 0; i < fn_type_id.param_count; i += 1) {
471 FnTypeParamInfo *param_info = &fn_type_id.param_info[i];479 FnTypeParamInfo *param_info = &fn_type_id.param_info[i];
472480
...@@ -634,7 +642,7 @@ static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, B...@@ -634,7 +642,7 @@ static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, B
634}642}
635643
636static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,644static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
637 TypeTableEntry *expected_type, AstNode *node, bool is_naked)645 TypeTableEntry *expected_type, AstNode *node, bool is_naked, bool is_cold)
638{646{
639 assert(node->type == NodeTypeFnProto);647 assert(node->type == NodeTypeFnProto);
640 AstNodeFnProto *fn_proto = &node->data.fn_proto;648 AstNodeFnProto *fn_proto = &node->data.fn_proto;
...@@ -646,6 +654,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor...@@ -646,6 +654,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
646 FnTypeId fn_type_id;654 FnTypeId fn_type_id;
647 fn_type_id.is_extern = fn_proto->is_extern || (fn_proto->visib_mod == VisibModExport);655 fn_type_id.is_extern = fn_proto->is_extern || (fn_proto->visib_mod == VisibModExport);
648 fn_type_id.is_naked = is_naked;656 fn_type_id.is_naked = is_naked;
657 fn_type_id.is_cold = is_cold;
649 fn_type_id.param_count = node->data.fn_proto.params.length;658 fn_type_id.param_count = node->data.fn_proto.params.length;
650 fn_type_id.param_info = allocate<FnTypeParamInfo>(fn_type_id.param_count);659 fn_type_id.param_info = allocate<FnTypeParamInfo>(fn_type_id.param_count);
651 fn_type_id.is_var_args = fn_proto->is_var_args;660 fn_type_id.is_var_args = fn_proto->is_var_args;
...@@ -716,6 +725,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -716,6 +725,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
716725
717 fn_table_entry->is_inline = fn_proto->is_inline;726 fn_table_entry->is_inline = fn_proto->is_inline;
718727
728 bool is_cold = false;
719 bool is_naked = false;729 bool is_naked = false;
720730
721 if (fn_proto->directives) {731 if (fn_proto->directives) {
...@@ -728,6 +738,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -728,6 +738,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
728 if (fn_table_entry->fn_def_node) {738 if (fn_table_entry->fn_def_node) {
729 if (buf_eql_str(attr_name, "naked")) {739 if (buf_eql_str(attr_name, "naked")) {
730 is_naked = true;740 is_naked = true;
741 } else if (buf_eql_str(attr_name, "cold")) {
742 is_cold = true;
731 } else {743 } else {
732 add_node_error(g, directive_node,744 add_node_error(g, directive_node,
733 buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));745 buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
...@@ -743,7 +755,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -743,7 +755,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
743 }755 }
744 }756 }
745757
746 TypeTableEntry *fn_type = analyze_fn_proto_type(g, import, import->block_context, nullptr, node, is_naked);758 TypeTableEntry *fn_type = analyze_fn_proto_type(g, import, import->block_context, nullptr, node,
759 is_naked, is_cold);
747760
748 fn_table_entry->type_entry = fn_type;761 fn_table_entry->type_entry = fn_type;
749762
...@@ -1549,6 +1562,9 @@ static bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTable...@@ -1549,6 +1562,9 @@ static bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTable
1549 if (expected_type->data.fn.fn_type_id.is_naked != actual_type->data.fn.fn_type_id.is_naked) {1562 if (expected_type->data.fn.fn_type_id.is_naked != actual_type->data.fn.fn_type_id.is_naked) {
1550 return false;1563 return false;
1551 }1564 }
1565 if (expected_type->data.fn.fn_type_id.is_cold != actual_type->data.fn.fn_type_id.is_cold) {
1566 return false;
1567 }
1552 if (!types_match_const_cast_only(expected_type->data.fn.fn_type_id.return_type,1568 if (!types_match_const_cast_only(expected_type->data.fn.fn_type_id.return_type,
1553 actual_type->data.fn.fn_type_id.return_type))1569 actual_type->data.fn.fn_type_id.return_type))
1554 {1570 {
...@@ -3121,7 +3137,7 @@ static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import,...@@ -3121,7 +3137,7 @@ static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import,
3121static TypeTableEntry *analyze_fn_proto_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,3137static TypeTableEntry *analyze_fn_proto_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
3122 TypeTableEntry *expected_type, AstNode *node)3138 TypeTableEntry *expected_type, AstNode *node)
3123{3139{
3124 TypeTableEntry *type_entry = analyze_fn_proto_type(g, import, context, expected_type, node, false);3140 TypeTableEntry *type_entry = analyze_fn_proto_type(g, import, context, expected_type, node, false, false);
31253141
3126 if (type_entry->id == TypeTableEntryIdInvalid) {3142 if (type_entry->id == TypeTableEntryIdInvalid) {
3127 return type_entry;3143 return type_entry;
...@@ -5498,6 +5514,7 @@ uint32_t fn_type_id_hash(FnTypeId id) {...@@ -5498,6 +5514,7 @@ uint32_t fn_type_id_hash(FnTypeId id) {
5498 uint32_t result = 0;5514 uint32_t result = 0;
5499 result += id.is_extern ? 3349388391 : 0;5515 result += id.is_extern ? 3349388391 : 0;
5500 result += id.is_naked ? 608688877 : 0;5516 result += id.is_naked ? 608688877 : 0;
5517 result += id.is_cold ? 3605523458 : 0;
5501 result += id.is_var_args ? 1931444534 : 0;5518 result += id.is_var_args ? 1931444534 : 0;
5502 result += hash_ptr(id.return_type);5519 result += hash_ptr(id.return_type);
5503 result += id.param_count;5520 result += id.param_count;
...@@ -5512,6 +5529,7 @@ uint32_t fn_type_id_hash(FnTypeId id) {...@@ -5512,6 +5529,7 @@ uint32_t fn_type_id_hash(FnTypeId id) {
5512bool fn_type_id_eql(FnTypeId a, FnTypeId b) {5529bool fn_type_id_eql(FnTypeId a, FnTypeId b) {
5513 if (a.is_extern != b.is_extern ||5530 if (a.is_extern != b.is_extern ||
5514 a.is_naked != b.is_naked ||5531 a.is_naked != b.is_naked ||
5532 a.is_cold != b.is_cold ||
5515 a.return_type != b.return_type ||5533 a.return_type != b.return_type ||
5516 a.is_var_args != b.is_var_args ||5534 a.is_var_args != b.is_var_args ||
5517 a.param_count != b.param_count)5535 a.param_count != b.param_count)
std/std.zig+6
...@@ -172,6 +172,12 @@ pub fn os_get_random_bytes(buf: []u8) -> %void {...@@ -172,6 +172,12 @@ pub fn os_get_random_bytes(buf: []u8) -> %void {
172 }172 }
173}173}
174174
175#attribute("cold")
176pub fn abort() -> unreachable {
177 raise(SIGABRT);
178 raise(SIGKILL);
179 while (true) {}
180}
175181
176pub error InvalidChar;182pub error InvalidChar;
177pub error Overflow;183pub error Overflow;
std/syscall.zig+119-13
...@@ -1,11 +1,18 @@...@@ -1,11 +1,18 @@
1const SYS_read = 0;1// this file is specific to x86_64
2const SYS_write = 1;2
3const SYS_mmap = 9;3const SYS_read = 0;
4const SYS_munmap = 11;4const SYS_write = 1;
5const SYS_exit = 60;5const SYS_mmap = 9;
6const SYS_getrandom = 318;6const SYS_munmap = 11;
77const SYS_rt_sigprocmask = 14;
8// mmap constants8const SYS_exit = 60;
9const SYS_kill = 62;
10const SYS_getgid = 104;
11const SYS_gettid = 186;
12const SYS_tkill = 200;
13const SYS_tgkill = 234;
14const SYS_getrandom = 318;
15
9pub const MMAP_PROT_NONE = 0;16pub const MMAP_PROT_NONE = 0;
10pub const MMAP_PROT_READ = 1;17pub const MMAP_PROT_READ = 1;
11pub const MMAP_PROT_WRITE = 2;18pub const MMAP_PROT_WRITE = 2;
...@@ -17,31 +24,100 @@ pub const MMAP_MAP_PRIVATE = 2;...@@ -17,31 +24,100 @@ pub const MMAP_MAP_PRIVATE = 2;
17pub const MMAP_MAP_FIXED = 16;24pub const MMAP_MAP_FIXED = 16;
18pub const MMAP_MAP_ANON = 32;25pub const MMAP_MAP_ANON = 32;
1926
27pub const SIGHUP = 1;
28pub const SIGINT = 2;
29pub const SIGQUIT = 3;
30pub const SIGILL = 4;
31pub const SIGTRAP = 5;
32pub const SIGABRT = 6;
33pub const SIGIOT = SIGABRT;
34pub const SIGBUS = 7;
35pub const SIGFPE = 8;
36pub const SIGKILL = 9;
37pub const SIGUSR1 = 10;
38pub const SIGSEGV = 11;
39pub const SIGUSR2 = 12;
40pub const SIGPIPE = 13;
41pub const SIGALRM = 14;
42pub const SIGTERM = 15;
43pub const SIGSTKFLT = 16;
44pub const SIGCHLD = 17;
45pub const SIGCONT = 18;
46pub const SIGSTOP = 19;
47pub const SIGTSTP = 20;
48pub const SIGTTIN = 21;
49pub const SIGTTOU = 22;
50pub const SIGURG = 23;
51pub const SIGXCPU = 24;
52pub const SIGXFSZ = 25;
53pub const SIGVTALRM = 26;
54pub const SIGPROF = 27;
55pub const SIGWINCH = 28;
56pub const SIGIO = 29;
57pub const SIGPOLL = 29;
58pub const SIGPWR = 30;
59pub const SIGSYS = 31;
60pub const SIGUNUSED = SIGSYS;
61
62const SIG_BLOCK = 0;
63const SIG_UNBLOCK = 1;
64const SIG_SETMASK = 2;
65
66fn syscall0(number: isize) -> isize {
67 asm volatile ("syscall"
68 : [ret] "={rax}" (-> isize)
69 : [number] "{rax}" (number)
70 : "rcx", "r11")
71}
72
20fn syscall1(number: isize, arg1: isize) -> isize {73fn syscall1(number: isize, arg1: isize) -> isize {
21 asm volatile ("syscall"74 asm volatile ("syscall"
22 : [ret] "={rax}" (-> isize)75 : [ret] "={rax}" (-> isize)
23 : [number] "{rax}" (number), [arg1] "{rdi}" (arg1)76 : [number] "{rax}" (number),
77 [arg1] "{rdi}" (arg1)
78 : "rcx", "r11")
79}
80
81fn syscall2(number: isize, arg1: isize, arg2: isize) -> isize {
82 asm volatile ("syscall"
83 : [ret] "={rax}" (-> isize)
84 : [number] "{rax}" (number),
85 [arg1] "{rdi}" (arg1),
86 [arg2] "{rsi}" (arg2)
24 : "rcx", "r11")87 : "rcx", "r11")
25}88}
2689
27fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {90fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
28 asm volatile ("syscall"91 asm volatile ("syscall"
29 : [ret] "={rax}" (-> isize)92 : [ret] "={rax}" (-> isize)
30 : [number] "{rax}" (number), [arg1] "{rdi}" (arg1), [arg2] "{rsi}" (arg2), [arg3] "{rdx}" (arg3)93 : [number] "{rax}" (number),
94 [arg1] "{rdi}" (arg1),
95 [arg2] "{rsi}" (arg2),
96 [arg3] "{rdx}" (arg3)
31 : "rcx", "r11")97 : "rcx", "r11")
32}98}
3399
34fn syscall2(number: isize, arg1: isize, arg2: isize) -> isize {100fn syscall4(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize) -> isize {
35 asm volatile ("syscall"101 asm volatile ("syscall"
36 : [ret] "={rax}" (-> isize)102 : [ret] "={rax}" (-> isize)
37 : [number] "{rax}" (number), [arg1] "{rdi}" (arg1), [arg2] "{rsi}" (arg2)103 : [number] "{rax}" (number),
104 [arg1] "{rdi}" (arg1),
105 [arg2] "{rsi}" (arg2),
106 [arg3] "{rdx}" (arg3),
107 [arg4] "{r10}" (arg4)
38 : "rcx", "r11")108 : "rcx", "r11")
39}109}
40110
41fn syscall6(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize, arg5: isize, arg6: isize) -> isize {111fn syscall6(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize, arg5: isize, arg6: isize) -> isize {
42 asm volatile ("syscall"112 asm volatile ("syscall"
43 : [ret] "={rax}" (-> isize)113 : [ret] "={rax}" (-> isize)
44 : [number] "{rax}" (number), [arg1] "{rdi}" (arg1), [arg2] "{rsi}" (arg2), [arg3] "{rdx}" (arg3), [arg4] "{r10}" (arg4), [arg5] "{r8}" (arg5), [arg6] "{r9}" (arg6)114 : [number] "{rax}" (number),
115 [arg1] "{rdi}" (arg1),
116 [arg2] "{rsi}" (arg2),
117 [arg3] "{rdx}" (arg3),
118 [arg4] "{r10}" (arg4),
119 [arg5] "{r8}" (arg5),
120 [arg6] "{r9}" (arg6)
45 : "rcx", "r11")121 : "rcx", "r11")
46}122}
47123
...@@ -69,3 +145,33 @@ pub fn exit(status: i32) -> unreachable {...@@ -69,3 +145,33 @@ pub fn exit(status: i32) -> unreachable {
69pub fn getrandom(buf: &u8, count: isize, flags: u32) -> isize {145pub fn getrandom(buf: &u8, count: isize, flags: u32) -> isize {
70 syscall3(SYS_getrandom, isize(buf), count, isize(flags))146 syscall3(SYS_getrandom, isize(buf), count, isize(flags))
71}147}
148
149pub fn kill(pid: i32, sig: i32) -> i32 {
150 i32(syscall2(SYS_kill, pid, sig))
151}
152
153const NSIG = 65;
154const sigset_t = [128]u8;
155const all_mask = []u8 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, };
156const app_mask = []u8 { 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, };
157
158pub fn raise(sig: i32) -> i32 {
159 var set: sigset_t = undefined;
160 block_app_signals(&set);
161 const tid = i32(syscall0(SYS_gettid));
162 const ret = i32(syscall2(SYS_tkill, tid, sig));
163 restore_signals(&set);
164 return ret;
165}
166
167fn block_all_signals(set: &sigset_t) {
168 syscall4(SYS_rt_sigprocmask, SIG_BLOCK, isize(&all_mask), isize(set), NSIG/8);
169}
170
171fn block_app_signals(set: &sigset_t) {
172 syscall4(SYS_rt_sigprocmask, SIG_BLOCK, isize(&app_mask), isize(set), NSIG/8);
173}
174
175fn restore_signals(set: &sigset_t) {
176 syscall4(SYS_rt_sigprocmask, SIG_SETMASK, isize(set), 0, NSIG/8);
177}