| author | |
| committer | |
| log | 6f1a7a0d70d53e7402380ce23a7b1e9c55aefa5c |
| tree | f568794f5e83b6840afcd37812a6652ed21a93c8 |
| parent | fc5ffd32e99bfac6bbf6f5f77804c3c5ebe9ae88 |
4 files changed, 149 insertions(+), 18 deletions(-)
src/all_types.hpp+1| ... | ... | @@ -792,6 +792,7 @@ struct FnTypeId { |
| 792 | 792 | int param_count; |
| 793 | 793 | bool is_var_args; |
| 794 | 794 | bool is_naked; |
| 795 | bool is_cold; | |
| 795 | 796 | bool is_extern; |
| 796 | 797 | }; |
| 797 | 798 |
src/analyze.cpp+23-5| ... | ... | @@ -457,7 +457,14 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId fn_type_id) { |
| 457 | 457 | |
| 458 | 458 | TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn); |
| 459 | 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 | } | |
| 461 | 468 | |
| 462 | 469 | fn_type->size_in_bits = g->pointer_size_bytes * 8; |
| 463 | 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 | 473 | buf_resize(&fn_type->name, 0); |
| 467 | 474 | const char *extern_str = fn_type_id.is_extern ? "extern " : ""; |
| 468 | 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 | 478 | for (int i = 0; i < fn_type_id.param_count; i += 1) { |
| 471 | 479 | FnTypeParamInfo *param_info = &fn_type_id.param_info[i]; |
| 472 | 480 | |
| ... | ... | @@ -634,7 +642,7 @@ static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, B |
| 634 | 642 | } |
| 635 | 643 | |
| 636 | 644 | static 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 | 647 | assert(node->type == NodeTypeFnProto); |
| 640 | 648 | AstNodeFnProto *fn_proto = &node->data.fn_proto; |
| ... | ... | @@ -646,6 +654,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor |
| 646 | 654 | FnTypeId fn_type_id; |
| 647 | 655 | fn_type_id.is_extern = fn_proto->is_extern || (fn_proto->visib_mod == VisibModExport); |
| 648 | 656 | fn_type_id.is_naked = is_naked; |
| 657 | fn_type_id.is_cold = is_cold; | |
| 649 | 658 | fn_type_id.param_count = node->data.fn_proto.params.length; |
| 650 | 659 | fn_type_id.param_info = allocate<FnTypeParamInfo>(fn_type_id.param_count); |
| 651 | 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 | 725 | |
| 717 | 726 | fn_table_entry->is_inline = fn_proto->is_inline; |
| 718 | 727 | |
| 728 | bool is_cold = false; | |
| 719 | 729 | bool is_naked = false; |
| 720 | 730 | |
| 721 | 731 | if (fn_proto->directives) { |
| ... | ... | @@ -728,6 +738,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 728 | 738 | if (fn_table_entry->fn_def_node) { |
| 729 | 739 | if (buf_eql_str(attr_name, "naked")) { |
| 730 | 740 | is_naked = true; |
| 741 | } else if (buf_eql_str(attr_name, "cold")) { | |
| 742 | is_cold = true; | |
| 731 | 743 | } else { |
| 732 | 744 | add_node_error(g, directive_node, |
| 733 | 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 | 755 | } |
| 744 | 756 | } |
| 745 | 757 | |
| 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); | |
| 747 | 760 | |
| 748 | 761 | fn_table_entry->type_entry = fn_type; |
| 749 | 762 | |
| ... | ... | @@ -1549,6 +1562,9 @@ static bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTable |
| 1549 | 1562 | if (expected_type->data.fn.fn_type_id.is_naked != actual_type->data.fn.fn_type_id.is_naked) { |
| 1550 | 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 | 1568 | if (!types_match_const_cast_only(expected_type->data.fn.fn_type_id.return_type, |
| 1553 | 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 | 3137 | static TypeTableEntry *analyze_fn_proto_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 3122 | 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); | |
| 3125 | 3141 | |
| 3126 | 3142 | if (type_entry->id == TypeTableEntryIdInvalid) { |
| 3127 | 3143 | return type_entry; |
| ... | ... | @@ -5498,6 +5514,7 @@ uint32_t fn_type_id_hash(FnTypeId id) { |
| 5498 | 5514 | uint32_t result = 0; |
| 5499 | 5515 | result += id.is_extern ? 3349388391 : 0; |
| 5500 | 5516 | result += id.is_naked ? 608688877 : 0; |
| 5517 | result += id.is_cold ? 3605523458 : 0; | |
| 5501 | 5518 | result += id.is_var_args ? 1931444534 : 0; |
| 5502 | 5519 | result += hash_ptr(id.return_type); |
| 5503 | 5520 | result += id.param_count; |
| ... | ... | @@ -5512,6 +5529,7 @@ uint32_t fn_type_id_hash(FnTypeId id) { |
| 5512 | 5529 | bool fn_type_id_eql(FnTypeId a, FnTypeId b) { |
| 5513 | 5530 | if (a.is_extern != b.is_extern || |
| 5514 | 5531 | a.is_naked != b.is_naked || |
| 5532 | a.is_cold != b.is_cold || | |
| 5515 | 5533 | a.return_type != b.return_type || |
| 5516 | 5534 | a.is_var_args != b.is_var_args || |
| 5517 | 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 | 172 | } |
| 173 | 173 | } |
| 174 | 174 | |
| 175 | #attribute("cold") | |
| 176 | pub fn abort() -> unreachable { | |
| 177 | raise(SIGABRT); | |
| 178 | raise(SIGKILL); | |
| 179 | while (true) {} | |
| 180 | } | |
| 175 | 181 | |
| 176 | 182 | pub error InvalidChar; |
| 177 | 183 | pub error Overflow; |
std/syscall.zig+119-13| ... | ... | @@ -1,11 +1,18 @@ |
| 1 | const SYS_read = 0; | |
| 2 | const SYS_write = 1; | |
| 3 | const SYS_mmap = 9; | |
| 4 | const SYS_munmap = 11; | |
| 5 | const SYS_exit = 60; | |
| 6 | const SYS_getrandom = 318; | |
| 7 | ||
| 8 | // mmap constants | |
| 1 | // this file is specific to x86_64 | |
| 2 | ||
| 3 | const SYS_read = 0; | |
| 4 | const SYS_write = 1; | |
| 5 | const SYS_mmap = 9; | |
| 6 | const SYS_munmap = 11; | |
| 7 | const SYS_rt_sigprocmask = 14; | |
| 8 | const SYS_exit = 60; | |
| 9 | const SYS_kill = 62; | |
| 10 | const SYS_getgid = 104; | |
| 11 | const SYS_gettid = 186; | |
| 12 | const SYS_tkill = 200; | |
| 13 | const SYS_tgkill = 234; | |
| 14 | const SYS_getrandom = 318; | |
| 15 | ||
| 9 | 16 | pub const MMAP_PROT_NONE = 0; |
| 10 | 17 | pub const MMAP_PROT_READ = 1; |
| 11 | 18 | pub const MMAP_PROT_WRITE = 2; |
| ... | ... | @@ -17,31 +24,100 @@ pub const MMAP_MAP_PRIVATE = 2; |
| 17 | 24 | pub const MMAP_MAP_FIXED = 16; |
| 18 | 25 | pub const MMAP_MAP_ANON = 32; |
| 19 | 26 | |
| 27 | pub const SIGHUP = 1; | |
| 28 | pub const SIGINT = 2; | |
| 29 | pub const SIGQUIT = 3; | |
| 30 | pub const SIGILL = 4; | |
| 31 | pub const SIGTRAP = 5; | |
| 32 | pub const SIGABRT = 6; | |
| 33 | pub const SIGIOT = SIGABRT; | |
| 34 | pub const SIGBUS = 7; | |
| 35 | pub const SIGFPE = 8; | |
| 36 | pub const SIGKILL = 9; | |
| 37 | pub const SIGUSR1 = 10; | |
| 38 | pub const SIGSEGV = 11; | |
| 39 | pub const SIGUSR2 = 12; | |
| 40 | pub const SIGPIPE = 13; | |
| 41 | pub const SIGALRM = 14; | |
| 42 | pub const SIGTERM = 15; | |
| 43 | pub const SIGSTKFLT = 16; | |
| 44 | pub const SIGCHLD = 17; | |
| 45 | pub const SIGCONT = 18; | |
| 46 | pub const SIGSTOP = 19; | |
| 47 | pub const SIGTSTP = 20; | |
| 48 | pub const SIGTTIN = 21; | |
| 49 | pub const SIGTTOU = 22; | |
| 50 | pub const SIGURG = 23; | |
| 51 | pub const SIGXCPU = 24; | |
| 52 | pub const SIGXFSZ = 25; | |
| 53 | pub const SIGVTALRM = 26; | |
| 54 | pub const SIGPROF = 27; | |
| 55 | pub const SIGWINCH = 28; | |
| 56 | pub const SIGIO = 29; | |
| 57 | pub const SIGPOLL = 29; | |
| 58 | pub const SIGPWR = 30; | |
| 59 | pub const SIGSYS = 31; | |
| 60 | pub const SIGUNUSED = SIGSYS; | |
| 61 | ||
| 62 | const SIG_BLOCK = 0; | |
| 63 | const SIG_UNBLOCK = 1; | |
| 64 | const SIG_SETMASK = 2; | |
| 65 | ||
| 66 | fn syscall0(number: isize) -> isize { | |
| 67 | asm volatile ("syscall" | |
| 68 | : [ret] "={rax}" (-> isize) | |
| 69 | : [number] "{rax}" (number) | |
| 70 | : "rcx", "r11") | |
| 71 | } | |
| 72 | ||
| 20 | 73 | fn syscall1(number: isize, arg1: isize) -> isize { |
| 21 | 74 | asm volatile ("syscall" |
| 22 | 75 | : [ret] "={rax}" (-> isize) |
| 23 | : [number] "{rax}" (number), [arg1] "{rdi}" (arg1) | |
| 76 | : [number] "{rax}" (number), | |
| 77 | [arg1] "{rdi}" (arg1) | |
| 78 | : "rcx", "r11") | |
| 79 | } | |
| 80 | ||
| 81 | fn 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 | 87 | : "rcx", "r11") |
| 25 | 88 | } |
| 26 | 89 | |
| 27 | 90 | fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize { |
| 28 | 91 | asm volatile ("syscall" |
| 29 | 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 | 97 | : "rcx", "r11") |
| 32 | 98 | } |
| 33 | 99 | |
| 34 | fn syscall2(number: isize, arg1: isize, arg2: isize) -> isize { | |
| 100 | fn syscall4(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize) -> isize { | |
| 35 | 101 | asm volatile ("syscall" |
| 36 | 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 | 108 | : "rcx", "r11") |
| 39 | 109 | } |
| 40 | 110 | |
| 41 | 111 | fn syscall6(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize, arg5: isize, arg6: isize) -> isize { |
| 42 | 112 | asm volatile ("syscall" |
| 43 | 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 | 121 | : "rcx", "r11") |
| 46 | 122 | } |
| 47 | 123 | |
| ... | ... | @@ -69,3 +145,33 @@ pub fn exit(status: i32) -> unreachable { |
| 69 | 145 | pub fn getrandom(buf: &u8, count: isize, flags: u32) -> isize { |
| 70 | 146 | syscall3(SYS_getrandom, isize(buf), count, isize(flags)) |
| 71 | 147 | } |
| 148 | ||
| 149 | pub fn kill(pid: i32, sig: i32) -> i32 { | |
| 150 | i32(syscall2(SYS_kill, pid, sig)) | |
| 151 | } | |
| 152 | ||
| 153 | const NSIG = 65; | |
| 154 | const sigset_t = [128]u8; | |
| 155 | const all_mask = []u8 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; | |
| 156 | const app_mask = []u8 { 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, }; | |
| 157 | ||
| 158 | pub 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 | ||
| 167 | fn block_all_signals(set: &sigset_t) { | |
| 168 | syscall4(SYS_rt_sigprocmask, SIG_BLOCK, isize(&all_mask), isize(set), NSIG/8); | |
| 169 | } | |
| 170 | ||
| 171 | fn block_app_signals(set: &sigset_t) { | |
| 172 | syscall4(SYS_rt_sigprocmask, SIG_BLOCK, isize(&app_mask), isize(set), NSIG/8); | |
| 173 | } | |
| 174 | ||
| 175 | fn restore_signals(set: &sigset_t) { | |
| 176 | syscall4(SYS_rt_sigprocmask, SIG_SETMASK, isize(set), 0, NSIG/8); | |
| 177 | } |