Commit 6f1a7a0d70

Andrew Kelley <superjoe30@gmail.com>
2016-02-02 08:42:06
add abort function and "cold" fn attribute
1 parent fc5ffd3
src/all_types.hpp
@@ -792,6 +792,7 @@ struct FnTypeId {
     int param_count;
     bool is_var_args;
     bool is_naked;
+    bool is_cold;
     bool is_extern;
 };
 
src/analyze.cpp
@@ -457,7 +457,14 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId fn_type_id) {
 
     TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
     fn_type->data.fn.fn_type_id = fn_type_id;
-    fn_type->data.fn.calling_convention = fn_type_id.is_extern ? LLVMCCallConv : LLVMFastCallConv;
+
+    if (fn_type_id.is_cold) {
+        fn_type->data.fn.calling_convention = LLVMColdCallConv;
+    } else if (fn_type_id.is_extern) {
+        fn_type->data.fn.calling_convention = LLVMCCallConv;
+    } else {
+        fn_type->data.fn.calling_convention = LLVMFastCallConv;
+    }
 
     fn_type->size_in_bits = g->pointer_size_bytes * 8;
     fn_type->align_in_bits = g->pointer_size_bytes * 8;
@@ -466,7 +473,8 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId fn_type_id) {
     buf_resize(&fn_type->name, 0);
     const char *extern_str = fn_type_id.is_extern ? "extern " : "";
     const char *naked_str = fn_type_id.is_naked ? "naked " : "";
-    buf_appendf(&fn_type->name, "%s%sfn(", extern_str, naked_str);
+    const char *cold_str = fn_type_id.is_cold ? "cold " : "";
+    buf_appendf(&fn_type->name, "%s%s%sfn(", extern_str, naked_str, cold_str);
     for (int i = 0; i < fn_type_id.param_count; i += 1) {
         FnTypeParamInfo *param_info = &fn_type_id.param_info[i];
 
@@ -634,7 +642,7 @@ static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, B
 }
 
 static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
-        TypeTableEntry *expected_type, AstNode *node, bool is_naked)
+        TypeTableEntry *expected_type, AstNode *node, bool is_naked, bool is_cold)
 {
     assert(node->type == NodeTypeFnProto);
     AstNodeFnProto *fn_proto = &node->data.fn_proto;
@@ -646,6 +654,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
     FnTypeId fn_type_id;
     fn_type_id.is_extern = fn_proto->is_extern || (fn_proto->visib_mod == VisibModExport);
     fn_type_id.is_naked = is_naked;
+    fn_type_id.is_cold = is_cold;
     fn_type_id.param_count = node->data.fn_proto.params.length;
     fn_type_id.param_info = allocate<FnTypeParamInfo>(fn_type_id.param_count);
     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
 
     fn_table_entry->is_inline = fn_proto->is_inline;
 
+    bool is_cold = false;
     bool is_naked = false;
 
     if (fn_proto->directives) {
@@ -728,6 +738,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
                 if (fn_table_entry->fn_def_node) {
                     if (buf_eql_str(attr_name, "naked")) {
                         is_naked = true;
+                    } else if (buf_eql_str(attr_name, "cold")) {
+                        is_cold = true;
                     } else {
                         add_node_error(g, directive_node,
                                 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
         }
     }
 
-    TypeTableEntry *fn_type = analyze_fn_proto_type(g, import, import->block_context, nullptr, node, is_naked);
+    TypeTableEntry *fn_type = analyze_fn_proto_type(g, import, import->block_context, nullptr, node,
+            is_naked, is_cold);
 
     fn_table_entry->type_entry = fn_type;
 
@@ -1549,6 +1562,9 @@ static bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTable
         if (expected_type->data.fn.fn_type_id.is_naked != actual_type->data.fn.fn_type_id.is_naked) {
             return false;
         }
+        if (expected_type->data.fn.fn_type_id.is_cold != actual_type->data.fn.fn_type_id.is_cold) {
+            return false;
+        }
         if (!types_match_const_cast_only(expected_type->data.fn.fn_type_id.return_type,
             actual_type->data.fn.fn_type_id.return_type))
         {
@@ -3121,7 +3137,7 @@ static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import,
 static TypeTableEntry *analyze_fn_proto_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
         TypeTableEntry *expected_type, AstNode *node)
 {
-    TypeTableEntry *type_entry = analyze_fn_proto_type(g, import, context, expected_type, node, false);
+    TypeTableEntry *type_entry = analyze_fn_proto_type(g, import, context, expected_type, node, false, false);
 
     if (type_entry->id == TypeTableEntryIdInvalid) {
         return type_entry;
@@ -5498,6 +5514,7 @@ uint32_t fn_type_id_hash(FnTypeId id) {
     uint32_t result = 0;
     result += id.is_extern ? 3349388391 : 0;
     result += id.is_naked ? 608688877 : 0;
+    result += id.is_cold ? 3605523458 : 0;
     result += id.is_var_args ? 1931444534 : 0;
     result += hash_ptr(id.return_type);
     result += id.param_count;
@@ -5512,6 +5529,7 @@ uint32_t fn_type_id_hash(FnTypeId id) {
 bool fn_type_id_eql(FnTypeId a, FnTypeId b) {
     if (a.is_extern != b.is_extern ||
         a.is_naked != b.is_naked ||
+        a.is_cold != b.is_cold ||
         a.return_type != b.return_type ||
         a.is_var_args != b.is_var_args ||
         a.param_count != b.param_count)
std/std.zig
@@ -172,6 +172,12 @@ pub fn os_get_random_bytes(buf: []u8) -> %void {
     }
 }
 
+#attribute("cold")
+pub fn abort() -> unreachable {
+    raise(SIGABRT);
+    raise(SIGKILL);
+    while (true) {}
+}
 
 pub error InvalidChar;
 pub error Overflow;
std/syscall.zig
@@ -1,11 +1,18 @@
-const SYS_read      = 0;
-const SYS_write     = 1;
-const SYS_mmap      = 9;
-const SYS_munmap    = 11;
-const SYS_exit      = 60;
-const SYS_getrandom = 318;
-
-// mmap constants
+// this file is specific to x86_64
+
+const SYS_read           = 0;
+const SYS_write          = 1;
+const SYS_mmap           = 9;
+const SYS_munmap         = 11;
+const SYS_rt_sigprocmask = 14;
+const SYS_exit           = 60;
+const SYS_kill           = 62;
+const SYS_getgid         = 104;
+const SYS_gettid         = 186;
+const SYS_tkill          = 200;
+const SYS_tgkill         = 234;
+const SYS_getrandom      = 318;
+
 pub const MMAP_PROT_NONE =  0;
 pub const MMAP_PROT_READ =  1;
 pub const MMAP_PROT_WRITE = 2;
@@ -17,31 +24,100 @@ pub const MMAP_MAP_PRIVATE = 2;
 pub const MMAP_MAP_FIXED =   16;
 pub const MMAP_MAP_ANON =    32;
 
+pub const SIGHUP    = 1;
+pub const SIGINT    = 2;
+pub const SIGQUIT   = 3;
+pub const SIGILL    = 4;
+pub const SIGTRAP   = 5;
+pub const SIGABRT   = 6;
+pub const SIGIOT    = SIGABRT;
+pub const SIGBUS    = 7;
+pub const SIGFPE    = 8;
+pub const SIGKILL   = 9;
+pub const SIGUSR1   = 10;
+pub const SIGSEGV   = 11;
+pub const SIGUSR2   = 12;
+pub const SIGPIPE   = 13;
+pub const SIGALRM   = 14;
+pub const SIGTERM   = 15;
+pub const SIGSTKFLT = 16;
+pub const SIGCHLD   = 17;
+pub const SIGCONT   = 18;
+pub const SIGSTOP   = 19;
+pub const SIGTSTP   = 20;
+pub const SIGTTIN   = 21;
+pub const SIGTTOU   = 22;
+pub const SIGURG    = 23;
+pub const SIGXCPU   = 24;
+pub const SIGXFSZ   = 25;
+pub const SIGVTALRM = 26;
+pub const SIGPROF   = 27;
+pub const SIGWINCH  = 28;
+pub const SIGIO     = 29;
+pub const SIGPOLL   = 29;
+pub const SIGPWR    = 30;
+pub const SIGSYS    = 31;
+pub const SIGUNUSED = SIGSYS;
+
+const SIG_BLOCK   = 0;
+const SIG_UNBLOCK = 1;
+const SIG_SETMASK = 2;
+
+fn syscall0(number: isize) -> isize {
+    asm volatile ("syscall"
+        : [ret] "={rax}" (-> isize)
+        : [number] "{rax}" (number)
+        : "rcx", "r11")
+}
+
 fn syscall1(number: isize, arg1: isize) -> isize {
     asm volatile ("syscall"
         : [ret] "={rax}" (-> isize)
-        : [number] "{rax}" (number), [arg1] "{rdi}" (arg1)
+        : [number] "{rax}" (number),
+            [arg1] "{rdi}" (arg1)
+        : "rcx", "r11")
+}
+
+fn syscall2(number: isize, arg1: isize, arg2: isize) -> isize {
+    asm volatile ("syscall"
+        : [ret] "={rax}" (-> isize)
+        : [number] "{rax}" (number),
+            [arg1] "{rdi}" (arg1),
+            [arg2] "{rsi}" (arg2)
         : "rcx", "r11")
 }
 
 fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
     asm volatile ("syscall"
         : [ret] "={rax}" (-> isize)
-        : [number] "{rax}" (number), [arg1] "{rdi}" (arg1), [arg2] "{rsi}" (arg2), [arg3] "{rdx}" (arg3)
+        : [number] "{rax}" (number),
+            [arg1] "{rdi}" (arg1),
+            [arg2] "{rsi}" (arg2),
+            [arg3] "{rdx}" (arg3)
         : "rcx", "r11")
 }
 
-fn syscall2(number: isize, arg1: isize, arg2: isize) -> isize {
+fn syscall4(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize) -> isize {
     asm volatile ("syscall"
         : [ret] "={rax}" (-> isize)
-        : [number] "{rax}" (number), [arg1] "{rdi}" (arg1), [arg2] "{rsi}" (arg2)
+        : [number] "{rax}" (number),
+            [arg1] "{rdi}" (arg1),
+            [arg2] "{rsi}" (arg2),
+            [arg3] "{rdx}" (arg3),
+            [arg4] "{r10}" (arg4)
         : "rcx", "r11")
 }
 
 fn syscall6(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize, arg5: isize, arg6: isize) -> isize {
     asm volatile ("syscall"
         : [ret] "={rax}" (-> isize)
-        : [number] "{rax}" (number), [arg1] "{rdi}" (arg1), [arg2] "{rsi}" (arg2), [arg3] "{rdx}" (arg3), [arg4] "{r10}" (arg4), [arg5] "{r8}" (arg5), [arg6] "{r9}" (arg6)
+        : [number] "{rax}" (number),
+            [arg1] "{rdi}" (arg1),
+            [arg2] "{rsi}" (arg2),
+            [arg3] "{rdx}" (arg3),
+            [arg4] "{r10}" (arg4),
+            [arg5] "{r8}" (arg5),
+            [arg6] "{r9}" (arg6)
         : "rcx", "r11")
 }
 
@@ -69,3 +145,33 @@ pub fn exit(status: i32) -> unreachable {
 pub fn getrandom(buf: &u8, count: isize, flags: u32) -> isize {
     syscall3(SYS_getrandom, isize(buf), count, isize(flags))
 }
+
+pub fn kill(pid: i32, sig: i32) -> i32 {
+    i32(syscall2(SYS_kill, pid, sig))
+}
+
+const NSIG = 65;
+const sigset_t = [128]u8;
+const all_mask = []u8 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, };
+const app_mask = []u8 { 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, };
+
+pub fn raise(sig: i32) -> i32 {
+    var set: sigset_t = undefined;
+    block_app_signals(&set);
+    const tid = i32(syscall0(SYS_gettid));
+    const ret = i32(syscall2(SYS_tkill, tid, sig));
+    restore_signals(&set);
+    return ret;
+}
+
+fn block_all_signals(set: &sigset_t) {
+    syscall4(SYS_rt_sigprocmask, SIG_BLOCK, isize(&all_mask), isize(set), NSIG/8);
+}
+
+fn block_app_signals(set: &sigset_t) {
+    syscall4(SYS_rt_sigprocmask, SIG_BLOCK, isize(&app_mask), isize(set), NSIG/8);
+}
+
+fn restore_signals(set: &sigset_t) {
+    syscall4(SYS_rt_sigprocmask, SIG_SETMASK, isize(set), 0, NSIG/8);
+}