Patchwork [gccgo] Library support for recover and runtime panics

login
register
mail settings
Submitter Ian Taylor
Date June 14, 2010, 6:07 a.m.
Message ID <mcrbpbef8pn.fsf@dhcp-172-17-9-151.mtv.corp.google.com>
Download mbox | patch
Permalink /patch/55472/
State New
Headers show

Comments

Ian Taylor - June 14, 2010, 6:07 a.m.
This patch includes the gccgo specific library support for recover and
runtime panics.  This unwinds the stack as needed to permit a recover
to catch a panic thrown farther down on the call stack, using gcc's
generic exception mechanism.  Committed to gccgo branch.

Ian

Patch

diff -r 74bfcdacefb6 libgo/Makefile.am
--- a/libgo/Makefile.am	Sun Jun 13 22:25:39 2010 -0700
+++ b/libgo/Makefile.am	Sun Jun 13 22:27:12 2010 -0700
@@ -28,7 +28,8 @@ 
 
 ACLOCAL_AMFLAGS = -I . -I .. -I ../config
 
-AM_CFLAGS = -fplan9-extensions $(SPLIT_STACK) $(WARN_CFLAGS)
+AM_CFLAGS = -fexceptions -fplan9-extensions $(SPLIT_STACK) $(WARN_CFLAGS) \
+	-I $(srcdir)/../gcc -I $(MULTIBUILDTOP)../../gcc/include
 
 # Multilib support.
 MAKEOVERRIDES=
@@ -248,6 +249,8 @@ 
 	runtime/go-construct-map.c \
 	runtime/go-convert-interface.c \
 	runtime/go-defer.c \
+	runtime/go-defer-stack.c \
+	runtime/go-deferred-recover.c \
 	runtime/go-go.c \
 	runtime/go-goexit.c \
 	runtime/go-gomaxprocs.c \
@@ -268,11 +271,13 @@ 
 	runtime/go-new.c \
 	runtime/go-note.c \
 	runtime/go-panic.c \
+	runtime/go-panic-defer.c \
 	runtime/go-print.c \
 	runtime/go-rec-big.c \
 	runtime/go-rec-nb-big.c \
 	runtime/go-rec-nb-small.c \
 	runtime/go-rec-small.c \
+	runtime/go-recover.c \
 	runtime/go-refcount-decrement.c \
 	runtime/go-refcount-flush.c \
 	runtime/go-refcount-increment.c \
@@ -305,9 +310,10 @@ 
 	runtime/go-unsafe-new.c \
 	runtime/go-unsafe-newarray.c \
 	runtime/go-unsafe-pointer.c \
+	runtime/go-unwind.c \
 	runtime/mcache.c \
 	runtime/mcentral.c \
-\	runtime/mem.c \
+	runtime/mem.c \
 	runtime/mfinal.c \
 	runtime/mfixalloc.c \
 	runtime/mgc0.c \
@@ -531,6 +537,7 @@ 
 	go/rpc/server.go
 
 go_runtime_files = \
+	go/runtime/error.go \
 	go/runtime/extern.go \
 	go/runtime/type.go
 
diff -r 74bfcdacefb6 libgo/configure.ac
--- a/libgo/configure.ac	Sun Jun 13 22:25:39 2010 -0700
+++ b/libgo/configure.ac	Sun Jun 13 22:27:12 2010 -0700
@@ -182,6 +182,8 @@ 
 
 AC_C_BIGENDIAN
 
+GCC_CHECK_UNWIND_GETIPINFO
+
 AC_CHECK_HEADERS(sys/mman.h syscall.h sys/epoll.h sys/ptrace.h sys/user.h)
 AC_CHECK_FUNCS(srandom random strsignal)
 
diff -r 74bfcdacefb6 libgo/runtime/go-bad-index.c
--- a/libgo/runtime/go-bad-index.c	Sun Jun 13 22:25:39 2010 -0700
+++ b/libgo/runtime/go-bad-index.c	Sun Jun 13 22:27:12 2010 -0700
@@ -11,5 +11,5 @@ 
 void
 __go_bad_index ()
 {
-  __go_panic_msg ("index out of range");
+  __go_panic_msg ("index or slice out of range");
 }
diff -r 74bfcdacefb6 libgo/runtime/go-convert-interface.c
--- a/libgo/runtime/go-convert-interface.c	Sun Jun 13 22:25:39 2010 -0700
+++ b/libgo/runtime/go-convert-interface.c	Sun Jun 13 22:27:12 2010 -0700
@@ -86,29 +86,27 @@ 
 	      --rhs_method_count;
 	    }
 
-	  if (rhs_method_count == 0)
+	  if (rhs_method_count == 0
+	      || !__go_type_descriptors_equal (p_lhs_method->__type,
+					       p_rhs_method->__mtype))
 	    {
+	      struct __go_interface *panic_arg;
+
 	      if (success != NULL)
 		{
 		  *success = 0;
 		  return NULL;
 		}
-	      __go_print_msg (1, "interface conversion failed: no '");
-	      __go_print_string (1, *p_lhs_method->__name);
-	      __go_panic_msg ("' method");
-	    }
 
-	  if (!__go_type_descriptors_equal (p_lhs_method->__type,
-					    p_rhs_method->__mtype))
-	    {
-	      if (success != NULL)
-		{
-		  *success = 0;
-		  return NULL;
-		}
-	      __go_print_msg (1, "interface conversion failed: '");
-	      __go_print_string (1, *p_lhs_method->__name);
-	      __go_panic_msg ("' method has wrong type");
+	      newTypeAssertionError(NULL,
+				    rhs->__type_descriptor,
+				    lhs_descriptor,
+				    NULL,
+				    rhs->__type_descriptor->__reflection,
+				    lhs_descriptor->__reflection,
+				    p_lhs_method->__name,
+				    &panic_arg);
+	      __go_panic (panic_arg);
 	    }
 
 	  methods[i] = p_rhs_method->__function;
diff -r 74bfcdacefb6 libgo/runtime/go-defer-stack.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/runtime/go-defer-stack.c	Sun Jun 13 22:27:12 2010 -0700
@@ -0,0 +1,9 @@ 
+/* go-defer-stack.c -- The defer stack.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-defer.h"
+
+__thread struct __defer_stack *__go_defer_stack;
diff -r 74bfcdacefb6 libgo/runtime/go-defer.c
--- a/libgo/runtime/go-defer.c	Sun Jun 13 22:25:39 2010 -0700
+++ b/libgo/runtime/go-defer.c	Sun Jun 13 22:27:12 2010 -0700
@@ -7,50 +7,63 @@ 
 #include <stddef.h>
 
 #include "go-alloc.h"
-
-/* The defer stack is a list of these structures.  */
-
-struct __defer_stack
-{
-  /* The next entry in the stack.  */
-  struct __defer_stack* __next;
-
-  /* The function to call.  */
-  void (*__pfn) (void *);
-
-  /* The argument to pass to the function.  */
-  void *__arg;
-};
+#include "go-panic.h"
+#include "go-defer.h"
 
 /* This function is called each time we need to defer a call.  */
 
-void *
-__go_defer (void *stack, void (*pfn) (void *), void *arg)
+void
+__go_defer (void *frame, void (*pfn) (void *), void *arg)
 {
-  struct __defer_stack *n;
+  struct __go_defer_stack *n;
 
-  n = (struct __defer_stack *) __go_alloc (sizeof (struct __defer_stack));
-  n->__next = (struct __defer_stack *) stack;
+  if (__go_panic_defer == NULL)
+    __go_panic_defer = ((struct __go_panic_defer_struct *)
+			__go_alloc (sizeof (struct __go_panic_defer_struct)));
+
+  n = (struct __go_defer_stack *) __go_alloc (sizeof (struct __go_defer_stack));
+  n->__next = __go_panic_defer->__defer;
+  n->__frame = frame;
+  n->__panic = __go_panic_defer->__panic;
   n->__pfn = pfn;
   n->__arg = arg;
-  return (void *) n;
+  n->__retaddr = NULL;
+  __go_panic_defer->__defer = n;
 }
 
 /* This function is called when we want to undefer the stack.  */
 
 void
-__go_undefer (void *arg)
+__go_undefer (void *frame)
 {
-  struct __defer_stack *p;
+  if (__go_panic_defer == NULL)
+    return;
+  while (__go_panic_defer->__defer != NULL
+	 && __go_panic_defer->__defer->__frame == frame)
+    {
+      struct __go_defer_stack *d;
+      void (*pfn) (void *);
 
-  p = (struct __defer_stack *) arg;
-  while (p != NULL)
-    {
-      struct __defer_stack *n;
+      d = __go_panic_defer->__defer;
+      pfn = d->__pfn;
+      d->__pfn = NULL;
 
-      n = p->__next;
-      (*p->__pfn) (p->__arg);
-      __go_free (p);
-      p = n;
+      if (pfn != NULL)
+	(*pfn) (d->__arg);
+
+      __go_panic_defer->__defer = d->__next;
+      __go_free (d);
     }
 }
+
+/* This function is called to record the address to which the deferred
+   function returns.  This may in turn be checked by __go_can_recover.
+   The frontend relies on this function returning false.  */
+
+_Bool
+__go_set_defer_retaddr (void *retaddr)
+{
+  if (__go_panic_defer != NULL && __go_panic_defer->__defer != NULL)
+    __go_panic_defer->__defer->__retaddr = retaddr;
+  return 0;
+}
diff -r 74bfcdacefb6 libgo/runtime/go-defer.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/runtime/go-defer.h	Sun Jun 13 22:27:12 2010 -0700
@@ -0,0 +1,36 @@ 
+/* go-defer.h -- the defer stack.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+struct __go_panic_stack;
+
+/* The defer stack is a list of these structures.  */
+
+struct __go_defer_stack
+{
+  /* The next entry in the stack.  */
+  struct __go_defer_stack *__next;
+
+  /* The frame pointer for the function which called this defer
+     statement.  */
+  void *__frame;
+
+  /* The value of the panic stack when this function is deferred.
+     This function can not recover this value from the panic stack.
+     This can happen if a deferred function uses its own defer
+     statement.  */
+  struct __go_panic_stack *__panic;
+
+  /* The function to call.  */
+  void (*__pfn) (void *);
+
+  /* The argument to pass to the function.  */
+  void *__arg;
+
+  /* The return address that a recover thunk matches against.  This is
+     set by __go_set_defer_retaddr which is called by the thunks
+     created by defer statements.  */
+  const void *__retaddr;
+};
diff -r 74bfcdacefb6 libgo/runtime/go-deferred-recover.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/runtime/go-deferred-recover.c	Sun Jun 13 22:27:12 2010 -0700
@@ -0,0 +1,91 @@ 
+/* go-deferred-recover.c -- support for a deferred recover function.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stddef.h>
+
+#include "go-panic.h"
+#include "go-defer.h"
+
+/* This is called when a call to recover is deferred.  That is,
+   something like
+     defer recover()
+
+   We need to handle this specially.  In 6g/8g, the recover function
+   looks up the stack frame.  In particular, that means that a
+   deferred recover will not recover a panic thrown in the same
+   function that defers the recover.  It will only recover a panic
+   thrown in a function that defers the deferred call to recover.
+
+   In other words:
+
+   func f1() {
+	defer recover()	// does not stop panic
+	panic(0)
+   }
+
+   func f2() {
+	defer func() {
+		defer recover()	// stops panic(0)
+	}()
+	panic(0)
+   }
+
+   func f3() {
+	defer func() {
+		defer recover()	// does not stop panic
+		panic(0)
+	}()
+	panic(1)
+   }
+
+   func f4() {
+	defer func() {
+		defer func() {
+			defer recover()	// stops panic(0)
+		}()
+		panic(0)
+	}()
+	panic(1)
+   }
+
+   The interesting case here is f3.  As can be seen from f2, the
+   deferred recover could pick up panic(1).  However, this does not
+   happen because it is blocked by the panic(0).
+
+   When a function calls recover, then when we invoke it we pass a
+   hidden parameter indicating whether it should recover something.
+   This parameter is set based on whether the function is being
+   invoked directly from defer.  The parameter winds up determining
+   whether __go_recover or __go_deferred_recover is called at all.
+
+   In the case of a deferred recover, the hidden parameter which
+   controls the call is actually the one set up for the function which
+   runs the defer recover() statement.  That is the right thing in all
+   the cases above except for f3.  In f3 the function is permitted to
+   call recover, but the deferred recover call is not.  We address
+   that here by checking for that specific case before calling
+   recover.  If this function was deferred when there is already a
+   panic on the panic stack, then we can only recover that panic, not
+   any other.
+
+   Note that we can get away with using a special function here
+   because you are not permitted to take the address of a predeclared
+   function like recover.  */
+
+struct __go_interface *
+__go_deferred_recover ()
+{
+  struct __go_defer_stack *d;
+
+  if (__go_panic_defer == NULL)
+    return NULL;
+  d = __go_panic_defer->__defer;
+  if (d == NULL)
+    return 0;
+  if (d->__panic != __go_panic_defer->__panic)
+    return 0;
+  return __go_recover();
+}
diff -r 74bfcdacefb6 libgo/runtime/go-interface-to-object.c
--- a/libgo/runtime/go-interface-to-object.c	Sun Jun 13 22:25:39 2010 -0700
+++ b/libgo/runtime/go-interface-to-object.c	Sun Jun 13 22:27:12 2010 -0700
@@ -5,9 +5,9 @@ 
    license that can be found in the LICENSE file.  */
 
 #include <assert.h>
-#include <stdlib.h>
 
 #include "interface.h"
+#include "go-panic.h"
 
 /* Get an object from an interface.  This checks that the types match,
    and crashes if they don't.  */
@@ -20,10 +20,24 @@ 
   const struct __go_interface *rhs = (const struct __go_interface *) rhs_arg;
 
   assert (!__go_is_pointer_type (lhs_descriptor));
+
+  if (rhs == NULL)
+    {
+      __builtin_memset (result, 0, object_size);
+      return;
+    }
+
   if ((rhs->__type_descriptor != lhs_descriptor
        && !__go_type_descriptors_equal (rhs->__type_descriptor,
 					lhs_descriptor))
       || rhs->__type_descriptor->__size != object_size)
-    abort ();
+    {
+      struct __go_interface *panic_arg;
+
+      newTypeAssertionError(NULL, rhs->__type_descriptor, lhs_descriptor,
+			    NULL, rhs->__type_descriptor->__reflection,
+			    lhs_descriptor->__reflection, NULL, &panic_arg);
+      __go_panic(panic_arg);
+    }
   __builtin_memcpy (result, rhs->__object, object_size);
 }
diff -r 74bfcdacefb6 libgo/runtime/go-interface-to-pointer.c
--- a/libgo/runtime/go-interface-to-pointer.c	Sun Jun 13 22:25:39 2010 -0700
+++ b/libgo/runtime/go-interface-to-pointer.c	Sun Jun 13 22:27:12 2010 -0700
@@ -5,8 +5,8 @@ 
    license that can be found in the LICENSE file.  */
 
 #include <assert.h>
-#include <stdlib.h>
 
+#include "go-panic.h"
 #include "interface.h"
 
 /* Get a pointer from an interface.  This checks that the types match,
@@ -19,10 +19,21 @@ 
   const struct __go_interface *rhs = (const struct __go_interface *) rhs_arg;
 
   assert (__go_is_pointer_type (lhs_descriptor));
+
+  if (rhs == NULL)
+    return NULL;
+
   if (rhs->__type_descriptor != lhs_descriptor
       && !__go_type_descriptors_equal (rhs->__type_descriptor, lhs_descriptor)
       && lhs_descriptor->__code != GO_UNSAFE_POINTER
       && rhs->__type_descriptor->__code != GO_UNSAFE_POINTER)
-    abort ();
+    {
+      struct __go_interface *panic_arg;
+
+      newTypeAssertionError(NULL, rhs->__type_descriptor, lhs_descriptor,
+			    NULL, rhs->__type_descriptor->__reflection,
+			    lhs_descriptor->__reflection, NULL, &panic_arg);
+      __go_panic(panic_arg);
+    }
   return rhs->__object;
 }
diff -r 74bfcdacefb6 libgo/runtime/go-main.c
--- a/libgo/runtime/go-main.c	Sun Jun 13 22:25:39 2010 -0700
+++ b/libgo/runtime/go-main.c	Sun Jun 13 22:27:12 2010 -0700
@@ -4,10 +4,15 @@ 
    Use of this source code is governed by a BSD-style
    license that can be found in the LICENSE file.  */
 
+#include "config.h"
+
 #include <stdlib.h>
 #include <time.h>
 
-#include "config.h"
+#ifdef HAVE_FPU_CONTROL_H
+#include <fpu_control.h>
+#endif
+
 #include "go-alloc.h"
 #include "array.h"
 #include "go-signal.h"
diff -r 74bfcdacefb6 libgo/runtime/go-panic-defer.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/runtime/go-panic-defer.c	Sun Jun 13 22:27:12 2010 -0700
@@ -0,0 +1,9 @@ 
+/* go-panic-stack.c -- The panic/defer stack.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-panic.h"
+
+__thread struct __go_panic_defer_struct *__go_panic_defer;
diff -r 74bfcdacefb6 libgo/runtime/go-panic.c
--- a/libgo/runtime/go-panic.c	Sun Jun 13 22:25:39 2010 -0700
+++ b/libgo/runtime/go-panic.c	Sun Jun 13 22:27:12 2010 -0700
@@ -1,4 +1,4 @@ 
-/* go-panic.c -- support for the go panic statement.
+/* go-panic.c -- support for the go panic function.
 
    Copyright 2009 The Go Authors. All rights reserved.
    Use of this source code is governed by a BSD-style
@@ -7,29 +7,115 @@ 
 #include <stdio.h>
 #include <stdlib.h>
 
+#include "runtime.h"
+#include "malloc.h"
+#include "go-alloc.h"
+#include "go-defer.h"
 #include "go-panic.h"
+#include "go-string.h"
+#include "interface.h"
+
+/* Print the panic stack.  This is used when there is no recover.  */
+
+static void
+__printpanics (struct __go_panic_stack *p)
+{
+  if (p->__next != NULL)
+    {
+      __printpanics (p->__next);
+      printf ("\t");
+    }
+  printf ("panic: ");
+  printany (p->__arg);
+  if (p->__was_recovered)
+    printf (" [recovered]");
+  putchar ('\n');
+}
 
 /* This implements __go_panic which is used for the panic
-   statement.  */
+   function.  */
 
 void
-__go_panic ()
+__go_panic (struct __go_interface *arg)
 {
-  fputs ("\npanic\n", stderr);
+  struct __go_panic_stack *n;
+
+  if (__go_panic_defer == NULL)
+    __go_panic_defer = ((struct __go_panic_defer_struct *)
+			__go_alloc (sizeof (struct __go_panic_defer_struct)));
+
+  n = (struct __go_panic_stack *) __go_alloc (sizeof (struct __go_panic_stack));
+  n->__arg = arg;
+  n->__next = __go_panic_defer->__panic;
+  __go_panic_defer->__panic = n;
+
+  /* Run all the defer functions.  */
+
+  while (1)
+    {
+      struct __go_defer_stack *d;
+      void (*pfn) (void *);
+
+      d = __go_panic_defer->__defer;
+      if (d == NULL)
+	break;
+
+      pfn = d->__pfn;
+      d->__pfn = NULL;
+
+      if (pfn != NULL)
+	{
+	  (*pfn) (d->__arg);
+
+	  if (n->__was_recovered)
+	    {
+	      /* Some defer function called recover.  That means that
+		 we should stop running this panic.  */
+
+	      __go_panic_defer->__panic = n->__next;
+	      __go_free (n);
+
+	      /* Now unwind the stack by throwing an exception.  The
+		 compiler has arranged to create exception handlers in
+		 each function which uses a defer statement.  These
+		 exception handlers will check whether the entry on
+		 the top of the defer stack is from the current
+		 function.  If it is, we have unwound the stack far
+		 enough.  */
+	      __go_unwind_stack ();
+
+	      /* __go_unwind_stack should not return.  */
+	      abort ();
+	    }
+	}
+
+      __go_panic_defer->__defer = d->__next;
+      __go_free (d);
+    }
+
+  /* The panic was not recovered.  */
+
+  __printpanics (__go_panic_defer->__panic);
+
+  /* FIXME: We should dump a call stack here.  */
   abort ();
 }
 
-/* These are used by the runtime library.  */
+/* This is used by the runtime library.  */
 
 void
 __go_panic_msg (const char* msg)
 {
-  __go_print_msg (1, msg);
-  __go_panic ();
+  size_t len;
+  unsigned char *sdata;
+  struct __go_string s;
+  struct __go_interface *arg;
+
+  len = __builtin_strlen (msg);
+  sdata = mallocgc (len, RefNoPointers, 0, 0);
+  __builtin_memcpy (sdata, msg, len);
+  s.__data = sdata;
+  s.__length = len;
+  newErrorString(s, &arg);
+  __go_panic (arg);
 }
-
-void
-__go_print_msg (_Bool is_panic, const char* msg)
-{
-  fputs (msg, is_panic ? stderr : stdout);
-}
diff -r 74bfcdacefb6 libgo/runtime/go-panic.h
--- a/libgo/runtime/go-panic.h	Sun Jun 13 22:25:39 2010 -0700
+++ b/libgo/runtime/go-panic.h	Sun Jun 13 22:27:12 2010 -0700
@@ -1,16 +1,85 @@ 
-/* go-panic.h -- declare the go panic statement.
+/* go-panic.h -- declare the go panic functions.
 
    Copyright 2009 The Go Authors. All rights reserved.
    Use of this source code is governed by a BSD-style
    license that can be found in the LICENSE file.  */
 
-extern void __go_panic (void)
+#ifndef LIBGO_GO_PANIC_H
+#define LIBGO_GO_PANIC_H
+
+struct __go_interface;
+struct __go_string;
+struct __go_type_descriptor;
+struct __go_defer_stack;
+
+/* The stack of panic calls.  */
+
+struct __go_panic_stack
+{
+  /* The next entry in the stack.  */
+  struct __go_panic_stack *__next;
+
+  /* The value associated with this panic.  */
+  struct __go_interface *__arg;
+
+  /* Whether this panic has been recovered.  */
+  _Bool __was_recovered;
+
+  /* Whether this panic was pushed on the stack because of an
+     exception thrown in some other language.  */
+  _Bool __is_foreign;
+};
+
+/* The panic and defer stacks, grouped together into a single thread
+   local variable for convenience for systems without TLS.  */
+
+struct __go_panic_defer_struct
+{
+  /* The list of defers to execute.  */
+  struct __go_defer_stack *__defer;
+
+  /* The list of currently active panics.  There will be more than one
+     if a deferred function calls panic.  */
+  struct __go_panic_stack *__panic;
+
+  /* The current exception being thrown when unwinding after a call to
+     panic .  This is really struct _UnwindException *.  */
+  void *__exception;
+
+  /* Whether the current exception is from some other language.  */
+  _Bool __is_foreign;
+};
+
+extern __thread struct __go_panic_defer_struct *__go_panic_defer;
+
+extern void __go_panic (struct __go_interface *)
   __attribute__ ((noreturn));
 
 extern void __go_panic_msg (const char* msg)
   __attribute__ ((noreturn));
 
-extern void __go_print_msg (_Bool is_panic, const char* msg);
+extern void __go_print_string (struct __go_string);
 
-struct __go_string;
-extern void __go_print_string (_Bool is_panic, struct __go_string);
+extern struct __go_interface * __go_recover (void);
+
+extern void __go_unwind_stack (void);
+
+/* Functions defined in libgo/go/runtime/error.go.  */
+
+extern void newTypeAssertionError(const struct __go_type_descriptor *pt1,
+				  const struct __go_type_descriptor *pt2,
+				  const struct __go_type_descriptor *pt3,
+				  const struct __go_string *ps1,
+				  const struct __go_string *ps2,
+				  const struct __go_string *ps3,
+				  const struct __go_string *pmeth,
+				  struct __go_interface **ret)
+  __asm__ ("libgo_runtime.runtime.NewTypeAssertionError");
+
+extern void newErrorString(struct __go_string, struct __go_interface **)
+  __asm__ ("libgo_runtime.runtime.NewErrorString");
+
+extern void printany(struct __go_interface *)
+  __asm__ ("libgo_runtime.runtime.Printany");
+
+#endif /* !defined(LIBGO_GO_PANIC_H) */
diff -r 74bfcdacefb6 libgo/runtime/go-print.c
--- a/libgo/runtime/go-print.c	Sun Jun 13 22:25:39 2010 -0700
+++ b/libgo/runtime/go-print.c	Sun Jun 13 22:27:12 2010 -0700
@@ -15,66 +15,66 @@ 
    the predeclared functions print/println/panic/panicln.  */
 
 void
-__go_print_space (_Bool is_panic)
+__go_print_space ()
 {
-  putc (' ', is_panic ? stderr : stdout);
+  putchar (' ');
 }
 
 void
-__go_print_nl (_Bool is_panic)
+__go_print_nl ()
 {
-  putc ('\n', is_panic ? stderr : stdout);
+  putchar ('\n');
 }
 
 void
-__go_print_string (_Bool is_panic, struct __go_string val)
+__go_print_string (struct __go_string val)
 {
-  fprintf (is_panic ? stderr : stdout, "%.*s", (int) val.__length,
-	   (const char *) val.__data);
+  printf ("%.*s", (int) val.__length, (const char *) val.__data);
 }
 
 void
-__go_print_uint64 (_Bool is_panic, uint64_t val)
+__go_print_uint64 (uint64_t val)
 {
-  fprintf (is_panic ? stderr : stdout, "%llu", (unsigned long long) val);
+  printf ("%llu", (unsigned long long) val);
 }
 
 void
-__go_print_int64 (_Bool is_panic, int64_t val)
+__go_print_int64 (int64_t val)
 {
-  fprintf (is_panic ? stderr : stdout, "%lld", (long long) val);
+  printf ("%lld", (long long) val);
 }
 
 void
-__go_print_double (_Bool is_panic, double val)
+__go_print_double (double val)
 {
-  fprintf (is_panic ? stderr : stdout, "%.24g", val);
+  printf ("%.24g", val);
 }
 
 void
-__go_print_complex (_Bool is_panic, __complex double val)
+__go_print_complex (__complex double val)
 {
-  fprintf (is_panic ? stderr : stdout, "(%.24g%s%.24gi)",
-	   __builtin_creal (val),
-	   __builtin_cimag (val) >= 0 ? "+" : "",
-	   __builtin_cimag (val));
+  printf ("(%.24g%s%.24gi)",
+	  __builtin_creal (val),
+	  (__builtin_cimag (val) >= 0 || __builtin_isnan (__builtin_cimag(val))
+	   ? "+"
+	   : ""),
+	  __builtin_cimag (val));
 }
 
 void
-__go_print_bool (_Bool is_panic, _Bool val)
+__go_print_bool (_Bool val)
 {
-  fputs (val ? "true" : "false", is_panic ? stderr : stdout);
+  fputs (val ? "true" : "false", stdout);
 }
 
 void
-__go_print_pointer (_Bool is_panic, void *val)
+__go_print_pointer (void *val)
 {
-  fprintf (is_panic ? stderr : stdout, "%p", val);
+  printf ("%p", val);
 }
 
 void
-__go_print_slice (_Bool is_panic, struct __go_open_array val)
+__go_print_slice (struct __go_open_array val)
 {
-  fprintf (is_panic ? stderr : stdout, "[%d/%d]%p",
-	   val.__count, val.__capacity, val.__values);
+  printf ("[%d/%d]%p", val.__count, val.__capacity, val.__values);
 }
diff -r 74bfcdacefb6 libgo/runtime/go-rec-nb-small.c
--- a/libgo/runtime/go-rec-nb-small.c	Sun Jun 13 22:25:39 2010 -0700
+++ b/libgo/runtime/go-rec-nb-small.c	Sun Jun 13 22:27:12 2010 -0700
@@ -36,7 +36,11 @@ 
 	{
 	  ++channel->closed_op_count;
 	  if (channel->closed_op_count >= MAX_CLOSED_OPERATIONS)
-	    __go_panic_msg ("too many operations on closed channel");
+	    {
+	      i = pthread_mutex_unlock (&channel->lock);
+	      assert (i == 0);
+	      __go_panic_msg ("too many operations on closed channel");
+	    }
 	}
       channel->saw_close = 1;
       __go_unlock_and_notify_selects (channel);
diff -r 74bfcdacefb6 libgo/runtime/go-recover.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/runtime/go-recover.c	Sun Jun 13 22:27:12 2010 -0700
@@ -0,0 +1,64 @@ 
+/* go-recover.c -- support for the go recover function.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "interface.h"
+#include "go-panic.h"
+#include "go-defer.h"
+
+/* This is called by a thunk to see if the real function should be
+   permitted to recover a panic value.  Recovering a value is
+   permitted if the thunk was called directly by defer.  RETADDR is
+   the return address of the function which is calling
+   __go_can_recover--this is, the thunk.  */
+
+_Bool
+__go_can_recover (const void* retaddr)
+{
+  struct __go_defer_stack *d;
+  const char* ret;
+  const char* dret;
+
+  if (__go_panic_defer == NULL)
+    return 0;
+  d = __go_panic_defer->__defer;
+  if (d == NULL)
+    return 0;
+
+  /* The panic which this function would recover is the one on the top
+     of the panic stack.  We do not want to recover it if that panic
+     was on the top of the panic stack when this function was
+     deferred.  */
+  if (d->__panic == __go_panic_defer->__panic)
+    return 0;
+
+  /* D->__RETADDR is the address of a label immediately following the
+     call to the thunk.  We can recover a panic if that is the same as
+     the return address of the thunk.  We permit a bit of slack in
+     case there is any code between the function return and the label,
+     such as an instruction to adjust the stack pointer.  */
+
+  ret = (const char *) retaddr;
+  dret = (const char *) d->__retaddr;
+  return ret <= dret && ret + 16 >= dret;
+}
+
+/* This is only called when it is valid for the caller to recover the
+   value on top of the panic stack, if there is one.  */
+
+struct __go_interface *
+__go_recover ()
+{
+  struct __go_panic_stack *p;
+
+  if (__go_panic_defer == NULL)
+    return NULL;
+  p = __go_panic_defer->__panic;
+  if (p == NULL || p->__was_recovered)
+    return NULL;
+
+  p->__was_recovered = 1;
+  return p->__arg;
+}
diff -r 74bfcdacefb6 libgo/runtime/go-send-nb-small.c
--- a/libgo/runtime/go-send-nb-small.c	Sun Jun 13 22:25:39 2010 -0700
+++ b/libgo/runtime/go-send-nb-small.c	Sun Jun 13 22:27:12 2010 -0700
@@ -31,7 +31,11 @@ 
     {
       ++channel->closed_op_count;
       if (channel->closed_op_count >= MAX_CLOSED_OPERATIONS)
-	__go_panic_msg ("too many operations on closed channel");
+	{
+	  i = pthread_mutex_unlock (&channel->lock);
+	  assert (i == 0);
+	  __go_panic_msg ("too many operations on closed channel");
+	}
       i = pthread_mutex_unlock (&channel->lock);
       assert (i == 0);
       return SEND_NONBLOCKING_ACQUIRE_CLOSED;
diff -r 74bfcdacefb6 libgo/runtime/go-send-small.c
--- a/libgo/runtime/go-send-small.c	Sun Jun 13 22:25:39 2010 -0700
+++ b/libgo/runtime/go-send-small.c	Sun Jun 13 22:27:12 2010 -0700
@@ -30,7 +30,11 @@ 
 	{
 	  ++channel->closed_op_count;
 	  if (channel->closed_op_count >= MAX_CLOSED_OPERATIONS)
-	    __go_panic_msg ("too many operations on closed channel");
+	    {
+	      i = pthread_mutex_unlock (&channel->lock);
+	      assert (i == 0);
+	      __go_panic_msg ("too many operations on closed channel");
+	    }
 	  channel->selected_for_send = 0;
 	  __go_unlock_and_notify_selects (channel);
 	  return 0;
diff -r 74bfcdacefb6 libgo/runtime/go-signal.c
--- a/libgo/runtime/go-signal.c	Sun Jun 13 22:25:39 2010 -0700
+++ b/libgo/runtime/go-signal.c	Sun Jun 13 22:27:12 2010 -0700
@@ -8,6 +8,7 @@ 
 #include <signal.h>
 #include <stdlib.h>
 
+#include "go-panic.h"
 #include "go-signal.h"
 
 #include "runtime.h"
@@ -36,12 +37,27 @@ 
   { SIGINT, 0 },
   { SIGALRM, 1 },
   { SIGTERM, 0 },
+#ifdef SIGBUS
+  { SIGBUS, 0 },
+#endif
+#ifdef SIGFPE
+  { SIGFPE, 0 },
+#endif
 #ifdef SIGUSR1
   { SIGUSR1, 1 },
 #endif
+#ifdef SIGSEGV
+  { SIGSEGV, 0 },
+#endif
 #ifdef SIGUSR2
   { SIGUSR2, 1 },
 #endif
+#ifdef SIGPIPE
+  { SIGPIPE, 1 },
+#endif
+#ifdef SIGCHLD
+  { SIGCHLD, 1 },
+#endif
 #ifdef SIGTSTP
   { SIGTSTP, 1 },
 #endif
@@ -83,8 +99,49 @@ 
 static void
 sighandler (int sig)
 {
+  const char *msg;
   int i;
 
+  /* FIXME: Should check siginfo for more information when
+     available.  */
+  msg = NULL;
+  switch (sig)
+    {
+#ifdef SIGBUS
+    case SIGBUS:
+      msg = "invalid memory address or nil pointer dereference";
+      break;
+#endif
+
+#ifdef SIGFPE
+    case SIGFPE:
+      msg = "division by zero or floating point error";
+      break;
+#endif
+
+#ifdef SIGSEGV
+    case SIGSEGV:
+      msg = "invalid memory address or nil pointer dereference";
+      break;
+#endif
+
+    default:
+      break;
+    }
+
+  if (msg != NULL)
+    {
+      sigset_t clear;
+
+      /* The signal handler blocked signals; unblock them.  */
+      i = sigfillset (&clear);
+      assert (i == 0);
+      i = sigprocmask (SIG_UNBLOCK, &clear, NULL);
+      assert (i == 0);
+
+      __go_panic_msg (msg);
+    }
+
   if (sigsend (sig))
     return;
   for (i = 0; signals[i].sig != -1; ++i)
diff -r 74bfcdacefb6 libgo/runtime/go-type-error.c
--- a/libgo/runtime/go-type-error.c	Sun Jun 13 22:25:39 2010 -0700
+++ b/libgo/runtime/go-type-error.c	Sun Jun 13 22:27:12 2010 -0700
@@ -14,7 +14,7 @@ 
 __go_type_hash_error (const void *val __attribute__ ((unused)),
 		      size_t key_size __attribute__ ((unused)))
 {
-  __go_panic_msg ("hash of type which does not support hash computations");
+  __go_panic_msg ("hash of unhashable type");
 }
 
 /* An equality function for an interface.  */
@@ -24,5 +24,5 @@ 
 		       const void *v2 __attribute__ ((unused)),
 		       size_t key_size __attribute__ ((unused)))
 {
-  __go_panic_msg ("comparison of type which may not be compared");
+  __go_panic_msg ("comparing uncomparable types");
 }
diff -r 74bfcdacefb6 libgo/runtime/go-unwind.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/runtime/go-unwind.c	Sun Jun 13 22:27:12 2010 -0700
@@ -0,0 +1,401 @@ 
+/* go-unwind.c -- unwind the stack for panic/recover.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include "unwind.h"
+#define NO_SIZE_OF_ENCODED_VALUE
+#include "unwind-pe.h"
+
+#include "go-alloc.h"
+#include "go-defer.h"
+#include "go-panic.h"
+
+/* The code for a Go exception.  */
+
+#ifdef __ARM_EABI_UNWINDER__
+static const _Unwind_Exception_Class __go_exception_class =
+  { 'G', 'N', 'U', 'C', 'G', 'O', '\0', '\0' };
+#else
+static const _Unwind_Exception_Class __go_exception_class =
+  ((((((((_Unwind_Exception_Class) 'G' 
+         << 8 | (_Unwind_Exception_Class) 'N')
+        << 8 | (_Unwind_Exception_Class) 'U')
+       << 8 | (_Unwind_Exception_Class) 'C')
+      << 8 | (_Unwind_Exception_Class) 'G')
+     << 8 | (_Unwind_Exception_Class) 'O')
+    << 8 | (_Unwind_Exception_Class) '\0')
+   << 8 | (_Unwind_Exception_Class) '\0');
+#endif
+
+
+/* This function is called by exception handlers used when unwinding
+   the stack after a recovered panic.  The exception handler looks
+   like this:
+     __go_check_defer (frame);
+     return;
+   If we have not yet reached the frame we are looking for, we
+   continue unwinding.  */
+
+void
+__go_check_defer (void *frame)
+{
+  struct _Unwind_Exception *hdr;
+
+  if (__go_panic_defer->__is_foreign)
+    {
+      struct __go_panic_stack *n;
+      _Bool was_recovered;
+
+      /* Some other language has thrown an exception.  We need to run
+	 the local defer handlers.  If they call recover, we stop
+	 unwinding the stack here.  */
+
+      n = ((struct __go_panic_stack *)
+	   __go_alloc (sizeof (struct __go_panic_stack)));
+
+      n->__arg = NULL;
+      n->__was_recovered = 0;
+      n->__is_foreign = 1;
+      n->__next = __go_panic_defer->__panic;
+      __go_panic_defer->__panic = n;
+
+      while (1)
+	{
+	  struct __go_defer_stack *d;
+	  void (*pfn) (void *);
+
+	  d = __go_panic_defer->__defer;
+	  if (d == NULL || d->__frame != frame || d->__pfn == NULL)
+	    break;
+
+	  pfn = d->__pfn;
+	  __go_panic_defer->__defer = d->__next;
+
+	  (*pfn) (d->__arg);
+
+	  __go_free (d);
+
+	  if (n->__was_recovered)
+	    {
+	      /* The recover function caught the panic thrown by some
+		 other language.  */
+	      break;
+	    }
+	}
+
+      was_recovered = n->__was_recovered;
+      __go_panic_defer->__panic = n->__next;
+      __go_free (n);
+
+      if (was_recovered)
+	{
+	  /* Just return and continue executing Go code.  */
+	  return;
+	}
+    }
+  else if (__go_panic_defer->__defer != NULL
+	   && __go_panic_defer->__defer->__pfn == NULL
+	   && __go_panic_defer->__defer->__frame == frame)
+    {
+      struct __go_defer_stack *d;
+
+      /* This is the defer function which called recover.  Simply
+	 return to stop the stack unwind, and let the Go code continue
+	 to execute.  */
+      d = __go_panic_defer->__defer;
+      __go_panic_defer->__defer = d->__next;
+      __go_free (d);
+      return;
+    }
+
+  /* This is some other defer function.  It was already run by the
+     call to panic, or just above.  Rethrow the exception.  */
+
+  hdr = (struct _Unwind_Exception *) __go_panic_defer->__exception;
+
+#ifdef _GLIBCXX_SJLJ_EXCEPTIONS
+  _Unwind_SjLj_Resume_or_Rethrow (hdr);
+#else
+#if defined(_LIBUNWIND_STD_ABI)
+  _Unwind_RaiseException (hdr);
+#else
+  _Unwind_Resume_or_Rethrow (hdr);
+#endif
+#endif
+
+  /* Rethrowing the exception should not return.  */
+  abort();
+}
+
+/* Unwind function calls until we reach the one which used a defer
+   function which called recover.  Each function which uses a defer
+   statement will have an exception handler, as shown above.  */
+
+void
+__go_unwind_stack ()
+{
+  struct _Unwind_Exception *hdr;
+
+  hdr = ((struct _Unwind_Exception *)
+	 __go_alloc (sizeof (struct _Unwind_Exception)));
+  __builtin_memcpy (&hdr->exception_class, &__go_exception_class,
+		    sizeof hdr->exception_class);
+  hdr->exception_cleanup = NULL;
+
+  __go_panic_defer->__exception = hdr;
+
+  _Unwind_Reason_Code code;
+#ifdef __USING_SJLJ_EXCEPTIONS__
+  code = _Unwind_SjLj_RaiseException (hdr);
+#else
+  code = _Unwind_RaiseException (hdr);
+#endif
+
+  /* Raising an exception should not return.  */
+  abort ();
+}
+
+/* The rest of this code is really similar to gcc/unwind-c.c and
+   libjava/exception.cc.  */
+
+typedef struct
+{
+  _Unwind_Ptr Start;
+  _Unwind_Ptr LPStart;
+  _Unwind_Ptr ttype_base;
+  const unsigned char *TType;
+  const unsigned char *action_table;
+  unsigned char ttype_encoding;
+  unsigned char call_site_encoding;
+} lsda_header_info;
+
+static const unsigned char *
+parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
+		   lsda_header_info *info)
+{
+  _uleb128_t tmp;
+  unsigned char lpstart_encoding;
+
+  info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
+
+  /* Find @LPStart, the base to which landing pad offsets are relative.  */
+  lpstart_encoding = *p++;
+  if (lpstart_encoding != DW_EH_PE_omit)
+    p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
+  else
+    info->LPStart = info->Start;
+
+  /* Find @TType, the base of the handler and exception spec type data.  */
+  info->ttype_encoding = *p++;
+  if (info->ttype_encoding != DW_EH_PE_omit)
+    {
+      p = read_uleb128 (p, &tmp);
+      info->TType = p + tmp;
+    }
+  else
+    info->TType = 0;
+
+  /* The encoding and length of the call-site table; the action table
+     immediately follows.  */
+  info->call_site_encoding = *p++;
+  p = read_uleb128 (p, &tmp);
+  info->action_table = p + tmp;
+
+  return p;
+}
+
+#ifdef __ARM_EABI_UNWINDER__
+/* ARM EABI personality routines must also unwind the stack.  */
+#define CONTINUE_UNWINDING \
+  do								\
+    {								\
+      if (__gnu_unwind_frame (ue_header, context) != _URC_OK)	\
+	return _URC_FAILURE;					\
+      return _URC_CONTINUE_UNWIND;				\
+    }								\
+  while (0)
+#else
+#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
+#endif
+
+#ifdef __USING_SJLJ_EXCEPTIONS__
+#define PERSONALITY_FUNCTION    __gccgo_personality_sj0
+#define __builtin_eh_return_data_regno(x) x
+#else
+#define PERSONALITY_FUNCTION    __gccgo_personality_v0
+#endif
+
+#ifdef __ARM_EABI_UNWINDER__
+_Unwind_Reason_Code
+PERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *,
+		      struct _Unwind_Context *);
+
+_Unwind_Reason_Code
+PERSONALITY_FUNCTION (_Unwind_State state,
+		      struct _Unwind_Exception * ue_header,
+		      struct _Unwind_Context * context)
+#else
+_Unwind_Reason_Code
+PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class,
+		      struct _Unwind_Exception *, struct _Unwind_Context *);
+
+_Unwind_Reason_Code
+PERSONALITY_FUNCTION (int version,
+		      _Unwind_Action actions,
+		      _Unwind_Exception_Class exception_class,
+		      struct _Unwind_Exception *ue_header,
+		      struct _Unwind_Context *context)
+#endif
+{
+  lsda_header_info info;
+  const unsigned char *language_specific_data, *p, *action_record;
+  _Unwind_Ptr landing_pad, ip;
+  int ip_before_insn = 0;
+  _Bool is_foreign;
+
+#ifdef __ARM_EABI_UNWINDER__
+  _Unwind_Action actions;
+
+  switch (state & _US_ACTION_MASK)
+    {
+    case _US_VIRTUAL_UNWIND_FRAME:
+      actions = _UA_SEARCH_PHASE;
+      break;
+
+    case _US_UNWIND_FRAME_STARTING:
+      actions = _UA_CLEANUP_PHASE;
+      if (!(state & _US_FORCE_UNWIND)
+	  && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13))
+	actions |= _UA_HANDLER_FRAME;
+      break;
+
+    case _US_UNWIND_FRAME_RESUME:
+      CONTINUE_UNWINDING;
+      break;
+
+    default:
+      std::abort();
+    }
+  actions |= state & _US_FORCE_UNWIND;
+
+  is_foreign = 0;
+
+  /* The dwarf unwinder assumes the context structure holds things like the
+     function and LSDA pointers.  The ARM implementation caches these in
+     the exception header (UCB).  To avoid rewriting everything we make the
+     virtual IP register point at the UCB.  */
+  ip = (_Unwind_Ptr) ue_header;
+  _Unwind_SetGR (context, 12, ip);
+#else
+  if (version != 1)
+    return _URC_FATAL_PHASE1_ERROR;
+
+  is_foreign = exception_class != __go_exception_class;
+#endif
+
+  language_specific_data = (const unsigned char *)
+    _Unwind_GetLanguageSpecificData (context);
+
+  /* If no LSDA, then there are no handlers or cleanups.  */
+  if (! language_specific_data)
+    CONTINUE_UNWINDING;
+
+  /* Parse the LSDA header.  */
+  p = parse_lsda_header (context, language_specific_data, &info);
+#ifdef HAVE_GETIPINFO
+  ip = _Unwind_GetIPInfo (context, &ip_before_insn);
+#else
+  ip = _Unwind_GetIP (context);
+#endif
+  if (! ip_before_insn)
+    --ip;
+  landing_pad = 0;
+
+#ifdef __USING_SJLJ_EXCEPTIONS__
+  /* The given "IP" is an index into the call-site table, with two
+     exceptions -- -1 means no-action, and 0 means terminate.  But
+     since we're using uleb128 values, we've not got random access
+     to the array.  */
+  if ((int) ip <= 0)
+    return _URC_CONTINUE_UNWIND;
+  else
+    {
+      _uleb128_t cs_lp, cs_action;
+      do
+	{
+	  p = read_uleb128 (p, &cs_lp);
+	  p = read_uleb128 (p, &cs_action);
+	}
+      while (--ip);
+
+      /* Can never have null landing pad for sjlj -- that would have
+	 been indicated by a -1 call site index.  */
+      landing_pad = (_Unwind_Ptr)cs_lp + 1;
+      if (cs_action)
+	action_record = info.action_table + cs_action - 1;
+      goto found_something;
+    }
+#else
+  /* Search the call-site table for the action associated with this IP.  */
+  while (p < info.action_table)
+    {
+      _Unwind_Ptr cs_start, cs_len, cs_lp;
+      _uleb128_t cs_action;
+
+      /* Note that all call-site encodings are "absolute" displacements.  */
+      p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
+      p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
+      p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
+      p = read_uleb128 (p, &cs_action);
+
+      /* The table is sorted, so if we've passed the ip, stop.  */
+      if (ip < info.Start + cs_start)
+	p = info.action_table;
+      else if (ip < info.Start + cs_start + cs_len)
+	{
+	  if (cs_lp)
+	    landing_pad = info.LPStart + cs_lp;
+	  if (cs_action)
+	    action_record = info.action_table + cs_action - 1;
+	  goto found_something;
+	}
+    }
+#endif
+
+  /* IP is not in table.  No associated cleanups.  */
+  CONTINUE_UNWINDING;
+
+ found_something:
+  if (landing_pad == 0)
+    {
+      /* IP is present, but has a null landing pad.
+	 No handler to be run.  */
+      CONTINUE_UNWINDING;
+    }
+
+  if (actions & _UA_SEARCH_PHASE)
+    return _URC_HANDLER_FOUND;
+
+  if (__go_panic_defer == NULL)
+    {
+      if (!is_foreign)
+	abort();
+      __go_panic_defer = ((struct __go_panic_defer_struct *)
+			  __go_alloc (sizeof (struct __go_panic_defer_struct)));
+    }
+
+  __go_panic_defer->__exception = ue_header;
+  __go_panic_defer->__is_foreign = is_foreign;
+
+  _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
+		 (_Unwind_Ptr) ue_header);
+  _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0);
+  _Unwind_SetIP (context, landing_pad);
+  return _URC_INSTALL_CONTEXT;
+}
diff -r 74bfcdacefb6 libgo/runtime/runtime.h
--- a/libgo/runtime/runtime.h	Sun Jun 13 22:25:39 2010 -0700
+++ b/libgo/runtime/runtime.h	Sun Jun 13 22:27:12 2010 -0700
@@ -7,6 +7,7 @@ 
 #include "config.h"
 
 #define _GNU_SOURCE
+#include <assert.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -89,8 +90,8 @@ 
 #define	nil		((void*)0)
 #define USED(v)		((void) v)
 
-/* We map throw to panic.  */
-#define throw(s) __go_panic_msg (s)
+/* We map throw to assert.  */
+#define throw(s) assert(s == 0)
 
 void	mallocinit(void);
 void	siginit(void);